diff --git a/.github/AppImageBuilder.yml b/.github/AppImageBuilder.yml new file mode 100644 index 0000000000..cce46890c4 --- /dev/null +++ b/.github/AppImageBuilder.yml @@ -0,0 +1,57 @@ +# appimage-builder recipe see https://appimage-builder.readthedocs.io for details +version: 1 +script: + # Ensure that the mksquashfs tool is installed (workaround for the AppImageCrafters/build-appimage GHA) + - which mksquashfs || apt install squashfs-tools + # fake icons + - mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps + - touch AppDir/usr/share/icons/hicolor/64x64/apps/nvme-cli.png + +AppDir: + path: AppDir + app_info: + id: linux-nvme.nvme-cli + name: nvme-cli + version: latest + icon: nvme-cli + exec: usr/sbin/nvme + exec_args: $@ + apt: + arch: amd64 + allow_unauthenticated: true + sources: + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse + key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C' + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse + - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse + include: + - libjson-c5 + - libssl3 + files: + include: + - libcrypt.so.3 + - libdbus-1.so.3 + - libjson-c.so.5 + exclude: + - usr/share/man + - usr/share/doc + test: + fedora-30: + image: appimagecrafters/tests-env:fedora-30 + command: ./AppRun + debian-stable: + image: appimagecrafters/tests-env:debian-stable + command: ./AppRun + archlinux-latest: + image: appimagecrafters/tests-env:archlinux-latest + command: ./AppRun + centos-7: + image: appimagecrafters/tests-env:centos-7 + command: ./AppRun + ubuntu-xenial: + image: appimagecrafters/tests-env:ubuntu-xenial + command: ./AppRun +AppImage: + update-information: 'gh-releases-zsync|linux-nvme|nvme-cli|latest|*x86_64.AppImage.zsync' + arch: x86_64 diff --git a/.github/azure-pipelines.yml b/.github/azure-pipelines.yml new file mode 100644 index 0000000000..f9eb5edc32 --- /dev/null +++ b/.github/azure-pipelines.yml @@ -0,0 +1,38 @@ +--- +# Do not run following tests +# - exclude data varification tests, too slow +# - nvme/010 +# - nvme/011 +# - nvme/012 +# - nvme/013 + +trigger: + - master +pr: + - master + +jobs: + - job: blktests + timeoutInMinutes: 5 + pool: + name: linux-nvme + steps: + - script: | + meson $(Agent.TempDirectory)/build + ninja -C $(Agent.TempDirectory)/build + displayName: Build nvme-cli + - script: | + git clone --depth 1 https://github.com/osandov/blktests.git $(Agent.TempDirectory)/blktests + displayName: Clone blktests + - script: | + cd $(Agent.TempDirectory)/blktests + sudo sh -c 'PATH=$(Agent.TempDirectory)/build:$PATH nvme_trtype=tcp ./check -x nvme/010 -x nvme/011 -x nvme/012 -x nvme/013 nvme' + displayName: Run blktests for NVMe transport TCP + - script: | + cd $(Agent.TempDirectory)/blktests + sudo sh -c 'PATH=$(Agent.TempDirectory)/build:$PATH nvme_trtype=rdma ./check -x nvme/010 -x nvme/011 -x nvme/012 -x nvme/013 nvme' + displayName: Run blktests for NVMe transport RDMA + - script: | + cd $(Agent.TempDirectory)/blktests + sudo sh -c 'PATH=$(Agent.TempDirectory)/build:$PATH nvme_trtype=fc ./check -x nvme/010 -x nvme/011 -x nvme/012 -x nvme/013 nvme' + displayName: Run blktests for NVMe transport FC diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000000..d9079fd939 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,3 @@ +name: "CodeQL Config" +paths-ignore: + - subprojects/** diff --git a/.github/cross/ubuntu-cross-armhf.txt b/.github/cross/ubuntu-cross-armhf.txt new file mode 100644 index 0000000000..41c8328906 --- /dev/null +++ b/.github/cross/ubuntu-cross-armhf.txt @@ -0,0 +1,18 @@ +[binaries] +c = '/usr/bin/arm-linux-gnueabihf-gcc' +ar = '/usr/arm-linux-gnueabihf/bin/ar' +strip = '/usr/arm-linux-gnueabihf/bin/strip' +pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config' +ld = '/usr/bin/arm-linux/gnueabihf-ld' +exe_wrapper = '/usr/bin/qemu-arm-static' + +[properties] +root = '/usr/arm-linux-gnueabihf' +has_function_printf = true +skip_sanity_check = true + +[host_machine] +system = 'linux' +cpu_family = 'arm' +cpu = 'armv7' +endian = 'little' diff --git a/.github/cross/ubuntu-cross-ppc64le.txt b/.github/cross/ubuntu-cross-ppc64le.txt new file mode 100644 index 0000000000..6baaefbc26 --- /dev/null +++ b/.github/cross/ubuntu-cross-ppc64le.txt @@ -0,0 +1,18 @@ +[binaries] +c = '/usr/bin/powerpc64le-linux-gnu-gcc' +ar = '/usr/powerpc64le-linux-gnu/bin/ar' +strip = '/usr/powerpc64le-linux-gnu/bin/strip' +pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config' +ld = '/usr/bin/powerpc64le-linux-gnu-ld' +exe_wrapper = '/usr/bin/qemu-ppc64le-static' + +[properties] +root = '/usr/powerpc64le-linux-gnu' +has_function_printf = true +skip_sanity_check = true + +[host_machine] +system = 'linux' +cpu_family = 'ppc64' +cpu = '' +endian = 'little' diff --git a/.github/cross/ubuntu-cross-s390x.txt b/.github/cross/ubuntu-cross-s390x.txt new file mode 100644 index 0000000000..51a3511fbe --- /dev/null +++ b/.github/cross/ubuntu-cross-s390x.txt @@ -0,0 +1,18 @@ +[binaries] +c = '/usr/bin/s390x-linux-gnu-gcc' +ar = '/usr/s390x-linux-gnu/bin/ar' +strip = '/usr/s390x-linux-gnu/bin/strip' +pkgconfig = '/usr/bin/s390x-linux-gnu-pkg-config' +ld = '/usr/bin/s390x-linux-gnu-ld' +exe_wrapper = '/usr/bin/qemu-s390x-static' + +[properties] +root = '/usr/s390x-linux-gnu' +has_function_printf = true +skip_sanity_check = true + +[host_machine] +system = 'linux' +cpu_family = 's390x' +cpu = '' +endian = 'big' diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml new file mode 100644 index 0000000000..6c0d3e51a3 --- /dev/null +++ b/.github/workflows/appimage.yml @@ -0,0 +1,56 @@ +--- +name: appimage + +on: + push: + branches: [master] + pull_request: + branches: [master] +env: + DESTDIR: ../AppDir + +jobs: + build-appimage: + name: build AppImage + runs-on: ubuntu-latest + container: + image: ghcr.io/igaw/linux-nvme/debian:latest + steps: + - uses: actions/checkout@v4 + - name: build + run: | + scripts/build.sh appimage + - name: build AppImage + uses: AppImageCrafters/build-appimage@v1.3 + with: + recipe: .github/AppImageBuilder.yml + - uses: actions/upload-artifact@v4 + name: upload artifacts to github + with: + name: AppImage + path: '*.AppImage*' + + deploy-appimage: + name: deploy AppImage + runs-on: ubuntu-latest + needs: build-appimage + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'linux-nvme/nvme-cli' }} + steps: + - name: Download artifact + uses: dawidd6/action-download-artifact@v3 + with: + workflow: ${{ github.event.workflow_run.workflow_id }} + workflow_conclusion: success + - name: FTP Deployer + uses: sand4rt/ftp-deployer@v1.7 + with: + sftp: true + host: ${{ secrets.SFTP_SERVER }} + port: 22 + username: ${{ secrets.SFTP_USERNAME }} + password: ${{ secrets.SFTP_PASSWORD }} + remote_folder: '/upload' + local_folder: '.' + cleanup: false + include: '[ "*", "**/*" ]' + exclude: '[".github/**", ".git/**", "*.env"]' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..0b1251704d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,101 @@ +--- +name: build + +on: + push: + branches: [master] + pull_request: + branches: [master] + + workflow_dispatch: + +jobs: + default: + runs-on: ubuntu-latest + strategy: + matrix: + compiler: [gcc, clang] + buildtype: [debug, release] + container: + image: ghcr.io/igaw/linux-nvme/debian.python:latest + steps: + - uses: actions/checkout@v4 + - name: build + run: | + scripts/build.sh -b ${{ matrix.buildtype }} -c ${{ matrix.compiler }} + - uses: actions/upload-artifact@v4 + name: upload logs + if: failure() + with: + name: logs files + path: | + .build-ci/meson-logs/*.txt + + cross: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: armhf + - arch: s390x + - arch: ppc64le + steps: + - uses: actions/checkout@v4 + - name: enable foreign arch + uses: dbhi/qus/action@main + - name: compile and run unit tests + uses: mosteo-actions/docker-run@v1 + with: + image: ghcr.io/igaw/linux-nvme/ubuntu-cross-${{ matrix.arch }}:latest + guest-dir: /build + host-dir: ${{ github.workspace }} + command: | + scripts/build.sh -b release -c gcc -t ${{ matrix.arch }} cross + params: "--platform linux/amd64" + pull-params: "--platform linux/amd64" + - uses: actions/upload-artifact@v4 + name: upload logs + if: failure() + with: + name: log files + path: | + .build-ci/meson-logs/*.txt + + fallback-shared-libraries: + name: fallback shared libraries + runs-on: ubuntu-latest + container: + image: ghcr.io/igaw/linux-nvme/debian:latest + if: github.ref == 'refs/heads/master' + steps: + - uses: actions/checkout@v4 + - name: build + run: | + scripts/build.sh -b release -c gcc fallback + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: log files + path: | + .build-ci/meson-logs/*.txt + + build-muon: + name: muon minimal static + runs-on: ubuntu-latest + container: + image: ghcr.io/igaw/linux-nvme/debian:latest + steps: + - uses: actions/checkout@v4 + - name: build + run: | + scripts/build.sh -m muon + build-make-static: + name: make static + runs-on: ubuntu-latest + container: + image: ghcr.io/igaw/linux-nvme/debian:latest + steps: + - uses: actions/checkout@v4 + - name: build + run: | + make static diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml new file mode 100644 index 0000000000..c0a09b7653 --- /dev/null +++ b/.github/workflows/checkpatch.yml @@ -0,0 +1,15 @@ +name: checkpatch review +on: [pull_request] +jobs: + checkpatch: + name: checkpatch review + runs-on: ubuntu-latest + steps: + - name: 'Calculate PR commits + 1' + run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> $GITHUB_ENV + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + - name: Run checkpatch review + uses: webispy/checkpatch-action@v9 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..d57e17aa7d --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,71 @@ +# CodeQL build configuration for nvme-cli +# Mostly based on auto-configuration with additions and tweaks for: +# * meson install +# * language detection +name: "CodeQL" + +on: + push: + branches: [ "master" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '24 2 * * 5' + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: 'ubuntu-latest' + timeout-minutes: 360 + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'c-cpp', 'python' ] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install build tools + run: | + sudo apt-get update + sudo apt-get install meson + + # Initializes the CodeQL tools for scanning. + - if: matrix.language == 'c-cpp' + name: Initialize CodeQL C + uses: github/codeql-action/init@v3 + with: + languages: 'c-cpp' + + - if: matrix.language == 'python' + name: Initialize CodeQL Python + uses: github/codeql-action/init@v3 + with: + languages: 'python' + config-file: ./.github/codeql/codeql-config.yml + + - name: meson build + run: | + meson setup --force-fallback-for=libnvme,json-c .build + ninja -C .build + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000000..875ed6d6d2 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,22 @@ +--- +name: coverage + +on: + push: + branches: [master] + +jobs: + code-coverage: + if: github.repository == 'linux-nvme/nvme-cli' + name: code coverage + runs-on: ubuntu-latest + container: + image: ghcr.io/igaw/linux-nvme/debian.python:latest + steps: + - uses: actions/checkout@v4 + - name: build + run: | + scripts/build.sh coverage + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: false diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml deleted file mode 100644 index c49470bc4d..0000000000 --- a/.github/workflows/meson.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: nvme-cli meson CI - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - - workflow_dispatch: - -jobs: - build-disto: - runs-on: ubuntu-latest - - steps: - - name: install libraries - run: sudo apt-get install libjson-c-dev libhugetlbfs-dev - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - # - name: install python dependencies - # run: | - # python -m pip install --upgrade pip - # pip install nose nose2 - - uses: BSFishy/meson-build@v1.0.3 - with: - setup-options: --werror - action: build - - build-fallback: - runs-on: ubuntu-latest - steps: - - name: install libraries - run: sudo apt-get install -y libpam-dev libcap-ng-dev - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - uses: BSFishy/meson-build@v1.0.3 - with: - setup-options: --werror -Duuid:werror=false --wrap-mode=forcefallback - options: --verbose - action: build - meson-version: 0.61.2 - - build-static: - runs-on: ubuntu-latest - steps: - - name: install libraries - run: sudo apt-get install -y libpam-dev libcap-ng-dev - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - uses: BSFishy/meson-build@v1.0.3 - with: - setup-options: --werror -Duuid:werror=false --wrap-mode=forcefallback --default-library=static - options: --verbose - action: build - meson-version: 0.61.2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db84ef52ff..8a5651c86a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,5 @@ -name: Releases +--- +name: release on: push: @@ -9,11 +10,11 @@ on: jobs: build: runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/v') + if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'linux-nvme/nvme-cli' permissions: contents: write steps: - - uses: actions/checkout@v2 - - uses: ncipollo/release-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v4 + - uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 0745eff7a4..da4804c9e3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,9 +10,11 @@ subprojects/* !subprojects/*.wrap cscope.* +compile_commands.json tests/__pycache__ tests/nvmetests tests/*.pyc -.build \ No newline at end of file +.build +.cache diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000000..b506f8583a --- /dev/null +++ b/.mailmap @@ -0,0 +1 @@ +Vigneshwaran Saravanan diff --git a/Documentation/cmd-plugins.txt b/Documentation/cmd-plugins.txt index 2ab6c6821d..f767603932 100644 --- a/Documentation/cmd-plugins.txt +++ b/Documentation/cmd-plugins.txt @@ -198,3 +198,6 @@ linknvme:nvme-zns-zone-mgmt-send[1]:: linknvme:nvme-zns-zrwa-flush-zone[1]:: Flush LBAs associated with a ZRWA to a zone + +linknvme:nvme-inspur-nvme-vendor-log[1]:: + NVMe Inspur Device Vendor log page request diff --git a/Documentation/cmds-main.txt b/Documentation/cmds-main.txt index 58a8094fcd..14a6ff6998 100644 --- a/Documentation/cmds-main.txt +++ b/Documentation/cmds-main.txt @@ -270,3 +270,6 @@ linknvme:nvme-supported-log-pages[1]:: linknvme:nvme-verify[1]:: verify command + +linknvme:nvme-show-topology[1]:: + Show NVMe topology diff --git a/Documentation/meson.build b/Documentation/meson.build index a47c27f6e4..0dc03006d1 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -31,6 +31,13 @@ adoc_sources = [ 'nvme-error-log', 'nvme-fid-support-effects-log', 'nvme-mi-cmd-support-effects-log', + 'nvme-fdp-configs', + 'nvme-fdp-usage', + 'nvme-fdp-stats', + 'nvme-fdp-events', + 'nvme-fdp-status', + 'nvme-fdp-update', + 'nvme-fdp-set-events', 'nvme-flush', 'nvme-format', 'nvme-fw-commit', @@ -56,6 +63,8 @@ adoc_sources = [ 'nvme-intel-market-name', 'nvme-intel-smart-log-add', 'nvme-intel-temp-stats', + 'nvme-io-mgmt-recv', + 'nvme-io-mgmt-send', 'nvme-io-passthru', 'nvme-lba-status-log', 'nvme-list', @@ -75,9 +84,14 @@ adoc_sources = [ 'nvme-netapp-smdevices', 'nvme-ns-descs', 'nvme-ns-rescan', + 'nvme-nvme-mi-recv', + 'nvme-nvme-mi-send', 'nvme-nvm-id-ctrl', 'nvme-ocp-latency-monitor-log', 'nvme-ocp-smart-add-log', + 'nvme-ocp-clear-fw-activate-history', + 'nvme-ocp-clear-pcie-correctable-error-counters', + 'nvme-ocp-eol-plp-failure-mode', 'nvme-persistent-event-log', 'nvme-pred-lat-event-agg-log', 'nvme-predictable-lat-log', @@ -92,6 +106,20 @@ adoc_sources = [ 'nvme-rpmb', 'nvme-sanitize', 'nvme-sanitize-log', + 'nvme-seagate-clear-pcie-correctable-errors', + 'nvme-seagate-get-ctrl-tele', + 'nvme-seagate-get-host-tele', + 'nvme-seagate-help', + 'nvme-seagate-plugin-version', + 'nvme-seagate-version', + 'nvme-seagate-vs-internal-log', + 'nvme-seagate-vs-log-page-sup', + 'nvme-seagate-vs-pcie-stats', + 'nvme-seagate-vs-smart-add-log', + 'nvme-seagate-vs-temperature-stats', + 'nvme-seagate-cloud-SSD-plugin-version', + 'nvme-seagate-vs-fw-activate-history', + 'nvme-seagate-clear-fw-activate-history', 'nvme-security-recv', 'nvme-security-send', 'nvme-self-test-log', @@ -99,6 +127,7 @@ adoc_sources = [ 'nvme-set-property', 'nvme-show-hostnqn', 'nvme-show-regs', + 'nvme-show-topology', 'nvme-smart-log', 'nvme-subsystem-reset', 'nvme-supported-log-pages', @@ -161,6 +190,7 @@ adoc_sources = [ 'nvme-zns-zone-append', 'nvme-zns-zone-mgmt-recv', 'nvme-zns-zone-mgmt-send', + 'nvme-inspur-nvme-vendor-log', ] adoc_includes = [ diff --git a/Documentation/nvme-admin-passthru.1 b/Documentation/nvme-admin-passthru.1 index f487265ab5..b057dec3ab 100644 --- a/Documentation/nvme-admin-passthru.1 +++ b/Documentation/nvme-admin-passthru.1 @@ -2,12 +2,12 @@ .\" Title: nvme-admin-passthru .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ADMIN\-PASSTHR" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ADMIN\-PASSTHR" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,21 +32,24 @@ nvme-admin-passthru \- Submit an arbitrary admin command, return results .SH "SYNOPSIS" .sp .nf -\fInvme\-admin\-passthru\fR [\-\-opcode= | \-o ] - [\-\-flags= | \-f ] [\-rsvd= | \-R ] - [\-\-namespace\-id=] [\-\-cdw2=] [\-\-cdw3=] - [\-\-cdw10=] [\-\-cdw11=] [\-\-cdw12=] - [\-\-cdw13=] [\-\-cdw14=] [\-\-cdw15=] - [\-\-data\-len= | \-l ] - [\-\-metadata\-len= | \-m ] - [\-\-input\-file= | \-i ] - [\-\-read | \-r ] [\-\-write | \-w] - [\-\-timeout= | \-t ] - [\-\-show\-command | \-s] - [\-\-dry\-run | \-d] - [\-\-raw\-binary | \-b] - [\-\-prefill= | \-p ] - [\-\-latency | \-T] +\fInvme\-admin\-passthru\fR [\-\-opcode= | \-O ] + [\-\-flags= | \-f ] [\-rsvd= | \-R ] + [\-\-namespace\-id= | \-n ] [\-\-cdw2= | \-2 ] + [\-\-cdw3= | \-3 ] [\-\-cdw10= | \-4 ] + [\-\-cdw11= | \-5 ] [\-\-cdw12= | \-6 ] + [\-\-cdw13= | \-7 ] [\-\-cdw14= | \-8 ] + [\-\-cdw15= | \-9 ] + [\-\-data\-len= | \-l ] + [\-\-metadata\-len= | \-m ] + [\-\-input\-file= | \-i ] + [\-\-read | \-r] [\-\-write | \-w] + [\-\-timeout= | \-t ] + [\-\-show\-command | \-s] + [\-\-dry\-run | \-d] + [\-\-raw\-binary | \-b] + [\-\-prefill= | \-p ] + [\-\-latency | \-T] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -57,7 +60,7 @@ The parameter is mandatory and may be either the NVMe character device 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= +\-O , \-\-opcode= .RS 4 The NVMe opcode to send to the device in the command .RE @@ -77,7 +80,7 @@ The value for the reserved field in the command\&. The value for the ns\-id in the command\&. .RE .PP -\-\-cdw[2\-3,10\-15]= +\-[2\-9] , \-\-cdw[2\-3,10\-15]= .RS 4 Specifies the command dword value for that specified entry in the command .RE @@ -129,6 +132,20 @@ Prefill the buffer with a predetermined byte value\&. Defaults to 0\&. This may .RS 4 Print out the latency the IOCTL took (in us)\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-admin-passthru.html b/Documentation/nvme-admin-passthru.html index 27683efbe6..7a4f6ac90f 100644 --- a/Documentation/nvme-admin-passthru.html +++ b/Documentation/nvme-admin-passthru.html @@ -749,21 +749,24 @@

NAME

SYNOPSIS

-
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>]
-                [--latency | -T]
+
nvme-admin-passthru <device> [--opcode=<opcode> | -O <opcode>]
+                        [--flags=<flags> | -f <flags>] [-rsvd=<rsvd> | -R <rsvd>]
+                        [--namespace-id=<nsid> | -n <nsid>] [--cdw2=<cdw2> | -2 <cdw2>]
+                        [--cdw3=<cdw3> | -3 <cdw3>] [--cdw10=<cdw10> | -4 <cdw4>]
+                        [--cdw11=<cdw11> | -5 <cdw5>] [--cdw12=<cdw12> | -6 <cdw6>]
+                        [--cdw13=<cdw13> | -7 <cdw7>] [--cdw14=<cdw14> | -8 <cdw8>]
+                        [--cdw15=<cdw15> | -9 <cdw9>]
+                        [--data-len=<data-len> | -l <data-len>]
+                        [--metadata-len=<len> | -m <len>]
+                        [--input-file=<file> | -i <file>]
+                        [--read | -r] [--write | -w]
+                        [--timeout=<to> | -t <to>]
+                        [--show-command | -s]
+                        [--dry-run | -d]
+                        [--raw-binary | -b]
+                        [--prefill=<prefill> | -p <prefill>]
+                        [--latency | -T]
+                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -788,7 +791,7 @@

OPTIONS

--o <opcode> +-O <opcode>
--opcode=<opcode> @@ -832,6 +835,9 @@

OPTIONS

+-[2-9] <cdw> +
+
--cdw[2-3,10-15]=<cdw>
@@ -956,6 +962,29 @@

OPTIONS

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

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

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

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

+ Increase the information detail in the output. +

+
@@ -998,7 +1027,7 @@

NVME

diff --git a/Documentation/nvme-admin-passthru.txt b/Documentation/nvme-admin-passthru.txt index ce452fa2b1..51e9e0767d 100644 --- a/Documentation/nvme-admin-passthru.txt +++ b/Documentation/nvme-admin-passthru.txt @@ -8,21 +8,24 @@ nvme-admin-passthru - Submit an arbitrary admin command, return results SYNOPSIS -------- [verse] -'nvme-admin-passthru' [--opcode= | -o ] - [--flags= | -f ] [-rsvd= | -R ] - [--namespace-id=] [--cdw2=] [--cdw3=] - [--cdw10=] [--cdw11=] [--cdw12=] - [--cdw13=] [--cdw14=] [--cdw15=] - [--data-len= | -l ] - [--metadata-len= | -m ] - [--input-file= | -i ] - [--read | -r ] [--write | -w] - [--timeout= | -t ] - [--show-command | -s] - [--dry-run | -d] - [--raw-binary | -b] - [--prefill= | -p ] - [--latency | -T] +'nvme-admin-passthru' [--opcode= | -O ] + [--flags= | -f ] [-rsvd= | -R ] + [--namespace-id= | -n ] [--cdw2= | -2 ] + [--cdw3= | -3 ] [--cdw10= | -4 ] + [--cdw11= | -5 ] [--cdw12= | -6 ] + [--cdw13= | -7 ] [--cdw14= | -8 ] + [--cdw15= | -9 ] + [--data-len= | -l ] + [--metadata-len= | -m ] + [--input-file= | -i ] + [--read | -r] [--write | -w] + [--timeout= | -t ] + [--show-command | -s] + [--dry-run | -d] + [--raw-binary | -b] + [--prefill= | -p ] + [--latency | -T] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -41,7 +44,7 @@ printed to stdout for another program to parse. OPTIONS ------- --o :: +-O :: --opcode=:: The NVMe opcode to send to the device in the command @@ -57,6 +60,7 @@ OPTIONS --namespace-id=:: The value for the ns-id in the command. +-[2-9] :: --cdw[2-3,10-15]=:: Specifies the command dword value for that specified entry in the command @@ -110,6 +114,15 @@ OPTIONS --latency:: Print out the latency the IOCTL took (in us). +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * The following will run the admin command with opcode=6 and cdw10=1, which diff --git a/Documentation/nvme-ana-log.1 b/Documentation/nvme-ana-log.1 index 34f432714f..eb3042a917 100644 --- a/Documentation/nvme-ana-log.1 +++ b/Documentation/nvme-ana-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-ana-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ANA\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ANA\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,8 @@ nvme-ana-log \- Send NVMe ANA log page request, returns result and log .SH "SYNOPSIS" .sp .nf -\fInvme ana\-log\fR [\-o | \-\-output\-format=] +\fInvme ana\-log\fR [\-\-groups | \-g] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -48,13 +49,19 @@ On success, the returned ANA log structure may be returned in one of several way Return the list of ANA groups without the namespace listing\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-ana-log.html b/Documentation/nvme-ana-log.html index a6bc46cd85..2adec9ff46 100644 --- a/Documentation/nvme-ana-log.html +++ b/Documentation/nvme-ana-log.html @@ -749,7 +749,8 @@

NAME

SYNOPSIS

-
nvme ana-log <device> [-o <fmt> | --output-format=<fmt>]
+
nvme ana-log <device> [--groups | -g]
+                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -778,19 +779,30 @@

OPTIONS

- Return the list of ANA groups without the namespace listing. + Return the list of ANA groups without the namespace listing.

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

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

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

+ Increase the information detail in the output.

@@ -823,7 +835,7 @@

NVME

diff --git a/Documentation/nvme-ana-log.txt b/Documentation/nvme-ana-log.txt index b6dc9c5861..92dc12a03c 100644 --- a/Documentation/nvme-ana-log.txt +++ b/Documentation/nvme-ana-log.txt @@ -8,7 +8,8 @@ nvme-ana-log - Send NVMe ANA log page request, returns result and log SYNOPSIS -------- [verse] -'nvme ana-log' [-o | --output-format=] +'nvme ana-log' [--groups | -g] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -26,12 +27,16 @@ OPTIONS ------- -g:: --groups:: - Return the list of ANA groups without the namespace listing. + Return the list of ANA groups without the namespace listing. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-attach-ns.1 b/Documentation/nvme-attach-ns.1 index cfa5f85361..0eb5c2c7a2 100644 --- a/Documentation/nvme-attach-ns.1 +++ b/Documentation/nvme-attach-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-attach-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ATTACH\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ATTACH\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,6 +34,7 @@ nvme-attach-ns \- Send NVMe attach namespace, return result\&. .nf \fInvme attach\-ns\fR [\-\-namespace\-id= | \-n ] [\-\-controllers= | \-c ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -49,6 +50,20 @@ The namespace identifier to attach\&. .RS 4 The comma separated list of controller identifiers to attach the namespace too\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .if n \{\ @@ -65,7 +80,7 @@ Attach namespace to the controller: .RS 4 .\} .nf -# nvme attach\-ns /dev/nvme1 \-n 0x2 \-c 0x21 +# nvme attach\-ns /dev/nvme1 \-n 0x2 \-c 0x21 .fi .if n \{\ .RE diff --git a/Documentation/nvme-attach-ns.html b/Documentation/nvme-attach-ns.html index 55eb72e30a..eae3957f86 100644 --- a/Documentation/nvme-attach-ns.html +++ b/Documentation/nvme-attach-ns.html @@ -750,7 +750,8 @@

SYNOPSIS

nvme attach-ns <device> [--namespace-id=<nsid> | -n <nsid>]
-                        [--controllers=<ctrl-list,> | -c <ctrl-list,>]
+ [--controllers=<ctrl-list,> | -c <ctrl-list,>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -790,6 +791,29 @@

OPTIONS

the namespace too.

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

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

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

+ Increase the information detail in the output. +

+
@@ -802,7 +826,7 @@

EXAMPLES

-
# nvme attach-ns /dev/nvme1  -n 0x2 -c 0x21
+
# nvme attach-ns /dev/nvme1 -n 0x2 -c 0x21
@@ -817,7 +841,7 @@

NVME

diff --git a/Documentation/nvme-attach-ns.txt b/Documentation/nvme-attach-ns.txt index 64ab9d1a8e..601c20df30 100644 --- a/Documentation/nvme-attach-ns.txt +++ b/Documentation/nvme-attach-ns.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'nvme attach-ns' [--namespace-id= | -n ] [--controllers= | -c ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -28,11 +29,20 @@ OPTIONS The comma separated list of controller identifiers to attach the namespace too. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- Attach namespace to the controller: - # nvme attach-ns /dev/nvme1 -n 0x2 -c 0x21 + # nvme attach-ns /dev/nvme1 -n 0x2 -c 0x21 NVME ---- diff --git a/Documentation/nvme-boot-part-log.1 b/Documentation/nvme-boot-part-log.1 index 8c08712346..6bbd3a331f 100644 --- a/Documentation/nvme-boot-part-log.1 +++ b/Documentation/nvme-boot-part-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-boot-part-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-BOOT\-PART\-LO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-BOOT\-PART\-LO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,8 +33,8 @@ nvme-boot-part-log \- Retrieves a Boot Partition log page from an NVMe device .sp .nf \fInvme boot\-part\-log\fR [\-\-lsp= | \-s ] - [\-\-output\-file= | \-o ] - [\-\-output\-format= | \-o ] + [\-\-output\-file= | \-f ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -50,18 +50,24 @@ On success, the returned log structure will be in raw binary format \fIonly\fR w The log specified field of LID\&. .RE .PP -\-o , \-\-output\-file= +\-f , \-\-output\-file= .RS 4 File name to which raw binary data will be saved to\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-boot-part-log.html b/Documentation/nvme-boot-part-log.html index ae7bafb7b6..64a79e5334 100644 --- a/Documentation/nvme-boot-part-log.html +++ b/Documentation/nvme-boot-part-log.html @@ -750,8 +750,8 @@

SYNOPSIS

nvme boot-part-log <device> [--lsp=<field> | -s <field>]
-                    [--output-file=<file> | -o <file>]
-                    [--output-format=<fmt> | -o <fmt>]
+ [--output-file=<file> | -f <file>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -783,7 +783,7 @@

OPTIONS

--o <file> +-f <file>
--output-file=<file> @@ -794,15 +794,26 @@

OPTIONS

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

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

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

+ Increase the information detail in the output.

@@ -835,7 +846,7 @@

NVME

diff --git a/Documentation/nvme-boot-part-log.txt b/Documentation/nvme-boot-part-log.txt index 2dd32a67b1..0999071503 100644 --- a/Documentation/nvme-boot-part-log.txt +++ b/Documentation/nvme-boot-part-log.txt @@ -9,8 +9,8 @@ SYNOPSIS -------- [verse] 'nvme boot-part-log' [--lsp= | -s ] - [--output-file= | -o ] - [--output-format= | -o ] + [--output-file= | -f ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -29,14 +29,18 @@ OPTIONS --lsp=:: The log specified field of LID. --o :: +-f :: --output-file=:: File name to which raw binary data will be saved to. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-capacity-mgmt.1 b/Documentation/nvme-capacity-mgmt.1 index 425327f42c..19593c4415 100644 --- a/Documentation/nvme-capacity-mgmt.1 +++ b/Documentation/nvme-capacity-mgmt.1 @@ -2,12 +2,12 @@ .\" Title: nvme-capacity-mgmt .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-CAPACITY\-MGMT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-CAPACITY\-MGMT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,10 +32,11 @@ nvme-capacity-mgmt \- Send capacity management command to configure/create/delet .SH "SYNOPSIS" .sp .nf -\fInvme capacity\-mgmt\fR [\-\-operation= | \-o ] +\fInvme capacity\-mgmt\fR [\-\-operation= | \-O ] [\-\-element\-id= | \-i ] [\-\-cap\-lower= | \-l ] [\-\-cap\-upper= | \-u ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -44,7 +45,7 @@ For the NVMe device given, sends a capacity management command to configure/crea The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. .SH "OPTIONS" .PP -\-o , \-\-operation= +\-O , \-\-operation= .RS 4 Operation to be performed by the controller .RE @@ -63,6 +64,20 @@ Least significant 32 bits of the capacity in bytes of the Endurance Group or NVM .RS 4 Most significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples provided yet\&. diff --git a/Documentation/nvme-capacity-mgmt.html b/Documentation/nvme-capacity-mgmt.html index 519a288c83..29cc903f6e 100644 --- a/Documentation/nvme-capacity-mgmt.html +++ b/Documentation/nvme-capacity-mgmt.html @@ -740,7 +740,7 @@

NAME

nvme-capacity-mgmt - - Send capacity management command to configure/create/delete Endurance Groups or NVM Sets, returns results. + Send capacity management command to configure/create/delete Endurance Groups or NVM Sets, returns results.

@@ -749,10 +749,11 @@

NAME

SYNOPSIS

-
nvme capacity-mgmt <device> [--operation=<operation> | -o <operation>]
+
nvme capacity-mgmt <device> [--operation=<operation> | -O <operation>]
                         [--element-id=<element-id> | -i <element-id>]
                         [--cap-lower=<cap-lower> | -l <cap-lower>]
-                        [--cap-upper=<cap-upper> | -u <cap-upper>]
+ [--cap-upper=<cap-upper> | -u <cap-upper>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -774,14 +775,14 @@

OPTIONS

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

- Operation to be performed by the controller + Operation to be performed by the controller

@@ -792,7 +793,7 @@

OPTIONS

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

@@ -804,7 +805,7 @@

OPTIONS

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

@@ -816,7 +817,30 @@

OPTIONS

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

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

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

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

+ Increase the information detail in the output.

@@ -839,7 +863,7 @@

NVME

diff --git a/Documentation/nvme-capacity-mgmt.txt b/Documentation/nvme-capacity-mgmt.txt index 96274cf0f2..a20561f049 100644 --- a/Documentation/nvme-capacity-mgmt.txt +++ b/Documentation/nvme-capacity-mgmt.txt @@ -4,15 +4,16 @@ nvme-capacity-mgmt(1) NAME ---- nvme-capacity-mgmt - Send capacity management command to configure/create/delete - Endurance Groups or NVM Sets, returns results. +Endurance Groups or NVM Sets, returns results. SYNOPSIS -------- [verse] -'nvme capacity-mgmt' [--operation= | -o ] +'nvme capacity-mgmt' [--operation= | -O ] [--element-id= | -i ] [--cap-lower= | -l ] [--cap-upper= | -u ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -27,23 +28,32 @@ device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). OPTIONS ------- --o :: +-O :: --operation=:: - Operation to be performed by the controller + Operation to be performed by the controller -i :: --element-id=:: - Value specific to the value of the Operation field. + Value specific to the value of the Operation field. -l :: --cap-lower=:: Least significant 32 bits of the capacity in bytes of the Endurance Group or - NVM Set to be created + NVM Set to be created -u :: --cap-upper=:: Most significant 32 bits of the capacity in bytes of the Endurance Group or - NVM Set to be created + NVM Set to be created + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-changed-ns-list-log.1 b/Documentation/nvme-changed-ns-list-log.1 index 7d1cbb3f83..2ab0d3bc01 100644 --- a/Documentation/nvme-changed-ns-list-log.1 +++ b/Documentation/nvme-changed-ns-list-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-changed-ns-list-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-CHANGED\-NS\-L" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-CHANGED\-NS\-L" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-changed-ns-list-log \- Send NVMe Changed Namespace List log page request, r .sp .nf \fInvme changed\-ns\-list\-log\fR [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -49,13 +49,19 @@ On success, the returned Changed Namespace List log structure may be returned in Print the raw Changed Namespace List log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-changed-ns-list-log.html b/Documentation/nvme-changed-ns-list-log.html index 08bb4d5d68..2b7aa2869c 100644 --- a/Documentation/nvme-changed-ns-list-log.html +++ b/Documentation/nvme-changed-ns-list-log.html @@ -740,7 +740,7 @@

NAME

nvme-changed-ns-list-log - - Send NVMe Changed Namespace List log page request, returns result and log. + Send NVMe Changed Namespace List log page request, returns result and log.

@@ -750,7 +750,7 @@

SYNOPSIS

nvme changed-ns-list-log <device> [--raw-binary | -b]
-                        [--output-format=<fmt> | -o <fmt>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -784,15 +784,26 @@

OPTIONS

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

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

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

+ Increase the information detail in the output.

@@ -835,7 +846,7 @@

NVME

diff --git a/Documentation/nvme-changed-ns-list-log.txt b/Documentation/nvme-changed-ns-list-log.txt index 4cfd065314..22e552f650 100644 --- a/Documentation/nvme-changed-ns-list-log.txt +++ b/Documentation/nvme-changed-ns-list-log.txt @@ -4,13 +4,13 @@ nvme-changed-ns-list-log(1) NAME ---- nvme-changed-ns-list-log - Send NVMe Changed Namespace List log page - request, returns result and log. +request, returns result and log. SYNOPSIS -------- [verse] 'nvme changed-ns-list-log' [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -31,10 +31,14 @@ OPTIONS --raw-binary:: Print the raw Changed Namespace List log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-check-dhchap-key.txt b/Documentation/nvme-check-dhchap-key.txt index 9cfa1f7307..b131afecd0 100644 --- a/Documentation/nvme-check-dhchap-key.txt +++ b/Documentation/nvme-check-dhchap-key.txt @@ -8,7 +8,8 @@ nvme-check-dhchap-key - Check a generated host DH-HMAC-CHAP key SYNOPSIS -------- [verse] -'nvme check-dhchap-key' [--key= ] +'nvme check-dhchap-key' [--key=] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -22,6 +23,15 @@ OPTIONS --key=:: Key to be checked. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No Examples diff --git a/Documentation/nvme-check-tls-key.txt b/Documentation/nvme-check-tls-key.txt index 9ef6679ba4..2df4fcad3b 100644 --- a/Documentation/nvme-check-tls-key.txt +++ b/Documentation/nvme-check-tls-key.txt @@ -8,20 +8,68 @@ nvme-check-tls-key - Check a generated NVMe TLS PSK SYNOPSIS -------- [verse] -'nvme check-tls-key' [--key= ] +'nvme check-tls-key' [--keyring= | -k ] + [--keytype= | -t ] + [--hostnqn= | -n ] + [--subsysnqn= | -c ] + [--keydata= | -d ] + [--output-format= | -o ] + [--identity= | -I ] + [--insert | -i ] + [--verbose | -v] DESCRIPTION ----------- Checks if the key is a valid NVMe TLS PSK in the PSK interchange format -NVMeTLSkey-1:01:VRLbtnN9AQb2WXW3c9+wEf/DRLz0QuLdbYvEhwtdWwNf9LrZ: - +'NVMeTLSkey-1:01::'. If '--insert' is specified the +the derived 'retained' TLS key is stored in the keyring, otherwise the +TLS identity of the key is printed out. OPTIONS ------- --k :: ---key=:: +-k :: +--keyring=:: + Name of the keyring into which the 'retained' TLS key should be + stored. Default is '.nvme'. + +-t :: +--keytype=:: + Type of the key for resulting TLS key. + Default is 'psk'. + +-n :: +--hostnqn=:: + Host NVMe Qualified Name (NQN) to be used to derive the + 'retained' TLS key + +-c :: +--subsysnqn=:: + Subsystem NVMe Qualified Name (NQN) to be used to derive the + 'retained' TLS key + +-d :: +--keydata=:: Key to be checked. +-I :: +--identity=:: + NVMe TLS key identity version to be used; '0' for the default + identity, and '1' for the TLS identity suffixed by the PSK hash + as specified in TP8018. + +-i: +--insert: + Insert the derived 'retained' key in the keyring. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No Examples diff --git a/Documentation/nvme-cmdset-ind-id-ns.1 b/Documentation/nvme-cmdset-ind-id-ns.1 index 263f760b26..7d6053d455 100644 --- a/Documentation/nvme-cmdset-ind-id-ns.1 +++ b/Documentation/nvme-cmdset-ind-id-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-cmdset-ind-id-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-CMDSET\-IND\-I" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-CMDSET\-IND\-I" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,9 +33,8 @@ nvme-cmdset-ind-id-ns \- Send NVMe I/O Command Set Independent Identify Namespac .sp .nf \fInvme cmdset\-ind\-id\-ns\fR [\-\-namespace\-id= | \-n ] - [\-b | \-\-raw\-binary] - [\-\-human\-readable | \-H] - [\-\-output\-format= | \-o ] + [\-\-raw\-binary | \-b] [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -61,13 +60,19 @@ Print the raw buffer to stdout\&. Structure is not parsed by program\&. This ove This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-cmdset-ind-id-ns.html b/Documentation/nvme-cmdset-ind-id-ns.html index 7ef0bb3d1b..59a36f0a61 100644 --- a/Documentation/nvme-cmdset-ind-id-ns.html +++ b/Documentation/nvme-cmdset-ind-id-ns.html @@ -750,9 +750,8 @@

SYNOPSIS

nvme cmdset-ind-id-ns <device> [--namespace-id=<nsid> | -n <nsid>]
-                        [-b | --raw-binary]
-                    [--human-readable | -H]
-                    [--output-format=<fmt> | -o <fmt>]
+ [--raw-binary | -b] [--human-readable | -H] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -815,15 +814,26 @@

OPTIONS

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

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

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

+ Increase the information detail in the output.

@@ -879,7 +889,7 @@

NVME

diff --git a/Documentation/nvme-cmdset-ind-id-ns.txt b/Documentation/nvme-cmdset-ind-id-ns.txt index fa55c8335b..5bf3862f13 100644 --- a/Documentation/nvme-cmdset-ind-id-ns.txt +++ b/Documentation/nvme-cmdset-ind-id-ns.txt @@ -9,9 +9,8 @@ SYNOPSIS -------- [verse] 'nvme cmdset-ind-id-ns' [--namespace-id= | -n ] - [-b | --raw-binary] - [--human-readable | -H] - [--output-format= | -o ] + [--raw-binary | -b] [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -47,11 +46,14 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-compare.1 b/Documentation/nvme-compare.1 index e58cacd2dd..68b0f75674 100644 --- a/Documentation/nvme-compare.1 +++ b/Documentation/nvme-compare.1 @@ -2,12 +2,12 @@ .\" Title: nvme-compare .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-COMPARE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-COMPARE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -47,11 +47,13 @@ nvme-compare \- Send an NVMe Compare command, provide results [\-\-dir\-type= | \-T ] [\-\-dir\-spec= | \-S ] [\-\-dsm= | \-D ] - [\-\-show\-command | \-v] + [\-\-show\-command | \-V] [\-\-dry\-run | \-w] [\-\-latency | \-t] - [\-\-storage\-tag\-check | \-C ] + [\-\-storage\-tag | \-g ] + [\-\-storage\-tag\-check | \-C] [\-\-force] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -96,9 +98,6 @@ Metadata file\&. \-p , \-\-prinfo= .RS 4 Protection Information and check field\&. -.RE -.sp -+ .TS allbox tab(:); lt lt @@ -108,49 +107,38 @@ 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 +.RE .PP \-m , \-\-app\-tag\-mask= .RS 4 @@ -187,7 +175,7 @@ Optional field for directive specifics\&. When used with write streams, this val The optional data set management attributes for this command\&. The argument for this is the least significant 8 bits of the DSM field in a write command; the most significant 16 bits of the field come from the directive specific field, if used\&. This may be used to set attributes for the LBAs being written, like access frequency, type, latency, among other things, as well as yet to be defined types\&. Please consult the NVMe specification for detailed breakdown of how to use this field\&. .RE .PP -\-v, \-\-show\-cmd +\-V, \-\-show\-cmd .RS 4 Print out the command to be sent\&. .RE @@ -205,15 +193,34 @@ be set\&. Otherwise \-\-dry\-run option will be Print out the latency the IOCTL took (in us)\&. .RE .PP -\-\-storage\-tag\-check=, \-C +\-g , \-\-storage\-tag= +.RS 4 +Variable Sized Expected Logical Block Storage Tag(ELBST)\&. +.RE +.PP +\-C, \-\-storage\-tag\-check .RS 4 -This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +This flag enables Storage Tag field checking as part of end\-to\-end data protection processing\&. .RE .PP \-\-force .RS 4 Ignore namespace is currently busy and performed the operation even though\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-compare.html b/Documentation/nvme-compare.html index 93204a6c39..e05cb8ae50 100644 --- a/Documentation/nvme-compare.html +++ b/Documentation/nvme-compare.html @@ -764,11 +764,13 @@

SYNOPSIS

[--dir-type=<type> | -T <type>] [--dir-spec=<spec> | -S <spec>] [--dsm=<dsm> | -D <dsm>] - [--show-command | -v] + [--show-command | -V] [--dry-run | -w] [--latency | -t] - [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>] - [--force] + [--storage-tag<storage-tag> | -g <storage-tag>] + [--storage-tag-check | -C] + [--force] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -876,9 +878,6 @@

OPTIONS

Protection Information and check field.

- - -

+

OPTIONS
-
+
-m <appmask>
@@ -1008,7 +1007,7 @@

OPTIONS

--v +-V
--show-cmd @@ -1043,14 +1042,25 @@

OPTIONS

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

- This bit specifies the Storage Tag field shall be checked as part of end-to-end + Variable Sized Expected Logical Block Storage Tag(ELBST). +

+
+
+-C +
+
+--storage-tag-check +
+
+

+ This flag enables Storage Tag field checking as part of end-to-end data protection processing.

@@ -1059,8 +1069,31 @@

OPTIONS

- Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. +

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

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

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

+ Increase the information detail in the output.

@@ -1083,7 +1116,7 @@

NVME

diff --git a/Documentation/nvme-compare.txt b/Documentation/nvme-compare.txt index 11299bd783..59d1ea9cea 100644 --- a/Documentation/nvme-compare.txt +++ b/Documentation/nvme-compare.txt @@ -23,11 +23,13 @@ SYNOPSIS [--dir-type= | -T ] [--dir-spec= | -S ] [--dsm= | -D ] - [--show-command | -v] + [--show-command | -V] [--dry-run | -w] [--latency | -t] - [--storage-tag-check | -C ] + [--storage-tag | -g ] + [--storage-tag-check | -C] [--force] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -72,7 +74,6 @@ OPTIONS -p :: --prinfo=:: Protection Information and check field. - + [] |================= @@ -126,7 +127,7 @@ metadata is passes. 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:: +-V:: --show-cmd:: Print out the command to be sent. @@ -140,14 +141,27 @@ metadata is passes. --latency:: Print out the latency the IOCTL took (in us). ---storage-tag-check=:: --C :: - This bit specifies the Storage Tag field shall be checked as part of end-to-end +-g :: +--storage-tag=:: + Variable Sized Expected Logical Block Storage Tag(ELBST). + +-C:: +--storage-tag-check:: + This flag enables Storage Tag field checking as part of end-to-end data protection processing. --force:: - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-config.txt b/Documentation/nvme-config.txt index 5b769258eb..8a66644754 100644 --- a/Documentation/nvme-config.txt +++ b/Documentation/nvme-config.txt @@ -8,40 +8,35 @@ nvme-config - NVMe-over-Fabrics configuration. SYNOPSIS -------- [verse] -'nvme config' - [--scan | -R] - [--modify | -M] - [--update | -U] - [--dump | -O] - [--config= | -J ] - [--transport= | -t ] - [--nqn= | -n ] - [--traddr= | -a ] - [--trsvcid= | -s ] - [--host-traddr= | -w ] - [--host-iface= | -f ] - [--hostnqn= | -q ] - [--hostid= | -I ] - [--dhchap-secret= | -S ] - [--dhchap-ctrl-secret= | -C ] - [--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] +'nvme config' [--scan | -R] [--modify | -M] [--update | -U] [--dump | -O] + [--config= | -J ] + [--transport= | -t ] + [--nqn= | -n ] + [--traddr= | -a ] + [--trsvcid= | -s ] + [--host-traddr= | -w ] + [--host-iface= | -f ] + [--hostnqn= | -q ] + [--hostid= | -I ] + [--dhchap-secret= | -S ] + [--dhchap-ctrl-secret= | -C ] + [--nr-io-queues=<#> | -i <#>] + [--nr-write-queues=<#> | -W <#>] + [--nr-poll-queues=<#> | -P <#>] + [--queue-size=<#> | -Q <#>] + [--keep-alive-tmo=<#> | -k <#>] + [--reconnect-delay=<#> | -c <#>] + [--ctrl-loss-tmo=<#> | -l <#>] + [--duplicate-connect | -D] [--disable-sqflow | -d] + [--hdr-digest | -g] [--data-digest | -G] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- Read in the NVMe over Fabrics configuration from the specified JSON configuration file and allow to update or modify the contents. The JSON configuration file format is documented in -https://github.com/linux-nvme/libnvme/doc/config-schema.json +https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json OPTIONS ------- @@ -52,7 +47,7 @@ OPTIONS -M:: --modify:: Add or modify entries in the configuration based on the values from - the commandline. + the commandline. -U:: --update:: @@ -71,7 +66,7 @@ OPTIONS -t :: --transport=:: This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + a NVMe-over-Fabrics network. Current string values include: + [] |================= @@ -94,7 +89,7 @@ OPTIONS -s :: --trsvcid=:: - This field specifies the transport service id. For transports using IP + 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. @@ -186,6 +181,15 @@ OPTIONS --data-digest:: Generates/verifies data digest (TCP). +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Read the current system configuration and write the contents to /tmp/config.json: @@ -198,8 +202,7 @@ SEE ALSO -------- nvme-discover(1) nvme-connect(1) -https://github.com/linux-nvme/libnvme/doc/config-schema.json - +https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json AUTHORS ------- diff --git a/Documentation/nvme-connect-all.1 b/Documentation/nvme-connect-all.1 index 57762ed641..3ee4f6db16 100644 --- a/Documentation/nvme-connect-all.1 +++ b/Documentation/nvme-connect-all.1 @@ -2,12 +2,12 @@ .\" Title: nvme-connect-all .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-CONNECT\-ALL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-CONNECT\-ALL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,35 +32,35 @@ nvme-connect-all \- Discover and Connect to Fabrics controllers\&. .SH "SYNOPSIS" .sp .nf -\fInvme connect\-all\fR - [\-\-transport= | \-t ] - [\-\-nqn= | \-n ] - [\-\-traddr= | \-a ] - [\-\-trsvcid= | \-s ] - [\-\-host\-traddr= | \-w ] - [\-\-host\-iface= | \-f ] - [\-\-hostnqn= | \-q ] - [\-\-hostid= | \-I ] - [\-\-raw= | \-r ] - [\-\-cfg\-file= | \-C ] - [\-\-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 <#>] - [\-\-persistent | \-p] - [\-\-quiet | \-S] - [\-\-dump\-config | \-O] +\fInvme connect\-all\fR [\-\-transport= | \-t ] + [\-\-nqn= | \-n ] + [\-\-traddr= | \-a ] + [\-\-trsvcid= | \-s ] + [\-\-host\-traddr= | \-w ] + [\-\-host\-iface= | \-f ] + [\-\-hostnqn= | \-q ] + [\-\-hostid= | \-I ] + [\-\-raw= | \-r ] + [\-\-device= | \-d ] + [\-\-config= | \-J ] + [\-\-keep\-alive\-tmo= | \-k ] + [\-\-reconnect\-delay=<#> | \-c <#>] + [\-\-ctrl\-loss\-tmo=<#> | \-l <#>] + [\-\-nr\-io\-queues=<#> | \-i <#>] + [\-\-nr\-write\-queues=<#> | \-W <#>] + [\-\-nr\-poll\-queues=<#> | \-P <#>] + [\-\-queue\-size=<#> | \-Q <#>] [\-\-keyring=<#>] + [\-\-tls_key=<#>] [\-\-hdr\-digest | \-g] [\-\-data\-digest | \-G] + [\-\-persistent | \-p] [\-\-tls] [\-\-concat] [\-\-quiet | \-S] + [\-\-dump\-config | \-O] [\-\-nbft] [\-\-no\-nbft] + [\-\-nbft\-path=] [\-\-context=] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Send one or more Discovery requests to a NVMe over Fabrics Discovery Controller, and create controllers for the returned discovery records\&. .sp -If no parameters are given, then \fInvme connect\-all\fR will attempt to find a /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\&. +If no parameters are given, then \fInvme connect\-all\fR will attempt to find a /usr/local/etc/nvme/discovery\&.conf file to use to supply a list of connect\-all commands to run\&. If no /usr/local/etc/nvme/discovery\&.conf file exists, the command will quit with an error\&. .sp Otherwise a specific Discovery Controller should be specified using the \-\-transport, \-\-traddr and if necessary the \-\-trsvcid and a Discovery request will be sent to the specified Discovery Controller\&. .sp @@ -134,7 +134,7 @@ This field specifies the network interface used on the host to connect to the Co .PP \-q , \-\-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\&. +Overrides the default Host NQN that identifies the NVMe Host\&. If this option is not specified, the default is read from /usr/local/etc/nvme/hostnqn first\&. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next\&. The Host NQN uniquely identifies the NVMe Host, and may be used by the the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection\&. .RE .PP \-I , \-\-hostid= @@ -151,12 +151,17 @@ command and dump it to a raw binary file\&. By default will dump the output to stdout\&. .RE .PP -\-C , \-\-config\-file= +\-d , \-\-device= +.RS 4 +This field takes a device as input\&. It must be a persistent device associated with a Discovery Controller previously created by the command "connect\-all" or "discover"\&. follows the format nvme*, eg\&. nvme0, nvme1\&. +.RE +.PP +\-J , \-\-config= .RS 4 -Use the specified JSON configuration file instead of the default /etc/nvme/config\&.json file or +Use the specified JSON configuration file instead of the default /usr/local/etc/nvme/config\&.json file or \fInone\fR to not read in an existing configuration file\&. The JSON configuration file format is documented in -\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/doc/config\-schema\&.json\fR\m[] +\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/blob/master/doc/config\-schema\&.json\fR\m[] .RE .PP \-k <#>, \-\-keep\-alive\-tmo=<#> @@ -174,16 +179,6 @@ Overrides the default delay (in seconds) before reconnect is attempted after a c 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\&. @@ -204,11 +199,41 @@ Adds additional queues that will be used for polling latency sensitive I/O\&. Overrides the default number of elements in the I/O queues created by the driver\&. This option will be ignored for discovery, but will be passed on to the subsequent connect call\&. .RE .PP +\-\-keyring=<#> +.RS 4 +Keyring for TLS key lookup\&. +.RE +.PP +\-\-tls_key=<#> +.RS 4 +TLS key for the connection (TCP)\&. +.RE +.PP +\-g, \-\-hdr\-digest +.RS 4 +Generates/verifies header digest (TCP)\&. +.RE +.PP +\-G, \-\-data\-digest +.RS 4 +Generates/verifies data digest (TCP)\&. +.RE +.PP \-p, \-\-persistent .RS 4 Don\(cqt remove the discovery controller after retrieving the discovery log page\&. .RE .PP +\-\-tls +.RS 4 +Enable TLS encryption (TCP)\&. +.RE +.PP +\-\-concat +.RS 4 +Enable secure concatenation (TCP)\&. +.RE +.PP \-S, \-\-quiet .RS 4 Suppress error messages\&. @@ -218,6 +243,40 @@ Suppress error messages\&. .RS 4 Print out resulting JSON configuration file to stdout\&. .RE +.PP +\-\-nbft +.RS 4 +Only look at NBFT tables +.RE +.PP +\-\-no\-nbft +.RS 4 +Do not look at NBFT tables +.RE +.PP +\-\-nbft\-path= +.RS 4 +Use a user\-defined path to the NBFT tables +.RE +.PP +\-\-context +.RS 4 +Set the execution context to \&. This allows to coordinate the management of the global resources\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 @@ -252,15 +311,61 @@ Connect to all records returned by the Discover Controller with IP4 address 192\ .\} Issue a \fInvme connect\-all\fR -command using a /etc/nvme/discovery\&.conf file: +command using the default system defined NBFT tables: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme connect\-all \-\-nbft +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Issue a +\fInvme connect\-all\fR +command with a user\-defined path for the NBFT table: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme connet\-all \-\-nbft\-path=/sys/firmware/acpi/tables/NBFT1 +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Issue a +\fInvme connect\-all\fR +command using a /usr/local/etc/nvme/discovery\&.conf file: .sp .if n \{\ .RS 4 .\} .nf -# Machine default \*(Aqnvme discover\*(Aq commands\&. Query the +# 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 +# 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 diff --git a/Documentation/nvme-connect-all.html b/Documentation/nvme-connect-all.html index f0fa62e2d4..5a3ef231ac 100644 --- a/Documentation/nvme-connect-all.html +++ b/Documentation/nvme-connect-all.html @@ -749,29 +749,29 @@

NAME

SYNOPSIS

-
nvme connect-all
-                [--transport=<trtype>     | -t <trtype>]
-                [--nqn=<subnqn>           | -n <subnqn>]
-                [--traddr=<traddr>        | -a <traddr>]
-                [--trsvcid=<trsvcid>      | -s <trsvcid>]
-                [--host-traddr=<traddr>   | -w <traddr>]
-                [--host-iface=<iface>     | -f <iface>]
-                [--hostnqn=<hostnqn>      | -q <hostnqn>]
-                [--hostid=<hostid>        | -I <hostid>]
-                [--raw=<filename>         | -r <filename>]
-                [--cfg-file=<cfg>         | -C <cfg>]
-                [--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 <#>]
-                [--persistent             | -p]
-                [--quiet                  | -S]
-                [--dump-config            | -O]
+
nvme connect-all [--transport=<trtype> | -t <trtype>]
+                        [--nqn=<subnqn> | -n <subnqn>]
+                        [--traddr=<traddr> | -a <traddr>]
+                        [--trsvcid=<trsvcid> | -s <trsvcid>]
+                        [--host-traddr=<traddr> | -w <traddr>]
+                        [--host-iface=<iface> | -f <iface>]
+                        [--hostnqn=<hostnqn> | -q <hostnqn>]
+                        [--hostid=<hostid> | -I <hostid>]
+                        [--raw=<filename> | -r <filename>]
+                        [--device=<device> | -d <device>]
+                        [--config=<filename> | -J <cfg>]
+                        [--keep-alive-tmo=<sec> | -k <sec>]
+                        [--reconnect-delay=<#> | -c <#>]
+                        [--ctrl-loss-tmo=<#>     | -l <#>]
+                        [--nr-io-queues=<#> | -i <#>]
+                        [--nr-write-queues=<#> | -W <#>]
+                        [--nr-poll-queues=<#> | -P <#>]
+                        [--queue-size=<#> | -Q <#>] [--keyring=<#>]
+                        [--tls_key=<#>] [--hdr-digest | -g] [--data-digest | -G]
+                        [--persistent | -p] [--tls] [--concat] [--quiet | -S]
+                        [--dump-config | -O] [--nbft] [--no-nbft]
+                        [--nbft-path=<STR>] [--context=<STR>]
+                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
@@ -782,8 +782,8 @@

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 +find a /usr/local/etc/nvme/discovery.conf file to use to supply a list of +connect-all commands to run. If no /usr/local/etc/nvme/discovery.conf file exists, the command will quit with an error.

Otherwise a specific Discovery Controller should be specified using the --transport, --traddr and if necessary the --trsvcid and a Discovery @@ -805,7 +805,7 @@

OPTIONS

This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + a NVMe-over-Fabrics network. Current string values include:

OPTIONS

- This field specifies the transport service id. For transports using IP + 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.

@@ -912,7 +912,7 @@

OPTIONS

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 + /usr/local/etc/nvme/hostnqn first. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next. The Host NQN uniquely identifies the NVMe Host, and may be used by the the Discovery Controller to control what NVMe Target resources are @@ -945,18 +945,32 @@

OPTIONS

--C <cfg> +-d <device>
---config-file=<cfg> +--device=<device> +
+
+

+ This field takes a device as input. It must be a persistent device + associated with a Discovery Controller previously created by the + command "connect-all" or "discover". <device> follows the format + nvme*, eg. nvme0, nvme1. +

+
+
+-J <filename> +
+
+--config=<filename>

Use the specified JSON configuration file instead of the - default /etc/nvme/config.json file or none to not read in + default /usr/local/etc/nvme/config.json file or none to not read in an existing configuration file. The JSON configuration file format is documented in - https://github.com/linux-nvme/libnvme/doc/config-schema.json + https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json

@@ -996,28 +1010,6 @@

OPTIONS

--g -
-
---hdr-digest -
-
-

- Generates/verifies header digest (TCP). -

-
-
--G -
-
---data-digest -
-
-

- Generates/verifies data digest (TCP). -

-
-
-i <#>
@@ -1066,6 +1058,44 @@

OPTIONS

+--keyring=<#> +
+
+

+ Keyring for TLS key lookup. +

+
+
+--tls_key=<#> +
+
+

+ TLS key for the connection (TCP). +

+
+
+-g +
+
+--hdr-digest +
+
+

+ Generates/verifies header digest (TCP). +

+
+
+-G +
+
+--data-digest +
+
+

+ Generates/verifies data digest (TCP). +

+
+
-p
@@ -1078,6 +1108,22 @@

OPTIONS

+--tls +
+
+

+ Enable TLS encryption (TCP). +

+
+
+--concat +
+
+

+ Enable secure concatenation (TCP). +

+
+
-S
@@ -1099,6 +1145,62 @@

OPTIONS

Print out resulting JSON configuration file to stdout.

+
+--nbft +
+
+

+ Only look at NBFT tables +

+
+
+--no-nbft +
+
+

+ Do not look at NBFT tables +

+
+
+--nbft-path=<STR> +
+
+

+ Use a user-defined path to the NBFT tables +

+
+
+--context <STR> +
+
+

+ Set the execution context to <STR>. This allows to coordinate + the management of the global resources. +

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

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

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

+ Increase the information detail in the output. +

+
@@ -1120,13 +1222,31 @@

EXAMPLES

  • -Issue a nvme connect-all command using a /etc/nvme/discovery.conf file: +Issue a nvme connect-all command using the default system defined NBFT tables: +

    +
    +
    +
    # nvme connect-all --nbft
    +
    +
  • +
  • +

    +Issue a nvme connect-all command with a user-defined path for the NBFT table: +

    +
    +
    +
    # nvme connet-all --nbft-path=/sys/firmware/acpi/tables/NBFT1
    +
    +
  • +
  • +

    +Issue a nvme connect-all command using a /usr/local/etc/nvme/discovery.conf file:

    -
    # Machine default 'nvme discover' commands.  Query the
    +
    # 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
    +# 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
    @@ -1156,7 +1276,7 @@ 

    NVME

    diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt index b449955d52..4cd1873426 100644 --- a/Documentation/nvme-connect-all.txt +++ b/Documentation/nvme-connect-all.txt @@ -8,29 +8,29 @@ nvme-connect-all - Discover and Connect to Fabrics controllers. SYNOPSIS -------- [verse] -'nvme connect-all' - [--transport= | -t ] - [--nqn= | -n ] - [--traddr= | -a ] - [--trsvcid= | -s ] - [--host-traddr= | -w ] - [--host-iface= | -f ] - [--hostnqn= | -q ] - [--hostid= | -I ] - [--raw= | -r ] - [--cfg-file= | -C ] - [--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 <#>] - [--persistent | -p] - [--quiet | -S] - [--dump-config | -O] +'nvme connect-all' [--transport= | -t ] + [--nqn= | -n ] + [--traddr= | -a ] + [--trsvcid= | -s ] + [--host-traddr= | -w ] + [--host-iface= | -f ] + [--hostnqn= | -q ] + [--hostid= | -I ] + [--raw= | -r ] + [--device= | -d ] + [--config= | -J ] + [--keep-alive-tmo= | -k ] + [--reconnect-delay=<#> | -c <#>] + [--ctrl-loss-tmo=<#> | -l <#>] + [--nr-io-queues=<#> | -i <#>] + [--nr-write-queues=<#> | -W <#>] + [--nr-poll-queues=<#> | -P <#>] + [--queue-size=<#> | -Q <#>] [--keyring=<#>] + [--tls_key=<#>] [--hdr-digest | -g] [--data-digest | -G] + [--persistent | -p] [--tls] [--concat] [--quiet | -S] + [--dump-config | -O] [--nbft] [--no-nbft] + [--nbft-path=] [--context=] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -54,13 +54,13 @@ OPTIONS -t :: --transport=:: This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + 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. +|fc |*WIP* The network fabric is a Fibre Channel network. |tcp |The network fabric is a TCP/IP network. |loop|Connect to a NVMe over Fabrics target on the local host |================= @@ -77,7 +77,7 @@ OPTIONS -s :: --trsvcid=:: - This field specifies the transport service id. For transports using IP + 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. @@ -114,13 +114,20 @@ OPTIONS and dump it to a raw binary file. By default 'nvme connect-all' will dump the output to stdout. --C :: ---config-file=:: +-d :: +--device=:: + This field takes a device as input. It must be a persistent device + associated with a Discovery Controller previously created by the + command "connect-all" or "discover". follows the format + nvme*, eg. nvme0, nvme1. + +-J :: +--config=:: Use the specified JSON configuration file instead of the default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in an existing configuration file. The JSON configuration file format is documented in - https://github.com/linux-nvme/libnvme/doc/config-schema.json + https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json -k <#>:: --keep-alive-tmo=<#>:: @@ -137,14 +144,6 @@ OPTIONS --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. @@ -165,11 +164,31 @@ OPTIONS by the driver. This option will be ignored for discovery, but will be passed on to the subsequent connect call. +--keyring=<#>:: + Keyring for TLS key lookup. + +--tls_key=<#>:: + TLS key for the connection (TCP). + +-g:: +--hdr-digest:: + Generates/verifies header digest (TCP). + +-G:: +--data-digest:: + Generates/verifies data digest (TCP). + -p:: --persistent:: Don't remove the discovery controller after retrieving the discovery log page. +--tls:: + Enable TLS encryption (TCP). + +--concat:: + Enable secure concatenation (TCP). + -S:: --quiet:: Suppress error messages. @@ -178,6 +197,27 @@ OPTIONS --dump-config:: Print out resulting JSON configuration file to stdout. +--nbft:: + Only look at NBFT tables + +--no-nbft:: + Do not look at NBFT tables + +--nbft-path=:: + Use a user-defined path to the NBFT tables + +--context :: + Set the execution context to . This allows to coordinate + the management of the global resources. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- @@ -190,12 +230,24 @@ the RDMA network. Port 4420 is used by default: --hostnqn=host1-rogue-nqn ------------ + +* Issue a 'nvme connect-all' command using the default system defined NBFT tables: ++ +----------- +# nvme connect-all --nbft +------------ ++ +* Issue a 'nvme connect-all' command with a user-defined path for the NBFT table: ++ +----------- +# nvme connet-all --nbft-path=/sys/firmware/acpi/tables/NBFT1 +------------ ++ * Issue a 'nvme connect-all' command using a @SYSCONFDIR@/nvme/discovery.conf file: + ----------- -# Machine default 'nvme discover' commands. Query the +# 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 +# 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 diff --git a/Documentation/nvme-connect.1 b/Documentation/nvme-connect.1 index 6e4a8e3c2f..0210d8a8ee 100644 --- a/Documentation/nvme-connect.1 +++ b/Documentation/nvme-connect.1 @@ -2,12 +2,12 @@ .\" Title: nvme-connect .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-CONNECT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-CONNECT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,31 +32,29 @@ nvme-connect \- Connect to a Fabrics controller\&. .SH "SYNOPSIS" .sp .nf -\fInvme connect\fR - [\-\-transport= | \-t ] - [\-\-nqn= | \-n ] - [\-\-traddr= | \-a ] - [\-\-trsvcid= | \-s ] - [\-\-host\-traddr= | \-w ] - [\-\-host\-iface= | \-f ] - [\-\-hostnqn= | \-q ] - [\-\-hostid= | \-I ] - [\-\-config\-file= | \-J ] - [\-\-dhchap\-secret= | \-S ] - [\-\-dhchap\-ctrl\-secret= | \-C ] - [\-\-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] - [\-\-dump\-config | \-O] - [\-\-output\-format= | \-o ] +\fInvme connect\fR [\-\-transport= | \-t ] + [\-\-nqn= | \-n ] + [\-\-traddr= | \-a ] + [\-\-trsvcid= | \-s ] + [\-\-host\-traddr= | \-w ] + [\-\-host\-iface= | \-f ] + [\-\-hostnqn= | \-q ] + [\-\-hostid= | \-I ] + [\-\-config= | \-J ] + [\-\-dhchap\-secret= | \-S ] + [\-\-dhchap\-ctrl\-secret= | \-C ] + [\-\-nr\-io\-queues=<#> | \-i <#>] + [\-\-nr\-write\-queues=<#> | \-W <#>] + [\-\-nr\-poll\-queues=<#> | \-P <#>] + [\-\-queue\-size=<#> | \-Q <#>] + [\-\-keep\-alive\-tmo=<#> | \-k <#>] + [\-\-reconnect\-delay=<#> | \-c <#>] + [\-\-ctrl\-loss\-tmo=<#> | \-l <#>] [\-\-tos=<#> | \-T <#>] + [\-\-keyring=<#>] [\-\-tls_key=<#>] + [\-\-duplicate\-connect | \-D] [\-\-disable\-sqflow | \-d] + [\-\-hdr\-digest | \-g] [\-\-data\-digest | \-G] [\-\-tls] + [\-\-concat] [\-\-dump\-config | \-O] [\-\-application=] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -130,7 +128,7 @@ This field specifies the network interface used on the host to connect to the Co .PP \-q , \-\-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\&. +Overrides the default Host NQN that identifies the NVMe Host\&. If this option is not specified, the default is read from /usr/local/etc/nvme/hostnqn first\&. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next\&. The Host NQN uniquely identifies the NVMe Host\&. .RE .PP \-I , \-\-hostid= @@ -138,18 +136,18 @@ Overrides the default Host NQN that identifies the NVMe Host\&. If this option i UUID(Universally Unique Identifier) to be discovered which should be formatted\&. .RE .PP -\-J , \-\-config\-file= +\-J , \-\-config= .RS 4 -Use the specified JSON configuration file instead of the default /etc/nvme/config\&.json file or +Use the specified JSON configuration file instead of the default /usr/local/etc/nvme/config\&.json file or \fInone\fR to not read in an existing configuration file\&. The JSON configuration file format is documented in -\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/doc/config\-schema\&.json\fR\m[] +\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/blob/master/doc/config\-schema\&.json\fR\m[] .RE .PP \-S , \-\-dhchap\-secret= .RS 4 NVMe In\-band authentication secret; needs to be in ASCII format as specified in NVMe 2\&.0 section 8\&.13\&.5\&.8 -\fISecret representation\fR\&. If this option is not specified, the default is read from /etc/nvme/hostkey\&. If that does not exist no in\-band authentication is attempted\&. +\fISecret representation\fR\&. .RE .PP \-C , \-\-dhchap\-ctrl\-secret= @@ -193,6 +191,21 @@ Overrides the default delay (in seconds) before reconnect is attempted after a c Overrides the default controller loss timeout period (in seconds)\&. .RE .PP +\-T <#>, \-\-tos=<#> +.RS 4 +Type of service for the connection (TCP) +.RE +.PP +\-\-keyring=<#> +.RS 4 +Keyring for TLS key lookup\&. +.RE +.PP +\-\-tls_key=<#> +.RS 4 +TLS key for the connection (TCP)\&. +.RE +.PP \-D, \-\-duplicate\-connect .RS 4 Allows duplicated connections between same transport host and subsystem port\&. @@ -213,17 +226,38 @@ Generates/verifies header digest (TCP)\&. Generates/verifies data digest (TCP)\&. .RE .PP +\-\-tls +.RS 4 +Enable TLS encryption (TCP)\&. +.RE +.PP +\-\-concat +.RS 4 +Enable secure concatenation (TCP)\&. +.RE +.PP \-O, \-\-dump\-config .RS 4 Print out resulting JSON configuration file to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-\-context +.RS 4 +Set the execution context to \&. This allows to coordinate the management of the global resources\&. +.RE +.PP +\-o , \-\-output\-format= .RS 4 Set the reporting format to -\fInormal\fR +\fInormal\fR, +\fIjson\fR or -\fIjson\fR\&. Only one output format can be used at a time\&. When this option is specified, the device associated with the connection will be printed\&. Nothing is printed otherwise\&. +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-connect.html b/Documentation/nvme-connect.html index c816b2a5fe..a3e1ff5083 100644 --- a/Documentation/nvme-connect.html +++ b/Documentation/nvme-connect.html @@ -749,31 +749,29 @@

    NAME

    SYNOPSIS

    -
    nvme connect
    -                [--transport=<trtype>     | -t <trtype>]
    -                [--nqn=<subnqn>           | -n <subnqn>]
    -                [--traddr=<traddr>        | -a <traddr>]
    -                [--trsvcid=<trsvcid>      | -s <trsvcid>]
    -                [--host-traddr=<traddr>   | -w <traddr>]
    -                [--host-iface=<iface>     | -f <iface>]
    -                [--hostnqn=<hostnqn>      | -q <hostnqn>]
    -                [--hostid=<hostid>        | -I <hostid>]
    -                [--config-file=<cfg>      | -J <cfg> ]
    -                [--dhchap-secret=<secret> | -S <secret>]
    -                [--dhchap-ctrl-secret=<secret> | -C <secret>]
    -                [--nr-io-queues=<#>       | -i <#>]
    -                [--nr-write-queues=<#>    | -W <#>]
    -                [--nr-poll-queues=<#>     | -P <#>]
    -                [--queue-size=<#>         | -Q <#>]
    -                [--keep-alive-tmo=<#>     | -k <#>]
    -                [--reconnect-delay=<#>    | -c <#>]
    -                [--ctrl-loss-tmo=<#>      | -l <#>]
    -                [--duplicate-connect      | -D]
    -                [--disable-sqflow         | -d]
    -                [--hdr-digest             | -g]
    -                [--data-digest            | -G]
    -                [--dump-config            | -O]
    -                [--output-format=<fmt>    | -o <fmt>]
    +
    nvme connect [--transport=<trtype> | -t <trtype>]
    +                        [--nqn=<subnqn> | -n <subnqn>]
    +                        [--traddr=<traddr> | -a <traddr>]
    +                        [--trsvcid=<trsvcid> | -s <trsvcid>]
    +                        [--host-traddr=<traddr> | -w <traddr>]
    +                        [--host-iface=<iface> | -f <iface>]
    +                        [--hostnqn=<hostnqn> | -q <hostnqn>]
    +                        [--hostid=<hostid> | -I <hostid>]
    +                        [--config=<filename> | -J <filename>]
    +                        [--dhchap-secret=<secret> | -S <secret>]
    +                        [--dhchap-ctrl-secret=<secret> | -C <secret>]
    +                        [--nr-io-queues=<#> | -i <#>]
    +                        [--nr-write-queues=<#> | -W <#>]
    +                        [--nr-poll-queues=<#> | -P <#>]
    +                        [--queue-size=<#> | -Q <#>]
    +                        [--keep-alive-tmo=<#> | -k <#>]
    +                        [--reconnect-delay=<#> | -c <#>]
    +                        [--ctrl-loss-tmo=<#> | -l <#>] [--tos=<#> | -T <#>]
    +                        [--keyring=<#>] [--tls_key=<#>]
    +                        [--duplicate-connect | -D] [--disable-sqflow | -d]
    +                        [--hdr-digest | -g] [--data-digest | -G] [--tls]
    +                        [--concat] [--dump-config | -O] [--application=<id>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -799,7 +797,7 @@

    OPTIONS

    This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + a NVMe-over-Fabrics network. Current string values include:

  • OPTIONS

    - This field specifies the transport service id. For transports using IP + 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.

    @@ -906,7 +904,7 @@

    OPTIONS

    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 + /usr/local/etc/nvme/hostnqn first. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next. The Host NQN uniquely identifies the NVMe Host.

    @@ -924,18 +922,18 @@

    OPTIONS

    --J <cfg> +-J <filename>
    ---config-file=<cfg> +--config=<filename>

    Use the specified JSON configuration file instead of the - default /etc/nvme/config.json file or none to not read in + default /usr/local/etc/nvme/config.json file or none to not read in an existing configuration file. The JSON configuration file format is documented in - https://github.com/linux-nvme/libnvme/doc/config-schema.json + https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json

    @@ -948,9 +946,6 @@

    OPTIONS

    NVMe In-band authentication secret; needs to be in ASCII format as specified in NVMe 2.0 section 8.13.5.8 Secret representation. - If this option is not specified, the default is read from - /etc/nvme/hostkey. If that does not exist no in-band authentication - is attempted.

    @@ -1047,6 +1042,33 @@

    OPTIONS

    +-T <#> +
    +
    +--tos=<#> +
    +
    +

    + Type of service for the connection (TCP) +

    +
    +
    +--keyring=<#> +
    +
    +

    + Keyring for TLS key lookup. +

    +
    +
    +--tls_key=<#> +
    +
    +

    + TLS key for the connection (TCP). +

    +
    +
    -D
    @@ -1093,6 +1115,22 @@

    OPTIONS

    +--tls +
    +
    +

    + Enable TLS encryption (TCP). +

    +
    +
    +--concat +
    +
    +

    + Enable secure concatenation (TCP). +

    +
    +
    -O
    @@ -1104,16 +1142,35 @@

    OPTIONS

    --o <format> +--context <STR> +
    +
    +

    + Set the execution context to <STR>. This allows to coordinate + the management of the global resources. +

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

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

    +
    +
    +-v
    ---output-format=<format> +--verbose

    - Set the reporting format to normal or json. Only one output format can - be used at a time. When this option is specified, the device associated with - the connection will be printed. Nothing is printed otherwise. + Increase the information detail in the output.

    @@ -1162,7 +1219,7 @@

    NVME

    diff --git a/Documentation/nvme-connect.txt b/Documentation/nvme-connect.txt index f57b34dd68..583aaf9b91 100644 --- a/Documentation/nvme-connect.txt +++ b/Documentation/nvme-connect.txt @@ -8,31 +8,29 @@ nvme-connect - Connect to a Fabrics controller. SYNOPSIS -------- [verse] -'nvme connect' - [--transport= | -t ] - [--nqn= | -n ] - [--traddr= | -a ] - [--trsvcid= | -s ] - [--host-traddr= | -w ] - [--host-iface= | -f ] - [--hostnqn= | -q ] - [--hostid= | -I ] - [--config-file= | -J ] - [--dhchap-secret= | -S ] - [--dhchap-ctrl-secret= | -C ] - [--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] - [--dump-config | -O] - [--output-format= | -o ] +'nvme connect' [--transport= | -t ] + [--nqn= | -n ] + [--traddr= | -a ] + [--trsvcid= | -s ] + [--host-traddr= | -w ] + [--host-iface= | -f ] + [--hostnqn= | -q ] + [--hostid= | -I ] + [--config= | -J ] + [--dhchap-secret= | -S ] + [--dhchap-ctrl-secret= | -C ] + [--nr-io-queues=<#> | -i <#>] + [--nr-write-queues=<#> | -W <#>] + [--nr-poll-queues=<#> | -P <#>] + [--queue-size=<#> | -Q <#>] + [--keep-alive-tmo=<#> | -k <#>] + [--reconnect-delay=<#> | -c <#>] + [--ctrl-loss-tmo=<#> | -l <#>] [--tos=<#> | -T <#>] + [--keyring=<#>] [--tls_key=<#>] + [--duplicate-connect | -D] [--disable-sqflow | -d] + [--hdr-digest | -g] [--data-digest | -G] [--tls] + [--concat] [--dump-config | -O] [--application=] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -45,7 +43,7 @@ OPTIONS -t :: --transport=:: This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + a NVMe-over-Fabrics network. Current string values include: + [] |================= @@ -68,7 +66,7 @@ OPTIONS -s :: --trsvcid=:: - This field specifies the transport service id. For transports using IP + 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. @@ -97,21 +95,18 @@ OPTIONS UUID(Universally Unique Identifier) to be discovered which should be formatted. --J :: ---config-file=:: +-J :: +--config=:: Use the specified JSON configuration file instead of the default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in an existing configuration file. The JSON configuration file format is documented in - https://github.com/linux-nvme/libnvme/doc/config-schema.json + https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json -S :: --dhchap-secret=:: NVMe In-band authentication secret; needs to be in ASCII format as specified in NVMe 2.0 section 8.13.5.8 'Secret representation'. - If this option is not specified, the default is read from - @SYSCONFDIR@/nvme/hostkey. If that does not exist no in-band authentication - is attempted. -C :: --dhchap-ctrl-secret=:: @@ -150,6 +145,16 @@ OPTIONS --ctrl-loss-tmo=<#>:: Overrides the default controller loss timeout period (in seconds). +-T <#>:: +--tos=<#>:: + Type of service for the connection (TCP) + +--keyring=<#>:: + Keyring for TLS key lookup. + +--tls_key=<#>:: + TLS key for the connection (TCP). + -D:: --duplicate-connect:: Allows duplicated connections between same transport host and subsystem @@ -168,15 +173,28 @@ OPTIONS --data-digest:: Generates/verifies data digest (TCP). +--tls:: + Enable TLS encryption (TCP). + +--concat:: + Enable secure concatenation (TCP). + -O:: --dump-config:: Print out resulting JSON configuration file to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal' or 'json'. Only one output format can - be used at a time. When this option is specified, the device associated with - the connection will be printed. Nothing is printed otherwise. +--context :: + Set the execution context to . This allows to coordinate + the management of the global resources. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- @@ -193,7 +211,6 @@ SEE ALSO nvme-discover(1) nvme-connect-all(1) - AUTHORS ------- This was co-written by mailto:james.p.freyensee@intel.com[Jay Freyensee] diff --git a/Documentation/nvme-copy.1 b/Documentation/nvme-copy.1 index 9ac24126af..6e0c67deb7 100644 --- a/Documentation/nvme-copy.1 +++ b/Documentation/nvme-copy.1 @@ -2,12 +2,12 @@ .\" Title: nvme-copy .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-COPY" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-COPY" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -35,6 +35,8 @@ nvme-copy \- Send an NVMe Simple Copy command, provide results \fInvme\-copy\fR [\-\-sdlba= | \-d ] [\-\-blocks= | \-b ] [\-\-slbs= | \-s ] + [\-\-snsids= | \-N ] + [\-\-sopts= | \-O ] [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f] [\-\-prinfow= | \-p ] @@ -48,91 +50,116 @@ nvme-copy \- Send an NVMe Simple Copy command, provide results [\-\-dir\-type= | \-T ] [\-\-dir\-spec= | \-S ] [\-\-format= | \-F ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Copy command is used by the host to copy data from one or more source logical block ranges to a single consecutive destination logical block range\&. .SH "OPTIONS" .PP -\-\-sdlba=, \-d +\-d , \-\-sdlba= .RS 4 64\-bit addr of first destination logical block .RE .PP -\-\-blocks=, \-b +\-b , \-\-blocks= .RS 4 Comma separated list of the number of blocks in each range .RE .PP -\-\-slbs=, \-s +\-s , \-\-slbs= .RS 4 Comma separated list of the starting blocks in each range .RE .PP -\-\-limited\-retry, \-l +\-\-snsids=, \-N +.RS 4 +Comma separated list of the source namespace identifiers in each range +.RE +.PP +\-\-sopts=, \-O +.RS 4 +Comma separated list of the source options in each range +.RE +.PP +\-l, \-\-limited\-retry .RS 4 Sets the limited retry flag\&. .RE .PP -\-\-force\-unit\-access, \-f +\-f, \-\-force\-unit\-access .RS 4 Set the force\-unit access flag\&. .RE .PP -\-\-prinfow=, \-p +\-p , \-\-prinfow= .RS 4 Protection Information field write definition\&. .RE .PP -\-\-prinfor=, \-P +\-P , \-\-prinfor= .RS 4 Protection Information field read definition\&. .RE .PP -\-\-ref\-tag=, \-r +\-r , \-\-ref\-tag= .RS 4 initial lba reference tag\&. .RE .PP -\-\-expected\-ref\-tags=, \-R +\-R , \-\-expected\-ref\-tags= .RS 4 expected lba reference tags (comma\-separated list)\&. .RE .PP -\-\-app\-tag=, \-a +\-a , \-\-app\-tag= .RS 4 lba app tag .RE .PP -\-\-expected\-app\-tags=, \-A +\-A , \-\-expected\-app\-tags= .RS 4 expected lba app tags (comma\-separated list) .RE .PP -\-\-app\-mask=, \-m +\-m , \-\-app\-mask= .RS 4 lba tag mask .RE .PP -\-\-expected\-app\-masks=, \-M +\-M , \-\-expected\-app\-masks= .RS 4 expected lba tag masks (comma\-separated list) .RE .PP -\-\-dir\-type=, \-T +\-T , \-\-dir\-type= .RS 4 Optional directive type\&. The nvme\-cli only enforces the value be in the defined range for the directive type, though the NVMe specification (1\&.3a) defines only one directive, 01h, for write stream identifiers\&. .RE .PP -\-\-dir\-spec=, \-S +\-S , \-\-dir\-spec= .RS 4 Optional field for directive specifics\&. When used with write streams, this value is defined to be the write stream identifier\&. The nvme\-cli will not validate the stream requested is within the controller\(cqs capabilities\&. .RE .PP -\-\-format=, \-F +\-F , \-\-format= .RS 4 source range entry format .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-copy.html b/Documentation/nvme-copy.html index 468feeec34..54921be619 100644 --- a/Documentation/nvme-copy.html +++ b/Documentation/nvme-copy.html @@ -752,6 +752,8 @@

    SYNOPSIS

    nvme-copy <device> [--sdlba=<sdlba> | -d <sdlba>]
                             [--blocks=<nlb-list,> | -b <nlb-list,>]
                             [--slbs=<slbas,> | -s <slbas,>]
    +                        [--snsids=<snsids,> | -N <snsids,>]
    +                        [--sopts=<sopts,> | -O <sopts,>]
                             [--limited-retry | -l]
                             [--force-unit-access | -f]
                             [--prinfow=<prinfow> | -p <prinfow>]
    @@ -764,7 +766,8 @@ 

    SYNOPSIS

    [--expected-app-masks=<appmask,> | -M <appmask,>] [--dir-type=<type> | -T <type>] [--dir-spec=<spec> | -S <spec>] - [--format=<entry-format> | -F <entry-format>]
    + [--format=<entry-format> | -F <entry-format>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -781,10 +784,10 @@

    OPTIONS

    ---sdlba=<sdlba> +-d <sdlba>
    --d <sdlba> +--sdlba=<sdlba>

    @@ -792,10 +795,10 @@

    OPTIONS

    ---blocks=<nlb-list,> +-b <nlb-list,>
    --b <nlb-list,> +--blocks=<nlb-list,>

    @@ -803,10 +806,10 @@

    OPTIONS

    ---slbs=<slbas,> +-s <slbas,>
    --s <slbas,> +--slbs=<slbas,>

    @@ -814,21 +817,43 @@

    OPTIONS

    ---limited-retry +--snsids=<snsids,> +
    +
    +-N <snsids,> +
    +
    +

    + Comma separated list of the source namespace identifiers in each range +

    +
    +
    +--sopts=<sopts,>
    +-O <sopts,> +
    +
    +

    + Comma separated list of the source options in each range +

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

    Sets the limited retry flag.

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

    @@ -836,10 +861,10 @@

    OPTIONS

    ---prinfow=<prinfow> +-p <prinfow>
    --p <prinfow> +--prinfow=<prinfow>

    @@ -847,10 +872,10 @@

    OPTIONS

    ---prinfor=<prinfor> +-P <prinfor>
    --P <prinfor> +--prinfor=<prinfor>

    @@ -858,10 +883,10 @@

    OPTIONS

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

    @@ -869,10 +894,10 @@

    OPTIONS

    ---expected-ref-tags=<reftag,> +-R <reftag,>
    --R <reftag,> +--expected-ref-tags=<reftag,>

    @@ -880,10 +905,10 @@

    OPTIONS

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

    @@ -891,10 +916,10 @@

    OPTIONS

    ---expected-app-tags=<apptag,> +-A <apptag,>
    --A <apptag,> +--expected-app-tags=<apptag,>

    @@ -902,10 +927,10 @@

    OPTIONS

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

    @@ -913,10 +938,10 @@

    OPTIONS

    ---expected-app-masks=<appmask,> +-M <appmask,>
    --M <appmask,> +--expected-app-masks=<appmask,>

    @@ -924,10 +949,10 @@

    OPTIONS

    ---dir-type=<type> +-T <type>
    --T <type> +--dir-type=<type>

    @@ -938,10 +963,10 @@

    OPTIONS

    ---dir-spec=<spec> +-S <spec>
    --S <spec> +--dir-spec=<spec>

    @@ -952,16 +977,39 @@

    OPTIONS

    ---format=<entry-format> +-F <entry-format>
    --F <entry-format> +--format=<entry-format>

    source range entry format

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -982,7 +1030,7 @@

    NVME

    diff --git a/Documentation/nvme-copy.txt b/Documentation/nvme-copy.txt index 1fad952d65..7c5fb0e65d 100644 --- a/Documentation/nvme-copy.txt +++ b/Documentation/nvme-copy.txt @@ -11,6 +11,8 @@ SYNOPSIS 'nvme-copy' [--sdlba= | -d ] [--blocks= | -b ] [--slbs= | -s ] + [--snsids= | -N ] + [--sopts= | -O ] [--limited-retry | -l] [--force-unit-access | -f] [--prinfow= | -p ] @@ -24,6 +26,7 @@ SYNOPSIS [--dir-type= | -T ] [--dir-spec= | -S ] [--format= | -F ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -32,76 +35,93 @@ logical block ranges to a single consecutive destination logical block range. OPTIONS ------- ---sdlba=:: -d :: +--sdlba=:: 64-bit addr of first destination logical block ---blocks=:: -b :: +--blocks=:: Comma separated list of the number of blocks in each range ---slbs=:: -s :: +--slbs=:: Comma separated list of the starting blocks in each range ---limited-retry:: +--snsids=:: +-N :: + Comma separated list of the source namespace identifiers in each range + +--sopts=:: +-O :: + Comma separated list of the source options in each range + -l:: +--limited-retry:: Sets the limited retry flag. ---force-unit-access:: -f:: +--force-unit-access:: Set the force-unit access flag. ---prinfow=:: -p :: +--prinfow=:: Protection Information field write definition. ---prinfor=:: -P :: +--prinfor=:: Protection Information field read definition. ---ref-tag=:: -r :: +--ref-tag=:: initial lba reference tag. ---expected-ref-tags=:: -R :: +--expected-ref-tags=:: expected lba reference tags (comma-separated list). ---app-tag=:: -a :: +--app-tag=:: lba app tag ---expected-app-tags=:: -A :: +--expected-app-tags=:: expected lba app tags (comma-separated list) ---app-mask=:: -m :: +--app-mask=:: lba tag mask ---expected-app-masks=:: -M :: +--expected-app-masks=:: expected lba tag masks (comma-separated list) ---dir-type=:: -T :: +--dir-type=:: Optional directive type. The nvme-cli only enforces the value be in the defined range for the directive type, though the NVMe specification (1.3a) defines only one directive, 01h, for write stream identifiers. ---dir-spec=:: -S :: +--dir-spec=:: Optional field for directive specifics. When used with write streams, this value is defined to be the write stream identifier. The nvme-cli will not validate the stream requested is within the controller's capabilities. ---format=:: -F :: +--format=:: source range entry format +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-create-ns.1 b/Documentation/nvme-create-ns.1 index e0f5460311..b4818bd72f 100644 --- a/Documentation/nvme-create-ns.1 +++ b/Documentation/nvme-create-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-create-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-CREATE\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-CREATE\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -39,23 +39,27 @@ nvme-create-ns \- Send NVMe Namespace management command to create namespace, re [\-\-nmic= | \-m ] [\-\-anagrp\-id= | \-a ] [\-\-nvmset\-id= | \-i ] + [\-\-endg\-id= | \-e ] [\-\-csi= | \-y ] [\-\-lbstm= | \-l ] + [\-\-nphndls= | \-n ] [\-\-block\-size= | \-b ] [\-\-timeout= | \-t ] -DESCRIPTION + [\-\-nsze\-si= | \-S ] + [\-\-ncap\-si= | \-C ] + [\-\-azr | \-z] + [\-\-rar= | \-r ] + [\-\-ror= | \-O ] + [\-\-rnumzrwa= | \-u ] + [\-\-phndls= | \-p ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi +.SH "DESCRIPTION" .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 parameter is mandatory and may be either the NVMe character -device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. - -OPTIONS -.fi +For the NVMe device given, sends a namespace management command to create the namespace with the requested settings\&. On success, the namespace identifier assigned by the controller is returned\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" .PP \-s, \-\-nsze .RS 4 @@ -92,6 +96,11 @@ ANA Group Identifier\&. If this value is 0h specifies that the controller determ This field specifies the identifier of the NVM Set\&. .RE .PP +\-e , \-\-endg\-id= +.RS 4 +This field specifies the identifier of the endurance group\&. +.RE +.PP \-y , \-\-csi= .RS 4 This field specifies the identifier of command set\&. if not issued, NVM Command Set will be selected\&. @@ -102,13 +111,87 @@ This field specifies the identifier of command set\&. if not issued, NVM Command Logical Block Storage Tag Mask for end\-to\-end protection\&. .RE .PP +\-n , \-\-nphndls= +.RS 4 +Number of Placement Handle included in the Placement Handle List\&. If the Flexible Data Placement capability is not supported or not enabled in specified Endurance Group, then the controller shall ignore this field\&. +.RE +.PP \-b, \-\-block\-size .RS 4 Target block size the new namespace should be formatted as\&. Potential FLBAS values will be values will be scanned and the lowest numbered will be selected for the create\-ns operation\&. Conflicts with \-\-flbas argument\&. .RE +.PP +\-S, \-\-nsze\-si +.RS 4 +The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries, unless the controller recommends a smaller value)\&. The value SI suffixed is divided by the namespace LBA size to set as NSZE\&. If the value not suffixed it is set as same with the nsze option\&. +.RE +.PP +\-C, \-\-ncap\-si +.RS 4 +The namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries, unless the controller recommends a smaller value)\&. The value SI suffixed is divided by the namespace LBA size to set as NCAP\&. If the value not suffixed it is set as same with the ncap option\&. +.RE +.PP +\-z, \-\-azr +.RS 4 +Allocate ZRWA Resources\&. If set to 1, then the namespace is to be created with the number of ZRWA resource specified in the RNUMZRWA field of this data structure\&. If cleared to 0, then no ZRWA resources are allocated to the namespace to be created\&. +.RE +.PP +\-r , \-\-rar= +.RS 4 +Requested Active Resources\&. This field specifies the number of active resources to be allocated to the created namespace\&. +.RE +.PP +\-O , \-\-ror= +.RS 4 +Requested Open Resources\&. This field specifies the number of open resources to be allocated to the created namespace\&. +.RE +.PP +\-u , \-\-rnumzrwa= +.RS 4 +Requested Number of ZRWA Resources\&. This field specifies the number of ZRWA resources to be allocated to the created namespace\&. +.RE +.PP +\-p , \-\-phndls= +.RS 4 +The comma separated list of Reclaim Unit Handle Identifier to be associated with each Placement Handle\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp -No examples provided yet\&. +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Create a namespace: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme create\-ns /dev/nvme0 \-\-nsze 11995709440 \-\-ncap 1199570940 \-\-flbas 0 \-\-dps 0 \-\-nmic 0 +# nvme create\-ns /dev/nvme0 \-\-nsze\-si 6\&.14T \-\-ncap 1199570940 \-\-flbas 0 \-\-dps 0 \-\-nmic 0 +.fi +.if n \{\ +.RE +.\} +.RE .SH "NVME" .sp Part of the nvme\-user suite diff --git a/Documentation/nvme-create-ns.html b/Documentation/nvme-create-ns.html index 900a402294..c3a9ece560 100644 --- a/Documentation/nvme-create-ns.html +++ b/Documentation/nvme-create-ns.html @@ -756,24 +756,37 @@

    SYNOPSIS

    [--nmic=<nmic> | -m <nmic>] [--anagrp-id=<anagrpid> | -a <anagrpid>] [--nvmset-id=<nvmsetid> | -i <nvmsetid>] + [--endg-id=<endgid> | -e <endgid>] [--csi=<command_set_identifier> | -y <command_set_identifier>] [--lbstm=<lbstm> | -l <lbstm>] + [--nphndls=<nphndls> | -n <nphndls>] [--block-size=<block-size> | -b <block-size>] [--timeout=<timeout> | -t <timeout>] -DESCRIPTION + [--nsze-si=<nsze-si> | -S <nsze-si>] + [--ncap-si=<ncap-si> | -C <ncap-si>] + [--azr | -z] + [--rar=<rar> | -r <rar>] + [--ror=<ror> | -O <ror>] + [--rnumzrwa=<rnumzrwa> | -u <rnumzrwa>] + [--phndls=<placement-handle-list,> | -p <placement-handle-list,>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    -
    -
    -
    For the NVMe device given, sends a namespace management command to create
    +
    +
    +
    +

    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 -

    +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 @@ -855,6 +868,17 @@

    SYNOPSIS

    +-e <endgid> +
    +
    +--endg-id=<endgid> +
    +
    +

    + This field specifies the identifier of the endurance group. +

    +
    +
    -y <command_set_identifier>
    @@ -878,6 +902,19 @@

    SYNOPSIS

    +-n <nphndls> +
    +
    +--nphndls=<nphndls> +
    +
    +

    + Number of Placement Handle included in the Placement Handle List. + If the Flexible Data Placement capability is not supported or not enabled + in specified Endurance Group, then the controller shall ignore this field. +

    +
    +
    -b
    @@ -886,8 +923,121 @@

    SYNOPSIS

    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. + values will be values will be scanned and the lowest numbered will be + selected for the create-ns operation. Conflicts with --flbas argument. +

    +
    +
    +-S +
    +
    +--nsze-si +
    +
    +

    + The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries, + unless the controller recommends a smaller value). + The value SI suffixed is divided by the namespace LBA size to set as NSZE. + If the value not suffixed it is set as same with the nsze option. +

    +
    +
    +-C +
    +
    +--ncap-si +
    +
    +

    + The namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries, + unless the controller recommends a smaller value). + The value SI suffixed is divided by the namespace LBA size to set as NCAP. + If the value not suffixed it is set as same with the ncap option. +

    +
    +
    +-z +
    +
    +--azr +
    +
    +

    + Allocate ZRWA Resources. + If set to 1, then the namespace is to be created with the number of ZRWA + resource specified in the RNUMZRWA field of this data structure. If cleared + to 0, then no ZRWA resources are allocated to the namespace to be created. +

    +
    +
    +-r <rar> +
    +
    +--rar=<rar> +
    +
    +

    + Requested Active Resources. This field specifies the number of active + resources to be allocated to the created namespace. +

    +
    +
    +-O <ror> +
    +
    +--ror=<ror> +
    +
    +

    + Requested Open Resources. This field specifies the number of open resources + to be allocated to the created namespace. +

    +
    +
    +-u <rnumzrwa> +
    +
    +--rnumzrwa=<rnumzrwa> +
    +
    +

    + Requested Number of ZRWA Resources. This field specifies the number of ZRWA + resources to be allocated to the created namespace. +

    +
    +
    +-p <placement-handle-list,> +
    +
    +--phndls=<placement-handle-list,> +
    +
    +

    + The comma separated list of Reclaim Unit Handle Identifier to be associated + with each Placement Handle. +

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

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

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

    + Increase the information detail in the output.

    @@ -896,7 +1046,18 @@

    SYNOPSIS

    EXAMPLES

    -

    No examples provided yet.

    +
      +
    • +

      +Create a namespace: +

      +
      +
      +
      # nvme create-ns /dev/nvme0 --nsze 11995709440 --ncap 1199570940 --flbas 0 --dps 0 --nmic 0
      +# nvme create-ns /dev/nvme0 --nsze-si 6.14T --ncap 1199570940 --flbas 0 --dps 0 --nmic 0
      +
      +
    • +
    @@ -910,7 +1071,7 @@

    NVME

    diff --git a/Documentation/nvme-create-ns.txt b/Documentation/nvme-create-ns.txt index a17c70db70..352a94524e 100644 --- a/Documentation/nvme-create-ns.txt +++ b/Documentation/nvme-create-ns.txt @@ -15,10 +15,21 @@ SYNOPSIS [--nmic= | -m ] [--anagrp-id= | -a ] [--nvmset-id= | -i ] + [--endg-id= | -e ] [--csi= | -y ] [--lbstm= | -l ] + [--nphndls= | -n ] [--block-size= | -b ] [--timeout= | -t ] + [--nsze-si= | -S ] + [--ncap-si= | -C ] + [--azr | -z] + [--rar= | -r ] + [--ror= | -O ] + [--rnumzrwa= | -u ] + [--phndls= | -p ] + [--output-format= | -o ] [--verbose | -v] + DESCRIPTION ----------- For the NVMe device given, sends a namespace management command to create @@ -60,6 +71,10 @@ OPTIONS --nvmset-id=:: This field specifies the identifier of the NVM Set. +-e :: +--endg-id=:: + This field specifies the identifier of the endurance group. + -y :: --csi=:: This field specifies the identifier of command set. @@ -69,16 +84,76 @@ OPTIONS --lbstm=:: Logical Block Storage Tag Mask for end-to-end protection. +-n :: +--nphndls=:: + Number of Placement Handle included in the Placement Handle List. + If the Flexible Data Placement capability is not supported or not enabled + in specified Endurance Group, then the controller shall ignore this field. + -b:: --block-size:: Target block size the new namespace should be formatted as. Potential FLBAS - values will be values will be scanned and the lowest numbered will be - selected for the create-ns operation. Conflicts with --flbas argument. - + values will be values will be scanned and the lowest numbered will be + selected for the create-ns operation. Conflicts with --flbas argument. + +-S:: +--nsze-si:: + The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries, + unless the controller recommends a smaller value). + The value SI suffixed is divided by the namespace LBA size to set as NSZE. + If the value not suffixed it is set as same with the nsze option. + +-C:: +--ncap-si:: + The namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries, + unless the controller recommends a smaller value). + The value SI suffixed is divided by the namespace LBA size to set as NCAP. + If the value not suffixed it is set as same with the ncap option. + +-z:: +--azr:: + Allocate ZRWA Resources. + If set to 1, then the namespace is to be created with the number of ZRWA + resource specified in the RNUMZRWA field of this data structure. If cleared + to 0, then no ZRWA resources are allocated to the namespace to be created. + +-r :: +--rar=:: + Requested Active Resources. This field specifies the number of active + resources to be allocated to the created namespace. + +-O :: +--ror=:: + Requested Open Resources. This field specifies the number of open resources + to be allocated to the created namespace. + +-u :: +--rnumzrwa=:: + Requested Number of ZRWA Resources. This field specifies the number of ZRWA + resources to be allocated to the created namespace. + +-p :: +--phndls=:: + The comma separated list of Reclaim Unit Handle Identifier to be associated + with each Placement Handle. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- -No examples provided yet. +* Create a namespace: ++ +------------ +# nvme create-ns /dev/nvme0 --nsze 11995709440 --ncap 1199570940 --flbas 0 --dps 0 --nmic 0 +# nvme create-ns /dev/nvme0 --nsze-si 6.14T --ncap 1199570940 --flbas 0 --dps 0 --nmic 0 +------------ NVME ---- diff --git a/Documentation/nvme-delete-ns.1 b/Documentation/nvme-delete-ns.1 index 75c383d3f5..80454d138f 100644 --- a/Documentation/nvme-delete-ns.1 +++ b/Documentation/nvme-delete-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,6 +33,7 @@ nvme-delete-ns \- Send NVMe Namespace Management delete namespace command, retur .sp .nf \fInvme delete\-ns\fR [\-\-namespace\-id= | \-n ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -45,6 +46,20 @@ The parameter is mandatory and may be either the NVMe character device .RS 4 The namespace identifier to delete\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-delete-ns.html b/Documentation/nvme-delete-ns.html index 287f2a0427..eb379d3dca 100644 --- a/Documentation/nvme-delete-ns.html +++ b/Documentation/nvme-delete-ns.html @@ -749,7 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme delete-ns <device> [--namespace-id=<nsid> | -n <nsid>]
    +
    nvme delete-ns <device> [--namespace-id=<nsid> | -n <nsid>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -779,6 +780,29 @@

    OPTIONS

    The namespace identifier to delete.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -799,7 +823,7 @@

    NVME

    diff --git a/Documentation/nvme-delete-ns.txt b/Documentation/nvme-delete-ns.txt index 62301b4e0d..1b306b212c 100644 --- a/Documentation/nvme-delete-ns.txt +++ b/Documentation/nvme-delete-ns.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'nvme delete-ns' [--namespace-id= | -n ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -25,6 +26,15 @@ OPTIONS --namespace-id=:: The namespace identifier to delete. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-dera-stat.1 b/Documentation/nvme-dera-stat.1 index 0f8e64710f..5469c14fc5 100644 --- a/Documentation/nvme-dera-stat.1 +++ b/Documentation/nvme-dera-stat.1 @@ -2,12 +2,12 @@ .\" Title: nvme-dera-stat .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DERA\-STAT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DERA\-STAT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-dera-stat.html b/Documentation/nvme-dera-stat.html index f01206c2ab..c265ee7e5b 100644 --- a/Documentation/nvme-dera-stat.html +++ b/Documentation/nvme-dera-stat.html @@ -797,7 +797,7 @@

    NVME

    diff --git a/Documentation/nvme-dera-stat.txt b/Documentation/nvme-dera-stat.txt index 512e584f22..f3a87aeaa2 100644 --- a/Documentation/nvme-dera-stat.txt +++ b/Documentation/nvme-dera-stat.txt @@ -24,7 +24,6 @@ OPTIONS ------- none - EXAMPLES -------- * Print the Dera Device status and Additional SMART log page in a human readable format: diff --git a/Documentation/nvme-detach-ns.1 b/Documentation/nvme-detach-ns.1 index fe3fca5b79..70c29a4fa2 100644 --- a/Documentation/nvme-detach-ns.1 +++ b/Documentation/nvme-detach-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-detach-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DETACH\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DETACH\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,6 +34,7 @@ nvme-detach-ns \- Send NVMe detach namespace, return result\&. .nf \fInvme detach\-ns\fR [\-\-namespace\-id= | \-n ] [\-\-controllers= | \-c + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -45,10 +46,24 @@ For the NVMe device given, sends the nvme namespace detach command for the provi The namespace identifier to detach\&. .RE .PP -\-c , \-controllers= +\-c , \-\-controllers= .RS 4 The comma separated list of controller identifiers to detach the namespace from\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-detach-ns.html b/Documentation/nvme-detach-ns.html index bf515360e1..28d2c7cac5 100644 --- a/Documentation/nvme-detach-ns.html +++ b/Documentation/nvme-detach-ns.html @@ -750,7 +750,8 @@

    SYNOPSIS

    nvme detach-ns <device> [--namespace-id=<nsid> | -n <nsid>]
    -                        [--controllers=<ctrl-list,> | -c <ctrl-list,>
    + [--controllers=<ctrl-list,> | -c <ctrl-list,> + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -782,7 +783,7 @@

    OPTIONS

    -c <ctrl-list,>
    --controllers=<ctrl-list,> +--controllers=<ctrl-list,>

    @@ -790,6 +791,29 @@

    OPTIONS

    the namespace from.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -810,7 +834,7 @@

    NVME

    diff --git a/Documentation/nvme-detach-ns.txt b/Documentation/nvme-detach-ns.txt index ed23c15c9b..842889c794 100644 --- a/Documentation/nvme-detach-ns.txt +++ b/Documentation/nvme-detach-ns.txt @@ -10,6 +10,7 @@ SYNOPSIS [verse] 'nvme detach-ns' [--namespace-id= | -n ] [--controllers= | -c + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -24,10 +25,19 @@ OPTIONS The namespace identifier to detach. -c :: --controllers=:: +--controllers=:: The comma separated list of controller identifiers to detach the namespace from. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-device-self-test.1 b/Documentation/nvme-device-self-test.1 index b9c402766c..605baf8ecb 100644 --- a/Documentation/nvme-device-self-test.1 +++ b/Documentation/nvme-device-self-test.1 @@ -2,12 +2,12 @@ .\" Title: nvme-device-self-test .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DEVICE\-SELF\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DEVICE\-SELF\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,8 @@ nvme-device-self-test \- Perform the necessary tests to observe the performance .sp .nf \fInvme device\-self\-test\fR [\-\-namespace\-id= | \-n ] - [\-\-self\-test\-code= | \-s ] + [\-\-self\-test\-code= | \-s ] [\-\-wait | \-w] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -51,7 +52,26 @@ Indicate the namespace in which the device self\-test has to be carried out .PP \-s , \-\-self\-test\-code= .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 +This field specifies the action taken by the device self\-test command : 0h: Show current state of device self\-test operation 1h: Start a short device self\-test operation 2h: Start a extended device self\-test operation eh: Start a vendor specific device self\-test operation fh: Abort the device self\-test operation Default is 0h\&. +.RE +.PP +\-w, \-\-wait +.RS 4 +Wait for the device self test to complete before exiting The device self\-test is aborted by SIGINT signal interrupt for the wait The option is ignored if the abort self\-test code option specified\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-device-self-test.html b/Documentation/nvme-device-self-test.html index e9eb6d7e26..ea0cb1350e 100644 --- a/Documentation/nvme-device-self-test.html +++ b/Documentation/nvme-device-self-test.html @@ -750,7 +750,8 @@

    SYNOPSIS

    nvme device-self-test <device> [--namespace-id=<NUM> | -n <NUM>]
    -                        [--self-test-code=<NUM> | -s <NUM>]
    + [--self-test-code=<NUM> | -s <NUM>] [--wait | -w] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -788,10 +789,48 @@

    OPTIONS

    This field specifies the action taken by the device self-test command : + 0h: Show current state of device self-test operation 1h: Start a short device self-test operation 2h: Start a extended device self-test operation eh: Start a vendor specific device self-test operation - fh: abort the device self-test operation + fh: Abort the device self-test operation + Default is 0h. +

    +
    +
    +-w +
    +
    +--wait +
    +
    +

    + Wait for the device self test to complete before exiting + The device self-test is aborted by SIGINT signal interrupt for the wait + The option is ignored if the abort self-test code option specified. +

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

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

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

    + Increase the information detail in the output.

    @@ -833,7 +872,7 @@

    NVME

    diff --git a/Documentation/nvme-device-self-test.txt b/Documentation/nvme-device-self-test.txt index 62bba88cea..17fe87580e 100644 --- a/Documentation/nvme-device-self-test.txt +++ b/Documentation/nvme-device-self-test.txt @@ -9,7 +9,8 @@ SYNOPSIS -------- [verse] 'nvme device-self-test' [--namespace-id= | -n ] - [--self-test-code= | -s ] + [--self-test-code= | -s ] [--wait | -w] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -28,12 +29,28 @@ OPTIONS -s :: --self-test-code=:: - 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 + This field specifies the action taken by the device self-test command : + 0h: Show current state of device self-test operation + 1h: Start a short device self-test operation + 2h: Start a extended device self-test operation + eh: Start a vendor specific device self-test operation + fh: Abort the device self-test operation + Default is 0h. +-w:: +--wait:: + Wait for the device self test to complete before exiting + The device self-test is aborted by SIGINT signal interrupt for the wait + The option is ignored if the abort self-test code option specified. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-dim.1 b/Documentation/nvme-dim.1 index 22fbef3fbf..f9245ea495 100644 --- a/Documentation/nvme-dim.1 +++ b/Documentation/nvme-dim.1 @@ -2,12 +2,12 @@ .\" Title: nvme-dim .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DIM" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DIM" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,10 +32,9 @@ nvme-dim \- Send Discovery Information Management command to one or more Discove .SH "SYNOPSIS" .sp .nf -\fInvme dim\fR - [\-\-task= | \-t ] - [\-\-nqn= | \-n ] - [\-\-device= | \-d ] +\fInvme dim\fR [\-\-task= | \-t ] [\-\-nqn= | \-n ] + [\-\-device= | \-d ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -62,6 +61,20 @@ The DIM command will be sent to the Discovery Controller (DC) matching this NQN\ .RS 4 The DIM command will be sent to the Discovery Controllers (DC) associated with this NVMe device handle\&. A list of comma\-separated device handles can be supplied to apply the command to more than one DC\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-dim.html b/Documentation/nvme-dim.html index d06d0a235e..2678197fc8 100644 --- a/Documentation/nvme-dim.html +++ b/Documentation/nvme-dim.html @@ -749,10 +749,9 @@

    NAME

    SYNOPSIS

    -
    nvme dim
    -                [--task=<task>     | -t <task>]
    -                [--nqn=<nqn>       | -n <nqn>]
    -                [--device=<device> | -d <device>]
    +
    nvme dim [--task=<task> | -t <task>] [--nqn=<nqn> | -n <nqn>]
    +                        [--device=<device> | -d <device>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -817,6 +816,29 @@

    OPTIONS

    be supplied to apply the command to more than one DC.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -863,7 +885,7 @@

    NVME

    diff --git a/Documentation/nvme-dim.txt b/Documentation/nvme-dim.txt index 52df256d13..fcfc9b8ad9 100644 --- a/Documentation/nvme-dim.txt +++ b/Documentation/nvme-dim.txt @@ -3,15 +3,15 @@ nvme-dim(1) NAME ---- -nvme-dim - Send Discovery Information Management command to one or more Discovery Controllers. +nvme-dim - Send Discovery Information Management command to one or more +Discovery Controllers. SYNOPSIS -------- [verse] -'nvme dim' - [--task= | -t ] - [--nqn= | -n ] - [--device= | -d ] +'nvme dim' [--task= | -t ] [--nqn= | -n ] + [--device= | -d ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -51,6 +51,15 @@ OPTIONS with this NVMe device handle. A list of comma-separated device handles can be supplied to apply the command to more than one DC. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Register with the Central Discovery Controller (CDC) named diff --git a/Documentation/nvme-dir-receive.1 b/Documentation/nvme-dir-receive.1 index 52ea328014..2d62d2dc92 100644 --- a/Documentation/nvme-dir-receive.1 +++ b/Documentation/nvme-dir-receive.1 @@ -2,12 +2,12 @@ .\" Title: nvme-dir-receive .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DIR\-RECEIVE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DIR\-RECEIVE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,13 +33,13 @@ nvme-dir-receive \- Send a directive receive command, returns applicable results .sp .nf \fInvme dir\-receive\fR [\-\-namespace\-id= | \-n ] - [\-\-data\-len= | \-l ] - [\-\-dir\-type= | \-D ] - [\-\-dir\-spec= | \-S ] - [\-\-dir\-oper= | \-O ] - [\-\-req\-resource= | \-r ] - [\-\-human\-readable | \-H] - [\-\-raw\-binary | \-b] + [\-\-data\-len= | \-l ] + [\-\-dir\-type= | \-D ] + [\-\-dir\-spec= | \-S ] + [\-\-dir\-oper= | \-O ] + [\-\-req\-resource= | \-r ] + [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -73,9 +73,6 @@ Directive operation \-r , \-\-req\-resource= .RS 4 Directive requested resource count -.RE -.sp -+ .TS allbox tab(:); lt lt @@ -85,49 +82,38 @@ 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 +.RE .PP \-l , \-\-data\-len= .RS 4 @@ -143,6 +129,20 @@ Print the raw receive buffer to stdout if the command returns a structure\&. .RS 4 Print the decoded receive buffer to stdout if the command returns a structure\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-dir-receive.html b/Documentation/nvme-dir-receive.html index bf0e505874..49d29f9fb3 100644 --- a/Documentation/nvme-dir-receive.html +++ b/Documentation/nvme-dir-receive.html @@ -750,13 +750,13 @@

    SYNOPSIS

    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]
    + [--data-len=<data-len> | -l <data-len>] + [--dir-type=<dtype> | -D <dtype>] + [--dir-spec=<dspec> | -S <dspec>] + [--dir-oper=<doper> | -O <doper>] + [--req-resource=<nsr> | -r <nsr>] + [--human-readable | -H] [--raw-binary | -b] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -835,9 +835,6 @@

    OPTIONS

    Directive requested resource count

    - - -

    +

    OPTIONS
    -
    +
    -l <data-len>
    @@ -911,6 +908,29 @@

    OPTIONS

    a structure.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -969,7 +989,7 @@

    NVME

    diff --git a/Documentation/nvme-dir-receive.txt b/Documentation/nvme-dir-receive.txt index b412c0b937..f3f31baebd 100644 --- a/Documentation/nvme-dir-receive.txt +++ b/Documentation/nvme-dir-receive.txt @@ -9,13 +9,13 @@ SYNOPSIS -------- [verse] 'nvme dir-receive' [--namespace-id= | -n ] - [--data-len= | -l ] - [--dir-type= | -D ] - [--dir-spec= | -S ] - [--dir-oper= | -O ] - [--req-resource= | -r ] - [--human-readable | -H] - [--raw-binary | -b] + [--data-len= | -l ] + [--dir-type= | -D ] + [--dir-spec= | -S ] + [--dir-oper= | -O ] + [--req-resource= | -r ] + [--human-readable | -H] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -41,20 +41,19 @@ OPTIONS -D :: --dir-type=:: - Directive type + Directive type -S :: --dir-spec=:: - Directive specific + Directive specific -O :: --dir-oper=:: - Directive operation + Directive operation -r :: --req-resource=:: Directive requested resource count - + [] |================== @@ -82,6 +81,15 @@ OPTIONS Print the decoded receive buffer to stdout if the command returns a structure. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Identify directive type supported : diff --git a/Documentation/nvme-dir-send.1 b/Documentation/nvme-dir-send.1 index 97b063dfad..482c77721b 100644 --- a/Documentation/nvme-dir-send.1 +++ b/Documentation/nvme-dir-send.1 @@ -2,12 +2,12 @@ .\" Title: nvme-dir-send .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DIR\-SEND" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DIR\-SEND" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,14 +33,14 @@ nvme-dir-send \- Issue a directive send command, returns applicable results .sp .nf \fInvme dir\-send\fR [\-\-namespace\-id= | \-n ] - [\-\-data\-len= | \-l ] - [\-\-dir\-type= | \-D ] - [\-\-dir\-spec= | \-S ] - [\-\-dir\-oper= | \-O ] - [\-\-endir= | \-e ] - [\-\-target\-dir= | \-T ] - [\-\-human\-readable | \-H] - [\-\-raw\-binary | \-b] + [\-\-data\-len= | \-l ] + [\-\-dir\-type= | \-D ] + [\-\-dir\-spec= | \-S ] + [\-\-dir\-oper= | \-O ] + [\-\-endir= | \-e ] + [\-\-target\-dir= | \-T ] + [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -79,9 +79,6 @@ Target directive of the operation \-e , \-\-endir= .RS 4 Target directive enable(1) or disable (0) operation -.RE -.sp -+ .TS allbox tab(:); lt lt @@ -91,49 +88,38 @@ 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 +.RE .PP \-l , \-\-data\-len= .RS 4 @@ -149,6 +135,20 @@ Print the raw receive buffer to stdout if the command returns a structure\&. .RS 4 Print the decoded receive buffer to stdout if the command returns a structure\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-dir-send.html b/Documentation/nvme-dir-send.html index bbcd938b75..a8182fa530 100644 --- a/Documentation/nvme-dir-send.html +++ b/Documentation/nvme-dir-send.html @@ -750,14 +750,14 @@

    SYNOPSIS

    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]
    + [--data-len=<data-len> | -l <data-len>] + [--dir-type=<dtype> | -D <dtype>] + [--dir-spec=<dspec> | -S <dspec>] + [--dir-oper=<doper> | -O <doper>] + [--endir=<endir> | -e <endir>] + [--target-dir=<tdir> | -T <tdir>] + [--human-readable | -H] [--raw-binary | -b] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -848,9 +848,6 @@

    OPTIONS

    Target directive enable(1) or disable (0) operation

    - - -

    +

    OPTIONS
    -
    +
    -l <data-len>
    @@ -924,6 +921,29 @@

    OPTIONS

    a structure.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -982,7 +1002,7 @@

    NVME

    diff --git a/Documentation/nvme-dir-send.txt b/Documentation/nvme-dir-send.txt index eb5dad0da0..1e3743d89e 100644 --- a/Documentation/nvme-dir-send.txt +++ b/Documentation/nvme-dir-send.txt @@ -9,14 +9,14 @@ SYNOPSIS -------- [verse] 'nvme dir-send' [--namespace-id= | -n ] - [--data-len= | -l ] - [--dir-type= | -D ] - [--dir-spec= | -S ] - [--dir-oper= | -O ] - [--endir= | -e ] - [--target-dir= | -T ] - [--human-readable | -H] - [--raw-binary | -b] + [--data-len= | -l ] + [--dir-type= | -D ] + [--dir-spec= | -S ] + [--dir-oper= | -O ] + [--endir= | -e ] + [--target-dir= | -T ] + [--human-readable | -H] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -43,15 +43,15 @@ OPTIONS -D :: --dir-type=:: - Directive type + Directive type -S :: --dir-spec=:: - Directive specific + Directive specific -O :: --dir-oper=:: - Directive operation + Directive operation -T :: --target-dir=:: @@ -60,7 +60,6 @@ OPTIONS -e :: --endir=:: Target directive enable(1) or disable (0) operation - + [] |================== @@ -88,6 +87,15 @@ OPTIONS Print the decoded receive buffer to stdout if the command returns a structure. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Enable streams directive : diff --git a/Documentation/nvme-disconnect-all.1 b/Documentation/nvme-disconnect-all.1 index 7bd523ed11..9652365918 100644 --- a/Documentation/nvme-disconnect-all.1 +++ b/Documentation/nvme-disconnect-all.1 @@ -2,12 +2,12 @@ .\" Title: nvme-disconnect-all .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DISCONNECT\-AL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DISCONNECT\-AL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,13 +32,28 @@ nvme-disconnect-all \- Disconnect from all connected Fabrics controllers\&. .SH "SYNOPSIS" .sp .nf -\fInvme disconnect\-all\fR +\fInvme disconnect\-all\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Disconnects and removes all existing NVMe over Fabrics controllers\&. .sp See the documentation for the nvme\-disconnect(1) command for further background\&. +.SH "OPTIONS" +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-disconnect-all.html b/Documentation/nvme-disconnect-all.html index 4280c37c6e..59b545eebb 100644 --- a/Documentation/nvme-disconnect-all.html +++ b/Documentation/nvme-disconnect-all.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme disconnect-all
    +
    nvme disconnect-all [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -763,6 +763,36 @@

    DESCRIPTION

    +

    OPTIONS

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

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

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

    + Increase the information detail in the output. +

    +
    +
    +
    +
    +

    EXAMPLES

      @@ -795,7 +825,7 @@

      NVME

      diff --git a/Documentation/nvme-disconnect-all.txt b/Documentation/nvme-disconnect-all.txt index 6be7e414de..9f023ea007 100644 --- a/Documentation/nvme-disconnect-all.txt +++ b/Documentation/nvme-disconnect-all.txt @@ -8,7 +8,7 @@ nvme-disconnect-all - Disconnect from all connected Fabrics controllers. SYNOPSIS -------- [verse] -'nvme disconnect-all' +'nvme disconnect-all' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -17,6 +17,17 @@ Disconnects and removes all existing NVMe over Fabrics controllers. See the documentation for the nvme-disconnect(1) command for further background. +OPTIONS +------- +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Disconnect all existing nvme controllers: diff --git a/Documentation/nvme-disconnect.1 b/Documentation/nvme-disconnect.1 index 84781045dc..2fcf3314e4 100644 --- a/Documentation/nvme-disconnect.1 +++ b/Documentation/nvme-disconnect.1 @@ -2,12 +2,12 @@ .\" Title: nvme-disconnect .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DISCONNECT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DISCONNECT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,9 @@ nvme-disconnect \- Disconnect one or more Fabrics controller(s)\&. .SH "SYNOPSIS" .sp .nf -\fInvme disconnect\fR - [\-\-nqn= | \-n ] - [\-\-device= | \-d ] +\fInvme disconnect\fR [\-\-nqn= | \-n ] + [\-\-device= | \-d ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -50,6 +50,20 @@ Indicates that all controllers for the NVMe subsystems specified should be remov .RS 4 Indicates that the controller with the specified name should be removed\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-disconnect.html b/Documentation/nvme-disconnect.html index 851bed2868..486efb4700 100644 --- a/Documentation/nvme-disconnect.html +++ b/Documentation/nvme-disconnect.html @@ -749,9 +749,9 @@

      NAME

      SYNOPSIS

      -
      nvme disconnect
      -                [--nqn=<subnqn>           | -n <subnqn>]
      -                [--device=<device>        | -d <device>]
      +
      nvme disconnect [--nqn=<subnqn> | -n <subnqn>]
      +                        [--device=<device> | -d <device>]
      +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
      @@ -761,7 +761,7 @@

      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 +identified by subnqn will be removed. If the --device option is specified the controller specified by the --device option will be removed.

    @@ -793,6 +793,29 @@

    OPTIONS

    removed.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -839,7 +862,7 @@

    NVME

    diff --git a/Documentation/nvme-disconnect.txt b/Documentation/nvme-disconnect.txt index badb86fa45..d3b8c524d7 100644 --- a/Documentation/nvme-disconnect.txt +++ b/Documentation/nvme-disconnect.txt @@ -8,15 +8,15 @@ nvme-disconnect - Disconnect one or more Fabrics controller(s). SYNOPSIS -------- [verse] -'nvme disconnect' - [--nqn= | -n ] - [--device= | -d ] +'nvme disconnect' [--nqn= | -n ] + [--device= | -d ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- Disconnects and removes one or more existing NVMe over Fabrics controllers. If the --nqn option is specified all controllers connecting to the Subsystem -identified by subnqn will be removed. If the --device option is specified +identified by subnqn will be removed. If the --device option is specified the controller specified by the --device option will be removed. OPTIONS @@ -31,6 +31,15 @@ OPTIONS Indicates that the controller with the specified name should be removed. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Disconnect all controllers for a subsystem named @@ -50,7 +59,6 @@ SEE ALSO -------- nvme-connect(1) - NVME ---- Part of the nvme-user suite diff --git a/Documentation/nvme-discover.1 b/Documentation/nvme-discover.1 index a24bf1fc9d..c099d1a446 100644 --- a/Documentation/nvme-discover.1 +++ b/Documentation/nvme-discover.1 @@ -2,12 +2,12 @@ .\" Title: nvme-discover .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DISCOVER" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DISCOVER" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,45 +32,43 @@ nvme-discover \- Send Get Log Page request to Discovery Controller\&. .SH "SYNOPSIS" .sp .nf -\fInvme discover\fR - [\-\-transport= | \-t ] - [\-\-nqn= | \-n ] - [\-\-traddr= | \-a ] - [\-\-trsvcid= | \-s ] - [\-\-host\-traddr= | \-w ] - [\-\-host\-iface= | \-f ] - [\-\-hostnqn= | \-q ] - [\-\-hostid= | \-I ] - [\-\-raw= | \-r ] - [\-\-device= | \-d ] - [\-\-cfg\-file= | \-C ] - [\-\-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 <#>] - [\-\-persistent | \-p] - [\-\-quiet | \-S] - [\-\-dump\-config | \-O] - [\-\-output\-format= | \-o ] - [\-\-force] +\fInvme discover\fR [\-\-transport= | \-t ] + [\-\-nqn= | \-n ] + [\-\-traddr= | \-a ] + [\-\-trsvcid= | \-s ] + [\-\-host\-traddr= | \-w ] + [\-\-host\-iface= | \-f ] + [\-\-hostnqn= | \-q ] + [\-\-hostid= | \-I ] + [\-\-raw= | \-r ] + [\-\-device= | \-d ] + [\-\-config= | \-J ] + [\-\-keep\-alive\-tmo= | \-k ] + [\-\-reconnect\-delay=<#> | \-c <#>] + [\-\-ctrl\-loss\-tmo=<#> | \-l <#>] + [\-\-nr\-io\-queues=<#> | \-i <#>] + [\-\-nr\-write\-queues=<#> | \-W <#>] + [\-\-nr\-poll\-queues=<#> | \-P <#>] + [\-\-queue\-size=<#> | \-Q <#>] [\-\-keyring=<#>] + [\-\-tls_key=<#>] [\-\-hdr\-digest | \-g] [\-\-data\-digest | \-G] + [\-\-persistent | \-p] [\-\-quiet | \-S] [\-\-tls] [\-\-concat] + [\-\-dump\-config | \-O] [\-\-output\-format= | \-o ] + [\-\-force] [\-\-nbft] [\-\-no\-nbft] [\-\-nbft\-path=] + [\-\-context=] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Send one or more Get Log Page requests to a NVMe\-over\-Fabrics Discovery Controller\&. .sp -If no parameters are given, then \fInvme discover\fR will attempt to find a /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\&. +If no parameters are given, then \fInvme discover\fR will attempt to find a /usr/local/etc/nvme/discovery\&.conf file to use to supply a list of Discovery commands to run\&. If no /usr/local/etc/nvme/discovery\&.conf file exists, the command will quit with an error\&. .sp Otherwise, a specific Discovery Controller should be specified using the \-\-transport, \-\-traddr, and if necessary the \-\-trsvcid flags\&. A Discovery request will then be sent to the specified Discovery Controller\&. .SH "BACKGROUND" .sp The NVMe\-over\-Fabrics specification defines the concept of a Discovery Controller that an NVMe Host can query on a fabric network to discover NVMe subsystems contained in NVMe Targets which it can connect to on the network\&. The Discovery Controller will return Discovery Log Pages that provide the NVMe Host with specific information (such as network address and unique subsystem NQN) the NVMe Host can use to issue an NVMe connect command to connect itself to a storage resource contained in that NVMe subsystem on the NVMe Target\&. .sp -Note that the base NVMe specification defines the NQN (NVMe Qualified Name) format which an NVMe endpoint (device, subsystem, etc) must follow to guarantee a unique name under the NVMe standard\&. In particular, the Host NQN uniquely identifies the NVMe Host, and may be used by the the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection\&. +Note that the base NVMe specification defines the NQN (NVMe Qualified Name) format which an NVMe endpoint (device, subsystem, etc) must follow to guarantee a unique name under the NVMe standard\&. In particular, the Host NQN uniquely identifies the NVMe Host, and may be used by the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection\&. .sp A Discovery Controller has it\(cqs own NQN defined in the NVMe\-over\-Fabrics specification, \fBnqn\&.2014\-08\&.org\&.nvmexpress\&.discovery\fR\&. All Discovery Controllers must use this NQN name\&. This NQN is used by default by nvme\-cli for the \fIdiscover\fR command\&. .SH "OPTIONS" @@ -122,7 +120,7 @@ This field specifies the name for the NVMe subsystem to connect to\&. .PP \-a , \-\-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\&. +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= @@ -142,7 +140,7 @@ This field specifies the network interface used on the host to connect to the Co .PP \-q , \-\-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\&. +Overrides the default host NQN that identifies the NVMe Host\&. If this option is not specified, the default is read from /usr/local/etc/nvme/hostnqn first\&. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next\&. .RE .PP \-I , \-\-hostid= @@ -161,20 +159,20 @@ will dump the output to stdout\&. .PP \-d , \-\-device= .RS 4 -This field takes a device as input\&. Device is in the format of nvme*, eg\&. nvme0, nvme1 +This field takes a device as input\&. It must be a persistent device associated with a Discovery Controller previously created by the command "connect\-all" or "discover"\&. follows the format nvme*, eg\&. nvme0, nvme1\&. .RE .PP -\-C , \-\-config\-file= +\-J , \-\-config= .RS 4 -Use the specified JSON configuration file instead of the default /etc/nvme/config\&.json file or +Use the specified JSON configuration file instead of the default /usr/local/etc/nvme/config\&.json file or \fInone\fR to not read in an existing configuration file\&. The JSON configuration file format is documented in -\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/doc/config\-schema\&.json\fR\m[] +\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/blob/master/doc/config\-schema\&.json\fR\m[] .RE .PP \-k <#>, \-\-keep\-alive\-tmo=<#> .RS 4 -Overrides the default timeout (in seconds) for keep alive\&. This option will be ignored for the discovery, and it is only implemented for completeness\&. +Overrides the default keep alive timeout (in seconds)\&. This option will be ignored for discovery, and it is only implemented for completeness\&. .RE .PP \-c <#>, \-\-reconnect\-delay=<#> @@ -187,16 +185,6 @@ Overrides the default delay (in seconds) before reconnect is attempted after a c 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\&. @@ -217,9 +205,39 @@ Adds additional queues that will be used for polling latency sensitive I/O\&. Overrides the default number of elements in the I/O queues created by the driver which can be found at drivers/nvme/host/fabrics\&.h\&. This option will be ignored for the discovery, and it is only implemented for completeness\&. .RE .PP +\-\-keyring=<#> +.RS 4 +Keyring for TLS key lookup\&. +.RE +.PP +\-\-tls_key=<#> +.RS 4 +TLS key for the connection (TCP)\&. +.RE +.PP +\-g, \-\-hdr\-digest +.RS 4 +Generates/verifies header digest (TCP)\&. +.RE +.PP +\-G, \-\-data\-digest +.RS 4 +Generates/verifies data digest (TCP)\&. +.RE +.PP \-p, \-\-persistent .RS 4 -Persistent discovery connection\&. +Don\(cqt remove the discovery controller after retrieving the discovery log page\&. +.RE +.PP +\-\-tls +.RS 4 +Enable TLS encryption (TCP)\&. +.RE +.PP +\-\-concat +.RS 4 +Enable secure concatenation (TCP)\&. .RE .PP \-S, \-\-quiet @@ -232,11 +250,12 @@ Suppress already connected errors\&. Print out resulting JSON configuration file to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE .PP @@ -244,6 +263,40 @@ Set the reporting format to .RS 4 Disable the built\-in persistent discover connection rules\&. Combined with \-\-persistent flag, always create new persistent discovery connection\&. .RE +.PP +\-\-nbft +.RS 4 +Only look at NBFT tables +.RE +.PP +\-\-no\-nbft +.RS 4 +Do not look at NBFT tables +.RE +.PP +\-\-nbft\-path= +.RS 4 +Use a user\-defined path to the NBFT tables +.RE +.PP +\-\-context +.RS 4 +Set the execution context to \&. This allows to coordinate the management of the global resources\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 @@ -278,15 +331,61 @@ Query the Discover Controller with IP4 address 192\&.168\&.1\&.3 for all resourc .\} Issue a \fInvme discover\fR -command using a /etc/nvme/discovery\&.conf file: +command using the default system defined NBFT tables: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme discover \-\-nbft +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Issue a +\fInvme discover\fR +command with a user\-defined path for the NBFT table: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme discover \-\-nbft\-path=/sys/firmware/acpi/tables/NBFT1 +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Issue a +\fInvme discover\fR +command using a /usr/local/etc/nvme/discovery\&.conf file: .sp .if n \{\ .RS 4 .\} .nf -# Machine default \*(Aqnvme discover\*(Aq commands\&. Query the +# 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 +# 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 diff --git a/Documentation/nvme-discover.html b/Documentation/nvme-discover.html index f0953b8214..0d5f6a92e1 100644 --- a/Documentation/nvme-discover.html +++ b/Documentation/nvme-discover.html @@ -749,32 +749,30 @@

    NAME

    SYNOPSIS

    -
    nvme discover
    -                [--transport=<trtype>     | -t <trtype>]
    -                [--nqn=<subnqn>           | -n <subnqn>]
    -                [--traddr=<traddr>        | -a <traddr>]
    -                [--trsvcid=<trsvcid>      | -s <trsvcid>]
    -                [--host-traddr=<traddr>   | -w <traddr>]
    -                [--host-iface=<iface>     | -f <iface>]
    -                [--hostnqn=<hostnqn>      | -q <hostnqn>]
    -                [--hostid=<hostid>        | -I <hostid>]
    -                [--raw=<filename>         | -r <filename>]
    -                [--device=<device>        | -d <device>]
    -                [--cfg-file=<cfg>         | -C <cfg> ]
    -                [--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]
    -                [--dump-config            | -O]
    -                [--output-format=<fmt>    | -o <fmt>]
    -                [--force]
    +
    nvme discover [--transport=<trtype> | -t <trtype>]
    +                        [--nqn=<subnqn> | -n <subnqn>]
    +                        [--traddr=<traddr> | -a <traddr>]
    +                        [--trsvcid=<trsvcid> | -s <trsvcid>]
    +                        [--host-traddr=<traddr> | -w <traddr>]
    +                        [--host-iface=<iface> | -f <iface>]
    +                        [--hostnqn=<hostnqn> | -q <hostnqn>]
    +                        [--hostid=<hostid> | -I <hostid>]
    +                        [--raw=<filename> | -r <filename>]
    +                        [--device=<device> | -d <device>]
    +                        [--config=<filename> | -J <filename>]
    +                        [--keep-alive-tmo=<sec> | -k <sec>]
    +                        [--reconnect-delay=<#> | -c <#>]
    +                        [--ctrl-loss-tmo=<#> | -l <#>]
    +                        [--nr-io-queues=<#> | -i <#>]
    +                        [--nr-write-queues=<#> | -W <#>]
    +                        [--nr-poll-queues=<#> | -P <#>]
    +                        [--queue-size=<#> | -Q <#>] [--keyring=<#>]
    +                        [--tls_key=<#>] [--hdr-digest | -g] [--data-digest | -G]
    +                        [--persistent | -p] [--quiet | -S] [--tls] [--concat]
    +                        [--dump-config | -O] [--output-format=<fmt> | -o <fmt>]
    +                        [--force] [--nbft] [--no-nbft] [--nbft-path=<STR>]
    +                        [--context=<STR>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -785,8 +783,8 @@

    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 +find a /usr/local/etc/nvme/discovery.conf file to use to supply a list of +Discovery commands to run. If no /usr/local/etc/nvme/discovery.conf file exists, the command will quit with an error.

    Otherwise, a specific Discovery Controller should be specified using the --transport, --traddr, and if necessary the --trsvcid flags. A Discovery @@ -799,7 +797,7 @@

    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 +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 @@ -809,10 +807,10 @@

    BACKGROUND

    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 +may be used by the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection.

    A Discovery Controller has it’s own NQN defined in the NVMe-over-Fabrics -specification, nqn.2014-08.org.nvmexpress.discovery. All Discovery +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.

    @@ -830,7 +828,7 @@

    OPTIONS

    This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + a NVMe-over-Fabrics network. Current string values include:

    OPTIONS

    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. + IP-based address (ex. IPv4).

    @@ -896,7 +894,7 @@

    OPTIONS

    - This field specifies the transport service id. For transports using IP + 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.

    @@ -937,7 +935,7 @@

    OPTIONS

    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 + /usr/local/etc/nvme/hostnqn first. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next.

    @@ -974,23 +972,25 @@

    OPTIONS

    - This field takes a device as input. Device is in the format of nvme*, - eg. nvme0, nvme1 + This field takes a device as input. It must be a persistent device + associated with a Discovery Controller previously created by the + command "connect-all" or "discover". <device> follows the format + nvme*, eg. nvme0, nvme1.

    --C <cfg> +-J <filename>
    ---config-file=<cfg> +--config=<filename>

    Use the specified JSON configuration file instead of the - default /etc/nvme/config.json file or none to not read in + default /usr/local/etc/nvme/config.json file or none to not read in an existing configuration file. The JSON configuration file format is documented in - https://github.com/linux-nvme/libnvme/doc/config-schema.json + https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json

    @@ -1001,8 +1001,8 @@

    OPTIONS

    - Overrides the default timeout (in seconds) for keep alive. - This option will be ignored for the discovery, and it is only + Overrides the default keep alive timeout (in seconds). This + option will be ignored for discovery, and it is only implemented for completeness.

    @@ -1030,74 +1030,90 @@

    OPTIONS

    --g +-i <#>
    ---hdr_digest +--nr-io-queues=<#>

    - Generates/verifies header digest (TCP). + 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.

    --G +-W <#>
    ---data_digest +--nr-write-queues=<#>

    - Generates/verifies data digest (TCP). + Adds additional queues that will be used for write I/O.

    --i <#> +-P <#>
    ---nr-io-queues=<#> +--nr-poll-queues=<#>

    - Overrides the default number of I/O queues create by the driver. + 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.

    --W <#> +--keyring=<#>
    +
    +

    + Keyring for TLS key lookup. +

    +
    ---nr-write-queues=<#> +--tls_key=<#>

    - Adds additional queues that will be used for write I/O. + TLS key for the connection (TCP).

    --P <#> +-g
    ---nr-poll-queues=<#> +--hdr-digest

    - Adds additional queues that will be used for polling latency sensitive I/O. + Generates/verifies header digest (TCP).

    --Q <#> +-G
    ---queue-size=<#> +--data-digest

    - 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. + Generates/verifies data digest (TCP).

    @@ -1108,7 +1124,24 @@

    OPTIONS

    - Persistent discovery connection. + Don’t remove the discovery controller after retrieving the discovery + log page. +

    +
    +
    +--tls +
    +
    +

    + Enable TLS encryption (TCP). +

    +
    +
    +--concat +
    +
    +

    + Enable secure concatenation (TCP).

    @@ -1134,15 +1167,15 @@

    OPTIONS

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

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

    @@ -1155,6 +1188,62 @@

    OPTIONS

    persistent discovery connection.

    +
    +--nbft +
    +
    +

    + Only look at NBFT tables +

    +
    +
    +--no-nbft +
    +
    +

    + Do not look at NBFT tables +

    +
    +
    +--nbft-path=<STR> +
    +
    +

    + Use a user-defined path to the NBFT tables +

    +
    +
    +--context <STR> +
    +
    +

    + Set the execution context to <STR>. This allows to coordinate + the management of the global resources. +

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -1176,13 +1265,31 @@

    EXAMPLES

  • -Issue a nvme discover command using a /etc/nvme/discovery.conf file: +Issue a nvme discover command using the default system defined NBFT tables: +

    +
    +
    +
    # nvme discover --nbft
    +
    +
  • +
  • +

    +Issue a nvme discover command with a user-defined path for the NBFT table: +

    +
    +
    +
    # nvme discover --nbft-path=/sys/firmware/acpi/tables/NBFT1
    +
    +
  • +
  • +

    +Issue a nvme discover command using a /usr/local/etc/nvme/discovery.conf file:

    -
    # Machine default 'nvme discover' commands.  Query the
    +
    # 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
    +# 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
    @@ -1218,7 +1325,7 @@ 

    NVME

    diff --git a/Documentation/nvme-discover.txt b/Documentation/nvme-discover.txt index 53826d54b6..1069d3cea1 100644 --- a/Documentation/nvme-discover.txt +++ b/Documentation/nvme-discover.txt @@ -8,32 +8,30 @@ nvme-discover - Send Get Log Page request to Discovery Controller. SYNOPSIS -------- [verse] -'nvme discover' - [--transport= | -t ] - [--nqn= | -n ] - [--traddr= | -a ] - [--trsvcid= | -s ] - [--host-traddr= | -w ] - [--host-iface= | -f ] - [--hostnqn= | -q ] - [--hostid= | -I ] - [--raw= | -r ] - [--device= | -d ] - [--cfg-file= | -C ] - [--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 <#>] - [--persistent | -p] - [--quiet | -S] - [--dump-config | -O] - [--output-format= | -o ] - [--force] +'nvme discover' [--transport= | -t ] + [--nqn= | -n ] + [--traddr= | -a ] + [--trsvcid= | -s ] + [--host-traddr= | -w ] + [--host-iface= | -f ] + [--hostnqn= | -q ] + [--hostid= | -I ] + [--raw= | -r ] + [--device= | -d ] + [--config= | -J ] + [--keep-alive-tmo= | -k ] + [--reconnect-delay=<#> | -c <#>] + [--ctrl-loss-tmo=<#> | -l <#>] + [--nr-io-queues=<#> | -i <#>] + [--nr-write-queues=<#> | -W <#>] + [--nr-poll-queues=<#> | -P <#>] + [--queue-size=<#> | -Q <#>] [--keyring=<#>] + [--tls_key=<#>] [--hdr-digest | -g] [--data-digest | -G] + [--persistent | -p] [--quiet | -S] [--tls] [--concat] + [--dump-config | -O] [--output-format= | -o ] + [--force] [--nbft] [--no-nbft] [--nbft-path=] + [--context=] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -42,7 +40,7 @@ Controller. If no parameters are given, then 'nvme discover' will attempt to find a @SYSCONFDIR@/nvme/discovery.conf file to use to supply a list of -Discovery commands to run. If no @SYSCONFDIR@/nvme/discovery.conf file +Discovery commands to run. If no @SYSCONFDIR@/nvme/discovery.conf file exists, the command will quit with an error. Otherwise, a specific Discovery Controller should be specified using the @@ -54,7 +52,7 @@ 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 +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 @@ -65,11 +63,11 @@ 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 +may be used by the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection. A Discovery Controller has it's own NQN defined in the NVMe-over-Fabrics -specification, *nqn.2014-08.org.nvmexpress.discovery*. All Discovery +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. @@ -78,7 +76,7 @@ OPTIONS -t :: --transport=:: This field specifies the network fabric being used for - a NVMe-over-Fabrics network. Current string values include: + a NVMe-over-Fabrics network. Current string values include: + [] |================= @@ -97,11 +95,11 @@ OPTIONS --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. + IP-based address (ex. IPv4). -s :: --trsvcid=:: - This field specifies the transport service id. For transports using IP + 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. @@ -137,21 +135,23 @@ OPTIONS -d :: --device=:: - This field takes a device as input. Device is in the format of nvme*, - eg. nvme0, nvme1 + This field takes a device as input. It must be a persistent device + associated with a Discovery Controller previously created by the + command "connect-all" or "discover". follows the format + nvme*, eg. nvme0, nvme1. --C :: ---config-file=:: +-J :: +--config=:: Use the specified JSON configuration file instead of the default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in an existing configuration file. The JSON configuration file format is documented in - https://github.com/linux-nvme/libnvme/doc/config-schema.json + https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json -k <#>:: --keep-alive-tmo=<#>:: - Overrides the default timeout (in seconds) for keep alive. - This option will be ignored for the discovery, and it is only + Overrides the default keep alive timeout (in seconds). This + option will be ignored for discovery, and it is only implemented for completeness. -c <#>:: @@ -163,14 +163,6 @@ OPTIONS --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. @@ -192,9 +184,30 @@ OPTIONS This option will be ignored for the discovery, and it is only implemented for completeness. +--keyring=<#>:: + Keyring for TLS key lookup. + +--tls_key=<#>:: + TLS key for the connection (TCP). + +-g:: +--hdr-digest:: + Generates/verifies header digest (TCP). + +-G:: +--data-digest:: + Generates/verifies data digest (TCP). + -p:: --persistent:: - Persistent discovery connection. + Don't remove the discovery controller after retrieving the discovery + log page. + +--tls:: + Enable TLS encryption (TCP). + +--concat:: + Enable secure concatenation (TCP). -S:: --quiet:: @@ -204,16 +217,38 @@ OPTIONS --dump-config:: Print out resulting JSON configuration file to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. --force:: Disable the built-in persistent discover connection rules. Combined with --persistent flag, always create new persistent discovery connection. +--nbft:: + Only look at NBFT tables + +--no-nbft:: + Do not look at NBFT tables + +--nbft-path=:: + Use a user-defined path to the NBFT tables + +--context :: + Set the execution context to . This allows to coordinate + the management of the global resources. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Query the Discover Controller with IP4 address 192.168.1.3 for all @@ -225,12 +260,24 @@ Port 4420 is used by default: --hostnqn=host1-rogue-nqn ------------ + +* Issue a 'nvme discover' command using the default system defined NBFT tables: ++ +----------- +# nvme discover --nbft +------------ ++ +* Issue a 'nvme discover' command with a user-defined path for the NBFT table: ++ +----------- +# nvme discover --nbft-path=/sys/firmware/acpi/tables/NBFT1 +------------ ++ * Issue a 'nvme discover' command using a @SYSCONFDIR@/nvme/discovery.conf file: + ----------- -# Machine default 'nvme discover' commands. Query the +# 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 +# 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 diff --git a/Documentation/nvme-dsm.1 b/Documentation/nvme-dsm.1 index 0955a087a0..ba3b7099f1 100644 --- a/Documentation/nvme-dsm.1 +++ b/Documentation/nvme-dsm.1 @@ -2,12 +2,12 @@ .\" Title: nvme-dsm .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-DSM" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-DSM" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,16 +32,18 @@ nvme-dsm \- Send NVMe Data Set Management, return results .SH "SYNOPSIS" .sp .nf -\fInvme dsm\fR [ \-\-namespace\-id= | \-n ] - [ \-\-ctx\-attrs= | \-a ] - [ \-\-blocks= | \-b ] - [ \-\-slbs= | \-s ] - [ \-\-ad | \-d ] [ \-\-idw | \-w ] [ \-\-idr | \-r ] - [ \-\-cdw11= | \-c ] +\fInvme dsm\fR [\-\-namespace\-id= | \-n ] + [\-\-ctx\-attrs= | \-a ] + [\-\-blocks= | \-b ] + [\-\-slbs= | \-s ] + [\-\-ad= | \-d ] + [\-\-idw= | \-w ] [\-\-idr= | \-r ] + [\-\-cdw11= | \-c ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp -For the NVMe device given, sends an Data Set Management command and provides the result and returned structure\&. +For the NVMe device given, sends a Data Set Management command and provides the result and returned structure\&. .sp The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. 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 @@ -89,6 +91,20 @@ Attribute Integral Dataset for Read\&. .RS 4 All the command command dword 11 attributes\&. Use exclusive from specifying individual attributes .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet diff --git a/Documentation/nvme-dsm.html b/Documentation/nvme-dsm.html index 502a307bf5..f5b4de2af6 100644 --- a/Documentation/nvme-dsm.html +++ b/Documentation/nvme-dsm.html @@ -749,12 +749,14 @@

    NAME

    SYNOPSIS

    -
    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> ]
    +
    nvme dsm <device> [--namespace-id=<nsid> | -n <nsid>]
    +                        [--ctx-attrs=<attribute-list,> | -a <attribute-list,>]
    +                        [--blocks=<nlb-list,> | -b <nlb-list,>]
    +                        [--slbs=<slba-list,> | -s <slba-list,>]
    +                        [--ad=<deallocate> | -d <deallocate>]
    +                        [--idw=<write> | -w <write>] [--idr=<read> | -r <read>]
    +                        [--cdw11=<cdw11> | -c <cdw11>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -762,7 +764,7 @@

    SYNOPSIS

    DESCRIPTION

    -

    For the NVMe device given, sends an Data Set Management command and +

    For the NVMe device given, sends a Data Set Management command and provides the result and returned structure.

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

    OPTIONS

    specifying individual attributes

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -893,7 +918,7 @@

    NVME

    diff --git a/Documentation/nvme-dsm.txt b/Documentation/nvme-dsm.txt index e81de14cc9..6a2e61a4e6 100644 --- a/Documentation/nvme-dsm.txt +++ b/Documentation/nvme-dsm.txt @@ -8,17 +8,18 @@ nvme-dsm - Send NVMe Data Set Management, return results SYNOPSIS -------- [verse] -'nvme dsm' [ --namespace-id= | -n ] - [ --ctx-attrs= | -a ] - [ --blocks= | -b ] - [ --slbs= | -s ] - [ --ad | -d ] [ --idw | -w ] [ --idr | -r ] - [ --cdw11= | -c ] - +'nvme dsm' [--namespace-id= | -n ] + [--ctx-attrs= | -a ] + [--blocks= | -b ] + [--slbs= | -s ] + [--ad= | -d ] + [--idw= | -w ] [--idr= | -r ] + [--cdw11= | -c ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- -For the NVMe device given, sends an Data Set Management command and +For the NVMe device given, sends a Data Set Management command and provides the result and returned structure. The parameter is mandatory and may be either the NVMe character @@ -73,6 +74,15 @@ OPTIONS All the command command dword 11 attributes. Use exclusive from specifying individual attributes +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet diff --git a/Documentation/nvme-effects-log.1 b/Documentation/nvme-effects-log.1 index 69b8d56847..112c264b3d 100644 --- a/Documentation/nvme-effects-log.1 +++ b/Documentation/nvme-effects-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-effects-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-EFFECTS\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-EFFECTS\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,8 @@ nvme-effects-log \- Send NVMe Command Effects log page request, returns result a .SH "SYNOPSIS" .sp .nf -\fInvme effects\-log\fR [\-\-output\-format= | \-o ] - [\-\-human\-readable | \-H] - [\-\-raw\-binary | \-b] +\fInvme effects\-log\fR [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -45,11 +44,6 @@ The parameter is mandatory and should be the NVMe character device (ex: On success, the returned command effects log structure will be printed for each command that is supported\&. .SH "OPTIONS" .PP -\-o , \-\-output\-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\&. @@ -59,6 +53,20 @@ This option will parse and format many of the bit fields into a human\-readable .RS 4 This option will print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the human\-readable option\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-effects-log.html b/Documentation/nvme-effects-log.html index ddff9e5aaa..b7570a9078 100644 --- a/Documentation/nvme-effects-log.html +++ b/Documentation/nvme-effects-log.html @@ -749,9 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme effects-log <device> [--output-format=<fmt> | -o <fmt>]
    -                            [--human-readable | -H]
    -                            [--raw-binary | -b]
    +
    nvme effects-log <device> [--human-readable | -H] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -772,39 +771,50 @@

    OPTIONS

    --o <format> +-H
    ---output-format=<format> +--human-readable

    - This option will set the reporting format to normal, json, or binary. - Only one output format can be used at a time. + This option will parse and format many of the bit fields into a + human-readable format.

    --H +-b
    ---human-readable +--raw-binary

    - This option will parse and format many of the bit fields into a - human-readable format. + This option will print the raw buffer to stdout. Structure is not + parsed by program. This overrides the human-readable option.

    --b +-o <fmt>
    ---raw-binary +--output-format=<fmt>

    - This option will print the raw buffer to stdout. Structure is not - parsed by program. This overrides the human-readable option. + Set the reporting format to normal, json or binary. Only one + output format can be used at a time. +

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

    + Increase the information detail in the output.

    @@ -847,7 +857,7 @@

    NVME

    diff --git a/Documentation/nvme-effects-log.txt b/Documentation/nvme-effects-log.txt index f7d0092dd4..57a13694e3 100644 --- a/Documentation/nvme-effects-log.txt +++ b/Documentation/nvme-effects-log.txt @@ -3,14 +3,14 @@ nvme-effects-log(1) NAME ---- -nvme-effects-log - Send NVMe Command Effects log page request, returns result and log +nvme-effects-log - Send NVMe Command Effects log page request, returns result +and log SYNOPSIS -------- [verse] -'nvme effects-log' [--output-format= | -o ] - [--human-readable | -H] - [--raw-binary | -b] +'nvme effects-log' [--human-readable | -H] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -26,11 +26,6 @@ for each command that is supported. OPTIONS ------- --o :: ---output-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 @@ -39,7 +34,16 @@ OPTIONS -b:: --raw-binary:: This option will print the raw buffer to stdout. Structure is not - parsed by program. This overrides the human-readable option. + parsed by program. This overrides the human-readable option. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-endurance-event-agg-log.1 b/Documentation/nvme-endurance-event-agg-log.1 index 6bb8981e70..08c22e9b2f 100644 --- a/Documentation/nvme-endurance-event-agg-log.1 +++ b/Documentation/nvme-endurance-event-agg-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-endurance-event-agg-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ENDURANCE\-EVE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ENDURANCE\-EVE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,7 +34,7 @@ nvme-endurance-event-agg-log \- Send NVMe Endurance log page request, returns re .nf \fInvme endurance\-event\-agg\-log\fR [\-\-log\-entries= | \-e ] [\-\-rae | \-r] [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,13 +55,19 @@ Retrieve the Endurance Group Event Aggregate Log pending entries\&. This argumen Retain an Asynchronous Event\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-endurance-event-agg-log.html b/Documentation/nvme-endurance-event-agg-log.html index 428d0c39fd..0bfc9e19a4 100644 --- a/Documentation/nvme-endurance-event-agg-log.html +++ b/Documentation/nvme-endurance-event-agg-log.html @@ -751,7 +751,7 @@

    SYNOPSIS

    nvme endurance-event-agg-log <device> [--log-entries=<log_entries> | -e <log_entries>]
                             [--rae | -r] [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -781,11 +781,11 @@

    OPTIONS

    - Retrieve the Endurance Group Event Aggregate Log pending entries. - This argument is mandatory and its success may depend on the device’s - statistics to provide this log For More details see NVM Express 1.4 Spec. - Section 5.14.1.15. The maximum number of log entries supported is 2044 - for the device. + Retrieve the Endurance Group Event Aggregate Log pending entries. + This argument is mandatory and its success may depend on the device’s + statistics to provide this log For More details see NVM Express 1.4 Spec. + Section 5.14.1.15. The maximum number of log entries supported is 2044 + for the device.

    @@ -800,15 +800,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -851,7 +862,7 @@

    NVME

    diff --git a/Documentation/nvme-endurance-event-agg-log.txt b/Documentation/nvme-endurance-event-agg-log.txt index 69701e3d52..7cbceb1b0e 100644 --- a/Documentation/nvme-endurance-event-agg-log.txt +++ b/Documentation/nvme-endurance-event-agg-log.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'nvme endurance-event-agg-log' [--log-entries= | -e ] [--rae | -r] [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -29,20 +29,24 @@ OPTIONS ------- -e :: --log-entries=:: - Retrieve the Endurance Group Event Aggregate Log pending entries. - This argument is mandatory and its success may depend on the device's - statistics to provide this log For More details see NVM Express 1.4 Spec. - Section 5.14.1.15. The maximum number of log entries supported is 2044 - for the device. + Retrieve the Endurance Group Event Aggregate Log pending entries. + This argument is mandatory and its success may depend on the device's + statistics to provide this log For More details see NVM Express 1.4 Spec. + Section 5.14.1.15. The maximum number of log entries supported is 2044 + for the device. -r:: --rae:: Retain an Asynchronous Event. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-endurance-log.1 b/Documentation/nvme-endurance-log.1 index 8e4b5456da..91cbdc1b0d 100644 --- a/Documentation/nvme-endurance-log.1 +++ b/Documentation/nvme-endurance-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-endurance-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ENDURANCE\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ENDURANCE\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-endurance-log \- Send NVMe Endurance log page request, returns result and l .sp .nf \fInvme endurance\-log\fR [\-\-group\-id= | \-g ] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -49,13 +49,19 @@ On success, the returned endurance log structure may be returned in one of sever The endurance group identifier\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-endurance-log.html b/Documentation/nvme-endurance-log.html index 03206fbc40..49ee586c57 100644 --- a/Documentation/nvme-endurance-log.html +++ b/Documentation/nvme-endurance-log.html @@ -750,7 +750,7 @@

    SYNOPSIS

    nvme endurance-log <device> [--group-id=<group> | -g <group>]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -783,15 +783,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -834,7 +845,7 @@

    NVME

    diff --git a/Documentation/nvme-endurance-log.txt b/Documentation/nvme-endurance-log.txt index 5e18b57ad0..c263834c93 100644 --- a/Documentation/nvme-endurance-log.txt +++ b/Documentation/nvme-endurance-log.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme endurance-log' [--group-id= | -g ] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -29,10 +29,14 @@ OPTIONS --group-id=:: The endurance group identifier. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-error-log.1 b/Documentation/nvme-error-log.1 index 5021d37ea1..b710a06c08 100644 --- a/Documentation/nvme-error-log.1 +++ b/Documentation/nvme-error-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-error-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ERROR\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ERROR\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,9 @@ nvme-error-log \- Send NVME Error log page request, return result and log .SH "SYNOPSIS" .sp .nf -\fInvme error\-log\fR [\-\-log\-entries= | \-e ] - [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] +\fInvme error\-log\fR [\-\-log\-entries= | \-e ] + [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,13 +55,19 @@ Specifies how many log entries the program should request from the device\&. Thi Print the raw error log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-error-log.html b/Documentation/nvme-error-log.html index c9b1ebb8b9..acf35fc3fe 100644 --- a/Documentation/nvme-error-log.html +++ b/Documentation/nvme-error-log.html @@ -749,9 +749,9 @@

    NAME

    SYNOPSIS

    -
    nvme error-log <device>  [--log-entries=<entries> | -e <entries>]
    -                         [--raw-binary | -b]
    -                         [--output-format=<fmt> | -o <fmt>]
    +
    nvme error-log <device> [--log-entries=<entries> | -e <entries>]
    +                        [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -798,15 +798,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -849,7 +860,7 @@

    NVME

    diff --git a/Documentation/nvme-error-log.txt b/Documentation/nvme-error-log.txt index eebaca7d3a..94442ee509 100644 --- a/Documentation/nvme-error-log.txt +++ b/Documentation/nvme-error-log.txt @@ -8,9 +8,9 @@ nvme-error-log - Send NVME Error log page request, return result and log SYNOPSIS -------- [verse] -'nvme error-log' [--log-entries= | -e ] - [--raw-binary | -b] - [--output-format= | -o ] +'nvme error-log' [--log-entries= | -e ] + [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -37,11 +37,14 @@ OPTIONS --raw-binary:: Print the raw error log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-fdp-configs.1 b/Documentation/nvme-fdp-configs.1 new file mode 100644 index 0000000000..1fdb44be5e --- /dev/null +++ b/Documentation/nvme-fdp-configs.1 @@ -0,0 +1,68 @@ +'\" t +.\" Title: nvme-fdp-configs +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-CONFIGS" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-configs \- Get Flexible Data Placement Configurations +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp configs\fR [\-\-endgrp\-id= | \-e ] + [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, and the endurance group identifier specified, list the possible configurations for Flexible Data Placement\&. +.SH "OPTIONS" +.PP +\-e , \-\-endgrp\-id= +.RS 4 +The endurance group identifier to use when requesting the log page\&. +.RE +.PP +\-H, \-\-human\-readable +.RS 4 +Parse, print and describe individual parts of bitfields\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Print the raw buffer to the standard output stream\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR, or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-configs.html b/Documentation/nvme-fdp-configs.html new file mode 100644 index 0000000000..dfcc5aa0f6 --- /dev/null +++ b/Documentation/nvme-fdp-configs.html @@ -0,0 +1,833 @@ + + + + + + +nvme-fdp-configs(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp configs <device> [--endgrp-id=<NUM> | -e <NUM>]
    +                        [--human-readable | -H] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, and the endurance group identifier specified, list +the possible configurations for Flexible Data Placement.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-e <NUM> +
    +
    +--endgrp-id=<NUM> +
    +
    +

    + The endurance group identifier to use when requesting the log page. +

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

    + Parse, print and describe individual parts of bitfields. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Print the raw buffer to the standard output stream. +

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

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

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-configs.txt b/Documentation/nvme-fdp-configs.txt new file mode 100644 index 0000000000..d5cc487343 --- /dev/null +++ b/Documentation/nvme-fdp-configs.txt @@ -0,0 +1,41 @@ +nvme-fdp-configs(1) +=================== + +NAME +---- +nvme-fdp-configs - Get Flexible Data Placement Configurations + +SYNOPSIS +-------- +[verse] +'nvme fdp configs' [--endgrp-id= | -e ] + [--human-readable | -H] [--raw-binary | -b] + [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, and the endurance group identifier specified, list +the possible configurations for Flexible Data Placement. + +OPTIONS +------- +-e :: +--endgrp-id=:: + The endurance group identifier to use when requesting the log page. + +-H:: +--human-readable:: + Parse, print and describe individual parts of bitfields. + +-b:: +--raw-binary:: + Print the raw buffer to the standard output stream. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. Only one + output format can be used at a time. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fdp-events.1 b/Documentation/nvme-fdp-events.1 new file mode 100644 index 0000000000..03c6ef2c67 --- /dev/null +++ b/Documentation/nvme-fdp-events.1 @@ -0,0 +1,67 @@ +'\" t +.\" Title: nvme-fdp-events +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-EVENTS" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-events \- Get Flexible Data Placement Events +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp events\fR [\-\-endgrp\-id= | \-e ] [\-\-host\-events | \-E] + [\-\-raw\-binary | \-b] [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, provide information about events affecting Reclaim Units and media usage in an Endurance Group\&. +.SH "OPTIONS" +.PP +\-e , \-\-endgrp\-id= +.RS 4 +The endurance group identifier to use when requesting the log page\&. +.RE +.PP +\-E, \-\-host\-events +.RS 4 +Request the controller to report host events\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Print the raw buffer to the standard output stream\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR, or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-events.html b/Documentation/nvme-fdp-events.html new file mode 100644 index 0000000000..79fffafaad --- /dev/null +++ b/Documentation/nvme-fdp-events.html @@ -0,0 +1,832 @@ + + + + + + +nvme-fdp-events(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp events <device> [--endgrp-id=<NUM> | -e <NUM>] [--host-events | -E]
    +                        [--raw-binary | -b] [--output-format=<fmt> | -o <fmt>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, provide information about events affecting Reclaim +Units and media usage in an Endurance Group.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-e <NUM> +
    +
    +--endgrp-id=<NUM> +
    +
    +

    + The endurance group identifier to use when requesting the log page. +

    +
    +
    +-E +
    +
    +--host-events +
    +
    +

    + Request the controller to report host events. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Print the raw buffer to the standard output stream. +

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

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

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-events.txt b/Documentation/nvme-fdp-events.txt new file mode 100644 index 0000000000..5602f448d3 --- /dev/null +++ b/Documentation/nvme-fdp-events.txt @@ -0,0 +1,40 @@ +nvme-fdp-events(1) +================== + +NAME +---- +nvme-fdp-events - Get Flexible Data Placement Events + +SYNOPSIS +-------- +[verse] +'nvme fdp events' [--endgrp-id= | -e ] [--host-events | -E] + [--raw-binary | -b] [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, provide information about events affecting Reclaim +Units and media usage in an Endurance Group. + +OPTIONS +------- +-e :: +--endgrp-id=:: + The endurance group identifier to use when requesting the log page. + +-E:: +--host-events:: + Request the controller to report host events. + +-b:: +--raw-binary:: + Print the raw buffer to the standard output stream. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. Only one + output format can be used at a time. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fdp-set-events.1 b/Documentation/nvme-fdp-set-events.1 new file mode 100644 index 0000000000..66aaa7e63d --- /dev/null +++ b/Documentation/nvme-fdp-set-events.1 @@ -0,0 +1,63 @@ +'\" t +.\" Title: nvme-fdp-set-events +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-SET\-EVEN" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-set-events \- Enable or disable FDP events +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp set\-events\fR [\-\-namespace\-id= | \-n ] + [\-\-placement\-handle= | \-p ] [\-\-enable | \-e] + [\-\-event\-types= | \-t ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, enable or disable a list of event types from being generated for the Reclaim Unit Handle reference by the specified Placement Handle\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Namespace identifier\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Print the raw buffer to the standard output stream\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR, or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-set-events.html b/Documentation/nvme-fdp-set-events.html new file mode 100644 index 0000000000..46157722dd --- /dev/null +++ b/Documentation/nvme-fdp-set-events.html @@ -0,0 +1,823 @@ + + + + + + +nvme-fdp-set-events(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp set-events <device> [--namespace-id=<NUM> | -n <NUM>]
    +                        [--placement-handle=<NUM> | -p <NUM>] [--enable | -e]
    +                        [--event-types=<NUM,> | -t <NUM,>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, enable or disable a list of event types from being +generated for the Reclaim Unit Handle reference by the specified Placement +Handle.

    +
    +
    +
    +

    OPTIONS

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

    + Namespace identifier. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Print the raw buffer to the standard output stream. +

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

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

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-set-events.txt b/Documentation/nvme-fdp-set-events.txt new file mode 100644 index 0000000000..b93cdc33a1 --- /dev/null +++ b/Documentation/nvme-fdp-set-events.txt @@ -0,0 +1,38 @@ +nvme-fdp-set-events(1) +====================== + +NAME +---- +nvme-fdp-set-events - Enable or disable FDP events + +SYNOPSIS +-------- +[verse] +'nvme fdp set-events' [--namespace-id= | -n ] + [--placement-handle= | -p ] [--enable | -e] + [--event-types= | -t ] + +DESCRIPTION +----------- +For the NVMe device given, enable or disable a list of event types from being +generated for the Reclaim Unit Handle reference by the specified Placement +Handle. + +OPTIONS +------- +-n :: +--namespace-id=:: + Namespace identifier. + +-b:: +--raw-binary:: + Print the raw buffer to the standard output stream. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. Only one + output format can be used at a time. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fdp-stats.1 b/Documentation/nvme-fdp-stats.1 new file mode 100644 index 0000000000..fb11832afc --- /dev/null +++ b/Documentation/nvme-fdp-stats.1 @@ -0,0 +1,62 @@ +'\" t +.\" Title: nvme-fdp-stats +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-STATS" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-stats \- Get Flexible Data Placement Statistics +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp stats\fR [\-\-endgrp\-id= | \-e ] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, provide information about the FDP configuration over the life of the FDP configuration in an Endurance Group\&. +.SH "OPTIONS" +.PP +\-e , \-\-endgrp\-id= +.RS 4 +The endurance group identifier to use when requesting the log page\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Print the raw buffer to the standard output stream\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR, or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-stats.html b/Documentation/nvme-fdp-stats.html new file mode 100644 index 0000000000..009bb38bd6 --- /dev/null +++ b/Documentation/nvme-fdp-stats.html @@ -0,0 +1,821 @@ + + + + + + +nvme-fdp-stats(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp stats <device> [--endgrp-id=<NUM> | -e <NUM>] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, provide information about the FDP configuration over +the life of the FDP configuration in an Endurance Group.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-e <NUM> +
    +
    +--endgrp-id=<NUM> +
    +
    +

    + The endurance group identifier to use when requesting the log page. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Print the raw buffer to the standard output stream. +

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

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

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-stats.txt b/Documentation/nvme-fdp-stats.txt new file mode 100644 index 0000000000..0b184a961b --- /dev/null +++ b/Documentation/nvme-fdp-stats.txt @@ -0,0 +1,36 @@ +nvme-fdp-stats(1) +================= + +NAME +---- +nvme-fdp-stats - Get Flexible Data Placement Statistics + +SYNOPSIS +-------- +[verse] +'nvme fdp stats' [--endgrp-id= | -e ] [--raw-binary | -b] + [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, provide information about the FDP configuration over +the life of the FDP configuration in an Endurance Group. + +OPTIONS +------- +-e :: +--endgrp-id=:: + The endurance group identifier to use when requesting the log page. + +-b:: +--raw-binary:: + Print the raw buffer to the standard output stream. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. Only one + output format can be used at a time. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fdp-status.1 b/Documentation/nvme-fdp-status.1 new file mode 100644 index 0000000000..362f4b1734 --- /dev/null +++ b/Documentation/nvme-fdp-status.1 @@ -0,0 +1,62 @@ +'\" t +.\" Title: nvme-fdp-status +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-STATUS" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-status \- Get Reclaim Unit Handle Status +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp status\fR [\-\-namespace\-id= | \-n ] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, provide information about Reclaim Unit Handles that are accessible by the specified namespace\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Namespace identifier\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Print the raw buffer to the standard output stream\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR, or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-status.html b/Documentation/nvme-fdp-status.html new file mode 100644 index 0000000000..a073a9425d --- /dev/null +++ b/Documentation/nvme-fdp-status.html @@ -0,0 +1,821 @@ + + + + + + +nvme-fdp-status(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp status <device> [--namespace-id=<NUM> | -n <NUM>] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, provide information about Reclaim Unit Handles that +are accessible by the specified namespace.

    +
    +
    +
    +

    OPTIONS

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

    + Namespace identifier. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Print the raw buffer to the standard output stream. +

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

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

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-status.txt b/Documentation/nvme-fdp-status.txt new file mode 100644 index 0000000000..78dddaedf2 --- /dev/null +++ b/Documentation/nvme-fdp-status.txt @@ -0,0 +1,36 @@ +nvme-fdp-status(1) +================== + +NAME +---- +nvme-fdp-status - Get Reclaim Unit Handle Status + +SYNOPSIS +-------- +[verse] +'nvme fdp status' [--namespace-id= | -n ] [--raw-binary | -b] + [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, provide information about Reclaim Unit Handles that +are accessible by the specified namespace. + +OPTIONS +------- +-n :: +--namespace-id=:: + Namespace identifier. + +-b:: +--raw-binary:: + Print the raw buffer to the standard output stream. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. Only one + output format can be used at a time. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fdp-update.1 b/Documentation/nvme-fdp-update.1 new file mode 100644 index 0000000000..ca7e39a3fe --- /dev/null +++ b/Documentation/nvme-fdp-update.1 @@ -0,0 +1,54 @@ +'\" t +.\" Title: nvme-fdp-update +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-UPDATE" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-update \- Reclaim Unit Handle Update +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp update\fR [\-\-namespace\-id= | \-n ] + [\-\-pids= | \-p ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, update the given Placement Identifiers to reference a different Reclaim Unit accessible by the specified namespace\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Namespace identifier\&. +.RE +.PP +\-p , \-\-pids= +.RS 4 +Comma\-separated list of placement identifiers to update\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-update.html b/Documentation/nvme-fdp-update.html new file mode 100644 index 0000000000..2ad566ffe0 --- /dev/null +++ b/Documentation/nvme-fdp-update.html @@ -0,0 +1,809 @@ + + + + + + +nvme-fdp-update(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp update <device> [--namespace-id=<NUM> | -n <NUM>]
    +                        [--pids=<NUM,> | -p <NUM,>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, update the given Placement Identifiers to reference +a different Reclaim Unit accessible by the specified namespace.

    +
    +
    +
    +

    OPTIONS

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

    + Namespace identifier. +

    +
    +
    +-p <NUM,> +
    +
    +--pids=<NUM,> +
    +
    +

    + Comma-separated list of placement identifiers to update. +

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-update.txt b/Documentation/nvme-fdp-update.txt new file mode 100644 index 0000000000..5af83e5a5f --- /dev/null +++ b/Documentation/nvme-fdp-update.txt @@ -0,0 +1,31 @@ +nvme-fdp-update(1) +================== + +NAME +---- +nvme-fdp-update - Reclaim Unit Handle Update + +SYNOPSIS +-------- +[verse] +'nvme fdp update' [--namespace-id= | -n ] + [--pids= | -p ] + +DESCRIPTION +----------- +For the NVMe device given, update the given Placement Identifiers to reference +a different Reclaim Unit accessible by the specified namespace. + +OPTIONS +------- +-n :: +--namespace-id=:: + Namespace identifier. + +-p :: +--pids=:: + Comma-separated list of placement identifiers to update. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fdp-usage.1 b/Documentation/nvme-fdp-usage.1 new file mode 100644 index 0000000000..912d0fd488 --- /dev/null +++ b/Documentation/nvme-fdp-usage.1 @@ -0,0 +1,62 @@ +'\" t +.\" Title: nvme-fdp-usage +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-FDP\-USAGE" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-fdp-usage \- Get Reclaim Unit Handle Usage +.SH "SYNOPSIS" +.sp +.nf +\fInvme fdp usage\fR [\-\-endgrp\-id= | \-e ] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, provide information about the Reclaim Unit Handles associated with the Placement Handles of the namespaces in the specified Endurance Group\&. +.SH "OPTIONS" +.PP +\-e , \-\-endgrp\-id= +.RS 4 +The endurance group identifier to use when requesting the log page\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Print the raw buffer to the standard output stream\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR, or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-fdp-usage.html b/Documentation/nvme-fdp-usage.html new file mode 100644 index 0000000000..aaa349b20c --- /dev/null +++ b/Documentation/nvme-fdp-usage.html @@ -0,0 +1,822 @@ + + + + + + +nvme-fdp-usage(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme fdp usage <device> [--endgrp-id=<NUM> | -e <NUM>] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, provide information about the Reclaim Unit Handles +associated with the Placement Handles of the namespaces in the specified +Endurance Group.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-e <NUM> +
    +
    +--endgrp-id=<NUM> +
    +
    +

    + The endurance group identifier to use when requesting the log page. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Print the raw buffer to the standard output stream. +

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

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

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-fdp-usage.txt b/Documentation/nvme-fdp-usage.txt new file mode 100644 index 0000000000..3e0fb98999 --- /dev/null +++ b/Documentation/nvme-fdp-usage.txt @@ -0,0 +1,37 @@ +nvme-fdp-usage(1) +================= + +NAME +---- +nvme-fdp-usage - Get Reclaim Unit Handle Usage + +SYNOPSIS +-------- +[verse] +'nvme fdp usage' [--endgrp-id= | -e ] [--raw-binary | -b] + [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, provide information about the Reclaim Unit Handles +associated with the Placement Handles of the namespaces in the specified +Endurance Group. + +OPTIONS +------- +-e :: +--endgrp-id=:: + The endurance group identifier to use when requesting the log page. + +-b:: +--raw-binary:: + Print the raw buffer to the standard output stream. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. Only one + output format can be used at a time. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-fid-support-effects-log.1 b/Documentation/nvme-fid-support-effects-log.1 index b61a7452f9..82417b4799 100644 --- a/Documentation/nvme-fid-support-effects-log.1 +++ b/Documentation/nvme-fid-support-effects-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-fid-support-effects-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-FID\-SUPPORT\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-FID\-SUPPORT\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-fid-support-effects-log \- Send NVMe FID Support and Effects log, return re .SH "SYNOPSIS" .sp .nf -\fInvme fid\-support\-effects\-log\fR [\-o | \-\-output\-format=] +\fInvme fid\-support\-effects\-log\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -43,17 +43,23 @@ The parameter is mandatory and may be either the NVMe character device On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-H, \-\-human\-readable +.RS 4 +This option will parse and format many of the bit fields into human\-readable formats\&. +.RE +.PP +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE .PP -\-H, \-\-human\-readable +\-v, \-\-verbose .RS 4 -This option will parse and format many of the bit fields into human\-readable formats\&. +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-fid-support-effects-log.html b/Documentation/nvme-fid-support-effects-log.html index 75abd3d295..d23d711065 100644 --- a/Documentation/nvme-fid-support-effects-log.html +++ b/Documentation/nvme-fid-support-effects-log.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme fid-support-effects-log <device> [-o <fmt> | --output-format=<fmt>]
    +
    nvme fid-support-effects-log <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -771,27 +771,38 @@

    OPTIONS

    --o <format> +-H
    ---output-format=<format> +--human-readable

    - Set the reporting format to normal, json, or - binary. Only one output format can be used at a time. + This option will parse and format many of the bit fields + into human-readable formats.

    --H +-o <fmt>
    ---human-readable +--output-format=<fmt>

    - This option will parse and format many of the bit fields - into human-readable formats. + Set the reporting format to normal, json or binary. Only one + output format can be used at a time. +

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

    + Increase the information detail in the output.

    @@ -814,7 +825,7 @@

    NVME

    diff --git a/Documentation/nvme-fid-support-effects-log.txt b/Documentation/nvme-fid-support-effects-log.txt index 5d12b18adb..9670b8878c 100644 --- a/Documentation/nvme-fid-support-effects-log.txt +++ b/Documentation/nvme-fid-support-effects-log.txt @@ -8,7 +8,7 @@ nvme-fid-support-effects-log - Send NVMe FID Support and Effects log, return res SYNOPSIS -------- [verse] -'nvme fid-support-effects-log' [-o | --output-format=] +'nvme fid-support-effects-log' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -24,16 +24,20 @@ raw buffer may be printed to stdout. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - -H:: --human-readable:: This option will parse and format many of the bit fields into human-readable formats. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-flush.1 b/Documentation/nvme-flush.1 index c5654baebe..a5ca384ca3 100644 --- a/Documentation/nvme-flush.1 +++ b/Documentation/nvme-flush.1 @@ -2,12 +2,12 @@ .\" Title: nvme-flush .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-FLUSH" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-FLUSH" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,6 +33,7 @@ nvme-flush \- Flush command\&. .sp .nf \fInvme flush\fR [\-\-namespace\-id= | \-n ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -43,6 +44,20 @@ The Flush command shall commit data and metadata associated with the specified n .RS 4 Specify the optional namespace id for this command\&. Defaults to 0xffffffff, indicating flush for all namespaces\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-flush.html b/Documentation/nvme-flush.html index 3b8f45bad3..b008b968e2 100644 --- a/Documentation/nvme-flush.html +++ b/Documentation/nvme-flush.html @@ -749,7 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme flush <device> [--namespace-id=<nsid> | -n <nsid>]
    +
    nvme flush <device> [--namespace-id=<nsid> | -n <nsid>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -780,6 +781,29 @@

    OPTIONS

    0xffffffff, indicating flush for all namespaces.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -800,7 +824,7 @@

    NVME

    diff --git a/Documentation/nvme-flush.txt b/Documentation/nvme-flush.txt index 28cfa63b97..102cd71d12 100644 --- a/Documentation/nvme-flush.txt +++ b/Documentation/nvme-flush.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'nvme flush' [--namespace-id= | -n ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -25,6 +26,15 @@ OPTIONS Specify the optional namespace id for this command. Defaults to 0xffffffff, indicating flush for all namespaces. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-format.1 b/Documentation/nvme-format.1 index 422cf34874..6837f23fcb 100644 --- a/Documentation/nvme-format.1 +++ b/Documentation/nvme-format.1 @@ -2,12 +2,12 @@ .\" Title: nvme-format .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-FORMAT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-FORMAT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,15 +33,13 @@ nvme-format \- Format an NVMe device .sp .nf \fInvme format\fR [\-\-namespace\-id= | \-n ] - [\-\-lbaf= | \-l ] - [\-\-block\-size=] - [\-\-ses= | \-s ] - [\-\-pil= | \-p ] - [\-\-pi= | \-i ] - [\-\-ms= | \-m ] - [\-\-reset | \-r ] - [\-\-force ] - [\-\-timeout= | \-t ] + [\-\-lbaf= | \-l ] + [\-\-block\-size=] + [\-\-ses= | \-s ] [\-\-pil= | \-p ] + [\-\-pi= | \-i ] [\-\-ms= | \-m ] + [\-\-reset | \-r] [\-\-force] + [\-\-timeout= | \-t ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -177,6 +175,20 @@ Just send the command immediately without warning of the implications\&. .RS 4 Override default timeout value\&. In milliseconds\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-format.html b/Documentation/nvme-format.html index 28eef20451..f462649fc2 100644 --- a/Documentation/nvme-format.html +++ b/Documentation/nvme-format.html @@ -750,15 +750,13 @@

    SYNOPSIS

    nvme format <device> [--namespace-id=<nsid> | -n <nsid>]
    -                    [--lbaf=<lbaf> | -l <lbaf>]
    -                    [--block-size=<block size | -b <block size>]
    -                    [--ses=<ses> | -s <ses>]
    -                    [--pil=<pil> | -p <pil>]
    -                    [--pi=<pi> | -i <pi>]
    -                    [--ms=<ms> | -m <ms>]
    -                    [--reset | -r ]
    -                    [--force ]
    -                    [--timeout=<timeout> | -t <timeout> ]
    + [--lbaf=<lbaf> | -l <lbaf>] + [--block-size=<block size | -b <block size>] + [--ses=<ses> | -s <ses>] [--pil=<pil> | -p <pil>] + [--pi=<pi> | -i <pi>] [--ms=<ms> | -m <ms>] + [--reset | -r] [--force] + [--timeout=<timeout> | -t <timeout>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -995,6 +993,29 @@

    OPTIONS

    Override default timeout value. In milliseconds.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -1035,7 +1056,7 @@

    NVME

    diff --git a/Documentation/nvme-format.txt b/Documentation/nvme-format.txt index cbadd1d62d..e4623f152c 100644 --- a/Documentation/nvme-format.txt +++ b/Documentation/nvme-format.txt @@ -9,15 +9,13 @@ SYNOPSIS -------- [verse] 'nvme format' [--namespace-id= | -n ] - [--lbaf= | -l ] - [--block-size=] - [--ses= | -s ] - [--pil= | -p ] - [--pi= | -i ] - [--ms= | -m ] - [--reset | -r ] - [--force ] - [--timeout= | -t ] + [--lbaf= | -l ] + [--block-size=] + [--ses= | -s ] [--pil= | -p ] + [--pi= | -i ] [--ms= | -m ] + [--reset | -r] [--force] + [--timeout= | -t ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -135,6 +133,15 @@ cryptographically. This is accomplished by deleting the encryption key. --timeout=:: Override default timeout value. In milliseconds. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Format the device using all defaults: diff --git a/Documentation/nvme-fw-commit.1 b/Documentation/nvme-fw-commit.1 index 6701bcf16e..62e46ee60e 100644 --- a/Documentation/nvme-fw-commit.1 +++ b/Documentation/nvme-fw-commit.1 @@ -2,12 +2,12 @@ .\" Title: nvme-fw-commit .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-FW\-COMMIT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-FW\-COMMIT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,8 +33,9 @@ nvme-fw-commit \- Used to verify and commit a firmware image\&. .sp .nf \fInvme fw\-commit\fR [\-\-slot= | \-s ] - [\-\-action= | \-a ] - [\-\-bpid= | \-b ] + [\-\-action= | \-a ] + [\-\-bpid= | \-b ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -117,6 +118,20 @@ Firmware Slot: Specifies the firmware slot that shall be used for the Commit Act .RS 4 Specifies the Boot partition that shall be used for the Commit Action, if applicable (default: 0) .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-fw-commit.html b/Documentation/nvme-fw-commit.html index 13c810e73a..5f02e38caf 100644 --- a/Documentation/nvme-fw-commit.html +++ b/Documentation/nvme-fw-commit.html @@ -750,8 +750,9 @@

    SYNOPSIS

    nvme fw-commit <device> [--slot=<slot> | -s <slot>]
    -                    [--action=<action> | -a <action>]
    -                    [--bpid=<boot-partid> | -b <boot-partid> ]
    + [--action=<action> | -a <action>] + [--bpid=<boot-partid> | -b <boot-partid>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -869,6 +870,29 @@

    OPTIONS

    if applicable (default: 0)

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -905,7 +929,7 @@

    NVME

    diff --git a/Documentation/nvme-fw-commit.txt b/Documentation/nvme-fw-commit.txt index 337e783efb..8e08bd443e 100644 --- a/Documentation/nvme-fw-commit.txt +++ b/Documentation/nvme-fw-commit.txt @@ -9,8 +9,9 @@ SYNOPSIS -------- [verse] 'nvme fw-commit' [--slot= | -s ] - [--action= | -a ] - [--bpid= | -b ] + [--action= | -a ] + [--bpid= | -b ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -75,6 +76,15 @@ BPINFO.ABPID. Specifies the Boot partition that shall be used for the Commit Action, if applicable (default: 0) +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * commit the last downloaded fw to slot 1. diff --git a/Documentation/nvme-fw-download.1 b/Documentation/nvme-fw-download.1 index ac58b8bbdc..18a87cae1c 100644 --- a/Documentation/nvme-fw-download.1 +++ b/Documentation/nvme-fw-download.1 @@ -2,12 +2,12 @@ .\" Title: nvme-fw-download .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-FW\-DOWNLOAD" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-FW\-DOWNLOAD" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,8 +33,9 @@ nvme-fw-download \- Download all or a portion of an nvme firmware image\&. .sp .nf \fInvme fw\-download\fR [\-\-fw= | \-f ] - [\-\-xfer= | \-x ] - [\-\-offset= | \-o ] + [\-\-xfer= | \-x ] + [\-\-offset= | \-O ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,12 +56,26 @@ Required argument\&. This specifies the path to the device\(cqs firmware file on 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= +\-O , \-\-offset= .RS 4 This specifies the starting offset in dwords\&. This is really only useful if your firmware is split in multiple files; otherwise the offset starts at zero and automatically adjusts based on the \fIxfer\fR size given\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-fw-download.html b/Documentation/nvme-fw-download.html index 7a708c6fc2..278bb7aca0 100644 --- a/Documentation/nvme-fw-download.html +++ b/Documentation/nvme-fw-download.html @@ -750,8 +750,9 @@

    SYNOPSIS

    nvme fw-download <device> [--fw=<firmware-file> | -f <firmware-file>]
    -                    [--xfer=<transfer-size> | -x <transfer-size>]
    -                    [--offset=<offset> | -o <offset>]
    + [--xfer=<transfer-size> | -x <transfer-size>] + [--offset=<offset> | -O <offset>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -809,7 +810,7 @@

    OPTIONS

    --o <offset> +-O <offset>
    --offset=<offset> @@ -822,6 +823,29 @@

    OPTIONS

    xfer size given.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -852,7 +876,7 @@

    NVME

    diff --git a/Documentation/nvme-fw-download.txt b/Documentation/nvme-fw-download.txt index 84e407ed83..1ec466f309 100644 --- a/Documentation/nvme-fw-download.txt +++ b/Documentation/nvme-fw-download.txt @@ -9,8 +9,9 @@ SYNOPSIS -------- [verse] 'nvme fw-download' [--fw= | -f ] - [--xfer= | -x ] - [--offset= | -o ] + [--xfer= | -x ] + [--offset= | -O ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -48,13 +49,22 @@ OPTIONS the device has a max transfer size requirement for firmware. It defaults to 4k. --o :: +-O :: --offset=:: This specifies the starting offset in dwords. This is really only useful if your firmware is split in multiple files; otherwise the offset starts at zero and automatically adjusts based on the 'xfer' size given. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Transfer a firmware size 128KiB at a time: diff --git a/Documentation/nvme-fw-log.1 b/Documentation/nvme-fw-log.1 index 81abc4116b..03776a79a7 100644 --- a/Documentation/nvme-fw-log.1 +++ b/Documentation/nvme-fw-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-fw-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-FW\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-FW\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-fw-log \- Send NVMe Firmware log page request, returns result and log .sp .nf \fInvme fw\-log\fR [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -49,13 +49,19 @@ On success, the returned f/w log structure may be returned in one of several way Print the raw fw log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-fw-log.html b/Documentation/nvme-fw-log.html index 40e1ebc8cc..92fd8f0042 100644 --- a/Documentation/nvme-fw-log.html +++ b/Documentation/nvme-fw-log.html @@ -750,7 +750,7 @@

    SYNOPSIS

    nvme fw-log <device> [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -784,15 +784,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -835,7 +846,7 @@

    NVME

    diff --git a/Documentation/nvme-fw-log.txt b/Documentation/nvme-fw-log.txt index 4b735772a2..d95754802f 100644 --- a/Documentation/nvme-fw-log.txt +++ b/Documentation/nvme-fw-log.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme fw-log' [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -30,11 +30,14 @@ OPTIONS --raw-binary:: Print the raw fw log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-gen-dhchap-key.txt b/Documentation/nvme-gen-dhchap-key.txt index 79e8ed588b..1e5f9696ed 100644 --- a/Documentation/nvme-gen-dhchap-key.txt +++ b/Documentation/nvme-gen-dhchap-key.txt @@ -9,9 +9,10 @@ SYNOPSIS -------- [verse] 'nvme gen-dhchap-key' [--hmac= | -h ] - [--secret= | -s ] - [--key-length= | -l ] - [--nqn= | -n ] + [--secret= | -s ] + [--key-length= | -l ] + [--nqn= | -n ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -43,6 +44,15 @@ OPTIONS Host-NQN to be used for the transformation. This parameter is only valid if a non-zero HMAC function has been specified. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No Examples diff --git a/Documentation/nvme-gen-hostnqn.1 b/Documentation/nvme-gen-hostnqn.1 index 40d0d7f31e..843a8a85fd 100644 --- a/Documentation/nvme-gen-hostnqn.1 +++ b/Documentation/nvme-gen-hostnqn.1 @@ -2,12 +2,12 @@ .\" Title: nvme-gen-hostnqn .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GEN\-HOSTNQN" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-GEN\-HOSTNQN" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,14 +32,26 @@ nvme-gen-hostnqn \- Generate a host NVMe Qualified Name .SH "SYNOPSIS" .sp .nf -\fInvme gen\-hostnqn\fR +\fInvme gen\-hostnqn\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Generate a random host NQN in the form: nqn\&.2014\-08\&.org\&.nvmexpress:uuid:1b4e28ba\-2fa1\-11d2\-883f\-0016d3cca427 and prints it to stdout\&. .SH "OPTIONS" -.sp -No options needed +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp nvme gen\-hostnqn diff --git a/Documentation/nvme-gen-hostnqn.html b/Documentation/nvme-gen-hostnqn.html index 29d2b747d6..a6d5fdaae4 100644 --- a/Documentation/nvme-gen-hostnqn.html +++ b/Documentation/nvme-gen-hostnqn.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme gen-hostnqn
    +
    nvme gen-hostnqn [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -765,7 +765,31 @@

    DESCRIPTION

    OPTIONS

    -

    No options needed

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

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

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

    + Increase the information detail in the output. +

    +
    +
    @@ -785,7 +809,7 @@

    NVME

    diff --git a/Documentation/nvme-gen-hostnqn.txt b/Documentation/nvme-gen-hostnqn.txt index 9efefb5a45..7b7d776d35 100644 --- a/Documentation/nvme-gen-hostnqn.txt +++ b/Documentation/nvme-gen-hostnqn.txt @@ -8,7 +8,7 @@ nvme-gen-hostnqn - Generate a host NVMe Qualified Name SYNOPSIS -------- [verse] -'nvme gen-hostnqn' +'nvme gen-hostnqn' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -18,7 +18,14 @@ and prints it to stdout. OPTIONS ------- -No options needed +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-gen-tls-key.txt b/Documentation/nvme-gen-tls-key.txt index cfa8614708..772c7bcb3c 100644 --- a/Documentation/nvme-gen-tls-key.txt +++ b/Documentation/nvme-gen-tls-key.txt @@ -8,29 +8,88 @@ nvme-gen-tls-key - Generate a NVMe TLS PSK SYNOPSIS -------- [verse] -'nvme gen-tls-key' [--hmac= | -h ] - [--secret= | -s ] +'nvme gen-tls-key' [--keyring= | -k ] + [--keytype= | -t ] + [--hostnqn= | -n ] + [--subsysnqn= | -c ] + [--hmac= | -h ] + [--identity= | -I ] + [--secret= | -s ] + [--insert | -i] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- -Generate a base64-encoded NVMe TLS pre-shared key (PSK) in -the PSK interchange format -NVMeTLSkey-1:01:VRLbtnN9AQb2WXW3c9+wEf/DRLz0QuLdbYvEhwtdWwNf9LrZ: -and prints it to stdout. +Generate a base64-encoded NVMe TLS pre-shared key (PSK). +The resulting key is either printed in the PSK interchange format +'NVMeTLSkey-1:01::' or inserted as a +'retained' key into the specified keyring if the '--insert' option +is given. +When the PSK should be inserted into the keyring a 'retained' key +is derived from the secret key material. The resulting 'retained' +key is stored with the identity +'NVMe0R0 ' +(for identity version '0') or +'NVMe1R0 ' +(for identity version '1') in the keyring. +The 'retained' key is derived from the secret key material, +the specified subsystem NQN, and the host NQN. +Once the 'retained' key is stored in the keyring the original +secret key material cannot be retrieved. OPTIONS ------- +-k :: +--keyring=:: + Name of the keyring into which the 'retained' TLS key should be + stored. Default is '.nvme'. + +-t :: +--keytype=:: + Type of the key for resulting TLS key. + Default is 'psk'. + +-n :: +--hostnqn=:: + Host NVMe Qualified Name (NQN) to be used to derive the + 'retained' TLS key + +-c :: +--subsysnqn=:: + Subsystem NVMe Qualified Name (NQN) to be used to derive the + 'retained' TLS key + -h :: --hmac=:: Select a HMAC algorithm to use. Possible values are: 1 - SHA-256 (default) 2 - SHA-384 +-I :: +--identity=:: + Select the TLS identity to use. Possible values are: + 0 - Original NVMe TLS 1.0c identity + 1 - NVMe TLS 2.0 (TP8018) identity + -s :: --secret=:: Secret value (in hexadecimal) to be used for the key. If none are provided a random value is used. +-i:: +--insert:: + Insert the resulting TLS key into the keyring without printing out + the key in PSK interchange format. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No Examples diff --git a/Documentation/nvme-get-feature.1 b/Documentation/nvme-get-feature.1 index 13eb5b30fd..c183514807 100644 --- a/Documentation/nvme-get-feature.1 +++ b/Documentation/nvme-get-feature.1 @@ -2,12 +2,12 @@ .\" Title: nvme-get-feature .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GET\-FEATURE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-GET\-FEATURE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,12 +33,13 @@ nvme-get-feature \- Gets an NVMe feature, returns applicable results .sp .nf \fInvme get\-feature\fR [\-\-namespace\-id= | \-n ] - [\-\-feature\-id= | \-f ] [\-\-cdw11=] - [\-\-uuid\-index= | \-U ] - [\-\-data\-len= | \-l ] - [\-\-sel=] - [\-\-raw\-binary | \-b] - [\-\-human\-readable | \-H] + [\-\-feature\-id= | \-f ] [\-\-cdw11=] + [\-\-uuid\-index= | \-U ] + [\-\-data\-len= | \-l ] + [\-\-sel=] + [\-\-raw\-binary | \-b] + [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -96,7 +97,7 @@ T}:T{ Supported capabilities T} T{ -4\(en7 +4\-7 T}:T{ Reserved T} @@ -128,6 +129,20 @@ Print the raw feature buffer to stdout if the feature returns a structure\&. .RS 4 This option will parse and format many of the bit fields into human\-readable formats\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-get-feature.html b/Documentation/nvme-get-feature.html index 3296f4896b..920a5e3be4 100644 --- a/Documentation/nvme-get-feature.html +++ b/Documentation/nvme-get-feature.html @@ -750,12 +750,13 @@

    SYNOPSIS

    nvme get-feature <device> [--namespace-id=<nsid> | -n <nsid>]
    -                          [--feature-id=<fid> | -f <fid>] [--cdw11=<cdw11>]
    -                          [--uuid-index=<uuid-index> | -U <uuid_index>]
    -                          [--data-len=<data-len> | -l <data-len>]
    -                          [--sel=<select> | -s <select>]
    -                          [--raw-binary | -b]
    -                          [--human-readable | -H]
    + [--feature-id=<fid> | -f <fid>] [--cdw11=<cdw11>] + [--uuid-index=<uuid-index> | -U <uuid_index>] + [--data-len=<data-len> | -l <data-len>] + [--sel=<select> | -s <select>] + [--raw-binary | -b] + [--human-readable | -H] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -843,7 +844,7 @@

    OPTIONS

  • - + @@ -906,6 +907,29 @@

    OPTIONS

    into human-readable formats.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -977,7 +1001,7 @@

    NVME

    diff --git a/Documentation/nvme-get-feature.txt b/Documentation/nvme-get-feature.txt index a6f57a7aee..5abbb47c26 100644 --- a/Documentation/nvme-get-feature.txt +++ b/Documentation/nvme-get-feature.txt @@ -9,12 +9,13 @@ SYNOPSIS -------- [verse] 'nvme get-feature' [--namespace-id= | -n ] - [--feature-id= | -f ] [--cdw11=] - [--uuid-index= | -U ] - [--data-len= | -l ] - [--sel=] - [--raw-binary | -b] - [--human-readable | -H] + [--feature-id= | -f ] + [--uuid-index= | -U ] + [--data-len= | -l ] + [--sel=] + [--raw-binary | -b] [--cdw11= | -c ] + [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -51,11 +52,11 @@ OPTIONS [] |================== |Select|Description -|0|Current -|1|Default +|0|Current +|1|Default |2|Saved |3|Supported capabilities -|4–7|Reserved +|4-7|Reserved |================== -U :: @@ -68,6 +69,7 @@ OPTIONS known features do not use this value. The exception is LBA Range Type +-c :: --cdw11=:: The value for command dword 11, if applicable. @@ -81,6 +83,15 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Retrieves the feature for Number of Queues, or feature id 7: diff --git a/Documentation/nvme-get-lba-status.1 b/Documentation/nvme-get-lba-status.1 index 9fc81b1de1..473a5b93ae 100644 --- a/Documentation/nvme-get-lba-status.1 +++ b/Documentation/nvme-get-lba-status.1 @@ -2,12 +2,12 @@ .\" Title: nvme-get-lba-status .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GET\-LBA\-STAT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-GET\-LBA\-STAT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,12 +33,12 @@ nvme-get-lba-status \- Get LBA Status from NVMe device .sp .nf \fInvme get\-lba\-status\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-max\-dw= | \-m ] - [\-\-action= | \-a ] - [\-\-range\-len= | \-l ] - [\-\-timeout= | \-t ] - [\-\-output\-format= | \-o ] + [\-\-start\-lba= | \-s ] + [\-\-max\-dw= | \-m ] + [\-\-action= | \-a ] + [\-\-range\-len= | \-l ] + [\-\-timeout= | \-t ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -79,13 +79,19 @@ Range Length(RL) specifies the length of the range of contiguous LBAs beginning Override default timeout value\&. In milliseconds\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-get-lba-status.html b/Documentation/nvme-get-lba-status.html index c64869982b..fe45726386 100644 --- a/Documentation/nvme-get-lba-status.html +++ b/Documentation/nvme-get-lba-status.html @@ -750,12 +750,12 @@

    SYNOPSIS

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

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -896,7 +907,7 @@

    NVME

    diff --git a/Documentation/nvme-get-lba-status.txt b/Documentation/nvme-get-lba-status.txt index 157dc419b6..9ef9d595ba 100644 --- a/Documentation/nvme-get-lba-status.txt +++ b/Documentation/nvme-get-lba-status.txt @@ -9,12 +9,12 @@ SYNOPSIS -------- [verse] 'nvme get-lba-status' [--namespace-id= | -n ] - [--start-lba= | -s ] - [--max-dw= | -m ] - [--action= | -a ] - [--range-len= | -l ] - [--timeout= | -t ] - [--output-format= | -o ] + [--start-lba= | -s ] + [--max-dw= | -m ] + [--action= | -a ] + [--range-len= | -l ] + [--timeout= | -t ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -57,10 +57,14 @@ OPTIONS --timeout=:: Override default timeout value. In milliseconds. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-get-log.1 b/Documentation/nvme-get-log.1 index e6f0f87b68..1f189c30c2 100644 --- a/Documentation/nvme-get-log.1 +++ b/Documentation/nvme-get-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-get-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GET\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-GET\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,16 +33,18 @@ nvme-get-log \- Retrieves a log page from an NVMe device .sp .nf \fInvme get\-log\fR [\-\-log\-id= | \-i ] - [\-\-log\-len= | \-l ] - [\-\-aen= | \-a ] - [\-\-namespace\-id= | \-n ] - [\-\-raw\-binary | \-b] - [\-\-lpo= | \-o ] - [\-\-lsp= | \-s ] - [\-\-lsi= | \-S ] - [\-\-rae | \-r] - [\-\-csi= | \-y ] - [\-\-ot= | \-O ] + [\-\-log\-len= | \-l ] + [\-\-aen= | \-a ] + [\-\-namespace\-id= | \-n ] + [\-\-raw\-binary | \-b] + [\-\-lpo= | \-L ] + [\-\-lsp= | \-s ] + [\-\-lsi= | \-S ] + [\-\-rae | \-r] + [\-\-csi= | \-y ] + [\-\-ot= | \-O ] + [\-\-xfer\-len= | \-x ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -78,7 +80,7 @@ Sets the command\(cqs nsid value to the given nsid\&. Defaults to 0xffffffff if Print the raw log buffer to stdout\&. .RE .PP -\-o , \-\-lpo= +\-L , \-\-lpo= .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 @@ -107,6 +109,25 @@ This field specifies the identifier of command set\&. if not issued, NVM Command .RS 4 This field specifies the offset type\&. If set to false, the Log Page Offset Lower field and the Log Page Offset Upper field specify the byte offset into the log page to be returned\&. If set to true, the Log Page Offset Lower field and the Log Page Offset Upper field specify the index into the list of data structures in the log page to be returned\&. The default is byte offset\&. If the option is specified the index mode is used\&. .RE +.PP +\-x +.RS 4 +\-\-xfer\-len : Specify the read chunk size\&. The length argument is expected to be a multiple of 4096\&. The default size is 4096\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-get-log.html b/Documentation/nvme-get-log.html index 5897f6fc23..0d86eb281c 100644 --- a/Documentation/nvme-get-log.html +++ b/Documentation/nvme-get-log.html @@ -750,16 +750,18 @@

    SYNOPSIS

    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>]
    -              [--lsi=<field> | -S <field>]
    -              [--rae | -r]
    -              [--csi=<command_set_identifier> | -y <command_set_identifier>]
    -              [--ot=<offset_type> | -O <offset_type>]
    + [--log-len=<log-len> | -l <log-len>] + [--aen=<aen> | -a <aen>] + [--namespace-id=<nsid> | -n <nsid>] + [--raw-binary | -b] + [--lpo=<offset> | -L <offset>] + [--lsp=<field> | -s <field>] + [--lsi=<field> | -S <field>] + [--rae | -r] + [--csi=<command_set_identifier> | -y <command_set_identifier>] + [--ot=<offset_type> | -O <offset_type>] + [--xfer-len=<length> | -x <length>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -844,7 +846,7 @@

    OPTIONS

    --o <offset> +-L <offset>
    --lpo=<offset> @@ -918,6 +920,39 @@

    OPTIONS

    the index mode is used.

    +
    +-x <length> +
    +
    +

    +--xfer-len <length>: + Specify the read chunk size. The length argument is expected to be + a multiple of 4096. The default size is 4096. +

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -962,7 +997,7 @@

    NVME

    diff --git a/Documentation/nvme-get-log.txt b/Documentation/nvme-get-log.txt index a92ab6a334..98b1f9ce1e 100644 --- a/Documentation/nvme-get-log.txt +++ b/Documentation/nvme-get-log.txt @@ -9,16 +9,18 @@ SYNOPSIS -------- [verse] 'nvme get-log' [--log-id= | -i ] - [--log-len= | -l ] - [--aen= | -a ] - [--namespace-id= | -n ] - [--raw-binary | -b] - [--lpo= | -o ] - [--lsp= | -s ] - [--lsi= | -S ] - [--rae | -r] - [--csi= | -y ] - [--ot= | -O ] + [--log-len= | -l ] + [--aen= | -a ] + [--namespace-id= | -n ] + [--raw-binary | -b] + [--lpo= | -L ] + [--lsp= | -s ] + [--lsi= | -S ] + [--rae | -r] + [--csi= | -y ] + [--ot= | -O ] + [--xfer-len= | -x ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -62,7 +64,7 @@ OPTIONS --raw-binary:: Print the raw log buffer to stdout. --o :: +-L :: --lpo=:: The log page offset specifies the location within a log page to start returning data from. It's Dword-aligned and 64-bits. @@ -95,6 +97,20 @@ OPTIONS The default is byte offset. If the option is specified the index mode is used. +-x :: +--xfer-len : + Specify the read chunk size. The length argument is expected to be + a multiple of 4096. The default size is 4096. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Get 512 bytes from log page 2 diff --git a/Documentation/nvme-get-ns-id.1 b/Documentation/nvme-get-ns-id.1 index cbfe8b628c..cb12425604 100644 --- a/Documentation/nvme-get-ns-id.1 +++ b/Documentation/nvme-get-ns-id.1 @@ -2,12 +2,12 @@ .\" Title: nvme-get-ns-id .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GET\-NS\-ID" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-GET\-NS\-ID" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,14 +32,26 @@ nvme-get-ns-id \- Retrieves the namespace ID for an NVMe block device .SH "SYNOPSIS" .sp .nf -\fInvme get\-ns\-id\fR +\fInvme get\-ns\-id\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Retrieves the namespace ID for an NVMe block device\&. The param is mandatory and must be an NVMe block device (ex: /dev/nvme0n1)\&. .SH "OPTIONS" -.sp -None +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-get-ns-id.html b/Documentation/nvme-get-ns-id.html index d41d27cb8b..07e9814f6b 100644 --- a/Documentation/nvme-get-ns-id.html +++ b/Documentation/nvme-get-ns-id.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme get-ns-id <device>
    +
    nvme get-ns-id <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -764,7 +764,31 @@

    DESCRIPTION

    OPTIONS

    -

    None

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

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

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

    + Increase the information detail in the output. +

    +
    +
    @@ -794,7 +818,7 @@

    NVME

    diff --git a/Documentation/nvme-get-ns-id.txt b/Documentation/nvme-get-ns-id.txt index 5dcdc6d4f8..8516cb89a2 100644 --- a/Documentation/nvme-get-ns-id.txt +++ b/Documentation/nvme-get-ns-id.txt @@ -8,7 +8,7 @@ nvme-get-ns-id - Retrieves the namespace ID for an NVMe block device SYNOPSIS -------- [verse] -'nvme get-ns-id' +'nvme get-ns-id' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -17,7 +17,14 @@ is mandatory and must be an NVMe block device (ex: /dev/nvme0n1). OPTIONS ------- -None +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-get-property.1 b/Documentation/nvme-get-property.1 index c093536b14..8053cc11fb 100644 --- a/Documentation/nvme-get-property.1 +++ b/Documentation/nvme-get-property.1 @@ -2,12 +2,12 @@ .\" Title: nvme-get-property .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GET\-PROPERTY" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-GET\-PROPERTY" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,15 +32,16 @@ nvme-get-property \- Reads and shows the defined NVMe controller property for NV .SH "SYNOPSIS" .sp .nf -\fInvme get\-property\fR [\-\-offset= | \-o ] - [\-\-human\-readable | \-H ] +\fInvme get\-property\fR [\-\-offset= | \-O ] + [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Reads and shows the defined NVMe controller property for NVMe over Fabric\&. .SH "OPTIONS" .PP -\-o, \-\-offset +\-O, \-\-offset .RS 4 The offset of the property\&. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20 .RE @@ -49,6 +50,20 @@ The offset of the property\&. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0 .RS 4 \-\-human\-readable: Show the fields packed in the property .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-get-property.html b/Documentation/nvme-get-property.html index 0fa9bb46f1..f19907cb4d 100644 --- a/Documentation/nvme-get-property.html +++ b/Documentation/nvme-get-property.html @@ -749,8 +749,9 @@

    NAME

    SYNOPSIS

    -
    nvme get-property <device> [--offset=<offset> | -o <offset>]
    -                                [--human-readable | -H ]
    +
    nvme get-property <device> [--offset=<offset> | -O <offset>]
    +                        [--human-readable | -H]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -766,7 +767,7 @@

    OPTIONS

    --o +-O
    --offset @@ -785,6 +786,29 @@

    OPTIONS

    Show the fields packed in the property

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -843,7 +867,7 @@

    NVME

    diff --git a/Documentation/nvme-get-property.txt b/Documentation/nvme-get-property.txt index b2b7d29024..bee65d11b5 100644 --- a/Documentation/nvme-get-property.txt +++ b/Documentation/nvme-get-property.txt @@ -9,25 +9,32 @@ for NVMe over Fabric SYNOPSIS -------- [verse] -'nvme get-property' [--offset= | -o ] - [--human-readable | -H ] - +'nvme get-property' [--offset= | -O ] + [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- Reads and shows the defined NVMe controller property for NVMe over Fabric. - OPTIONS ------- --o:: ---offset:: - The offset of the property. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20 +-O :: +--offset=:: + The offset of the property. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20 -H:: --human-readable: Show the fields packed in the property +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- @@ -37,7 +44,6 @@ EXAMPLES # nvme get-property /dev/nvme0 --offset=0x0 --human-readable ------------ - BUGS ---- Currently the CAP value is truncated to 32 bits due to a limitation in diff --git a/Documentation/nvme-help.1 b/Documentation/nvme-help.1 index a5efbe1f1f..f88439a2bf 100644 --- a/Documentation/nvme-help.1 +++ b/Documentation/nvme-help.1 @@ -2,12 +2,12 @@ .\" Title: nvme-help .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-HELP" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-HELP" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-help.html b/Documentation/nvme-help.html index 95d61fdf82..ef591a769e 100644 --- a/Documentation/nvme-help.html +++ b/Documentation/nvme-help.html @@ -794,7 +794,7 @@

    NVME

    diff --git a/Documentation/nvme-huawei-id-ctrl.1 b/Documentation/nvme-huawei-id-ctrl.1 index e3511451b5..39c7a01c33 100644 --- a/Documentation/nvme-huawei-id-ctrl.1 +++ b/Documentation/nvme-huawei-id-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-huawei-id-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-HUAWEI\-ID\-CT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-HUAWEI\-ID\-CT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,8 @@ nvme-huawei-id-ctrl \- Send NVMe Identify Controller, return result and structur .SH "SYNOPSIS" .sp .nf -\fInvme huawei id\-ctrl\fR [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary] - [\-o | \-\-output\-format=] +\fInvme huawei id\-ctrl\fR [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp @@ -63,7 +63,7 @@ In addition to parsing known fields, this option will dump the vendor specific r This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-huawei-id-ctrl.html b/Documentation/nvme-huawei-id-ctrl.html index 2644b5c02a..b04dd722df 100644 --- a/Documentation/nvme-huawei-id-ctrl.html +++ b/Documentation/nvme-huawei-id-ctrl.html @@ -749,8 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme huawei id-ctrl <device> [-v | --vendor-specific] [-b | --raw-binary]
    -                        [-o <fmt> | --output-format=<fmt>]
    +
    nvme huawei id-ctrl <device> [--vendor-specific | -v] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>]
    @@ -813,15 +813,15 @@

    OPTIONS

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

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

    @@ -855,7 +855,7 @@

    NVME

    diff --git a/Documentation/nvme-huawei-id-ctrl.txt b/Documentation/nvme-huawei-id-ctrl.txt index f4d2f80c5f..47225d1a68 100644 --- a/Documentation/nvme-huawei-id-ctrl.txt +++ b/Documentation/nvme-huawei-id-ctrl.txt @@ -8,8 +8,8 @@ nvme-huawei-id-ctrl - Send NVMe Identify Controller, return result and structure SYNOPSIS -------- [verse] -'nvme huawei id-ctrl' [-v | --vendor-specific] [-b | --raw-binary] - [-o | --output-format=] +'nvme huawei id-ctrl' [--vendor-specific | -v] [--raw-binary | -b] + [--output-format= | -o ] DESCRIPTION ----------- @@ -47,10 +47,10 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-huawei-list.1 b/Documentation/nvme-huawei-list.1 index 7c74936d44..f3c0bb28a5 100644 --- a/Documentation/nvme-huawei-list.1 +++ b/Documentation/nvme-huawei-list.1 @@ -2,12 +2,12 @@ .\" Title: nvme-list .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LIST" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LIST" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,14 +32,14 @@ nvme-huawei-list \- List all recognized Huawei NVMe devices .SH "SYNOPSIS" .sp .nf -\fInvme huawei list\fR [\-o | \-\-output\-format=] +\fInvme huawei list\fR [\-\-output\-format= | \-o ] .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 , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR diff --git a/Documentation/nvme-huawei-list.html b/Documentation/nvme-huawei-list.html index 98068b8406..5d3bbaa458 100644 --- a/Documentation/nvme-huawei-list.html +++ b/Documentation/nvme-huawei-list.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme huawei list [-o <fmt> | --output-format=<fmt>]
    +
    nvme huawei list [--output-format=<fmt> | -o <fmt>]
    @@ -766,10 +766,10 @@

    OPTIONS

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

    @@ -797,7 +797,7 @@

    NVME

    diff --git a/Documentation/nvme-huawei-list.txt b/Documentation/nvme-huawei-list.txt index 65a6c21b26..95f1099927 100644 --- a/Documentation/nvme-huawei-list.txt +++ b/Documentation/nvme-huawei-list.txt @@ -8,7 +8,7 @@ nvme-huawei-list - List all recognized Huawei NVMe devices SYNOPSIS -------- [verse] -'nvme huawei list' [-o | --output-format=] +'nvme huawei list' [--output-format= | -o ] DESCRIPTION ----------- @@ -17,8 +17,8 @@ for those Huawei devices as well as some pertinent information about them. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal' or 'json'. Only one output format can be used at a time. diff --git a/Documentation/nvme-id-ctrl.1 b/Documentation/nvme-id-ctrl.1 index c795bbc016..97214b6cfd 100644 --- a/Documentation/nvme-id-ctrl.1 +++ b/Documentation/nvme-id-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-CTRL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-CTRL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,8 @@ nvme-id-ctrl \- Send NVMe Identify Controller, return result and structure .SH "SYNOPSIS" .sp .nf -\fInvme id\-ctrl\fR [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary] - [\-o | \-\-output\-format=] +\fInvme id\-ctrl\fR [\-\-vendor\-specific | \-V] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -49,7 +49,7 @@ On success, the structure may be returned in one of several ways depending on th 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 +\-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 @@ -59,13 +59,19 @@ In addition to parsing known fields, this option will dump the vendor specific r This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 @@ -104,7 +110,7 @@ In addition to showing the known fields, has the program to display the vendor u .\} .nf # nvme id\-ctrl /dev/nvme0 \-\-vendor\-specific -# nvme id\-ctrl /dev/nvme0 \-v +# nvme id\-ctrl /dev/nvme0 \-V .fi .if n \{\ .RE diff --git a/Documentation/nvme-id-ctrl.html b/Documentation/nvme-id-ctrl.html index f1a239519d..9c00c75e59 100644 --- a/Documentation/nvme-id-ctrl.html +++ b/Documentation/nvme-id-ctrl.html @@ -749,8 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme id-ctrl <device> [-v | --vendor-specific] [-b | --raw-binary]
    -                        [-o <fmt> | --output-format=<fmt>]
    +
    nvme id-ctrl <device> [--vendor-specific | -V] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -784,7 +784,7 @@

    OPTIONS

    --v +-V
    --vendor-specific @@ -809,15 +809,26 @@

    OPTIONS

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

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

    +
    +
    +-v
    ---output-format=<format> +--verbose

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

    @@ -845,7 +856,7 @@

    EXAMPLES

    # nvme id-ctrl /dev/nvme0 --vendor-specific
    -# nvme id-ctrl /dev/nvme0 -v
    +# nvme id-ctrl /dev/nvme0 -V

    The above will dump the vs buffer in hex since it doesn’t know how to interpret it.

    @@ -910,7 +921,7 @@

    NVME

    diff --git a/Documentation/nvme-id-ctrl.txt b/Documentation/nvme-id-ctrl.txt index b9fcffc4ea..3667c63471 100644 --- a/Documentation/nvme-id-ctrl.txt +++ b/Documentation/nvme-id-ctrl.txt @@ -8,8 +8,8 @@ nvme-id-ctrl - Send NVMe Identify Controller, return result and structure SYNOPSIS -------- [verse] -'nvme id-ctrl' [-v | --vendor-specific] [-b | --raw-binary] - [-o | --output-format=] +'nvme id-ctrl' [--vendor-specific | -V] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -30,7 +30,7 @@ OPTIONS Print the raw buffer to stdout. Structure is not parsed by program. This overrides the vendor specific and human readable options. --v:: +-V:: --vendor-specific:: In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii @@ -41,10 +41,14 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- @@ -61,7 +65,7 @@ the vendor unique field: + ------------ # nvme id-ctrl /dev/nvme0 --vendor-specific -# nvme id-ctrl /dev/nvme0 -v +# nvme id-ctrl /dev/nvme0 -V ------------ + The above will dump the 'vs' buffer in hex since it doesn't know how to diff --git a/Documentation/nvme-id-domain.1 b/Documentation/nvme-id-domain.1 index 3313319226..f905dd6d2b 100644 --- a/Documentation/nvme-id-domain.1 +++ b/Documentation/nvme-id-domain.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-domain .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-DOMAIN" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-DOMAIN" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-id-domain \- Send NVMe Identify Domain List, return result and structure .sp .nf \fInvme id\-domain\fR [\-\-dom\-id= | \-d ] - [\-o | \-\-output\-format=] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -47,13 +47,19 @@ The parameter is mandatory and may be either the NVMe character device Retrieve the identify domain list data structure for the given domain id\&. If this value is not given, domain id will be 0xffff\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-id-domain.html b/Documentation/nvme-id-domain.html index d05b1b3860..dffc249549 100644 --- a/Documentation/nvme-id-domain.html +++ b/Documentation/nvme-id-domain.html @@ -750,7 +750,7 @@

    SYNOPSIS

    nvme id-domain <device> [--dom-id=<domian_id> | -d <domian_id>]
    -                        [-o <fmt> | --output-format=<fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -781,15 +781,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -812,7 +823,7 @@

    NVME

    diff --git a/Documentation/nvme-id-domain.txt b/Documentation/nvme-id-domain.txt index 87883c5011..1d6ec48cc0 100644 --- a/Documentation/nvme-id-domain.txt +++ b/Documentation/nvme-id-domain.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme id-domain' [--dom-id= | -d ] - [-o | --output-format=] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -26,10 +26,14 @@ OPTIONS Retrieve the identify domain list data structure for the given domain id. If this value is not given, domain id will be 0xffff. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-id-iocs.1 b/Documentation/nvme-id-iocs.1 index 8dd77020a6..e6918cd4ba 100644 --- a/Documentation/nvme-id-iocs.1 +++ b/Documentation/nvme-id-iocs.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-iocs .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-IOCS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-IOCS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-id-iocs \- Send NVMe Identify I/O Command Set, return result and structure .sp .nf \fInvme id\-iocs\fR [\-\-controller\-id= | \-c ] - [\-o | \-\-output\-format=] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -52,13 +52,19 @@ Retrieve the identify I/O Command set data structure for the given cntid\&. If t This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-id-iocs.html b/Documentation/nvme-id-iocs.html index f045c59263..704ddaebe9 100644 --- a/Documentation/nvme-id-iocs.html +++ b/Documentation/nvme-id-iocs.html @@ -750,7 +750,7 @@

    SYNOPSIS

    nvme id-iocs <device> [--controller-id=<cntid> | -c <cntid>]
    -                        [-o <fmt> | --output-format=<fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -793,15 +793,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -844,7 +855,7 @@

    NVME

    diff --git a/Documentation/nvme-id-iocs.txt b/Documentation/nvme-id-iocs.txt index a35217e15f..bb85aef1e4 100644 --- a/Documentation/nvme-id-iocs.txt +++ b/Documentation/nvme-id-iocs.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme id-iocs' [--controller-id= | -c ] - [-o | --output-format=] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -30,10 +30,14 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-id-ns-granularity.txt b/Documentation/nvme-id-ns-granularity.txt new file mode 100644 index 0000000000..67006c333d --- /dev/null +++ b/Documentation/nvme-id-ns-granularity.txt @@ -0,0 +1,46 @@ +nvme-id-ns-granularity(1) +========================= + +NAME +---- +nvme-id-ns-granularity - Send a Identify Namespace Granularity List command to +the specified device + +SYNOPSIS +-------- +[verse] +'nvme id-ns-granularity' + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Send a Identify Namespace Granularity List command command to the specified +device, return results. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Has the program issue a id-ns-granularity to display structure. ++ +------------ +# nvme id-ns-granularity /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-id-ns-lba-format.txt b/Documentation/nvme-id-ns-lba-format.txt index 32df2f616d..514ba48999 100644 --- a/Documentation/nvme-id-ns-lba-format.txt +++ b/Documentation/nvme-id-ns-lba-format.txt @@ -9,9 +9,9 @@ SYNOPSIS -------- [verse] 'nvme id-ns' [--uuid-index= | -U ] - [--lba-format-index= | -i ] - [-v | --verbose] - [--output-format= | -o ] + [--lba-format-index= | -i ] + [--verbose | -v] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -31,7 +31,7 @@ OPTIONS -U :: --uuid-index=:: UUID Index of the feature - + -i :: --lba-format-index=:: This field specifies the index into the LBA Format list identifying @@ -41,10 +41,10 @@ OPTIONS --verbose:: Increase the information detail in the output. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-id-ns.1 b/Documentation/nvme-id-ns.1 index 242b0d8b0d..1a440586f7 100644 --- a/Documentation/nvme-id-ns.1 +++ b/Documentation/nvme-id-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,10 +32,10 @@ nvme-id-ns \- Send NVMe Identify Namespace, return result and structure .SH "SYNOPSIS" .sp .nf -\fInvme id\-ns\fR [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary] - [\-\-namespace\-id= | \-n ] [\-\-force] - [\-\-human\-readable | \-H] - [\-\-output\-format= | \-o ] +\fInvme id\-ns\fR [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b] + [\-\-namespace\-id= | \-n ] [\-\-force] + [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -61,7 +61,7 @@ Request controller return the identify namespace structure even if the namespace 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 +\-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 @@ -71,13 +71,19 @@ In addition to parsing known fields, this option will dump the vendor specific r This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 @@ -139,7 +145,7 @@ In addition to showing the known fields, have the program to display the vendor .\} .nf # nvme id\-ns /dev/nvme0n1 \-\-vendor\-specific -# nvme id\-ns /dev/nvme0n1 \-v +# nvme id\-ns /dev/nvme0n1 \-V .fi .if n \{\ .RE diff --git a/Documentation/nvme-id-ns.html b/Documentation/nvme-id-ns.html index 63a32abe6c..20044bc77b 100644 --- a/Documentation/nvme-id-ns.html +++ b/Documentation/nvme-id-ns.html @@ -749,10 +749,10 @@

    NAME

    SYNOPSIS

    -
    nvme id-ns <device> [-v | --vendor-specific] [-b | --raw-binary]
    -                    [--namespace-id=<nsid> | -n <nsid>] [--force]
    -                    [--human-readable | -H]
    -                    [--output-format=<fmt> | -o <fmt>]
    +
    nvme id-ns <device> [--vendor-specific | -v] [--raw-binary | -b]
    +                        [--namespace-id=<nsid> | -n <nsid>] [--force]
    +                        [--human-readable | -H]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -817,7 +817,7 @@

    OPTIONS

    --v +-V
    --vendor-specific @@ -842,15 +842,26 @@

    OPTIONS

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

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

    +
    +
    +-v
    ---output-format=<format> +--verbose

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

    @@ -889,7 +900,7 @@

    EXAMPLES

    # nvme id-ns /dev/nvme0n1 --vendor-specific
    -# nvme id-ns /dev/nvme0n1 -v
    +# nvme id-ns /dev/nvme0n1 -V

    The above will dump the 'vs' buffer in hex since it doesn’t know how to interpret it.

    @@ -955,7 +966,7 @@

    NVME

    diff --git a/Documentation/nvme-id-ns.txt b/Documentation/nvme-id-ns.txt index a2ac155484..079125059e 100644 --- a/Documentation/nvme-id-ns.txt +++ b/Documentation/nvme-id-ns.txt @@ -8,10 +8,10 @@ nvme-id-ns - Send NVMe Identify Namespace, return result and structure SYNOPSIS -------- [verse] -'nvme id-ns' [-v | --vendor-specific] [-b | --raw-binary] - [--namespace-id= | -n ] [--force] - [--human-readable | -H] - [--output-format= | -o ] +'nvme id-ns' [--vendor-specific | -v] [--raw-binary | -b] + [--namespace-id= | -n ] [--force] + [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -51,7 +51,7 @@ OPTIONS Print the raw buffer to stdout. Structure is not parsed by program. This overrides the vendor specific and human readable options. --v:: +-V:: --vendor-specific:: In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii @@ -62,12 +62,14 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- @@ -93,7 +95,7 @@ the vendor unique field: + ------------ # nvme id-ns /dev/nvme0n1 --vendor-specific -# nvme id-ns /dev/nvme0n1 -v +# nvme id-ns /dev/nvme0n1 -V ------------ + The above will dump the \'vs' buffer in hex since it doesn't know how to diff --git a/Documentation/nvme-id-nvmset.1 b/Documentation/nvme-id-nvmset.1 index cfecb075bb..4a5f82c1a7 100644 --- a/Documentation/nvme-id-nvmset.1 +++ b/Documentation/nvme-id-nvmset.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-nvmset .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-NVMSET" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-NVMSET" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,8 @@ nvme-id-nvmset \- Send NVMe Identify NVM Set List, return result and structure .SH "SYNOPSIS" .sp .nf -\fInvme id\-nvmset\fR [\-i | \-\-nvmset_id= ] - [\-o | \-\-output\-format=] +\fInvme id\-nvmset\fR [\-\-nvmset_id= | \-i ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -49,13 +49,19 @@ On success, the structure may be returned in one of several ways depending on th 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 , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-id-nvmset.html b/Documentation/nvme-id-nvmset.html index e6e5c88958..535bb73dc1 100644 --- a/Documentation/nvme-id-nvmset.html +++ b/Documentation/nvme-id-nvmset.html @@ -749,8 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme id-nvmset <device> [-i <id> | --nvmset_id=<id> ]
    -                        [-o <fmt> | --output-format=<fmt>]
    +
    nvme id-nvmset <device> [--nvmset_id=<id> | -i <id>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -779,21 +779,32 @@

    OPTIONS

    - This field specifies the identifier of the NVM Set. If given, NVM set + 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> +-o <fmt>
    ---output-format=<format> +--output-format=<fmt>

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

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

    + Increase the information detail in the output.

    @@ -851,7 +862,7 @@

    EXAMPLES

    diff --git a/Documentation/nvme-id-nvmset.txt b/Documentation/nvme-id-nvmset.txt index c331410c92..e2894e3715 100644 --- a/Documentation/nvme-id-nvmset.txt +++ b/Documentation/nvme-id-nvmset.txt @@ -8,8 +8,8 @@ nvme-id-nvmset - Send NVMe Identify NVM Set List, return result and structure SYNOPSIS -------- [verse] -'nvme id-nvmset' [-i | --nvmset_id= ] - [-o | --output-format=] +'nvme id-nvmset' [--nvmset_id= | -i ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -27,14 +27,18 @@ OPTIONS ------- -i :: --nvmset_id=:: - This field specifies the identifier of the NVM Set. If given, NVM set + 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 :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-id-uuid.txt b/Documentation/nvme-id-uuid.txt new file mode 100644 index 0000000000..f7cc1c0b6e --- /dev/null +++ b/Documentation/nvme-id-uuid.txt @@ -0,0 +1,55 @@ +nvme-id-uuid(1) +=============== + +NAME +---- +nvme-id-uuid - Send a Identify UUID List command to the specified device + +SYNOPSIS +-------- +[verse] +'nvme id-uuid' [--raw-binary | -b] [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Send a Identify UUID List command command to the specified device, return +results. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-b:: +--raw-binary:: + Print the raw buffer to stdout. Structure is not parsed by + program. This overrides the vendor specific and human readable options. + +-H:: +--human-readable:: + This option will parse and format many of the bit fields + into human-readable formats. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Has the program issue a id-uuid to display structure. ++ +------------ +# nvme id-uuid /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-inspur-nvme-vendor-log.1 b/Documentation/nvme-inspur-nvme-vendor-log.1 new file mode 100644 index 0000000000..4ccea25882 --- /dev/null +++ b/Documentation/nvme-inspur-nvme-vendor-log.1 @@ -0,0 +1,71 @@ +'\" t +.\" Title: nvme-inspur-nvme-vendor-log +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-INSPUR\-NVME\-" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-inspur-nvme-vendor-log \- Send NVMe Inspur Device Vendor log page request, returns result +.SH "SYNOPSIS" +.sp +.nf +\fInvme inspur nvme\-vendor\-log\fR +.fi +.SH "DESCRIPTION" +.sp +Retrieves the NVMe Inspur Device Vendor log page from the device and provides the returned structure\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. +.sp +On success, vendor log structure are printed in a readable format\&. +.SH "OPTIONS" +.sp +none +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Print the Inspur Device Vendor log page in a human readable format: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme inspur nvme\-vendor\-log /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-inspur-nvme-vendor-log.html b/Documentation/nvme-inspur-nvme-vendor-log.html new file mode 100644 index 0000000000..424c26d722 --- /dev/null +++ b/Documentation/nvme-inspur-nvme-vendor-log.html @@ -0,0 +1,803 @@ + + + + + + +nvme-inspur-nvme-vendor-log(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme inspur nvme-vendor-log <device>
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Retrieves the NVMe Inspur Device Vendor log page from the device and provides the returned structure.

    +

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

    +

    On success, vendor log structure are printed in a readable format.

    +
    +
    +
    +

    OPTIONS

    +
    +

    none

    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Print the Inspur Device Vendor log page in a human readable format: +

      +
      +
      +
      # nvme inspur nvme-vendor-log /dev/nvme0
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-inspur-nvme-vendor-log.txt b/Documentation/nvme-inspur-nvme-vendor-log.txt new file mode 100644 index 0000000000..c860497269 --- /dev/null +++ b/Documentation/nvme-inspur-nvme-vendor-log.txt @@ -0,0 +1,36 @@ +nvme-inspur-nvme-vendor-log(1) +============================== + +NAME +---- +nvme-inspur-nvme-vendor-log - Send NVMe Inspur Device Vendor log page request, returns result + +SYNOPSIS +-------- +[verse] +'nvme inspur nvme-vendor-log' + +DESCRIPTION +----------- +Retrieves the NVMe Inspur Device Vendor log page from the device and provides the returned structure. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). + +On success, vendor log structure are printed in a readable format. + +OPTIONS +------- +none + +EXAMPLES +-------- +* Print the Inspur Device Vendor log page in a human readable format: ++ +------------ +# nvme inspur nvme-vendor-log /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-intel-id-ctrl.1 b/Documentation/nvme-intel-id-ctrl.1 index 61e10b741e..2c1a4d961e 100644 --- a/Documentation/nvme-intel-id-ctrl.1 +++ b/Documentation/nvme-intel-id-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-intel-id-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-INTEL\-ID\-CTR" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-INTEL\-ID\-CTR" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,8 @@ nvme-intel-id-ctrl \- Send NVMe Identify Controller, return result and structure .SH "SYNOPSIS" .sp .nf -\fInvme intel id\-ctrl\fR [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary] - [\-o | \-\-output\-format=] +\fInvme intel id\-ctrl\fR [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp @@ -61,7 +61,7 @@ In addition to parsing known fields, this option will dump the vendor specific r This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-intel-id-ctrl.html b/Documentation/nvme-intel-id-ctrl.html index 9c83d005a5..aabaa2f79d 100644 --- a/Documentation/nvme-intel-id-ctrl.html +++ b/Documentation/nvme-intel-id-ctrl.html @@ -749,8 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme intel id-ctrl <device> [-v | --vendor-specific] [-b | --raw-binary]
    -                        [-o <fmt> | --output-format=<fmt>]
    +
    nvme intel id-ctrl <device> [--vendor-specific | -v] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>]
    @@ -811,15 +811,15 @@

    OPTIONS

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

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

    @@ -853,7 +853,7 @@

    NVME

    diff --git a/Documentation/nvme-intel-id-ctrl.txt b/Documentation/nvme-intel-id-ctrl.txt index 1a6369c7aa..469d60ea2f 100644 --- a/Documentation/nvme-intel-id-ctrl.txt +++ b/Documentation/nvme-intel-id-ctrl.txt @@ -8,8 +8,8 @@ nvme-intel-id-ctrl - Send NVMe Identify Controller, return result and structure SYNOPSIS -------- [verse] -'nvme intel id-ctrl' [-v | --vendor-specific] [-b | --raw-binary] - [-o | --output-format=] +'nvme intel id-ctrl' [--vendor-specific | -v] [--raw-binary | -b] + [--output-format= | -o ] DESCRIPTION ----------- @@ -44,10 +44,10 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-intel-internal-log.1 b/Documentation/nvme-intel-internal-log.1 index 122d313696..0bec162d63 100644 --- a/Documentation/nvme-intel-internal-log.1 +++ b/Documentation/nvme-intel-internal-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-intel-internal-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-INTEL\-INTERNA" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-INTEL\-INTERNA" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-intel-internal-log.html b/Documentation/nvme-intel-internal-log.html index 19b66f7ec2..aca21330b3 100644 --- a/Documentation/nvme-intel-internal-log.html +++ b/Documentation/nvme-intel-internal-log.html @@ -873,7 +873,7 @@

    NVME

    diff --git a/Documentation/nvme-intel-internal-log.txt b/Documentation/nvme-intel-internal-log.txt index 2f00313ad3..a1e1792d29 100644 --- a/Documentation/nvme-intel-internal-log.txt +++ b/Documentation/nvme-intel-internal-log.txt @@ -53,7 +53,6 @@ OPTIONS 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: diff --git a/Documentation/nvme-intel-lat-stats.1 b/Documentation/nvme-intel-lat-stats.1 index 4e7c93a816..7b0428875f 100644 --- a/Documentation/nvme-intel-lat-stats.1 +++ b/Documentation/nvme-intel-lat-stats.1 @@ -2,12 +2,12 @@ .\" Title: nvme-intel-lat-stats .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-INTEL\-LAT\-ST" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-INTEL\-LAT\-ST" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-intel-lat-stats.html b/Documentation/nvme-intel-lat-stats.html index 832ea13f47..837e17ebdd 100644 --- a/Documentation/nvme-intel-lat-stats.html +++ b/Documentation/nvme-intel-lat-stats.html @@ -832,7 +832,7 @@

    NVME

    diff --git a/Documentation/nvme-intel-market-name.1 b/Documentation/nvme-intel-market-name.1 index 9bc461f12e..b77c38b6f2 100644 --- a/Documentation/nvme-intel-market-name.1 +++ b/Documentation/nvme-intel-market-name.1 @@ -2,12 +2,12 @@ .\" Title: nvme-intel-market-name .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-INTEL\-MARKET\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-INTEL\-MARKET\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-intel-market-name.html b/Documentation/nvme-intel-market-name.html index d0832f920f..817a255ec5 100644 --- a/Documentation/nvme-intel-market-name.html +++ b/Documentation/nvme-intel-market-name.html @@ -813,7 +813,7 @@

    NVME

    diff --git a/Documentation/nvme-intel-smart-log-add.1 b/Documentation/nvme-intel-smart-log-add.1 index a90ac5177b..539d9bff31 100644 --- a/Documentation/nvme-intel-smart-log-add.1 +++ b/Documentation/nvme-intel-smart-log-add.1 @@ -2,12 +2,12 @@ .\" Title: nvme-intel-smart-log-add .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-INTEL\-SMART\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-INTEL\-SMART\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,8 +33,7 @@ nvme-intel-smart-log-add \- Send NVMe Intel Additional SMART log page request, r .sp .nf \fInvme intel smart\-log\-add\fR [\-\-namespace\-id= | \-n ] - [\-\-raw\-binary | \-b] - [\-\-json | \-j] + [\-\-raw\-binary | \-b] [\-\-json | \-j] .fi .SH "DESCRIPTION" .sp diff --git a/Documentation/nvme-intel-smart-log-add.html b/Documentation/nvme-intel-smart-log-add.html index c842af1589..f5b1b5ecef 100644 --- a/Documentation/nvme-intel-smart-log-add.html +++ b/Documentation/nvme-intel-smart-log-add.html @@ -750,8 +750,7 @@

    SYNOPSIS

    nvme intel smart-log-add <device> [--namespace-id=<nsid> | -n <nsid>]
    -                        [--raw-binary | -b]
    -                        [--json | -j]
    + [--raw-binary | -b] [--json | -j]
    @@ -807,7 +806,7 @@

    OPTIONS

    - Dump output in json format. + Dump output in json format.

    @@ -850,7 +849,7 @@

    NVME

    diff --git a/Documentation/nvme-intel-smart-log-add.txt b/Documentation/nvme-intel-smart-log-add.txt index 7cfe79420f..0ed1f10cda 100644 --- a/Documentation/nvme-intel-smart-log-add.txt +++ b/Documentation/nvme-intel-smart-log-add.txt @@ -3,14 +3,14 @@ nvme-intel-smart-log-add(1) NAME ---- -nvme-intel-smart-log-add - Send NVMe Intel Additional SMART log page request, returns result and log +nvme-intel-smart-log-add - Send NVMe Intel Additional SMART log page request, +returns result and log SYNOPSIS -------- [verse] 'nvme intel smart-log-add' [--namespace-id= | -n ] - [--raw-binary | -b] - [--json | -j] + [--raw-binary | -b] [--json | -j] DESCRIPTION ----------- @@ -41,7 +41,7 @@ OPTIONS -j:: --json:: - Dump output in json format. + Dump output in json format. EXAMPLES -------- diff --git a/Documentation/nvme-intel-temp-stats.1 b/Documentation/nvme-intel-temp-stats.1 index de26521bde..15434bbc2b 100644 --- a/Documentation/nvme-intel-temp-stats.1 +++ b/Documentation/nvme-intel-temp-stats.1 @@ -2,12 +2,12 @@ .\" Title: nvme-intel-temp-stats .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-INTEL\-TEMP\-S" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-INTEL\-TEMP\-S" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-intel-temp-stats.html b/Documentation/nvme-intel-temp-stats.html index 4485f295e8..c03b0a0e32 100644 --- a/Documentation/nvme-intel-temp-stats.html +++ b/Documentation/nvme-intel-temp-stats.html @@ -822,7 +822,7 @@

    NVME

    diff --git a/Documentation/nvme-io-mgmt-recv.1 b/Documentation/nvme-io-mgmt-recv.1 new file mode 100644 index 0000000000..df8eda963b --- /dev/null +++ b/Documentation/nvme-io-mgmt-recv.1 @@ -0,0 +1,86 @@ +'\" t +.\" Title: nvme-io-mgmt-recv +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-IO\-MGMT\-RECV" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-io-mgmt-recv \- I/O Management Receive command +.SH "SYNOPSIS" +.sp +.nf +\fInvme io\-mgmt\-recv\fR [\-\-namespace\-id= | \-n ] + [\-\-mos= | \-s ] [\-\-mo= | \-m ] + [\-\-data= | \-d ] + [\-\-data\-len= | \-l ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, issues the I/O Management Receive command with the requested management operation (mo) and management operation specific parameter (mos)\&. This is the generic interface provided for forward compatibility as new operations are added that this program isn\(cqt aware of at the time of its development\&. As such, this is a generic command that does not do any additional decoding for specific types of data received\&. This will only report the data as a hex dump, or binary\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&. +.RE +.PP +\-d , \-\-data= +.RS 4 +File to write received data into\&. If unspecified, received data will be hex dumped to the standard output stream\&. +.RE +.PP +\-l , \-\-data\-len= +.RS 4 +Received data buffer length +.RE +.PP +\-m , \-\-mo +.RS 4 +Management Operation to perform\&. +.RE +.PP +\-s , \-\-mos= +.RS 4 +Management Operation Specific parameter\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-io-mgmt-recv.html b/Documentation/nvme-io-mgmt-recv.html new file mode 100644 index 0000000000..bed1c31a7c --- /dev/null +++ b/Documentation/nvme-io-mgmt-recv.html @@ -0,0 +1,876 @@ + + + + + + +nvme-io-mgmt-recv(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme io-mgmt-recv <device> [--namespace-id=<NUM> | -n <NUM>]
    +                        [--mos=<NUM> | -s <NUM>] [--mo=<NUM> | -m <NUM>]
    +                        [--data=<FILE> | -d <FILE>]
    +                        [--data-len=<NUM> | -l <NUM>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, issues the I/O Management Receive command with the +requested management operation (mo) and management operation specific parameter +(mos). This is the generic interface provided for forward compatibility as new +operations are added that this program isn’t aware of at the time of its +development. As such, this is a generic command that does not do any additional +decoding for specific types of data received. This will only report the data as +a hex dump, or binary.

    +
    +
    +
    +

    OPTIONS

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

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

    +
    +
    +-d <FILE> +
    +
    +--data=<FILE> +
    +
    +

    + File to write received data into. If unspecified, received data will be + hex dumped to the standard output stream. +

    +
    +
    +-l <NUM> +
    +
    +--data-len=<NUM> +
    +
    +

    + Received data buffer length +

    +
    +
    +-m <NUM> +
    +
    +--mo <NUM> +
    +
    +

    + Management Operation to perform. +

    +
    +
    +-s <NUM> +
    +
    +--mos=<NUM> +
    +
    +

    + Management Operation Specific parameter. +

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

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

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

    + Increase the information detail in the output. +

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-io-mgmt-recv.txt b/Documentation/nvme-io-mgmt-recv.txt new file mode 100644 index 0000000000..332d0bbdb2 --- /dev/null +++ b/Documentation/nvme-io-mgmt-recv.txt @@ -0,0 +1,63 @@ +nvme-io-mgmt-recv(1) +==================== + +NAME +---- +nvme-io-mgmt-recv - I/O Management Receive command + +SYNOPSIS +-------- +[verse] +'nvme io-mgmt-recv' [--namespace-id= | -n ] + [--mos= | -s ] [--mo= | -m ] + [--data= | -d ] + [--data-len= | -l ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +For the NVMe device given, issues the I/O Management Receive command with the +requested management operation (mo) and management operation specific parameter +(mos). This is the generic interface provided for forward compatibility as new +operations are added that this program isn't aware of at the time of its +development. As such, this is a generic command that does not do any additional +decoding for specific types of data received. This will only report the data as +a hex dump, or binary. + +OPTIONS +------- +-n :: +--namespace-id=:: + Use the provided namespace id for the command. If not provided, the + namespace id of the block device will be used. If the command is issued + to a non-block device, the parameter is required. + +-d :: +--data=:: + File to write received data into. If unspecified, received data will be + hex dumped to the standard output stream. + +-l :: +--data-len=:: + Received data buffer length + +-m :: +--mo :: + Management Operation to perform. + +-s :: +--mos=:: + Management Operation Specific parameter. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-io-mgmt-send.1 b/Documentation/nvme-io-mgmt-send.1 new file mode 100644 index 0000000000..3206738572 --- /dev/null +++ b/Documentation/nvme-io-mgmt-send.1 @@ -0,0 +1,86 @@ +'\" t +.\" Title: nvme-io-mgmt-send +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-IO\-MGMT\-SEND" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-io-mgmt-send \- I/O Management Send command +.SH "SYNOPSIS" +.sp +.nf +\fInvme io\-mgmt\-send\fR [\-\-namespace\-id= | \-n ] + [\-\-mos= | \-s ] [\-\-mo= | \-m ] + [\-\-data= | \-d ] + [\-\-data\-len= | \-l ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, issues the I/O Management Send command with the requested management operation (mo) and management operation specific parameter (mos)\&. This is the generic interface provided for forward compatibility as new operations are added that this program isn\(cqt aware of at the time of its development\&. As such, this is a generic command that does not provide any convenience parameters to produce the binary payload\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&. +.RE +.PP +\-d , \-\-data= +.RS 4 +File to read payload from\&. If unspecified, data will be read from the standard input stream\&. +.RE +.PP +\-l , \-\-data\-len= +.RS 4 +Payload data buffer length +.RE +.PP +\-m , \-\-mo +.RS 4 +Management Operation to perform\&. +.RE +.PP +\-s , \-\-mos= +.RS 4 +Management Operation Specific parameter\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE +.SH "NVME" +.sp +Part of nvme\-cli diff --git a/Documentation/nvme-io-mgmt-send.html b/Documentation/nvme-io-mgmt-send.html new file mode 100644 index 0000000000..42e1548842 --- /dev/null +++ b/Documentation/nvme-io-mgmt-send.html @@ -0,0 +1,875 @@ + + + + + + +nvme-io-mgmt-send(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme io-mgmt-send <device> [--namespace-id=<NUM> | -n <NUM>]
    +                        [--mos=<NUM> | -s <NUM>] [--mo=<NUM> | -m <NUM>]
    +                        [--data=<FILE> | -d <FILE>]
    +                        [--data-len=<NUM> | -l <NUM>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, issues the I/O Management Send command with the +requested management operation (mo) and management operation specific parameter +(mos). This is the generic interface provided for forward compatibility as new +operations are added that this program isn’t aware of at the time of its +development. As such, this is a generic command that does not provide any +convenience parameters to produce the binary payload.

    +
    +
    +
    +

    OPTIONS

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

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

    +
    +
    +-d <FILE> +
    +
    +--data=<FILE> +
    +
    +

    + File to read payload from. If unspecified, data will be read from the + standard input stream. +

    +
    +
    +-l <NUM> +
    +
    +--data-len=<NUM> +
    +
    +

    + Payload data buffer length +

    +
    +
    +-m <NUM> +
    +
    +--mo <NUM> +
    +
    +

    + Management Operation to perform. +

    +
    +
    +-s <NUM> +
    +
    +--mos=<NUM> +
    +
    +

    + Management Operation Specific parameter. +

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

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

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

    + Increase the information detail in the output. +

    +
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of nvme-cli

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-io-mgmt-send.txt b/Documentation/nvme-io-mgmt-send.txt new file mode 100644 index 0000000000..f7e8f6d40b --- /dev/null +++ b/Documentation/nvme-io-mgmt-send.txt @@ -0,0 +1,62 @@ +nvme-io-mgmt-send(1) +==================== + +NAME +---- +nvme-io-mgmt-send - I/O Management Send command + +SYNOPSIS +-------- +[verse] +'nvme io-mgmt-send' [--namespace-id= | -n ] + [--mos= | -s ] [--mo= | -m ] + [--data= | -d ] + [--data-len= | -l ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +For the NVMe device given, issues the I/O Management Send command with the +requested management operation (mo) and management operation specific parameter +(mos). This is the generic interface provided for forward compatibility as new +operations are added that this program isn't aware of at the time of its +development. As such, this is a generic command that does not provide any +convenience parameters to produce the binary payload. + +OPTIONS +------- +-n :: +--namespace-id=:: + Use the provided namespace id for the command. If not provided, the + namespace id of the block device will be used. If the command is issued + to a non-block device, the parameter is required. + +-d :: +--data=:: + File to read payload from. If unspecified, data will be read from the + standard input stream. + +-l :: +--data-len=:: + Payload data buffer length + +-m :: +--mo :: + Management Operation to perform. + +-s :: +--mos=:: + Management Operation Specific parameter. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +NVME +---- +Part of nvme-cli diff --git a/Documentation/nvme-io-passthru.1 b/Documentation/nvme-io-passthru.1 index 9730ec0d4b..a5c6d39f25 100644 --- a/Documentation/nvme-io-passthru.1 +++ b/Documentation/nvme-io-passthru.1 @@ -2,12 +2,12 @@ .\" Title: nvme-io-passthru .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-IO\-PASSTHRU" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-IO\-PASSTHRU" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,23 +32,22 @@ nvme-io-passthru \- Submit an arbitrary io command, return results .SH "SYNOPSIS" .sp .nf -\fInvme\-io\-passthru\fR [\-\-opcode= | \-o ] - [\-\-flags= | \-f ] [\-rsvd= | \-R ] - [\-\-namespace\-id= | \-nsid ] - [\-\-cdw2=] [\-\-cdw3=] [\-\-cdw10=] - [\-\-cdw11=] [\-\-cdw12=] [\-\-cdw13=] - [\-\-cdw14=] [\-\-cdw15=] - [\-\-data\-len= | \-l ] - [\-\-metadata\-len= | \-m ] - [\-\-read | \-r ] [\-\-write | \-w] - [\-\-input\-file= | \-i ] - [\-\-metadata= | \-M ] - [\-\-timeout= | \-t ] - [\-\-show\-command | \-s] - [\-\-dry\-run | \-d] - [\-\-raw\-binary | \-b] - [\-\-prefill= | \-p ] - [\-\-latency | \-T] +\fInvme\-io\-passthru\fR [\-\-opcode= | \-O ] + [\-\-flags= | \-f ] [\-rsvd= | \-R ] + [\-\-namespace\-id= | \-nsid ] + [\-\-cdw2=] [\-\-cdw3=] [\-\-cdw10=] + [\-\-cdw11=] [\-\-cdw12=] [\-\-cdw13=] + [\-\-cdw14=] [\-\-cdw15=] + [\-\-data\-len= | \-l ] + [\-\-metadata\-len= | \-m ] + [\-\-read | \-r] [\-\-write | \-w] + [\-\-input\-file= | \-i ] + [\-\-metadata= | \-M ] + [\-\-timeout= | \-t ] [\-\-show\-command | \-s] + [\-\-dry\-run | \-d] [\-\-raw\-binary | \-b] + [\-\-prefill= | \-p ] + [\-\-latency | \-T] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -59,7 +58,7 @@ The parameter is mandatory and may be either the NVMe character device 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= +\-O , \-\-opcode= .RS 4 The NVMe opcode to send to the device in the command .RE @@ -137,6 +136,20 @@ Prefill the buffer with a predetermined byte value\&. Defaults to 0\&. This may .RS 4 Print out the latency the IOCTL took (in us)\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp nvme io\-passthru /dev/nvme0n1 \-\-opcode=2 \-\-namespace\-id=1 \-\-data\-len=4096 \-\-read \-\-cdw10=0 \-\-cdw11=0 \-\-cdw12=0x70000 \-\-raw\-binary diff --git a/Documentation/nvme-io-passthru.html b/Documentation/nvme-io-passthru.html index b09f8eb4a1..da443ea958 100644 --- a/Documentation/nvme-io-passthru.html +++ b/Documentation/nvme-io-passthru.html @@ -749,23 +749,22 @@

    NAME

    SYNOPSIS

    -
    nvme-io-passthru <device> [--opcode=<opcode> | -o <opcode>]
    -                [--flags=<flags> | -f <flags>] [-rsvd=<rsvd> | -R <rsvd>]
    -                [--namespace-id=<nsid> | -nsid <nsid>]
    -                [--cdw2=<cdw2>] [--cdw3=<cdw3>] [--cdw10=<cdw10>]
    -                [--cdw11=<cdw11>] [--cdw12=<cdw12>] [--cdw13=<cdw13>]
    -                [--cdw14=<cdw14>] [--cdw15=<cdw15>]
    -                [--data-len=<data-len> | -l <data-len>]
    -                [--metadata-len=<len> | -m <len>]
    -                [--read | -r ] [--write | -w]
    -                [--input-file=<file> | -i <file>]
    -                [--metadata=<file> | -M <file>]
    -                [--timeout=<to> | -t <to>]
    -                [--show-command | -s]
    -                [--dry-run | -d]
    -                [--raw-binary | -b]
    -                [--prefill=<prefill> | -p <prefill>]
    -                [--latency | -T]
    +
    nvme-io-passthru <device> [--opcode=<opcode> | -O <opcode>]
    +                        [--flags=<flags> | -f <flags>] [-rsvd=<rsvd> | -R <rsvd>]
    +                        [--namespace-id=<nsid> | -nsid <nsid>]
    +                        [--cdw2=<cdw2>] [--cdw3=<cdw3>] [--cdw10=<cdw10>]
    +                        [--cdw11=<cdw11>] [--cdw12=<cdw12>] [--cdw13=<cdw13>]
    +                        [--cdw14=<cdw14>] [--cdw15=<cdw15>]
    +                        [--data-len=<data-len> | -l <data-len>]
    +                        [--metadata-len=<len> | -m <len>]
    +                        [--read | -r] [--write | -w]
    +                        [--input-file=<file> | -i <file>]
    +                        [--metadata=<file> | -M <file>]
    +                        [--timeout=<to> | -t <to>] [--show-command | -s]
    +                        [--dry-run | -d] [--raw-binary | -b]
    +                        [--prefill=<prefill> | -p <prefill>]
    +                        [--latency | -T]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -790,7 +789,7 @@

    OPTIONS

    --o <opcode> +-O <opcode>
    --opcode=<opcode> @@ -973,6 +972,29 @@

    OPTIONS

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

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -993,7 +1015,7 @@

    NVME

    diff --git a/Documentation/nvme-io-passthru.txt b/Documentation/nvme-io-passthru.txt index ba0904cf64..bbc34ebe6c 100644 --- a/Documentation/nvme-io-passthru.txt +++ b/Documentation/nvme-io-passthru.txt @@ -8,23 +8,23 @@ nvme-io-passthru - Submit an arbitrary io command, return results SYNOPSIS -------- [verse] -'nvme-io-passthru' [--opcode= | -o ] - [--flags= | -f ] [-rsvd= | -R ] - [--namespace-id= | -nsid ] - [--cdw2=] [--cdw3=] [--cdw10=] - [--cdw11=] [--cdw12=] [--cdw13=] - [--cdw14=] [--cdw15=] - [--data-len= | -l ] - [--metadata-len= | -m ] - [--read | -r ] [--write | -w] - [--input-file= | -i ] - [--metadata= | -M ] - [--timeout= | -t ] - [--show-command | -s] - [--dry-run | -d] - [--raw-binary | -b] - [--prefill= | -p ] - [--latency | -T] +'nvme-io-passthru' [--opcode= | -O ] + [--flags= | -f ] [-rsvd= | -R ] + [--namespace-id= | -n ] [--cdw2= | -2 ] + [--cdw3= | -3 ] [--cdw10= | -4 ] + [--cdw11= | -5 ] [--cdw12= | -6 ] + [--cdw13= | -7 ] [--cdw14= | -8 ] + [--cdw15= | -9 ] + [--data-len= | -l ] + [--metadata-len= | -m ] + [--read | -r] [--write | -w] + [--input-file= | -i ] + [--metadata= | -M ] + [--timeout= | -t ] [--show-command | -s] + [--dry-run | -d] [--raw-binary | -b] + [--prefill= | -p ] + [--latency | -T] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -43,7 +43,7 @@ printed to stdout for another program to parse. OPTIONS ------- --o :: +-O :: --opcode=:: The NVMe opcode to send to the device in the command @@ -59,6 +59,7 @@ OPTIONS --namespace-id=:: The value for the ns-id in the command. Defaults to '0'. +-[2-9] :: --cdw[2-3,10-15]=:: Specifies the command dword value for that specified entry in the command @@ -120,6 +121,15 @@ OPTIONS --latency:: Print out the latency the IOCTL took (in us). +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- diff --git a/Documentation/nvme-lba-status-log.1 b/Documentation/nvme-lba-status-log.1 index d385af3d15..a6466d39ec 100644 --- a/Documentation/nvme-lba-status-log.1 +++ b/Documentation/nvme-lba-status-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-lba-status-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LBA\-STATUS\-L" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LBA\-STATUS\-L" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,8 @@ nvme-lba-status-log \- Send LBA Status Log Page request returns result and log .SH "SYNOPSIS" .sp .nf -\fInvme lba\-status\-log\fR [\-\-rae | \-r] [\-\-output\-format= | \-o ] +\fInvme lba\-status\-log\fR [\-\-rae | \-r] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -48,13 +49,19 @@ On success, the returned LBA Status Log Page structure may be returned in one of Retain an Asynchronous Event\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-lba-status-log.html b/Documentation/nvme-lba-status-log.html index 0cb30f91a8..2f60ffbbfd 100644 --- a/Documentation/nvme-lba-status-log.html +++ b/Documentation/nvme-lba-status-log.html @@ -749,7 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme lba-status-log <device> [--rae | -r] [--output-format=<fmt> | -o <fmt>]
    +
    nvme lba-status-log <device> [--rae | -r]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -783,15 +784,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -831,7 +843,7 @@

    EXAMPLES

    diff --git a/Documentation/nvme-lba-status-log.txt b/Documentation/nvme-lba-status-log.txt index 0d888f7f6a..7d6efbd781 100644 --- a/Documentation/nvme-lba-status-log.txt +++ b/Documentation/nvme-lba-status-log.txt @@ -8,7 +8,8 @@ nvme-lba-status-log - Send LBA Status Log Page request returns result and log SYNOPSIS -------- [verse] -'nvme lba-status-log' [--rae | -r] [--output-format= | -o ] +'nvme lba-status-log' [--rae | -r] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -29,10 +30,14 @@ OPTIONS --rae:: Retain an Asynchronous Event. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or 'binary'. - Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-list-ctrl.1 b/Documentation/nvme-list-ctrl.1 index b703e80802..e504b78514 100644 --- a/Documentation/nvme-list-ctrl.1 +++ b/Documentation/nvme-list-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-list-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LIST\-CTRL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LIST\-CTRL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,25 +33,17 @@ nvme-list-ctrl \- Send NVMe Identify List Controllers, return result and structu .sp .nf \fInvme list\-ctrl\fR [\-\-cntid= | \-c ] - [\-\-namespace\-id= | \-n ] [\-o | \-\-output\-format=] -DESCRIPTION + [\-\-namespace\-id= | \-n ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi +.SH "DESCRIPTION" .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 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 +For the NVMe device given, sends an identify command for controller list and provides the result and returned structure\&. This uses either mode 12h or 13h depending on the requested namespace identifier\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. The starting controller in the list always begins with 0 unless the \*(Aq\-\-cntid\*(Aq option is given to override\&. +.sp +On success, the controller array is printed for each index and controller identifier\&. +.SH "OPTIONS" .PP \-c , \-\-cntid= .RS 4 @@ -63,12 +55,18 @@ Retrieve the identify list structure starting with the given controller id\&. If provided, will request the controllers attached to the specified namespace\&. If no namespace is given, or set to 0, the command requests the controller list for the entire subsystem, whether or not they are attached to namespace(s)\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to -\fInormal\fR +\fInormal\fR, +\fIjson\fR or -\fIjson\fR\&. Only one output format can be used at a time\&. +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-list-ctrl.html b/Documentation/nvme-list-ctrl.html index 16ce038d40..b0f1a16b23 100644 --- a/Documentation/nvme-list-ctrl.html +++ b/Documentation/nvme-list-ctrl.html @@ -750,26 +750,29 @@

    SYNOPSIS

    nvme list-ctrl <device> [--cntid=<cntid> | -c <cntid>]
    -                        [--namespace-id=<nsid> | -n <nsid>] [-o <fmt> | --output-format=<fmt>]
    -DESCRIPTION
    + [--namespace-id=<nsid> | -n <nsid>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    -
    -
    -
    For the NVMe device given, sends an identify command for controller list
    +
    +
    +
    +

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

    +'--cntid' option is given to override.

    +

    On success, the controller array is printed for each index and controller +identifier.

    +
    + +
    +

    OPTIONS

    +
    -c <cntid> @@ -797,15 +800,26 @@

    SYNOPSIS

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

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

    +
    +
    +-v
    ---output-format=<format> +--verbose

    - Set the reporting format to normal or json. Only one output - format can be used at a time. + Increase the information detail in the output.

    @@ -828,7 +842,7 @@

    NVME

    diff --git a/Documentation/nvme-list-ctrl.txt b/Documentation/nvme-list-ctrl.txt index f1bb52d916..6cd5c015a5 100644 --- a/Documentation/nvme-list-ctrl.txt +++ b/Documentation/nvme-list-ctrl.txt @@ -9,7 +9,9 @@ SYNOPSIS -------- [verse] 'nvme list-ctrl' [--cntid= | -c ] - [--namespace-id= | -n ] [-o | --output-format=] + [--namespace-id= | -n ] + [--output-format= | -o ] [--verbose | -v] + DESCRIPTION ----------- For the NVMe device given, sends an identify command for controller list @@ -37,10 +39,14 @@ OPTIONS command requests the controller list for the entire subsystem, whether or not they are attached to namespace(s). --o :: ---output-format=:: - Set the reporting format to 'normal' or 'json'. Only one output - format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-list-endgrp.1 b/Documentation/nvme-list-endgrp.1 index 331d993c53..345eb9efa8 100644 --- a/Documentation/nvme-list-endgrp.1 +++ b/Documentation/nvme-list-endgrp.1 @@ -2,12 +2,12 @@ .\" Title: nvme-list-endgrp .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LIST\-ENDGRP" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LIST\-ENDGRP" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-list-endgrp \- Send NVMe Identify Endurance Group List, return result and s .sp .nf \fInvme list\-endgrp\fR [\-\-endgrp\-id= | \-i ] - [\-o | \-\-output\-format=] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -47,12 +47,18 @@ The parameter is mandatory and may be either the NVMe character device Retrieve the identify endurance group list structure starting for the given endurance group id\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to -\fInormal\fR +\fInormal\fR, +\fIjson\fR or -\fIjson\fR\&. Only one output format can be used at a time\&. +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-list-endgrp.html b/Documentation/nvme-list-endgrp.html index d82561d215..eb2a318190 100644 --- a/Documentation/nvme-list-endgrp.html +++ b/Documentation/nvme-list-endgrp.html @@ -750,7 +750,7 @@

    SYNOPSIS

    nvme list-endgrp <device> [--endgrp-id=<endgrp-id> | -i <endgrp-id>]
    -                        [-o <fmt> | --output-format=<fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -779,20 +779,31 @@

    OPTIONS

    - Retrieve the identify endurance group list structure starting for the given - endurance group id. + Retrieve the identify endurance group list structure starting for the + given endurance group id.

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

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

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

    + Increase the information detail in the output.

    @@ -815,7 +826,7 @@

    NVME

    diff --git a/Documentation/nvme-list-endgrp.txt b/Documentation/nvme-list-endgrp.txt index 157dca9862..2d7724d9c2 100644 --- a/Documentation/nvme-list-endgrp.txt +++ b/Documentation/nvme-list-endgrp.txt @@ -3,14 +3,15 @@ nvme-list-endgrp(1) NAME ---- -nvme-list-endgrp - Send NVMe Identify Endurance Group List, return result and structure +nvme-list-endgrp - Send NVMe Identify Endurance Group List, return result and +structure SYNOPSIS -------- [verse] 'nvme list-endgrp' [--endgrp-id= | -i ] - [-o | --output-format=] - + [--output-format= | -o ] [--verbose | -v] + DESCRIPTION ----------- For the NVMe device given, sends an identify command for endurance group list @@ -26,13 +27,17 @@ OPTIONS ------- -i :: --endgrp-id=:: - Retrieve the identify endurance group list structure starting for the given - endurance group id. + Retrieve the identify endurance group list structure starting for the + given endurance group id. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. --o :: ---output-format=:: - Set the reporting format to 'normal' or 'json'. Only one output - format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-list-ns.1 b/Documentation/nvme-list-ns.1 index d69bc501b1..49cabd4687 100644 --- a/Documentation/nvme-list-ns.1 +++ b/Documentation/nvme-list-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,7 +34,8 @@ nvme-list-ns \- Send NVMe Identify List Namespaces, return result and structure .nf \fInvme list\-ns\fR [\-\-namespace\-id= | \-n ] [\-\-csi= | \-y ] - [\-\-all | \-a] [\-\-output\-format= | \-o ] + [\-\-all | \-a] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -60,11 +61,18 @@ If this value is given, retrieve the identify list structure associated with the Retrieve the identify list structure for all namespaces in the subsystem, whether attached or inactive\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to -\fInormal\fR, or -\fIjson\fR\&. Only one output format can be used at a time\&. +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-list-ns.html b/Documentation/nvme-list-ns.html index 0940bb4d0b..7d7ffdcfe6 100644 --- a/Documentation/nvme-list-ns.html +++ b/Documentation/nvme-list-ns.html @@ -751,7 +751,8 @@

    SYNOPSIS

    nvme list-ns <device> [--namespace-id=<nsid> | -n <nsid>]
                             [--csi=<command_set_identifier> | -y <command_set_identifier>]
    -                        [--all | -a] [--output-format=<fmt> | -o <fmt>]
    + [--all | -a] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -809,15 +810,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -859,7 +871,7 @@

    NVME

    diff --git a/Documentation/nvme-list-ns.txt b/Documentation/nvme-list-ns.txt index 753a959421..d24128765f 100644 --- a/Documentation/nvme-list-ns.txt +++ b/Documentation/nvme-list-ns.txt @@ -10,7 +10,8 @@ SYNOPSIS [verse] 'nvme list-ns' [--namespace-id= | -n ] [--csi= | -y ] - [--all | -a] [--output-format= | -o ] + [--all | -a] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -41,10 +42,14 @@ OPTIONS Retrieve the identify list structure for all namespaces in the subsystem, whether attached or inactive. --o :: ---output-format=:: - Set the reporting format to 'normal', or 'json'. - Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-list-secondary.txt b/Documentation/nvme-list-secondary.txt new file mode 100644 index 0000000000..88fbf420cb --- /dev/null +++ b/Documentation/nvme-list-secondary.txt @@ -0,0 +1,54 @@ +nvme-list-secondary(1) +====================== + +NAME +---- +nvme-list-secondary - Show secondary controller list associated with the primary +controller of the given device + +SYNOPSIS +-------- +[verse] +'nvme list-secondary' [--cntid= | -c ] + [--num-entries= | -e ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Show secondary controller list associated with the primary of the given device + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +On success, the secondary controller list is printed. + +OPTIONS +------- +-c :: +--cntid=:: + Lowest controller identifier to display. + +-e :: +--num-entries=:: + Number of entries to retrieve. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Has the program issue a list-secondary to display list. ++ +------------ +# nvme list-secondary /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-list-subsys.1 b/Documentation/nvme-list-subsys.1 index f806a631cc..15212a1a00 100644 --- a/Documentation/nvme-list-subsys.1 +++ b/Documentation/nvme-list-subsys.1 @@ -2,12 +2,12 @@ .\" Title: nvme-list-subsys .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LIST\-SUBSYS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LIST\-SUBSYS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,19 +32,25 @@ nvme-list-subsys \- List all NVMe subsystems .SH "SYNOPSIS" .sp .nf -\fInvme list\-subsys\fR [\-o | \-\-output\-format=] +\fInvme list\-subsys\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Scan the sysfs tree for NVM Express subsystems and return the controllers for those subsystems as well as some pertinent information about them\&. If a device is given, print out only the values for the controllers and subsystems leading to the device\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to -\fInormal\fR +\fInormal\fR, +\fIjson\fR or -\fIjson\fR\&. Only one output format can be used at a time\&. +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp @@ -55,12 +61,12 @@ or \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 + +\- 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 + +\- 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 @@ -82,12 +88,12 @@ nvme\-subsys1 \- NQN=nvmf\-test2 { "Name" : "nvme0", "Transport" : "rdma", - "Address" : "traddr=1\&.1\&.1\&.3 trsvcid=4420 host_traddr=1\&.1\&.1\&.1" + "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" + "Address" : "traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.2" } ] }, @@ -100,12 +106,12 @@ nvme\-subsys1 \- NQN=nvmf\-test2 { "Name" : "nvme2", "Transport" : "rdma", - "Address" : "traddr=1\&.1\&.1\&.3 trsvcid=4420 host_traddr=1\&.1\&.1\&.2" + "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" + "Address" : "traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.1" } ] } diff --git a/Documentation/nvme-list-subsys.html b/Documentation/nvme-list-subsys.html index c3d5d989e5..eb55027a58 100644 --- a/Documentation/nvme-list-subsys.html +++ b/Documentation/nvme-list-subsys.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme list-subsys [-o <fmt> | --output-format=<fmt>] <device>
    +
    nvme list-subsys <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -768,15 +768,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -789,12 +800,12 @@

    EXAMPLES

    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
    + +- 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
    + +- 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
    @@ -810,12 +821,12 @@

    EXAMPLES

    { "Name" : "nvme0", "Transport" : "rdma", - "Address" : "traddr=1.1.1.3 trsvcid=4420 host_traddr=1.1.1.1" + "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" + "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2" } ] }, @@ -828,12 +839,12 @@

    EXAMPLES

    { "Name" : "nvme2", "Transport" : "rdma", - "Address" : "traddr=1.1.1.3 trsvcid=4420 host_traddr=1.1.1.2" + "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" + "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1" } ] } @@ -854,7 +865,7 @@

    NVME

    diff --git a/Documentation/nvme-list-subsys.txt b/Documentation/nvme-list-subsys.txt index 56045b89e4..a5d2d480a2 100644 --- a/Documentation/nvme-list-subsys.txt +++ b/Documentation/nvme-list-subsys.txt @@ -8,7 +8,7 @@ nvme-list-subsys - List all NVMe subsystems SYNOPSIS -------- [verse] -'nvme list-subsys' [-o | --output-format=] +'nvme list-subsys' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -19,10 +19,14 @@ and subsystems leading to the device. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal' or 'json'. Only one output - format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- @@ -30,12 +34,12 @@ EXAMPLES 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 + +- 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 + +- 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 @@ -50,12 +54,12 @@ root@host# nvme list-subsys -o json { "Name" : "nvme0", "Transport" : "rdma", - "Address" : "traddr=1.1.1.3 trsvcid=4420 host_traddr=1.1.1.1" + "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" + "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2" } ] }, @@ -68,12 +72,12 @@ root@host# nvme list-subsys -o json { "Name" : "nvme2", "Transport" : "rdma", - "Address" : "traddr=1.1.1.3 trsvcid=4420 host_traddr=1.1.1.2" + "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" + "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1" } ] } diff --git a/Documentation/nvme-list.1 b/Documentation/nvme-list.1 index d2d7eddcb8..400aefa8d9 100644 --- a/Documentation/nvme-list.1 +++ b/Documentation/nvme-list.1 @@ -2,12 +2,12 @@ .\" Title: nvme-list .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LIST" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LIST" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,19 +32,20 @@ nvme-list \- List all recognized NVMe devices .SH "SYNOPSIS" .sp .nf -\fInvme list\fR [\-o | \-\-output\-format=] +\fInvme list\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Scan the sysfs tree for NVM Express devices and return the /dev node for those devices as well as some pertinent information about them\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to -\fInormal\fR +\fInormal\fR, +\fIjson\fR or -\fIjson\fR\&. Only one output format can be used at a time\&. +\fIbinary\fR\&. Only one output format can be used at a time\&. .RE .PP \-v, \-\-verbose diff --git a/Documentation/nvme-list.html b/Documentation/nvme-list.html index ab448d23e4..c90b3eb7d8 100644 --- a/Documentation/nvme-list.html +++ b/Documentation/nvme-list.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme list [-o <fmt> | --output-format=<fmt>]
    +
    nvme list [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -766,15 +766,15 @@

    OPTIONS

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

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

    @@ -816,7 +816,7 @@

    NVME

    diff --git a/Documentation/nvme-list.txt b/Documentation/nvme-list.txt index 7cc333be52..a8c5428cff 100644 --- a/Documentation/nvme-list.txt +++ b/Documentation/nvme-list.txt @@ -8,7 +8,7 @@ nvme-list - List all recognized NVMe devices SYNOPSIS -------- [verse] -'nvme list' [-o | --output-format=] +'nvme list' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -17,10 +17,10 @@ for those devices as well as some pertinent information about them. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal' or 'json'. Only one output - format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. -v:: --verbose:: @@ -32,7 +32,6 @@ ENVIRONMENT ----------- PCI_IDS_PATH - Full path of pci.ids file in case nvme could not find it in common locations. - EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-lockdown.1 b/Documentation/nvme-lockdown.1 index 1489852776..48fe02af88 100644 --- a/Documentation/nvme-lockdown.1 +++ b/Documentation/nvme-lockdown.1 @@ -2,12 +2,12 @@ .\" Title: nvme-lockdown .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-LOCKDOWN" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-LOCKDOWN" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,41 +32,56 @@ nvme-lockdown \- Send an NVMe Lockdown command to prohibit or allow the executio .SH "SYNOPSIS" .sp .nf -\fInvme\-lockdown\fR [\-\-ofi= | \-o ] +\fInvme\-lockdown\fR [\-\-ofi= | \-O ] [\-\-ifc= | \-f ] [\-\-prhbt= | \-p ] [\-\-scp= | \-s ] [\-\-uuid= | \-U ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Lockdown command is used to control the Command and Feature Lockdown capability which configures the prohibition or allowance of execution of the specified command or Set Features command targeting a specific Feature Identifier\&. .SH "OPTIONS" .PP -\-\-ofi=, \-o +\-O , \-\-ofi= .RS 4 Opcode or Feature Identifier(OFI) specifies the command opcode or Set Features Feature Identifier identified by the Scope field\&. .RE .PP -\-\-ifc=, \-f +\-f , \-\-ifc= .RS 4 Interface (INF) field identifies the interfaces affected by this command\&. .RE .PP -\-\-prhbt=, \-p +\-p , \-\-prhbt= .RS 4 Prohibit (PRHBT) bit specifies whether to prohibit or allow the command opcode or Set Features Feature Identifier specified by this command\&. .RE .PP -\-\-scp=, \-s +\-s , \-\-scp= .RS 4 Scope (SCP) field specifies the contents of the Opcode or Feature Identifier field\&. .RE .PP -\-\-uuid=, \-U +\-U , \-\-uuid= .RS 4 UUID Index \- If this field is set to a non\-zero value, then the value of this field is the index of a UUID in the UUID List that is used by the command\&. If this field is cleared to 0h,then no UUID index is specified\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-lockdown.html b/Documentation/nvme-lockdown.html index 9384877ac6..d04aa9dfc7 100644 --- a/Documentation/nvme-lockdown.html +++ b/Documentation/nvme-lockdown.html @@ -749,11 +749,12 @@

    NAME

    SYNOPSIS

    -
    nvme-lockdown <device> [--ofi=<ofi> | -o <ofi>]
    +
    nvme-lockdown <device> [--ofi=<ofi> | -O <ofi>]
                             [--ifc=<ifc> | -f <ifc>]
                             [--prhbt=<prhbt> | -p <prhbt>]
                             [--scp=<scp> | -s <scp>]
    -                        [--uuid=<UUID_Index> | -U <UUID_Index>]
    + [--uuid=<UUID_Index> | -U <UUID_Index>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -772,10 +773,10 @@

    OPTIONS

    ---ofi=<ofi> +-O <ofi>
    --o <ofi> +--ofi=<ofi>

    @@ -784,10 +785,10 @@

    OPTIONS

    ---ifc=<ifc> +-f <ifc>
    --f <ifc> +--ifc=<ifc>

    @@ -795,10 +796,10 @@

    OPTIONS

    ---prhbt=<prhbt> +-p <prhbt>
    --p <prhbt> +--prhbt=<prhbt>

    @@ -807,10 +808,10 @@

    OPTIONS

    ---scp=<scp> +-s <scp>
    --s <scp> +--scp=<scp>

    @@ -818,10 +819,10 @@

    OPTIONS

    ---uuid=<UUID_Index> +-U <UUID_Index>
    --U <UUID_Index> +--uuid=<UUID_Index>

    @@ -830,6 +831,29 @@

    OPTIONS

    If this field is cleared to 0h,then no UUID index is specified.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -850,7 +874,7 @@

    NVME

    diff --git a/Documentation/nvme-lockdown.txt b/Documentation/nvme-lockdown.txt index cf8a48ff9c..e17ac70e67 100644 --- a/Documentation/nvme-lockdown.txt +++ b/Documentation/nvme-lockdown.txt @@ -8,11 +8,12 @@ nvme-lockdown - Send an NVMe Lockdown command to prohibit or allow the execution SYNOPSIS -------- [verse] -'nvme-lockdown' [--ofi= | -o ] +'nvme-lockdown' [--ofi= | -O ] [--ifc= | -f ] [--prhbt= | -p ] [--scp= | -s ] [--uuid= | -U ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -23,34 +24,42 @@ Identifier. OPTIONS ------- +-O :: --ofi=:: --o :: Opcode or Feature Identifier(OFI) specifies the command opcode or Set Features Feature Identifier identified by the Scope field. ---ifc=:: -f :: +--ifc=:: Interface (INF) field identifies the interfaces affected by this command. ---prhbt=:: -p :: +--prhbt=:: Prohibit (PRHBT) bit specifies whether to prohibit or allow the command opcode or Set Features Feature Identifier specified by this command. ---scp=:: -s :: +--scp=:: Scope (SCP) field specifies the contents of the Opcode or Feature Identifier field. - ---uuid=:: -U :: +--uuid=:: UUID Index - If this field is set to a non-zero value, then the value of this field is the index of a UUID in the UUID List that is used by the command. If this field is cleared to 0h,then no UUID index is specified. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet. NVME ---- -Part of the nvme-user suite \ No newline at end of file +Part of the nvme-user suite diff --git a/Documentation/nvme-media-unit-stat-log.txt b/Documentation/nvme-media-unit-stat-log.txt index 427b77cf55..997a497421 100644 --- a/Documentation/nvme-media-unit-stat-log.txt +++ b/Documentation/nvme-media-unit-stat-log.txt @@ -9,9 +9,8 @@ request, returns result and log. SYNOPSIS -------- [verse] -'nvme media-unit-stat-log' [--dom-id | -d ] - [--output-format= | -o ] - [--raw-binary | -b] +'nvme media-unit-stat-log' [--dom-id | -d] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -26,17 +25,18 @@ On success, the returned Media unit status log pages log structure will be print OPTIONS ------- --o :: ---output-format=:: - This option will set the reporting format to normal, json, or binary. - Only one output format can be used at a time. +-o :: +--output-format=:: + This option will set the reporting format to normal, json, or binary. + Only one output format can be used at a time. -d:: --dom-id:: - To get the domain ID. + To get the domain ID. + -b:: --raw-binary:: - To show raw binary data. + To show raw binary data. EXAMPLES -------- diff --git a/Documentation/nvme-mi-cmd-support-effects-log.1 b/Documentation/nvme-mi-cmd-support-effects-log.1 index d4b24f9b8e..8d18e62ff4 100644 --- a/Documentation/nvme-mi-cmd-support-effects-log.1 +++ b/Documentation/nvme-mi-cmd-support-effects-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-mi-cmd-support-effects-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MI\-CMD\-SUPPO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MI\-CMD\-SUPPO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,8 @@ nvme-mi-cmd-support-effects-log \- Send NVMe MI Command Support and Effects log, .SH "SYNOPSIS" .sp .nf -\fInvme\-mi\-cmd\-support\-effects\-log\fR [\-o | \-\-output\-format=] - [\-H | \-\-human\-readable] +\fInvme\-mi\-cmd\-support\-effects\-log\fR [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -44,17 +44,23 @@ The parameter is mandatory and may be either the NVMe character device On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-H, \-\-human\-readable +.RS 4 +This option will parse and format many of the bit fields into human\-readable formats\&. +.RE +.PP +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE .PP -\-H, \-\-human\-readable +\-v, \-\-verbose .RS 4 -This option will parse and format many of the bit fields into human\-readable formats\&. +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-mi-cmd-support-effects-log.html b/Documentation/nvme-mi-cmd-support-effects-log.html index fb64b1678f..c70a8b0971 100644 --- a/Documentation/nvme-mi-cmd-support-effects-log.html +++ b/Documentation/nvme-mi-cmd-support-effects-log.html @@ -740,7 +740,7 @@

    NAME

    nvme-mi-cmd-support-effects-log - - Send NVMe MI Command Support and Effects log, returns results and structure + Send NVMe MI Command Support and Effects log, returns results and structure

    @@ -749,8 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme-mi-cmd-support-effects-log <device> [-o <fmt> | --output-format=<fmt>]
    -                                        [-H | --human-readable]
    +
    nvme-mi-cmd-support-effects-log <device> [--human-readable | -H]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -772,27 +772,38 @@

    OPTIONS

    --o <format> +-H
    ---output-format=<format> +--human-readable

    - Set the reporting format to normal, json, or - binary. Only one output format can be used at a time. + This option will parse and format many of the bit fields + into human-readable formats.

    --H +-o <fmt>
    ---human-readable +--output-format=<fmt>

    - This option will parse and format many of the bit fields - into human-readable formats. + Set the reporting format to normal, json or binary. Only one + output format can be used at a time. +

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

    + Increase the information detail in the output.

    @@ -815,7 +826,7 @@

    NVME

    diff --git a/Documentation/nvme-mi-cmd-support-effects-log.txt b/Documentation/nvme-mi-cmd-support-effects-log.txt index 67b8355fd2..22218040ff 100644 --- a/Documentation/nvme-mi-cmd-support-effects-log.txt +++ b/Documentation/nvme-mi-cmd-support-effects-log.txt @@ -4,13 +4,13 @@ nvme-mi-cmd-support-effects-log(1) NAME ---- nvme-mi-cmd-support-effects-log - Send NVMe MI Command Support and Effects log, - returns results and structure +returns results and structure SYNOPSIS -------- [verse] -'nvme-mi-cmd-support-effects-log' [-o | --output-format=] - [-H | --human-readable] +'nvme-mi-cmd-support-effects-log' [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -26,16 +26,20 @@ raw buffer may be printed to stdout. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - -H:: --human-readable:: This option will parse and format many of the bit fields into human-readable formats. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- nvme mi-cmd-support-effects-log /dev/nvme0 -H diff --git a/Documentation/nvme-micron-clear-pcie-errors.1 b/Documentation/nvme-micron-clear-pcie-errors.1 index 0914d6b8e2..3d76b45da3 100644 --- a/Documentation/nvme-micron-clear-pcie-errors.1 +++ b/Documentation/nvme-micron-clear-pcie-errors.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-clear-pcie-errors .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-CLEAR\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-CLEAR\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-micron-clear-pcie-errors.html b/Documentation/nvme-micron-clear-pcie-errors.html index 8544e15aee..b7b9e1a254 100644 --- a/Documentation/nvme-micron-clear-pcie-errors.html +++ b/Documentation/nvme-micron-clear-pcie-errors.html @@ -798,7 +798,7 @@

    NVME

    diff --git a/Documentation/nvme-micron-internal-log.1 b/Documentation/nvme-micron-internal-log.1 index 8bca8a9ad7..97428fdce9 100644 --- a/Documentation/nvme-micron-internal-log.1 +++ b/Documentation/nvme-micron-internal-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-internal-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-INTERN" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-INTERN" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -36,7 +36,7 @@ nvme-micron-internal-log \- Retrieve Micron device\*(Aqs internal logs and save .fi .SH "DESCRIPTION" .sp -For the given NVMe device, sends the Micron vendor specific device commands to retrieve various logs (in binary format) and compresses them and saves into specified zip file\&. These vendor unique logs can be analyzed with Micron Technical support team for any device specific issues +For the given NVMe device, sends the Micron vendor specific device commands to retrieve various logs (in binary format) and compresses them and saves into specified zip file\&. These vendor unique logs can be analyzed with Micron Technical support team for any device specific issues\&. .sp The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. .sp diff --git a/Documentation/nvme-micron-internal-log.html b/Documentation/nvme-micron-internal-log.html index 8f7d565189..6e288c1439 100644 --- a/Documentation/nvme-micron-internal-log.html +++ b/Documentation/nvme-micron-internal-log.html @@ -757,15 +757,16 @@

    SYNOPSIS

    DESCRIPTION

    -

    For the given NVMe device, sends the Micron vendor specific device commands to retrieve -various logs (in binary format) and compresses them and saves into specified zip file. -These vendor unique logs can be analyzed with Micron Technical support team for any device -specific issues

    +

    For the given NVMe device, sends the Micron vendor specific device commands to +retrieve various logs (in binary format) and compresses them and saves into +specified zip file. These vendor unique logs can be analyzed with Micron +Technical support team for any device specific issues.

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

    -

    This will only work on Micron devices devices of model numbers 9200 and 54XX. Support -for new devices may be added subsequently. Results for any other device are undefined.

    +

    This will only work on Micron devices devices of model numbers 9200 and 54XX. +Support for new devices may be added subsequently. Results for any other device +are undefined.

    @@ -813,7 +814,7 @@

    NVME

    diff --git a/Documentation/nvme-micron-internal-log.txt b/Documentation/nvme-micron-internal-log.txt index 37a50ad4d6..b8e92281dc 100644 --- a/Documentation/nvme-micron-internal-log.txt +++ b/Documentation/nvme-micron-internal-log.txt @@ -3,7 +3,8 @@ nvme-micron-internal-log(1) NAME ---- -nvme-micron-internal-log - Retrieve Micron device's internal logs and save to given zip file. +nvme-micron-internal-log - Retrieve Micron device's internal logs and save to +given zip file. SYNOPSIS -------- @@ -12,23 +13,24 @@ SYNOPSIS DESCRIPTION ----------- -For the given NVMe device, sends the Micron vendor specific device commands to retrieve -various logs (in binary format) and compresses them and saves into specified zip file. -These vendor unique logs can be analyzed with Micron Technical support team for any device -specific issues +For the given NVMe device, sends the Micron vendor specific device commands to +retrieve various logs (in binary format) and compresses them and saves into +specified zip file. These vendor unique logs can be analyzed with Micron +Technical support team for any device specific issues. The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). -This will only work on Micron devices devices of model numbers 9200 and 54XX. Support -for new devices may be added subsequently. Results for any other device are undefined. +This will only work on Micron devices devices of model numbers 9200 and 54XX. +Support for new devices may be added subsequently. Results for any other device +are undefined. OPTIONS ------- -l :: --package=:: - name of the file (with .zip extension) to save the device logs + name of the file (with .zip extension) to save the device logs EXAMPLES -------- diff --git a/Documentation/nvme-micron-nand-stats.1 b/Documentation/nvme-micron-nand-stats.1 index fb820e18f0..bb73919571 100644 --- a/Documentation/nvme-micron-nand-stats.1 +++ b/Documentation/nvme-micron-nand-stats.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-nand-stats .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-NAND\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-NAND\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-micron-nand-stats.html b/Documentation/nvme-micron-nand-stats.html index 7be9edae2b..57806b084e 100644 --- a/Documentation/nvme-micron-nand-stats.html +++ b/Documentation/nvme-micron-nand-stats.html @@ -799,7 +799,7 @@

    NVME

    diff --git a/Documentation/nvme-micron-pcie-stats.1 b/Documentation/nvme-micron-pcie-stats.1 index f6947d71e7..3c1875a16b 100644 --- a/Documentation/nvme-micron-pcie-stats.1 +++ b/Documentation/nvme-micron-pcie-stats.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-pcie-stats .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-PCIE\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-PCIE\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-micron-pcie-stats.html b/Documentation/nvme-micron-pcie-stats.html index 20f6be2d37..d81e4a7dad 100644 --- a/Documentation/nvme-micron-pcie-stats.html +++ b/Documentation/nvme-micron-pcie-stats.html @@ -799,7 +799,7 @@

    NVME

    diff --git a/Documentation/nvme-micron-selective-download.1 b/Documentation/nvme-micron-selective-download.1 index de567016c1..da20310d20 100644 --- a/Documentation/nvme-micron-selective-download.1 +++ b/Documentation/nvme-micron-selective-download.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-selective-download .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-SELECT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-SELECT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -28,19 +28,20 @@ .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" -nvme-micron-selective-download \- Performs selective firmware download that allows user to select which firmware binary to update for 9200 devices\&. This requires power cycle once the update completes\&. +nvme-micron-selective-download \- Performs selective firmware download that allows user select which firmware binary to update for 9200 devices\&. This requires power cycle the update completes\&. .SH "SYNOPSIS" .sp .nf -\fInvme micron selective\-download\fR [\-\-fw=, \-f ] [\-\-select=, \-s ] +\fInvme micron selective\-download\fR [\-\-fw=, \-f ] + [\-\-select=, \-s ] .fi .SH "DESCRIPTION" .sp -This command uses micron vendor specific nvme commands to download given firmware image to the specified 9200 device to update selected or all portions of firmware image\&. +This command uses micron vendor specific nvme commands to download given firmware image to the 9200 device to update selected or all portions of firmware image\&. .sp The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. .sp -This will only work on Micron devices devices of model number 9200\&. Support for new devices may be added subsequently\&. Results for any other device are undefined\&. +This will only work on Micron devices devices of model number 9200\&. Support for new devices be added subsequently\&. Results for any other device are undefined\&. .SH "OPTIONS" .PP \-f , \-\-fw= diff --git a/Documentation/nvme-micron-selective-download.html b/Documentation/nvme-micron-selective-download.html index 7ae5e2a9ee..84774ec4ad 100644 --- a/Documentation/nvme-micron-selective-download.html +++ b/Documentation/nvme-micron-selective-download.html @@ -740,7 +740,7 @@

    NAME

    nvme-micron-selective-download - - Performs selective firmware download that allows user to select which firmware binary to update for 9200 devices. This requires power cycle once the update completes. + Performs selective firmware download that allows user select which firmware binary to update for 9200 devices. This requires power cycle the update completes.

    @@ -749,7 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme micron selective-download <device> [--fw=<FILE>, -f <FILE>] [--select=<flag>, -s <flag>]
    +
    nvme micron selective-download <device> [--fw=<FILE>, -f <FILE>]
    +                        [--select=<flag>, -s <flag>]
    @@ -757,13 +758,14 @@

    SYNOPSIS

    DESCRIPTION

    -

    This command uses micron vendor specific nvme commands to download given firmware image to the -specified 9200 device to update selected or all portions of firmware image.

    +

    This command uses micron vendor specific nvme commands to download given +firmware image to the 9200 device to update selected or all portions of firmware +image.

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

    -

    This will only work on Micron devices devices of model number 9200. Support for new devices -may be added subsequently. Results for any other device are undefined.

    +

    This will only work on Micron devices devices of model number 9200. Support for +new devices be added subsequently. Results for any other device are undefined.

    @@ -867,7 +869,7 @@

    NVME

    diff --git a/Documentation/nvme-micron-selective-download.txt b/Documentation/nvme-micron-selective-download.txt index 5fb11d79a5..c20af74fe3 100644 --- a/Documentation/nvme-micron-selective-download.txt +++ b/Documentation/nvme-micron-selective-download.txt @@ -3,38 +3,41 @@ nvme-micron-selective-download(1) NAME ---- -nvme-micron-selective-download - Performs selective firmware download that allows user -to select which firmware binary to update for 9200 devices. This requires power cycle -once the update completes. +nvme-micron-selective-download - Performs selective firmware download that +allows user select which firmware binary to update for 9200 devices. This +requires power cycle the update completes. SYNOPSIS -------- [verse] -'nvme micron selective-download' [--fw=, -f ] [--select=, -s ] +'nvme micron selective-download' [--fw=, -f ] + [--select=, -s ] DESCRIPTION ----------- -This command uses micron vendor specific nvme commands to download given firmware image to the -specified 9200 device to update selected or all portions of firmware image. +This command uses micron vendor specific nvme commands to download given +firmware image to the 9200 device to update selected or all portions of firmware +image. The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). -This will only work on Micron devices devices of model number 9200. Support for new devices -may be added subsequently. Results for any other device are undefined. +This will only work on Micron devices devices of model number 9200. Support for +new devices be added subsequently. Results for any other device are undefined. OPTIONS ------- -f :: --fw=:: - name of the firmware image file + name of the firmware image file + -s :: --select=:: - flag that has following values - OOB:: This updates the OOB and main firmware\n" - EEP:: This updates the eeprom and main firmware\n" - ALL:: This updates the eeprom, OOB, and main firmware"; + flag that has following values + OOB:: This updates the OOB and main firmware\n" + EEP:: This updates the eeprom and main firmware\n" + ALL:: This updates the eeprom, OOB, and main firmware"; EXAMPLES -------- @@ -42,7 +45,7 @@ EXAMPLES + ------------ # nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=OOB -# nvme micron selective-download /dev/nvme0 -f firmware_bin -s OOB +# nvme micron selective-download /dev/nvme0 -f firmware_bin -s OOB ------------ * Update OOB and main firmware diff --git a/Documentation/nvme-micron-smart-add-log.1 b/Documentation/nvme-micron-smart-add-log.1 index 56da6d84c8..3ef3f17260 100644 --- a/Documentation/nvme-micron-smart-add-log.1 +++ b/Documentation/nvme-micron-smart-add-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-smart-add-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-SMART\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-SMART\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-micron-smart-add-log \- Retrieves NAND statistics (2200 model drives) or Ex .SH "SYNOPSIS" .sp .nf -\fInvme micron vs\-smart\-add\-log\fR \-f +\fInvme micron vs\-smart\-add\-log\fR \-f .fi .SH "DESCRIPTION" .sp @@ -44,8 +44,11 @@ The \fI\-f\fR option controls the displayed output data format based on the opti .sp This will only work on Micron devices devices of model numbers 54XX and OCP complaint controllers\&. Support for new devices may be added subsequently\&. .SH "OPTIONS" -.sp -\-f controls the format of displayed output\&. +.PP +\-f +.RS 4 +Controls the format of displayed output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-micron-smart-add-log.html b/Documentation/nvme-micron-smart-add-log.html index ad6e58d5dd..34a21dd17f 100644 --- a/Documentation/nvme-micron-smart-add-log.html +++ b/Documentation/nvme-micron-smart-add-log.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme micron vs-smart-add-log <device>  -f <json|normal>
    +
    nvme micron vs-smart-add-log <device> -f <json|normal>
    @@ -775,7 +775,16 @@

    DESCRIPTION

    OPTIONS

    -

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

    +
    +
    +-f <json|normal> +
    +
    +

    + Controls the format of displayed output. +

    +
    +
    @@ -808,7 +817,7 @@

    EXAMPLES

    diff --git a/Documentation/nvme-micron-smart-add-log.txt b/Documentation/nvme-micron-smart-add-log.txt index 1fd74bac92..13e0d968d1 100644 --- a/Documentation/nvme-micron-smart-add-log.txt +++ b/Documentation/nvme-micron-smart-add-log.txt @@ -9,7 +9,7 @@ or Extended SMART information (OCP complaint models) of given micron device SYNOPSIS -------- [verse] -'nvme micron vs-smart-add-log' -f +'nvme micron vs-smart-add-log' -f DESCRIPTION ----------- @@ -32,8 +32,8 @@ complaint controllers. Support for new devices may be added subsequently. OPTIONS ------- --f controls the format of displayed output. - +-f :: + Controls the format of displayed output. EXAMPLES -------- diff --git a/Documentation/nvme-micron-temperature-stats.1 b/Documentation/nvme-micron-temperature-stats.1 index 225588c292..ee8a62b41a 100644 --- a/Documentation/nvme-micron-temperature-stats.1 +++ b/Documentation/nvme-micron-temperature-stats.1 @@ -2,12 +2,12 @@ .\" Title: nvme-micron-temperature-stats .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-MICRON\-TEMPER" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-MICRON\-TEMPER" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-micron-temperature-stats.html b/Documentation/nvme-micron-temperature-stats.html index baa045f11e..7fa023fc8f 100644 --- a/Documentation/nvme-micron-temperature-stats.html +++ b/Documentation/nvme-micron-temperature-stats.html @@ -799,7 +799,7 @@

    NVME

    diff --git a/Documentation/nvme-netapp-ontapdevices.1 b/Documentation/nvme-netapp-ontapdevices.1 index d810b05f14..0dda70296d 100644 --- a/Documentation/nvme-netapp-ontapdevices.1 +++ b/Documentation/nvme-netapp-ontapdevices.1 @@ -2,12 +2,12 @@ .\" Title: nvme-netapp-ontapdevices .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-NETAPP\-ONTAPD" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-NETAPP\-ONTAPD" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-netapp-ontapdevices \- Display information about ONTAP devices .SH "SYNOPSIS" .sp .nf -\fInvme netapp ontapdevices\fR [\-o | \-\-output\-format=] +\fInvme netapp ontapdevices\fR [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp diff --git a/Documentation/nvme-netapp-ontapdevices.html b/Documentation/nvme-netapp-ontapdevices.html index 058764044f..38ef119c8e 100644 --- a/Documentation/nvme-netapp-ontapdevices.html +++ b/Documentation/nvme-netapp-ontapdevices.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme netapp ontapdevices [-o <fmt> | --output-format=<fmt>]
    +
    nvme netapp ontapdevices [--output-format=<fmt> | -o <fmt>]
    @@ -773,8 +773,8 @@

    OPTIONS

    - Set the reporting format to normal (default), column, or - json. Only one output format can be used at a time. + Set the reporting format to normal (default), column, or + json. Only one output format can be used at a time.

    @@ -807,7 +807,7 @@

    NVME

    diff --git a/Documentation/nvme-netapp-ontapdevices.txt b/Documentation/nvme-netapp-ontapdevices.txt index c292758598..fc28947d60 100644 --- a/Documentation/nvme-netapp-ontapdevices.txt +++ b/Documentation/nvme-netapp-ontapdevices.txt @@ -8,7 +8,7 @@ nvme-netapp-ontapdevices - Display information about ONTAP devices SYNOPSIS -------- [verse] -'nvme netapp ontapdevices' [-o | --output-format=] +'nvme netapp ontapdevices' [--output-format= | -o ] DESCRIPTION ----------- @@ -19,8 +19,8 @@ OPTIONS ------- -o :: --output-format=:: - Set the reporting format to 'normal' (default), 'column', or - 'json'. Only one output format can be used at a time. + Set the reporting format to 'normal' (default), 'column', or + 'json'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-netapp-smdevices.1 b/Documentation/nvme-netapp-smdevices.1 index 2df22e207d..8f19522ba1 100644 --- a/Documentation/nvme-netapp-smdevices.1 +++ b/Documentation/nvme-netapp-smdevices.1 @@ -2,12 +2,12 @@ .\" Title: nvme-netapp-smdevices .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-NETAPP\-SMDEVI" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-NETAPP\-SMDEVI" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-netapp-smdevices \- Display information for each NVMe path to an E\-Series .SH "SYNOPSIS" .sp .nf -\fInvme netapp smdevices\fR [\-o | \-\-output\-format=] +\fInvme netapp smdevices\fR [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp diff --git a/Documentation/nvme-netapp-smdevices.html b/Documentation/nvme-netapp-smdevices.html index d974e9d441..2fb48305de 100644 --- a/Documentation/nvme-netapp-smdevices.html +++ b/Documentation/nvme-netapp-smdevices.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme netapp smdevices [-o <fmt> | --output-format=<fmt>]
    +
    nvme netapp smdevices [--output-format=<fmt> | -o <fmt>]
    @@ -809,7 +809,7 @@

    NVME

    diff --git a/Documentation/nvme-netapp-smdevices.txt b/Documentation/nvme-netapp-smdevices.txt index b66b98d1d9..cb68acf7c0 100644 --- a/Documentation/nvme-netapp-smdevices.txt +++ b/Documentation/nvme-netapp-smdevices.txt @@ -8,7 +8,7 @@ nvme-netapp-smdevices - Display information for each NVMe path to an E-Series vo SYNOPSIS -------- [verse] -'nvme netapp smdevices' [-o | --output-format=] +'nvme netapp smdevices' [--output-format= | -o ] DESCRIPTION ----------- diff --git a/Documentation/nvme-ns-descs.1 b/Documentation/nvme-ns-descs.1 index 5e30c337bb..cc5a192fef 100644 --- a/Documentation/nvme-ns-descs.1 +++ b/Documentation/nvme-ns-descs.1 @@ -2,12 +2,12 @@ .\" Title: nvme-ns-descs .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-NS\-DESCS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-NS\-DESCS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,8 @@ nvme-ns-descs \- Send NVMe Identify for a list of Namespace Identification Descr .SH "SYNOPSIS" .sp .nf -\fInvme ns\-descs\fR [\-\-namespace\-id= | \-n ] - [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] +\fInvme ns\-descs\fR [\-\-namespace\-id= | \-n ] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,13 +54,19 @@ Retrieve the identify namespace identification descriptor structure for the give Print the raw buffer to stdout\&. Structure is not parsed by program\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-ns-descs.html b/Documentation/nvme-ns-descs.html index 8e3a4b8bdf..02dc1fc340 100644 --- a/Documentation/nvme-ns-descs.html +++ b/Documentation/nvme-ns-descs.html @@ -749,9 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme ns-descs <device> [--namespace-id=<nsid> | -n <nsid>]
    -                        [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    +
    nvme ns-descs <device> [--namespace-id=<nsid> | -n <nsid>] [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -803,15 +802,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -857,7 +867,7 @@

    NVME

    diff --git a/Documentation/nvme-ns-descs.txt b/Documentation/nvme-ns-descs.txt index 8afeba580a..04c6e51ecf 100644 --- a/Documentation/nvme-ns-descs.txt +++ b/Documentation/nvme-ns-descs.txt @@ -9,9 +9,8 @@ nvme-ns-descs - Send NVMe Identify for a list of Namespace Identification SYNOPSIS -------- [verse] -'nvme ns-descs' [--namespace-id= | -n ] - [--raw-binary | -b] - [--output-format= | -o ] +'nvme ns-descs' [--namespace-id= | -n ] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -43,11 +42,14 @@ OPTIONS Print the raw buffer to stdout. Structure is not parsed by program. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or 'binary'. - Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-ns-rescan.1 b/Documentation/nvme-ns-rescan.1 index c8ba8876ca..4d62049b55 100644 --- a/Documentation/nvme-ns-rescan.1 +++ b/Documentation/nvme-ns-rescan.1 @@ -2,12 +2,12 @@ .\" Title: nvme-ns-rescan .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-NS\-RESCAN" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-NS\-RESCAN" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,14 +32,26 @@ nvme-ns-rescan \- Rescans the nvme namespaces\&. .SH "SYNOPSIS" .sp .nf -\fInvme ns\-rescan\fR +\fInvme ns\-rescan\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Requests NVMe controller rescans the namespaces\&. The param is mandatory and must be an NVMe character device (ex: /dev/nvme0)\&. .SH "OPTIONS" -.sp -None +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-ns-rescan.html b/Documentation/nvme-ns-rescan.html index b9af4b3e12..622dfbd3d9 100644 --- a/Documentation/nvme-ns-rescan.html +++ b/Documentation/nvme-ns-rescan.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme ns-rescan <device>
    +
    nvme ns-rescan <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -764,7 +764,31 @@

    DESCRIPTION

    OPTIONS

    -

    None

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

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

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

    + Increase the information detail in the output. +

    +
    +
    @@ -794,7 +818,7 @@

    NVME

    diff --git a/Documentation/nvme-ns-rescan.txt b/Documentation/nvme-ns-rescan.txt index cd41870a10..5681eabfbf 100644 --- a/Documentation/nvme-ns-rescan.txt +++ b/Documentation/nvme-ns-rescan.txt @@ -8,7 +8,7 @@ nvme-ns-rescan - Rescans the nvme namespaces. SYNOPSIS -------- [verse] -'nvme ns-rescan' +'nvme ns-rescan' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -17,7 +17,14 @@ be an NVMe character device (ex: /dev/nvme0). OPTIONS ------- -None +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-nvm-id-ctrl.1 b/Documentation/nvme-nvm-id-ctrl.1 index 0472c0e6e4..343724d6ab 100644 --- a/Documentation/nvme-nvm-id-ctrl.1 +++ b/Documentation/nvme-nvm-id-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-nvm-id-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-NVM\-ID\-CTRL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-NVM\-ID\-CTRL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-nvm-id-ctrl \- Send NVMe Identify Controller, return NVM command set struct .SH "SYNOPSIS" .sp .nf -\fInvme nvm\-id\-ctrl\fR [\-o | \-\-output\-format=] +\fInvme nvm\-id\-ctrl\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -43,13 +43,19 @@ The parameter is mandatory and may be either the NVMe character device On success, the data structure returned by the device will be decoded and displayed in one of several ways\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-nvm-id-ctrl.html b/Documentation/nvme-nvm-id-ctrl.html index ef1b59b600..4024a80a88 100644 --- a/Documentation/nvme-nvm-id-ctrl.html +++ b/Documentation/nvme-nvm-id-ctrl.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme nvm-id-ctrl <device> [-o <fmt> | --output-format=<fmt>]
    +
    nvme nvm-id-ctrl <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -770,15 +770,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -821,7 +832,7 @@

    NVME

    diff --git a/Documentation/nvme-nvm-id-ctrl.txt b/Documentation/nvme-nvm-id-ctrl.txt index fb4a23724b..eabc4b1f05 100644 --- a/Documentation/nvme-nvm-id-ctrl.txt +++ b/Documentation/nvme-nvm-id-ctrl.txt @@ -8,7 +8,7 @@ nvme-nvm-id-ctrl - Send NVMe Identify Controller, return NVM command set structu SYNOPSIS -------- [verse] -'nvme nvm-id-ctrl' [-o | --output-format=] +'nvme nvm-id-ctrl' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -23,10 +23,14 @@ displayed in one of several ways. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-nvm-id-ns-lba-format.txt b/Documentation/nvme-nvm-id-ns-lba-format.txt index 638e2fbad7..1048995ce3 100644 --- a/Documentation/nvme-nvm-id-ns-lba-format.txt +++ b/Documentation/nvme-nvm-id-ns-lba-format.txt @@ -11,8 +11,7 @@ SYNOPSIS [verse] 'nvme nvm-id-ns-lba-format' [--uuid-index= | -U ] [--lba-format-index= | -i ] - [-v | --verbose] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -37,15 +36,15 @@ OPTIONS This field specifies the index into the LBA Format list identifying the LBA Format capabilities that are to be returned +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + -v:: --verbose:: Increase the information detail in the output. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - EXAMPLES -------- * Has the program interpret the returned buffer and display the known diff --git a/Documentation/nvme-nvm-id-ns.txt b/Documentation/nvme-nvm-id-ns.txt index dfbbfaa29a..5a8cb09043 100644 --- a/Documentation/nvme-nvm-id-ns.txt +++ b/Documentation/nvme-nvm-id-ns.txt @@ -10,8 +10,7 @@ SYNOPSIS [verse] 'nvme nvm-id-ns' [--uuid-index= | -U ] [--namespace-id= | -n ] - [-v | --verbose] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -37,15 +36,15 @@ OPTIONS --uuid-index=:: UUID Index of the feature +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + -v:: --verbose:: Increase the information detail in the output. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - EXAMPLES -------- * Has the program interpret the returned buffer and display the known diff --git a/Documentation/nvme-nvme-mi-recv.1 b/Documentation/nvme-nvme-mi-recv.1 new file mode 100644 index 0000000000..789d620bf2 --- /dev/null +++ b/Documentation/nvme-nvme-mi-recv.1 @@ -0,0 +1,124 @@ +'\" t +.\" Title: nvme-nvme-mi-recv +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-NVME\-MI\-RECV" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-nvme-mi-recv \- Send a NVMe\-MI Receive command to the specified device +.SH "SYNOPSIS" +.sp +.nf +\fInvme nvme\-mi\-recv\fR [\-\-opcode= | \-O ] + [\-\-namespace\-id= | \-n ] + [\-\-data\-len= | \-l ] + [\-\-nmimt= | \-m ] + [\-\-nmd0= | \-0 ] [\-\-nmd1= | \-1 ] + [\-\-input\-file= | \-i ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] +.fi +.SH "DESCRIPTION" +.sp +Send a NVMe\-MI Receive command to the specified device, return results\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&. +.sp +On success it returns 0, error code otherwise\&. +.SH "OPTIONS" +.PP +\-O , \-\-opcode= +.RS 4 +The NVMe\-MI opcode to send to the device in the command +.RE +.PP +\-n , \-\-namespace\-id= +.RS 4 +The value for the ns\-id in the command\&. +.RE +.PP +\-l , \-\-data\-len= +.RS 4 +The data length for the buffer used for this command\&. +.RE +.PP +\-m , \-\-nmimt= +.RS 4 +The value for the NVMe\-MI message type in the command\&. +.RE +.PP +\-0 , \-\-nmd0= +.RS 4 +The value for the NVMe management request dword 0 in the command\&. +.RE +.PP +\-1 , \-\-nmd1= +.RS 4 +The value for the NVMe management request dword 1 in the command\&. +.RE +.PP +\-i , \-\-input\-file= +.RS 4 +If the command is a data\-out (write) command, use this file to fill the buffer sent to the device\&. If no file is given, assumed to use STDIN\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Has the program issue a nvme\-mi\-recv to execute the VPD read\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme nvme\-mi\-recv /dev/nvme0n1 \-O 5 \-m 1 \-0 0 \-1 0x100 \-l 256 +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite\&. diff --git a/Documentation/nvme-nvme-mi-recv.html b/Documentation/nvme-nvme-mi-recv.html new file mode 100644 index 0000000000..758e4fc5dc --- /dev/null +++ b/Documentation/nvme-nvme-mi-recv.html @@ -0,0 +1,912 @@ + + + + + + +nvme-nvme-mi-recv(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme nvme-mi-recv <device> [--opcode=<opcode> | -O <opcode>]
    +                        [--namespace-id=<nsid> | -n <nsid>]
    +                        [--data-len=<data-len> | -l <data-len>]
    +                        [--nmimt=<nmimt> | -m <nmimt>]
    +                        [--nmd0=<nmd0> | -0 <nmd0>] [--nmd1=<nmd1> | -1 <nmd1>]
    +                        [--input-file=<file> | -i <file>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Send a NVMe-MI Receive command to the specified device, return results.

    +

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

    +

    On success it returns 0, error code otherwise.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-O <opcode> +
    +
    +--opcode=<opcode> +
    +
    +

    + The NVMe-MI opcode to send to the device in the command +

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

    + The value for the ns-id in the command. +

    +
    +
    +-l <data-len> +
    +
    +--data-len=<data-len> +
    +
    +

    + The data length for the buffer used for this command. +

    +
    +
    +-m <nmimt> +
    +
    +--nmimt=<nmimt> +
    +
    +

    + The value for the NVMe-MI message type in the command. +

    +
    +
    +-0 <nmd0> +
    +
    +--nmd0=<nmd0> +
    +
    +

    + The value for the NVMe management request dword 0 in the command. +

    +
    +
    +-1 <nmd1> +
    +
    +--nmd1=<nmd1> +
    +
    +

    + The value for the NVMe management request dword 1 in the command. +

    +
    +
    +-i <file> +
    +
    +--input-file=<file> +
    +
    +

    + If the command is a data-out (write) command, use this file + to fill the buffer sent to the device. If no file is given, + assumed to use STDIN. +

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

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

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

    + Increase the information detail in the output. +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Has the program issue a nvme-mi-recv to execute the VPD read. +

      +
      +
      +
      # nvme nvme-mi-recv /dev/nvme0n1 -O 5 -m 1 -0 0 -1 0x100 -l 256
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite.

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-nvme-mi-recv.txt b/Documentation/nvme-nvme-mi-recv.txt new file mode 100644 index 0000000000..152bbe67c0 --- /dev/null +++ b/Documentation/nvme-nvme-mi-recv.txt @@ -0,0 +1,79 @@ +nvme-nvme-mi-recv(1) +==================== + +NAME +---- +nvme-nvme-mi-recv - Send a NVMe-MI Receive command to the specified device + +SYNOPSIS +-------- +[verse] +'nvme nvme-mi-recv' [--opcode= | -O ] + [--namespace-id= | -n ] + [--data-len= | -l ] + [--nmimt= | -m ] + [--nmd0= | -0 ] [--nmd1= | -1 ] + [--input-file= | -i ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Send a NVMe-MI Receive command to the specified device, return results. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-O :: +--opcode=:: + The NVMe-MI opcode to send to the device in the command + +-n :: +--namespace-id=:: + The value for the ns-id in the command. + +-l :: +--data-len=:: + The data length for the buffer used for this command. + +-m :: +--nmimt=:: + The value for the NVMe-MI message type in the command. + +-0 :: +--nmd0=:: + The value for the NVMe management request dword 0 in the command. + +-1 :: +--nmd1=:: + The value for the NVMe management request dword 1 in the command. + +-i :: +--input-file=:: + If the command is a data-out (write) command, use this file + to fill the buffer sent to the device. If no file is given, + assumed to use STDIN. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Has the program issue a nvme-mi-recv to execute the VPD read. ++ +------------ +# nvme nvme-mi-recv /dev/nvme0n1 -O 5 -m 1 -0 0 -1 0x100 -l 256 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-nvme-mi-send.1 b/Documentation/nvme-nvme-mi-send.1 new file mode 100644 index 0000000000..31317d8497 --- /dev/null +++ b/Documentation/nvme-nvme-mi-send.1 @@ -0,0 +1,124 @@ +'\" t +.\" Title: nvme-nvme-mi-send +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-NVME\-MI\-SEND" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-nvme-mi-send \- Send a NVMe\-MI Send command to the specified device +.SH "SYNOPSIS" +.sp +.nf +\fInvme nvme\-mi\-send\fR [\-\-opcode= | \-O ] + [\-\-namespace\-id= | \-n ] + [\-\-data\-len= | \-l ] + [\-\-nmimt= | \-m ] + [\-\-nmd0= | \-0 ] [\-\-nmd1= | \-1 ] + [\-\-input\-file= | \-i ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] +.fi +.SH "DESCRIPTION" +.sp +Send a NVMe\-MI Send command to the specified device, return results\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&. +.sp +On success it returns 0, error code otherwise\&. +.SH "OPTIONS" +.PP +\-O , \-\-opcode= +.RS 4 +The NVMe\-MI opcode to send to the device in the command +.RE +.PP +\-n , \-\-namespace\-id= +.RS 4 +The value for the ns\-id in the command\&. +.RE +.PP +\-l , \-\-data\-len= +.RS 4 +The data length for the buffer used for this command\&. +.RE +.PP +\-m , \-\-nmimt= +.RS 4 +The value for the NVMe\-MI message type in the command\&. +.RE +.PP +\-0 , \-\-nmd0= +.RS 4 +The value for the NVMe management request dword 0 in the command\&. +.RE +.PP +\-1 , \-\-nmd1= +.RS 4 +The value for the NVMe management request dword 1 in the command\&. +.RE +.PP +\-i , \-\-input\-file= +.RS 4 +If the command is a data\-out (write) command, use this file to fill the buffer sent to the device\&. If no file is given, assumed to use STDIN\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Has the program issue a nvme\-mi\-send to execute the VPD write\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme nvme\-mi\-send /dev/nvme0n1 \-O 6 \-m 1 \-0 0 \-1 0x100 \-l 256 \-i vpd\&.bin +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite\&. diff --git a/Documentation/nvme-nvme-mi-send.html b/Documentation/nvme-nvme-mi-send.html new file mode 100644 index 0000000000..85aef3a969 --- /dev/null +++ b/Documentation/nvme-nvme-mi-send.html @@ -0,0 +1,912 @@ + + + + + + +nvme-nvme-mi-send(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme nvme-mi-send <device> [--opcode=<opcode> | -O <opcode>]
    +                        [--namespace-id=<nsid> | -n <nsid>]
    +                        [--data-len=<data-len> | -l <data-len>]
    +                        [--nmimt=<nmimt> | -m <nmimt>]
    +                        [--nmd0=<nmd0> | -0 <nmd0>] [--nmd1=<nmd1> | -1 <nmd1>]
    +                        [--input-file=<file> | -i <file>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Send a NVMe-MI Send command to the specified device, return results.

    +

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

    +

    On success it returns 0, error code otherwise.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-O <opcode> +
    +
    +--opcode=<opcode> +
    +
    +

    + The NVMe-MI opcode to send to the device in the command +

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

    + The value for the ns-id in the command. +

    +
    +
    +-l <data-len> +
    +
    +--data-len=<data-len> +
    +
    +

    + The data length for the buffer used for this command. +

    +
    +
    +-m <nmimt> +
    +
    +--nmimt=<nmimt> +
    +
    +

    + The value for the NVMe-MI message type in the command. +

    +
    +
    +-0 <nmd0> +
    +
    +--nmd0=<nmd0> +
    +
    +

    + The value for the NVMe management request dword 0 in the command. +

    +
    +
    +-1 <nmd1> +
    +
    +--nmd1=<nmd1> +
    +
    +

    + The value for the NVMe management request dword 1 in the command. +

    +
    +
    +-i <file> +
    +
    +--input-file=<file> +
    +
    +

    + If the command is a data-out (write) command, use this file + to fill the buffer sent to the device. If no file is given, + assumed to use STDIN. +

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

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

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

    + Increase the information detail in the output. +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Has the program issue a nvme-mi-send to execute the VPD write. +

      +
      +
      +
      # nvme nvme-mi-send /dev/nvme0n1 -O 6 -m 1 -0 0 -1 0x100 -l 256 -i vpd.bin
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite.

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-nvme-mi-send.txt b/Documentation/nvme-nvme-mi-send.txt new file mode 100644 index 0000000000..0e80fe7a02 --- /dev/null +++ b/Documentation/nvme-nvme-mi-send.txt @@ -0,0 +1,79 @@ +nvme-nvme-mi-send(1) +==================== + +NAME +---- +nvme-nvme-mi-send - Send a NVMe-MI Send command to the specified device + +SYNOPSIS +-------- +[verse] +'nvme nvme-mi-send' [--opcode= | -O ] + [--namespace-id= | -n ] + [--data-len= | -l ] + [--nmimt= | -m ] + [--nmd0= | -0 ] [--nmd1= | -1 ] + [--input-file= | -i ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Send a NVMe-MI Send command to the specified device, return results. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-O :: +--opcode=:: + The NVMe-MI opcode to send to the device in the command + +-n :: +--namespace-id=:: + The value for the ns-id in the command. + +-l :: +--data-len=:: + The data length for the buffer used for this command. + +-m :: +--nmimt=:: + The value for the NVMe-MI message type in the command. + +-0 :: +--nmd0=:: + The value for the NVMe management request dword 0 in the command. + +-1 :: +--nmd1=:: + The value for the NVMe management request dword 1 in the command. + +-i :: +--input-file=:: + If the command is a data-out (write) command, use this file + to fill the buffer sent to the device. If no file is given, + assumed to use STDIN. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Has the program issue a nvme-mi-send to execute the VPD write. ++ +------------ +# nvme nvme-mi-send /dev/nvme0n1 -O 6 -m 1 -0 0 -1 0x100 -l 256 -i vpd.bin +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-clear-fw-activate-history.1 b/Documentation/nvme-ocp-clear-fw-activate-history.1 new file mode 100644 index 0000000000..29e9e956d5 --- /dev/null +++ b/Documentation/nvme-ocp-clear-fw-activate-history.1 @@ -0,0 +1,78 @@ +'\" t +.\" Title: nvme-ocp-clear-fw-activate-history +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-OCP\-CLEAR\-FW" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-ocp-clear-fw-activate-history \- Clear the OCP Firmware Update History Log +.SH "SYNOPSIS" +.sp +.nf +\fInvme ocp clear\-fw\-activate\-history\fR [\-\-no\-uuid | \-n] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, Clear OCP Firmware Update History Log\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&. +.sp +This command with no option added, will try to automatically detect the parameters of the command\&. This will work successfully or fail gracefully for devices supporting UUID for Vendor Specific Information (NVMe 1\&.4 or later, OCP 2\&.0 requires NVMe 1\&.4b)\&. For devices that do not support OCP 2\&.0 the command will fail gracefully, unless the \-\-no\-uuid option is provided\&. +.sp +For OCP 1\&.0 devices (before NVMe 1\&.4) the \-\-no\-uuid option is required\&. When \-\-no\-uuid option is provided, results for devices before NVMe 1\&.4 without OCP support are undefined\&. +.sp +On success it returns 0, error code otherwise\&. +.SH "OPTIONS" +.PP +\-n, \-\-no\-uuid +.RS 4 +Do not try to automatically detect UUID index for this command (required for old OCP 1\&.0 support) +.RE +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Clears OCP Firmware Activation History Log for the device: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme ocp clear\-fw\-activate\-history /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite\&. diff --git a/Documentation/nvme-ocp-clear-fw-activate-history.html b/Documentation/nvme-ocp-clear-fw-activate-history.html new file mode 100644 index 0000000000..a2035db4d4 --- /dev/null +++ b/Documentation/nvme-ocp-clear-fw-activate-history.html @@ -0,0 +1,824 @@ + + + + + + +nvme-ocp-clear-fw-activate-history(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme ocp clear-fw-activate-history <device> [--no-uuid | -n]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, Clear OCP Firmware Update History Log.

    +

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

    +

    This command with no option added, will try to automatically detect the +parameters of the command. This will work successfully or fail gracefully for +devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later, +OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the +command will fail gracefully, unless the --no-uuid option is provided.

    +

    For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required. +When --no-uuid option is provided, results for devices before NVMe 1.4 without +OCP support are undefined.

    +

    On success it returns 0, error code otherwise.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-n +
    +
    +--no-uuid +
    +
    +

    + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Clears OCP Firmware Activation History Log for the device: +

      +
      +
      +
      # nvme ocp clear-fw-activate-history /dev/nvme0
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite.

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-ocp-clear-fw-activate-history.txt b/Documentation/nvme-ocp-clear-fw-activate-history.txt new file mode 100644 index 0000000000..335a2288fd --- /dev/null +++ b/Documentation/nvme-ocp-clear-fw-activate-history.txt @@ -0,0 +1,49 @@ +nvme-ocp-clear-fw-activate-history(1) +===================================== + +NAME +---- +nvme-ocp-clear-fw-activate-history - Clear the OCP Firmware Update History Log + +SYNOPSIS +-------- +[verse] +'nvme ocp clear-fw-activate-history' [--no-uuid | -n] + +DESCRIPTION +----------- +For the NVMe device given, Clear OCP Firmware Update History Log. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This command with no option added, will try to automatically detect the +parameters of the command. This will work successfully or fail gracefully for +devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later, +OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the +command will fail gracefully, unless the --no-uuid option is provided. + +For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required. +When --no-uuid option is provided, results for devices before NVMe 1.4 without +OCP support are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-n:: +--no-uuid:: + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) + +EXAMPLES +-------- +* Clears OCP Firmware Activation History Log for the device: ++ +------------ +# nvme ocp clear-fw-activate-history /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. \ No newline at end of file diff --git a/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.1 b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.1 new file mode 100644 index 0000000000..9652db546a --- /dev/null +++ b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.1 @@ -0,0 +1,78 @@ +'\" t +.\" Title: nvme-ocp-clear-pcie-correctable-error-counters +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-OCP\-CLEAR\-PC" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-ocp-clear-pcie-correctable-error-counters \- Clear PCIe correctable error counters +.SH "SYNOPSIS" +.sp +.nf +\fInvme ocp clear\-pcie\-correctable\-error\-counters\fR [\-\-no\-uuid | \-n] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, Clear PCIe correctable error counters\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&. +.sp +This command with no option added, will try to automatically detect the parameters of the command\&. This will work successfully or fail gracefully for devices supporting UUID for Vendor Specific Information (NVMe 1\&.4 or later, OCP 2\&.0 requires NVMe 1\&.4b)\&. For devices that do not support OCP 2\&.0 the command will fail gracefully, unless the \-\-no\-uuid option is provided\&. +.sp +For OCP 1\&.0 devices (before NVMe 1\&.4) the \-\-no\-uuid option is required\&. When \-\-no\-uuid option is provided, results for devices before NVMe 1\&.4 without OCP support are undefined\&. +.sp +On success it returns 0, error code otherwise\&. +.SH "OPTIONS" +.PP +\-n, \-\-no\-uuid +.RS 4 +Do not try to automatically detect UUID index for this command (required for old OCP 1\&.0 support) +.RE +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Clears PCIe correctable error counters Log for the device: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme ocp clear\-pcie\-correctable\-error\-counters /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite\&. diff --git a/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html new file mode 100644 index 0000000000..c05eb8d513 --- /dev/null +++ b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html @@ -0,0 +1,824 @@ + + + + + + +nvme-ocp-clear-pcie-correctable-error-counters(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme ocp clear-pcie-correctable-error-counters <device> [--no-uuid | -n]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, Clear PCIe correctable error counters.

    +

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

    +

    This command with no option added, will try to automatically detect the +parameters of the command. This will work successfully or fail gracefully for +devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later, +OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the +command will fail gracefully, unless the --no-uuid option is provided.

    +

    For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required. +When --no-uuid option is provided, results for devices before NVMe 1.4 without +OCP support are undefined.

    +

    On success it returns 0, error code otherwise.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-n +
    +
    +--no-uuid +
    +
    +

    + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Clears PCIe correctable error counters Log for the device: +

      +
      +
      +
      # nvme ocp clear-pcie-correctable-error-counters /dev/nvme0
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite.

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt new file mode 100644 index 0000000000..3d5706d908 --- /dev/null +++ b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt @@ -0,0 +1,49 @@ +nvme-ocp-clear-pcie-correctable-error-counters(1) +================================================= + +NAME +---- +nvme-ocp-clear-pcie-correctable-error-counters - Clear PCIe correctable error counters + +SYNOPSIS +-------- +[verse] +'nvme ocp clear-pcie-correctable-error-counters' [--no-uuid | -n] + +DESCRIPTION +----------- +For the NVMe device given, Clear PCIe correctable error counters. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This command with no option added, will try to automatically detect the +parameters of the command. This will work successfully or fail gracefully for +devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later, +OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the +command will fail gracefully, unless the --no-uuid option is provided. + +For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required. +When --no-uuid option is provided, results for devices before NVMe 1.4 without +OCP support are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-n:: +--no-uuid:: + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) + +EXAMPLES +-------- +* Clears PCIe correctable error counters Log for the device: ++ +------------ +# nvme ocp clear-pcie-correctable-error-counters /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-device-capability-log.txt b/Documentation/nvme-ocp-device-capability-log.txt new file mode 100644 index 0000000000..d2f07613ec --- /dev/null +++ b/Documentation/nvme-ocp-device-capability-log.txt @@ -0,0 +1,42 @@ +nvme-ocp-device-capability-log(1) +================================= + +NAME +---- +nvme-ocp-device-capability-log - Retrieves OCP Device Capability Log Page + +SYNOPSIS +-------- +[verse] +'nvme ocp device-capability-log' [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, retrieves OCP Device Capability Log Page + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-o :: +--output-format=:: + Set the reporting format to 'normal' or 'json' or 'binary'. + Only one output format can be used at a time. The default is normal. + +EXAMPLES +-------- +* Has the program issue a device-capability-log command to retrieve the 0xC4 log page. ++ +------------ +# nvme ocp device-capability-log /dev/nvme0 -o normal +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-eol-plp-failure-mode.1 b/Documentation/nvme-ocp-eol-plp-failure-mode.1 new file mode 100644 index 0000000000..dbefc04503 --- /dev/null +++ b/Documentation/nvme-ocp-eol-plp-failure-mode.1 @@ -0,0 +1,137 @@ +'\" t +.\" Title: nvme-ocp-eol-plp-failure-mode +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-OCP\-EOL\-PLP\" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-ocp-eol-plp-failure-mode \- Define and print EOL or PLP circuitry failure mode +.SH "SYNOPSIS" +.sp +.nf +\fInvme ocp eol\-plp\-failure\-mode\fR [\-\-mode= | \-m ] + [\-\-no\-uuid | \-n] [\-\-save | \-s] + [\-\-sel=] +.fi +.SH "DESCRIPTION" +.sp +Define EOL or PLP circuitry failure mode\&. No argument prints current mode\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&. +.sp +This will only work on OCP compliant devices supporting this feature\&. Results for any other device are undefined\&. +.sp +On success it returns 0, error code otherwise\&. +.SH "OPTIONS" +.PP +\-m , \-\-mode= +.RS 4 +Set the EOL or PLP circuitry failure mode to [0\-3] (\fI0: default\fR, +\fI1: rom\fR, +\fI2: wtm\fR +or +\fI3: normal\fR)\&. Only one mode can be used at a time\&. The default is rom\&. +.RE +.PP +\-n, \-\-no\-uuid +.RS 4 +Do not try to automatically detect UUID index for this command (required for old OCP 1\&.0 support) +.RE +.PP +\-s, \-\-save +.RS 4 +Save the attribute so that it persists through all power states and resets\&. +.RE +.PP +\-s +.RS 4 +Select (SEL): This field specifies which value of the attributes to return in the provided data: +.TS +allbox tab(:); +lt lt +lt lt +lt lt +lt lt +lt lt +lt lt. +T{ +Select +T}:T{ +Description +T} +T{ +0 +T}:T{ +Current +T} +T{ +1 +T}:T{ +Default +T} +T{ +2 +T}:T{ +Saved +T} +T{ +3 +T}:T{ +Supported capabilities +T} +T{ +4\-7 +T}:T{ +Reserved +T} +.TE +.sp 1 +.RE +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Has the program issue a eol\-plp\-failure\-mode to retrieve the 0xC2 get features\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme ocp eol\-plp\-failure\-mode /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite\&. diff --git a/Documentation/nvme-ocp-eol-plp-failure-mode.html b/Documentation/nvme-ocp-eol-plp-failure-mode.html new file mode 100644 index 0000000000..ce22f5ffb8 --- /dev/null +++ b/Documentation/nvme-ocp-eol-plp-failure-mode.html @@ -0,0 +1,893 @@ + + + + + + +nvme-ocp-eol-plp-failure-mode(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme ocp eol-plp-failure-mode <device> [--mode=<mode> | -m <mode>]
    +                        [--no-uuid | -n] [--save | -s]
    +                        [--sel=<select> | -s <select>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Define EOL or PLP circuitry failure mode. +No argument prints current mode.

    +

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

    +

    This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined.

    +

    On success it returns 0, error code otherwise.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-m <mode> +
    +
    +--mode=<mode> +
    +
    +

    + Set the EOL or PLP circuitry failure mode to [0-3] (0: default, + 1: rom, 2: wtm or 3: normal). Only one mode + can be used at a time. The default is rom. +

    +
    +
    +-n +
    +
    +--no-uuid +
    +
    +

    + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) +

    +
    +
    +-s +
    +
    +--save +
    +
    +

    + Save the attribute so that it persists through all power states and + resets. +

    +
    +
    +-s <select> +
    +
    +--sel=<select> +
    +
    +

    + Select (SEL): This field specifies which value of the attributes + to return in the provided data: +

    +
    +

    Supported capabilities

    4–7

    4-7

    Reserved

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

    Select

    Description

    0

    Current

    1

    Default

    2

    Saved

    3

    Supported capabilities

    4-7

    Reserved

    +
    +
    + + + +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Has the program issue a eol-plp-failure-mode to retrieve the 0xC2 get features. +

      +
      +
      +
      # nvme ocp eol-plp-failure-mode /dev/nvme0
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite.

    +
    +
    + +

    + + + diff --git a/Documentation/nvme-ocp-eol-plp-failure-mode.txt b/Documentation/nvme-ocp-eol-plp-failure-mode.txt new file mode 100644 index 0000000000..0ebc4ab7fb --- /dev/null +++ b/Documentation/nvme-ocp-eol-plp-failure-mode.txt @@ -0,0 +1,72 @@ +nvme-ocp-eol-plp-failure-mode(1) +================================ + +NAME +---- +nvme-ocp-eol-plp-failure-mode - Define and print EOL or PLP circuitry failure +mode + +SYNOPSIS +-------- +[verse] +'nvme ocp eol-plp-failure-mode' [--mode= | -m ] + [--no-uuid | -n] [--save | -s] + [--sel=] + +DESCRIPTION +----------- +Define EOL or PLP circuitry failure mode. +No argument prints current mode. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-m :: +--mode=:: + Set the EOL or PLP circuitry failure mode to [0-3] ('0: default', + '1: rom', '2: wtm' or '3: normal'). Only one mode + can be used at a time. The default is rom. + +-n:: +--no-uuid:: + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) + +-s:: +--save:: + Save the attribute so that it persists through all power states and + resets. + +-s :: + Select (SEL): This field specifies which value of the attributes + to return in the provided data: ++ +[] +|================== +|Select|Description +|0|Current +|1|Default +|2|Saved +|3|Supported capabilities +|4-7|Reserved +|================== + +EXAMPLES +-------- +* Has the program issue a eol-plp-failure-mode to retrieve the 0xC2 get features. ++ +------------ +# nvme ocp eol-plp-failure-mode /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-error-recovery-log.txt b/Documentation/nvme-ocp-error-recovery-log.txt new file mode 100644 index 0000000000..7a261503dc --- /dev/null +++ b/Documentation/nvme-ocp-error-recovery-log.txt @@ -0,0 +1,42 @@ +nvme-ocp-error-recovery-log(1) +============================== + +NAME +---- +nvme-ocp-error-recovery-log - Retrieves OCP Error Recovery Log Page + +SYNOPSIS +-------- +[verse] +'nvme ocp error-recovery-log' [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, retrieves OCP Error Recovery Log Page + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-o :: +--output-format=:: + Set the reporting format to 'normal' or 'json' or 'binary'. + Only one output format can be used at a time. The default is normal. + +EXAMPLES +-------- +* Has the program issue a error-recovery-log command to retrieve the 0xC1 log page. ++ +------------ +# nvme ocp error-recovery-log /dev/nvme0 -o normal +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-get-plp-health-check-interval.txt b/Documentation/nvme-ocp-get-plp-health-check-interval.txt new file mode 100644 index 0000000000..7ecd5d507b --- /dev/null +++ b/Documentation/nvme-ocp-get-plp-health-check-interval.txt @@ -0,0 +1,54 @@ +nvme-ocp-get-plp-health-check-interval(1) +================================ + +NAME +---- +nvme-ocp-get-plp-health-check-interval - Define and print plp-health-check-interval value + +SYNOPSIS +-------- +[verse] +'nvme ocp get-plp-health-check-interval' [--sel=] + +DESCRIPTION +----------- +Define plp-health-check-interval. +No argument prints current mode. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- + +-s :: + Select (SEL): This field specifies which value of the attributes + to return in the provided data: ++ +[] +|================== +|Select|Description +|0|Current +|1|Default +|2|Saved +|3|Supported capabilities +|4-7|Reserved +|================== + +EXAMPLES +-------- +* Has the program issue a get-plp-health-check-interval to retrieve the 0xC6 get features. ++ +------------ +# nvme ocp get-plp-health-check-interval /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-latency-monitor-log.1 b/Documentation/nvme-ocp-latency-monitor-log.1 index c5a29636bf..7fa607e82b 100644 --- a/Documentation/nvme-ocp-latency-monitor-log.1 +++ b/Documentation/nvme-ocp-latency-monitor-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-ocp-latency-monitor-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-OCP\-LATENCY\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-OCP\-LATENCY\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -45,7 +45,7 @@ This will only work on OCP compliant devices supporting this log page\&. Results On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR diff --git a/Documentation/nvme-ocp-latency-monitor-log.html b/Documentation/nvme-ocp-latency-monitor-log.html index 8e3ec2a609..a6cae12385 100644 --- a/Documentation/nvme-ocp-latency-monitor-log.html +++ b/Documentation/nvme-ocp-latency-monitor-log.html @@ -770,10 +770,10 @@

    OPTIONS

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

    @@ -811,7 +811,7 @@

    NVME

    diff --git a/Documentation/nvme-ocp-latency-monitor-log.txt b/Documentation/nvme-ocp-latency-monitor-log.txt index 66f760c5cf..a67c52378f 100644 --- a/Documentation/nvme-ocp-latency-monitor-log.txt +++ b/Documentation/nvme-ocp-latency-monitor-log.txt @@ -26,8 +26,8 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal' or 'json'. Only one output format can be used at a time. The default is normal. diff --git a/Documentation/nvme-ocp-set-dssd-power-state-feature.txt b/Documentation/nvme-ocp-set-dssd-power-state-feature.txt new file mode 100644 index 0000000000..c9ae578333 --- /dev/null +++ b/Documentation/nvme-ocp-set-dssd-power-state-feature.txt @@ -0,0 +1,43 @@ +set-dssd-power-state-feature(1) +=============================== + +NAME +---- +nvme-ocp-set-dssd-power-state-feature - Set DSSD Power State + +SYNOPSIS +-------- +[verse] +'nvme ocp set-dssd-power-state-feature' + [--power-state= | -p ] [--no-uuid | -n] + [--save | -s] + +DESCRIPTION +----------- +For the NVMe device given, retrieves OCP DSSD Power state Feature + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-p :: +--power-state=:: + DSSD Power State to set in watts. + +EXAMPLES +-------- +* Has the program issue a set-dssd-power-state-feature command to set DSSD Power State to set in watts. ++ +------------ +# nvme ocp set-dssd-power-state-feature /dev/nvme0 -p -s -n +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-set-plp-health-check-interval.txt b/Documentation/nvme-ocp-set-plp-health-check-interval.txt new file mode 100644 index 0000000000..ac3acb322e --- /dev/null +++ b/Documentation/nvme-ocp-set-plp-health-check-interval.txt @@ -0,0 +1,53 @@ +nvme-ocp-set-plp-health-check-interval(1) +================================ + +NAME +---- +nvme-ocp-set-plp-health-check-interval - Define and set PLP health check interval + +SYNOPSIS +-------- +[verse] +'nvme ocp set-plp-health-check-interval' [--plp_health_interval= | -p ] [--save | -s] [--no-uuid | -n] + + +DESCRIPTION +----------- +Define Set PLP health check interval. +No argument prints current mode. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-p :: +--plp_health_interval=:: + Set the plp health check interval [31:16] + +-n:: +--no-uuid:: + Do not try to automatically detect UUID index for this command (required + for old OCP 1.0 support) + +-s:: +--save:: + Save the attribute so that it persists through all power states and resets. + + +EXAMPLES +-------- +* Has the program issue a set-plp-health-check-interval to retrieve the 0xC6 set features. ++ +------------ +# nvme ocp eol-plp-failure-mode /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-smart-add-log.1 b/Documentation/nvme-ocp-smart-add-log.1 index f5c2fc44b0..092321e2fe 100644 --- a/Documentation/nvme-ocp-smart-add-log.1 +++ b/Documentation/nvme-ocp-smart-add-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-ocp-smart-add-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-OCP\-SMART\-AD" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-OCP\-SMART\-AD" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -45,7 +45,7 @@ This will only work on OCP compliant devices supporting this feature\&. Results On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR diff --git a/Documentation/nvme-ocp-smart-add-log.html b/Documentation/nvme-ocp-smart-add-log.html index 8fd92d63a5..fa10b956a3 100644 --- a/Documentation/nvme-ocp-smart-add-log.html +++ b/Documentation/nvme-ocp-smart-add-log.html @@ -771,10 +771,10 @@

    OPTIONS

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

    @@ -812,7 +812,7 @@

    NVME

    diff --git a/Documentation/nvme-ocp-smart-add-log.txt b/Documentation/nvme-ocp-smart-add-log.txt index 3a2582274b..66a55a90ec 100644 --- a/Documentation/nvme-ocp-smart-add-log.txt +++ b/Documentation/nvme-ocp-smart-add-log.txt @@ -26,8 +26,8 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal' or 'json'. Only one output format can be used at a time. The default is normal. diff --git a/Documentation/nvme-ocp-telemetry-string-log-page.txt b/Documentation/nvme-ocp-telemetry-string-log-page.txt new file mode 100644 index 0000000000..76349ed797 --- /dev/null +++ b/Documentation/nvme-ocp-telemetry-string-log-page.txt @@ -0,0 +1,43 @@ +nvme-ocp-telemetry-string-log-page(1) +===================================== + +NAME +---- +nvme-ocp-telemetry-string-log-page - Retrieve OCP Telemetry String Log page + +SYNOPSIS +-------- +[verse] +'nvme ocp telemetry-str-log' [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, Retrieve OCP Telemetry String Log page + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-o :: +--output-format=:: + This option will set the reporting format to normal, json, or binary. + Only one output format can be used at a time. + + +EXAMPLES +-------- +* Has the program issue a telemetry-string-log command to get the log page data from bin file. ++ +------------ +# nvme ocp telemetry-string-log /dev/nvme0n1 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-ocp-unsupported-reqs-log-pages.txt b/Documentation/nvme-ocp-unsupported-reqs-log-pages.txt new file mode 100644 index 0000000000..1657f6aa24 --- /dev/null +++ b/Documentation/nvme-ocp-unsupported-reqs-log-pages.txt @@ -0,0 +1,45 @@ +unsupported-reqs-log +==================== + +NAME +---- +unsupported-reqs-log - Retrieves unsupported requirements log page of given OCP +compliant device + +SYNOPSIS +-------- +[verse] +'nvme ocp unsupported-reqs-log' [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, send a unsupported-reqs-log command and +provide the unsupported requirements log page. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +This will only work on OCP compliant devices supporting this feature. +Results for any other device are undefined. + +On success it returns 0, error code otherwise. + +OPTIONS +------- + +-o :: +--output-format=:: + This option will set the reporting format to normal, json, or binary. + Only one output format can be used at a time. + +EXAMPLES +-------- +* Has the program issue a unsupported-reqs-log command to retrieve the 0xC5 log page. ++ +------------ +# nvme ocp unsupported-reqs-log /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite \ No newline at end of file diff --git a/Documentation/nvme-persistent-event-log.1 b/Documentation/nvme-persistent-event-log.1 index 94f145bbf1..4781586439 100644 --- a/Documentation/nvme-persistent-event-log.1 +++ b/Documentation/nvme-persistent-event-log.1 @@ -2,12 +2,12 @@ .\" Title: persistent-event-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "PERSISTENT\-EVENT\-L" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "PERSISTENT\-EVENT\-L" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,9 +33,8 @@ nvme-persistent-event-log \- Send NVMe persistent event log page request, return .sp .nf \fInvme persistent\-event\-log\fR [\-\-action= | \-a ] - [\-\-log\-len= | \-l ] - [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-log\-len= | \-l ] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -61,13 +60,19 @@ Allocates a buffer of bytes size and requests this many bytes be retu Print the raw persistent event log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-persistent-event-log.html b/Documentation/nvme-persistent-event-log.html index a89cca4cec..f4998f49b8 100644 --- a/Documentation/nvme-persistent-event-log.html +++ b/Documentation/nvme-persistent-event-log.html @@ -750,9 +750,8 @@

    SYNOPSIS

    nvme persistent-event-log <device> [--action=<action> | -a <action>]
    -            [--log-len=<log-len> | -l <log-len>]
    -            [--raw-binary | -b]
    -            [--output-format=<fmt> | -o <fmt>]
    + [--log-len=<log-len> | -l <log-len>] [--raw-binary | -b] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -782,12 +781,12 @@

    OPTIONS

    - While try to retrieve this log action the controller shall take - during processing this persistent log page command. This mandatory - field, based on the value issued it may Read Log Data, Establish - Context and Read Log Data or Release Context can occur. For More - details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent - Event Log (Log Identifier 0Dh) + While try to retrieve this log action the controller shall take + during processing this persistent log page command. This mandatory + field, based on the value issued it may Read Log Data, Establish + Context and Read Log Data or Release Context can occur. For More + details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent + Event Log (Log Identifier 0Dh)

    @@ -798,10 +797,10 @@

    OPTIONS

    - Allocates a buffer of <log-len> bytes size and requests this - many bytes be returned in the constructed NVMe command. This - param is mandatory. If <log-len> given is 0 and action is 0, - it will read the Total Log Length(TLL) of the page. + Allocates a buffer of <log-len> bytes size and requests this + many bytes be returned in the constructed NVMe command. This + param is mandatory. If <log-len> given is 0 and action is 0, + it will read the Total Log Length(TLL) of the page.

    @@ -812,19 +811,30 @@

    OPTIONS

    - Print the raw persistent event log buffer to stdout. + Print the raw persistent event log buffer to stdout.

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

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

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

    + Increase the information detail in the output.

    @@ -867,7 +877,7 @@

    NVME

    diff --git a/Documentation/nvme-persistent-event-log.txt b/Documentation/nvme-persistent-event-log.txt index 833491f45a..cf1cbad1b2 100644 --- a/Documentation/nvme-persistent-event-log.txt +++ b/Documentation/nvme-persistent-event-log.txt @@ -10,9 +10,8 @@ SYNOPSIS -------- [verse] 'nvme persistent-event-log' [--action= | -a ] - [--log-len= | -l ] - [--raw-binary | -b] - [--output-format= | -o ] + [--log-len= | -l ] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -31,28 +30,32 @@ OPTIONS ------- -a :: --action=:: - While try to retrieve this log action the controller shall take - during processing this persistent log page command. This mandatory - field, based on the value issued it may Read Log Data, Establish - Context and Read Log Data or Release Context can occur. For More - details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent - Event Log (Log Identifier 0Dh) + While try to retrieve this log action the controller shall take + during processing this persistent log page command. This mandatory + field, based on the value issued it may Read Log Data, Establish + Context and Read Log Data or Release Context can occur. For More + details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent + Event Log (Log Identifier 0Dh) -l :: --log-len=:: - Allocates a buffer of bytes size and requests this - many bytes be returned in the constructed NVMe command. This - param is mandatory. If given is 0 and action is 0, - it will read the Total Log Length(TLL) of the page. + Allocates a buffer of bytes size and requests this + many bytes be returned in the constructed NVMe command. This + param is mandatory. If given is 0 and action is 0, + it will read the Total Log Length(TLL) of the page. -b:: --raw-binary:: - Print the raw persistent event log buffer to stdout. + Print the raw persistent event log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or 'binary'. - Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-phy-rx-eom-log.txt b/Documentation/nvme-phy-rx-eom-log.txt new file mode 100644 index 0000000000..8a311313a3 --- /dev/null +++ b/Documentation/nvme-phy-rx-eom-log.txt @@ -0,0 +1,68 @@ +nvme-phy-rx-eom-log(1) +====================== + +NAME +---- +nvme-phy-rx-eom-log - Retrieves a Physical Interface Receiver Eye Opening +Measurement log page from an NVMe device + +SYNOPSIS +-------- +[verse] +'nvme phy-rx-eom-log' [--lsp= | -s ] + [--controller= | -c ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Retrieves a Physical Interface Receiver Eye Opening Measurement log page from +an NVMe device and provides the returned structure. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-s :: +--lsp=:: + The log specified field configuring the controller's action to take + during processing of the command and the measurement quality. + +-c :: +--controller=:: + Controller ID of the controller associated with the PCIe port to be + measured. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Start a best quality measurement and retrieve the log page header ++ +------------ +# nvme phy-rx-eom-log /dev/nvme0 --lsp=10 +------------ + +* Retrieve a finished best quality measurement on controller with ID 3 ++ +------------ +# nvme phy-rx-eom-log /dev/nvme0 --lsp=2 --controller=3 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-pred-lat-event-agg-log.1 b/Documentation/nvme-pred-lat-event-agg-log.1 index 2bf5b6b97e..d3e76d9927 100644 --- a/Documentation/nvme-pred-lat-event-agg-log.1 +++ b/Documentation/nvme-pred-lat-event-agg-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-pred-lat-event-agg-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-PRED\-LAT\-EVE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-PRED\-LAT\-EVE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,10 @@ nvme-pred-lat-event-agg-log \- Send Predictable Latency Event Aggregate Log Page .SH "SYNOPSIS" .sp .nf -\fInvme pred\-lat\-event\-agg\-log\fR [\-\-log\-entries= | \-e ] +\fInvme pred\-lat\-event\-agg\-log\fR + [\-\-log\-entries= | \-e ] [\-\-rae | \-r] [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -60,7 +61,7 @@ Retain an Asynchronous Event\&. Print the raw Predictable Latency Event Aggregate log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-pred-lat-event-agg-log.html b/Documentation/nvme-pred-lat-event-agg-log.html index a49054b267..3f18097552 100644 --- a/Documentation/nvme-pred-lat-event-agg-log.html +++ b/Documentation/nvme-pred-lat-event-agg-log.html @@ -749,9 +749,10 @@

    NAME

    SYNOPSIS

    -
    nvme pred-lat-event-agg-log <device> [--log-entries=<log_entries> | -e <log_entries>]
    +
    nvme pred-lat-event-agg-log <device>
    +                        [--log-entries=<log_entries> | -e <log_entries>]
                             [--rae | -r] [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -782,11 +783,11 @@

    OPTIONS

    - Retrieve the Predictable Latency Event Aggregate Log pending entries. - This argument is mandatory and its success may depend on the device’s - statistics to provide this log For More details see NVM Express 1.4 Spec. - Section 5.14.1.11. The maximum number of log entries supported is 2044 - for the device. + Retrieve the Predictable Latency Event Aggregate Log pending entries. + This argument is mandatory and its success may depend on the device’s + statistics to provide this log For More details see NVM Express 1.4 Spec. + Section 5.14.1.11. The maximum number of log entries supported is 2044 + for the device.

    @@ -812,15 +813,15 @@

    OPTIONS

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

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

    @@ -863,7 +864,7 @@

    NVME

    diff --git a/Documentation/nvme-pred-lat-event-agg-log.txt b/Documentation/nvme-pred-lat-event-agg-log.txt index b01c9bb0d6..6fb8accbee 100644 --- a/Documentation/nvme-pred-lat-event-agg-log.txt +++ b/Documentation/nvme-pred-lat-event-agg-log.txt @@ -9,9 +9,10 @@ Page request, returns result and log SYNOPSIS -------- [verse] -'nvme pred-lat-event-agg-log' [--log-entries= | -e ] +'nvme pred-lat-event-agg-log' + [--log-entries= | -e ] [--rae | -r] [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -31,11 +32,11 @@ OPTIONS ------- -e :: --log-entries=:: - Retrieve the Predictable Latency Event Aggregate Log pending entries. - This argument is mandatory and its success may depend on the device's - statistics to provide this log For More details see NVM Express 1.4 Spec. - Section 5.14.1.11. The maximum number of log entries supported is 2044 - for the device. + Retrieve the Predictable Latency Event Aggregate Log pending entries. + This argument is mandatory and its success may depend on the device's + statistics to provide this log For More details see NVM Express 1.4 Spec. + Section 5.14.1.11. The maximum number of log entries supported is 2044 + for the device. -r:: --rae:: @@ -45,10 +46,10 @@ OPTIONS --raw-binary:: Print the raw Predictable Latency Event Aggregate log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or 'binary'. - Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. + Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-predictable-lat-log.1 b/Documentation/nvme-predictable-lat-log.1 index 0b7e4bc855..df39fd8bfc 100644 --- a/Documentation/nvme-predictable-lat-log.1 +++ b/Documentation/nvme-predictable-lat-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-predictable-lat-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-PREDICTABLE\-L" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-PREDICTABLE\-L" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,7 +34,7 @@ nvme-predictable-lat-log \- Send Predictable latency per NVM set log page reques .nf \fInvme predictable\-lat\-log\fR [\-\-nvmset\-id= | \-i ] [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,13 +55,19 @@ Retrieve the Predictable latency per NVM set log for the given nvmset id\&. This Print the raw Predictable latency per NVM set log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-predictable-lat-log.html b/Documentation/nvme-predictable-lat-log.html index f66c376a77..b4f699dfa8 100644 --- a/Documentation/nvme-predictable-lat-log.html +++ b/Documentation/nvme-predictable-lat-log.html @@ -751,7 +751,7 @@

    SYNOPSIS

    nvme predictable-lat-log <device> [--nvmset-id=<nvmset_id> | -i <nvmset_id>]
                             [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -781,10 +781,10 @@

    OPTIONS

    - Retrieve the Predictable latency per NVM set log for the given nvmset id. - This argument is mandatory and its success may depend on the device’s - statistics to provide this log For More details see NVM Express 1.4 Spec. - Section 5.14.1.10. The default nvmset id to use is 1 for the device. + Retrieve the Predictable latency per NVM set log for the given nvmset id. + This argument is mandatory and its success may depend on the device’s + statistics to provide this log For More details see NVM Express 1.4 Spec. + Section 5.14.1.10. The default nvmset id to use is 1 for the device.

    @@ -799,15 +799,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -850,7 +861,7 @@

    NVME

    diff --git a/Documentation/nvme-predictable-lat-log.txt b/Documentation/nvme-predictable-lat-log.txt index d1dde80d4d..f0b2ad3500 100644 --- a/Documentation/nvme-predictable-lat-log.txt +++ b/Documentation/nvme-predictable-lat-log.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'nvme predictable-lat-log' [--nvmset-id= | -i ] [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -30,19 +30,23 @@ OPTIONS ------- -i :: --nvmset-id=:: - Retrieve the Predictable latency per NVM set log for the given nvmset id. - This argument is mandatory and its success may depend on the device's - statistics to provide this log For More details see NVM Express 1.4 Spec. - Section 5.14.1.10. The default nvmset id to use is 1 for the device. + Retrieve the Predictable latency per NVM set log for the given nvmset id. + This argument is mandatory and its success may depend on the device's + statistics to provide this log For More details see NVM Express 1.4 Spec. + Section 5.14.1.10. The default nvmset id to use is 1 for the device. -b:: --raw-binary:: Print the raw Predictable latency per NVM set log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-primary-ctrl-caps.1 b/Documentation/nvme-primary-ctrl-caps.1 index 6a9d215984..37303b1288 100644 --- a/Documentation/nvme-primary-ctrl-caps.1 +++ b/Documentation/nvme-primary-ctrl-caps.1 @@ -2,12 +2,12 @@ .\" Title: nvme-primary-ctrl-caps .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-PRIMARY\-CTRL\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-PRIMARY\-CTRL\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-primary-ctrl-caps \- Send identify Primary Controller Caps, return result a .SH "SYNOPSIS" .sp .nf -\fInvme primary\-ctrl\-caps\fR [\-o | \-\-output\-format=] +\fInvme primary\-ctrl\-caps\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -43,17 +43,23 @@ The parameter is mandatory and may be either the NVMe character device On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-H, \-\-human\-readable +.RS 4 +This option will parse and format many of the bit fields into human\-readable formats\&. +.RE +.PP +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE .PP -\-H, \-\-human\-readable +\-v, \-\-verbose .RS 4 -This option will parse and format many of the bit fields into human\-readable formats\&. +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-primary-ctrl-caps.html b/Documentation/nvme-primary-ctrl-caps.html index 0c85a415d9..5343c77cd4 100644 --- a/Documentation/nvme-primary-ctrl-caps.html +++ b/Documentation/nvme-primary-ctrl-caps.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme primary-ctrl-caps <device> [-o <format> | --output-format=<format>]
    +
    nvme primary-ctrl-caps <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -771,27 +771,38 @@

    OPTIONS

    --o <format> +-H
    ---output-format=<format> +--human-readable

    - Set the reporting format to normal, json, or - binary. Only one output format can be used at a time. + This option will parse and format many of the bit fields + into human-readable formats.

    --H +-o <fmt>
    ---human-readable +--output-format=<fmt>

    - This option will parse and format many of the bit fields - into human-readable formats. + Set the reporting format to normal, json or binary. Only one + output format can be used at a time. +

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

    + Increase the information detail in the output.

    @@ -835,7 +846,7 @@

    NVME

    diff --git a/Documentation/nvme-primary-ctrl-caps.txt b/Documentation/nvme-primary-ctrl-caps.txt index 3edf5c1a5d..0300383e39 100644 --- a/Documentation/nvme-primary-ctrl-caps.txt +++ b/Documentation/nvme-primary-ctrl-caps.txt @@ -8,7 +8,7 @@ nvme-primary-ctrl-caps - Send identify Primary Controller Caps, return result an SYNOPSIS -------- [verse] -'nvme primary-ctrl-caps' [-o | --output-format=] +'nvme primary-ctrl-caps' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -24,16 +24,20 @@ raw buffer may be printed to stdout. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - -H:: --human-readable:: This option will parse and format many of the bit fields into human-readable formats. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Get Primary Ctrl Caps of the device in default format diff --git a/Documentation/nvme-read.1 b/Documentation/nvme-read.1 index db0eb59139..85cc1e3df5 100644 --- a/Documentation/nvme-read.1 +++ b/Documentation/nvme-read.1 @@ -2,12 +2,12 @@ .\" Title: nvme-read .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-READ" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-READ" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -42,53 +42,50 @@ nvme-read \- Send an NVMe Read command, provide results [\-\-prinfo= | \-p ] [\-\-app\-tag\-mask= | \-m ] [\-\-app\-tag= | \-a ] - [\-\-limited\-retry | \-l] - [\-\-force\-unit\-access | \-f] + [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f] [\-\-dir\-type= | \-T ] - [\-\-dir\-spec= | \-S ] - [\-\-dsm= | \-D ] - [\-\-show\-command | \-v] - [\-\-dry\-run | \-w] - [\-\-latency | \-t] - [\-\-storage\-tag\-check | \-C ] - [\-\-force] + [\-\-dir\-spec= | \-S ] [\-\-dsm= | \-D ] + [\-\-show\-command | \-V] [\-\-dry\-run | \-w] [\-\-latency | \-t] + [\-\-storage\-tag | \-g ] + [\-\-storage\-tag\-check | \-C] [\-\-force] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Read command reads the logical blocks specified by the command from the medium and copies to the data data buffer provided\&. Will use stdout by default if you don\(cqt provide a file\&. .SH "OPTIONS" .PP -\-\-start\-block=, \-s +\-s , \-\-start\-block= .RS 4 Start block\&. .RE .PP -\-\-block\-count, \-c +\-c, \-\-block\-count .RS 4 The number of blocks to transfer\&. This is a zeroes based value to align with the kernel\(cqs use of this field\&. (ie\&. 0 means transfer 1 block)\&. .RE .PP -\-\-data\-size=, \-z +\-z , \-\-data\-size= .RS 4 Size of data, in bytes\&. .RE .PP -\-\-metadata\-size=, \-y +\-y , \-\-metadata\-size= .RS 4 Size of metadata in bytes\&. .RE .PP -\-\-data=, \-d +\-d , \-\-data= .RS 4 Data file\&. If none provided, contents are sent to STDOUT\&. .RE .PP -\-\-metadata=, \-M +\-M , \-\-metadata= .RS 4 Metadata file, if necessary\&. .RE .PP -\-\-prinfo=, \-p +\-p , \-\-prinfo= .RS 4 Protection Information field definition\&. .TS @@ -133,17 +130,17 @@ T} .sp 1 .RE .PP -\-\-ref\-tag=, \-r +\-r , \-\-ref\-tag= .RS 4 Optional reftag when used with protection information\&. .RE .PP -\-\-app\-tag\-mask=, \-m +\-m , \-\-app\-tag\-mask= .RS 4 Optional application tag mask when used with protection information\&. .RE .PP -\-\-force\-unit\-access, \-f +\-f, \-\-force\-unit\-access .RS 4 Set the force\-unit access flag\&. .RE @@ -163,7 +160,7 @@ Optional field for directive specifics\&. When used with write streams, this val The optional data set management attributes for this command\&. The argument for this is the least significant 8 bits of the DSM field in a write command; the most significant 16 bits of the field come from the directive specific field, if used\&. This may be used to set attributes for the LBAs being written, like access frequency, type, latency, among other things, as well as yet to be defined types\&. Please consult the NVMe specification for detailed breakdown of how to use this field\&. .RE .PP -\-v, \-\-show\-cmd +\-V, \-\-show\-cmd .RS 4 Print out the command to be sent\&. .RE @@ -181,15 +178,34 @@ be set\&. Otherwise \-\-dry\-run option will be Print out the latency the IOCTL took (in us)\&. .RE .PP -\-\-storage\-tag\-check=, \-C +\-g , \-\-storage\-tag= .RS 4 -This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +Variable Sized Expected Logical Block Storage Tag(ELBST)\&. +.RE +.PP +\-C, \-\-storage\-tag\-check +.RS 4 +This flag enables Storage Tag field checking as part of end\-to\-end data protection processing\&. .RE .PP \-\-force .RS 4 Ignore namespace is currently busy and performed the operation even though\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-read.html b/Documentation/nvme-read.html index 8c37390973..ff4ab43019 100644 --- a/Documentation/nvme-read.html +++ b/Documentation/nvme-read.html @@ -759,16 +759,13 @@

    SYNOPSIS

    [--prinfo=<prinfo> | -p <prinfo>] [--app-tag-mask=<appmask> | -m <appmask>] [--app-tag=<apptag> | -a <apptag>] - [--limited-retry | -l] - [--force-unit-access | -f] + [--limited-retry | -l] [--force-unit-access | -f] [--dir-type=<type> | -T <type>] - [--dir-spec=<spec> | -S <spec>] - [--dsm=<dsm> | -D <dsm>] - [--show-command | -v] - [--dry-run | -w] - [--latency | -t] - [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>] - [--force] + [--dir-spec=<spec> | -S <spec>] [--dsm=<dsm> | -D <dsm>] + [--show-command | -V] [--dry-run | -w] [--latency | -t] + [--storage-tag<storage-tag> | -g <storage-tag>] + [--storage-tag-check | -C] [--force] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -786,10 +783,10 @@

    OPTIONS

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

    @@ -797,10 +794,10 @@

    OPTIONS

    ---block-count +-c
    --c +--block-count

    @@ -810,10 +807,10 @@

    OPTIONS

    ---data-size=<size> +-z <size>
    --z <size> +--data-size=<size>

    @@ -821,10 +818,10 @@

    OPTIONS

    ---metadata-size=<size> +-y <size>
    --y <size> +--metadata-size=<size>

    @@ -832,10 +829,10 @@

    OPTIONS

    ---data=<data-file> +-d <data-file>
    --d <data-file> +--data=<data-file>

    @@ -843,10 +840,10 @@

    OPTIONS

    ---metadata=<metadata-file> +-M <metadata-file>
    --M <metadata-file> +--metadata=<metadata-file>

    @@ -854,10 +851,10 @@

    OPTIONS

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

    @@ -902,10 +899,10 @@

    OPTIONS

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

    @@ -913,10 +910,10 @@

    OPTIONS

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

    @@ -924,10 +921,10 @@

    OPTIONS

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

    @@ -981,7 +978,7 @@

    OPTIONS

    --v +-V
    --show-cmd @@ -1016,14 +1013,25 @@

    OPTIONS

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

    - This bit specifies the Storage Tag field shall be checked as part of end-to-end + Variable Sized Expected Logical Block Storage Tag(ELBST). +

    +
    +
    +-C +
    +
    +--storage-tag-check +
    +
    +

    + This flag enables Storage Tag field checking as part of end-to-end data protection processing.

    @@ -1032,8 +1040,31 @@

    OPTIONS

    - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. +

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

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

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

    + Increase the information detail in the output.

    @@ -1056,7 +1087,7 @@

    NVME

    diff --git a/Documentation/nvme-read.txt b/Documentation/nvme-read.txt index c5f0e5224b..cecaa71183 100644 --- a/Documentation/nvme-read.txt +++ b/Documentation/nvme-read.txt @@ -18,16 +18,13 @@ SYNOPSIS [--prinfo= | -p ] [--app-tag-mask= | -m ] [--app-tag= | -a ] - [--limited-retry | -l] - [--force-unit-access | -f] + [--limited-retry | -l] [--force-unit-access | -f] [--dir-type= | -T ] - [--dir-spec= | -S ] - [--dsm= | -D ] - [--show-command | -v] - [--dry-run | -w] - [--latency | -t] - [--storage-tag-check | -C ] - [--force] + [--dir-spec= | -S ] [--dsm= | -D ] + [--show-command | -V] [--dry-run | -w] [--latency | -t] + [--storage-tag | -g ] + [--storage-tag-check | -C] [--force] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -37,34 +34,34 @@ by default if you don't provide a file. OPTIONS ------- ---start-block=:: -s :: +--start-block=:: Start block. ---block-count:: -c:: +--block-count:: The number of blocks to transfer. This is a zeroes based value to align with the kernel's use of this field. (ie. 0 means transfer 1 block). ---data-size=:: -z :: +--data-size=:: Size of data, in bytes. ---metadata-size=:: -y :: +--metadata-size=:: Size of metadata in bytes. ---data=:: -d :: +--data=:: Data file. If none provided, contents are sent to STDOUT. ---metadata=:: -M :: +--metadata=:: Metadata file, if necessary. ---prinfo=:: -p :: +--prinfo=:: Protection Information field definition. + [] @@ -79,16 +76,16 @@ metadata is passes. |0|Set to 1 enables checking the reference tag |================= ---ref-tag=:: -r :: +--ref-tag=:: Optional reftag when used with protection information. ---app-tag-mask=:: -m :: +--app-tag-mask=:: Optional application tag mask when used with protection information. ---force-unit-access:: -f:: +--force-unit-access:: Set the force-unit access flag. -T :: @@ -116,7 +113,7 @@ metadata is passes. consult the NVMe specification for detailed breakdown of how to use this field. --v:: +-V:: --show-cmd:: Print out the command to be sent. @@ -130,14 +127,27 @@ metadata is passes. --latency:: Print out the latency the IOCTL took (in us). ---storage-tag-check=:: --C :: - This bit specifies the Storage Tag field shall be checked as part of end-to-end +-g :: +--storage-tag=:: + Variable Sized Expected Logical Block Storage Tag(ELBST). + +-C:: +--storage-tag-check:: + This flag enables Storage Tag field checking as part of end-to-end data protection processing. --force:: - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-reset.1 b/Documentation/nvme-reset.1 index 287d4775d6..d9fa8e6199 100644 --- a/Documentation/nvme-reset.1 +++ b/Documentation/nvme-reset.1 @@ -2,12 +2,12 @@ .\" Title: nvme-reset .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RESET" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RESET" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,14 +32,26 @@ nvme-reset \- Reset the nvme controller\&. .SH "SYNOPSIS" .sp .nf -\fInvme reset\fR +\fInvme reset\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Requests NVMe controller reset\&. The param is mandatory and must be an NVMe character device (ex: /dev/nvme0)\&. .SH "OPTIONS" -.sp -None +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-reset.html b/Documentation/nvme-reset.html index d55fd0f6c1..1ce4b8d5f0 100644 --- a/Documentation/nvme-reset.html +++ b/Documentation/nvme-reset.html @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme reset <device>
    +
    nvme reset <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -764,7 +764,31 @@

    DESCRIPTION

    OPTIONS

    -

    None

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

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

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

    + Increase the information detail in the output. +

    +
    +
    @@ -794,7 +818,7 @@

    NVME

    diff --git a/Documentation/nvme-reset.txt b/Documentation/nvme-reset.txt index d1a282bcb3..20fcbb1072 100644 --- a/Documentation/nvme-reset.txt +++ b/Documentation/nvme-reset.txt @@ -8,7 +8,7 @@ nvme-reset - Reset the nvme controller. SYNOPSIS -------- [verse] -'nvme reset' +'nvme reset' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -17,7 +17,14 @@ be an NVMe character device (ex: /dev/nvme0). OPTIONS ------- -None +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-resv-acquire.1 b/Documentation/nvme-resv-acquire.1 index 7bf7e05941..f308bf35a4 100644 --- a/Documentation/nvme-resv-acquire.1 +++ b/Documentation/nvme-resv-acquire.1 @@ -2,12 +2,12 @@ .\" Title: nvme-resv-acquire .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RESV\-ACQUIRE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RESV\-ACQUIRE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,11 +33,11 @@ nvme-resv-acquire \- Acquire an nvme reservation .sp .nf \fInvme resv\-acquire\fR [\-\-namespace\-id= | \-n ] - [\-\-crkey= | \-c ] - [\-\-prkey= | \-p ] - [\-\-rtype= | \-t ] - [\-\-racqa= | \-a ] - [\-\-iekey | \-i] + [\-\-crkey= | \-c ] + [\-\-prkey= | \-p ] + [\-\-rtype= | \-t ] + [\-\-racqa= | \-a ] [\-\-iekey | \-i] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -169,6 +169,20 @@ Ignore Existing Key: If this bit is set to a Indicator option, defaults to \fI0\fR\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet diff --git a/Documentation/nvme-resv-acquire.html b/Documentation/nvme-resv-acquire.html index 23702b4ef0..35719eeee3 100644 --- a/Documentation/nvme-resv-acquire.html +++ b/Documentation/nvme-resv-acquire.html @@ -750,11 +750,11 @@

    SYNOPSIS

    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]
    + [--crkey=<crkey> | -c <crkey>] + [--prkey=<prkey> | -p <prkey>] + [--rtype=<rtype> | -t <rtype>] + [--racqa=<racqa> | -a <racqa>] [--iekey | -i] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -924,10 +924,33 @@

    OPTIONS

    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. + shall succeed regardless of the CRKEY field value.

    Indicator option, defaults to 0.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -948,7 +971,7 @@

    NVME

    diff --git a/Documentation/nvme-resv-acquire.txt b/Documentation/nvme-resv-acquire.txt index 1b6e110cfa..19282c6a9e 100644 --- a/Documentation/nvme-resv-acquire.txt +++ b/Documentation/nvme-resv-acquire.txt @@ -9,11 +9,11 @@ SYNOPSIS -------- [verse] 'nvme resv-acquire' [--namespace-id= | -n ] - [--crkey= | -c ] - [--prkey= | -p ] - [--rtype= | -t ] - [--racqa= | -a ] - [--iekey | -i] + [--crkey= | -c ] + [--prkey= | -p ] + [--rtype= | -t ] + [--racqa= | -a ] [--iekey | -i] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -79,10 +79,19 @@ OPTIONS --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. + shall succeed regardless of the CRKEY field value. + Indicator option, defaults to '0'. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet diff --git a/Documentation/nvme-resv-notif-log.1 b/Documentation/nvme-resv-notif-log.1 index 6b54042a85..655ee091d1 100644 --- a/Documentation/nvme-resv-notif-log.1 +++ b/Documentation/nvme-resv-notif-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-resv-notif-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RESV\-NOTIF\-L" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RESV\-NOTIF\-L" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-resv-notif-log \- Send NVMe Reservation Notification log page request, retu .SH "SYNOPSIS" .sp .nf -\fInvme resv\-notif\-log\fR [\-\-output\-format= | \-o ] +\fInvme resv\-notif\-log\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -43,13 +43,19 @@ The parameter is mandatory and may be either the NVMe character device On success, the returned Reservation Notification log structure may be returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-resv-notif-log.html b/Documentation/nvme-resv-notif-log.html index 8e582e9a0a..e8149285b2 100644 --- a/Documentation/nvme-resv-notif-log.html +++ b/Documentation/nvme-resv-notif-log.html @@ -740,7 +740,7 @@

    NAME

    nvme-resv-notif-log - - Send NVMe Reservation Notification log page request, return result and log + Send NVMe Reservation Notification log page request, return result and log

    @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme resv-notif-log <device> [--output-format=<fmt> | -o <fmt>]
    +
    nvme resv-notif-log <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -772,15 +772,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -822,7 +833,7 @@

    NVME

    diff --git a/Documentation/nvme-resv-notif-log.txt b/Documentation/nvme-resv-notif-log.txt index a9c5cddaba..f8d828bc7b 100644 --- a/Documentation/nvme-resv-notif-log.txt +++ b/Documentation/nvme-resv-notif-log.txt @@ -4,12 +4,12 @@ nvme-resv-notif-log(1) NAME ---- nvme-resv-notif-log - Send NVMe Reservation Notification log page request, - return result and log +return result and log SYNOPSIS -------- [verse] -'nvme resv-notif-log' [--output-format= | -o ] +'nvme resv-notif-log' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -26,10 +26,14 @@ may be printed to stdout for another program to parse. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-resv-register.1 b/Documentation/nvme-resv-register.1 index 3be6292691..3a86f7c929 100644 --- a/Documentation/nvme-resv-register.1 +++ b/Documentation/nvme-resv-register.1 @@ -2,12 +2,12 @@ .\" Title: nvme-resv-register .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RESV\-REGISTER" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RESV\-REGISTER" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,11 +33,11 @@ nvme-resv-register \- Register an nvme reservation .sp .nf \fInvme resv\-register\fR [\-\-namespace\-id= | \-n ] - [\-\-crkey= | \-c ] - [\-\-nrkey= | \-k ] - [\-\-rrega= | \-r ] - [\-\-cptpl= | \-p ] - [\-\-iekey | \-i] + [\-\-crkey= | \-c ] + [\-\-nrkey= | \-k ] + [\-\-rrega= | \-r ] + [\-\-cptpl= | \-p ] [\-\-iekey | \-i] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -145,6 +145,20 @@ Ignore Existing Key: If this bit is set to a Indicator option, defaults to \fI0\fR\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet diff --git a/Documentation/nvme-resv-register.html b/Documentation/nvme-resv-register.html index b09c3f254f..fb78ac7c21 100644 --- a/Documentation/nvme-resv-register.html +++ b/Documentation/nvme-resv-register.html @@ -750,11 +750,11 @@

    SYNOPSIS

    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]
    + [--crkey=<crkey> | -c <crkey>] + [--nrkey=<nrkey> | -k <nrkey>] + [--rrega=<rrega> | -r <rrega>] + [--cptpl=<cptpl> | -p <cptpl>] [--iekey | -i] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -917,6 +917,29 @@

    OPTIONS

    Indicator option, defaults to 0.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -937,7 +960,7 @@

    NVME

    diff --git a/Documentation/nvme-resv-register.txt b/Documentation/nvme-resv-register.txt index e0553f42a9..4a830506ee 100644 --- a/Documentation/nvme-resv-register.txt +++ b/Documentation/nvme-resv-register.txt @@ -9,11 +9,11 @@ SYNOPSIS -------- [verse] 'nvme resv-register' [--namespace-id= | -n ] - [--crkey= | -c ] - [--nrkey= | -k ] - [--rrega= | -r ] - [--cptpl= | -p ] - [--iekey | -i] + [--crkey= | -c ] + [--nrkey= | -k ] + [--rrega= | -r ] + [--cptpl= | -p ] [--iekey | -i] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -84,6 +84,15 @@ a power loss. + Indicator option, defaults to '0'. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet diff --git a/Documentation/nvme-resv-release.1 b/Documentation/nvme-resv-release.1 index 7466335ae9..06ed2e7292 100644 --- a/Documentation/nvme-resv-release.1 +++ b/Documentation/nvme-resv-release.1 @@ -2,12 +2,12 @@ .\" Title: nvme-resv-release .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RESV\-RELEASE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RESV\-RELEASE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,10 +33,10 @@ nvme-resv-release \- Release an nvme reservation .sp .nf \fInvme resv\-release\fR [\-\-namespace\-id= | \-n ] - [\-\-crkey= | \-c ] - [\-\-rtype= | \-t ] - [\-\-rrela= | \-a ] - [\-\-iekey | \-i] + [\-\-crkey= | \-c ] + [\-\-rtype= | \-t ] + [\-\-rrela= | \-a ] [\-\-iekey | \-i] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -157,6 +157,20 @@ Ignore Existing Key: If this bit is set to a Indicator option, defaults to \fI0\fR\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet diff --git a/Documentation/nvme-resv-release.html b/Documentation/nvme-resv-release.html index 3878661171..d166276679 100644 --- a/Documentation/nvme-resv-release.html +++ b/Documentation/nvme-resv-release.html @@ -750,10 +750,10 @@

    SYNOPSIS

    nvme resv-release <device> [--namespace-id=<nsid> | -n <nsid>]
    -                             [--crkey=<crkey> | -c <crkey>]
    -                             [--rtype=<rtype> | -t <rtype>]
    -                             [--rrela=<rrela> | -a <rrela>]
    -                             [--iekey | -i]
    + [--crkey=<crkey> | -c <crkey>] + [--rtype=<rtype> | -t <rtype>] + [--rrela=<rrela> | -a <rrela>] [--iekey | -i] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -910,6 +910,29 @@

    OPTIONS

    Indicator option, defaults to 0.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -930,7 +953,7 @@

    NVME

    diff --git a/Documentation/nvme-resv-release.txt b/Documentation/nvme-resv-release.txt index 6eb0b43c1a..c3dc90d39a 100644 --- a/Documentation/nvme-resv-release.txt +++ b/Documentation/nvme-resv-release.txt @@ -9,10 +9,10 @@ SYNOPSIS -------- [verse] 'nvme resv-release' [--namespace-id= | -n ] - [--crkey= | -c ] - [--rtype= | -t ] - [--rrela= | -a ] - [--iekey | -i] + [--crkey= | -c ] + [--rtype= | -t ] + [--rrela= | -a ] [--iekey | -i] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -75,6 +75,15 @@ OPTIONS + Indicator option, defaults to '0'. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples yet diff --git a/Documentation/nvme-resv-report.1 b/Documentation/nvme-resv-report.1 index a1e3db3833..0b8e78cef3 100644 --- a/Documentation/nvme-resv-report.1 +++ b/Documentation/nvme-resv-report.1 @@ -2,12 +2,12 @@ .\" Title: nvme-resv-report .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RESV\-REPORT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RESV\-REPORT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,10 +33,9 @@ nvme-resv-report \- Send NVMe Reservation Report, parse the result .sp .nf \fInvme resv\-report\fR [\-\-namespace\-id= | \-n ] - [\-\-numd= | \-d ] - [\-\-eds | \-e] + [\-\-numd= | \-d ] [\-\-eds | \-e] [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -66,13 +65,19 @@ Request extended Data Structure: If this bit is set to a Print the raw buffer to stdout\&. Structure is not parsed by program\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-resv-report.html b/Documentation/nvme-resv-report.html index 2b5da01b7a..7e22653cb8 100644 --- a/Documentation/nvme-resv-report.html +++ b/Documentation/nvme-resv-report.html @@ -750,10 +750,9 @@

    SYNOPSIS

    nvme resv-report <device> [--namespace-id=<nsid> | -n <nsid>]
    -                        [--numd=<num-dwords> | -d <num-dwords>]
    -                        [--eds | -e]
    +                        [--numd=<num-dwords> | -d <num-dwords>] [--eds | -e]
                             [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -824,15 +823,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -855,7 +865,7 @@

    NVME

    diff --git a/Documentation/nvme-resv-report.txt b/Documentation/nvme-resv-report.txt index 32012fed43..2e12826ed1 100644 --- a/Documentation/nvme-resv-report.txt +++ b/Documentation/nvme-resv-report.txt @@ -9,10 +9,9 @@ SYNOPSIS -------- [verse] 'nvme resv-report' [--namespace-id= | -n ] - [--numd= | -d ] - [--eds | -e] + [--numd= | -d ] [--eds | -e] [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -48,11 +47,14 @@ OPTIONS Print the raw buffer to stdout. Structure is not parsed by program. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-rpmb.1 b/Documentation/nvme-rpmb.1 index 7a44cdecd1..cedee9ac9c 100644 --- a/Documentation/nvme-rpmb.1 +++ b/Documentation/nvme-rpmb.1 @@ -2,12 +2,12 @@ .\" Title: nvme-rpmb .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-RPMB" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-RPMB" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,13 +33,13 @@ nvme-rpmb \- Send RPMB commands to an NVMe device .sp .nf \fInvme rpmb\fR [\-\-cmd= | \-c ] - [\-\-msgfile= | \-f ] - [\-\-keyfile= | \-g ] - [\-\-key= | \-k ] - [\-\-msg= | \-d ] - [\-\-address= | \-o ] - [\-\-blocks=<512 byte sectors> | \-b ] - [\-\-target= | \-t ] + [\-\-msgfile= | \-f ] + [\-\-keyfile= | \-g ] + [\-\-key= | \-k ] [\-\-msg= | \-d ] + [\-\-address= | \-o ] + [\-\-blocks=<512 byte sectors> | \-b ] + [\-\-target= | \-t ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -181,6 +181,20 @@ The address (in 512 byte sector offset from 0) to be used for data transfer comm .RS 4 The size in 512 byte sectors to be used for data transfer commands (read or write) for a specified RPMB target\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-rpmb.html b/Documentation/nvme-rpmb.html index 5d9879a549..82c503b4bb 100644 --- a/Documentation/nvme-rpmb.html +++ b/Documentation/nvme-rpmb.html @@ -750,13 +750,13 @@

    SYNOPSIS

    nvme rpmb <device> [--cmd=<command> | -c <command>]
    -                    [--msgfile=<data-file> | -f <data-file>]
    -                    [--keyfile=<key-file> | -g <key-file>]
    -                    [--key=<key> | -k <key>]
    -                    [--msg=<data> | -d <data>]
    -                    [--address=<offset> | -o <offset>]
    -                    [--blocks=<512 byte sectors> | -b <sectors> ]
    -                    [--target=<target-id> | -t <id> ]
    + [--msgfile=<data-file> | -f <data-file>] + [--keyfile=<key-file> | -g <key-file>] + [--key=<key> | -k <key>] [--msg=<data> | -d <data>] + [--address=<offset> | -o <offset>] + [--blocks=<512 byte sectors> | -b <sectors>] + [--target=<target-id> | -t <id>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -921,6 +921,29 @@

    OPTIONS

    (read or write) for a specified RPMB target.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -1001,7 +1024,7 @@

    NVME

    diff --git a/Documentation/nvme-rpmb.txt b/Documentation/nvme-rpmb.txt index c30c83d897..9dc954db91 100644 --- a/Documentation/nvme-rpmb.txt +++ b/Documentation/nvme-rpmb.txt @@ -9,13 +9,13 @@ SYNOPSIS -------- [verse] 'nvme rpmb' [--cmd= | -c ] - [--msgfile= | -f ] - [--keyfile= | -g ] - [--key= | -k ] - [--msg= | -d ] - [--address= | -o ] - [--blocks=<512 byte sectors> | -b ] - [--target= | -t ] + [--msgfile= | -f ] + [--keyfile= | -g ] + [--key= | -k ] [--msg= | -d ] + [--address= | -o ] + [--blocks=<512 byte sectors> | -b ] + [--target= | -t ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -71,7 +71,7 @@ OPTIONS nvme-rpmb without sending it to device. RPMB target 0 is used as the default target if --target or -t is not specified. 0x0 is used as the default address if no -address or -o option is specified, - + -t :: --target=:: RPMB target id. This should be one of the supported RPMB targets as @@ -105,6 +105,15 @@ OPTIONS The size in 512 byte sectors to be used for data transfer commands (read or write) for a specified RPMB target. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Print RPMB support information of an NVMe device @@ -147,4 +156,3 @@ EXAMPLES NVME ---- Part of the nvme-user suite - diff --git a/Documentation/nvme-sanitize-log.1 b/Documentation/nvme-sanitize-log.1 index e23f9ecf61..11ce433b94 100644 --- a/Documentation/nvme-sanitize-log.1 +++ b/Documentation/nvme-sanitize-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-sanitize-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SANITIZE\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SANITIZE\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,9 @@ nvme-sanitize-log \- Send NVMe sanitize\-log Command, return result .SH "SYNOPSIS" .sp .nf -\fInvme sanitize\-log\fR [\-\-rae | \-r] [\-\-output\-format= | \-o ] - [\-\-human\-readable | \-H] - [\-\-raw\-binary | \-b] +\fInvme sanitize\-log\fR [\-\-rae | \-r] [\-\-human\-readable | \-H] + [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -105,14 +105,6 @@ On success it returns 0, error code otherwise\&. Retain an Asynchronous Event\&. .RE .PP -\-o , \-\-output\-format= -.RS 4 -Set the reporting format to -\fInormal\fR, -\fIjson\fR, or -\fIbinary\fR\&. Only one output format can be used at a time\&. -.RE -.PP \-H, \-\-human\-readable .RS 4 This option will parse and format many of the bit fields into human\-readable formats\&. @@ -122,6 +114,20 @@ This option will parse and format many of the bit fields into human\-readable fo .RS 4 Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-sanitize-log.html b/Documentation/nvme-sanitize-log.html index 67b122ef6e..6872560c06 100644 --- a/Documentation/nvme-sanitize-log.html +++ b/Documentation/nvme-sanitize-log.html @@ -749,9 +749,9 @@

    NAME

    SYNOPSIS

    -
    nvme sanitize-log <device> [--rae | -r] [--output-format=<fmt> | -o <fmt>]
    -                             [--human-readable | -H]
    -                             [--raw-binary | -b]
    +
    nvme sanitize-log <device> [--rae | -r] [--human-readable | -H]
    +                        [--raw-binary | -b]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -798,11 +798,11 @@

    DESCRIPTION

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

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

    @@ -827,18 +827,6 @@

    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
    @@ -862,6 +850,29 @@

    OPTIONS

    program. This overrides the vendor specific and human readable options.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -892,7 +903,7 @@

    NVME

    diff --git a/Documentation/nvme-sanitize-log.txt b/Documentation/nvme-sanitize-log.txt index 3c2d43eaca..af45e9fc68 100644 --- a/Documentation/nvme-sanitize-log.txt +++ b/Documentation/nvme-sanitize-log.txt @@ -8,9 +8,9 @@ nvme-sanitize-log - Send NVMe sanitize-log Command, return result SYNOPSIS -------- [verse] -'nvme sanitize-log' [--rae | -r] [--output-format= | -o ] - [--human-readable | -H] - [--raw-binary | -b] +'nvme sanitize-log' [--rae | -r] [--human-readable | -H] + [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -41,11 +41,11 @@ Expected status and description :- |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. + 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. + 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 @@ -58,11 +58,6 @@ OPTIONS --rae:: Retain an Asynchronous Event. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. - -H:: --human-readable:: This option will parse and format many of the bit fields @@ -73,6 +68,15 @@ OPTIONS Print the raw buffer to stdout. Structure is not parsed by program. This overrides the vendor specific and human readable options. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Has the program issue Sanitize-log Command : diff --git a/Documentation/nvme-sanitize.1 b/Documentation/nvme-sanitize.1 index c328d42d87..e5c815f911 100644 --- a/Documentation/nvme-sanitize.1 +++ b/Documentation/nvme-sanitize.1 @@ -2,12 +2,12 @@ .\" Title: nvme-sanitize .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SANITIZE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SANITIZE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,13 +32,12 @@ nvme-sanitize \- Send NVMe Sanitize Command, return result .SH "SYNOPSIS" .sp .nf -\fInvme sanitize\fR [\-\-no\-dealloc | \-d] - [\-\-oipbp | \-i] - [\-\-owpass= | \-n ] - [\-\-ause | \-u] - [\-\-sanact= | \-a ] - [\-\-ovrpat= | \-p ] - [\-\-force] +\fInvme sanitize\fR [\-\-no\-dealloc | \-d] [\-\-oipbp | \-i] + [\-\-owpass= | \-n ] + [\-\-ause | \-u] [\-\-sanact= | \-a ] + [\-\-ovrpat= | \-p ] + [\-\-force] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -71,7 +70,51 @@ Allow Unrestricted Sanitize Exit: If set, then the sanitize operation is perform .PP \-a , \-\-sanact= .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 +Sanitize Action: +.TS +allbox tab(:); +lt lt +lt lt +lt lt +lt lt +lt lt +lt lt. +T{ +Value +T}:T{ +Definition +T} +T{ +0x00 +T}:T{ +Reserved +T} +T{ +0x01 | +\fIexit\-failure\fR +T}:T{ +Exit Failure Mode +T} +T{ +0x02 | +\fIstart\-block\-erase\fR +T}:T{ +Start a Block Erase sanitize operation +T} +T{ +0x03 | +\fIstart\-overwrite\fR +T}:T{ +Start an Overwrite sanitize operation +T} +T{ +0x04 | +\fIstart\-crypto\-erase\fR +T}:T{ +Start a Crypto Erase sanitize operation +T} +.TE +.sp 1 .RE .PP \-p , \-\-ovrpat= @@ -83,6 +126,20 @@ Overwrite Pattern: This field is ignored unless the Sanitize Action field in Com .RS 4 Ignore namespace is currently busy and performed the operation even though\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 @@ -99,8 +156,9 @@ Has the program issue Sanitize Command : .RS 4 .\} .nf -# nvme sanitize /dev/nvme0n1 \-a 0x02 -# nvme sanitize /dev/nvme0n1 \-\-sanact=0x01 +# nvme sanitize /dev/nvme0 \-a 0x02 +# nvme sanitize /dev/nvme0 \-\-sanact=0x01 +# nvme sanitize /dev/nvme0 \-\-sanact=start\-overwrite .fi .if n \{\ .RE diff --git a/Documentation/nvme-sanitize.html b/Documentation/nvme-sanitize.html index a620dc6b78..4469620afc 100644 --- a/Documentation/nvme-sanitize.html +++ b/Documentation/nvme-sanitize.html @@ -749,13 +749,12 @@

    NAME

    SYNOPSIS

    -
    nvme sanitize <device> [--no-dealloc | -d]
    -              [--oipbp | -i]
    -              [--owpass=<overwrite-pass-count> | -n <overwrite-pass-count>]
    -              [--ause | -u]
    -              [--sanact=<action> | -a <action>]
    -              [--ovrpat=<overwrite-pattern> | -p <overwrite-pattern>]
    -              [--force]
    +
    nvme sanitize <device> [--no-dealloc | -d] [--oipbp | -i]
    +                        [--owpass=<overwrite-pass-count> | -n <overwrite-pass-count>]
    +                        [--ause | -u] [--sanact=<action> | -a <action>]
    +                        [--ovrpat=<overwrite-pattern> | -p <overwrite-pattern>]
    +                        [--force]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -781,13 +780,13 @@

    OPTIONS

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

    @@ -798,11 +797,11 @@

    OPTIONS

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

    @@ -813,12 +812,12 @@

    OPTIONS

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

    @@ -829,11 +828,11 @@

    OPTIONS

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

    @@ -844,13 +843,43 @@

    OPTIONS

    - 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 + Sanitize Action:

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

    Value

    Definition

    0x00

    Reserved

    0x01 | exit-failure

    Exit Failure Mode

    0x02 | start-block-erase

    Start a Block Erase sanitize operation

    0x03 | start-overwrite

    Start an Overwrite sanitize operation

    0x04 | start-crypto-erase

    Start a Crypto Erase sanitize operation

    +
    -p <overwrite-pattern> @@ -860,11 +889,11 @@

    OPTIONS

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

    @@ -872,8 +901,31 @@

    OPTIONS

    - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. +

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

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

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

    + Increase the information detail in the output.

    @@ -889,8 +941,9 @@

    EXAMPLES

    -
    # nvme sanitize /dev/nvme0n1 -a 0x02
    -# nvme sanitize /dev/nvme0n1 --sanact=0x01
    +
    # nvme sanitize /dev/nvme0 -a 0x02
    +# nvme sanitize /dev/nvme0 --sanact=0x01
    +# nvme sanitize /dev/nvme0 --sanact=start-overwrite
    @@ -907,7 +960,7 @@

    NVME

    diff --git a/Documentation/nvme-sanitize.txt b/Documentation/nvme-sanitize.txt index 196983b6c7..1e4346322b 100644 --- a/Documentation/nvme-sanitize.txt +++ b/Documentation/nvme-sanitize.txt @@ -8,13 +8,12 @@ nvme-sanitize - Send NVMe Sanitize Command, return result SYNOPSIS -------- [verse] -'nvme sanitize' [--no-dealloc | -d] - [--oipbp | -i] - [--owpass= | -n ] - [--ause | -u] - [--sanact= | -a ] - [--ovrpat= | -p ] - [--force] +'nvme sanitize' [--no-dealloc | -d] [--oipbp | -i] + [--owpass= | -n ] + [--ause | -u] [--sanact= | -a ] + [--ovrpat= | -p ] + [--force] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -29,67 +28,82 @@ OPTIONS ------- -d:: --no-dealloc:: - No Deallocate After Sanitize: - If set, then the controller shall not deallocate any logical - blocks as a result of successfully completing the sanitize - operation. If cleared, then the controller should deallocate - logical blocks as a result of successfully completing the - sanitize operation. This bit shall be ignored if the Sanitize - Action field is set to 001b (i.e., Exit Failure Mode). + 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). + 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 :: --owpass=:: - 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). + 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). + 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 :: --sanact=:: - 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 + Sanitize Action: ++ +[] +|================= +|Value|Definition +|0x00| Reserved +|0x01 \| 'exit-failure'| Exit Failure Mode +|0x02 \| 'start-block-erase'| Start a Block Erase sanitize operation +|0x03 \| 'start-overwrite'| Start an Overwrite sanitize operation +|0x04 \| 'start-crypto-erase'| Start a Crypto Erase sanitize operation +|================= -p :: --ovrpat=:: - 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. + Overwrite Pattern: + This field is ignored unless the Sanitize Action field in + Command Dword 10 is set to 011b (i.e., Overwrite). This field + specifies a 32-bit pattern that is used for the Overwrite + sanitize operation. --force:: - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- * Has the program issue Sanitize Command : + ------------ -# nvme sanitize /dev/nvme0n1 -a 0x02 -# nvme sanitize /dev/nvme0n1 --sanact=0x01 +# nvme sanitize /dev/nvme0 -a 0x02 +# nvme sanitize /dev/nvme0 --sanact=0x01 +# nvme sanitize /dev/nvme0 --sanact=start-overwrite ------------ diff --git a/Documentation/nvme-seagate-clear-fw-activate-history.1 b/Documentation/nvme-seagate-clear-fw-activate-history.1 new file mode 100644 index 0000000000..b5eb66a9cb --- /dev/null +++ b/Documentation/nvme-seagate-clear-fw-activate-history.1 @@ -0,0 +1,60 @@ +'\" t +.\" Title: nvme-seagate-clear-fw-activate-history +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-CLEAR" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-clear-fw-activate-history \- Clear the firmware activation history for a given Seagate device\&. +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate clear\-fw\-activate\-history [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.sp +\-s \-\-save:: specifies that the controller shall save the attribute\&. +.SH "EXAMPLES" +.sp +Clear the FW Activation History for the given Seagate device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate clear\-fw\-activate\-history /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-clear-fw-activate-history.html b/Documentation/nvme-seagate-clear-fw-activate-history.html new file mode 100644 index 0000000000..5502b59a8a --- /dev/null +++ b/Documentation/nvme-seagate-clear-fw-activate-history.html @@ -0,0 +1,799 @@ + + + + + + +nvme-seagate-clear-fw-activate-history (1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate clear-fw-activate-history <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

    The <device> may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1).

    +
    +
    +
    +

    OPTIONS

    +
    +

    -s +--save:: + specifies that the controller shall save the attribute.

    +
    +
    +
    +

    EXAMPLES

    +
    +

    Clear the FW Activation History for the given Seagate device.

    +
    +
    +
    # nvme seagate clear-fw-activate-history /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-clear-fw-activate-history.txt b/Documentation/nvme-seagate-clear-fw-activate-history.txt new file mode 100644 index 0000000000..01f018b76e --- /dev/null +++ b/Documentation/nvme-seagate-clear-fw-activate-history.txt @@ -0,0 +1,37 @@ +nvme-seagate-clear-fw-activate-history (1) +============================================ + +NAME +---- +nvme-seagate-clear-fw-activate-history - Clear the firmware activation history for a given Seagate device. + +SYNOPSIS +-------- +[verse] +'nvme seagate clear-fw-activate-history [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The '' may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-s +--save:: + specifies that the controller shall save the attribute. + +EXAMPLES +-------- +Clear the FW Activation History for the given Seagate device. + +------------ +# nvme seagate clear-fw-activate-history /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-clear-pcie-correctable-errors.1 b/Documentation/nvme-seagate-clear-pcie-correctable-errors.1 new file mode 100644 index 0000000000..8aaf4f5772 --- /dev/null +++ b/Documentation/nvme-seagate-clear-pcie-correctable-errors.1 @@ -0,0 +1,63 @@ +'\" t +.\" Title: nvme-seagate-clear-pcie-correctable-errors +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-CLEAR" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-clear-pcie-correctable-errors \- Clear Seagate PCIe error statistics +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate clear\-pcie\-correctable\-errors [] [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0), or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-s, \-\-save +.RS 4 +Specifies that the controller shall save the attribute +.RE +.SH "EXAMPLES" +.sp +Clears the PCIe error statistics from the device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate clear\-pcie\-correctable\-errors /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-clear-pcie-correctable-errors.html b/Documentation/nvme-seagate-clear-pcie-correctable-errors.html new file mode 100644 index 0000000000..08ef87d734 --- /dev/null +++ b/Documentation/nvme-seagate-clear-pcie-correctable-errors.html @@ -0,0 +1,809 @@ + + + + + + +nvme-seagate-clear-pcie-correctable-errors(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate clear-pcie-correctable-errors [<device>] [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

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

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-s +
    +
    +--save +
    +
    +

    + Specifies that the controller shall save the attribute +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Clears the PCIe error statistics from the device.

    +
    +
    +
    # nvme seagate clear-pcie-correctable-errors /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-clear-pcie-correctable-errors.txt b/Documentation/nvme-seagate-clear-pcie-correctable-errors.txt new file mode 100644 index 0000000000..1239f83f94 --- /dev/null +++ b/Documentation/nvme-seagate-clear-pcie-correctable-errors.txt @@ -0,0 +1,38 @@ +nvme-seagate-clear-pcie-correctable-errors(1) +============================================= + +NAME +---- +nvme-seagate-clear-pcie-correctable-errors - Clear Seagate PCIe error statistics + +SYNOPSIS +-------- +[verse] +'nvme seagate clear-pcie-correctable-errors [] [OPTIONS]' + +DESCRIPTION +----------- + +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The '' parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0), or an +nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-s:: +--save:: + Specifies that the controller shall save the attribute + +EXAMPLES +-------- +Clears the PCIe error statistics from the device. + +------------ +# nvme seagate clear-pcie-correctable-errors /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-cloud-SSD-plugin-version.1 b/Documentation/nvme-seagate-cloud-SSD-plugin-version.1 new file mode 100644 index 0000000000..88f683b193 --- /dev/null +++ b/Documentation/nvme-seagate-cloud-SSD-plugin-version.1 @@ -0,0 +1,58 @@ +'\" t +.\" Title: nvme-seagate-cloud-SSD-plugin-version +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-CLOUD" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-cloud-SSD-plugin-version \- Shows OCP Seagate plugin\*(Aqs version information +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate cloud\-SSD\-plugin\-version\fR +.fi +.SH "DESCRIPTION" +.sp +Shows OCP Seagate plugin\(cqs version information +.SH "OPTIONS" +.sp +No Options +.SH "EXAMPLES" +.sp +Get the OCP plugin version of the specific nvme device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate cloud\-SSD\-plugin\-version +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-cloud-SSD-plugin-version.html b/Documentation/nvme-seagate-cloud-SSD-plugin-version.html new file mode 100644 index 0000000000..e8628add96 --- /dev/null +++ b/Documentation/nvme-seagate-cloud-SSD-plugin-version.html @@ -0,0 +1,794 @@ + + + + + + +nvme-seagate-cloud-SSD-plugin-version (1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate cloud-SSD-plugin-version
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Shows OCP Seagate plugin’s version information

    +
    +
    +
    +

    OPTIONS

    +
    +

    No Options

    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the OCP plugin version of the specific nvme device.

    +
    +
    +
    # nvme seagate cloud-SSD-plugin-version
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-cloud-SSD-plugin-version.txt b/Documentation/nvme-seagate-cloud-SSD-plugin-version.txt new file mode 100644 index 0000000000..f9a92af90a --- /dev/null +++ b/Documentation/nvme-seagate-cloud-SSD-plugin-version.txt @@ -0,0 +1,31 @@ +nvme-seagate-cloud-SSD-plugin-version (1) +========================================= + +NAME +---- +nvme-seagate-cloud-SSD-plugin-version - Shows OCP Seagate plugin's version information + +SYNOPSIS +-------- +[verse] +'nvme seagate cloud-SSD-plugin-version' + +DESCRIPTION +----------- +Shows OCP Seagate plugin's version information + +OPTIONS +------- +No Options + +EXAMPLES +-------- +Get the OCP plugin version of the specific nvme device. + +------------ +# nvme seagate cloud-SSD-plugin-version +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-get-ctrl-tele.1 b/Documentation/nvme-seagate-get-ctrl-tele.1 new file mode 100644 index 0000000000..e4f0af6bf3 --- /dev/null +++ b/Documentation/nvme-seagate-get-ctrl-tele.1 @@ -0,0 +1,68 @@ +'\" t +.\" Title: nvme-seagate-get-ctrl-tele +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-GET\-" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-get-ctrl-tele \- Retrieve Seagate Controller\-Initiated Telemetry in either hex\-dump (default) or binary format +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate get\-ctrl\-tele [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \*(Aq\*(Aqparameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Desired namespace +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +Output in raw format +.RE +.SH "EXAMPLES" +.sp +Get the controller initiated telemetry log in hexdump or binary format for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate get\-ctrl\-tele /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-get-ctrl-tele.html b/Documentation/nvme-seagate-get-ctrl-tele.html new file mode 100644 index 0000000000..6b9e4e3ae9 --- /dev/null +++ b/Documentation/nvme-seagate-get-ctrl-tele.html @@ -0,0 +1,820 @@ + + + + + + +nvme-seagate-get-ctrl-tele(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate get-ctrl-tele <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

    The '<device>'parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1).

    +
    +
    +
    +

    OPTIONS

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

    + Desired namespace +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + Output in raw format +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the controller initiated telemetry log in hexdump or binary format for the specified device.

    +
    +
    +
    # nvme seagate get-ctrl-tele /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-get-ctrl-tele.txt b/Documentation/nvme-seagate-get-ctrl-tele.txt new file mode 100644 index 0000000000..4bb7362eb9 --- /dev/null +++ b/Documentation/nvme-seagate-get-ctrl-tele.txt @@ -0,0 +1,42 @@ +nvme-seagate-get-ctrl-tele(1) +============================= + +NAME +---- +nvme-seagate-get-ctrl-tele - Retrieve Seagate Controller-Initiated Telemetry in +either hex-dump (default) or binary format + +SYNOPSIS +-------- +[verse] +'nvme seagate get-ctrl-tele [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The ''parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-n :: +--namespace-id=:: + Desired namespace + +-b:: +--raw-binary:: + Output in raw format + +EXAMPLES +-------- +Get the controller initiated telemetry log in hexdump or binary format for the specified device. + +------------ +# nvme seagate get-ctrl-tele /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-get-host-tele.1 b/Documentation/nvme-seagate-get-host-tele.1 new file mode 100644 index 0000000000..398c2a4192 --- /dev/null +++ b/Documentation/nvme-seagate-get-host-tele.1 @@ -0,0 +1,73 @@ +'\" t +.\" Title: nvme-seagate-get-host-tele +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-GET\-" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-get-host-tele \- Retrieve Seagate Host\-Initiated Telemetry in either hex\-dump (default) or binary format +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate get\-host\-tele [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +desired namespace +.RE +.PP +\-i , \-\-log_specific= +.RS 4 +1 \- controller shall capture Data representing the internal state of the controller at the time the command is processed\&. 0 \- controller shall not update the Telemetry Host Initiated Data\&. +.RE +.PP +\-b, \-\-raw\-binary +.RS 4 +output in raw format +.RE +.SH "EXAMPLES" +.sp +Get the host initiated telemetry log in hexdump or binary format for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate get\-host\-tele /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-get-host-tele.html b/Documentation/nvme-seagate-get-host-tele.html new file mode 100644 index 0000000000..8549d55cef --- /dev/null +++ b/Documentation/nvme-seagate-get-host-tele.html @@ -0,0 +1,833 @@ + + + + + + +nvme-seagate-get-host-tele(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate get-host-tele <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This will only work on Seagate devices supporting this feature. Not all +commands work across all product families.

    +

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

    +
    +
    +
    +

    OPTIONS

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

    + desired namespace +

    +
    +
    +-i <NUM> +
    +
    +--log_specific=<NUM> +
    +
    +

    + 1 - controller shall capture Data representing the internal state of the + controller at the time the command is processed. + 0 - controller shall not update the Telemetry Host Initiated Data. +

    +
    +
    +-b +
    +
    +--raw-binary +
    +
    +

    + output in raw format +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the host initiated telemetry log in hexdump or binary format for the specified device.

    +
    +
    +
    # nvme seagate get-host-tele /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-get-host-tele.txt b/Documentation/nvme-seagate-get-host-tele.txt new file mode 100644 index 0000000000..83cdefc95a --- /dev/null +++ b/Documentation/nvme-seagate-get-host-tele.txt @@ -0,0 +1,48 @@ +nvme-seagate-get-host-tele(1) +============================= + +NAME +---- +nvme-seagate-get-host-tele - Retrieve Seagate Host-Initiated Telemetry in +either hex-dump (default) or binary format + +SYNOPSIS +-------- +[verse] +'nvme seagate get-host-tele [OPTIONS]' + +DESCRIPTION +----------- +This will only work on Seagate devices supporting this feature. Not all +commands work across all product families. + +The '' parameter is mandatory and may be either an NVMe character device +(ex: /dev/nvme0) or an block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-n :: +--namespace-id=:: + desired namespace + +-i :: +--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. + +-b:: +--raw-binary:: + output in raw format + +EXAMPLES +-------- +Get the host initiated telemetry log in hexdump or binary format for the specified device. + +------------ +# nvme seagate get-host-tele /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-help.1 b/Documentation/nvme-seagate-help.1 new file mode 100644 index 0000000000..3f3a9aa0b4 --- /dev/null +++ b/Documentation/nvme-seagate-help.1 @@ -0,0 +1,85 @@ +'\" t +.\" Title: nvme-seagate-help +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-HELP" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-help \- Shows the Seagate plugin\*(Aqs help information +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate help\fR +.fi +.SH "DESCRIPTION" +.sp +Provides the help information for the Seagate plugin\&. +.SH "OPTIONS" +.sp +No Options +.SH "EXAMPLES" +.sp +Get help information for specific seagate sub\-commands\&. +.PP +Seagate vendor specific extensions +.RS 4 +The following are all implemented sub\-commands: +.sp +.if n \{\ +.RS 4 +.\} +.nf +vs\-temperature\-stats Retrieve Seagate temperature statistics +vs\-log\-page\-sup Retrieve Seagate Supported Log\-pages Information +vs\-smart\-add\-log Retrieve Seagate extended\-SMART Information +vs\-pcie\-stats Retrieve Seagate PCIe error statistics +clear\-pcie\-correctable\-errors Clear Seagate PCIe error statistics +get\-host\-tele Retrieve Seagate Host\-Initiated Telemetry +get\-ctrl\-tele Retrieve Seagate Controller\-Initiated Telemetry +vs\-internal\-log Retrieve Seagate Controller\-Initiated Telemetry in binary format +plugin\-version Shows Seagate plugin\*(Aqs version information +version Shows the program version +help Display this help +.fi +.if n \{\ +.RE +.\} +.RE +.sp +See \fInvme seagate help \fR for more information on a specific command +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate help +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-help.html b/Documentation/nvme-seagate-help.html new file mode 100644 index 0000000000..fba2dc81df --- /dev/null +++ b/Documentation/nvme-seagate-help.html @@ -0,0 +1,819 @@ + + + + + + +nvme-seagate-help(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate help
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Provides the help information for the Seagate plugin.

    +
    +
    +
    +

    OPTIONS

    +
    +

    No Options

    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get help information for specific seagate sub-commands.

    +
    +
    +Seagate vendor specific extensions +
    +
    +

    +The following are all implemented sub-commands: +

    +
    +
    +
    vs-temperature-stats            Retrieve Seagate temperature statistics
    +vs-log-page-sup                 Retrieve Seagate Supported Log-pages Information
    +vs-smart-add-log                Retrieve Seagate extended-SMART Information
    +vs-pcie-stats                   Retrieve Seagate PCIe error statistics
    +clear-pcie-correctable-errors   Clear Seagate PCIe error statistics
    +get-host-tele                   Retrieve Seagate Host-Initiated Telemetry
    +get-ctrl-tele                   Retrieve Seagate Controller-Initiated Telemetry
    +vs-internal-log                 Retrieve Seagate Controller-Initiated Telemetry in binary format
    +plugin-version                  Shows Seagate plugin's version information
    +version                         Shows the program version
    +help                            Display this help
    +
    +
    +
    +

    See nvme seagate help <command> for more information on a specific command

    +
    +
    +
    # nvme seagate help
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-help.txt b/Documentation/nvme-seagate-help.txt new file mode 100644 index 0000000000..0a077a85d9 --- /dev/null +++ b/Documentation/nvme-seagate-help.txt @@ -0,0 +1,49 @@ +nvme-seagate-help(1) +==================== + +NAME +---- +nvme-seagate-help - Shows the Seagate plugin's help information + +SYNOPSIS +-------- +[verse] +'nvme seagate help' + +DESCRIPTION +----------- +Provides the help information for the Seagate plugin. + +OPTIONS +------- +No Options + +EXAMPLES +-------- +Get help information for specific seagate sub-commands. + +Seagate vendor specific extensions:: + +The following are all implemented sub-commands: + + vs-temperature-stats Retrieve Seagate temperature statistics + vs-log-page-sup Retrieve Seagate Supported Log-pages Information + vs-smart-add-log Retrieve Seagate extended-SMART Information + vs-pcie-stats Retrieve Seagate PCIe error statistics + clear-pcie-correctable-errors Clear Seagate PCIe error statistics + get-host-tele Retrieve Seagate Host-Initiated Telemetry + get-ctrl-tele Retrieve Seagate Controller-Initiated Telemetry + vs-internal-log Retrieve Seagate Controller-Initiated Telemetry in binary format + plugin-version Shows Seagate plugin's version information + version Shows the program version + help Display this help + +See 'nvme seagate help ' for more information on a specific command + +------------ +# nvme seagate help +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-plugin-version.1 b/Documentation/nvme-seagate-plugin-version.1 new file mode 100644 index 0000000000..702b64e701 --- /dev/null +++ b/Documentation/nvme-seagate-plugin-version.1 @@ -0,0 +1,58 @@ +'\" t +.\" Title: nvme-seagate-plugin-version +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-PLUGI" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-plugin-version \- Shows Seagate plugin\*(Aqs version information +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate plugin\-version\fR +.fi +.SH "DESCRIPTION" +.sp +Provides the help information for the Seagate plugin\&. +.SH "OPTIONS" +.sp +No Options +.SH "EXAMPLES" +.sp +Get the plugin version of the specific nvme device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate plugin\-version +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-plugin-version.html b/Documentation/nvme-seagate-plugin-version.html new file mode 100644 index 0000000000..d72265a736 --- /dev/null +++ b/Documentation/nvme-seagate-plugin-version.html @@ -0,0 +1,794 @@ + + + + + + +nvme-seagate-plugin-version(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate plugin-version
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Provides the help information for the Seagate plugin.

    +
    +
    +
    +

    OPTIONS

    +
    +

    No Options

    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the plugin version of the specific nvme device.

    +
    +
    +
    # nvme seagate plugin-version
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-plugin-version.txt b/Documentation/nvme-seagate-plugin-version.txt new file mode 100644 index 0000000000..5e4a759e1e --- /dev/null +++ b/Documentation/nvme-seagate-plugin-version.txt @@ -0,0 +1,31 @@ +nvme-seagate-plugin-version(1) +============================== + +NAME +---- +nvme-seagate-plugin-version - Shows Seagate plugin's version information + +SYNOPSIS +-------- +[verse] +'nvme seagate plugin-version' + +DESCRIPTION +----------- +Provides the help information for the Seagate plugin. + +OPTIONS +------- +No Options + +EXAMPLES +-------- +Get the plugin version of the specific nvme device. + +------------ +# nvme seagate plugin-version +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-version.1 b/Documentation/nvme-seagate-version.1 new file mode 100644 index 0000000000..912d94719c --- /dev/null +++ b/Documentation/nvme-seagate-version.1 @@ -0,0 +1,58 @@ +'\" t +.\" Title: nvme-seagate-version +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VERSI" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-version \- Shows the Seagate version information for nvme\-cli +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate version\fR +.fi +.SH "DESCRIPTION" +.sp +Provides the git version information for the Seagate version for nvme\-cli\&. This is for the nvme\-cli tool\&. +.SH "OPTIONS" +.sp +No Options +.SH "EXAMPLES" +.sp +Get the Seagate version information for nvme\-cli\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate version +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-version.html b/Documentation/nvme-seagate-version.html new file mode 100644 index 0000000000..44c996043c --- /dev/null +++ b/Documentation/nvme-seagate-version.html @@ -0,0 +1,794 @@ + + + + + + +nvme-seagate-version(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate version
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Provides the git version information for the Seagate version for nvme-cli. This is for the nvme-cli tool.

    +
    +
    +
    +

    OPTIONS

    +
    +

    No Options

    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the Seagate version information for nvme-cli.

    +
    +
    +
    # nvme seagate version
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-version.txt b/Documentation/nvme-seagate-version.txt new file mode 100644 index 0000000000..2d5c7cefcf --- /dev/null +++ b/Documentation/nvme-seagate-version.txt @@ -0,0 +1,31 @@ +nvme-seagate-version(1) +======================= + +NAME +---- +nvme-seagate-version - Shows the Seagate version information for nvme-cli + +SYNOPSIS +-------- +[verse] +'nvme seagate version' + +DESCRIPTION +----------- +Provides the git version information for the Seagate version for nvme-cli. This is for the nvme-cli tool. + +OPTIONS +------- +No Options + +EXAMPLES +-------- +Get the Seagate version information for nvme-cli. + +------------ +# nvme seagate version +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-vs-fw-activate-history.1 b/Documentation/nvme-seagate-vs-fw-activate-history.1 new file mode 100644 index 0000000000..cf43aa0840 --- /dev/null +++ b/Documentation/nvme-seagate-vs-fw-activate-history.1 @@ -0,0 +1,68 @@ +'\" t +.\" Title: nvme-seagate-vs-fw-activate-history +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VS\-F" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-vs-fw-activate-history \- Retrieve Seagate vendor specific Controller\-Initiated Telemetry in binary +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate vs\-fw\-activate\-history [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Desired namespace +.RE +.PP +\-f , \-\-dump\-file= +.RS 4 +Dump file +.RE +.SH "EXAMPLES" +.sp +Get the Seagate vendor specific Controller\-Initiated telemetry log for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate vs\-fw\-activate\-history /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-vs-fw-activate-history.html b/Documentation/nvme-seagate-vs-fw-activate-history.html new file mode 100644 index 0000000000..a45e9ec30c --- /dev/null +++ b/Documentation/nvme-seagate-vs-fw-activate-history.html @@ -0,0 +1,820 @@ + + + + + + +nvme-seagate-vs-fw-activate-history (1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate vs-fw-activate-history <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

    The <device> may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1).

    +
    +
    +
    +

    OPTIONS

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

    + Desired namespace +

    +
    +
    +-f <FILE> +
    +
    +--dump-file=<FILE> +
    +
    +

    + Dump file +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the Seagate vendor specific Controller-Initiated telemetry log for the specified device.

    +
    +
    +
    # nvme seagate vs-fw-activate-history /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-vs-fw-activate-history.txt b/Documentation/nvme-seagate-vs-fw-activate-history.txt new file mode 100644 index 0000000000..8df58b4623 --- /dev/null +++ b/Documentation/nvme-seagate-vs-fw-activate-history.txt @@ -0,0 +1,42 @@ +nvme-seagate-vs-fw-activate-history (1) +======================================= + +NAME +---- +nvme-seagate-vs-fw-activate-history - Retrieve Seagate vendor specific +Controller-Initiated Telemetry in binary + +SYNOPSIS +-------- +[verse] +'nvme seagate vs-fw-activate-history [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The '' may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-n :: +--namespace-id=:: + Desired namespace + +-f :: +--dump-file=:: + Dump file + +EXAMPLES +-------- +Get the Seagate vendor specific Controller-Initiated telemetry log for the specified device. + +------------ +# nvme seagate vs-fw-activate-history /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-vs-internal-log.1 b/Documentation/nvme-seagate-vs-internal-log.1 new file mode 100644 index 0000000000..18c5a1b6fa --- /dev/null +++ b/Documentation/nvme-seagate-vs-internal-log.1 @@ -0,0 +1,68 @@ +'\" t +.\" Title: nvme-seagate-vs-internal-log +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VS\-I" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-vs-internal-log \- Retrieve Seagate vendor specific Controller\-Initiated Telemetry in binary +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate vs\-internal\-log [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Desired namespace +.RE +.PP +\-f , \-\-dump\-file= +.RS 4 +Dump file +.RE +.SH "EXAMPLES" +.sp +Get the Seagate vendor specific Controller\-Initiated telemetry log for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate vs\-internal\-log /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-vs-internal-log.html b/Documentation/nvme-seagate-vs-internal-log.html new file mode 100644 index 0000000000..9eb5b72ae2 --- /dev/null +++ b/Documentation/nvme-seagate-vs-internal-log.html @@ -0,0 +1,821 @@ + + + + + + +nvme-seagate-vs-internal-log(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate vs-internal-log <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

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

    +
    +
    +
    +

    OPTIONS

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

    + Desired namespace +

    +
    +
    +-f <FILE> +
    +
    +--dump-file=<FILE> +
    +
    +

    + Dump file +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the Seagate vendor specific Controller-Initiated telemetry log for the +specified device.

    +
    +
    +
    # nvme seagate vs-internal-log /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-vs-internal-log.txt b/Documentation/nvme-seagate-vs-internal-log.txt new file mode 100644 index 0000000000..4a895bcb7d --- /dev/null +++ b/Documentation/nvme-seagate-vs-internal-log.txt @@ -0,0 +1,43 @@ +nvme-seagate-vs-internal-log(1) +=============================== + +NAME +---- +nvme-seagate-vs-internal-log - Retrieve Seagate vendor specific +Controller-Initiated Telemetry in binary + +SYNOPSIS +-------- +[verse] +'nvme seagate vs-internal-log [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The '' parameter is mandatory and may be either an NVMe character device +(ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-n :: +--namespace-id=:: + Desired namespace + +-f :: +--dump-file=:: + Dump file + +EXAMPLES +-------- +Get the Seagate vendor specific Controller-Initiated telemetry log for the +specified device. + +------------ +# nvme seagate vs-internal-log /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-vs-log-page-sup.1 b/Documentation/nvme-seagate-vs-log-page-sup.1 new file mode 100644 index 0000000000..470e2b55dd --- /dev/null +++ b/Documentation/nvme-seagate-vs-log-page-sup.1 @@ -0,0 +1,75 @@ +'\" t +.\" Title: nvme-seagate-vs-log-page-sup +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VS\-L" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-vs-log-page-sup \- Retrieve Seagate vendor specific Supported Log\-pages Information +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate vs\-log\-page\-sup [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR may be either an NVMe character device (ex: /dev/nvme0) or an NVMe block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-o , \-\-output\-format= +.RS 4 +Output in binary format +.RE +.SH "EXAMPLES" +.sp +Get the vendor specific log page information for a particular device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate vs\-log\-page\-sup /dev/nvme0 +Output: +Seagate Supported Log\-pages count :8 +LogPage\-Id LogPage\-Name + +0x1 ERROR_INFORMATION +0x2 SMART_INFORMATION +0x3 FW_SLOT_INFORMATION +0x5 COMMANDS_SUPPORTED_AND_EFFECTS +0xC8 VS_RECENT_DRIVE_HISTORY +0xC4 VS_EXTENDED_SMART_INFO +0xC5 VS_LIST_SUPPORTED_LOG_PAGE +0xCB VS_PCIE_ERROR_LOG_PAGE +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-vs-log-page-sup.html b/Documentation/nvme-seagate-vs-log-page-sup.html new file mode 100644 index 0000000000..da0d05baae --- /dev/null +++ b/Documentation/nvme-seagate-vs-log-page-sup.html @@ -0,0 +1,821 @@ + + + + + + +nvme-seagate-vs-log-page-sup(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate vs-log-page-sup <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

    The <device> may be either an NVMe character device (ex: /dev/nvme0) or an +NVMe block device (ex: /dev/nvme0n1).

    +
    +
    +
    +

    OPTIONS

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

    + Output in binary format +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the vendor specific log page information for a particular device.

    +
    +
    +
    # nvme seagate vs-log-page-sup /dev/nvme0
    +Output:
    +Seagate Supported Log-pages count :8
    +LogPage-Id      LogPage-Name
    +
    +0x1              ERROR_INFORMATION
    +0x2              SMART_INFORMATION
    +0x3              FW_SLOT_INFORMATION
    +0x5              COMMANDS_SUPPORTED_AND_EFFECTS
    +0xC8             VS_RECENT_DRIVE_HISTORY
    +0xC4             VS_EXTENDED_SMART_INFO
    +0xC5             VS_LIST_SUPPORTED_LOG_PAGE
    +0xCB             VS_PCIE_ERROR_LOG_PAGE
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-vs-log-page-sup.txt b/Documentation/nvme-seagate-vs-log-page-sup.txt new file mode 100644 index 0000000000..55c65fd13e --- /dev/null +++ b/Documentation/nvme-seagate-vs-log-page-sup.txt @@ -0,0 +1,50 @@ +nvme-seagate-vs-log-page-sup(1) +=============================== + +NAME +---- +nvme-seagate-vs-log-page-sup - Retrieve Seagate vendor specific Supported +Log-pages Information + +SYNOPSIS +-------- +[verse] +'nvme seagate vs-log-page-sup [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The '' may be either an NVMe character device (ex: /dev/nvme0) or an +NVMe block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-o :: +--output-format=:: + Output in binary format + +EXAMPLES +-------- +Get the vendor specific log page information for a particular device. + +------------ +# nvme seagate vs-log-page-sup /dev/nvme0 +Output: +Seagate Supported Log-pages count :8 +LogPage-Id LogPage-Name + +0x1 ERROR_INFORMATION +0x2 SMART_INFORMATION +0x3 FW_SLOT_INFORMATION +0x5 COMMANDS_SUPPORTED_AND_EFFECTS +0xC8 VS_RECENT_DRIVE_HISTORY +0xC4 VS_EXTENDED_SMART_INFO +0xC5 VS_LIST_SUPPORTED_LOG_PAGE +0xCB VS_PCIE_ERROR_LOG_PAGE +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-vs-pcie-stats.1 b/Documentation/nvme-seagate-vs-pcie-stats.1 new file mode 100644 index 0000000000..20650e40b8 --- /dev/null +++ b/Documentation/nvme-seagate-vs-pcie-stats.1 @@ -0,0 +1,63 @@ +'\" t +.\" Title: nvme-seagate-vs-pcie-stats +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VS\-P" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-vs-pcie-stats \- Retrieve Seagate vendor specific PCIe error statistics +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate vs\-pcie\-stats [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \fI\fR parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-o , \-\-output\-format= +.RS 4 +Output in binary format +.RE +.SH "EXAMPLES" +.sp +Get the vendor specific PCIe error statistics for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate vs\-pcie\-stats /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-vs-pcie-stats.html b/Documentation/nvme-seagate-vs-pcie-stats.html new file mode 100644 index 0000000000..7b8d5ec0ea --- /dev/null +++ b/Documentation/nvme-seagate-vs-pcie-stats.html @@ -0,0 +1,809 @@ + + + + + + +nvme-seagate-vs-pcie-stats(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate vs-pcie-stats <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

    The <device> parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1).

    +
    +
    +
    +

    OPTIONS

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

    + Output in binary format +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the vendor specific PCIe error statistics for the specified device.

    +
    +
    +
    # nvme seagate vs-pcie-stats /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-vs-pcie-stats.txt b/Documentation/nvme-seagate-vs-pcie-stats.txt new file mode 100644 index 0000000000..86f87a3d7a --- /dev/null +++ b/Documentation/nvme-seagate-vs-pcie-stats.txt @@ -0,0 +1,38 @@ +nvme-seagate-vs-pcie-stats(1) +============================= + +NAME +---- +nvme-seagate-vs-pcie-stats - Retrieve Seagate vendor specific PCIe error +statistics + +SYNOPSIS +-------- +[verse] +'nvme seagate vs-pcie-stats [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The '' parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-o :: +--output-format=:: + Output in binary format + +EXAMPLES +-------- +Get the vendor specific PCIe error statistics for the specified device. + +------------ +# nvme seagate vs-pcie-stats /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-vs-smart-add-log.1 b/Documentation/nvme-seagate-vs-smart-add-log.1 new file mode 100644 index 0000000000..5a833f563b --- /dev/null +++ b/Documentation/nvme-seagate-vs-smart-add-log.1 @@ -0,0 +1,79 @@ +'\" t +.\" Title: nvme-seagate-vs-smart-add-log +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VS\-S" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-vs-smart-add-log \- Retrieve Seagate vendor specific extended\-SMART Information +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate vs\-smart\-add\-log [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, sends the Seagate vendor log request and either saves the result to a file or dumps the content to stdout\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. +.sp +The log contents may be associated with the controller, in which case the namespace parameter is ignored\&. +.sp +Two logs exist, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page) +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.SH "OPTIONS" +.PP +\-l , \-\-log= +.RS 4 +Log number, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page) +.RE +.PP +\-n , \-\-namespace\-id= +.RS 4 +Namespace number +.RE +.PP +\-o , \-\-output\-file= +.RS 4 +Output in binary format\&. Defaults to text\-formatted dump to stdout +.RE +.SH "EXAMPLES" +.sp +Get the vendor specific extended SMART information for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate vs\-smart\-add\-log /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-vs-smart-add-log.html b/Documentation/nvme-seagate-vs-smart-add-log.html new file mode 100644 index 0000000000..54912cff59 --- /dev/null +++ b/Documentation/nvme-seagate-vs-smart-add-log.html @@ -0,0 +1,837 @@ + + + + + + +nvme-seagate-vs-smart-add-log(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate vs-smart-add-log <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, sends the Seagate vendor log +request and either saves the result to a file or dumps the content to stdout.

    +

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

    +

    The log contents may be associated with the controller, in which case the namespace parameter is ignored.

    +

    Two logs exist, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page)

    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +
    +
    +
    +

    OPTIONS

    +
    +
    +
    +-l <NUM> +
    +
    +--log=<NUM> +
    +
    +

    + Log number, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM + Supercap SMART log page) +

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

    + Namespace number +

    +
    +
    +-o <FILE> +
    +
    +--output-file=<FILE> +
    +
    +

    + Output in binary format. Defaults to text-formatted dump to stdout +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get the vendor specific extended SMART information for the specified device.

    +
    +
    +
    # nvme seagate vs-smart-add-log /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-vs-smart-add-log.txt b/Documentation/nvme-seagate-vs-smart-add-log.txt new file mode 100644 index 0000000000..836220a61e --- /dev/null +++ b/Documentation/nvme-seagate-vs-smart-add-log.txt @@ -0,0 +1,55 @@ +nvme-seagate-vs-smart-add-log(1) +================================ + +NAME +---- +nvme-seagate-vs-smart-add-log - Retrieve Seagate vendor specific extended-SMART +Information + +SYNOPSIS +-------- +[verse] +'nvme seagate vs-smart-add-log [OPTIONS]' + +DESCRIPTION +----------- +For the NVMe device given, sends the Seagate vendor log +request and either saves the result to a file or dumps the content to stdout. + +The parameter is mandatory and may be either the NVMe +character device (ex: /dev/nvme0), or a namespace block device (ex: +/dev/nvme0n1). + +The log contents may be associated with the controller, in which case the namespace parameter is ignored. + +Two logs exist, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page) + +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +OPTIONS +------- +-l :: +--log=:: + Log number, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM + Supercap SMART log page) + +-n :: +--namespace-id=:: + Namespace number + +-o :: +--output-file=:: + Output in binary format. Defaults to text-formatted dump to stdout + +EXAMPLES +-------- +Get the vendor specific extended SMART information for the specified device. + +------------ +# nvme seagate vs-smart-add-log /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-seagate-vs-temperature-stats.1 b/Documentation/nvme-seagate-vs-temperature-stats.1 new file mode 100644 index 0000000000..0de2ec12f6 --- /dev/null +++ b/Documentation/nvme-seagate-vs-temperature-stats.1 @@ -0,0 +1,63 @@ +'\" t +.\" Title: nvme-seagate-vs-temperature-stats +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SEAGATE\-VS\-T" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-seagate-vs-temperature-stats \- Retrieve Seagate vendor specific temperature statistics +.SH "SYNOPSIS" +.sp +.nf +\fInvme seagate vs\-temperature\-stats [OPTIONS]\fR +.fi +.SH "DESCRIPTION" +.sp +This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&. +.sp +The \*(Aq\*(Aqparameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&. +.SH "OPTIONS" +.PP +\-o , \-\-output\-format= +.RS 4 +Output in binary format +.RE +.SH "EXAMPLES" +.sp +Get vendor specific temperature statistics for the specified device\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme seagate vs\-temperature\-stats /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-seagate-vs-temperature-stats.html b/Documentation/nvme-seagate-vs-temperature-stats.html new file mode 100644 index 0000000000..22f13c4a48 --- /dev/null +++ b/Documentation/nvme-seagate-vs-temperature-stats.html @@ -0,0 +1,809 @@ + + + + + + +nvme-seagate-vs-temperature-stats(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme seagate vs-temperature-stats <device> [OPTIONS]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families.

    +

    The '<device>'parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1).

    +
    +
    +
    +

    OPTIONS

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

    + Output in binary format +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    Get vendor specific temperature statistics for the specified device.

    +
    +
    +
    # nvme seagate vs-temperature-stats /dev/nvme0
    +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-seagate-vs-temperature-stats.txt b/Documentation/nvme-seagate-vs-temperature-stats.txt new file mode 100644 index 0000000000..58a9f116d6 --- /dev/null +++ b/Documentation/nvme-seagate-vs-temperature-stats.txt @@ -0,0 +1,38 @@ +nvme-seagate-vs-temperature-stats(1) +==================================== + +NAME +---- +nvme-seagate-vs-temperature-stats - Retrieve Seagate vendor specific +temperature statistics + +SYNOPSIS +-------- +[verse] +'nvme seagate vs-temperature-stats [OPTIONS]' + +DESCRIPTION +----------- +This command will only work on Seagate devices supporting this feature. Not +all commands work across all product families. + +The ''parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an +nvme block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-o :: +--output-format=:: + Output in binary format + +EXAMPLES +-------- +Get vendor specific temperature statistics for the specified device. + +------------ +# nvme seagate vs-temperature-stats /dev/nvme0 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-security-recv.1 b/Documentation/nvme-security-recv.1 index 5e9af12be6..21503cbbed 100644 --- a/Documentation/nvme-security-recv.1 +++ b/Documentation/nvme-security-recv.1 @@ -2,12 +2,12 @@ .\" Title: nvme-security-recv .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SECURITY\-RECV" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SECURITY\-RECV" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,12 +33,12 @@ nvme-security-recv \- Security Recv command .sp .nf \fInvme security\-recv\fR [\-\-size= | \-x ] - [\-\-secp= | \-p ] - [\-\-spsp= | \-s ] - [\-\-nssf= | \-N ] - [\-\-al= | \-t ] - [\-\-namespace\-id= | \-n ] - [\-\-raw\-binary | \-b] + [\-\-secp= | \-p ] + [\-\-spsp= | \-s ] + [\-\-nssf= | \-N ] + [\-\-al= | \-t ] + [\-\-namespace\-id= | \-n ] [\-\-raw\-binary | \-b] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -83,6 +83,20 @@ Allocation Length: The value of this field is specific to the Security Protocol .RS 4 Print the raw buffer to stdout\&. Defaults to print in hex\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No Examples diff --git a/Documentation/nvme-security-recv.html b/Documentation/nvme-security-recv.html index 22adf1ef75..58da38d576 100644 --- a/Documentation/nvme-security-recv.html +++ b/Documentation/nvme-security-recv.html @@ -750,12 +750,12 @@

    SYNOPSIS

    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]
    + [--secp=<security-protocol> | -p <security-protocol>] + [--spsp=<protocol-specific> | -s <protocol-specific>] + [--nssf=<nvme-specific> | -N <nvme-specific>] + [--al=<allocation-length> | -t <allocation-length>] + [--namespace-id=<nsid> | -n <nsid>] [--raw-binary | -b] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -866,6 +866,29 @@

    OPTIONS

    Print the raw buffer to stdout. Defaults to print in hex.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -886,7 +909,7 @@

    NVME

    diff --git a/Documentation/nvme-security-recv.txt b/Documentation/nvme-security-recv.txt index 0b9fe99cc6..ef77531216 100644 --- a/Documentation/nvme-security-recv.txt +++ b/Documentation/nvme-security-recv.txt @@ -9,12 +9,12 @@ SYNOPSIS -------- [verse] 'nvme security-recv' [--size= | -x ] - [--secp= | -p ] - [--spsp= | -s ] - [--nssf= | -N ] - [--al= | -t ] - [--namespace-id= | -n ] - [--raw-binary | -b] + [--secp= | -p ] + [--spsp= | -s ] + [--nssf= | -N ] + [--al= | -t ] + [--namespace-id= | -n ] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -71,6 +71,15 @@ OPTIONS --raw-binary:: Print the raw buffer to stdout. Defaults to print in hex. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No Examples diff --git a/Documentation/nvme-security-send.1 b/Documentation/nvme-security-send.1 index f4e45833e0..d463f85982 100644 --- a/Documentation/nvme-security-send.1 +++ b/Documentation/nvme-security-send.1 @@ -2,12 +2,12 @@ .\" Title: nvme-security-send .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SECURITY\-SEND" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SECURITY\-SEND" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,11 +33,12 @@ nvme-security-send \- Security Send command .sp .nf \fInvme security\-send\fR [\-\-file= | \-f ] - [\-\-secp= | \-p ] - [\-\-spsp= | \-s ] - [\-\-tl= | \-t ] - [\-\-nssf= | \-N ] - [\-\-namespace\-id= | \-n ] + [\-\-secp= | \-p ] + [\-\-spsp= | \-s ] + [\-\-tl= | \-t ] + [\-\-nssf= | \-N ] + [\-\-namespace\-id= | \-n ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -75,6 +76,20 @@ SP Specific: The value of this field is specific to the Security Protocol as def .RS 4 Transfer Length: The value of this field is specific to the Security Protocol as defined in SPC\-4\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No Examples diff --git a/Documentation/nvme-security-send.html b/Documentation/nvme-security-send.html index b468950a65..4ff43d9d35 100644 --- a/Documentation/nvme-security-send.html +++ b/Documentation/nvme-security-send.html @@ -750,11 +750,12 @@

    SYNOPSIS

    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>]
    + [--secp=<security-protocol> | -p <security-protocol>] + [--spsp=<protocol-specific> | -s <protocol-specific>] + [--tl=<transfer-length> | -t <transfer-length>] + [--nssf=<nvme-specific> | -N <nvme-specific>] + [--namespace-id=<nsid> | -n <nsid>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -852,6 +853,29 @@

    OPTIONS

    Security Protocol as defined in SPC-4.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -872,7 +896,7 @@

    NVME

    diff --git a/Documentation/nvme-security-send.txt b/Documentation/nvme-security-send.txt index ae226281a7..347b9701fc 100644 --- a/Documentation/nvme-security-send.txt +++ b/Documentation/nvme-security-send.txt @@ -9,11 +9,12 @@ SYNOPSIS -------- [verse] 'nvme security-send' [--file= | -f ] - [--secp= | -p ] - [--spsp= | -s ] - [--tl= | -t ] - [--nssf= | -N ] - [--namespace-id= | -n ] + [--secp= | -p ] + [--spsp= | -s ] + [--tl= | -t ] + [--nssf= | -N ] + [--namespace-id= | -n ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -63,6 +64,15 @@ OPTIONS Transfer Length: The value of this field is specific to the Security Protocol as defined in SPC-4. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No Examples diff --git a/Documentation/nvme-self-test-log.1 b/Documentation/nvme-self-test-log.1 index 0a2f6e8242..0fe2ec5989 100644 --- a/Documentation/nvme-self-test-log.1 +++ b/Documentation/nvme-self-test-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-self-test-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SELF\-TEST\-LO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SELF\-TEST\-LO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,7 +33,7 @@ nvme-self-test-log \- Retrieve the log information initiated by device\-self\-te .sp .nf \fInvme self\-test\fR\-log [\-\-log\-entries= | \-e ] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -51,13 +51,19 @@ By default the log is printed out in the normal readable format\&. Specifies how many DST log entries the program should request from the device\&. This must be at least one, and shouldn\(cqt exceed the 20 entries\&. Defaults to 20 DST log entries\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-self-test-log.html b/Documentation/nvme-self-test-log.html index 6343bdf775..4945aa6a16 100644 --- a/Documentation/nvme-self-test-log.html +++ b/Documentation/nvme-self-test-log.html @@ -750,7 +750,7 @@

    SYNOPSIS

    nvme self-test-log <device> [--log-entries=<entries> | -e <entries>]
    -                    [--output-format=<FMT> | -o <FMT>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -788,15 +788,26 @@

    OPTION

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

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

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

    + Increase the information detail in the output.

    @@ -847,7 +858,7 @@

    NVME

    diff --git a/Documentation/nvme-self-test-log.txt b/Documentation/nvme-self-test-log.txt index 56a3c4ac60..d4600e8ae4 100644 --- a/Documentation/nvme-self-test-log.txt +++ b/Documentation/nvme-self-test-log.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme self-test'-log [--log-entries= | -e ] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -35,11 +35,14 @@ OPTION the device. This must be at least one, and shouldn't exceed the 20 entries. Defaults to 20 DST log entries. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-set-feature.1 b/Documentation/nvme-set-feature.1 index 841b684e82..5b635c72fe 100644 --- a/Documentation/nvme-set-feature.1 +++ b/Documentation/nvme-set-feature.1 @@ -2,12 +2,12 @@ .\" Title: nvme-set-feature .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SET\-FEATURE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SET\-FEATURE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,11 +33,11 @@ nvme-set-feature \- Sets an NVMe feature, returns applicable results .sp .nf \fInvme set\-feature\fR [\-\-namespace\-id= | \-n ] - [\-\-feature\-id= | \-f ] [\-\-value= | \-v ] - [\-\-uuid\-index= | \-U ] - [\-\-data\-len= | \-l ] - [\-\-data= | \-d ] - [\-\-save| \-s] + [\-\-feature\-id= | \-f ] [\-\-value= | \-V ] + [\-\-uuid\-index= | \-U ] + [\-\-data\-len= | \-l ] + [\-\-data= | \-d ] [\-\-save | \-s] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -68,7 +68,7 @@ The data length for the buffer submitted for this feature\&. Most known features 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= +\-V , \-\-value= .RS 4 The value for command dword 11, the value you want to set the feature to\&. .RE @@ -82,6 +82,20 @@ Save the attribute so that it persists through all power states and resets\&. .RS 4 UUID Index of the feature .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 @@ -98,7 +112,7 @@ Sets the Power State (PS) to 1 in feature id 2: .RS 4 .\} .nf -# nvme set\-feature /dev/nvme0 \-f 2 /dev/nvme0n1 \-v 0x1 +# nvme set\-feature /dev/nvme0 \-f 2 /dev/nvme0n1 \-V 0x1 .fi .if n \{\ .RE diff --git a/Documentation/nvme-set-feature.html b/Documentation/nvme-set-feature.html index 67dc354367..7da6fae2b0 100644 --- a/Documentation/nvme-set-feature.html +++ b/Documentation/nvme-set-feature.html @@ -750,11 +750,11 @@

    SYNOPSIS

    nvme set-feature <device> [--namespace-id=<nsid> | -n <nsid>]
    -                          [--feature-id=<fid> | -f <fid>] [--value=<value> | -v <value>]
    -                          [--uuid-index=<uuid-index> | -U <uuid_index>]
    -                          [--data-len=<data-len> | -l <data-len>]
    -                          [--data=<data-file> | -d <data-file>]
    -                          [--save| -s]
    + [--feature-id=<fid> | -f <fid>] [--value=<value> | -V <value>] + [--uuid-index=<uuid-index> | -U <uuid_index>] + [--data-len=<data-len> | -l <data-len>] + [--data=<data-file> | -d <data-file>] [--save | -s] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -826,7 +826,7 @@

    OPTIONS

    --v <value> +-V <value>
    --value=<value> @@ -859,6 +859,29 @@

    OPTIONS

    UUID Index of the feature

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -868,11 +891,11 @@

    EXAMPLES

    • -Sets the Power State (PS) to 1 in feature id 2: +Sets the Power State (PS) to 1 in feature id 2:

      -
      # nvme set-feature /dev/nvme0 -f 2 /dev/nvme0n1 -v 0x1
      +
      # nvme set-feature /dev/nvme0 -f 2 /dev/nvme0n1 -V 0x1
    • @@ -899,7 +922,7 @@

      NVME

      diff --git a/Documentation/nvme-set-feature.txt b/Documentation/nvme-set-feature.txt index 24a9f40955..a36385e309 100644 --- a/Documentation/nvme-set-feature.txt +++ b/Documentation/nvme-set-feature.txt @@ -9,11 +9,12 @@ SYNOPSIS -------- [verse] 'nvme set-feature' [--namespace-id= | -n ] - [--feature-id= | -f ] [--value= | -v ] - [--uuid-index= | -U ] - [--data-len= | -l ] - [--data= | -d ] - [--save| -s] + [--feature-id= | -f ] [--value= | -V ] + [--uuid-index= | -U ] + [--data-len= | -l ] + [--data= | -d ] [--save | -s] + [--output-format= | -o ] [--verbose | -v] + [--cdw12= | -c ] DESCRIPTION ----------- @@ -51,25 +52,38 @@ OPTIONS Range Type and host identifier. This defaults to STDIN so files and echo can be piped. --v :: +-V :: --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. + Save the attribute so that it persists through all power states and resets. -U :: --uuid-index=:: UUID Index of the feature +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +-c :: +--cdw12=:: + The value for command dword 12, if applicable. + EXAMPLES -------- -* Sets the Power State (PS) to 1 in feature id 2: +* Sets the Power State (PS) to 1 in feature id 2: + ------------ -# nvme set-feature /dev/nvme0 -f 2 /dev/nvme0n1 -v 0x1 +# nvme set-feature /dev/nvme0 -f 2 /dev/nvme0n1 -V 0x1 ------------ + diff --git a/Documentation/nvme-set-property.1 b/Documentation/nvme-set-property.1 index 2dc3510d52..b66fa30364 100644 --- a/Documentation/nvme-set-property.1 +++ b/Documentation/nvme-set-property.1 @@ -2,12 +2,12 @@ .\" Title: nvme-set-property .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SET\-PROPERTY" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SET\-PROPERTY" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,23 +32,38 @@ nvme-set-property \- Writes and shows the defined NVMe controller property for N .SH "SYNOPSIS" .sp .nf -\fInvme set\-property\fR [\-\-offset= | \-o ] - [\-\-value= | \-v ] +\fInvme set\-property\fR [\-\-offset= | \-O ] + [\-\-value= | \-V ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Writes and shows the defined NVMe controller property for NVMe over Fabric\&. .SH "OPTIONS" .PP -\-o, \-\-offset +\-O, \-\-offset .RS 4 The offset of the property\&. .RE .PP -\-v +\-V .RS 4 \-\-value: The value of the property to be set\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples (yet)\&. diff --git a/Documentation/nvme-set-property.html b/Documentation/nvme-set-property.html index 7166ab60de..88bda56313 100644 --- a/Documentation/nvme-set-property.html +++ b/Documentation/nvme-set-property.html @@ -749,8 +749,9 @@

      NAME

      SYNOPSIS

      -
      nvme set-property <device> [--offset=<offset> | -o <offset>]
      -                                [--value=<val> | -v <val>]
      +
      nvme set-property <device> [--offset=<offset> | -O <offset>]
      +                        [--value=<val> | -V <val>]
      +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
      @@ -766,18 +767,18 @@

      OPTIONS

      --o +-O
      --offset

      - The offset of the property. + The offset of the property.

      --v +-V

      @@ -785,6 +786,29 @@

      OPTIONS

      The value of the property to be set.

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

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

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

      + Increase the information detail in the output. +

      +
    @@ -805,7 +829,7 @@

    NVME

    diff --git a/Documentation/nvme-set-property.txt b/Documentation/nvme-set-property.txt index ba90fd3b0e..578503724a 100644 --- a/Documentation/nvme-set-property.txt +++ b/Documentation/nvme-set-property.txt @@ -9,9 +9,9 @@ for NVMe over Fabric SYNOPSIS -------- [verse] -'nvme set-property' [--offset= | -o ] - [--value= | -v ] - +'nvme set-property' [--offset= | -O ] + [--value= | -V ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -19,14 +19,23 @@ Writes and shows the defined NVMe controller property for NVMe over Fabric. OPTIONS ------- --o:: ---offset:: - The offset of the property. +-O :: +--offset=:: + The offset of the property. --v:: ---value: +-V :: +--value=:: The value of the property to be set. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples (yet). diff --git a/Documentation/nvme-show-hostnqn.1 b/Documentation/nvme-show-hostnqn.1 index d079005acf..618ad0fdbc 100644 --- a/Documentation/nvme-show-hostnqn.1 +++ b/Documentation/nvme-show-hostnqn.1 @@ -2,12 +2,12 @@ .\" Title: nvme-show-hostnqn .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SHOW\-HOSTNQN" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SHOW\-HOSTNQN" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -28,18 +28,30 @@ .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" -nvme-show-hostnqn \- Generate a host NVMe Qualified Name +nvme-show-hostnqn \- Show the host NQN configured for the system .SH "SYNOPSIS" .sp .nf -\fInvme show\-hostnqn\fR +\fInvme show\-hostnqn\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .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\&. +Show the host NQN configured for the system\&. If /usr/local/etc/nvme/hostnqn is not present and systemd application\-specific machine IDs are available, this will show the systemd\-generated host NQN for the system\&. .SH "OPTIONS" -.sp -No options needed +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp nvme show\-hostnqn diff --git a/Documentation/nvme-show-hostnqn.html b/Documentation/nvme-show-hostnqn.html index 22fdfa1ac4..c948837796 100644 --- a/Documentation/nvme-show-hostnqn.html +++ b/Documentation/nvme-show-hostnqn.html @@ -740,7 +740,7 @@

    NAME

    nvme-show-hostnqn - - Generate a host NVMe Qualified Name + Show the host NQN configured for the system

    @@ -749,7 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme show-hostnqn
    +
    nvme show-hostnqn [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -757,7 +757,7 @@

    SYNOPSIS

    DESCRIPTION

    -

    Show the host NQN configured for the system. If /etc/nvme/hostnqn is +

    Show the host NQN configured for the system. If /usr/local/etc/nvme/hostnqn is not present and systemd application-specific machine IDs are available, this will show the systemd-generated host NQN for the system.

    @@ -765,7 +765,31 @@

    DESCRIPTION

    OPTIONS

    -

    No options needed

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

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

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

    + Increase the information detail in the output. +

    +
    +
    @@ -785,7 +809,7 @@

    NVME

    diff --git a/Documentation/nvme-show-hostnqn.txt b/Documentation/nvme-show-hostnqn.txt index 58263d8609..5074e2c8e9 100644 --- a/Documentation/nvme-show-hostnqn.txt +++ b/Documentation/nvme-show-hostnqn.txt @@ -3,22 +3,29 @@ nvme-show-hostnqn(1) NAME ---- -nvme-show-hostnqn - Generate a host NVMe Qualified Name +nvme-show-hostnqn - Show the host NQN configured for the system SYNOPSIS -------- [verse] -'nvme show-hostnqn' +'nvme show-hostnqn' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- -Show the host NQN configured for the system. If @SYSCONFDIR@/nvme/hostnqn is +Show the host NQN configured for the system. If @SYSCONFDIR@/nvme/hostnqn is not present and systemd application-specific machine IDs are available, this will show the systemd-generated host NQN for the system. OPTIONS ------- -No options needed +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-show-regs.1 b/Documentation/nvme-show-regs.1 index 714f47e9cd..115a00da15 100644 --- a/Documentation/nvme-show-regs.1 +++ b/Documentation/nvme-show-regs.1 @@ -2,12 +2,12 @@ .\" Title: nvme-id-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,8 @@ nvme-show-regs \- Reads and shows the defined NVMe controller registers for NVMe .SH "SYNOPSIS" .sp .nf -\fInvme show\-regs\fR [\-\-human\-readable | \-H] - [\-\-output\-format= | \-o ] +\fInvme show\-regs\fR [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -47,13 +47,19 @@ The parameter is mandatory and must be the nvme admin character device Display registers or supported properties in human readable format\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-show-regs.html b/Documentation/nvme-show-regs.html index 1ff71b5944..0fbe431aa6 100644 --- a/Documentation/nvme-show-regs.html +++ b/Documentation/nvme-show-regs.html @@ -749,8 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme show-regs <device>       [--human-readable | -H]
    -                                [--output-format=<FMT> | -o <FMT>]
    +
    nvme show-regs <device> [--human-readable | -H]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -782,19 +782,30 @@

    OPTIONS

    - Display registers or supported properties in human readable format. + Display registers or supported properties in human readable format.

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

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

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

    + Increase the information detail in the output.

    @@ -848,7 +859,7 @@

    NVME

    diff --git a/Documentation/nvme-show-regs.txt b/Documentation/nvme-show-regs.txt index 892b394438..0460365f7e 100644 --- a/Documentation/nvme-show-regs.txt +++ b/Documentation/nvme-show-regs.txt @@ -9,8 +9,8 @@ NVMe over PCIe or the controller properties for NVMe over Fabrics. SYNOPSIS -------- [verse] -'nvme show-regs' [--human-readable | -H] - [--output-format= | -o ] +'nvme show-regs' [--human-readable | -H] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -30,12 +30,16 @@ OPTIONS ------- -H:: --human-readable:: - Display registers or supported properties in human readable format. + Display registers or supported properties in human readable format. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-show-topology.1 b/Documentation/nvme-show-topology.1 new file mode 100644 index 0000000000..cde2d83498 --- /dev/null +++ b/Documentation/nvme-show-topology.1 @@ -0,0 +1,84 @@ +'\" t +.\" Title: nvme-show-topology +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 02/14/2024 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-SHOW\-TOPOLOGY" "1" "02/14/2024" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-show-topology \- Show topology of all NVMe subsystems +.SH "SYNOPSIS" +.sp +.nf +\fInvme show\-topology\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] +.fi +.SH "DESCRIPTION" +.sp +Show the topology of all NVMe subsystems\&. +.SH "OPTIONS" +.PP +\-o , \-\-output\-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 related to each other\&. +.RE +.PP +\-r , \-\-ranking= +.RS 4 +Set the ranking orer to +\fInamespace\fR +(default) or +\fIctrl\fR\&. This option has only an effect for output format +\fInormal\fR\&. The JSON output is always +\fInamespace\fR +ordered\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE +.SH "EXAMPLES" +.sp +nvme show\-topology +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-show-topology.html b/Documentation/nvme-show-topology.html new file mode 100644 index 0000000000..51196dbc09 --- /dev/null +++ b/Documentation/nvme-show-topology.html @@ -0,0 +1,852 @@ + + + + + + +nvme-show-topology(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme show-topology [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    Show the topology of all NVMe subsystems.

    +
    +
    +
    +

    OPTIONS

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

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

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

    + Increase the information in the output, showing nvme subsystems, + controllers and namespaces separately and how they’re related to each + other. +

    +
    +
    +-r <order> +
    +
    +--ranking=<order> +
    +
    +

    + Set the ranking orer to namespace (default) or ctrl. This option + has only an effect for output format normal. The JSON output is + always namespace ordered. +

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

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

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

    + Increase the information detail in the output. +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    nvme show-topology

    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-show-topology.txt b/Documentation/nvme-show-topology.txt new file mode 100644 index 0000000000..32ffad1e75 --- /dev/null +++ b/Documentation/nvme-show-topology.txt @@ -0,0 +1,51 @@ +nvme-show-topology(1) +===================== + +NAME +---- +nvme-show-topology - Show topology of all NVMe subsystems + +SYNOPSIS +-------- +[verse] +'nvme show-topology' [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Show the topology of all NVMe subsystems. + +OPTIONS +------- +-o :: +--output-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 related to each + other. + +-r :: +--ranking=:: + Set the ranking orer to 'namespace' (default) or 'ctrl'. This option + has only an effect for output format 'normal'. The JSON output is + always 'namespace' ordered. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +nvme show-topology + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-smart-log.1 b/Documentation/nvme-smart-log.1 index c75bda01f4..abb0ed734b 100644 --- a/Documentation/nvme-smart-log.1 +++ b/Documentation/nvme-smart-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-smart-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SMART\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SMART\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,7 +34,7 @@ nvme-smart-log \- Send NVMe SMART log page request, returns result and log .nf \fInvme smart\-log\fR [\-\-namespace\-id= | \-n ] [\-\-raw\-binary | \-b] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,13 +55,19 @@ Retrieve the SMART log for the given nsid\&. This is optional and its success ma Print the raw SMART log buffer to stdout\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, -\fIjson\fR, or +\fIjson\fR +or \fIbinary\fR\&. Only one output format can be used at a time\&. .RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-smart-log.html b/Documentation/nvme-smart-log.html index de628f1a39..989675da4c 100644 --- a/Documentation/nvme-smart-log.html +++ b/Documentation/nvme-smart-log.html @@ -751,7 +751,7 @@

    SYNOPSIS

    nvme smart-log <device> [--namespace-id=<nsid> | -n <nsid>]
                             [--raw-binary | -b]
    -                        [--output-format=<fmt> | -o <fmt>]
    + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -799,15 +799,26 @@

    OPTIONS

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

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

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

    + Increase the information detail in the output.

    @@ -850,7 +861,7 @@

    NVME

    diff --git a/Documentation/nvme-smart-log.txt b/Documentation/nvme-smart-log.txt index 77d0015133..c08f523cb2 100644 --- a/Documentation/nvme-smart-log.txt +++ b/Documentation/nvme-smart-log.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'nvme smart-log' [--namespace-id= | -n ] [--raw-binary | -b] - [--output-format= | -o ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -38,10 +38,14 @@ OPTIONS --raw-binary:: Print the raw SMART log buffer to stdout. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-subsystem-reset.1 b/Documentation/nvme-subsystem-reset.1 index 476592da16..7bdae5bcee 100644 --- a/Documentation/nvme-subsystem-reset.1 +++ b/Documentation/nvme-subsystem-reset.1 @@ -2,12 +2,12 @@ .\" Title: nvme-subsystem-reset .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SUBSYSTEM\-RES" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SUBSYSTEM\-RES" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,13 +33,26 @@ nvme-subsystem-reset \- Reset the nvme subsystem\&. .sp .nf \fInvme subsystem\-reset\fR + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp Requests NVMe subsystem reset\&. The param is mandatory and must be an NVMe character device (ex: /dev/nvme0)\&. .SH "OPTIONS" -.sp -None +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-subsystem-reset.html b/Documentation/nvme-subsystem-reset.html index 0270817cdd..4847ad4c39 100644 --- a/Documentation/nvme-subsystem-reset.html +++ b/Documentation/nvme-subsystem-reset.html @@ -749,7 +749,8 @@

    NAME

    SYNOPSIS

    -
    nvme subsystem-reset <device>
    +
    nvme subsystem-reset <device>
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -764,7 +765,31 @@

    DESCRIPTION

    OPTIONS

    -

    None

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

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

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

    + Increase the information detail in the output. +

    +
    +
    @@ -794,7 +819,7 @@

    NVME

    diff --git a/Documentation/nvme-subsystem-reset.txt b/Documentation/nvme-subsystem-reset.txt index 2267acddb7..cc3a139fc7 100644 --- a/Documentation/nvme-subsystem-reset.txt +++ b/Documentation/nvme-subsystem-reset.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'nvme subsystem-reset' + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -17,7 +18,14 @@ be an NVMe character device (ex: /dev/nvme0). OPTIONS ------- -None +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-supported-cap-config-log.txt b/Documentation/nvme-supported-cap-config-log.txt index 00506340e3..b60303bcbf 100644 --- a/Documentation/nvme-supported-cap-config-log.txt +++ b/Documentation/nvme-supported-cap-config-log.txt @@ -9,9 +9,8 @@ Configuration List Log pages request, returns result and log. SYNOPSIS -------- [verse] -'nvme supported-cap-config-log' [--dom-id | -d ] - [--output-format= | -o ] - [--raw-binary | -b] +'nvme supported-cap-config-log' [--dom-id | -d] [--raw-binary | -b] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -27,19 +26,23 @@ pages log structure will be printed. OPTIONS ------- - --o :: ---output-format=:: - This option will set the reporting format to normal, json, or binary. - Only one output format can be used at a time. - -d:: --dom-id:: - To get the domain ID. + To get the domain ID. + -b:: --raw-binary:: To show raw binary data. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- No examples provided yet. diff --git a/Documentation/nvme-supported-log-pages.1 b/Documentation/nvme-supported-log-pages.1 index b6944a7768..4d2574f612 100644 --- a/Documentation/nvme-supported-log-pages.1 +++ b/Documentation/nvme-supported-log-pages.1 @@ -2,12 +2,12 @@ .\" Title: nvme-supported-log-pages .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SUPPORTED\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-SUPPORTED\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,7 @@ nvme-supported-log-pages \- Send NVMe Supported Log pages request, returns resul .SH "SYNOPSIS" .sp .nf -\fInvme supported\-log\-pages\fR [\-\-output\-format= | \-o ] - [\-\-human\-readable | \-H] +\fInvme supported\-log\-pages\fR [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -44,14 +43,18 @@ The parameter is mandatory and should be the NVMe character device (ex: On success, the returned supported log pages log structure will be printed for each command that is supported\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-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\&. +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 +\-v, \-\-verbose .RS 4 -This option will parse and format many of the bit fields into a human\-readable format\&. +Increase the information detail in the output\&. Show more information including LID Supported (LSUPP) and Index Offset Supported (IOP) details\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-supported-log-pages.html b/Documentation/nvme-supported-log-pages.html index 5b2b63a03f..5073a61dfe 100644 --- a/Documentation/nvme-supported-log-pages.html +++ b/Documentation/nvme-supported-log-pages.html @@ -749,8 +749,7 @@

    NAME

    SYNOPSIS

    -
    nvme supported-log-pages <device> [--output-format=<fmt> | -o <fmt>]
    -                            [--human-readable | -H]
    +
    nvme supported-log-pages <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -771,27 +770,27 @@

    OPTIONS

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

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

    --H +-v
    ---human-readable +--verbose

    - This option will parse and format many of the bit fields into a - human-readable format. + Increase the information detail in the output. Show more information + including LID Supported (LSUPP) and Index Offset Supported (IOP) details.

    @@ -814,7 +813,7 @@

    NVME

    diff --git a/Documentation/nvme-supported-log-pages.txt b/Documentation/nvme-supported-log-pages.txt index 32f95fec53..bd17fdf328 100644 --- a/Documentation/nvme-supported-log-pages.txt +++ b/Documentation/nvme-supported-log-pages.txt @@ -8,8 +8,7 @@ nvme-supported-log-pages - Send NVMe Supported Log pages request, returns result SYNOPSIS -------- [verse] -'nvme supported-log-pages' [--output-format= | -o ] - [--human-readable | -H] +'nvme supported-log-pages' [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -25,15 +24,15 @@ for each command that is supported. OPTIONS ------- --o :: ---output-format=:: - This option will set the reporting format to normal, json, or binary. - Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. --H:: ---human-readable:: - This option will parse and format many of the bit fields into a - human-readable format. +-v:: +--verbose:: + Increase the information detail in the output. Show more information + including LID Supported (LSUPP) and Index Offset Supported (IOP) details. EXAMPLES -------- @@ -41,4 +40,4 @@ No examples provided yet. NVME ---- -Part of the nvme-user suite \ No newline at end of file +Part of the nvme-user suite diff --git a/Documentation/nvme-telemetry-log.1 b/Documentation/nvme-telemetry-log.1 index 7ab19d05f7..4522c5b9df 100644 --- a/Documentation/nvme-telemetry-log.1 +++ b/Documentation/nvme-telemetry-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-telemetry-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-TELEMETRY\-LOG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-TELEMETRY\-LOG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,9 @@ nvme-telemetry-log \- Retrieves a Telemetry Host\-Initiated log page from an NVM .SH "SYNOPSIS" .sp .nf -\fInvme telemetry\-log\fR [\-\-output\-file= | \-o ] - [\-\-host\-generate= | \-g ] +\fInvme telemetry\-log\fR [\-\-output\-file= | \-O ] + [\-\-host\-generate= | \-g ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -44,7 +45,7 @@ The parameter is mandatory and may be either the NVMe character device 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 , \-\-output\-file= +\-O , \-\-output\-file= .RS 4 File name to which raw binary data will be saved to\&. .RE @@ -60,6 +61,20 @@ update this data\&. .RS 4 Retrieves the specific data area requested\&. Valid inputs are 1,2,3,4\&. If this option is not specified, the default value is 3, since data area 4 may not be supported\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-telemetry-log.html b/Documentation/nvme-telemetry-log.html index 9716064b18..7d5f95ced9 100644 --- a/Documentation/nvme-telemetry-log.html +++ b/Documentation/nvme-telemetry-log.html @@ -749,8 +749,9 @@

    NAME

    SYNOPSIS

    -
    nvme telemetry-log <device> [--output-file=<file> | -o <file>]
    -                      [--host-generate=<gen> | -g <gen>]
    +
    nvme telemetry-log <device> [--output-file=<file> | -O <file>]
    +                        [--host-generate=<gen> | -g <gen>]
    +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
    @@ -771,7 +772,7 @@

    OPTIONS

    --o <file> +-O <file>
    --output-file=<file> @@ -808,6 +809,29 @@

    OPTIONS

    4 may not be supported.

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

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

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

    + Increase the information detail in the output. +

    +
    @@ -838,7 +862,7 @@

    NVME

    diff --git a/Documentation/nvme-telemetry-log.txt b/Documentation/nvme-telemetry-log.txt index cf126d9c51..4d2a494e0d 100644 --- a/Documentation/nvme-telemetry-log.txt +++ b/Documentation/nvme-telemetry-log.txt @@ -8,8 +8,9 @@ nvme-telemetry-log - Retrieves a Telemetry Host-Initiated log page from an NVMe SYNOPSIS -------- [verse] -'nvme telemetry-log' [--output-file= | -o ] - [--host-generate= | -g ] +'nvme telemetry-log' [--output-file= | -O ] + [--host-generate= | -g ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -24,7 +25,7 @@ On success, the returned log structure will be in raw binary format _only_ with OPTIONS ------- --o :: +-O :: --output-file=:: File name to which raw binary data will be saved to. @@ -41,6 +42,15 @@ OPTIONS this option is not specified, the default value is 3, since data area 4 may not be supported. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + EXAMPLES -------- * Retrieve Telemetry Host-Initiated data to telemetry_log.bin diff --git a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1 b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1 index 1ac275e03c..cfa6106fc0 100644 --- a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1 +++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1 @@ -2,12 +2,12 @@ .\" Title: nvme-toshiba-clear-pcie-correctable-errors .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-TOSHIBA\-CLEAR" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-TOSHIBA\-CLEAR" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html index 77264990b8..94ead34177 100644 --- a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html +++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html @@ -791,7 +791,7 @@

    NVME

    diff --git a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt index 587190007e..862c8601cf 100644 --- a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt +++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt @@ -10,7 +10,6 @@ SYNOPSIS [verse] 'nvme toshiba clear-pcie-correctable-errors ' - DESCRIPTION ----------- For the NVMe device given, sends the Toshiba clear PCIe correctable errors @@ -20,7 +19,6 @@ The 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: diff --git a/Documentation/nvme-toshiba-vs-internal-log.1 b/Documentation/nvme-toshiba-vs-internal-log.1 index a2a2f8aec1..68ba681868 100644 --- a/Documentation/nvme-toshiba-vs-internal-log.1 +++ b/Documentation/nvme-toshiba-vs-internal-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-toshiba-vs-internal-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-TOSHIBA\-VS\-I" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-TOSHIBA\-VS\-I" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-toshiba-vs-internal-log.html b/Documentation/nvme-toshiba-vs-internal-log.html index 78fbc651bf..e079c4d378 100644 --- a/Documentation/nvme-toshiba-vs-internal-log.html +++ b/Documentation/nvme-toshiba-vs-internal-log.html @@ -837,7 +837,7 @@

    NVME

    diff --git a/Documentation/nvme-toshiba-vs-internal-log.txt b/Documentation/nvme-toshiba-vs-internal-log.txt index d3c01040a9..3cfb9175b5 100644 --- a/Documentation/nvme-toshiba-vs-internal-log.txt +++ b/Documentation/nvme-toshiba-vs-internal-log.txt @@ -34,12 +34,10 @@ A progress runner is included when data is written to file and a page count is i OPTIONS ------- - -o :: --output-file=:: Output binary file. Defaults to text-formatted dump to stdout - -p:: --prev-log:: Use previous log contents. Defaults to the current log contents. diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.1 b/Documentation/nvme-toshiba-vs-smart-add-log.1 index 6bc35da869..22e8a1868c 100644 --- a/Documentation/nvme-toshiba-vs-smart-add-log.1 +++ b/Documentation/nvme-toshiba-vs-smart-add-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-toshiba-vs-smart-add-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-TOSHIBA\-VS\-S" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-TOSHIBA\-VS\-S" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.html b/Documentation/nvme-toshiba-vs-smart-add-log.html index be7e926ce0..ef4a80b331 100644 --- a/Documentation/nvme-toshiba-vs-smart-add-log.html +++ b/Documentation/nvme-toshiba-vs-smart-add-log.html @@ -764,7 +764,8 @@

    DESCRIPTION

    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.

    +

    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.

    @@ -781,7 +782,7 @@

    OPTIONS

    - Log page: 0xC0 or 0xCA (defaults to 0xCA) + Log page: 0xC0 or 0xCA (defaults to 0xCA)

    @@ -840,7 +841,7 @@

    NVME

    diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.txt b/Documentation/nvme-toshiba-vs-smart-add-log.txt index 8ea4d3e06d..96a13cacb9 100644 --- a/Documentation/nvme-toshiba-vs-smart-add-log.txt +++ b/Documentation/nvme-toshiba-vs-smart-add-log.txt @@ -3,7 +3,8 @@ 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. +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 -------- @@ -12,7 +13,6 @@ SYNOPSIS [--namespace-id=, -n ] [--output-file=, -o ] - DESCRIPTION ----------- For the NVMe device given, sends the Toshiba vendor log @@ -22,7 +22,8 @@ The 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. +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) @@ -33,7 +34,7 @@ OPTIONS -l :: --log=:: - Log page: 0xC0 or 0xCA (defaults to 0xCA) + Log page: 0xC0 or 0xCA (defaults to 0xCA) -n :: --namespace-id=:: @@ -42,8 +43,6 @@ OPTIONS --output-file=:: Output binary file. Defaults to text-formatted dump to stdout - - EXAMPLES -------- * Get the current log from the device and dumps it to stdout: diff --git a/Documentation/nvme-transcend-badblock.1 b/Documentation/nvme-transcend-badblock.1 index c509b2b87c..86774bdff6 100644 --- a/Documentation/nvme-transcend-badblock.1 +++ b/Documentation/nvme-transcend-badblock.1 @@ -2,12 +2,12 @@ .\" Title: nvme-transcend-badblock .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-TRANSCEND\-BAD" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-TRANSCEND\-BAD" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-transcend-badblock.html b/Documentation/nvme-transcend-badblock.html index 12be15ab63..4e3130a80a 100644 --- a/Documentation/nvme-transcend-badblock.html +++ b/Documentation/nvme-transcend-badblock.html @@ -796,7 +796,7 @@

    NVME

    diff --git a/Documentation/nvme-transcend-badblock.txt b/Documentation/nvme-transcend-badblock.txt index 888076c3e7..9b6f67161c 100644 --- a/Documentation/nvme-transcend-badblock.txt +++ b/Documentation/nvme-transcend-badblock.txt @@ -23,7 +23,6 @@ OPTIONS ------- none - EXAMPLES -------- * Print the Transcend device's bad blocks in a human readable format: diff --git a/Documentation/nvme-transcend-healthvalue.1 b/Documentation/nvme-transcend-healthvalue.1 index 52c3182ad2..d222a03798 100644 --- a/Documentation/nvme-transcend-healthvalue.1 +++ b/Documentation/nvme-transcend-healthvalue.1 @@ -2,12 +2,12 @@ .\" Title: nvme-transcend-healthvalue .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-TRANSCEND\-HEA" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-TRANSCEND\-HEA" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-transcend-healthvalue.html b/Documentation/nvme-transcend-healthvalue.html index 2a41c4670c..8c0cf9759a 100644 --- a/Documentation/nvme-transcend-healthvalue.html +++ b/Documentation/nvme-transcend-healthvalue.html @@ -757,7 +757,8 @@

    SYNOPSIS

    DESCRIPTION

    -

    Retrieves the NVMe Device SMART log page from the Transcend device and evaluate health status of Transcend device.

    +

    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.

    @@ -796,7 +797,7 @@

    NVME

    diff --git a/Documentation/nvme-transcend-healthvalue.txt b/Documentation/nvme-transcend-healthvalue.txt index 4a7d52f10f..90340cef28 100644 --- a/Documentation/nvme-transcend-healthvalue.txt +++ b/Documentation/nvme-transcend-healthvalue.txt @@ -3,7 +3,8 @@ nvme-transcend-healthvalue(1) NAME ---- -nvme-transcend-healthvalue - Use NVMe SMART table to analyze the health value of Transcend device. +nvme-transcend-healthvalue - Use NVMe SMART table to analyze the health value of +Transcend device. SYNOPSIS -------- @@ -12,7 +13,8 @@ SYNOPSIS DESCRIPTION ----------- -Retrieves the NVMe Device SMART log page from the Transcend device and evaluate health status of Transcend device. +Retrieves the NVMe Device SMART log page from the Transcend device and evaluate +health status of Transcend device. The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). @@ -23,7 +25,6 @@ OPTIONS ------- none - EXAMPLES -------- * Print the Transcend Device health value in a human readable format: diff --git a/Documentation/nvme-verify.1 b/Documentation/nvme-verify.1 index 059f2826bf..d56d554d78 100644 --- a/Documentation/nvme-verify.1 +++ b/Documentation/nvme-verify.1 @@ -2,12 +2,12 @@ .\" Title: nvme-verify .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-VERIFY" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-VERIFY" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,48 +33,48 @@ nvme-verify \- Send an NVMe Verify command, return results .sp .nf \fInvme\-verify\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-block= | \-s ] - [\-\-block\-count= | \-c ] - [\-\-limited\-retry | \-l] - [\-\-force\-unit\-access | \-f] - [\-\-prinfo= | \-p ] - [\-\-ref\-tag= | \-r ] - [\-\-app\-tag\-mask= | \-m ] - [\-\-app\-tag= | \-a ] - [\-\-storage\-tag | \-S ] - [\-\-storage\-tag\-check | \-C ] + [\-\-start\-block= | \-s ] + [\-\-block\-count= | \-c ] [\-\-limited\-retry | \-l] + [\-\-force\-unit\-access | \-f] + [\-\-prinfo= | \-p ] + [\-\-ref\-tag= | \-r ] + [\-\-app\-tag\-mask= | \-m ] + [\-\-app\-tag= | \-a ] + [\-\-storage\-tag | \-S ] + [\-\-storage\-tag\-check | \-C] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Verify command verifies the integrity of the stored information by reading data and metadata\&. .SH "OPTIONS" .PP -\-\-namespace\-id=, \-n +\-n , \-\-namespace\-id= .RS 4 Namespace ID use in the command\&. .RE .PP -\-\-start\-block=, \-s +\-s , \-\-start\-block= .RS 4 Start block address\&. .RE .PP -\-\-block\-count=, \-c +\-c , \-\-block\-count= .RS 4 Number of logical blocks to Verify\&. .RE .PP -\-\-limited\-retry, \-l +\-l, \-\-limited\-retry .RS 4 Sets the limited retry flag\&. .RE .PP -\-\-force\-unit\-access, \-f +\-f, \-\-force\-unit\-access .RS 4 Set the force\-unit access flag\&. .RE .PP -\-\-prinfo=, \-p +\-p , \-\-prinfo= .RS 4 Protection Information field definition\&. .TS @@ -119,29 +119,43 @@ T} .sp 1 .RE .PP -\-\-ref\-tag=, \-r +\-r , \-\-ref\-tag= .RS 4 Optional reftag when used with protection information\&. .RE .PP -\-\-app\-tag\-mask=, \-m +\-m , \-\-app\-tag\-mask= .RS 4 Optional application tag mask when used with protection information\&. .RE .PP -\-\-app\-tag=, \-a +\-a , \-\-app\-tag= .RS 4 Optional application tag when used with protection information\&. .RE .PP -\-\-storage\-tag=, \-S +\-S , \-\-storage\-tag= .RS 4 Variable Sized Expected Logical Block Storage Tag(ELBST)\&. .RE .PP -\-\-storage\-tag\-check=, \-C +\-C, \-\-storage\-tag\-check .RS 4 -This bit specifies the Storage Tag field shall be checked as part of Verify operation\&. +This flag enables Storage Tag field checking as part of Verify operation\&. +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-verify.html b/Documentation/nvme-verify.html index b46216f38a..8581e22e8c 100644 --- a/Documentation/nvme-verify.html +++ b/Documentation/nvme-verify.html @@ -750,16 +750,16 @@

    SYNOPSIS

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

    OPTIONS

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

    @@ -787,10 +787,10 @@

    OPTIONS

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

    @@ -798,10 +798,10 @@

    OPTIONS

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

    @@ -809,10 +809,10 @@

    OPTIONS

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

    @@ -820,10 +820,10 @@

    OPTIONS

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

    @@ -831,10 +831,10 @@

    OPTIONS

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

    @@ -879,10 +879,10 @@

    OPTIONS

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

    @@ -890,10 +890,10 @@

    OPTIONS

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

    @@ -901,10 +901,10 @@

    OPTIONS

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

    @@ -912,10 +912,10 @@

    OPTIONS

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

    @@ -923,14 +923,37 @@

    OPTIONS

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

    + This flag enables Storage Tag field checking as part of Verify operation. +

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

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

    +
    +
    +-v
    --C <storage-tag-check> +--verbose

    - This bit specifies the Storage Tag field shall be checked as part of Verify operation. + Increase the information detail in the output.

    @@ -953,7 +976,7 @@

    NVME

    diff --git a/Documentation/nvme-verify.txt b/Documentation/nvme-verify.txt index 75c1de0967..01dabbf494 100644 --- a/Documentation/nvme-verify.txt +++ b/Documentation/nvme-verify.txt @@ -9,16 +9,16 @@ SYNOPSIS -------- [verse] 'nvme-verify' [--namespace-id= | -n ] - [--start-block= | -s ] - [--block-count= | -c ] - [--limited-retry | -l] - [--force-unit-access | -f] - [--prinfo= | -p ] - [--ref-tag= | -r ] - [--app-tag-mask= | -m ] - [--app-tag= | -a ] - [--storage-tag | -S ] - [--storage-tag-check | -C ] + [--start-block= | -s ] + [--block-count= | -c ] [--limited-retry | -l] + [--force-unit-access | -f] + [--prinfo= | -p ] + [--ref-tag= | -r ] + [--app-tag-mask= | -m ] + [--app-tag= | -a ] + [--storage-tag | -S ] + [--storage-tag-check | -C] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -27,28 +27,28 @@ reading data and metadata. OPTIONS ------- ---namespace-id=:: -n :: +--namespace-id=:: Namespace ID use in the command. ---start-block=:: -s :: +--start-block=:: Start block address. ---block-count=:: -c :: +--block-count=:: Number of logical blocks to Verify. ---limited-retry:: -l:: +--limited-retry:: Sets the limited retry flag. ---force-unit-access:: -f:: +--force-unit-access:: Set the force-unit access flag. ---prinfo=:: -p :: +--prinfo=:: Protection Information field definition. + [] @@ -63,25 +63,34 @@ metadata is passes. |0|Set to 1 enables checking the reference tag |================= ---ref-tag=:: -r :: +--ref-tag=:: Optional reftag when used with protection information. ---app-tag-mask=:: -m :: +--app-tag-mask=:: Optional application tag mask when used with protection information. ---app-tag=:: -a :: +--app-tag=:: Optional application tag when used with protection information. ---storage-tag=:: -S :: +--storage-tag=:: Variable Sized Expected Logical Block Storage Tag(ELBST). ---storage-tag-check=:: --C :: - This bit specifies the Storage Tag field shall be checked as part of Verify operation. +-C:: +--storage-tag-check:: + This flag enables Storage Tag field checking as part of Verify operation. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-virt-mgmt.txt b/Documentation/nvme-virt-mgmt.txt new file mode 100644 index 0000000000..5eede1403e --- /dev/null +++ b/Documentation/nvme-virt-mgmt.txt @@ -0,0 +1,70 @@ +nvme-virt-mgmt(1) +================= + +NAME +---- +nvme-virt-mgmt - Manage flexible resources between primary and secondary +controller + +SYNOPSIS +-------- +[verse] +'nvme virt-mgmt' [--cntlid= | -c ] + [--rt= | -r ] [--act= | -a ] + [--nr= | -n ] + [--output-format= | -o ] [--verbose | -v] + +DESCRIPTION +----------- +Manage flexible resources between primary and secondary controller, return +results. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1). + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-c :: +--cntlid=:: + Controller identifier (CNTLID) + +-r :: +--rt=:: + Resource Type (RT): [0,1] + 0h: VQ Resources + 1h: VI Resources + +-a :: +--act=:: + Action(ACT): [1,7,8,9] + 1h: Primary Flexible + 7h: Secondary Offline + 8h: Secondary Assign + 9h: Secondary Online + +-n :: +--nr=:: + Number of controller resources (NR) + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. + +EXAMPLES +-------- +* Has the program issue a virt-mgmt to manage flexible resources. ++ +------------ +# nvme virt-mgmt /dev/nvme0 -c 0 -r 1 -a 1 -n 0 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.1 b/Documentation/nvme-virtium-save-smart-to-vtview-log.1 index ef7475ff72..15ba0a5d29 100644 --- a/Documentation/nvme-virtium-save-smart-to-vtview-log.1 +++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-virtium-save-smart-to-vtview-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-VIRTIUM\-SAVE\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-VIRTIUM\-SAVE\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -39,7 +39,7 @@ nvme-virtium-save-smart-to-vtview-log \- Periodically save smart attributes into .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\&. +This command automates the process of collecting SMART data periodically and saving the data in a ready\-to\-analyze format\&. Each entry is saved with timestamp and in csv format\&. Users can use excel to analyze the data\&. Some examples of use cases are collecting SMART data for temperature characterization, data to calculate endurance, or collecting SMART data during a test or during normal operation\&. .sp The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. .sp @@ -57,7 +57,7 @@ If the test\-name option is specified, it will be recorded in the log file and b .PP \-f , \-\-freq= .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\&. +(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 , \-\-output\-file= diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.html b/Documentation/nvme-virtium-save-smart-to-vtview-log.html index 3541b2612e..5edfd37bf7 100644 --- a/Documentation/nvme-virtium-save-smart-to-vtview-log.html +++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.html @@ -763,18 +763,19 @@

    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.

    +Some examples of use cases are collecting SMART data for temperature +characterization, data to calculate endurance, or collecting SMART data during a +test or during normal operation.

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

    -

    On success, the command generates a log file, which contains an entry for identify device -(current features & settings) and periodic entries of SMART data.

    -

    This command runs for the time specified by the option <run-time>, and collects SMART data -at the frequency specified by the option <freq>. If the output file name is not specified, -this command will generate a file name that include model string and serial number of the device.

    -

    If the test-name option is specified, it will be recorded in the log file and be used as part -of the log file name.

    +

    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.

    @@ -800,8 +801,8 @@

    OPTIONS

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

    @@ -812,9 +813,9 @@

    OPTIONS

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

    @@ -825,7 +826,8 @@

    OPTIONS

    - (optional) Name of the test you are doing. We use this string as part of the name of the log file. + (optional) Name of the test you are doing. We use this string as part of + the name of the log file.

    @@ -876,7 +878,7 @@

    NVME

    diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.txt b/Documentation/nvme-virtium-save-smart-to-vtview-log.txt old mode 100755 new mode 100644 index 313ac35a0c..72090c07f0 --- a/Documentation/nvme-virtium-save-smart-to-vtview-log.txt +++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.txt @@ -3,7 +3,8 @@ 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). +nvme-virtium-save-smart-to-vtview-log - Periodically save smart attributes into +a log file (csv format). SYNOPSIS -------- @@ -12,28 +13,29 @@ SYNOPSIS [--freq= | -f ] [--output-file= | -o ] [--test-name= | -n ] - + 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. +Some examples of use cases are collecting SMART data for temperature +characterization, data to calculate endurance, or collecting SMART data during a +test or during normal operation. The 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. +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 , and collects SMART data -at the frequency specified by the option . 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. +This command runs for the time specified by the option , and collects +SMART data at the frequency specified by the option . 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. +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 ------- @@ -43,20 +45,20 @@ OPTIONS -f :: --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. + (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 :: --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, the file name will be generated - as --.txt. + (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 --.txt. -n :: --test-name=:: - (optional) Name of the test you are doing. We use this string as part of the name of the log file. - - + (optional) Name of the test you are doing. We use this string as part of + the name of the log file. + EXAMPLES -------- * Temperature characterization: diff --git a/Documentation/nvme-virtium-show-identify.1 b/Documentation/nvme-virtium-show-identify.1 index 9489368b31..10f9697d32 100644 --- a/Documentation/nvme-virtium-show-identify.1 +++ b/Documentation/nvme-virtium-show-identify.1 @@ -2,12 +2,12 @@ .\" Title: nvme-virtium-show-identify .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-VIRTIUM\-SHOW\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-VIRTIUM\-SHOW\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-virtium-show-identify.html b/Documentation/nvme-virtium-show-identify.html index 28577b07bd..9e03e8d13c 100644 --- a/Documentation/nvme-virtium-show-identify.html +++ b/Documentation/nvme-virtium-show-identify.html @@ -798,7 +798,7 @@

    NVME

    diff --git a/Documentation/nvme-virtium-show-identify.txt b/Documentation/nvme-virtium-show-identify.txt old mode 100755 new mode 100644 index 5ce1933f3c..881824c358 --- a/Documentation/nvme-virtium-show-identify.txt +++ b/Documentation/nvme-virtium-show-identify.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'nvme virtium show-identify' - + DESCRIPTION ----------- This command prints complete detail of the identify device information. The @@ -24,8 +24,7 @@ On success, the command prints identify device in human readable format. OPTIONS ------- none - - + EXAMPLES -------- * Show Identify Device: diff --git a/Documentation/nvme-wdc-cap-diag.1 b/Documentation/nvme-wdc-cap-diag.1 index a362884c7e..b6a50aaea7 100644 --- a/Documentation/nvme-wdc-cap-diag.1 +++ b/Documentation/nvme-wdc-cap-diag.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-cap-diag .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CAP\-DIAG" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CAP\-DIAG" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-cap-diag.html b/Documentation/nvme-wdc-cap-diag.html index b5c244ae28..f25b31c2ed 100644 --- a/Documentation/nvme-wdc-cap-diag.html +++ b/Documentation/nvme-wdc-cap-diag.html @@ -787,7 +787,7 @@

    OPTIONS

    - Transfer size; defaults to 0x10000 (65536 decimal) bytes + Transfer size; defaults to 0x10000 (65536 decimal) bytes

    @@ -856,7 +856,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-cap-diag.txt b/Documentation/nvme-wdc-cap-diag.txt index 9439eaa680..bfcde9a653 100644 --- a/Documentation/nvme-wdc-cap-diag.txt +++ b/Documentation/nvme-wdc-cap-diag.txt @@ -29,7 +29,7 @@ OPTIONS -s :: --transfer-size=:: - Transfer size; defaults to 0x10000 (65536 decimal) bytes + Transfer size; defaults to 0x10000 (65536 decimal) bytes EXAMPLES -------- diff --git a/Documentation/nvme-wdc-capabilities.1 b/Documentation/nvme-wdc-capabilities.1 index 6b767b0810..3bf216b0aa 100644 --- a/Documentation/nvme-wdc-capabilities.1 +++ b/Documentation/nvme-wdc-capabilities.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-capabilities .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CAPABILIT" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CAPABILIT" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-capabilities.html b/Documentation/nvme-wdc-capabilities.html index e3c2f60427..5768612947 100644 --- a/Documentation/nvme-wdc-capabilities.html +++ b/Documentation/nvme-wdc-capabilities.html @@ -789,7 +789,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-clear-assert-dump.1 b/Documentation/nvme-wdc-clear-assert-dump.1 index ea5ebcc599..08267d7885 100644 --- a/Documentation/nvme-wdc-clear-assert-dump.1 +++ b/Documentation/nvme-wdc-clear-assert-dump.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-clear-assert-dump .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CLEAR\-AS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CLEAR\-AS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-clear-assert-dump.html b/Documentation/nvme-wdc-clear-assert-dump.html index e2b16629a7..2a8ab95a6c 100644 --- a/Documentation/nvme-wdc-clear-assert-dump.html +++ b/Documentation/nvme-wdc-clear-assert-dump.html @@ -798,7 +798,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-clear-assert-dump.txt b/Documentation/nvme-wdc-clear-assert-dump.txt index a5750896e1..60493df52c 100644 --- a/Documentation/nvme-wdc-clear-assert-dump.txt +++ b/Documentation/nvme-wdc-clear-assert-dump.txt @@ -33,7 +33,6 @@ EXAMPLES # 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 index 1a81717c76..592336d245 100644 --- a/Documentation/nvme-wdc-clear-fw-activate-history.1 +++ b/Documentation/nvme-wdc-clear-fw-activate-history.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-clear-fw-activate-history .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CLEAR\-FW" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CLEAR\-FW" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-clear-fw-activate-history.html b/Documentation/nvme-wdc-clear-fw-activate-history.html index 6e40eeca8d..6fc643495b 100644 --- a/Documentation/nvme-wdc-clear-fw-activate-history.html +++ b/Documentation/nvme-wdc-clear-fw-activate-history.html @@ -797,7 +797,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-clear-fw-activate-history.txt b/Documentation/nvme-wdc-clear-fw-activate-history.txt index 50be1e9357..ddb6c26c02 100644 --- a/Documentation/nvme-wdc-clear-fw-activate-history.txt +++ b/Documentation/nvme-wdc-clear-fw-activate-history.txt @@ -32,7 +32,6 @@ EXAMPLES # nvme wdc clear-fw-activate-history /dev/nvme0 ------------ - NVME ---- Part of the nvme-user suite diff --git a/Documentation/nvme-wdc-clear-pcie-correctable-errors.1 b/Documentation/nvme-wdc-clear-pcie-correctable-errors.1 index a1131dbf6d..b3cff45752 100644 --- a/Documentation/nvme-wdc-clear-pcie-correctable-errors.1 +++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-clear-pcie-correctable-errors .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CLEAR\-PC" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CLEAR\-PC" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-clear-pcie-correctable-errors.html b/Documentation/nvme-wdc-clear-pcie-correctable-errors.html index 9e219c9857..30e109f281 100644 --- a/Documentation/nvme-wdc-clear-pcie-correctable-errors.html +++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.html @@ -799,7 +799,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt b/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt index 4788f1fc08..cecc52edb5 100644 --- a/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt +++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt @@ -34,7 +34,6 @@ EXAMPLES # nvme wdc clear-pcie-correctable-errors /dev/nvme0 ------------ - NVME ---- Part of the nvme-user suite diff --git a/Documentation/nvme-wdc-cloud-SSD-plugin-version.1 b/Documentation/nvme-wdc-cloud-SSD-plugin-version.1 index a35443502d..8f1147a3fb 100644 --- a/Documentation/nvme-wdc-cloud-SSD-plugin-version.1 +++ b/Documentation/nvme-wdc-cloud-SSD-plugin-version.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-cloud-SSD-plugin-version .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CLOUD\-SS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CLOUD\-SS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-cloud-SSD-plugin-version.html b/Documentation/nvme-wdc-cloud-SSD-plugin-version.html index cd932e4822..314631e875 100644 --- a/Documentation/nvme-wdc-cloud-SSD-plugin-version.html +++ b/Documentation/nvme-wdc-cloud-SSD-plugin-version.html @@ -790,7 +790,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-cloud-boot-SSD-version.1 b/Documentation/nvme-wdc-cloud-boot-SSD-version.1 index b6079dd79d..a79a715c4a 100644 --- a/Documentation/nvme-wdc-cloud-boot-SSD-version.1 +++ b/Documentation/nvme-wdc-cloud-boot-SSD-version.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-cloud-boot-SSD-version .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-CLOUD\-BO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-CLOUD\-BO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-cloud-boot-SSD-version.html b/Documentation/nvme-wdc-cloud-boot-SSD-version.html index f48f2d91a9..7369c48119 100644 --- a/Documentation/nvme-wdc-cloud-boot-SSD-version.html +++ b/Documentation/nvme-wdc-cloud-boot-SSD-version.html @@ -790,7 +790,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-drive-essentials.1 b/Documentation/nvme-wdc-drive-essentials.1 index 220e78b0a2..850d63b517 100644 --- a/Documentation/nvme-wdc-drive-essentials.1 +++ b/Documentation/nvme-wdc-drive-essentials.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-drive-essentials .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-DRIVE\-ES" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-DRIVE\-ES" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-drive-essentials.html b/Documentation/nvme-wdc-drive-essentials.html index 75bd9d3e40..40dad8a3b8 100644 --- a/Documentation/nvme-wdc-drive-essentials.html +++ b/Documentation/nvme-wdc-drive-essentials.html @@ -757,9 +757,10 @@

    SYNOPSIS

    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

    +

    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.

    @@ -821,7 +822,7 @@

    NVME

    diff --git a/Documentation/nvme-wdc-drive-essentials.txt b/Documentation/nvme-wdc-drive-essentials.txt index 59b27877a5..7f06040707 100644 --- a/Documentation/nvme-wdc-drive-essentials.txt +++ b/Documentation/nvme-wdc-drive-essentials.txt @@ -3,7 +3,8 @@ nvme-wdc-drive-essentials(1) NAME ---- -nvme-wdc-drive-essentials - Retrieve WDC device's drive essentials bin files and save to a tar file. +nvme-wdc-drive-essentials - Retrieve WDC device's drive essentials bin files and +save to a tar file. SYNOPSIS -------- @@ -13,9 +14,10 @@ SYNOPSIS 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____

    The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0).

    -

    The --log-id=<NUM>, -l <NUM> parameter is mandatory and may be either 0xd1, 0xd2, 0xd3, 0xd4, 0xe2 and 0xe4.

    +

    The --log-id=<NUM>, -l <NUM> parameter is mandatory and may be either 0xd1, 0xd2, +0xd3, 0xd4, 0xe2 and 0xe4.

    This will only work on WDC devices supporting this feature. Results for any other device are undefined.

    On success it returns the enclosure log data, error code otherwise.

    @@ -779,7 +782,7 @@

    OPTIONS

    - Output file pathname + Output file pathname

    @@ -790,7 +793,8 @@

    OPTIONS

    - Data retrieval transfer size, maximum transfer size should be 0x2000 (decimal 8192) + Data retrieval transfer size, maximum transfer size should be 0x2000 + (decimal 8192)

    @@ -802,7 +806,8 @@

    EXAMPLES

    • -Gets the enclosure log from the device based on the log id(0xd1) with transfer size(0x2000) and saves to defined file in current directory: +Gets the enclosure log from the device based on the log id(0xd1) with transfer + size(0x2000) and saves to defined file in current directory:

      @@ -832,7 +837,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-enc-get-log.txt b/Documentation/nvme-wdc-enc-get-log.txt index ae93a7ab58..bcff83fd0d 100644 --- a/Documentation/nvme-wdc-enc-get-log.txt +++ b/Documentation/nvme-wdc-enc-get-log.txt @@ -3,12 +3,15 @@ nvme-wdc-enc-get-log(1) NAME ---- -nvme-wdc-enc-get-log - Send NVMe WDC enc-get-log Vendor Unique Command, return result. +nvme-wdc-enc-get-log - Send NVMe WDC enc-get-log Vendor Unique Command, return +result. SYNOPSIS -------- [verse] -'nvme wdc enc-get-log' [--log-id=, -l ] [--output-file=, -o ] [--transfer-size=, -s ] +'nvme wdc enc-get-log' [--log-id=, -l ] + [--output-file=, -o ] + [--transfer-size=, -s ] DESCRIPTION ----------- @@ -19,7 +22,8 @@ output the Enclosure logs. The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0). -The --log-id=, -l parameter is mandatory and may be either 0xd1, 0xd2, 0xd3, 0xd4, 0xe2 and 0xe4. +The --log-id=, -l parameter is mandatory and may be either 0xd1, 0xd2, +0xd3, 0xd4, 0xe2 and 0xe4. This will only work on WDC devices supporting this feature. Results for any other device are undefined. @@ -30,15 +34,17 @@ OPTIONS ------- -o :: --output-file=:: - Output file pathname + Output file pathname -s :: --transfer-size=:: - Data retrieval transfer size, maximum transfer size should be 0x2000 (decimal 8192) + Data retrieval transfer size, maximum transfer size should be 0x2000 + (decimal 8192) EXAMPLES -------- -* Gets the enclosure log from the device based on the log id(0xd1) with transfer size(0x2000) and saves to defined file in current directory: +* Gets the enclosure log from the device based on the log id(0xd1) with transfer + size(0x2000) and saves to defined file in current directory: + ------------ # nvme wdc enc-get-log /dev/nvme0 -l 0xd1 -o d1_log.bin -s 0x2000 diff --git a/Documentation/nvme-wdc-get-crash-dump.1 b/Documentation/nvme-wdc-get-crash-dump.1 index 22b36156f7..803596cb93 100644 --- a/Documentation/nvme-wdc-get-crash-dump.1 +++ b/Documentation/nvme-wdc-get-crash-dump.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-crash-dump .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-CRAS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-CRAS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-get-crash-dump.html b/Documentation/nvme-wdc-get-crash-dump.html index 75d99439a4..22eaaa4c64 100644 --- a/Documentation/nvme-wdc-get-crash-dump.html +++ b/Documentation/nvme-wdc-get-crash-dump.html @@ -830,7 +830,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-dev-capabilities-log.1 b/Documentation/nvme-wdc-get-dev-capabilities-log.1 index b1152ce2f1..a838f032ce 100644 --- a/Documentation/nvme-wdc-get-dev-capabilities-log.1 +++ b/Documentation/nvme-wdc-get-dev-capabilities-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-dev-capabilities-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-DEV\" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-DEV\" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,8 +32,7 @@ nvme-wdc-get-dev-capabilities-log \- Send NVMe WDC get\-dev\-capabilities\-log p .SH "SYNOPSIS" .sp .nf -\fInvme wdc get\-dev\-capabilities\-log\fR [\-\-output\-format= -\-o ] +\fInvme wdc get\-dev\-capabilities\-log\fR [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp @@ -46,7 +45,7 @@ This will only work on WDC devices supporting this log page\&. Results for any o On success it returns the parsed device capabilities log page data, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-get-dev-capabilities-log.html b/Documentation/nvme-wdc-get-dev-capabilities-log.html index 585e4a6837..4f1869f9db 100644 --- a/Documentation/nvme-wdc-get-dev-capabilities-log.html +++ b/Documentation/nvme-wdc-get-dev-capabilities-log.html @@ -740,7 +740,7 @@

      NAME

      nvme-wdc-get-dev-capabilities-log - - Send NVMe WDC get-dev-capabilities-log plugin command, return parsed log output + Send NVMe WDC get-dev-capabilities-log plugin command, return parsed log output

      @@ -749,8 +749,7 @@

      NAME

      SYNOPSIS

      -
      nvme wdc get-dev-capabilities-log <device> [--output-format=<normal|json>
      --o <normal|json>]
      +
      nvme wdc get-dev-capabilities-log <device> [--output-format=<fmt> | -o <fmt>]
      @@ -774,10 +773,10 @@

      OPTIONS

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

      @@ -816,7 +815,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-dev-capabilities-log.txt b/Documentation/nvme-wdc-get-dev-capabilities-log.txt index 06218812d9..cf8606a5c9 100644 --- a/Documentation/nvme-wdc-get-dev-capabilities-log.txt +++ b/Documentation/nvme-wdc-get-dev-capabilities-log.txt @@ -4,13 +4,12 @@ nvme-wdc-get-dev-capabilities-log(1) NAME ---- nvme-wdc-get-dev-capabilities-log - Send NVMe WDC get-dev-capabilities-log - plugin command, return parsed log output +plugin command, return parsed log output SYNOPSIS -------- [verse] -'nvme wdc get-dev-capabilities-log' [--output-format= --o ] +'nvme wdc get-dev-capabilities-log' [--output-format= | -o ] DESCRIPTION ----------- @@ -29,8 +28,8 @@ code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. diff --git a/Documentation/nvme-wdc-get-drive-status.1 b/Documentation/nvme-wdc-get-drive-status.1 index 27728ce0b5..f9e44f3b3a 100644 --- a/Documentation/nvme-wdc-get-drive-status.1 +++ b/Documentation/nvme-wdc-get-drive-status.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-drive-status .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-DRIV" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-DRIV" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-get-drive-status.html b/Documentation/nvme-wdc-get-drive-status.html index 255ec6f67f..47df6dfa89 100644 --- a/Documentation/nvme-wdc-get-drive-status.html +++ b/Documentation/nvme-wdc-get-drive-status.html @@ -790,19 +790,19 @@

      Output Explanation

      EOL (End of Life) Status

      -

      The 3 possible states are : Normal, Read Only, or End of Life.

      +

      The 3 possible states are : Normal, Read Only, or End of Life.

      Assert Dump Status

      -

      The 2 possible states are : Present or Not Present.

      +

      The 2 possible states are : Present or Not Present.

      Thermal Throttling Status

      -

      The 3 possible states are : Off, On, or Unavailable.

      +

      The 3 possible states are : Off, On, or Unavailable.

      Format Corrupt Reason

      -

      The 3 possible states are : Not Corrupted, Corrupt due to FW Assert, or Corrupt for Unknown Reason.

      +

      The 3 possible states are : Not Corrupted, Corrupt due to FW Assert, or Corrupt for Unknown Reason.

      @@ -836,7 +836,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-drive-status.txt b/Documentation/nvme-wdc-get-drive-status.txt index 10e212b159..b1b4de4811 100644 --- a/Documentation/nvme-wdc-get-drive-status.txt +++ b/Documentation/nvme-wdc-get-drive-status.txt @@ -3,7 +3,8 @@ nvme-wdc-get-drive-status(1) NAME ---- -nvme-wdc-get-drive-status - Send the NVMe WDC get-drive-status command, return result +nvme-wdc-get-drive-status - Send the NVMe WDC get-drive-status command, return +result SYNOPSIS -------- @@ -33,20 +34,19 @@ Output Explanation |The percentage of drive function used. |*EOL (End of Life) Status* -|The 3 possible states are : Normal, Read Only, or End of Life. +|The 3 possible states are : Normal, Read Only, or End of Life. |*Assert Dump Status* -|The 2 possible states are : Present or Not Present. +|The 2 possible states are : Present or Not Present. |*Thermal Throttling Status* -|The 3 possible states are : Off, On, or Unavailable. +|The 3 possible states are : Off, On, or Unavailable. |*Format Corrupt Reason* -|The 3 possible states are : Not Corrupted, Corrupt due to FW Assert, or Corrupt for Unknown Reason. +|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 : diff --git a/Documentation/nvme-wdc-get-error-recovery-log.1 b/Documentation/nvme-wdc-get-error-recovery-log.1 index d027e4e096..8b0cc437e1 100644 --- a/Documentation/nvme-wdc-get-error-recovery-log.1 +++ b/Documentation/nvme-wdc-get-error-recovery-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-error-recovery-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-ERRO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-ERRO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -46,7 +46,7 @@ This will only work on WDC devices supporting this log page\&. Results for any o On success it returns the parsed error recovery log page data, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-get-error-recovery-log.html b/Documentation/nvme-wdc-get-error-recovery-log.html index 502a08f059..342bfb92bb 100644 --- a/Documentation/nvme-wdc-get-error-recovery-log.html +++ b/Documentation/nvme-wdc-get-error-recovery-log.html @@ -740,7 +740,7 @@

      NAME

      nvme-wdc-get-error-recovery-log - - Send NVMe WDC get-error-recovery-log plugin command, return parsed log output + Send NVMe WDC get-error-recovery-log plugin command, return parsed log output

      @@ -774,10 +774,10 @@

      OPTIONS

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

      @@ -816,7 +816,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-error-recovery-log.txt b/Documentation/nvme-wdc-get-error-recovery-log.txt index 2ad3605f7b..4998390ec2 100644 --- a/Documentation/nvme-wdc-get-error-recovery-log.txt +++ b/Documentation/nvme-wdc-get-error-recovery-log.txt @@ -4,7 +4,7 @@ nvme-wdc-get-error-recovery-log(1) NAME ---- nvme-wdc-get-error-recovery-log - Send NVMe WDC get-error-recovery-log plugin - command, return parsed log output +command, return parsed log output SYNOPSIS -------- @@ -29,8 +29,8 @@ code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. diff --git a/Documentation/nvme-wdc-get-latency-monitor-log.1 b/Documentation/nvme-wdc-get-latency-monitor-log.1 index 7351c18796..437e9c618d 100644 --- a/Documentation/nvme-wdc-get-latency-monitor-log.1 +++ b/Documentation/nvme-wdc-get-latency-monitor-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-latency-monitor-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-LATE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-LATE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -45,7 +45,7 @@ This will only work on WDC devices supporting this log page\&. Results for any o On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR diff --git a/Documentation/nvme-wdc-get-latency-monitor-log.html b/Documentation/nvme-wdc-get-latency-monitor-log.html index dc27611a8b..092f346226 100644 --- a/Documentation/nvme-wdc-get-latency-monitor-log.html +++ b/Documentation/nvme-wdc-get-latency-monitor-log.html @@ -769,10 +769,10 @@

      OPTIONS

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

      @@ -810,7 +810,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-latency-monitor-log.txt b/Documentation/nvme-wdc-get-latency-monitor-log.txt index 19fda4a932..abab8e84a3 100644 --- a/Documentation/nvme-wdc-get-latency-monitor-log.txt +++ b/Documentation/nvme-wdc-get-latency-monitor-log.txt @@ -24,8 +24,8 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal' or 'json'. Only one output format can be used at a time. The default is normal. diff --git a/Documentation/nvme-wdc-get-pfail-dump.1 b/Documentation/nvme-wdc-get-pfail-dump.1 index a52d23e473..37ba4a18c3 100644 --- a/Documentation/nvme-wdc-get-pfail-dump.1 +++ b/Documentation/nvme-wdc-get-pfail-dump.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-pfail-dump .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-PFAI" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-PFAI" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-get-pfail-dump.html b/Documentation/nvme-wdc-get-pfail-dump.html index 6426f64fbd..3fd5726ada 100644 --- a/Documentation/nvme-wdc-get-pfail-dump.html +++ b/Documentation/nvme-wdc-get-pfail-dump.html @@ -832,7 +832,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-unsupported-reqs-log.1 b/Documentation/nvme-wdc-get-unsupported-reqs-log.1 index eb1da671ab..f458f3315c 100644 --- a/Documentation/nvme-wdc-get-unsupported-reqs-log.1 +++ b/Documentation/nvme-wdc-get-unsupported-reqs-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-get-unsupported-reqs-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-GET\-UNSU" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-GET\-UNSU" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -46,7 +46,7 @@ This will only work on WDC devices supporting this log page\&. Results for any o On success it returns the parsed unsupported requirements log page data, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-get-unsupported-reqs-log.html b/Documentation/nvme-wdc-get-unsupported-reqs-log.html index 34b8568386..57cd69746a 100644 --- a/Documentation/nvme-wdc-get-unsupported-reqs-log.html +++ b/Documentation/nvme-wdc-get-unsupported-reqs-log.html @@ -774,10 +774,10 @@

      OPTIONS

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

      @@ -816,7 +816,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-get-unsupported-reqs-log.txt b/Documentation/nvme-wdc-get-unsupported-reqs-log.txt index f028665d50..61f09aa0ba 100644 --- a/Documentation/nvme-wdc-get-unsupported-reqs-log.txt +++ b/Documentation/nvme-wdc-get-unsupported-reqs-log.txt @@ -29,8 +29,8 @@ code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. diff --git a/Documentation/nvme-wdc-id-ctrl.1 b/Documentation/nvme-wdc-id-ctrl.1 index 2e74a20caf..c3a31da953 100644 --- a/Documentation/nvme-wdc-id-ctrl.1 +++ b/Documentation/nvme-wdc-id-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-id-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-ID\-CTRL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-ID\-CTRL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,9 @@ nvme-wdc-id-ctrl \- Send NVMe Identify Controller, return result and structure .SH "SYNOPSIS" .sp .nf -\fInvme wdc id\-ctrl\fR [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary] - [\-H | \-\-human\-readable] - [\-o | \-\-output\-format=] +\fInvme wdc id\-ctrl\fR [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b] + [\-\-human\-readable | \-H] + [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp @@ -64,7 +64,7 @@ In addition to parsing known fields, this option will dump the vendor specific r This option will parse and format many of the bit fields into human\-readable formats\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-wdc-id-ctrl.html b/Documentation/nvme-wdc-id-ctrl.html index fb9df9b665..36c535d3b5 100644 --- a/Documentation/nvme-wdc-id-ctrl.html +++ b/Documentation/nvme-wdc-id-ctrl.html @@ -749,9 +749,9 @@

      NAME

      SYNOPSIS

      -
      nvme wdc id-ctrl <device> [-v | --vendor-specific] [-b | --raw-binary]
      -                        [-H | --human-readable]
      -                        [-o <fmt> | --output-format=<fmt>]
      +
      nvme wdc id-ctrl <device> [--vendor-specific | -v] [--raw-binary | -b]
      +                        [--human-readable | -H]
      +                        [--output-format=<fmt> | -o <fmt>]
      @@ -814,15 +814,15 @@

      OPTIONS

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

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

      @@ -856,7 +856,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-id-ctrl.txt b/Documentation/nvme-wdc-id-ctrl.txt index a9c6afe5ac..b62eb60e45 100644 --- a/Documentation/nvme-wdc-id-ctrl.txt +++ b/Documentation/nvme-wdc-id-ctrl.txt @@ -8,9 +8,9 @@ nvme-wdc-id-ctrl - Send NVMe Identify Controller, return result and structure SYNOPSIS -------- [verse] -'nvme wdc id-ctrl' [-v | --vendor-specific] [-b | --raw-binary] - [-H | --human-readable] - [-o | --output-format=] +'nvme wdc id-ctrl' [--vendor-specific | -v] [--raw-binary | -b] + [--human-readable | -H] + [--output-format= | -o ] DESCRIPTION ----------- @@ -48,10 +48,10 @@ OPTIONS This option will parse and format many of the bit fields into human-readable formats. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-wdc-log-page-directory.1 b/Documentation/nvme-wdc-log-page-directory.1 index 1a8ee5b93d..5856e2437a 100644 --- a/Documentation/nvme-wdc-log-page-directory.1 +++ b/Documentation/nvme-wdc-log-page-directory.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-log-page-directory .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-LOG\-PAGE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-LOG\-PAGE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -45,7 +45,7 @@ This will only work on WDC devices supporting this feature\&. Results for any ot On success it returns the log page directory information, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-wdc-log-page-directory.html b/Documentation/nvme-wdc-log-page-directory.html index 0cfe7cb01b..21927544f3 100644 --- a/Documentation/nvme-wdc-log-page-directory.html +++ b/Documentation/nvme-wdc-log-page-directory.html @@ -758,7 +758,7 @@

      SYNOPSIS

      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 +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. @@ -771,10 +771,10 @@

      OPTIONS

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

      @@ -812,7 +812,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-log-page-directory.txt b/Documentation/nvme-wdc-log-page-directory.txt index 4d6192f040..27b5d9e9f8 100644 --- a/Documentation/nvme-wdc-log-page-directory.txt +++ b/Documentation/nvme-wdc-log-page-directory.txt @@ -13,7 +13,7 @@ SYNOPSIS 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 +log page IDs supported by the drive. The --output-format option will format the output as specified. The parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0). @@ -25,8 +25,8 @@ On success it returns the log page directory information, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', 'json', or 'binary'. Only one output format can be used at a time. The default is normal. diff --git a/Documentation/nvme-wdc-namespace-resize.1 b/Documentation/nvme-wdc-namespace-resize.1 index bdd4c2b511..88637d9e9c 100644 --- a/Documentation/nvme-wdc-namespace-resize.1 +++ b/Documentation/nvme-wdc-namespace-resize.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-namespace-resize .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-NAMESPACE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-NAMESPACE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,40 +32,26 @@ nvme-wdc-namespace-resize \- Resizes the device\*(Aqs namespace\&. .SH "SYNOPSIS" .sp .nf -\fInvme wdc namespace\-resize\fR [\-\-nsid=, \-n ] [\-\-op_option=, \-o ] +\fInvme wdc namespace\-resize\fR [\-\-nsid=, \-n ] + [\-\-op_option=, \-o ] .fi .SH "DESCRIPTION" .sp -For the NVMe device given, sends the WDC Vendor Specific Command that modifies the namespace size reported by the device\&. +For the NVMe device given, sends the WDC Vendor Specific Command that modifies the namespace size reported the device\&. .sp The parameter is mandatory NVMe character device (ex: /dev/nvme0)\&. .sp This will only work on WDC devices supporting this feature\&. Results for any other device are undefined\&. .SH "OPTIONS" .PP -\-n , \-\-namespace\-id= +\-n , \-\-namespace\-id= .RS 4 Namespace ID; ID of the namespace to resize .RE .PP \-o , \-\-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 -.\} +Overprovisioning Option; defaults to 0xF Valid Values: 0x1 \- 7% of Original TNVMCAP reported value 0x2 \- 28% of Original TNVMCAP reported value 0x3 \- 50% of Original TNVMCAP reported value 0xF \- 0% of Original TNVMCAP reported value (original config) All other values \- reserved .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-wdc-namespace-resize.html b/Documentation/nvme-wdc-namespace-resize.html index 06492677ea..d5fcc2ba21 100644 --- a/Documentation/nvme-wdc-namespace-resize.html +++ b/Documentation/nvme-wdc-namespace-resize.html @@ -749,7 +749,8 @@

      NAME

      SYNOPSIS

      -
      nvme wdc namespace-resize <device> [--nsid=<NAMSPACE ID>, -n <NAMSPACE ID>] [--op_option=<OP OPTION>, -o <OP OPTION>]
      +
      nvme wdc namespace-resize <device> [--nsid=<NAMESPACE ID>, -n <NAMSPACE ID>]
      +                        [--op_option=<OP OPTION>, -o <OP OPTION>]
      @@ -757,8 +758,8 @@

      SYNOPSIS

      DESCRIPTION

      -

      For the NVMe device given, sends the WDC Vendor Specific Command that modifies the namespace size reported -by the device.

      +

      For the NVMe device given, sends the WDC Vendor Specific Command that modifies +the namespace size reported the device.

      The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).

      This will only work on WDC devices supporting this feature. Results for any other device are undefined.

      @@ -769,10 +770,10 @@

      OPTIONS

      --n <NAMSPACE ID> +-n <NAMESPACE ID>
      ---namespace-id=<NAMSPACE_ID> +--namespace-id=<NAMESPACE_ID>

      @@ -787,17 +788,14 @@

      OPTIONS

      - Overprovisioning Option; defaults to 0xF + 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

      -
      -
      -
      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
      -
      @@ -838,7 +836,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-namespace-resize.txt b/Documentation/nvme-wdc-namespace-resize.txt index 71fc781272..42994adaa9 100644 --- a/Documentation/nvme-wdc-namespace-resize.txt +++ b/Documentation/nvme-wdc-namespace-resize.txt @@ -8,13 +8,14 @@ nvme-wdc-namespace-resize - Resizes the device's namespace. SYNOPSIS -------- [verse] -'nvme wdc namespace-resize' [--nsid=, -n ] [--op_option=, -o ] +'nvme wdc namespace-resize' [--nsid=, -n ] + [--op_option=, -o ] DESCRIPTION ----------- -For the NVMe device given, sends the WDC Vendor Specific Command that modifies the namespace size reported -by the device. +For the NVMe device given, sends the WDC Vendor Specific Command that modifies +the namespace size reported the device. The parameter is mandatory NVMe character device (ex: /dev/nvme0). @@ -23,20 +24,19 @@ Results for any other device are undefined. OPTIONS ------- --n :: ---namespace-id=:: +-n :: +--namespace-id=:: Namespace ID; ID of the namespace to resize -o :: --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 + 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 -------- diff --git a/Documentation/nvme-wdc-purge-monitor.1 b/Documentation/nvme-wdc-purge-monitor.1 index a1bd2dcdec..e01e1c1a99 100644 --- a/Documentation/nvme-wdc-purge-monitor.1 +++ b/Documentation/nvme-wdc-purge-monitor.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-purge-monitor .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-PURGE\-MO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-PURGE\-MO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-purge-monitor.html b/Documentation/nvme-wdc-purge-monitor.html index ccb8a229a6..c25a28f83f 100644 --- a/Documentation/nvme-wdc-purge-monitor.html +++ b/Documentation/nvme-wdc-purge-monitor.html @@ -837,7 +837,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-purge-monitor.txt b/Documentation/nvme-wdc-purge-monitor.txt index 313c8db192..5d441835d0 100644 --- a/Documentation/nvme-wdc-purge-monitor.txt +++ b/Documentation/nvme-wdc-purge-monitor.txt @@ -37,7 +37,6 @@ Expected status and description :- |Purge State Error : Purge operation interrupted by power cycle or reset. |=== - The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). diff --git a/Documentation/nvme-wdc-purge.1 b/Documentation/nvme-wdc-purge.1 index 7b65965218..89fb3b4846 100644 --- a/Documentation/nvme-wdc-purge.1 +++ b/Documentation/nvme-wdc-purge.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-purge .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-PURGE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-PURGE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-purge.html b/Documentation/nvme-wdc-purge.html index 7f02da7930..9afac8ed39 100644 --- a/Documentation/nvme-wdc-purge.html +++ b/Documentation/nvme-wdc-purge.html @@ -799,7 +799,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-set-latency-monitor-feature.txt b/Documentation/nvme-wdc-set-latency-monitor-feature.txt new file mode 100644 index 0000000000..60b3e266f4 --- /dev/null +++ b/Documentation/nvme-wdc-set-latency-monitor-feature.txt @@ -0,0 +1,118 @@ +nvme-wdc-set-latency-monitor-feature(1) +======================================= + +NAME +---- +nvme-wdc-set-latency-monitor-feature - Set NVMe WDC latency monitor feature options + +SYNOPSIS +-------- +[verse] +'nvme wdc set-latency-monitor-feature' + [--active_bucket_timer_threshold= | -t ] + [--active_threshold_a= | -a ] + [--active_threshold_b= | -b ] + [--active_threshold_c= | -c ] + [--active_threshold_d= | -d ] + [--active_latency_config= | -f ] + [--active_latency_minimum_window= | -w ] + [--debug_log_trigger_enable= | -r ] + [--discard_debug_log= | -l ] + [--latency_monitor_feature_enable= | -e ] + +DESCRIPTION +----------- +For the NVMe device given, this command set the +latency monitor feature options (if supported by the device). + +The parameter is mandatory NVMe character device (ex: /dev/nvme0). + +Setting results can be checked with 'get-latency-monitor-log' command. + +On success it returns 0, error code otherwise. + +OPTIONS +------- +-t :: +--active_bucket_timer_threshold=:: + The value that loads the Active Bucket Timer Threshold; default value is 07E0h. + +-a :: +--active_threshold_a=:: + The value that loads into the Active Threshold A; default value is 05h. + +-b :: +--active_threshold_b=:: + The value that loads into the Active Threshold B; default value is 13h. + +-c :: +--active_threshold_c=:: + The value that loads into the Active Threshold C; default value is 1Eh. + +-d :: +--active_threshold_d=:: + The value that loads into the Active Threshold D; default value is 2Eh. + +-f :: +--active_latency_config=:: + The value that loads into the Active Latency Configuration. This + configures how both the Active Latency Stamp, and the Active Measured + Latency Fields are updated on a per I/O command (Read, Write, Deallocate) + counter basis; default value is 0FFFh. + +-w :: +--active_latency_minimum_window=:: + The value that loads into the Active Latency Minimum Window; default value is 0Ah. + +-r :: +--debug_log_trigger_enable=:: + The value that loads into the Debug Log Trigger Enable; When set to 1b + the first time the bucket/counter combination is incremented a debug log + is triggered. When cleared to 0b a debug log will not be triggered when + the bucket/counter combination is incremented. + +-l :: +--discard_debug_log=:: + Discard Debug Log. When cleared to 00h the debug log, if it exists, will + not be cleared. When set to 01h the debug log will be discarded so + another log can be triggered. All the fields in the Set Features Data + structure are valid. When set to 02h the debug log will be discarded so + another log can be triggered. None of the other fields of the Set + Features Data structure are valid. + +-e :: +--latency_monitor_feature_enable=:: + Latency Monitor Feature Enable; When set to 01h the Latency Monitor + Feature is enabled. When cleared to 00h the Latency Monitor Feature is + disabled. + +EXAMPLES +-------- +* Set NVMe WDC latency monitor feature options enabled with default value values: ++ +------------ +# nvme wdc set-latency-monitor-feature /dev/nvme0 -e 1 +------------ +* Set NVMe WDC latency monitor feature options disabled with default value values: ++ +------------ +# nvme wdc set-latency-monitor-feature /dev/nvme0 -e 0 +------------ +* Set NVMe WDC latency monitor feature options enabled with specific values: ++ +------------ +# nvme wdc set-latency-monitor-feature /dev/nvme0 --active_bucket_timer_threshold=1 \ + --active_threshold_a=0x0 \ + --active_threshold_b=0x1 \ + --active_threshold_c=0x2 \ + --active_threshold_d=0x3 \ + --active_latency_config=0xfff \ + --active_latency_minimum_window=0 \ + --debug_log_trigger_enable=0 \ + --discard_debug_log=0 \ + --latency_monitor_feature_enable=0x1 +------------ + +NVME +---- +Part of the nvme-user suite. diff --git a/Documentation/nvme-wdc-vs-cloud-log.1 b/Documentation/nvme-wdc-vs-cloud-log.1 index 7f2dee135a..91f4c991dd 100644 --- a/Documentation/nvme-wdc-vs-cloud-log.1 +++ b/Documentation/nvme-wdc-vs-cloud-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-cloud-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-CLOUD" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-CLOUD" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -46,7 +46,7 @@ This will only work on WDC devices supporting this feature\&. Results for any ot On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-vs-cloud-log.html b/Documentation/nvme-wdc-vs-cloud-log.html index a6b91e01f5..f34317a633 100644 --- a/Documentation/nvme-wdc-vs-cloud-log.html +++ b/Documentation/nvme-wdc-vs-cloud-log.html @@ -772,10 +772,10 @@

      OPTIONS

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

      @@ -828,7 +828,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-cloud-log.txt b/Documentation/nvme-wdc-vs-cloud-log.txt index 9eeee421f6..9739295943 100644 --- a/Documentation/nvme-wdc-vs-cloud-log.txt +++ b/Documentation/nvme-wdc-vs-cloud-log.txt @@ -26,8 +26,8 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. diff --git a/Documentation/nvme-wdc-vs-device-waf.1 b/Documentation/nvme-wdc-vs-device-waf.1 index 31c57e12a6..d864c808c2 100644 --- a/Documentation/nvme-wdc-vs-device-waf.1 +++ b/Documentation/nvme-wdc-vs-device-waf.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-device-waf .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-DEVIC" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-DEVIC" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -46,7 +46,7 @@ This will only work on WDC devices supporting this feature\&. Results for any ot On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-vs-device-waf.html b/Documentation/nvme-wdc-vs-device-waf.html index 8b26fa24a3..a4a90be838 100644 --- a/Documentation/nvme-wdc-vs-device-waf.html +++ b/Documentation/nvme-wdc-vs-device-waf.html @@ -772,10 +772,10 @@

      OPTIONS

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

      @@ -828,7 +828,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-device-waf.txt b/Documentation/nvme-wdc-vs-device-waf.txt index 55095a4d4e..f25618d224 100644 --- a/Documentation/nvme-wdc-vs-device-waf.txt +++ b/Documentation/nvme-wdc-vs-device-waf.txt @@ -27,8 +27,8 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. diff --git a/Documentation/nvme-wdc-vs-drive-info.1 b/Documentation/nvme-wdc-vs-drive-info.1 index 7bbbad5e06..28162772e9 100644 --- a/Documentation/nvme-wdc-vs-drive-info.1 +++ b/Documentation/nvme-wdc-vs-drive-info.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-drive-info .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-DRIVE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-DRIVE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-vs-drive-info.html b/Documentation/nvme-wdc-vs-drive-info.html index b650acab67..ede45c7af8 100644 --- a/Documentation/nvme-wdc-vs-drive-info.html +++ b/Documentation/nvme-wdc-vs-drive-info.html @@ -795,7 +795,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-drive-info.txt b/Documentation/nvme-wdc-vs-drive-info.txt index 0cfdd7a232..bc18b173e2 100644 --- a/Documentation/nvme-wdc-vs-drive-info.txt +++ b/Documentation/nvme-wdc-vs-drive-info.txt @@ -38,12 +38,10 @@ HyperScale Boot Version TCG Device Ownership - EXAMPLE -------- # nvme wdc vs-drive-info /dev/nvme0 - NVME ---- Part of the nvme-user suite. diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.1 b/Documentation/nvme-wdc-vs-error-reason-identifier.1 index f05e920d73..05e12fb0f7 100644 --- a/Documentation/nvme-wdc-vs-error-reason-identifier.1 +++ b/Documentation/nvme-wdc-vs-error-reason-identifier.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-error-reason-identifier .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-ERROR" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-ERROR" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.html b/Documentation/nvme-wdc-vs-error-reason-identifier.html index 1aa0e4f764..4c96ee80e5 100644 --- a/Documentation/nvme-wdc-vs-error-reason-identifier.html +++ b/Documentation/nvme-wdc-vs-error-reason-identifier.html @@ -758,7 +758,7 @@

      SYNOPSIS

      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 +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. @@ -836,7 +836,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.txt b/Documentation/nvme-wdc-vs-error-reason-identifier.txt index 054d67597c..0c7f397a0b 100644 --- a/Documentation/nvme-wdc-vs-error-reason-identifier.txt +++ b/Documentation/nvme-wdc-vs-error-reason-identifier.txt @@ -13,8 +13,8 @@ SYNOPSIS 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. +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 parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0). @@ -27,7 +27,7 @@ OPTIONS ------- -i :: --log-id=:: - Specifies the telemetry log id of the error reason identifier to retrieve. + 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 diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.1 b/Documentation/nvme-wdc-vs-fw-activate-history.1 index 3528a7399a..9fab5aef67 100644 --- a/Documentation/nvme-wdc-vs-fw-activate-history.1 +++ b/Documentation/nvme-wdc-vs-fw-activate-history.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-fw-activate-history .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-FW\-A" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-FW\-A" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -45,7 +45,7 @@ This will only work on WDC devices supporting this feature\&. Results for any ot On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.html b/Documentation/nvme-wdc-vs-fw-activate-history.html index 0c4fbfdce1..cdae180414 100644 --- a/Documentation/nvme-wdc-vs-fw-activate-history.html +++ b/Documentation/nvme-wdc-vs-fw-activate-history.html @@ -770,10 +770,10 @@

      OPTIONS

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

      @@ -805,7 +805,7 @@

      Firmware Ac

      Entry Number

      -

      The number of fw activate entry. The most recent 20 entries will be displayed.

      +

      The number of fw activate entry. The most recent 20 entries will be displayed.

      Power on Hour

      @@ -833,7 +833,7 @@

      Firmware Ac

      Result

      -

      The result of the firmware activation event. The output shall be in the format: +

      The result of the firmware activation event. The output shall be in the format: Pass or Failed + error code

      @@ -868,7 +868,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.txt b/Documentation/nvme-wdc-vs-fw-activate-history.txt index 30c6edeaff..923ff0aa83 100644 --- a/Documentation/nvme-wdc-vs-fw-activate-history.txt +++ b/Documentation/nvme-wdc-vs-fw-activate-history.txt @@ -24,13 +24,12 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-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"] @@ -38,7 +37,7 @@ Firmware Activate History Log Page Data Output Explanation |Field |Description |*Entry Number* -|The number of fw activate entry. The most recent 20 entries will be displayed. +|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. @@ -59,7 +58,7 @@ Firmware Activate History Log Page Data Output Explanation |The commit action type associated with the firmware activation event |*Result* -|The result of the firmware activation event. The output shall be in the format: +|The result of the firmware activation event. The output shall be in the format: Pass or Failed + error code |=== diff --git a/Documentation/nvme-wdc-vs-hw-rev-log.1 b/Documentation/nvme-wdc-vs-hw-rev-log.1 index 8ec057c094..abe700f953 100644 --- a/Documentation/nvme-wdc-vs-hw-rev-log.1 +++ b/Documentation/nvme-wdc-vs-hw-rev-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-hw-rev-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-HW\-R" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-HW\-R" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -46,7 +46,7 @@ This will only work on WDC devices supporting this feature\&. Results for any ot On success it returns 0, error code otherwise\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, or diff --git a/Documentation/nvme-wdc-vs-hw-rev-log.html b/Documentation/nvme-wdc-vs-hw-rev-log.html index cee784bd05..5225883673 100644 --- a/Documentation/nvme-wdc-vs-hw-rev-log.html +++ b/Documentation/nvme-wdc-vs-hw-rev-log.html @@ -771,10 +771,10 @@

      OPTIONS

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

      @@ -827,7 +827,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-hw-rev-log.txt b/Documentation/nvme-wdc-vs-hw-rev-log.txt index c5335d957f..b4eb4dd8f3 100644 --- a/Documentation/nvme-wdc-vs-hw-rev-log.txt +++ b/Documentation/nvme-wdc-vs-hw-rev-log.txt @@ -25,8 +25,8 @@ On success it returns 0, error code otherwise. OPTIONS ------- --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. diff --git a/Documentation/nvme-wdc-vs-internal-log.1 b/Documentation/nvme-wdc-vs-internal-log.1 index e2f439b677..0f94172725 100644 --- a/Documentation/nvme-wdc-vs-internal-log.1 +++ b/Documentation/nvme-wdc-vs-internal-log.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-internal-log .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-INTER" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-INTER" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,12 @@ nvme-wdc-vs-internal-log \- Retrieve WDC device\*(Aqs internal firmware log and .SH "SYNOPSIS" .sp .nf -\fInvme wdc vs\-internal\-log\fR [\-\-output\-file=, \-o ] [\-\-transfer\-size=, \-s ] - [\-\-data\-area=, \-d ] [\-\-file\-size=, \-f ] [\-\-offset=, \-e ] - [\-\-type=, \-t ] [\-\-verbose, \-v] +\fInvme wdc vs\-internal\-log\fR [\-\-output\-file=, \-o ] + [\-\-transfer\-size=, \-s ] + [\-\-data\-area=, \-d ] + [\-\-file\-size=, \-f ] + [\-\-offset=, \-e ] + [\-\-type=, \-t ] [\-\-verbose, \-v] .fi .SH "DESCRIPTION" .sp diff --git a/Documentation/nvme-wdc-vs-internal-log.html b/Documentation/nvme-wdc-vs-internal-log.html index 90d3f0fb7a..e07879be12 100644 --- a/Documentation/nvme-wdc-vs-internal-log.html +++ b/Documentation/nvme-wdc-vs-internal-log.html @@ -749,9 +749,12 @@

      NAME

      SYNOPSIS

      -
      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]
      +
      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]
      @@ -759,8 +762,8 @@

      SYNOPSIS

      DESCRIPTION

      -

      For the NVMe device given, sends the WDC Vendor Specific Internal Log request and saves -the result to a file.

      +

      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.

      @@ -778,7 +781,8 @@

      OPTIONS

      - Output file; defaults to device serial number followed by "internal_fw_log<date>_<time>.bin" suffix + Output file; defaults to device serial number followed by + "internal_fw_log<date>_<time>.bin" suffix

      @@ -789,7 +793,7 @@

      OPTIONS

      - Transfer size; defaults to 0x10000 (65536 decimal) bytes + Transfer size; defaults to 0x10000 (65536 decimal) bytes

      @@ -800,8 +804,9 @@

      OPTIONS

      - DUI data area to retrieve. The DUI data areas from 1 to <DATA AREA> will be retrieved. This parameter - is currently only supported on the SN340, SN640, SN730, and SN840 devices. + DUI data area to retrieve. The DUI data areas from 1 to <DATA AREA> will + be retrieved. This parameter is currently only supported on the SN340, + SN640, SN730, and SN840 devices.

      @@ -812,9 +817,10 @@

      OPTIONS

      - Specifies the desired size of the data file starting at the passed in offset. This allows the user to - retrieve the data in several smaller files of the passed in size. This parameter is currently only - supported on the SN340 device. + Specifies the desired size of the data file starting at the passed in + offset. This allows the user to retrieve the data in several smaller + files of the passed in size. This parameter is currently only supported + on the SN340 device.

      @@ -825,9 +831,10 @@

      OPTIONS

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

      @@ -838,10 +845,11 @@

      OPTIONS

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

      @@ -950,7 +958,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-internal-log.txt b/Documentation/nvme-wdc-vs-internal-log.txt index 4fbde38e12..08f585b5ba 100644 --- a/Documentation/nvme-wdc-vs-internal-log.txt +++ b/Documentation/nvme-wdc-vs-internal-log.txt @@ -8,15 +8,18 @@ nvme-wdc-vs-internal-log - Retrieve WDC device's internal firmware log and save SYNOPSIS -------- [verse] -'nvme wdc vs-internal-log' [--output-file=, -o ] [--transfer-size=, -s ] - [--data-area=, -d ] [--file-size=, -f ] [--offset=, -e ] - [--type=, -t ] [--verbose, -v] +'nvme wdc vs-internal-log' [--output-file=, -o ] + [--transfer-size=, -s ] + [--data-area=, -d ] + [--file-size=, -f ] + [--offset=, -e ] + [--type=, -t ] [--verbose, -v] DESCRIPTION ----------- -For the NVMe device given, sends the WDC Vendor Specific Internal Log request and saves -the result to a file. +For the NVMe device given, sends the WDC Vendor Specific Internal Log request +and saves the result to a file. The parameter is mandatory NVMe character device (ex: /dev/nvme0). @@ -27,35 +30,40 @@ OPTIONS ------- -o :: --output-file=:: - Output file; defaults to device serial number followed by "_internal_fw_log__

      - Return the statistics from specific interval, defaults to 14. This parameter is only valid for the 0xC1 log page - and ignored for all other log pages. + Return the statistics from specific interval, defaults to 14. This + parameter is only valid for the 0xC1 log page and ignored for all other + log pages.

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

      @@ -807,8 +808,8 @@

      OPTIONS

      - Log Page Version: 0 = vendor, 1 = WDC. This parameter is only valid for the 0xC0 log page and ignored for all - other log pages. + Log Page Version: 0 = vendor, 1 = WDC. This parameter is only valid for + the 0xC0 log page and ignored for all other log pages.

      @@ -819,10 +820,10 @@

      OPTIONS

      - Supply a comma separated list of desired log pages to display. - The possible values are 0xc0, 0xc1, 0xca, 0xd0. - Note: Not all pages are supported on all drives. - The default is to display all supported log pages. + Supply a comma separated list of desired log pages to display. + The possible values are 0xc0, 0xc1, 0xca, 0xd0. + Note: Not all pages are supported on all drives. + The default is to display all supported log pages.

      @@ -927,7 +928,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-smart-add-log.txt b/Documentation/nvme-wdc-vs-smart-add-log.txt index 7de1ac8ffb..925287faa2 100644 --- a/Documentation/nvme-wdc-vs-smart-add-log.txt +++ b/Documentation/nvme-wdc-vs-smart-add-log.txt @@ -3,7 +3,8 @@ 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 +nvme-wdc-vs-smart-add-log - Send NVMe WDC vs-smart-add-log Vendor Unique Command, +return result SYNOPSIS -------- @@ -31,26 +32,27 @@ OPTIONS ------- -i :: --interval=:: - Return the statistics from specific interval, defaults to 14. This parameter is only valid for the 0xC1 log page - and ignored for all other log pages. + Return the statistics from specific interval, defaults to 14. This + parameter is only valid for the 0xC1 log page and ignored for all other + log pages. --o :: ---output-format=:: +-o :: +--output-format=:: Set the reporting format to 'normal', or 'json'. Only one output format can be used at a time. Default is normal. -l :: --log-page-version=:: - Log Page Version: 0 = vendor, 1 = WDC. This parameter is only valid for the 0xC0 log page and ignored for all - other log pages. + Log Page Version: 0 = vendor, 1 = WDC. This parameter is only valid for + the 0xC0 log page and ignored for all other log pages. -p :: --log-page-mask=:: - Supply a comma separated list of desired log pages to display. - The possible values are 0xc0, 0xc1, 0xca, 0xd0. - Note: Not all pages are supported on all drives. - The default is to display all supported log pages. + Supply a comma separated list of desired log pages to display. + The possible values are 0xc0, 0xc1, 0xca, 0xd0. + Note: Not all pages are supported on all drives. + The default is to display all supported log pages. -n :: --namespace-id=:: @@ -82,7 +84,6 @@ accumulated statistics. |The statistical set accumulated during the entire lifetime of the device. |=== - EXAMPLES -------- * Has the program issue WDC vs-smart-add-log Vendor Unique Command with default interval (14) : diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.1 b/Documentation/nvme-wdc-vs-telemetry-controller-option.1 index 82506e493a..713642e22d 100644 --- a/Documentation/nvme-wdc-vs-telemetry-controller-option.1 +++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-telemetry-controller-option .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-TELEM" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-TELEM" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,12 +32,12 @@ nvme-wdc-vs-telemetry-controller-option \- Disable/Enable the controller initiat .SH "SYNOPSIS" .sp .nf -\fInvme wdc vs\-telemetry\-controller\-option\fR [\-\-disable, \-d] [\-\-enable, \-e] - [\-\-status, \-s] +\fInvme wdc vs\-telemetry\-controller\-option\fR + [\-\-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\&. +For the NVMe device given, sends the WDC Vendor Specific set feature command to disable, enable or get current status the controller initiated option of the telemetry log page\&. .sp The parameter is mandatory NVMe character device (ex: /dev/nvme0)\&. .sp diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.html b/Documentation/nvme-wdc-vs-telemetry-controller-option.html index 87e8c38cfa..0a0cbf8d4a 100644 --- a/Documentation/nvme-wdc-vs-telemetry-controller-option.html +++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.html @@ -749,8 +749,8 @@

      NAME

      SYNOPSIS

      -
      nvme wdc vs-telemetry-controller-option <device> [--disable, -d] [--enable, -e]
      -    [--status, -s]
      +
      nvme wdc vs-telemetry-controller-option <device>
      +                        [--disable, -d] [--enable, -e] [--status, -s]
      @@ -758,8 +758,9 @@

      SYNOPSIS

      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.

      +

      For the NVMe device given, sends the WDC Vendor Specific set feature command to +disable, enable or get current status the controller initiated option of the +telemetry log page.

      The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).

      This will only work on WDC devices supporting this feature. Results for any other device are undefined.

      @@ -799,7 +800,8 @@

      OPTIONS

      - Returns the current status (enabled or disabled) of the controller initiated option of the telemetry log page. + Returns the current status (enabled or disabled) of the controller + initiated option of the telemetry log page.

      @@ -853,7 +855,7 @@

      NVME

      diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.txt b/Documentation/nvme-wdc-vs-telemetry-controller-option.txt index 8c1a7e728a..2353e7c0a2 100644 --- a/Documentation/nvme-wdc-vs-telemetry-controller-option.txt +++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.txt @@ -3,19 +3,21 @@ 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. +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' [--disable, -d] [--enable, -e] - [--status, -s] +'nvme wdc vs-telemetry-controller-option' + [--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. +For the NVMe device given, sends the WDC Vendor Specific set feature command to +disable, enable or get current status the controller initiated option of the +telemetry log page. The parameter is mandatory NVMe character device (ex: /dev/nvme0). @@ -34,8 +36,8 @@ OPTIONS -s:: --status:: - Returns the current status (enabled or disabled) of the controller initiated option of the telemetry log page. - + Returns the current status (enabled or disabled) of the controller + initiated option of the telemetry log page. EXAMPLES -------- diff --git a/Documentation/nvme-wdc-vs-temperature-stats.1 b/Documentation/nvme-wdc-vs-temperature-stats.1 index b34350e81e..4206337c77 100644 --- a/Documentation/nvme-wdc-vs-temperature-stats.1 +++ b/Documentation/nvme-wdc-vs-temperature-stats.1 @@ -2,12 +2,12 @@ .\" Title: nvme-wdc-vs-temperature-stats .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WDC\-VS\-TEMPE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WDC\-VS\-TEMPE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-wdc-vs-temperature-stats.html b/Documentation/nvme-wdc-vs-temperature-stats.html index ad18037665..cf2fa1d313 100644 --- a/Documentation/nvme-wdc-vs-temperature-stats.html +++ b/Documentation/nvme-wdc-vs-temperature-stats.html @@ -857,7 +857,7 @@

      NVME

      diff --git a/Documentation/nvme-write-uncor.1 b/Documentation/nvme-write-uncor.1 index e41697cbb5..1523285595 100644 --- a/Documentation/nvme-write-uncor.1 +++ b/Documentation/nvme-write-uncor.1 @@ -2,12 +2,12 @@ .\" Title: nvme-uncor .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-UNCOR" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-UNCOR" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -35,31 +35,52 @@ nvme-write-uncor \- Send an NVMe write uncorrectable command, return results \fInvme\-write\-uncor\fR [\-\-start\-block= | \-s ] [\-\-block\-count= | \-c ] [\-\-namespace\-id= | \-n ] - [\-\-force] + [\-\-dir\-type= | \-T ] + [\-\-dir\-spec= | \-S ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Write Uncorrectable command is used to invalidate a range of logical blocks\&. .SH "OPTIONS" .PP -\-\-start\-block=, \-s +\-s , \-\-start\-block= .RS 4 Start block\&. .RE .PP -\-\-block\-count=, \-c +\-c, \-\-block\-count= .RS 4 Number of logical blocks to write uncorrectable\&. .RE .PP -\-\-namespace\-id=, \-n +\-n , \-\-namespace\-id= .RS 4 Namespace ID use in the command\&. .RE .PP -\-\-force +\-T , \-\-dir\-type= .RS 4 -Ignore namespace is currently busy and performed the operation even though\&. +Directive type +.RE +.PP +\-S , \-\-dir\-spec= +.RS 4 +Directive specific +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-write-uncor.html b/Documentation/nvme-write-uncor.html index 9cedd437df..f4e58a99b4 100644 --- a/Documentation/nvme-write-uncor.html +++ b/Documentation/nvme-write-uncor.html @@ -752,7 +752,9 @@

      SYNOPSIS

      nvme-write-uncor <device> [--start-block=<slba> | -s <slba>]
                               [--block-count=<nlb> | -c <nlb>]
                               [--namespace-id=<nsid> | -n <nsid>]
      -                        [--force]
      + [--dir-type=<dtype> | -T <dtype>] + [--dir-spec=<dspec> | -S <dspec>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
      @@ -769,10 +771,10 @@

      OPTIONS

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

      @@ -780,10 +782,10 @@

      OPTIONS

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

      @@ -791,10 +793,10 @@

      OPTIONS

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

      @@ -802,12 +804,48 @@

      OPTIONS

      ---force +-T <dtype> +
      +
      +--dir-type=<dtype> +
      +
      +

      + Directive type +

      +
      +
      +-S <dspec> +
      +
      +--dir-spec=<dspec> +
      +
      +

      + Directive specific +

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

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

      +
      +
      +-v +
      +
      +--verbose

      - Ignore namespace is currently busy and performed the operation - even though. + Increase the information detail in the output.

      @@ -830,7 +868,7 @@

      NVME

      diff --git a/Documentation/nvme-write-uncor.txt b/Documentation/nvme-write-uncor.txt index 38af31364c..6e49c61088 100644 --- a/Documentation/nvme-write-uncor.txt +++ b/Documentation/nvme-write-uncor.txt @@ -11,7 +11,9 @@ SYNOPSIS 'nvme-write-uncor' [--start-block= | -s ] [--block-count= | -c ] [--namespace-id= | -n ] - [--force] + [--dir-type= | -T ] + [--dir-spec= | -S ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -20,21 +22,34 @@ blocks. OPTIONS ------- ---start-block=:: -s :: +--start-block=:: Start block. ---block-count=:: -c:: +--block-count=:: Number of logical blocks to write uncorrectable. ---namespace-id=:: -n :: +--namespace-id=:: Namespace ID use in the command. ---force:: - Ignore namespace is currently busy and performed the operation - even though. +-T :: +--dir-type=:: + Directive type + +-S :: +--dir-spec=:: + Directive specific + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-write-zeroes.1 b/Documentation/nvme-write-zeroes.1 index 8d2161e0f8..c21c69152a 100644 --- a/Documentation/nvme-write-zeroes.1 +++ b/Documentation/nvme-write-zeroes.1 @@ -2,12 +2,12 @@ .\" Title: nvme-write-zeroes .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WRITE\-ZEROES" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WRITE\-ZEROES" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -37,31 +37,31 @@ nvme-write-zeroes \- Send an NVMe write zeroes command, return results [\-\-ref\-tag= | \-r ] [\-\-prinfo= | \-p ] [\-\-app\-tag\-mask= | \-m ] - [\-\-app\-tag= | \-a ] - [\-\-deac | \-d] - [\-\-limited\-retry | \-l] - [\-\-force\-unit\-access | \-f] + [\-\-app\-tag= | \-a ] [\-\-deac | \-d] + [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f] [\-\-namespace\-id= | \-n ] [\-\-storage\-tag | \-S ] [\-\-storage\-tag\-check | \-C ] - [\-\-force] + [\-\-dir\-type= | \-T ] + [\-\-dir\-spec= | \-D ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Write Zeroes command is used to set a range of logical blocks to 0\&. .SH "OPTIONS" .PP -\-\-start\-block=, \-s +\-s , \-\-start\-block= .RS 4 Start block\&. .RE .PP -\-\-block\-count=, \-c +\-c , \-\-block\-count= .RS 4 Number of logical blocks to write zeroes\&. .RE .PP -\-\-prinfo=, \-p +\-p , \-\-prinfo= .RS 4 Protection Information field definition\&. .TS @@ -106,54 +106,73 @@ T} .sp 1 .RE .PP -\-\-ref\-tag=, \-r +\-r , \-\-ref\-tag= .RS 4 Optional reftag when used with protection information\&. .RE .PP -\-\-app\-tag\-mask=, \-m +\-m , \-\-app\-tag\-mask= .RS 4 Optional application tag mask when used with protection information\&. .RE .PP -\-\-app\-tag=, \-a +\-a , \-\-app\-tag= .RS 4 Optional application tag when used with protection information\&. .RE .PP -\-\-limited\-retry, \-l +\-l, \-\-limited\-retry .RS 4 Sets the limited retry flag\&. .RE .PP -\-\-deac, \-d +\-d, \-\-deac .RS 4 Sets the DEAC bit, requesting controller deallocate the logical blocks\&. .RE .PP -\-\-force\-unit\-access, \-f +\-f, \-\-force\-unit\-access .RS 4 Set the force\-unit access flag\&. .RE .PP -\-\-namespace\-id=, \-n +\-n , \-\-namespace\-id= .RS 4 Namespace ID use in the command\&. .RE .PP -\-\-storage\-tag=, \-S +\-S , \-\-storage\-tag= .RS 4 Variable Sized Logical Block Storage Tag(LBST)\&. .RE .PP -\-\-storage\-tag\-check=, \-C +\-C , \-\-storage\-tag\-check= .RS 4 This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. .RE .PP -\-\-force +\-T , \-\-dir\-type= .RS 4 -Ignore namespace is currently busy and performed the operation even though\&. +Directive type +.RE +.PP +\-D , \-\-dir\-spec= +.RS 4 +Directive specific +.RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. .RE .SH "EXAMPLES" .sp diff --git a/Documentation/nvme-write-zeroes.html b/Documentation/nvme-write-zeroes.html index 1155a6187d..d5820b3838 100644 --- a/Documentation/nvme-write-zeroes.html +++ b/Documentation/nvme-write-zeroes.html @@ -754,14 +754,14 @@

      SYNOPSIS

      [--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] + [--app-tag=<apptag> | -a <apptag>] [--deac | -d] + [--limited-retry | -l] [--force-unit-access | -f] [--namespace-id=<nsid> | -n <nsid>] [--storage-tag<storage-tag> | -S <storage-tag>] [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>] - [--force] + [--dir-type=<dtype> | -T <dtype>] + [--dir-spec=<dspec> | -D <dspec>] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
      @@ -777,10 +777,10 @@

      OPTIONS

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

      @@ -788,10 +788,10 @@

      OPTIONS

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

      @@ -799,10 +799,10 @@

      OPTIONS

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

      @@ -847,10 +847,10 @@

      OPTIONS

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

      @@ -858,10 +858,10 @@

      OPTIONS

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

      @@ -869,10 +869,10 @@

      OPTIONS

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

      @@ -880,10 +880,10 @@

      OPTIONS

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

      @@ -891,10 +891,10 @@

      OPTIONS

      ---deac +-d
      --d +--deac

      @@ -902,10 +902,10 @@

      OPTIONS

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

      @@ -913,10 +913,10 @@

      OPTIONS

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

      @@ -924,10 +924,10 @@

      OPTIONS

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

      @@ -935,10 +935,10 @@

      OPTIONS

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

      @@ -947,12 +947,48 @@

      OPTIONS

      ---force +-T <dtype> +
      +
      +--dir-type=<dtype> +
      +
      +

      + Directive type +

      +
      +
      +-D <dspec> +
      +
      +--dir-spec=<dspec> +
      +
      +

      + Directive specific +

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

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

      +
      +
      +-v +
      +
      +--verbose

      - Ignore namespace is currently busy and performed the operation - even though. + Increase the information detail in the output.

      @@ -975,7 +1011,7 @@

      NVME

      diff --git a/Documentation/nvme-write-zeroes.txt b/Documentation/nvme-write-zeroes.txt index cfcac36fe8..0daf320944 100644 --- a/Documentation/nvme-write-zeroes.txt +++ b/Documentation/nvme-write-zeroes.txt @@ -13,14 +13,14 @@ SYNOPSIS [--ref-tag= | -r ] [--prinfo= | -p ] [--app-tag-mask= | -m ] - [--app-tag= | -a ] - [--deac | -d] - [--limited-retry | -l] - [--force-unit-access | -f] + [--app-tag= | -a ] [--deac | -d] + [--limited-retry | -l] [--force-unit-access | -f] [--namespace-id= | -n ] [--storage-tag | -S ] [--storage-tag-check | -C ] - [--force] + [--dir-type= | -T ] + [--dir-spec= | -D ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -28,16 +28,16 @@ The Write Zeroes command is used to set a range of logical blocks to 0. OPTIONS ------- ---start-block=:: -s :: +--start-block=:: Start block. ---block-count=:: -c :: +--block-count=:: Number of logical blocks to write zeroes. ---prinfo=:: -p :: +--prinfo=:: Protection Information field definition. + [] @@ -52,46 +52,59 @@ metadata is passes. |0|Set to 1 enables checking the reference tag |================= ---ref-tag=:: -r :: +--ref-tag=:: Optional reftag when used with protection information. ---app-tag-mask=:: -m :: +--app-tag-mask=:: Optional application tag mask when used with protection information. ---app-tag=:: -a :: +--app-tag=:: Optional application tag when used with protection information. ---limited-retry:: -l:: +--limited-retry:: Sets the limited retry flag. ---deac:: -d:: +--deac:: Sets the DEAC bit, requesting controller deallocate the logical blocks. ---force-unit-access:: -f:: +--force-unit-access:: Set the force-unit access flag. ---namespace-id=:: -n :: +--namespace-id=:: Namespace ID use in the command. ---storage-tag=:: -S :: +--storage-tag=:: Variable Sized Logical Block Storage Tag(LBST). ---storage-tag-check=:: -C :: +--storage-tag-check=:: This bit specifies the Storage Tag field shall be checked as part of end-to-end data protection processing. ---force:: - Ignore namespace is currently busy and performed the operation - even though. +-T :: +--dir-type=:: + Directive type + +-D :: +--dir-spec=:: + Directive specific + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-write.1 b/Documentation/nvme-write.1 index 62e1349297..64757b4884 100644 --- a/Documentation/nvme-write.1 +++ b/Documentation/nvme-write.1 @@ -2,12 +2,12 @@ .\" Title: nvme-write .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WRITE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-WRITE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -42,53 +42,50 @@ nvme-write \- Send an NVMe write command, provide results [\-\-prinfo= | \-p ] [\-\-app\-tag\-mask= | \-m ] [\-\-app\-tag= | \-a ] - [\-\-limited\-retry | \-l] - [\-\-force\-unit\-access | \-f] + [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f] [\-\-dir\-type= | \-T ] - [\-\-dir\-spec= | \-S ] - [\-\-dsm= | \-D ] - [\-\-show\-command | \-v] - [\-\-dry\-run | \-w] - [\-\-latency | \-t] - [\-\-storage\-tag\-check | \-C ] - [\-\-force] + [\-\-dir\-spec= | \-S ] [\-\-dsm= | \-D ] + [\-\-show\-command | \-V] [\-\-dry\-run | \-w] [\-\-latency | \-t] + [\-\-storage\-tag | \-g ] + [\-\-storage\-tag\-check | \-C] [\-\-force] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp The Write command writes the logical blocks specified by the command to the medium from the data data buffer provided\&. Will use stdin by default if you don\(cqt provide a file\&. .SH "OPTIONS" .PP -\-\-start\-block=, \-s +\-s , \-\-start\-block= .RS 4 Start block\&. .RE .PP -\-\-block\-count, \-c +\-c, \-\-block\-count .RS 4 The number of blocks to transfer\&. This is a zeroes based value to align with the kernel\(cqs use of this field\&. (ie\&. 0 means transfer 1 block)\&. .RE .PP -\-\-data\-size=, \-z +\-z , \-\-data\-size= .RS 4 Size of data, in bytes\&. .RE .PP -\-\-metadata\-size=, \-y +\-y , \-\-metadata\-size= .RS 4 Size of metadata in bytes\&. .RE .PP -\-\-data=, \-d +\-d , \-\-data= .RS 4 Data file\&. If none provided, contents are sent from STDIN\&. .RE .PP -\-\-metadata=, \-M +\-M , \-\-metadata= .RS 4 Metadata file, if necessary\&. .RE .PP -\-\-prinfo=, \-p +\-p , \-\-prinfo= .RS 4 Protection Information field definition\&. .TS @@ -133,27 +130,27 @@ T} .sp 1 .RE .PP -\-\-ref\-tag=, \-r +\-r , \-\-ref\-tag= .RS 4 Optional reftag when used with protection information\&. .RE .PP -\-\-app\-tag\-mask=, \-m +\-m , \-\-app\-tag\-mask= .RS 4 Optional application tag mask when used with protection information\&. .RE .PP -\-\-app\-tag=, \-a +\-a , \-\-app\-tag= .RS 4 Optional application tag when used with protection information\&. .RE .PP -\-\-limited\-retry, \-l +\-l, \-\-limited\-retry .RS 4 Sets the limited retry flag\&. .RE .PP -\-\-force\-unit\-access, \-f +\-f, \-\-force\-unit\-access .RS 4 Set the force\-unit access flag\&. .RE @@ -173,7 +170,7 @@ Optional field for directive specifics\&. When used with write streams, this val The optional data set management attributes for this command\&. The argument for this is the least significant 8 bits of the DSM field in a write command; the most significant 16 bits of the field come from the directive specific field, if used\&. This may be used to set attributes for the LBAs being written, like access frequency, type, latency, among other things, as well as yet to be defined types\&. Please consult the NVMe specification for detailed breakdown of how to use this field\&. .RE .PP -\-v, \-\-show\-cmd +\-V, \-\-show\-cmd .RS 4 Print out the command to be sent\&. .RE @@ -191,15 +188,34 @@ be set\&. Otherwise \-\-dry\-run option will be Print out the latency the IOCTL took (in us)\&. .RE .PP -\-\-storage\-tag\-check=, \-C +\-g , \-\-storage\-tag= .RS 4 -This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +Variable Sized Expected Logical Block Storage Tag(ELBST)\&. +.RE +.PP +\-C, \-\-storage\-tag\-check +.RS 4 +This flag enables Storage Tag field checking as part of end\-to\-end data protection processing\&. .RE .PP \-\-force .RS 4 Ignore namespace is currently busy and performed the operation even though\&. .RE +.PP +\-o , \-\-output\-format= +.RS 4 +Set the reporting format to +\fInormal\fR, +\fIjson\fR +or +\fIbinary\fR\&. Only one output format can be used at a time\&. +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-write.html b/Documentation/nvme-write.html index 0f609c7741..44710718e0 100644 --- a/Documentation/nvme-write.html +++ b/Documentation/nvme-write.html @@ -759,16 +759,13 @@

      SYNOPSIS

      [--prinfo=<prinfo> | -p <prinfo>] [--app-tag-mask=<appmask> | -m <appmask>] [--app-tag=<apptag> | -a <apptag>] - [--limited-retry | -l] - [--force-unit-access | -f] + [--limited-retry | -l] [--force-unit-access | -f] [--dir-type=<type> | -T <type>] - [--dir-spec=<spec> | -S <spec>] - [--dsm=<dsm> | -D <dsm>] - [--show-command | -v] - [--dry-run | -w] - [--latency | -t] - [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>] - [--force] + [--dir-spec=<spec> | -S <spec>] [--dsm=<dsm> | -D <dsm>] + [--show-command | -V] [--dry-run | -w] [--latency | -t] + [--storage-tag<storage-tag> | -g <storage-tag>] + [--storage-tag-check | -C] [--force] + [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
      @@ -786,10 +783,10 @@

      OPTIONS

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

      @@ -797,10 +794,10 @@

      OPTIONS

      ---block-count +-c
      --c +--block-count

      @@ -810,10 +807,10 @@

      OPTIONS

      ---data-size=<size> +-z <size>
      --z <size> +--data-size=<size>

      @@ -821,10 +818,10 @@

      OPTIONS

      ---metadata-size=<size> +-y <size>
      --y <size> +--metadata-size=<size>

      @@ -832,10 +829,10 @@

      OPTIONS

      ---data=<data-file> +-d <data-file>
      --d <data-file> +--data=<data-file>

      @@ -843,10 +840,10 @@

      OPTIONS

      ---metadata=<metadata-file> +-M <metadata-file>
      --M <metadata-file> +--metadata=<metadata-file>

      @@ -854,10 +851,10 @@

      OPTIONS

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

      @@ -902,10 +899,10 @@

      OPTIONS

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

      @@ -913,10 +910,10 @@

      OPTIONS

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

      @@ -924,10 +921,10 @@

      OPTIONS

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

      @@ -935,10 +932,10 @@

      OPTIONS

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

      @@ -946,10 +943,10 @@

      OPTIONS

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

      @@ -1003,7 +1000,7 @@

      OPTIONS

      --v +-V
      --show-cmd @@ -1038,14 +1035,25 @@

      OPTIONS

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

      - This bit specifies the Storage Tag field shall be checked as part of end-to-end + Variable Sized Expected Logical Block Storage Tag(ELBST). +

      +
      +
      +-C +
      +
      +--storage-tag-check +
      +
      +

      + This flag enables Storage Tag field checking as part of end-to-end data protection processing.

      @@ -1054,8 +1062,31 @@

      OPTIONS

      - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. +

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

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

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

      + Increase the information detail in the output.

      @@ -1078,7 +1109,7 @@

      NVME

      diff --git a/Documentation/nvme-write.txt b/Documentation/nvme-write.txt index 837bd5cac3..af5340e9c0 100644 --- a/Documentation/nvme-write.txt +++ b/Documentation/nvme-write.txt @@ -18,16 +18,13 @@ SYNOPSIS [--prinfo= | -p ] [--app-tag-mask= | -m ] [--app-tag= | -a ] - [--limited-retry | -l] - [--force-unit-access | -f] + [--limited-retry | -l] [--force-unit-access | -f] [--dir-type= | -T ] - [--dir-spec= | -S ] - [--dsm= | -D ] - [--show-command | -v] - [--dry-run | -w] - [--latency | -t] - [--storage-tag-check | -C ] - [--force] + [--dir-spec= | -S ] [--dsm= | -D ] + [--show-command | -V] [--dry-run | -w] [--latency | -t] + [--storage-tag | -g ] + [--storage-tag-check | -C] [--force] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -37,34 +34,34 @@ if you don't provide a file. OPTIONS ------- ---start-block=:: -s :: +--start-block=:: Start block. ---block-count:: -c:: +--block-count:: The number of blocks to transfer. This is a zeroes based value to align with the kernel's use of this field. (ie. 0 means transfer 1 block). ---data-size=:: -z :: +--data-size=:: Size of data, in bytes. ---metadata-size=:: -y :: +--metadata-size=:: Size of metadata in bytes. ---data=:: -d :: +--data=:: Data file. If none provided, contents are sent from STDIN. ---metadata=:: -M :: +--metadata=:: Metadata file, if necessary. ---prinfo=:: -p :: +--prinfo=:: Protection Information field definition. + [] @@ -79,24 +76,24 @@ metadata is passes. |0|Set to 1 enables checking the reference tag |================= ---ref-tag=:: -r :: +--ref-tag=:: Optional reftag when used with protection information. ---app-tag-mask=:: -m :: +--app-tag-mask=:: Optional application tag mask when used with protection information. ---app-tag=:: -a :: +--app-tag=:: Optional application tag when used with protection information. ---limited-retry:: -l:: +--limited-retry:: Sets the limited retry flag. ---force-unit-access:: -f:: +--force-unit-access:: Set the force-unit access flag. -T :: @@ -124,7 +121,7 @@ metadata is passes. consult the NVMe specification for detailed breakdown of how to use this field. --v:: +-V:: --show-cmd:: Print out the command to be sent. @@ -138,14 +135,27 @@ metadata is passes. --latency:: Print out the latency the IOCTL took (in us). ---storage-tag-check=:: --C :: - This bit specifies the Storage Tag field shall be checked as part of end-to-end +-g :: +--storage-tag=:: + Variable Sized Expected Logical Block Storage Tag(ELBST). + +-C:: +--storage-tag-check:: + This flag enables Storage Tag field checking as part of end-to-end data protection processing. --force:: - Ignore namespace is currently busy and performed the operation - even though. + Ignore namespace is currently busy and performed the operation + even though. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json' or 'binary'. Only one + output format can be used at a time. + +-v:: +--verbose:: + Increase the information detail in the output. EXAMPLES -------- diff --git a/Documentation/nvme-zns-changed-zone-list.1 b/Documentation/nvme-zns-changed-zone-list.1 index 46bb70bdea..2617f59740 100644 --- a/Documentation/nvme-zns-changed-zone-list.1 +++ b/Documentation/nvme-zns-changed-zone-list.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-changed-zone-list .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-CHANGED\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-CHANGED\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,8 @@ nvme-zns-changed-zone-list \- Retrieve Changed Zone log for the given device .SH "SYNOPSIS" .sp .nf -\fInvme zns changed\-zone\-list\fR [\-o | \-\-output\-format=] - [\-\-namespace\-id= | \-n ] - [\-\-rae | \-r] +\fInvme zns changed\-zone\-list\fR [\-\-output\-format= | \-o ] + [\-\-namespace\-id= | \-n ] [\-\-rae | \-r] .fi .SH "DESCRIPTION" .sp @@ -45,7 +44,7 @@ The parameter is mandatory and may be either the NVMe character device On success, the returned list may be decoded and displayed in one of several ways\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-zns-changed-zone-list.html b/Documentation/nvme-zns-changed-zone-list.html index c551af0087..a52942ea7f 100644 --- a/Documentation/nvme-zns-changed-zone-list.html +++ b/Documentation/nvme-zns-changed-zone-list.html @@ -749,9 +749,8 @@

      NAME

      SYNOPSIS

      -
      nvme zns changed-zone-list <device> [-o <fmt> | --output-format=<fmt>]
      -                                      [--namespace-id=<NUM> | -n <NUM>]
      -                                      [--rae | -r]
      +
      nvme zns changed-zone-list <device> [--output-format=<fmt> | -o <fmt>]
      +                        [--namespace-id=<NUM> | -n <NUM>] [--rae | -r]
      @@ -772,15 +771,15 @@

      OPTIONS

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

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

      @@ -833,7 +832,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-changed-zone-list.txt b/Documentation/nvme-zns-changed-zone-list.txt index 9626c05ecf..ad447cea39 100644 --- a/Documentation/nvme-zns-changed-zone-list.txt +++ b/Documentation/nvme-zns-changed-zone-list.txt @@ -8,9 +8,8 @@ nvme-zns-changed-zone-list - Retrieve Changed Zone log for the given device SYNOPSIS -------- [verse] -'nvme zns changed-zone-list' [-o | --output-format=] - [--namespace-id= | -n ] - [--rae | -r] +'nvme zns changed-zone-list' [--output-format= | -o ] + [--namespace-id= | -n ] [--rae | -r] DESCRIPTION ----------- @@ -25,10 +24,10 @@ ways. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. -r:: --rae:: diff --git a/Documentation/nvme-zns-close-zone.1 b/Documentation/nvme-zns-close-zone.1 index f105592021..6443d0b0f6 100644 --- a/Documentation/nvme-zns-close-zone.1 +++ b/Documentation/nvme-zns-close-zone.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-close-zone .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-CLOSE\-ZO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-CLOSE\-ZO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-zns-close-zone.html b/Documentation/nvme-zns-close-zone.html index 423984440d..55e431248a 100644 --- a/Documentation/nvme-zns-close-zone.html +++ b/Documentation/nvme-zns-close-zone.html @@ -846,7 +846,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-finish-zone.1 b/Documentation/nvme-zns-finish-zone.1 index 0e1bd2567e..de7f76a725 100644 --- a/Documentation/nvme-zns-finish-zone.1 +++ b/Documentation/nvme-zns-finish-zone.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-finish-zone .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-FINISH\-Z" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-FINISH\-Z" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-zns-finish-zone.html b/Documentation/nvme-zns-finish-zone.html index b6e6815766..ef7bcb8f62 100644 --- a/Documentation/nvme-zns-finish-zone.html +++ b/Documentation/nvme-zns-finish-zone.html @@ -847,7 +847,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-id-ctrl.1 b/Documentation/nvme-zns-id-ctrl.1 index f9e920a647..4a954841af 100644 --- a/Documentation/nvme-zns-id-ctrl.1 +++ b/Documentation/nvme-zns-id-ctrl.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-id-ctrl .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-ID\-CTRL" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-ID\-CTRL" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,7 +32,7 @@ nvme-zns-id-ctrl \- Send NVMe Zoned Command Set Identify Controller, return resu .SH "SYNOPSIS" .sp .nf -\fInvme zns id\-ctrl\fR [\-o | \-\-output\-format=] +\fInvme zns id\-ctrl\fR [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp @@ -43,7 +43,7 @@ The parameter is mandatory and may be either the NVMe character device On success, the data structure returned by the device will be decoded and displayed in one of several ways\&. .SH "OPTIONS" .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-zns-id-ctrl.html b/Documentation/nvme-zns-id-ctrl.html index 0ec955df50..16b891439a 100644 --- a/Documentation/nvme-zns-id-ctrl.html +++ b/Documentation/nvme-zns-id-ctrl.html @@ -740,7 +740,7 @@

      NAME

      nvme-zns-id-ctrl - - Send NVMe Zoned Command Set Identify Controller, return result and structure + Send NVMe Zoned Command Set Identify Controller, return result and structure

      @@ -749,7 +749,7 @@

      NAME

      SYNOPSIS

      -
      nvme zns id-ctrl <device> [-o <fmt> | --output-format=<fmt>]
      +
      nvme zns id-ctrl <device> [--output-format=<fmt> | -o <fmt>]
      @@ -770,15 +770,15 @@

      OPTIONS

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

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

      @@ -821,7 +821,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-id-ctrl.txt b/Documentation/nvme-zns-id-ctrl.txt index e7bd5baab2..00571592b7 100644 --- a/Documentation/nvme-zns-id-ctrl.txt +++ b/Documentation/nvme-zns-id-ctrl.txt @@ -4,12 +4,12 @@ nvme-zns-id-ctrl(1) NAME ---- nvme-zns-id-ctrl - Send NVMe Zoned Command Set Identify Controller, return - result and structure +result and structure SYNOPSIS -------- [verse] -'nvme zns id-ctrl' [-o | --output-format=] +'nvme zns id-ctrl' [--output-format= | -o ] DESCRIPTION ----------- @@ -24,10 +24,10 @@ displayed in one of several ways. OPTIONS ------- --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-zns-id-ns.1 b/Documentation/nvme-zns-id-ns.1 index 6aa126b2a8..61d57b8258 100644 --- a/Documentation/nvme-zns-id-ns.1 +++ b/Documentation/nvme-zns-id-ns.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-id-ns .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-ID\-NS" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-ID\-NS" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -32,9 +32,8 @@ nvme-zns-id-ns \- Send NVMe Zoned Command Set Identify namespace, return result .SH "SYNOPSIS" .sp .nf -\fInvme zns id\-ns\fR [\-\-namespace\-id= | \-n ] - [\-o | \-\-output\-format=] - [\-v | \-\-verbose] +\fInvme zns id\-ns\fR [\-\-namespace\-id= | \-n ] + [\-\-output\-format= | \-o ] [\-\-verbose | \-v] .fi .SH "DESCRIPTION" .sp @@ -55,7 +54,7 @@ Use the provided namespace id for the command\&. If not provided, the namespace Increase the information detail in the output\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-zns-id-ns.html b/Documentation/nvme-zns-id-ns.html index 140075fa80..f099014034 100644 --- a/Documentation/nvme-zns-id-ns.html +++ b/Documentation/nvme-zns-id-ns.html @@ -740,7 +740,7 @@

      NAME

      nvme-zns-id-ns - - Send NVMe Zoned Command Set Identify namespace, return result and structure + Send NVMe Zoned Command Set Identify namespace, return result and structure

      @@ -749,9 +749,8 @@

      NAME

      SYNOPSIS

      -
      nvme zns id-ns <device>  [--namespace-id=<NUM> | -n <NUM>]
      -                             [-o <fmt> | --output-format=<fmt>]
      -                             [-v | --verbose]
      +
      nvme zns id-ns <device> [--namespace-id=<NUM> | -n <NUM>]
      +                        [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
      @@ -796,15 +795,15 @@

      OPTIONS

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

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

      @@ -847,7 +846,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-id-ns.txt b/Documentation/nvme-zns-id-ns.txt index 799e3b6753..c22b5c7bce 100644 --- a/Documentation/nvme-zns-id-ns.txt +++ b/Documentation/nvme-zns-id-ns.txt @@ -3,15 +3,14 @@ nvme-zns-id-ns(1) NAME ---- -nvme-zns-id-ns - Send NVMe Zoned Command Set Identify namespace, return - result and structure +nvme-zns-id-ns - Send NVMe Zoned Command Set Identify namespace, return result +and structure SYNOPSIS -------- [verse] -'nvme zns id-ns' [--namespace-id= | -n ] - [-o | --output-format=] - [-v | --verbose] +'nvme zns id-ns' [--namespace-id= | -n ] + [--output-format= | -o ] [--verbose | -v] DESCRIPTION ----------- @@ -36,10 +35,10 @@ OPTIONS --verbose:: Increase the information detail in the output. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-zns-offline-zone.1 b/Documentation/nvme-zns-offline-zone.1 index 91a99e930b..974a77b7b0 100644 --- a/Documentation/nvme-zns-offline-zone.1 +++ b/Documentation/nvme-zns-offline-zone.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-offline-zone .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-OFFLINE\-" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-OFFLINE\-" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-zns-offline-zone.html b/Documentation/nvme-zns-offline-zone.html index ba39c268bd..cb4bd39942 100644 --- a/Documentation/nvme-zns-offline-zone.html +++ b/Documentation/nvme-zns-offline-zone.html @@ -846,7 +846,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-open-zone.1 b/Documentation/nvme-zns-open-zone.1 index f549268099..6831611bef 100644 --- a/Documentation/nvme-zns-open-zone.1 +++ b/Documentation/nvme-zns-open-zone.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-open-zone .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-OPEN\-ZON" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-OPEN\-ZON" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,10 +33,8 @@ nvme-zns-open-zone \- Opens one or all zones .sp .nf \fInvme zns open\-zone\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-zrwaa | \-r] - [\-\-select\-all | \-a] - [\-\-timeout= | \-t ] + [\-\-start\-lba= | \-s ] [\-\-zrwaa | \-r] + [\-\-select\-all | \-a] [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp diff --git a/Documentation/nvme-zns-open-zone.html b/Documentation/nvme-zns-open-zone.html index 6163f05adb..3db2fcc1fd 100644 --- a/Documentation/nvme-zns-open-zone.html +++ b/Documentation/nvme-zns-open-zone.html @@ -750,10 +750,8 @@

      SYNOPSIS

      nvme zns open-zone <device> [--namespace-id=<NUM> | -n <NUM>]
      -                              [--start-lba=<LBA> | -s <LBA>]
      -                              [--zrwaa | -r]
      -                              [--select-all | -a]
      -                              [--timeout=<timeout> | -t <timeout>]
      + [--start-lba=<LBA> | -s <LBA>] [--zrwaa | -r] + [--select-all | -a] [--timeout=<timeout> | -t <timeout>]
      @@ -858,7 +856,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-open-zone.txt b/Documentation/nvme-zns-open-zone.txt index 0f2cb3551a..4639bcc120 100644 --- a/Documentation/nvme-zns-open-zone.txt +++ b/Documentation/nvme-zns-open-zone.txt @@ -9,10 +9,8 @@ SYNOPSIS -------- [verse] 'nvme zns open-zone' [--namespace-id= | -n ] - [--start-lba= | -s ] - [--zrwaa | -r] - [--select-all | -a] - [--timeout= | -t ] + [--start-lba= | -s ] [--zrwaa | -r] + [--select-all | -a] [--timeout= | -t ] DESCRIPTION ----------- diff --git a/Documentation/nvme-zns-report-zones.1 b/Documentation/nvme-zns-report-zones.1 index 38e137ef6a..37b60a661d 100644 --- a/Documentation/nvme-zns-report-zones.1 +++ b/Documentation/nvme-zns-report-zones.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-report-zones .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-REPORT\-Z" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-REPORT\-Z" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -39,7 +39,7 @@ nvme-zns-report-zones \- Retrieve and display the Report Zones data structure [\-\-extended | \-e] [\-\-partial | \-p] [\-\-verbose | \-v] - [\-\-output\-format= | \-o ] + [\-\-output\-format= | \-o ] .fi .SH "DESCRIPTION" .sp @@ -143,7 +143,7 @@ If set, the device will return the number of zones that match the state rather t Increase the information detail in the output\&. .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Set the reporting format to \fInormal\fR, diff --git a/Documentation/nvme-zns-report-zones.html b/Documentation/nvme-zns-report-zones.html index 4a9d47618d..2b12d874f2 100644 --- a/Documentation/nvme-zns-report-zones.html +++ b/Documentation/nvme-zns-report-zones.html @@ -756,7 +756,7 @@

      SYNOPSIS

      [--extended | -e] [--partial | -p] [--verbose | -v] - [--output-format=<FMT> | -o <FMT>] + [--output-format=<fmt> | -o <fmt>]
      @@ -906,15 +906,15 @@

      OPTIONS

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

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

      @@ -957,7 +957,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-report-zones.txt b/Documentation/nvme-zns-report-zones.txt index 35d5eda404..23dd6b4965 100644 --- a/Documentation/nvme-zns-report-zones.txt +++ b/Documentation/nvme-zns-report-zones.txt @@ -15,7 +15,7 @@ SYNOPSIS [--extended | -e] [--partial | -p] [--verbose | -v] - [--output-format= | -o ] + [--output-format= | -o ] DESCRIPTION ----------- @@ -76,10 +76,10 @@ OPTIONS --verbose:: Increase the information detail in the output. --o :: ---output-format=:: - Set the reporting format to 'normal', 'json', or - 'binary'. Only one output format can be used at a time. +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- diff --git a/Documentation/nvme-zns-reset-zone.1 b/Documentation/nvme-zns-reset-zone.1 index 973c89b8df..51cb75860f 100644 --- a/Documentation/nvme-zns-reset-zone.1 +++ b/Documentation/nvme-zns-reset-zone.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-reset-zone .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-RESET\-ZO" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-RESET\-ZO" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,9 +33,9 @@ nvme-zns-reset-zone \- Resets one or all zones .sp .nf \fInvme zns reset\-zone\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-select\-all | \-a] - [\-\-timeout= | \-t ] + [\-\-start\-lba= | \-s ] + [\-\-select\-all | \-a] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp diff --git a/Documentation/nvme-zns-reset-zone.html b/Documentation/nvme-zns-reset-zone.html index bfa0e15600..695b06c1da 100644 --- a/Documentation/nvme-zns-reset-zone.html +++ b/Documentation/nvme-zns-reset-zone.html @@ -750,9 +750,9 @@

      SYNOPSIS

      nvme zns reset-zone <device> [--namespace-id=<NUM> | -n <NUM>]
      -                                    [--start-lba=<LBA> | -s <LBA>]
      -                                    [--select-all | -a]
      -                                    [--timeout=<timeout> | -t <timeout>]
      + [--start-lba=<LBA> | -s <LBA>] + [--select-all | -a] + [--timeout=<timeout> | -t <timeout>]
      @@ -847,7 +847,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-reset-zone.txt b/Documentation/nvme-zns-reset-zone.txt index 25d01a1200..b58f2767ea 100644 --- a/Documentation/nvme-zns-reset-zone.txt +++ b/Documentation/nvme-zns-reset-zone.txt @@ -9,9 +9,9 @@ SYNOPSIS -------- [verse] 'nvme zns reset-zone' [--namespace-id= | -n ] - [--start-lba= | -s ] - [--select-all | -a] - [--timeout= | -t ] + [--start-lba= | -s ] + [--select-all | -a] + [--timeout= | -t ] DESCRIPTION ----------- diff --git a/Documentation/nvme-zns-set-zone-desc.1 b/Documentation/nvme-zns-set-zone-desc.1 index 163db517a7..36de5fb878 100644 --- a/Documentation/nvme-zns-set-zone-desc.1 +++ b/Documentation/nvme-zns-set-zone-desc.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-set-zone-desc .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-SET\-ZONE" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-SET\-ZONE" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,10 +33,10 @@ nvme-zns-set-zone-desc \- Set extended descriptor data for a zone .sp .nf \fInvme zns set\-zone\-desc\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba=, \-s ] - [\-\-zrwaa | \-r] - [\-data=, \-d ] - [\-\-timeout= | \-t ] + [\-\-start\-lba=, \-s ] + [\-\-zrwaa | \-r] + [\-\-data=, \-d ] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -58,7 +58,7 @@ The starting LBA of the zone to manage send\&. Allocate Zone Random Write Area to zone\&. .RE .PP -\-d +\-d , \-\-data= .RS 4 Optional file for data (default stdin) .RE diff --git a/Documentation/nvme-zns-set-zone-desc.html b/Documentation/nvme-zns-set-zone-desc.html index 34ca7e2500..53e41d65ca 100644 --- a/Documentation/nvme-zns-set-zone-desc.html +++ b/Documentation/nvme-zns-set-zone-desc.html @@ -750,10 +750,10 @@

      SYNOPSIS

      nvme zns set-zone-desc <device> [--namespace-id=<NUM> | -n <NUM>]
      -                                 [--start-lba=<IONUM>, -s <IONUM>]
      -                                 [--zrwaa | -r]
      -                                 [-data=<FILE>, -d <FILE>]
      -                                 [--timeout=<timeout> | -t <timeout>]
      + [--start-lba=<IONUM>, -s <IONUM>] + [--zrwaa | -r] + [--data=<FILE>, -d <FILE>] + [--timeout=<timeout> | -t <timeout>]
      @@ -807,10 +807,10 @@

      OPTIONS

      --d <FILE +-d <FILE>
      --data=<FILE> +--data=<FILE>

      @@ -859,7 +859,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-set-zone-desc.txt b/Documentation/nvme-zns-set-zone-desc.txt index dd759a2123..3df8c4b267 100644 --- a/Documentation/nvme-zns-set-zone-desc.txt +++ b/Documentation/nvme-zns-set-zone-desc.txt @@ -9,10 +9,10 @@ SYNOPSIS -------- [verse] 'nvme zns set-zone-desc' [--namespace-id= | -n ] - [--start-lba=, -s ] - [--zrwaa | -r] - [-data=, -d ] - [--timeout= | -t ] + [--start-lba=, -s ] + [--zrwaa | -r] + [--data=, -d ] + [--timeout= | -t ] DESCRIPTION ----------- @@ -37,8 +37,8 @@ OPTIONS --zrwaa:: Allocate Zone Random Write Area to zone. --d :: +-d :: +--data=:: Optional file for data (default stdin) -t :: diff --git a/Documentation/nvme-zns-zone-append.1 b/Documentation/nvme-zns-zone-append.1 index 802ec32a72..fc226b78a8 100644 --- a/Documentation/nvme-zns-zone-append.1 +++ b/Documentation/nvme-zns-zone-append.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-zone-append .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-ZONE\-APP" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-ZONE\-APP" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- diff --git a/Documentation/nvme-zns-zone-append.html b/Documentation/nvme-zns-zone-append.html index 99a64f96ba..ff514b9660 100644 --- a/Documentation/nvme-zns-zone-append.html +++ b/Documentation/nvme-zns-zone-append.html @@ -940,7 +940,7 @@

      NVME

      diff --git a/Documentation/nvme-zns-zone-mgmt-recv.1 b/Documentation/nvme-zns-zone-mgmt-recv.1 index af54f054c0..4fa0f98540 100644 --- a/Documentation/nvme-zns-zone-mgmt-recv.1 +++ b/Documentation/nvme-zns-zone-mgmt-recv.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-zone-mgmt-recv .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-ZONE\-MGM" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-ZONE\-MGM" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,12 +33,10 @@ nvme-zns-zone-mgmt-recv \- Zone Management Receive command .sp .nf \fInvme zns zone\-mgmt\-recv\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-data\-len=, \-l ] - [\-\-zra=, \-z ] - [\-\-zrasf=, \-a ] - [\-\-zra\-spec\-feat, \-f] - [\-\-output\-format=, \-o ] + [\-\-start\-lba= | \-s ] + [\-\-data\-len=, \-l ] + [\-\-zra=, \-z ] [\-\-zrasf=, \-a ] + [\-\-zra\-spec\-feat, \-f] [\-\-output\-format=, \-o ] .fi .SH "DESCRIPTION" .sp @@ -55,7 +53,7 @@ Use the provided namespace id for the command\&. If not provided, the namespace The starting LBA of the zone to manage receive\&. .RE .sp -\-\-data\-len= \-l Received data buffer length +\-l \-\-data\-len= Received data buffer length .PP \-z , \-\-zra= .RS 4 @@ -69,7 +67,7 @@ Zone Receive Action Enable Zone Receive Action Specific features .RE .PP -\-o , \-\-output\-format= +\-o , \-\-output\-format= .RS 4 Output format: normal|json|binary .RE diff --git a/Documentation/nvme-zns-zone-mgmt-recv.html b/Documentation/nvme-zns-zone-mgmt-recv.html index aa4cddada5..0cc2274dda 100644 --- a/Documentation/nvme-zns-zone-mgmt-recv.html +++ b/Documentation/nvme-zns-zone-mgmt-recv.html @@ -750,12 +750,10 @@

      SYNOPSIS

      nvme zns zone-mgmt-recv <device> [--namespace-id=<NUM> | -n <NUM>]
      -                                   [--start-lba=<LBA> | -s <LBA>]
      -                                   [--data-len=<IONUM>, -l <IONUM>]
      -                                   [--zra=<NUM>, -z <NUM>]
      -                                   [--zrasf=<NUM>, -a <NUM>]
      -                                   [--zra-spec-feat, -f]
      -                                   [--output-format=<FMT>, -o <FMT>]
      + [--start-lba=<LBA> | -s <LBA>] + [--data-len=<IONUM>, -l <IONUM>] + [--zra=<NUM>, -z <NUM>] [--zrasf=<NUM>, -a <NUM>] + [--zra-spec-feat, -f] [--output-format=<fmt>, -o <fmt>]
      @@ -801,8 +799,8 @@

      OPTIONS

    -

    --data-len=<NUM> --l <NUM> +

    -l <NUM> +--data-len=<NUM> Received data buffer length

    @@ -833,10 +831,10 @@

    OPTIONS

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

    @@ -882,7 +880,7 @@

    NVME

    diff --git a/Documentation/nvme-zns-zone-mgmt-recv.txt b/Documentation/nvme-zns-zone-mgmt-recv.txt index 07cd98e9c3..5a3e2a33ee 100644 --- a/Documentation/nvme-zns-zone-mgmt-recv.txt +++ b/Documentation/nvme-zns-zone-mgmt-recv.txt @@ -9,12 +9,10 @@ SYNOPSIS -------- [verse] 'nvme zns zone-mgmt-recv' [--namespace-id= | -n ] - [--start-lba= | -s ] - [--data-len=, -l ] - [--zra=, -z ] - [--zrasf=, -a ] - [--zra-spec-feat, -f] - [--output-format=, -o ] + [--start-lba= | -s ] + [--data-len=, -l ] + [--zra=, -z ] [--zrasf=, -a ] + [--zra-spec-feat, -f] [--output-format=, -o ] DESCRIPTION ----------- @@ -38,8 +36,8 @@ OPTIONS --start-lba=:: The starting LBA of the zone to manage receive. ---data-len= -l +--data-len= Received data buffer length -z :: @@ -54,8 +52,8 @@ OPTIONS --zra-spec-feat:: Enable Zone Receive Action Specific features --o :: ---output-format=:: +-o :: +--output-format=:: Output format: normal|json|binary EXAMPLES diff --git a/Documentation/nvme-zns-zone-mgmt-send.1 b/Documentation/nvme-zns-zone-mgmt-send.1 index 85c805c649..9de56a27a2 100644 --- a/Documentation/nvme-zns-zone-mgmt-send.1 +++ b/Documentation/nvme-zns-zone-mgmt-send.1 @@ -2,12 +2,12 @@ .\" Title: nvme-zns-zone-mgmt-send .\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZNS\-ZONE\-MGM" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME\-ZNS\-ZONE\-MGM" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,13 +33,11 @@ nvme-zns-zone-mgmt-send \- Zone Management Send command .sp .nf \fInvme zns zone\-mgmt\-send\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba=, \-s ] - [\-\-zsaso, \-o] - [\-\-select\-all, \-a] - [\-\-zsa=, \-z ] - [\-\-data\-len=, \-l ] - [\-\-data=, \-d ] - [\-\-timeout= | \-t ] + [\-\-start\-lba=, \-s ] [\-\-zsaso, \-o] + [\-\-select\-all, \-a] [\-\-zsa=, \-z ] + [\-\-data\-len=, \-l ] + [\-\-data=, \-d ] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -66,7 +64,7 @@ Send data buffer length Zone Send Action Specific Option .RE .PP -\-\-select\-all, \-a +\-a, \-\-select\-all .RS 4 Send command to all zones .RE @@ -81,7 +79,7 @@ Zone send action\&. Buffer length if data required .RE .PP -\-d +\-d , \-\-data= .RS 4 Optional file for data (default stdin) .RE diff --git a/Documentation/nvme-zns-zone-mgmt-send.html b/Documentation/nvme-zns-zone-mgmt-send.html index ac42948756..1300db29da 100644 --- a/Documentation/nvme-zns-zone-mgmt-send.html +++ b/Documentation/nvme-zns-zone-mgmt-send.html @@ -750,13 +750,11 @@

    SYNOPSIS

    nvme zns zone-mgmt-send <device> [--namespace-id=<NUM> | -n <NUM>]
    -                                   [--start-lba=<IONUM>, -s <IONUM>]
    -                                   [--zsaso, -o]
    -                                   [--select-all, -a]
    -                                   [--zsa=<NUM>, -z <NUM>]
    -                                   [--data-len=<IONUM>, -l <IONUM>]
    -                                   [--data=<FILE>, -d <FILE>]
    -                                   [--timeout=<timeout> | -t <timeout>]
    + [--start-lba=<IONUM>, -s <IONUM>] [--zsaso, -o] + [--select-all, -a] [--zsa=<NUM>, -z <NUM>] + [--data-len=<IONUM>, -l <IONUM>] + [--data=<FILE>, -d <FILE>] + [--timeout=<timeout> | -t <timeout>]
    @@ -821,10 +819,10 @@

    OPTIONS

    ---select-all +-a
    --a +--select-all

    @@ -854,7 +852,7 @@

    OPTIONS

    --d <FILE +-d <FILE>
    --data=<FILE> @@ -916,7 +914,7 @@

    NVME

    diff --git a/Documentation/nvme-zns-zone-mgmt-send.txt b/Documentation/nvme-zns-zone-mgmt-send.txt index 8cbb5c0b5a..3803d27e90 100644 --- a/Documentation/nvme-zns-zone-mgmt-send.txt +++ b/Documentation/nvme-zns-zone-mgmt-send.txt @@ -9,13 +9,11 @@ SYNOPSIS -------- [verse] 'nvme zns zone-mgmt-send' [--namespace-id= | -n ] - [--start-lba=, -s ] - [--zsaso, -o] - [--select-all, -a] - [--zsa=, -z ] - [--data-len=, -l ] - [--data=, -d ] - [--timeout= | -t ] + [--start-lba=, -s ] [--zsaso, -o] + [--select-all, -a] [--zsa=, -z ] + [--data-len=, -l ] + [--data=, -d ] + [--timeout= | -t ] DESCRIPTION ----------- @@ -44,8 +42,8 @@ OPTIONS --zsaso:: Zone Send Action Specific Option ---select-all:: -a:: +--select-all:: Send command to all zones -z :: @@ -56,7 +54,7 @@ OPTIONS --data-len=:: Buffer length if data required --d :: --data=:: Optional file for data (default stdin) diff --git a/Documentation/nvme-zns-zrwa-flush-zone.txt b/Documentation/nvme-zns-zrwa-flush-zone.txt index 4f3e72ca2f..e8f61edf8c 100644 --- a/Documentation/nvme-zns-zrwa-flush-zone.txt +++ b/Documentation/nvme-zns-zrwa-flush-zone.txt @@ -9,8 +9,8 @@ SYNOPSIS -------- [verse] 'nvme zns zrwa-flush-zone' [--namespace-id= | -n ] - [--lba= | -l ] - [--timeout= | -t ] + [--lba= | -l ] + [--timeout= | -t ] DESCRIPTION ----------- diff --git a/Documentation/nvme.1 b/Documentation/nvme.1 index 64c5b41c8c..ba7ef23b57 100644 --- a/Documentation/nvme.1 +++ b/Documentation/nvme.1 @@ -2,12 +2,12 @@ .\" Title: nvme .\" Author: [see the "Authors" section] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 08/01/2022 +.\" Date: 02/14/2024 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME" "1" "08/01/2022" "NVMe" "NVMe Manual" +.TH "NVME" "1" "02/14/2024" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -507,6 +507,11 @@ Retrieve the Supported Log pages details .RS 4 verify command .RE +.PP +\fBnvme-show-topology\fR(1) +.RS 4 +Show NVMe topology +.RE .SS "Plugins/Vendor extension commands" .PP \fBnvme-intel-id-ctrl\fR(1) @@ -843,6 +848,11 @@ Zone Management Send command .RS 4 Flush LBAs associated with a ZRWA to a zone .RE +.PP +\fBnvme-inspur-nvme-vendor-log\fR(1) +.RS 4 +NVMe Inspur Device Vendor log page request +.RE .SH "RETURNS" .sp All commands will behave the same, they will return 0 on success and 1 on failure\&. diff --git a/Documentation/nvme.html b/Documentation/nvme.html index 8a1b510dca..b92d95aaf8 100644 --- a/Documentation/nvme.html +++ b/Documentation/nvme.html @@ -1514,6 +1514,14 @@

    Main commands

    verify command

    +
    +nvme-show-topology(1) +
    +
    +

    + Show NVMe topology +

    +
    @@ -2055,6 +2063,14 @@

    Plugins/Vendor extension commands +
    +nvme-inspur-nvme-vendor-log(1) +
    +
    +

    + NVMe Inspur Device Vendor log page request +

    +

    @@ -2098,7 +2114,7 @@

    NVME

    diff --git a/Documentation/update-docs.sh b/Documentation/update-docs.sh deleted file mode 100755 index 87a73cc12b..0000000000 --- a/Documentation/update-docs.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0-or-later - -BUILDDIR="$(mktemp -d)" -trap 'rm -rf -- $BUILDDIR' EXIT - -meson $BUILDDIR -Ddocs=all -Ddocs-build=true -ninja -C $BUILDDIR -find $BUILDDIR/Documentation -maxdepth 1 \ - \( -name '*.1' -o -name '*.html' \) \ - -exec cp {} Documentation/ \; diff --git a/Makefile b/Makefile index 085adf8fb0..7f44364cd0 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,10 @@ endif install dist: ${BUILD-DIR} cd ${BUILD-DIR} && meson $@ +.PHONY: uninstall +uninstall: + cd ${BUILD-DIR} && meson --internal uninstall + .PHONY: test test: ${BUILD-DIR} ninja -C ${BUILD-DIR} $@ @@ -45,3 +49,16 @@ rpm: -Dsystemddir=$(shell rpm --eval '%{_unitdir}') \ -Ddocs=man -Ddocs-build=true rpmbuild -ba ${BUILD-DIR}/nvme.spec --define "_builddir ${BUILD-DIR}" -v + +.PHONY: debug +debug: + meson ${BUILD-DIR} --buildtype=debug + ninja -C ${BUILD-DIR} + +.PHONY: static +static: + meson ${BUILD-DIR} --buildtype=release \ + --default-library=static -Dc_link_args="-static" \ + --wrap-mode=forcefallback \ + -Dlibnvme:tests=false -Dlibnvme:keyutils=disabled + ninja -C ${BUILD-DIR} diff --git a/README.md b/README.md index 20623c1ca6..1113b1e400 100644 --- a/README.md +++ b/README.md @@ -1,161 +1,129 @@ # nvme-cli ![Coverity Scan Build Status](https://scan.coverity.com/projects/24883/badge.svg) -![MesonBuild](https://github.com/linux-nvme/nvme-cli/actions/workflows/meson.yml/badge.svg) +![MesonBuild](https://github.com/linux-nvme/nvme-cli/actions/workflows/build.yml/badge.svg) ![GitHub](https://img.shields.io/github/license/linux-nvme/nvme-cli) NVM-Express user space tooling for Linux. -nvme-cli uses meson as build system. In order to build nvme-cli -run following commands +## Build from source - $ meson .build - $ ninja -C .build +nvme-cli uses meson as build system. There is more than one way to configure and +build the project in order to mitigate meson dependency on the build +environment. -nvme-cli depends on zlib, json-c and libuuid. +If you build on a relative modern system, either use meson directly or the +Makefile wrapper. -To install, run: +Older distros might ship a too old version of meson, in this case it's possible +to build the project using [samurai](https://github.com/michaelforney/samurai) +and [muon](https://github.com/annacrombie/muon). Both build tools have only a +minimal dependency on the build environment. Too easy this step there is a build +script which helps to setup a build environment. - # meson install -C .build +### nvme-cli dependencies: -There is a Makefile wrapper for meson for backwards compatiblily + | Library | Dependency | Notes | + |---------|------------|-------| + | libnvme, libnvme-mi| yes | be either installed or included into the build via meson fallback feature | + | json-c | optional | recommended, without all plugins are disabled and json-c output format is disabled | - $ make - # make install -RPM build support via Makefile that uses meson +### Build with meson - $ make rpm +#### Configuring -If not sure how to use, find the top-level documentation with: +In case libnvme is not installed on the system, it possible to use meson's +fallback feature to resolve the dependency. - $ man nvme + $ meson setup --force-fallback-for=libnvme .build -Or find a short summary with: +If the libnvme is already installed on the system meson is using pkg-config to +find the dependency. In this case a plain setup call is enough: - $ nvme help + $ meson setup .build -## Distro Support +With meson's --wrap-mode argument it's possible to control if the additional +dependencies should also resolved or not. The options are -### Alpine Linux + --wrap-mode {default,nofallback,nodownload,forcefallback,nopromote} -nvme-cli is tested on Alpine Linux 3.3. Install it using: +Note for nvme-cli the 'default' is set to nofallback. - # apk update && apk add nvme-cli nvme-cli-doc +#### Building -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% -``` + $ meson compile -C .build -### Arch Linux +#### Installing -nvme-cli is available in the `[community]` repository. It can be installed with: + # meson install -C .build + +### Build with build.sh wrapper - # pacman -S nvme-cli +The `scripts/build.sh` is used for the CI build but can also be used for +configuring and building the project. -The development version can be installed from AUR, e.g.: +Running `scripts/build.sh` without any argument builds the project in the +default configuration (meson, gcc and defaults) - $ yay -S nvme-cli-git +It's possible to change the compiler to clang -### Debian +`scripts/builds.sh -c clang` -nvme-cli is available in Debian 9 and up. Install it with your favorite -package manager. For example: +or enabling all the fallbacks - $ sudo apt install nvme-cli +`scripts/build.sh fallback` -### Fedora +### Minimal static build with muon -nvme-cli is available in Fedora 23 and up. Install it with your favorite -package manager. For example: +`scripts/build.sh -m muon` will download and build `samurai` and `muon` instead +using `meson` to build the project. This reduces the dependency on the build +environment to: +- gcc +- make +- git - $ sudo dnf install nvme-cli +Furthermore, this configuration will produce a static binary. -### FreeBSD +### Build with Makefile wrapper -`nvme-cli` is available in the FreeBSD Ports Collection. A prebuilt binary -package can be installed with: +There is a Makefile wrapper for meson for backwards compatibility -```console -# pkg install nvme-cli -``` + $ make + # make install -### Gentoo +Note in this case libnvme needs to be installed by hand first. -nvme-cli is available and tested in portage: -``` -$ emerge -av nvme-cli -``` +RPM build support via Makefile that uses meson -### Nix(OS) + $ make rpm -The attribute is named `nvme-cli` and can e.g. be installed with: -``` -$ nix-env -f '' -iA nvme-cli -``` +Static binary(no dependency) build support via Makefile that uses meson + + $ make static + +If not sure how to use, find the top-level documentation with: -### openSUSE + $ man nvme -nvme-cli is available in openSUSE Leap 42.2 or later and Tumbleweed. You can -install it using zypper. For example: +Or find a short summary with: - $ sudo zypper install nvme-cli + $ nvme help + +## Distro Support -### Ubuntu +Many popular distributions (Alpine, Arch, Debian, Fedora, FreeBSD, Gentoo, +Ubuntu, Nix(OS), openSUSE, ...) and the usual package name is nvme-cli. -nvme-cli is supported in the Universe package sources for -many architectures. For a complete list try running: - ``` - rmadison nvme-cli - nvme-cli | 0.5-1 | xenial/universe | source, amd64, arm64, armhf, i386, powerpc, ppc64el, s390x - nvme-cli | 0.5-1ubuntu0.2 | xenial-updates/universe | source, amd64, arm64, armhf, i386, powerpc, ppc64el, s390x - nvme-cli | 1.5-1 | bionic/universe | source, amd64, arm64, armhf, i386, ppc64el, s390x - nvme-cli | 1.5-1ubuntu1.2 | bionic-updates | source, amd64, arm64, armhf, i386, ppc64el, s390x - nvme-cli | 1.9-1 | focal/universe | source, amd64, arm64, armhf, ppc64el, riscv64, s390x - nvme-cli | 1.9-1ubuntu0.1 | focal-updates | source, amd64, arm64, armhf, ppc64el, riscv64, s390x - nvme-cli | 1.14-1 | impish | source, amd64, arm64, armhf, ppc64el, riscv64, s390x - nvme-cli | 1.16-3 | jammy | source, amd64, arm64, armhf, ppc64el, riscv64, s390x - ``` -A Debian based package for nvme-cli is currently maintained as a -Ubuntu PPA. To install nvme-cli using this approach please perform the following -steps: - 1. Perform an update of your repository list: - ``` - sudo apt-get update - ``` - 2. Get nvme-cli! - ``` - sudo apt-get install nvme-cli - ``` - 3. 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 +#### OpenEmbedded/Yocto An [nvme-cli recipe](https://layers.openembedded.org/layerindex/recipe/88631/) is available as part of the `meta-openembeded` layer collection. -### Buildroot +#### 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 @@ -254,7 +222,7 @@ means if the current branch is updated via git, the subprojects/libnvme branch will not updated accordingly. To update it, either use the normal git operations or the command: - $ meson subprojects update + $ meson subprojects update ## Dependency @@ -263,3 +231,105 @@ introduced in the Linux kernel release v4.15. Hence nvme-cli 2.x is only working on kernels >= v4.15. For older kernels nvme-cli 1.x is recommended to be used. +## How to contribute + +There are two ways to send code changes to the project. The first one +is by sending the changes to linux-nvme@lists.infradead.org. The +second one is by posting a pull request on github. In both cases +please follow the Linux contributions guidelines as documented in + +https://docs.kernel.org/process/submitting-patches.html# + +That means the changes should be a clean series (no merges should be +present in a github PR for example) and every commit should build. + +See also https://opensource.com/article/19/7/create-pull-request-github + +### How to cleanup your series before creating PR + +This example here assumes, the changes are in a branch called +fix-something, which branched away from master in the past. In the +meantime the upstream project has changed, hence the fix-something +branch is not based on the current HEAD. Before posting the PR, the +branch should be rebased on the current HEAD and retest everything. + +For example rebasing can be done by following steps + +```shell +# Update master branch +# upstream == https://github.com/linux-nvme/nvme-cli.git +$ git switch master +$ git fetch --all +$ git reset --hard upstream/master + +# Make sure all dependencies are up to date and make a sanity build +$ meson subprojects update +$ ninja -C .build + +# Go back to the fix-something branch +$ git switch fix-something + +# Rebase it to the current HEAD +$ git rebase master +[fixup all merge conflicts] +[retest] + +# Push your changes to github and trigger a PR +$ git push -u origin fix-something +``` + +## Persistent, volatile configuration + +Persistent configurations can be stored in two different locations: either in +the file `/etc/nvme/discovery.conf` using the old style, or in the file +`/etc/nvme/config.json` using the new style. + +On the other hand, volatile configurations, such as those obtained from +third-party tools like `nvme-stats` or `blktests'` can be stored in the +`/run/nvme` directory. When using the `nvme-cli` tool, all these configurations +are combined into a single configuration that is used as input. + +The volatile configuration is particularly useful for coordinating access to the +global resources among various components. For example, when executing +`blktests` for the FC transport, the `nvme-cli` udev rules can be triggered. To +prevent interference with a test, `blktests` can create a JSON configuration +file in `/run/nvme` to inform `nvme-cli` that it should not perform any actions +triggered from the udev context. This behavior can be controlled using the +`--context` argument. + +For example a `blktests` volatile configuration could look like: + +```json +[ + { + "hostnqn": "nqn.2014-08.org.nvmexpress:uuid:242d4a24-2484-4a80-8234-d0169409c5e8", + "hostid": "242d4a24-2484-4a80-8234-d0169409c5e8", + "subsystems": [ + { + "application": "blktests", + "nqn": "blktests-subsystem-1", + "ports": [ + { + "transport": "fc", + "traddr": "nn-0x10001100aa000001:pn-0x20001100aa000001", + "host_traddr": "nn-0x10001100aa000002:pn-0x20001100aa000002" + } + ] + } + ] + } +] +``` + +Note when updating the volatile configuration during runtime, it should done in +a an atomic way. For example create a temporary file without the `.json` file +extension in `/run/nvme` and write the contents to this file. When finished use +`rename` to add the `'.json'` file name extension. This ensures nvme-cli only +sees the complete file. + +## Testing + +For testing purposes a x86_64 AppImage is build from the current HEAD and is +available here: + +https://monom.org/linux-nvme/upload/AppImage/nvme-cli-latest-x86_64.AppImage diff --git a/ccan/ccan/build_assert/_info b/ccan/ccan/build_assert/_info deleted file mode 100644 index 97ebe6c966..0000000000 --- a/ccan/ccan/build_assert/_info +++ /dev/null @@ -1,49 +0,0 @@ -#include "config.h" -#include -#include - -/** - * build_assert - routines for build-time assertions - * - * This code provides routines which will cause compilation to fail should some - * assertion be untrue: such failures are preferable to run-time assertions, - * but much more limited since they can only depends on compile-time constants. - * - * These assertions are most useful when two parts of the code must be kept in - * sync: it is better to avoid such cases if possible, but seconds best is to - * detect invalid changes at build time. - * - * For example, a tricky piece of code might rely on a certain element being at - * the start of the structure. To ensure that future changes don't break it, - * you would catch such changes in your code like so: - * - * Example: - * #include - * #include - * - * struct foo { - * char string[5]; - * int x; - * }; - * - * static char *foo_string(struct foo *foo) - * { - * // This trick requires that the string be first in the structure - * BUILD_ASSERT(offsetof(struct foo, string) == 0); - * return (char *)foo; - * } - * - * License: CC0 (Public domain) - * Author: Rusty Russell - */ -int main(int argc, char *argv[]) -{ - if (argc != 2) - return 1; - - if (strcmp(argv[1], "depends") == 0) - /* Nothing. */ - return 0; - - return 1; -} diff --git a/ccan/ccan/check_type/_info b/ccan/ccan/check_type/_info deleted file mode 100644 index cc42673492..0000000000 --- a/ccan/ccan/check_type/_info +++ /dev/null @@ -1,33 +0,0 @@ -#include "config.h" -#include -#include - -/** - * check_type - routines for compile time type checking - * - * C has fairly weak typing: ints get automatically converted to longs, signed - * to unsigned, etc. There are some cases where this is best avoided, and - * these macros provide methods for evoking warnings (or build errors) when - * a precise type isn't used. - * - * On compilers which don't support typeof() these routines are less effective, - * since they have to use sizeof() which can only distiguish between types of - * different size. - * - * License: CC0 (Public domain) - * Author: Rusty Russell - */ -int main(int argc, char *argv[]) -{ - if (argc != 2) - return 1; - - if (strcmp(argv[1], "depends") == 0) { -#if !HAVE_TYPEOF - printf("ccan/build_assert\n"); -#endif - return 0; - } - - return 1; -} diff --git a/ccan/ccan/compiler/LICENSE b/ccan/ccan/compiler/LICENSE new file mode 120000 index 0000000000..b7951dabdc --- /dev/null +++ b/ccan/ccan/compiler/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/compiler/compiler.h b/ccan/ccan/compiler/compiler.h new file mode 100644 index 0000000000..562b29ec71 --- /dev/null +++ b/ccan/ccan/compiler/compiler.h @@ -0,0 +1,317 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_COMPILER_H +#define CCAN_COMPILER_H +#include "config.h" + +#ifndef COLD +#if HAVE_ATTRIBUTE_COLD +/** + * COLD - a function is unlikely to be called. + * + * Used to mark an unlikely code path and optimize appropriately. + * It is usually used on logging or error routines. + * + * Example: + * static void COLD moan(const char *reason) + * { + * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); + * } + */ +#define COLD __attribute__((__cold__)) +#else +#define COLD +#endif +#endif + +#ifndef NORETURN +#if HAVE_ATTRIBUTE_NORETURN +/** + * NORETURN - a function does not return + * + * Used to mark a function which exits; useful for suppressing warnings. + * + * Example: + * static void NORETURN fail(const char *reason) + * { + * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); + * exit(1); + * } + */ +#define NORETURN __attribute__((__noreturn__)) +#else +#define NORETURN +#endif +#endif + +#ifndef PRINTF_FMT +#if HAVE_ATTRIBUTE_PRINTF +/** + * PRINTF_FMT - a function takes printf-style arguments + * @nfmt: the 1-based number of the function's format argument. + * @narg: the 1-based number of the function's first variable argument. + * + * This allows the compiler to check your parameters as it does for printf(). + * + * Example: + * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...); + */ +#define PRINTF_FMT(nfmt, narg) \ + __attribute__((format(__printf__, nfmt, narg))) +#else +#define PRINTF_FMT(nfmt, narg) +#endif +#endif + +#ifndef CONST_FUNCTION +#if HAVE_ATTRIBUTE_CONST +/** + * CONST_FUNCTION - a function's return depends only on its argument + * + * This allows the compiler to assume that the function will return the exact + * same value for the exact same arguments. This implies that the function + * must not use global variables, or dereference pointer arguments. + */ +#define CONST_FUNCTION __attribute__((__const__)) +#else +#define CONST_FUNCTION +#endif + +#ifndef PURE_FUNCTION +#if HAVE_ATTRIBUTE_PURE +/** + * PURE_FUNCTION - a function is pure + * + * A pure function is one that has no side effects other than it's return value + * and uses no inputs other than it's arguments and global variables. + */ +#define PURE_FUNCTION __attribute__((__pure__)) +#else +#define PURE_FUNCTION +#endif +#endif +#endif + +#if HAVE_ATTRIBUTE_UNUSED +#ifndef UNNEEDED +/** + * UNNEEDED - a variable/function may not be needed + * + * This suppresses warnings about unused variables or functions, but tells + * the compiler that if it is unused it need not emit it into the source code. + * + * Example: + * // With some preprocessor options, this is unnecessary. + * static UNNEEDED int counter; + * + * // With some preprocessor options, this is unnecessary. + * static UNNEEDED void add_to_counter(int add) + * { + * counter += add; + * } + */ +#define UNNEEDED __attribute__((__unused__)) +#endif + +#ifndef NEEDED +#if HAVE_ATTRIBUTE_USED +/** + * NEEDED - a variable/function is needed + * + * This suppresses warnings about unused variables or functions, but tells + * the compiler that it must exist even if it (seems) unused. + * + * Example: + * // Even if this is unused, these are vital for debugging. + * static NEEDED int counter; + * static NEEDED void dump_counter(void) + * { + * printf("Counter is %i\n", counter); + * } + */ +#define NEEDED __attribute__((__used__)) +#else +/* Before used, unused functions and vars were always emitted. */ +#define NEEDED __attribute__((__unused__)) +#endif +#endif + +#ifndef UNUSED +/** + * UNUSED - a parameter is unused + * + * Some compilers (eg. gcc with -W or -Wunused) warn about unused + * function parameters. This suppresses such warnings and indicates + * to the reader that it's deliberate. + * + * Example: + * // This is used as a callback, so needs to have this prototype. + * static int some_callback(void *unused UNUSED) + * { + * return 0; + * } + */ +#define UNUSED __attribute__((__unused__)) +#endif +#else +#ifndef UNNEEDED +#define UNNEEDED +#endif +#ifndef NEEDED +#define NEEDED +#endif +#ifndef UNUSED +#define UNUSED +#endif +#endif + +#ifndef IS_COMPILE_CONSTANT +#if HAVE_BUILTIN_CONSTANT_P +/** + * IS_COMPILE_CONSTANT - does the compiler know the value of this expression? + * @expr: the expression to evaluate + * + * When an expression manipulation is complicated, it is usually better to + * implement it in a function. However, if the expression being manipulated is + * known at compile time, it is better to have the compiler see the entire + * expression so it can simply substitute the result. + * + * This can be done using the IS_COMPILE_CONSTANT() macro. + * + * Example: + * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON }; + * + * // Out-of-line version. + * const char *greek_name(enum greek greek); + * + * // Inline version. + * static inline const char *_greek_name(enum greek greek) + * { + * switch (greek) { + * case ALPHA: return "alpha"; + * case BETA: return "beta"; + * case GAMMA: return "gamma"; + * case DELTA: return "delta"; + * case EPSILON: return "epsilon"; + * default: return "**INVALID**"; + * } + * } + * + * // Use inline if compiler knows answer. Otherwise call function + * // to avoid copies of the same code everywhere. + * #define greek_name(g) \ + * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) + */ +#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) +#else +/* If we don't know, assume it's not. */ +#define IS_COMPILE_CONSTANT(expr) 0 +#endif +#endif + +#ifndef WARN_UNUSED_RESULT +#if HAVE_WARN_UNUSED_RESULT +/** + * WARN_UNUSED_RESULT - warn if a function return value is unused. + * + * Used to mark a function where it is extremely unlikely that the caller + * can ignore the result, eg realloc(). + * + * Example: + * // buf param may be freed by this; need return value! + * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size) + * { + * return realloc(buf, (*size) *= 2); + * } + */ +#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#else +#define WARN_UNUSED_RESULT +#endif +#endif + + +#if HAVE_ATTRIBUTE_DEPRECATED +/** + * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used. + * + * Used to mark a function, type or variable should not be used. + * + * Example: + * WARN_DEPRECATED char *oldfunc(char *buf); + */ +#define WARN_DEPRECATED __attribute__((__deprecated__)) +#else +#define WARN_DEPRECATED +#endif + + +#if HAVE_ATTRIBUTE_NONNULL +/** + * NO_NULL_ARGS - specify that no arguments to this function can be NULL. + * + * The compiler will warn if any pointer args are NULL. + * + * Example: + * NO_NULL_ARGS char *my_copy(char *buf); + */ +#define NO_NULL_ARGS __attribute__((__nonnull__)) + +/** + * NON_NULL_ARGS - specify that some arguments to this function can't be NULL. + * @...: 1-based argument numbers for which args can't be NULL. + * + * The compiler will warn if any of the specified pointer args are NULL. + * + * Example: + * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1); + */ +#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else +#define NO_NULL_ARGS +#define NON_NULL_ARGS(...) +#endif + +#if HAVE_ATTRIBUTE_RETURNS_NONNULL +/** + * RETURNS_NONNULL - specify that this function cannot return NULL. + * + * Mainly an optimization opportunity, but can also suppress warnings. + * + * Example: + * RETURNS_NONNULL char *my_copy(char *buf); + */ +#define RETURNS_NONNULL __attribute__((__returns_nonnull__)) +#else +#define RETURNS_NONNULL +#endif + +#if HAVE_ATTRIBUTE_SENTINEL +/** + * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL. + * + * The compiler will warn if the last argument isn't NULL. + * + * Example: + * char *join_string(char *buf, ...) LAST_ARG_NULL; + */ +#define LAST_ARG_NULL __attribute__((__sentinel__)) +#else +#define LAST_ARG_NULL +#endif + +#if HAVE_BUILTIN_CPU_SUPPORTS +/** + * cpu_supports - test if current CPU supports the named feature. + * + * This takes a literal string, and currently only works on glibc platforms. + * + * Example: + * if (cpu_supports("mmx")) + * printf("MMX support engaged!\n"); + */ +#define cpu_supports(x) __builtin_cpu_supports(x) +#else +#define cpu_supports(x) 0 +#endif /* HAVE_BUILTIN_CPU_SUPPORTS */ + +#endif /* CCAN_COMPILER_H */ diff --git a/ccan/ccan/container_of/_info b/ccan/ccan/container_of/_info deleted file mode 100644 index b1160522ed..0000000000 --- a/ccan/ccan/container_of/_info +++ /dev/null @@ -1,65 +0,0 @@ -#include "config.h" -#include -#include - -/** - * container_of - routine for upcasting - * - * It is often convenient to create code where the caller registers a pointer - * to a generic structure and a callback. The callback might know that the - * pointer points to within a larger structure, and container_of gives a - * convenient and fairly type-safe way of returning to the enclosing structure. - * - * This idiom is an alternative to providing a void * pointer for every - * callback. - * - * Example: - * #include - * #include - * - * struct timer { - * void *members; - * }; - * - * struct info { - * int my_stuff; - * struct timer timer; - * }; - * - * static void my_timer_callback(struct timer *timer) - * { - * struct info *info = container_of(timer, struct info, timer); - * printf("my_stuff is %u\n", info->my_stuff); - * } - * - * static void register_timer(struct timer *timer) - * { - * (void)timer; - * (void)my_timer_callback; - * //... - * } - * - * int main(void) - * { - * struct info info = { .my_stuff = 1 }; - * - * register_timer(&info.timer); - * // ... - * return 0; - * } - * - * License: CC0 (Public domain) - * Author: Rusty Russell - */ -int main(int argc, char *argv[]) -{ - if (argc != 2) - return 1; - - if (strcmp(argv[1], "depends") == 0) { - printf("ccan/check_type\n"); - return 0; - } - - return 1; -} diff --git a/ccan/ccan/endian/_info b/ccan/ccan/endian/_info deleted file mode 100644 index efe5a8bbde..0000000000 --- a/ccan/ccan/endian/_info +++ /dev/null @@ -1,55 +0,0 @@ -#include "config.h" -#include -#include - -/** - * endian - endian conversion macros for simple types - * - * Portable protocols (such as on-disk formats, or network protocols) - * are often defined to be a particular endian: little-endian (least - * significant bytes first) or big-endian (most significant bytes - * first). - * - * Similarly, some CPUs lay out values in memory in little-endian - * order (most commonly, Intel's 8086 and derivatives), or big-endian - * order (almost everyone else). - * - * This module provides conversion routines, inspired by the linux kernel. - * It also provides leint32_t, beint32_t etc typedefs, which are annotated for - * the sparse checker. - * - * Example: - * #include - * #include - * #include - * - * // - * int main(int argc, char *argv[]) - * { - * uint32_t value; - * - * if (argc != 2) - * errx(1, "Usage: %s ", argv[0]); - * - * value = atoi(argv[1]); - * printf("native: %08x\n", value); - * printf("little-endian: %08x\n", cpu_to_le32(value)); - * printf("big-endian: %08x\n", cpu_to_be32(value)); - * printf("byte-reversed: %08x\n", bswap_32(value)); - * exit(0); - * } - * - * License: License: CC0 (Public domain) - * Author: Rusty Russell - */ -int main(int argc, char *argv[]) -{ - if (argc != 2) - return 1; - - if (strcmp(argv[1], "depends") == 0) - /* Nothing */ - return 0; - - return 1; -} diff --git a/ccan/ccan/hash/LICENSE b/ccan/ccan/hash/LICENSE new file mode 120000 index 0000000000..b7951dabdc --- /dev/null +++ b/ccan/ccan/hash/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/hash/hash.c b/ccan/ccan/hash/hash.c new file mode 100644 index 0000000000..88d88fcc74 --- /dev/null +++ b/ccan/ccan/hash/hash.c @@ -0,0 +1,926 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hash_word(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ +//#define SELF_TEST 1 + +#if 0 +#include /* defines printf for tests */ +#include /* defines time_t for timings in the test */ +#include /* defines uint32_t etc */ +#include /* attempt to define endianness */ + +#ifdef linux +# include /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(__x86_64) || \ + defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# error Unknown endian +#endif +#endif /* old hash.c headers. */ + +#include "hash.h" + +#if HAVE_LITTLE_ENDIAN +#define HASH_LITTLE_ENDIAN 1 +#define HASH_BIG_ENDIAN 0 +#elif HAVE_BIG_ENDIAN +#define HASH_LITTLE_ENDIAN 0 +#define HASH_BIG_ENDIAN 1 +#else +#error Unknown endian +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +-------------------------------------------------------------------- + This works on all machines. To be useful, it requires + -- that the key be an array of uint32_t's, and + -- that the length be the number of uint32_t's in the key + + The function hash_word() is identical to hashlittle() on little-endian + machines, and identical to hashbig() on big-endian machines, + except that the length has to be measured in uint32_ts rather than in + bytes. hashlittle() is more complicated than hash_word() only because + hashlittle() has to dance around fitting the key bytes into registers. +-------------------------------------------------------------------- +*/ +uint32_t hash_u32( +const uint32_t *k, /* the key, an array of uint32_t values */ +size_t length, /* the length of the key, in uint32_ts */ +uint32_t initval) /* the previous hash, or an arbitrary value */ +{ + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch(length) /* all the case statements fall through */ + { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + final(a,b,c); + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + return c; +} + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + val2 : IN: can be any 4-byte value OUT: second 32 bit hash. +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. Note that the return value is better +mixed than val2, so use that first. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + * + * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR. + */ +#if 0 + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + *val2 = b; + return c; +} + +/* + * hashbig(): + * This is the same as hash_word() on big-endian machines. It is different + * from hashlittle() on all machines. hashbig() takes advantage of + * big-endian byte ordering. + */ +static uint32_t hashbig( const void *key, size_t length, uint32_t *val2) +{ + uint32_t a,b,c; + union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + *val2; + + u.ptr = key; + if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + const uint8_t *k8; + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]<<8" actually reads beyond the end of the string, but + * then shifts out the part it's not allowed to read. Because the + * string is aligned, the illegal read is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticeably faster for short strings (like English words). + * + * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR. + */ +#if 0 + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; + case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; + case 5 : b+=k[1]&0xff000000; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff00; break; + case 2 : a+=k[0]&0xffff0000; break; + case 1 : a+=k[0]&0xff000000; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) /* all the case statements fall through */ + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ + case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ + case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ + case 1 : a+=((uint32_t)k8[0])<<24; break; + case 0 : return c; + } + +#endif /* !VALGRIND */ + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += ((uint32_t)k[0])<<24; + a += ((uint32_t)k[1])<<16; + a += ((uint32_t)k[2])<<8; + a += ((uint32_t)k[3]); + b += ((uint32_t)k[4])<<24; + b += ((uint32_t)k[5])<<16; + b += ((uint32_t)k[6])<<8; + b += ((uint32_t)k[7]); + c += ((uint32_t)k[8])<<24; + c += ((uint32_t)k[9])<<16; + c += ((uint32_t)k[10])<<8; + c += ((uint32_t)k[11]); + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=k[11]; + case 11: c+=((uint32_t)k[10])<<8; + case 10: c+=((uint32_t)k[9])<<16; + case 9 : c+=((uint32_t)k[8])<<24; + case 8 : b+=k[7]; + case 7 : b+=((uint32_t)k[6])<<8; + case 6 : b+=((uint32_t)k[5])<<16; + case 5 : b+=((uint32_t)k[4])<<24; + case 4 : a+=k[3]; + case 3 : a+=((uint32_t)k[2])<<8; + case 2 : a+=((uint32_t)k[1])<<16; + case 1 : a+=((uint32_t)k[0])<<24; + break; + case 0 : return c; + } + } + + final(a,b,c); + *val2 = b; + return c; +} + +/* I basically use hashlittle here, but use native endian within each + * element. This delivers least-surprise: hash such as "int arr[] = { + * 1, 2 }; hash_stable(arr, 2, 0);" will be the same on big and little + * endian machines, even though a bytewise hash wouldn't be. */ +uint64_t hash64_stable_64(const void *key, size_t n, uint64_t base) +{ + const uint64_t *k = key; + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)n*8) + (base >> 32) + base; + + while (n > 3) { + a += (uint32_t)k[0]; + b += (uint32_t)(k[0] >> 32); + c += (uint32_t)k[1]; + mix(a,b,c); + a += (uint32_t)(k[1] >> 32); + b += (uint32_t)k[2]; + c += (uint32_t)(k[2] >> 32); + mix(a,b,c); + n -= 3; + k += 3; + } + switch (n) { + case 2: + a += (uint32_t)k[0]; + b += (uint32_t)(k[0] >> 32); + c += (uint32_t)k[1]; + mix(a,b,c); + a += (uint32_t)(k[1] >> 32); + break; + case 1: + a += (uint32_t)k[0]; + b += (uint32_t)(k[0] >> 32); + break; + case 0: + return c; + } + final(a,b,c); + return ((uint64_t)b << 32) | c; +} + +uint64_t hash64_stable_32(const void *key, size_t n, uint64_t base) +{ + const uint32_t *k = key; + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)n*4) + (base >> 32) + base; + + while (n > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + + n -= 3; + k += 3; + } + switch (n) { + case 2: + b += (uint32_t)k[1]; + case 1: + a += (uint32_t)k[0]; + break; + case 0: + return c; + } + final(a,b,c); + return ((uint64_t)b << 32) | c; +} + +uint64_t hash64_stable_16(const void *key, size_t n, uint64_t base) +{ + const uint16_t *k = key; + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)n*2) + (base >> 32) + base; + + while (n > 6) { + a += (uint32_t)k[0] + ((uint32_t)k[1] << 16); + b += (uint32_t)k[2] + ((uint32_t)k[3] << 16); + c += (uint32_t)k[4] + ((uint32_t)k[5] << 16); + mix(a,b,c); + + n -= 6; + k += 6; + } + + switch (n) { + case 5: + c += (uint32_t)k[4]; + case 4: + b += ((uint32_t)k[3] << 16); + case 3: + b += (uint32_t)k[2]; + case 2: + a += ((uint32_t)k[1] << 16); + case 1: + a += (uint32_t)k[0]; + break; + case 0: + return c; + } + final(a,b,c); + return ((uint64_t)b << 32) | c; +} + +uint64_t hash64_stable_8(const void *key, size_t n, uint64_t base) +{ + uint32_t b32 = base + (base >> 32); + uint32_t lower = hashlittle(key, n, &b32); + + return ((uint64_t)b32 << 32) | lower; +} + +uint32_t hash_any(const void *key, size_t length, uint32_t base) +{ + if (HASH_BIG_ENDIAN) + return hashbig(key, length, &base); + else + return hashlittle(key, length, &base); +} + +uint32_t hash_stable_64(const void *key, size_t n, uint32_t base) +{ + return hash64_stable_64(key, n, base); +} + +uint32_t hash_stable_32(const void *key, size_t n, uint32_t base) +{ + return hash64_stable_32(key, n, base); +} + +uint32_t hash_stable_16(const void *key, size_t n, uint32_t base) +{ + return hash64_stable_16(key, n, base); +} + +uint32_t hash_stable_8(const void *key, size_t n, uint32_t base) +{ + return hashlittle(key, n, &base); +} + +/* Jenkins' lookup8 is a 64 bit hash, but he says it's obsolete. Use + * the plain one and recombine into 64 bits. */ +uint64_t hash64_any(const void *key, size_t length, uint64_t base) +{ + uint32_t b32 = base + (base >> 32); + uint32_t lower; + + if (HASH_BIG_ENDIAN) + lower = hashbig(key, length, &b32); + else + lower = hashlittle(key, length, &b32); + + return ((uint64_t)b32 << 32) | lower; +} + +#ifdef SELF_TEST + +/* used for timings */ +void driver1() +{ + uint8_t buf[256]; + uint32_t i; + uint32_t h=0; + time_t a,z; + + time(&a); + for (i=0; i<256; ++i) buf[i] = 'x'; + for (i=0; i<1; ++i) + { + h = hashlittle(&buf[0],1,h); + } + time(&z); + if (z-a > 0) printf("time %d %.8x\n", z-a, h); +} + +/* check that every input bit changes every output bit half the time */ +#define HASHSTATE 1 +#define HASHLEN 1 +#define MAXPAIR 60 +#define MAXLEN 70 +void driver2() +{ + uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; + uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; + uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; + uint32_t x[HASHSTATE],y[HASHSTATE]; + uint32_t hlen; + + printf("No more than %d trials should ever be needed \n",MAXPAIR/2); + for (hlen=0; hlen < MAXLEN; ++hlen) + { + z=0; + for (i=0; i>(8-j)); + c[0] = hashlittle(a, hlen, m); + b[i] ^= ((k+1)<>(8-j)); + d[0] = hashlittle(b, hlen, m); + /* check every bit is 1, 0, set, and not set at least once */ + for (l=0; lz) z=k; + if (k==MAXPAIR) + { + printf("Some bit didn't change: "); + printf("%.8x %.8x %.8x %.8x %.8x %.8x ", + e[0],f[0],g[0],h[0],x[0],y[0]); + printf("i %d j %d m %d len %d\n", i, j, m, hlen); + } + if (z==MAXPAIR) goto done; + } + } + } + done: + if (z < MAXPAIR) + { + printf("Mix success %2d bytes %2d initvals ",i,m); + printf("required %d trials\n", z/2); + } + } + printf("\n"); +} + +/* Check for reading beyond the end of the buffer and alignment problems */ +void driver3() +{ + uint8_t buf[MAXLEN+20], *b; + uint32_t len; + uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; + uint32_t h; + uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; + uint32_t i; + uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; + uint32_t j; + uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; + uint32_t ref,x,y; + uint8_t *p; + + printf("Endianness. These lines should all be the same (for values filled in):\n"); + printf("%.8x %.8x %.8x\n", + hash_word((const uint32_t *)q, (sizeof(q)-1)/4, 13), + hash_word((const uint32_t *)q, (sizeof(q)-5)/4, 13), + hash_word((const uint32_t *)q, (sizeof(q)-9)/4, 13)); + p = q; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qq[1]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qqq[2]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qqqq[3]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + printf("\n"); + + /* check that hashlittle2 and hashlittle produce the same results */ + i=47; j=0; + hashlittle2(q, sizeof(q), &i, &j); + if (hashlittle(q, sizeof(q), 47) != i) + printf("hashlittle2 and hashlittle mismatch\n"); + + /* check that hash_word2 and hash_word produce the same results */ + len = 0xdeadbeef; + i=47, j=0; + hash_word2(&len, 1, &i, &j); + if (hash_word(&len, 1, 47) != i) + printf("hash_word2 and hash_word mismatch %x %x\n", + i, hash_word(&len, 1, 47)); + + /* check hashlittle doesn't read before or after the ends of the string */ + for (h=0, b=buf+1; h<8; ++h, ++b) + { + for (i=0; i +#include +#include + +/* Stolen mostly from: lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * http://burtleburtle.net/bob/c/lookup3.c + */ + +/** + * hash - fast hash of an array for internal use + * @p: the array or pointer to first element + * @num: the number of elements to hash + * @base: the base number to roll into the hash (usually 0) + * + * The memory region pointed to by p is combined with the base to form + * a 32-bit hash. + * + * This hash will have different results on different machines, so is + * only useful for internal hashes (ie. not hashes sent across the + * network or saved to disk). + * + * It may also change with future versions: it could even detect at runtime + * what the fastest hash to use is. + * + * See also: hash64, hash_stable. + * + * Example: + * #include + * #include + * #include + * #include + * + * // Simple demonstration: idential strings will have the same hash, but + * // two different strings will probably not. + * int main(int argc, char *argv[]) + * { + * uint32_t hash1, hash2; + * + * if (argc != 3) + * err(1, "Usage: %s ", argv[0]); + * + * hash1 = hash(argv[1], strlen(argv[1]), 0); + * hash2 = hash(argv[2], strlen(argv[2]), 0); + * printf("Hash is %s\n", hash1 == hash2 ? "same" : "different"); + * return 0; + * } + */ +#define hash(p, num, base) hash_any((p), (num)*sizeof(*(p)), (base)) + +/** + * hash_stable - hash of an array for external use + * @p: the array or pointer to first element + * @num: the number of elements to hash + * @base: the base number to roll into the hash (usually 0) + * + * The array of simple integer types pointed to by p is combined with + * the base to form a 32-bit hash. + * + * This hash will have the same results on different machines, so can + * be used for external hashes (ie. hashes sent across the network or + * saved to disk). The results will not change in future versions of + * this module. + * + * Note that it is only legal to hand an array of simple integer types + * to this hash (ie. char, uint16_t, int64_t, etc). In these cases, + * the same values will have the same hash result, even though the + * memory representations of integers depend on the machine + * endianness. + * + * See also: + * hash64_stable + * + * Example: + * #include + * #include + * #include + * #include + * + * int main(int argc, char *argv[]) + * { + * if (argc != 2) + * err(1, "Usage: %s ", argv[0]); + * + * printf("Hash stable result is %u\n", + * hash_stable(argv[1], strlen(argv[1]), 0)); + * return 0; + * } + */ +#define hash_stable(p, num, base) \ + (BUILD_ASSERT_OR_ZERO(sizeof(*(p)) == 8 || sizeof(*(p)) == 4 \ + || sizeof(*(p)) == 2 || sizeof(*(p)) == 1) + \ + sizeof(*(p)) == 8 ? hash_stable_64((p), (num), (base)) \ + : sizeof(*(p)) == 4 ? hash_stable_32((p), (num), (base)) \ + : sizeof(*(p)) == 2 ? hash_stable_16((p), (num), (base)) \ + : hash_stable_8((p), (num), (base))) + +/** + * hash_u32 - fast hash an array of 32-bit values for internal use + * @key: the array of uint32_t + * @num: the number of elements to hash + * @base: the base number to roll into the hash (usually 0) + * + * The array of uint32_t pointed to by @key is combined with the base + * to form a 32-bit hash. This is 2-3 times faster than hash() on small + * arrays, but the advantage vanishes over large hashes. + * + * This hash will have different results on different machines, so is + * only useful for internal hashes (ie. not hashes sent across the + * network or saved to disk). + */ +uint32_t hash_u32(const uint32_t *key, size_t num, uint32_t base); + +/** + * hash_string - very fast hash of an ascii string + * @str: the nul-terminated string + * + * The string is hashed, using a hash function optimized for ASCII and + * similar strings. It's weaker than the other hash functions. + * + * This hash may have different results on different machines, so is + * only useful for internal hashes (ie. not hashes sent across the + * network or saved to disk). The results will be different from the + * other hash functions in this module, too. + */ +static inline uint32_t hash_string(const char *string) +{ + /* This is Karl Nelson 's X31 hash. + * It's a little faster than the (much better) lookup3 hash(): 56ns vs + * 84ns on my 2GHz Intel Core Duo 2 laptop for a 10 char string. */ + uint32_t ret; + + for (ret = 0; *string; string++) + ret = (ret << 5) - ret + *string; + + return ret; +} + +/** + * hash64 - fast 64-bit hash of an array for internal use + * @p: the array or pointer to first element + * @num: the number of elements to hash + * @base: the 64-bit base number to roll into the hash (usually 0) + * + * The memory region pointed to by p is combined with the base to form + * a 64-bit hash. + * + * This hash will have different results on different machines, so is + * only useful for internal hashes (ie. not hashes sent across the + * network or saved to disk). + * + * It may also change with future versions: it could even detect at runtime + * what the fastest hash to use is. + * + * See also: hash. + * + * Example: + * #include + * #include + * #include + * #include + * + * // Simple demonstration: idential strings will have the same hash, but + * // two different strings will probably not. + * int main(int argc, char *argv[]) + * { + * uint64_t hash1, hash2; + * + * if (argc != 3) + * err(1, "Usage: %s ", argv[0]); + * + * hash1 = hash64(argv[1], strlen(argv[1]), 0); + * hash2 = hash64(argv[2], strlen(argv[2]), 0); + * printf("Hash is %s\n", hash1 == hash2 ? "same" : "different"); + * return 0; + * } + */ +#define hash64(p, num, base) hash64_any((p), (num)*sizeof(*(p)), (base)) + +/** + * hash64_stable - 64 bit hash of an array for external use + * @p: the array or pointer to first element + * @num: the number of elements to hash + * @base: the base number to roll into the hash (usually 0) + * + * The array of simple integer types pointed to by p is combined with + * the base to form a 64-bit hash. + * + * This hash will have the same results on different machines, so can + * be used for external hashes (ie. hashes sent across the network or + * saved to disk). The results will not change in future versions of + * this module. + * + * Note that it is only legal to hand an array of simple integer types + * to this hash (ie. char, uint16_t, int64_t, etc). In these cases, + * the same values will have the same hash result, even though the + * memory representations of integers depend on the machine + * endianness. + * + * See also: + * hash_stable + * + * Example: + * #include + * #include + * #include + * #include + * + * int main(int argc, char *argv[]) + * { + * if (argc != 2) + * err(1, "Usage: %s ", argv[0]); + * + * printf("Hash stable result is %llu\n", + * (long long)hash64_stable(argv[1], strlen(argv[1]), 0)); + * return 0; + * } + */ +#define hash64_stable(p, num, base) \ + (BUILD_ASSERT_OR_ZERO(sizeof(*(p)) == 8 || sizeof(*(p)) == 4 \ + || sizeof(*(p)) == 2 || sizeof(*(p)) == 1) + \ + sizeof(*(p)) == 8 ? hash64_stable_64((p), (num), (base)) \ + : sizeof(*(p)) == 4 ? hash64_stable_32((p), (num), (base)) \ + : sizeof(*(p)) == 2 ? hash64_stable_16((p), (num), (base)) \ + : hash64_stable_8((p), (num), (base))) + + +/** + * hashl - fast 32/64-bit hash of an array for internal use + * @p: the array or pointer to first element + * @num: the number of elements to hash + * @base: the base number to roll into the hash (usually 0) + * + * This is either hash() or hash64(), on 32/64 bit long machines. + */ +#define hashl(p, num, base) \ + (BUILD_ASSERT_OR_ZERO(sizeof(long) == sizeof(uint32_t) \ + || sizeof(long) == sizeof(uint64_t)) + \ + (sizeof(long) == sizeof(uint64_t) \ + ? hash64((p), (num), (base)) : hash((p), (num), (base)))) + +/* Our underlying operations. */ +uint32_t hash_any(const void *key, size_t length, uint32_t base); +uint32_t hash_stable_64(const void *key, size_t n, uint32_t base); +uint32_t hash_stable_32(const void *key, size_t n, uint32_t base); +uint32_t hash_stable_16(const void *key, size_t n, uint32_t base); +uint32_t hash_stable_8(const void *key, size_t n, uint32_t base); +uint64_t hash64_any(const void *key, size_t length, uint64_t base); +uint64_t hash64_stable_64(const void *key, size_t n, uint64_t base); +uint64_t hash64_stable_32(const void *key, size_t n, uint64_t base); +uint64_t hash64_stable_16(const void *key, size_t n, uint64_t base); +uint64_t hash64_stable_8(const void *key, size_t n, uint64_t base); + +/** + * hash_pointer - hash a pointer for internal use + * @p: the pointer value to hash + * @base: the base number to roll into the hash (usually 0) + * + * The pointer p (not what p points to!) is combined with the base to form + * a 32-bit hash. + * + * This hash will have different results on different machines, so is + * only useful for internal hashes (ie. not hashes sent across the + * network or saved to disk). + * + * Example: + * #include + * + * // Code to keep track of memory regions. + * struct region { + * struct region *chain; + * void *start; + * unsigned int size; + * }; + * // We keep a simple hash table. + * static struct region *region_hash[128]; + * + * static void add_region(struct region *r) + * { + * unsigned int h = hash_pointer(r->start, 0); + * + * r->chain = region_hash[h]; + * region_hash[h] = r->chain; + * } + * + * static struct region *find_region(const void *start) + * { + * struct region *r; + * + * for (r = region_hash[hash_pointer(start, 0)]; r; r = r->chain) + * if (r->start == start) + * return r; + * return NULL; + * } + */ +static inline uint32_t hash_pointer(const void *p, uint32_t base) +{ + if (sizeof(p) % sizeof(uint32_t) == 0) { + /* This convoluted union is the right way of aliasing. */ + union { + uint32_t a[sizeof(p) / sizeof(uint32_t)]; + const void *p; + } u; + u.p = p; + return hash_u32(u.a, sizeof(p) / sizeof(uint32_t), base); + } else + return hash(&p, 1, base); +} +#endif /* HASH_H */ diff --git a/ccan/ccan/htable/LICENSE b/ccan/ccan/htable/LICENSE new file mode 120000 index 0000000000..dc314ecac0 --- /dev/null +++ b/ccan/ccan/htable/LICENSE @@ -0,0 +1 @@ +../../licenses/LGPL-2.1 \ No newline at end of file diff --git a/ccan/ccan/htable/htable.c b/ccan/ccan/htable/htable.c new file mode 100644 index 0000000000..f631ffebf1 --- /dev/null +++ b/ccan/ccan/htable/htable.c @@ -0,0 +1,491 @@ +/* Licensed under LGPLv2+ - see LICENSE file for details */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* We use 0x1 as deleted marker. */ +#define HTABLE_DELETED (0x1) + +/* perfect_bitnum 63 means there's no perfect bitnum */ +#define NO_PERFECT_BIT (sizeof(uintptr_t) * CHAR_BIT - 1) + +static void *htable_default_alloc(struct htable *ht, size_t len) +{ + return calloc(len, 1); +} + +static void htable_default_free(struct htable *ht, void *p) +{ + free(p); +} + +static void *(*htable_alloc)(struct htable *, size_t) = htable_default_alloc; +static void (*htable_free)(struct htable *, void *) = htable_default_free; + +void htable_set_allocator(void *(*alloc)(struct htable *, size_t len), + void (*free)(struct htable *, void *p)) +{ + if (!alloc) + alloc = htable_default_alloc; + if (!free) + free = htable_default_free; + htable_alloc = alloc; + htable_free = free; +} + +/* We clear out the bits which are always the same, and put metadata there. */ +static inline uintptr_t get_extra_ptr_bits(const struct htable *ht, + uintptr_t e) +{ + return e & ht->common_mask; +} + +static inline void *get_raw_ptr(const struct htable *ht, uintptr_t e) +{ + return (void *)((e & ~ht->common_mask) | ht->common_bits); +} + +static inline uintptr_t make_hval(const struct htable *ht, + const void *p, uintptr_t bits) +{ + return ((uintptr_t)p & ~ht->common_mask) | bits; +} + +static inline bool entry_is_valid(uintptr_t e) +{ + return e > HTABLE_DELETED; +} + +static inline uintptr_t ht_perfect_mask(const struct htable *ht) +{ + return (uintptr_t)2 << ht->perfect_bitnum; +} + +static inline uintptr_t get_hash_ptr_bits(const struct htable *ht, + size_t hash) +{ + /* Shuffling the extra bits (as specified in mask) down the + * end is quite expensive. But the lower bits are redundant, so + * we fold the value first. */ + return (hash ^ (hash >> ht->bits)) + & ht->common_mask & ~ht_perfect_mask(ht); +} + +void htable_init(struct htable *ht, + size_t (*rehash)(const void *elem, void *priv), void *priv) +{ + struct htable empty = HTABLE_INITIALIZER(empty, NULL, NULL); + *ht = empty; + ht->rehash = rehash; + ht->priv = priv; + ht->table = &ht->common_bits; +} + +/* Fill to 87.5% */ +static inline size_t ht_max(const struct htable *ht) +{ + return ((size_t)7 << ht->bits) / 8; +} + +/* Clean deleted if we're full, and more than 12.5% deleted */ +static inline size_t ht_max_deleted(const struct htable *ht) +{ + return ((size_t)1 << ht->bits) / 8; +} + +bool htable_init_sized(struct htable *ht, + size_t (*rehash)(const void *, void *), + void *priv, size_t expect) +{ + htable_init(ht, rehash, priv); + + /* Don't go insane with sizing. */ + for (ht->bits = 1; ht_max(ht) < expect; ht->bits++) { + if (ht->bits == 30) + break; + } + + ht->table = htable_alloc(ht, sizeof(size_t) << ht->bits); + if (!ht->table) { + ht->table = &ht->common_bits; + return false; + } + (void)htable_debug(ht, HTABLE_LOC); + return true; +} + +void htable_clear(struct htable *ht) +{ + if (ht->table != &ht->common_bits) + htable_free(ht, (void *)ht->table); + htable_init(ht, ht->rehash, ht->priv); +} + +bool htable_copy_(struct htable *dst, const struct htable *src) +{ + uintptr_t *htable = htable_alloc(dst, sizeof(size_t) << src->bits); + + if (!htable) + return false; + + *dst = *src; + dst->table = htable; + memcpy(dst->table, src->table, sizeof(size_t) << src->bits); + return true; +} + +static size_t hash_bucket(const struct htable *ht, size_t h) +{ + return h & ((1 << ht->bits)-1); +} + +static void *htable_val(const struct htable *ht, + struct htable_iter *i, size_t hash, uintptr_t perfect) +{ + uintptr_t h2 = get_hash_ptr_bits(ht, hash) | perfect; + + while (ht->table[i->off]) { + if (ht->table[i->off] != HTABLE_DELETED) { + if (get_extra_ptr_bits(ht, ht->table[i->off]) == h2) + return get_raw_ptr(ht, ht->table[i->off]); + } + i->off = (i->off + 1) & ((1 << ht->bits)-1); + h2 &= ~perfect; + } + return NULL; +} + +void *htable_firstval_(const struct htable *ht, + struct htable_iter *i, size_t hash) +{ + i->off = hash_bucket(ht, hash); + return htable_val(ht, i, hash, ht_perfect_mask(ht)); +} + +void *htable_nextval_(const struct htable *ht, + struct htable_iter *i, size_t hash) +{ + i->off = (i->off + 1) & ((1 << ht->bits)-1); + return htable_val(ht, i, hash, 0); +} + +void *htable_first_(const struct htable *ht, struct htable_iter *i) +{ + for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) { + if (entry_is_valid(ht->table[i->off])) + return get_raw_ptr(ht, ht->table[i->off]); + } + return NULL; +} + +void *htable_next_(const struct htable *ht, struct htable_iter *i) +{ + for (i->off++; i->off < (size_t)1 << ht->bits; i->off++) { + if (entry_is_valid(ht->table[i->off])) + return get_raw_ptr(ht, ht->table[i->off]); + } + return NULL; +} + +void *htable_prev_(const struct htable *ht, struct htable_iter *i) +{ + for (;;) { + if (!i->off) + return NULL; + i->off--; + if (entry_is_valid(ht->table[i->off])) + return get_raw_ptr(ht, ht->table[i->off]); + } +} + +/* Another bit currently in mask needs to be exposed, so that a bucket with p in + * it won't appear invalid */ +static COLD void unset_another_common_bit(struct htable *ht, + uintptr_t *maskdiff, + const void *p) +{ + size_t i; + + for (i = sizeof(uintptr_t) * CHAR_BIT - 1; i > 0; i--) { + if (((uintptr_t)p & ((uintptr_t)1 << i)) + && ht->common_mask & ~*maskdiff & ((uintptr_t)1 << i)) + break; + } + /* There must have been one, right? */ + assert(i > 0); + + *maskdiff |= ((uintptr_t)1 << i); +} + +/* We want to change the common mask: this fixes up the table */ +static COLD void fixup_table_common(struct htable *ht, uintptr_t maskdiff) +{ + size_t i; + uintptr_t bitsdiff; + +again: + bitsdiff = ht->common_bits & maskdiff; + + for (i = 0; i < (size_t)1 << ht->bits; i++) { + uintptr_t e; + if (!entry_is_valid(e = ht->table[i])) + continue; + + /* Clear the bits no longer in the mask, set them as + * expected. */ + e &= ~maskdiff; + e |= bitsdiff; + /* If this made it invalid, restart with more exposed */ + if (!entry_is_valid(e)) { + unset_another_common_bit(ht, &maskdiff, get_raw_ptr(ht, e)); + goto again; + } + ht->table[i] = e; + } + + /* Take away those bits from our mask, bits and perfect bit. */ + ht->common_mask &= ~maskdiff; + ht->common_bits &= ~maskdiff; + if (ht_perfect_mask(ht) & maskdiff) + ht->perfect_bitnum = NO_PERFECT_BIT; +} + +/* Limited recursion */ +static void ht_add(struct htable *ht, const void *new, size_t h); + +/* We tried to add this entry, but it looked invalid! We need to + * let another pointer bit through mask */ +static COLD void update_common_fix_invalid(struct htable *ht, const void *p, size_t h) +{ + uintptr_t maskdiff; + + assert(ht->elems != 0); + + maskdiff = 0; + unset_another_common_bit(ht, &maskdiff, p); + fixup_table_common(ht, maskdiff); + + /* Now won't recurse */ + ht_add(ht, p, h); +} + +/* This does not expand the hash table, that's up to caller. */ +static void ht_add(struct htable *ht, const void *new, size_t h) +{ + size_t i; + uintptr_t perfect = ht_perfect_mask(ht); + + i = hash_bucket(ht, h); + + while (entry_is_valid(ht->table[i])) { + perfect = 0; + i = (i + 1) & ((1 << ht->bits)-1); + } + ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect); + if (!entry_is_valid(ht->table[i])) + update_common_fix_invalid(ht, new, h); +} + +static COLD bool double_table(struct htable *ht) +{ + unsigned int i; + size_t oldnum = (size_t)1 << ht->bits; + uintptr_t *oldtable, e; + + oldtable = ht->table; + ht->table = htable_alloc(ht, sizeof(size_t) << (ht->bits+1)); + if (!ht->table) { + ht->table = oldtable; + return false; + } + ht->bits++; + + /* If we lost our "perfect bit", get it back now. */ + if (ht->perfect_bitnum == NO_PERFECT_BIT && ht->common_mask) { + for (i = 0; i < sizeof(ht->common_mask) * CHAR_BIT; i++) { + if (ht->common_mask & ((size_t)2 << i)) { + ht->perfect_bitnum = i; + break; + } + } + } + + if (oldtable != &ht->common_bits) { + for (i = 0; i < oldnum; i++) { + if (entry_is_valid(e = oldtable[i])) { + void *p = get_raw_ptr(ht, e); + ht_add(ht, p, ht->rehash(p, ht->priv)); + } + } + htable_free(ht, oldtable); + } + ht->deleted = 0; + + (void)htable_debug(ht, HTABLE_LOC); + return true; +} + +static COLD void rehash_table(struct htable *ht) +{ + size_t start, i; + uintptr_t e, perfect = ht_perfect_mask(ht); + + /* Beware wrap cases: we need to start from first empty bucket. */ + for (start = 0; ht->table[start]; start++); + + for (i = 0; i < (size_t)1 << ht->bits; i++) { + size_t h = (i + start) & ((1 << ht->bits)-1); + e = ht->table[h]; + if (!e) + continue; + if (e == HTABLE_DELETED) + ht->table[h] = 0; + else if (!(e & perfect)) { + void *p = get_raw_ptr(ht, e); + ht->table[h] = 0; + ht_add(ht, p, ht->rehash(p, ht->priv)); + } + } + ht->deleted = 0; + (void)htable_debug(ht, HTABLE_LOC); +} + +/* We stole some bits, now we need to put them back... */ +static COLD void update_common(struct htable *ht, const void *p) +{ + uintptr_t maskdiff; + + if (ht->elems == 0) { + ht->common_mask = -1; + ht->common_bits = ((uintptr_t)p & ht->common_mask); + ht->perfect_bitnum = 0; + (void)htable_debug(ht, HTABLE_LOC); + return; + } + + /* Find bits which are unequal to old common set. */ + maskdiff = ht->common_bits ^ ((uintptr_t)p & ht->common_mask); + + fixup_table_common(ht, maskdiff); + (void)htable_debug(ht, HTABLE_LOC); +} + +bool htable_add_(struct htable *ht, size_t hash, const void *p) +{ + /* Cannot insert NULL, or (void *)1. */ + assert(p); + assert(entry_is_valid((uintptr_t)p)); + + /* Getting too full? */ + if (ht->elems+1 + ht->deleted > ht_max(ht)) { + /* If we're more than 1/8 deleted, clean those, + * otherwise double table size. */ + if (ht->deleted > ht_max_deleted(ht)) + rehash_table(ht); + else if (!double_table(ht)) + return false; + } + if (((uintptr_t)p & ht->common_mask) != ht->common_bits) + update_common(ht, p); + + ht_add(ht, p, hash); + ht->elems++; + return true; +} + +bool htable_del_(struct htable *ht, size_t h, const void *p) +{ + struct htable_iter i; + void *c; + + for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) { + if (c == p) { + htable_delval(ht, &i); + return true; + } + } + return false; +} + +void htable_delval_(struct htable *ht, struct htable_iter *i) +{ + assert(i->off < (size_t)1 << ht->bits); + assert(entry_is_valid(ht->table[i->off])); + + ht->elems--; + /* Cheap test: if the next bucket is empty, don't need delete marker */ + if (ht->table[hash_bucket(ht, i->off+1)] != 0) { + ht->table[i->off] = HTABLE_DELETED; + ht->deleted++; + } else + ht->table[i->off] = 0; +} + +void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i) +{ + void *e; + struct htable_iter unwanted; + + if (!i) + i = &unwanted; + i->off = seed % ((size_t)1 << ht->bits); + e = htable_next(ht, i); + if (!e) + e = htable_first(ht, i); + return e; +} + +struct htable *htable_check(const struct htable *ht, const char *abortstr) +{ + void *p; + struct htable_iter i; + size_t n = 0; + + /* Use non-DEBUG versions here, to avoid infinite recursion with + * CCAN_HTABLE_DEBUG! */ + for (p = htable_first_(ht, &i); p; p = htable_next_(ht, &i)) { + struct htable_iter i2; + void *c; + size_t h = ht->rehash(p, ht->priv); + bool found = false; + + n++; + + /* Open-code htable_get to avoid CCAN_HTABLE_DEBUG */ + for (c = htable_firstval_(ht, &i2, h); + c; + c = htable_nextval_(ht, &i2, h)) { + if (c == p) { + found = true; + break; + } + } + + if (!found) { + if (abortstr) { + fprintf(stderr, + "%s: element %p in position %zu" + " cannot find itself\n", + abortstr, p, i.off); + abort(); + } + return NULL; + } + } + if (n != ht->elems) { + if (abortstr) { + fprintf(stderr, + "%s: found %zu elems, expected %zu\n", + abortstr, n, ht->elems); + abort(); + } + return NULL; + } + + return (struct htable *)ht; +} diff --git a/ccan/ccan/htable/htable.h b/ccan/ccan/htable/htable.h new file mode 100644 index 0000000000..faaf541bd8 --- /dev/null +++ b/ccan/ccan/htable/htable.h @@ -0,0 +1,290 @@ +/* Licensed under LGPLv2+ - see LICENSE file for details */ +#ifndef CCAN_HTABLE_H +#define CCAN_HTABLE_H +#include "config.h" +#include +#include +#include +#include + +/* Define CCAN_HTABLE_DEBUG for expensive debugging checks on each call. */ +#define HTABLE_LOC __FILE__ ":" stringify(__LINE__) +#ifdef CCAN_HTABLE_DEBUG +#define htable_debug(h, loc) htable_check((h), loc) +#else +#define htable_debug(h, loc) ((void)loc, h) +#endif + +/** + * struct htable - private definition of a htable. + * + * It's exposed here so you can put it in your structures and so we can + * supply inline functions. + */ +struct htable { + size_t (*rehash)(const void *elem, void *priv); + void *priv; + unsigned int bits, perfect_bitnum; + size_t elems, deleted; + /* These are the bits which are the same in all pointers. */ + uintptr_t common_mask, common_bits; + uintptr_t *table; +}; + +/** + * HTABLE_INITIALIZER - static initialization for a hash table. + * @name: name of this htable. + * @rehash: hash function to use for rehashing. + * @priv: private argument to @rehash function. + * + * This is useful for setting up static and global hash tables. + * + * Example: + * // For simplicity's sake, say hash value is contents of elem. + * static size_t rehash(const void *elem, void *unused) + * { + * (void)unused; + * return *(size_t *)elem; + * } + * static struct htable ht = HTABLE_INITIALIZER(ht, rehash, NULL); + */ +#define HTABLE_INITIALIZER(name, rehash, priv) \ + { rehash, priv, 0, 0, 0, 0, -1, 0, &name.common_bits } + +/** + * htable_init - initialize an empty hash table. + * @ht: the hash table to initialize + * @rehash: hash function to use for rehashing. + * @priv: private argument to @rehash function. + */ +void htable_init(struct htable *ht, + size_t (*rehash)(const void *elem, void *priv), void *priv); + +/** + * htable_init_sized - initialize an empty hash table of given size. + * @ht: the hash table to initialize + * @rehash: hash function to use for rehashing. + * @priv: private argument to @rehash function. + * @size: the number of element. + * + * If this returns false, @ht is still usable, but may need to do reallocation + * upon an add. If this returns true, it will not need to reallocate within + * @size htable_adds. + */ +bool htable_init_sized(struct htable *ht, + size_t (*rehash)(const void *elem, void *priv), + void *priv, size_t size); + +/** + * htable_count - count number of entries in a hash table. + * @ht: the hash table + */ +static inline size_t htable_count(const struct htable *ht) +{ + return ht->elems; +} + +/** + * htable_clear - empty a hash table. + * @ht: the hash table to clear + * + * This doesn't do anything to any pointers left in it. + */ +void htable_clear(struct htable *ht); + + +/** + * htable_check - check hash table for consistency + * @ht: the htable + * @abortstr: the location to print on aborting, or NULL. + * + * Because hash tables have redundant information, consistency checking that + * each element is in the correct location can be done. This is useful as a + * debugging check. If @abortstr is non-NULL, that will be printed in a + * diagnostic if the htable is inconsistent, and the function will abort. + * + * Returns the htable if it is consistent, NULL if not (it can never return + * NULL if @abortstr is set). + */ +struct htable *htable_check(const struct htable *ht, const char *abortstr); + +/** + * htable_copy - duplicate a hash table. + * @dst: the hash table to overwrite + * @src: the hash table to copy + * + * Only fails on out-of-memory. + * + * Equivalent to (but faster than): + * if (!htable_init_sized(dst, src->rehash, src->priv, 1U << src->bits)) + * return false; + * v = htable_first(src, &i); + * while (v) { + * htable_add(dst, v); + * v = htable_next(src, i); + * } + * return true; + */ +#define htable_copy(dst, src) htable_copy_(dst, htable_debug(src, HTABLE_LOC)) +bool htable_copy_(struct htable *dst, const struct htable *src); + +/** + * htable_add - add a pointer into a hash table. + * @ht: the htable + * @hash: the hash value of the object + * @p: the non-NULL pointer (also cannot be (void *)1). + * + * Also note that this can only fail due to allocation failure. Otherwise, it + * returns true. + */ +#define htable_add(ht, hash, p) \ + htable_add_(htable_debug(ht, HTABLE_LOC), hash, p) +bool htable_add_(struct htable *ht, size_t hash, const void *p); + +/** + * htable_del - remove a pointer from a hash table + * @ht: the htable + * @hash: the hash value of the object + * @p: the pointer + * + * Returns true if the pointer was found (and deleted). + */ +#define htable_del(ht, hash, p) \ + htable_del_(htable_debug(ht, HTABLE_LOC), hash, p) +bool htable_del_(struct htable *ht, size_t hash, const void *p); + +/** + * struct htable_iter - iterator or htable_first or htable_firstval etc. + * + * This refers to a location inside the hashtable. + */ +struct htable_iter { + size_t off; +}; + +/** + * htable_firstval - find a candidate for a given hash value + * @htable: the hashtable + * @i: the struct htable_iter to initialize + * @hash: the hash value + * + * You'll need to check the value is what you want; returns NULL if none. + * See Also: + * htable_delval() + */ +#define htable_firstval(htable, i, hash) \ + htable_firstval_(htable_debug(htable, HTABLE_LOC), i, hash) + +void *htable_firstval_(const struct htable *htable, + struct htable_iter *i, size_t hash); + +/** + * htable_nextval - find another candidate for a given hash value + * @htable: the hashtable + * @i: the struct htable_iter to initialize + * @hash: the hash value + * + * You'll need to check the value is what you want; returns NULL if no more. + */ +#define htable_nextval(htable, i, hash) \ + htable_nextval_(htable_debug(htable, HTABLE_LOC), i, hash) +void *htable_nextval_(const struct htable *htable, + struct htable_iter *i, size_t hash); + +/** + * htable_get - find an entry in the hash table + * @ht: the hashtable + * @h: the hash value of the entry + * @cmp: the comparison function + * @ptr: the pointer to hand to the comparison function. + * + * Convenient inline wrapper for htable_firstval/htable_nextval loop. + */ +static inline void *htable_get(const struct htable *ht, + size_t h, + bool (*cmp)(const void *candidate, void *ptr), + const void *ptr) +{ + struct htable_iter i; + void *c; + + for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) { + if (cmp(c, (void *)ptr)) + return c; + } + return NULL; +} + +/** + * htable_first - find an entry in the hash table + * @ht: the hashtable + * @i: the struct htable_iter to initialize + * + * Get an entry in the hashtable; NULL if empty. + */ +#define htable_first(htable, i) \ + htable_first_(htable_debug(htable, HTABLE_LOC), i) +void *htable_first_(const struct htable *htable, struct htable_iter *i); + +/** + * htable_next - find another entry in the hash table + * @ht: the hashtable + * @i: the struct htable_iter to use + * + * Get another entry in the hashtable; NULL if all done. + * This is usually used after htable_first or prior non-NULL htable_next. + */ +#define htable_next(htable, i) \ + htable_next_(htable_debug(htable, HTABLE_LOC), i) +void *htable_next_(const struct htable *htable, struct htable_iter *i); + +/** + * htable_prev - find the previous entry in the hash table + * @ht: the hashtable + * @i: the struct htable_iter to use + * + * Get previous entry in the hashtable; NULL if all done. + * + * "previous" here only means the item that would have been returned by + * htable_next() before the item it returned most recently. + * + * This is usually used in the middle of (or after) a htable_next iteration and + * to "unwind" actions taken. + */ +#define htable_prev(htable, i) \ + htable_prev_(htable_debug(htable, HTABLE_LOC), i) +void *htable_prev_(const struct htable *htable, struct htable_iter *i); + +/** + * htable_delval - remove an iterated pointer from a hash table + * @ht: the htable + * @i: the htable_iter + * + * Usually used to delete a hash entry after it has been found with + * htable_firstval etc. + */ +#define htable_delval(htable, i) \ + htable_delval_(htable_debug(htable, HTABLE_LOC), i) +void htable_delval_(struct htable *ht, struct htable_iter *i); + +/** + * htable_pick - set iterator to a random valid entry. + * @ht: the htable + * @seed: a random number to use. + * @i: the htable_iter which is output (or NULL). + * + * Usually used with htable_delval to delete a random entry. Returns + * NULL iff the table is empty, otherwise a random entry. + */ +#define htable_pick(htable, seed, i) \ + htable_pick_(htable_debug(htable, HTABLE_LOC), seed, i) +void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i); + +/** + * htable_set_allocator - set calloc/free functions. + * @alloc: allocator to use, must zero memory! + * @free: unallocator to use (@p is NULL or a return from @alloc) + */ +void htable_set_allocator(void *(*alloc)(struct htable *, size_t len), + void (*free)(struct htable *, void *p)); +#endif /* CCAN_HTABLE_H */ diff --git a/ccan/ccan/htable/htable_type.h b/ccan/ccan/htable/htable_type.h new file mode 100644 index 0000000000..0aacb7f334 --- /dev/null +++ b/ccan/ccan/htable/htable_type.h @@ -0,0 +1,188 @@ +/* Licensed under LGPLv2+ - see LICENSE file for details */ +#ifndef CCAN_HTABLE_TYPE_H +#define CCAN_HTABLE_TYPE_H +#include +#include +#include "config.h" + +/** + * HTABLE_DEFINE_TYPE - create a set of htable ops for a type + * @type: a type whose pointers will be values in the hash. + * @keyof: a function/macro to extract a key: @keyof(const type *elem) + * @hashfn: a hash function for a @key: size_t @hashfn(const *) + * @eqfn: an equality function keys: bool @eqfn(const type *, const *) + * @prefix: a prefix for all the functions to define (of form _*) + * + * NULL values may not be placed into the hash table. + * + * This defines the type hashtable type and an iterator type: + * struct ; + * struct _iter; + * + * It also defines initialization and freeing functions: + * void _init(struct *); + * bool _init_sized(struct *, size_t); + * void _clear(struct *); + * bool _copy(struct *dst, const struct *src); + * + * Count entries: + * size_t _count(const struct *ht); + * + * Add function only fails if we run out of memory: + * bool _add(struct *ht, const *e); + * + * Delete and delete-by key return true if it was in the set: + * bool _del(struct *ht, const *e); + * bool _delkey(struct *ht, const *k); + * + * Delete by iterator: + * bool _delval(struct *ht, struct _iter *i); + * + * Find and return the (first) matching element, or NULL: + * type *_get(const struct @name *ht, const *k); + * + * Find and return all matching elements, or NULL: + * type *_getfirst(const struct @name *ht, const *k, + * struct _iter *i); + * type *_getnext(const struct @name *ht, const *k, + * struct _iter *i); + * + * Iteration over hashtable is also supported: + * type *_first(const struct *ht, struct _iter *i); + * type *_next(const struct *ht, struct _iter *i); + * type *_prev(const struct *ht, struct _iter *i); + * type *_pick(const struct *ht, size_t seed, + * struct _iter *i); + * It's currently safe to iterate over a changing hashtable, but you might + * miss an element. Iteration isn't very efficient, either. + * + * You can use HTABLE_INITIALIZER like so: + * struct ht = { HTABLE_INITIALIZER(ht.raw, _hash, NULL) }; + */ +#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \ + struct name { struct htable raw; }; \ + struct name##_iter { struct htable_iter i; }; \ + static inline size_t name##_hash(const void *elem, void *priv) \ + { \ + (void)priv; \ + return hashfn(keyof((const type *)elem)); \ + } \ + static inline UNNEEDED void name##_init(struct name *ht) \ + { \ + htable_init(&ht->raw, name##_hash, NULL); \ + } \ + static inline UNNEEDED bool name##_init_sized(struct name *ht, \ + size_t s) \ + { \ + return htable_init_sized(&ht->raw, name##_hash, NULL, s); \ + } \ + static inline UNNEEDED size_t name##_count(const struct name *ht) \ + { \ + return htable_count(&ht->raw); \ + } \ + static inline UNNEEDED void name##_clear(struct name *ht) \ + { \ + htable_clear(&ht->raw); \ + } \ + static inline UNNEEDED bool name##_copy(struct name *dst, \ + const struct name *src) \ + { \ + return htable_copy(&dst->raw, &src->raw); \ + } \ + static inline bool name##_add(struct name *ht, const type *elem) \ + { \ + return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \ + } \ + static inline UNNEEDED bool name##_del(struct name *ht, \ + const type *elem) \ + { \ + return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \ + } \ + static inline UNNEEDED type *name##_get(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k) \ + { \ + struct htable_iter i; \ + size_t h = hashfn(k); \ + void *c; \ + \ + for (c = htable_firstval(&ht->raw,&i,h); \ + c; \ + c = htable_nextval(&ht->raw,&i,h)) { \ + if (eqfn(c, k)) \ + return c; \ + } \ + return NULL; \ + } \ + static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k, \ + size_t h, \ + type *v, \ + struct name##_iter *iter) \ + { \ + while (v) { \ + if (eqfn(v, k)) \ + break; \ + v = htable_nextval(&ht->raw, &iter->i, h); \ + } \ + return v; \ + } \ + static inline UNNEEDED type *name##_getfirst(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k, \ + struct name##_iter *iter) \ + { \ + size_t h = hashfn(k); \ + type *v = htable_firstval(&ht->raw, &iter->i, h); \ + return name##_getmatch_(ht, k, h, v, iter); \ + } \ + static inline UNNEEDED type *name##_getnext(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k, \ + struct name##_iter *iter) \ + { \ + size_t h = hashfn(k); \ + type *v = htable_nextval(&ht->raw, &iter->i, h); \ + return name##_getmatch_(ht, k, h, v, iter); \ + } \ + static inline UNNEEDED bool name##_delkey(struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k) \ + { \ + type *elem = name##_get(ht, k); \ + if (elem) \ + return name##_del(ht, elem); \ + return false; \ + } \ + static inline UNNEEDED void name##_delval(struct name *ht, \ + struct name##_iter *iter) \ + { \ + htable_delval(&ht->raw, &iter->i); \ + } \ + static inline UNNEEDED type *name##_pick(const struct name *ht, \ + size_t seed, \ + struct name##_iter *iter) \ + { \ + return htable_pick(&ht->raw, seed, iter ? &iter->i : NULL); \ + } \ + static inline UNNEEDED type *name##_first(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_first(&ht->raw, &iter->i); \ + } \ + static inline UNNEEDED type *name##_next(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_next(&ht->raw, &iter->i); \ + } \ + static inline UNNEEDED type *name##_prev(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_prev(&ht->raw, &iter->i); \ + } + +#if HAVE_TYPEOF +#define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL)) +#else +/* Assumes keys are a pointer: if not, override. */ +#ifndef HTABLE_KTYPE +#define HTABLE_KTYPE(keyof, type) void * +#endif +#endif +#endif /* CCAN_HTABLE_TYPE_H */ diff --git a/ccan/ccan/ilog/LICENSE b/ccan/ccan/ilog/LICENSE new file mode 120000 index 0000000000..b7951dabdc --- /dev/null +++ b/ccan/ccan/ilog/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/ilog/ilog.c b/ccan/ccan/ilog/ilog.c new file mode 100644 index 0000000000..5f5122d518 --- /dev/null +++ b/ccan/ccan/ilog/ilog.c @@ -0,0 +1,141 @@ +/*(C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain). + * See LICENSE file for details. */ +#include "ilog.h" +#include + +/*The fastest fallback strategy for platforms with fast multiplication appears + to be based on de Bruijn sequences~\cite{LP98}. + Tests confirmed this to be true even on an ARM11, where it is actually faster + than using the native clz instruction. + Define ILOG_NODEBRUIJN to use a simpler fallback on platforms where + multiplication or table lookups are too expensive. + + @UNPUBLISHED{LP98, + author="Charles E. Leiserson and Harald Prokop", + title="Using de {Bruijn} Sequences to Index a 1 in a Computer Word", + month=Jun, + year=1998, + note="\url{http://supertech.csail.mit.edu/papers/debruijn.pdf}" + }*/ +static UNNEEDED const unsigned char DEBRUIJN_IDX32[32]={ + 0, 1,28, 2,29,14,24, 3,30,22,20,15,25,17, 4, 8, + 31,27,13,23,21,19,16, 7,26,12,18, 6,11, 5,10, 9 +}; + +/* We always compile these in, in case someone takes address of function. */ +#undef ilog32_nz +#undef ilog32 +#undef ilog64_nz +#undef ilog64 + +int ilog32(uint32_t _v){ +/*On a Pentium M, this branchless version tested as the fastest version without + multiplications on 1,000,000,000 random 32-bit integers, edging out a + similar version with branches, and a 256-entry LUT version.*/ +# if defined(ILOG_NODEBRUIJN) + int ret; + int m; + ret=_v>0; + m=(_v>0xFFFFU)<<4; + _v>>=m; + ret|=m; + m=(_v>0xFFU)<<3; + _v>>=m; + ret|=m; + m=(_v>0xFU)<<2; + _v>>=m; + ret|=m; + m=(_v>3)<<1; + _v>>=m; + ret|=m; + ret+=_v>1; + return ret; +/*This de Bruijn sequence version is faster if you have a fast multiplier.*/ +# else + int ret; + ret=_v>0; + _v|=_v>>1; + _v|=_v>>2; + _v|=_v>>4; + _v|=_v>>8; + _v|=_v>>16; + _v=(_v>>1)+1; + ret+=DEBRUIJN_IDX32[_v*0x77CB531U>>27&0x1F]; + return ret; +# endif +} + +int ilog32_nz(uint32_t _v) +{ + return ilog32(_v); +} + +int ilog64(uint64_t _v){ +# if defined(ILOG_NODEBRUIJN) + uint32_t v; + int ret; + int m; + ret=_v>0; + m=(_v>0xFFFFFFFFU)<<5; + v=(uint32_t)(_v>>m); + ret|=m; + m=(v>0xFFFFU)<<4; + v>>=m; + ret|=m; + m=(v>0xFFU)<<3; + v>>=m; + ret|=m; + m=(v>0xFU)<<2; + v>>=m; + ret|=m; + m=(v>3)<<1; + v>>=m; + ret|=m; + ret+=v>1; + return ret; +# else +/*If we don't have a 64-bit word, split it into two 32-bit halves.*/ +# if LONG_MAX<9223372036854775807LL + uint32_t v; + int ret; + int m; + ret=_v>0; + m=(_v>0xFFFFFFFFU)<<5; + v=(uint32_t)(_v>>m); + ret|=m; + v|=v>>1; + v|=v>>2; + v|=v>>4; + v|=v>>8; + v|=v>>16; + v=(v>>1)+1; + ret+=DEBRUIJN_IDX32[v*0x77CB531U>>27&0x1F]; + return ret; +/*Otherwise do it in one 64-bit operation.*/ +# else + static const unsigned char DEBRUIJN_IDX64[64]={ + 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, + 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, + 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, + 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 + }; + int ret; + ret=_v>0; + _v|=_v>>1; + _v|=_v>>2; + _v|=_v>>4; + _v|=_v>>8; + _v|=_v>>16; + _v|=_v>>32; + _v=(_v>>1)+1; + ret+=DEBRUIJN_IDX64[_v*0x218A392CD3D5DBF>>58&0x3F]; + return ret; +# endif +# endif +} + +int ilog64_nz(uint64_t _v) +{ + return ilog64(_v); +} + diff --git a/ccan/ccan/ilog/ilog.h b/ccan/ccan/ilog/ilog.h new file mode 100644 index 0000000000..32702b1785 --- /dev/null +++ b/ccan/ccan/ilog/ilog.h @@ -0,0 +1,154 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#if !defined(_ilog_H) +# define _ilog_H (1) +# include "config.h" +# include +# include +# include + +/** + * ilog32 - Integer binary logarithm of a 32-bit value. + * @_v: A 32-bit value. + * Returns floor(log2(_v))+1, or 0 if _v==0. + * This is the number of bits that would be required to represent _v in two's + * complement notation with all of the leading zeros stripped. + * Note that many uses will resolve to the fast macro version instead. + * + * See Also: + * ilog32_nz(), ilog64() + * + * Example: + * // Rounds up to next power of 2 (if not a power of 2). + * static uint32_t round_up32(uint32_t i) + * { + * assert(i != 0); + * return 1U << ilog32(i-1); + * } + */ +int ilog32(uint32_t _v) CONST_FUNCTION; + +/** + * ilog32_nz - Integer binary logarithm of a non-zero 32-bit value. + * @_v: A 32-bit value. + * Returns floor(log2(_v))+1, or undefined if _v==0. + * This is the number of bits that would be required to represent _v in two's + * complement notation with all of the leading zeros stripped. + * Note that many uses will resolve to the fast macro version instead. + * See Also: + * ilog32(), ilog64_nz() + * Example: + * // Find Last Set (ie. highest bit set, 0 to 31). + * static uint32_t fls32(uint32_t i) + * { + * assert(i != 0); + * return ilog32_nz(i) - 1; + * } + */ +int ilog32_nz(uint32_t _v) CONST_FUNCTION; + +/** + * ilog64 - Integer binary logarithm of a 64-bit value. + * @_v: A 64-bit value. + * Returns floor(log2(_v))+1, or 0 if _v==0. + * This is the number of bits that would be required to represent _v in two's + * complement notation with all of the leading zeros stripped. + * Note that many uses will resolve to the fast macro version instead. + * See Also: + * ilog64_nz(), ilog32() + */ +int ilog64(uint64_t _v) CONST_FUNCTION; + +/** + * ilog64_nz - Integer binary logarithm of a non-zero 64-bit value. + * @_v: A 64-bit value. + * Returns floor(log2(_v))+1, or undefined if _v==0. + * This is the number of bits that would be required to represent _v in two's + * complement notation with all of the leading zeros stripped. + * Note that many uses will resolve to the fast macro version instead. + * See Also: + * ilog64(), ilog32_nz() + */ +int ilog64_nz(uint64_t _v) CONST_FUNCTION; + +/** + * STATIC_ILOG_32 - The integer logarithm of an (unsigned, 32-bit) constant. + * @_v: A non-negative 32-bit constant. + * Returns floor(log2(_v))+1, or 0 if _v==0. + * This is the number of bits that would be required to represent _v in two's + * complement notation with all of the leading zeros stripped. + * This macro should only be used when you need a compile-time constant, + * otherwise ilog32 or ilog32_nz are just as fast and more flexible. + * + * Example: + * #define MY_PAGE_SIZE 4096 + * #define MY_PAGE_BITS (STATIC_ILOG_32(PAGE_SIZE) - 1) + */ +#define STATIC_ILOG_32(_v) (STATIC_ILOG5((uint32_t)(_v))) + +/** + * STATIC_ILOG_64 - The integer logarithm of an (unsigned, 64-bit) constant. + * @_v: A non-negative 64-bit constant. + * Returns floor(log2(_v))+1, or 0 if _v==0. + * This is the number of bits that would be required to represent _v in two's + * complement notation with all of the leading zeros stripped. + * This macro should only be used when you need a compile-time constant, + * otherwise ilog64 or ilog64_nz are just as fast and more flexible. + */ +#define STATIC_ILOG_64(_v) (STATIC_ILOG6((uint64_t)(_v))) + +/* Private implementation details */ + +/*Note the casts to (int) below: this prevents "upgrading" + the type of an entire expression to an (unsigned) size_t.*/ +#if INT_MAX>=2147483647 && HAVE_BUILTIN_CLZ +#define builtin_ilog32_nz(v) \ + (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clz(v)) +#elif LONG_MAX>=2147483647L && HAVE_BUILTIN_CLZL +#define builtin_ilog32_nz(v) \ + (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clzl(v)) +#endif + +#if INT_MAX>=9223372036854775807LL && HAVE_BUILTIN_CLZ +#define builtin_ilog64_nz(v) \ + (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clz(v)) +#elif LONG_MAX>=9223372036854775807LL && HAVE_BUILTIN_CLZL +#define builtin_ilog64_nz(v) \ + (((int)sizeof(unsigned long)*CHAR_BIT) - __builtin_clzl(v)) +#elif HAVE_BUILTIN_CLZLL +#define builtin_ilog64_nz(v) \ + (((int)sizeof(unsigned long long)*CHAR_BIT) - __builtin_clzll(v)) +#endif + +#ifdef builtin_ilog32_nz +/* This used to be builtin_ilog32_nz(_v)&-!!(_v), which means it zeroes out + * the undefined builtin_ilog32_nz(0) return. But clang UndefinedBehaviorSantizer + * complains, so do the branch: */ +#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0) +#define ilog32_nz(_v) builtin_ilog32_nz(_v) +#else +#define ilog32_nz(_v) ilog32(_v) +#define ilog32(_v) (IS_COMPILE_CONSTANT(_v) ? STATIC_ILOG_32(_v) : ilog32(_v)) +#endif /* builtin_ilog32_nz */ + +#ifdef builtin_ilog64_nz +#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0) +#define ilog64_nz(_v) builtin_ilog64_nz(_v) +#else +#define ilog64_nz(_v) ilog64(_v) +#define ilog64(_v) (IS_COMPILE_CONSTANT(_v) ? STATIC_ILOG_64(_v) : ilog64(_v)) +#endif /* builtin_ilog64_nz */ + +/* Macros for evaluating compile-time constant ilog. */ +# define STATIC_ILOG0(_v) (!!(_v)) +# define STATIC_ILOG1(_v) (((_v)&0x2)?2:STATIC_ILOG0(_v)) +# define STATIC_ILOG2(_v) (((_v)&0xC)?2+STATIC_ILOG1((_v)>>2):STATIC_ILOG1(_v)) +# define STATIC_ILOG3(_v) \ + (((_v)&0xF0)?4+STATIC_ILOG2((_v)>>4):STATIC_ILOG2(_v)) +# define STATIC_ILOG4(_v) \ + (((_v)&0xFF00)?8+STATIC_ILOG3((_v)>>8):STATIC_ILOG3(_v)) +# define STATIC_ILOG5(_v) \ + (((_v)&0xFFFF0000)?16+STATIC_ILOG4((_v)>>16):STATIC_ILOG4(_v)) +# define STATIC_ILOG6(_v) \ + (((_v)&0xFFFFFFFF00000000ULL)?32+STATIC_ILOG5((_v)>>32):STATIC_ILOG5(_v)) + +#endif /* _ilog_H */ diff --git a/ccan/ccan/likely/LICENSE b/ccan/ccan/likely/LICENSE new file mode 120000 index 0000000000..b7951dabdc --- /dev/null +++ b/ccan/ccan/likely/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/likely/likely.c b/ccan/ccan/likely/likely.c new file mode 100644 index 0000000000..83e8d6fbe1 --- /dev/null +++ b/ccan/ccan/likely/likely.c @@ -0,0 +1,136 @@ +/* CC0 (Public domain) - see LICENSE file for details. */ +#ifdef CCAN_LIKELY_DEBUG +#include +#include +#include +#include +#include +struct trace { + const char *condstr; + const char *file; + unsigned int line; + bool expect; + unsigned long count, right; +}; + +static size_t hash_trace(const struct trace *trace) +{ + return hash(trace->condstr, strlen(trace->condstr), + hash(trace->file, strlen(trace->file), + trace->line + trace->expect)); +} + +static bool trace_eq(const struct trace *t1, const struct trace *t2) +{ + return t1->condstr == t2->condstr + && t1->file == t2->file + && t1->line == t2->line + && t1->expect == t2->expect; +} + +/* struct thash */ +HTABLE_DEFINE_TYPE(struct trace, (const struct trace *), hash_trace, trace_eq, + thash); + +static struct thash htable += { HTABLE_INITIALIZER(htable.raw, thash_hash, NULL) }; + +static void init_trace(struct trace *trace, + const char *condstr, const char *file, unsigned int line, + bool expect) +{ + trace->condstr = condstr; + trace->file = file; + trace->line = line; + trace->expect = expect; + trace->count = trace->right = 0; +} + +static struct trace *add_trace(const struct trace *t) +{ + struct trace *trace = malloc(sizeof(*trace)); + *trace = *t; + thash_add(&htable, trace); + return trace; +} + +long _likely_trace(bool cond, bool expect, + const char *condstr, + const char *file, unsigned int line) +{ + struct trace *p, trace; + + init_trace(&trace, condstr, file, line, expect); + p = thash_get(&htable, &trace); + if (!p) + p = add_trace(&trace); + + p->count++; + if (cond == expect) + p->right++; + + return cond; +} + +static double right_ratio(const struct trace *t) +{ + return (double)t->right / t->count; +} + +char *likely_stats(unsigned int min_hits, unsigned int percent) +{ + struct trace *worst; + double worst_ratio; + struct thash_iter i; + char *ret; + struct trace *t; + + worst = NULL; + worst_ratio = 2; + + /* This is O(n), but it's not likely called that often. */ + for (t = thash_first(&htable, &i); t; t = thash_next(&htable, &i)) { + if (t->count >= min_hits) { + if (right_ratio(t) < worst_ratio) { + worst = t; + worst_ratio = right_ratio(t); + } + } + } + + if (worst_ratio * 100 > percent) + return NULL; + + ret = malloc(strlen(worst->condstr) + + strlen(worst->file) + + sizeof(long int) * 8 + + sizeof("%s:%u:%slikely(%s) correct %u%% (%lu/%lu)")); + sprintf(ret, "%s:%u:%slikely(%s) correct %u%% (%lu/%lu)", + worst->file, worst->line, + worst->expect ? "" : "un", worst->condstr, + (unsigned)(worst_ratio * 100), + worst->right, worst->count); + + thash_del(&htable, worst); + free(worst); + + return ret; +} + +void likely_stats_reset(void) +{ + struct thash_iter i; + struct trace *t; + + /* This is a bit better than O(n^2), but we have to loop since + * first/next during delete is unreliable. */ + while ((t = thash_first(&htable, &i)) != NULL) { + for (; t; t = thash_next(&htable, &i)) { + thash_del(&htable, t); + free(t); + } + } + + thash_clear(&htable); +} +#endif /*CCAN_LIKELY_DEBUG*/ diff --git a/ccan/ccan/likely/likely.h b/ccan/ccan/likely/likely.h new file mode 100644 index 0000000000..a8f003d727 --- /dev/null +++ b/ccan/ccan/likely/likely.h @@ -0,0 +1,111 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_LIKELY_H +#define CCAN_LIKELY_H +#include "config.h" +#include + +#ifndef CCAN_LIKELY_DEBUG +#if HAVE_BUILTIN_EXPECT +/** + * likely - indicate that a condition is likely to be true. + * @cond: the condition + * + * This uses a compiler extension where available to indicate a likely + * code path and optimize appropriately; it's also useful for readers + * to quickly identify exceptional paths through functions. The + * threshold for "likely" is usually considered to be between 90 and + * 99%; marginal cases should not be marked either way. + * + * See Also: + * unlikely(), likely_stats() + * + * Example: + * // Returns false if we overflow. + * static inline bool inc_int(unsigned int *val) + * { + * (*val)++; + * if (likely(*val)) + * return true; + * return false; + * } + */ +#define likely(cond) __builtin_expect(!!(cond), 1) + +/** + * unlikely - indicate that a condition is unlikely to be true. + * @cond: the condition + * + * This uses a compiler extension where available to indicate an unlikely + * code path and optimize appropriately; see likely() above. + * + * See Also: + * likely(), likely_stats(), COLD (compiler.h) + * + * Example: + * // Prints a warning if we overflow. + * static inline void inc_int(unsigned int *val) + * { + * (*val)++; + * if (unlikely(*val == 0)) + * fprintf(stderr, "Overflow!"); + * } + */ +#define unlikely(cond) __builtin_expect(!!(cond), 0) +#else +#define likely(cond) (!!(cond)) +#define unlikely(cond) (!!(cond)) +#endif +#else /* CCAN_LIKELY_DEBUG versions */ +#include + +#define likely(cond) \ + (_likely_trace(!!(cond), 1, stringify(cond), __FILE__, __LINE__)) +#define unlikely(cond) \ + (_likely_trace(!!(cond), 0, stringify(cond), __FILE__, __LINE__)) + +long _likely_trace(bool cond, bool expect, + const char *condstr, + const char *file, unsigned int line); +/** + * likely_stats - return description of abused likely()/unlikely() + * @min_hits: minimum number of hits + * @percent: maximum percentage correct + * + * When CCAN_LIKELY_DEBUG is defined, likely() and unlikely() trace their + * results: this causes a significant slowdown, but allows analysis of + * whether the branches are labelled correctly. + * + * This function returns a malloc'ed description of the least-correct + * usage of likely() or unlikely(). It ignores places which have been + * called less than @min_hits times, and those which were predicted + * correctly more than @percent of the time. It returns NULL when + * nothing meets those criteria. + * + * Note that this call is destructive; the returned offender is + * removed from the trace so that the next call to likely_stats() will + * return the next-worst likely()/unlikely() usage. + * + * Example: + * // Print every place hit more than twice which was wrong > 5%. + * static void report_stats(void) + * { + * #ifdef CCAN_LIKELY_DEBUG + * const char *bad; + * + * while ((bad = likely_stats(2, 95)) != NULL) { + * printf("Suspicious likely: %s", bad); + * free(bad); + * } + * #endif + * } + */ +char *likely_stats(unsigned int min_hits, unsigned int percent); + +/** + * likely_stats_reset - free up memory of likely()/unlikely() branches. + * + * This can also plug memory leaks. + */ +void likely_stats_reset(void); +#endif /* CCAN_LIKELY_DEBUG */ +#endif /* CCAN_LIKELY_H */ diff --git a/ccan/ccan/list/_info b/ccan/ccan/list/_info deleted file mode 100644 index c4f3e2a0ac..0000000000 --- a/ccan/ccan/list/_info +++ /dev/null @@ -1,72 +0,0 @@ -#include "config.h" -#include -#include - -/** - * list - double linked list routines - * - * The list header contains routines for manipulating double linked lists. - * It defines two types: struct list_head used for anchoring lists, and - * struct list_node which is usually embedded in the structure which is placed - * in the list. - * - * Example: - * #include - * #include - * #include - * #include - * - * struct parent { - * const char *name; - * struct list_head children; - * unsigned int num_children; - * }; - * - * struct child { - * const char *name; - * struct list_node list; - * }; - * - * int main(int argc, char *argv[]) - * { - * struct parent p; - * struct child *c; - * int i; - * - * if (argc < 2) - * errx(1, "Usage: %s parent children...", argv[0]); - * - * p.name = argv[1]; - * list_head_init(&p.children); - * p.num_children = 0; - * for (i = 2; i < argc; i++) { - * c = malloc(sizeof(*c)); - * c->name = argv[i]; - * list_add(&p.children, &c->list); - * p.num_children++; - * } - * - * printf("%s has %u children:", p.name, p.num_children); - * list_for_each(&p.children, c, list) - * printf("%s ", c->name); - * printf("\n"); - * return 0; - * } - * - * License: BSD-MIT - * Author: Rusty Russell - */ -int main(int argc, char *argv[]) -{ - if (argc != 2) - return 1; - - if (strcmp(argv[1], "depends") == 0) { - printf("ccan/str\n"); - printf("ccan/container_of\n"); - printf("ccan/check_type\n"); - return 0; - } - - return 1; -} diff --git a/ccan/ccan/short_types/LICENSE b/ccan/ccan/short_types/LICENSE new file mode 120000 index 0000000000..b7951dabdc --- /dev/null +++ b/ccan/ccan/short_types/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/short_types/short_types.h b/ccan/ccan/short_types/short_types.h new file mode 100644 index 0000000000..175377e9ba --- /dev/null +++ b/ccan/ccan/short_types/short_types.h @@ -0,0 +1,35 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_SHORT_TYPES_H +#define CCAN_SHORT_TYPES_H +#include + +/** + * u64/s64/u32/s32/u16/s16/u8/s8 - short names for explicitly-sized types. + */ +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint8_t u8; +typedef int8_t s8; + +/* Whichever they include first, they get these definitions. */ +#ifdef CCAN_ENDIAN_H +/** + * be64/be32/be16 - 64/32/16 bit big-endian representation. + */ +typedef beint64_t be64; +typedef beint32_t be32; +typedef beint16_t be16; + +/** + * le64/le32/le16 - 64/32/16 bit little-endian representation. + */ +typedef leint64_t le64; +typedef leint32_t le32; +typedef leint16_t le16; +#endif + +#endif /* CCAN_SHORT_TYPES_H */ diff --git a/ccan/ccan/str/_info b/ccan/ccan/str/_info deleted file mode 100644 index b579525faa..0000000000 --- a/ccan/ccan/str/_info +++ /dev/null @@ -1,52 +0,0 @@ -#include "config.h" -#include -#include - -/** - * str - string helper routines - * - * This is a grab bag of functions for string operations, designed to enhance - * the standard string.h. - * - * Note that if you define CCAN_STR_DEBUG, you will get extra compile - * checks on common misuses of the following functions (they will now - * be out-of-line, so there is a runtime penalty!). - * - * strstr, strchr, strrchr: - * Return const char * if first argument is const (gcc only). - * - * isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph, - * islower, isprint, ispunct, isspace, isupper, isxdigit: - * Static and runtime check that input is EOF or an *unsigned* - * char, as per C standard (really!). - * - * Example: - * #include - * #include - * - * int main(int argc, char *argv[]) - * { - * if (argc > 1 && streq(argv[1], "--verbose")) - * printf("verbose set\n"); - * if (argc > 1 && strstarts(argv[1], "--")) - * printf("Some option set\n"); - * if (argc > 1 && strends(argv[1], "cow-powers")) - * printf("Magic option set\n"); - * return 0; - * } - * - * License: CC0 (Public domain) - * Author: Rusty Russell - */ -int main(int argc, char *argv[]) -{ - if (argc != 2) - return 1; - - if (strcmp(argv[1], "depends") == 0) { - printf("ccan/build_assert\n"); - return 0; - } - - return 1; -} diff --git a/ccan/ccan/strset/strset.c b/ccan/ccan/strset/strset.c new file mode 100644 index 0000000000..06b0d7a76c --- /dev/null +++ b/ccan/ccan/strset/strset.c @@ -0,0 +1,309 @@ +/* This code is based on the public domain code at + * http://github.com/agl/critbit writtem by Adam Langley + * . + * + * Here are the main implementation differences: + * (1) We don't strdup the string on insert; we use the pointer we're given. + * (2) We use a straight bit number rather than a mask; it's simpler. + * (3) We don't use the bottom bit of the pointer, but instead use a leading + * zero to distinguish nodes from strings. + * (4) The empty string (which would look like a node) is handled + * using a special "empty node". + * (5) Delete returns the string, so you can free it if you want to. + * (6) Unions instead of void *, bool instead of int. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +struct node { + /* To differentiate us from strings. */ + char nul_byte; + /* The bit where these children differ. */ + u8 bit_num; + /* The byte number where first bit differs (-1 == empty string node). */ + size_t byte_num; + /* These point to strings or nodes. */ + struct strset child[2]; +}; + +/* Closest member to this in a non-empty set. */ +static const char *closest(struct strset n, const char *member) +{ + size_t len = strlen(member); + const u8 *bytes = (const u8 *)member; + + /* Anything with first byte 0 is a node. */ + while (!n.u.s[0]) { + u8 direction = 0; + + /* Special node which represents the empty string. */ + if (unlikely(n.u.n->byte_num == (size_t)-1)) { + n = n.u.n->child[0]; + break; + } + + if (n.u.n->byte_num < len) { + u8 c = bytes[n.u.n->byte_num]; + direction = (c >> n.u.n->bit_num) & 1; + } + n = n.u.n->child[direction]; + } + return n.u.s; +} + +char *strset_get(const struct strset *set, const char *member) +{ + const char *str; + + /* Non-empty set? */ + if (set->u.n) { + str = closest(*set, member); + if (streq(member, str)) + return (char *)str; + } + errno = ENOENT; + return NULL; +} + +static bool set_string(struct strset *set, + struct strset *n, const char *member) +{ + /* Substitute magic empty node if this is the empty string */ + if (unlikely(!member[0])) { + n->u.n = malloc(sizeof(*n->u.n)); + if (unlikely(!n->u.n)) { + errno = ENOMEM; + return false; + } + n->u.n->nul_byte = '\0'; + n->u.n->byte_num = (size_t)-1; + /* Attach the string to child[0] */ + n = &n->u.n->child[0]; + } + n->u.s = member; + return true; +} + +bool strset_add(struct strset *set, const char *member) +{ + size_t len = strlen(member); + const u8 *bytes = (const u8 *)member; + struct strset *np; + const char *str; + struct node *newn; + size_t byte_num; + u8 bit_num, new_dir; + + /* Empty set? */ + if (!set->u.n) { + return set_string(set, set, member); + } + + /* Find closest existing member. */ + str = closest(*set, member); + + /* Find where they differ. */ + for (byte_num = 0; str[byte_num] == member[byte_num]; byte_num++) { + if (member[byte_num] == '\0') { + /* All identical! */ + errno = EEXIST; + return false; + } + } + + /* Find which bit differs (if we had ilog8, we'd use it) */ + bit_num = ilog32_nz((u8)str[byte_num] ^ bytes[byte_num]) - 1; + assert(bit_num < CHAR_BIT); + + /* Which direction do we go at this bit? */ + new_dir = ((bytes[byte_num]) >> bit_num) & 1; + + /* Allocate new node. */ + newn = malloc(sizeof(*newn)); + if (!newn) { + errno = ENOMEM; + return false; + } + newn->nul_byte = '\0'; + newn->byte_num = byte_num; + newn->bit_num = bit_num; + if (unlikely(!set_string(set, &newn->child[new_dir], member))) { + free(newn); + return false; + } + + /* Find where to insert: not closest, but first which differs! */ + np = set; + while (!np->u.s[0]) { + u8 direction = 0; + + /* Special node which represents the empty string will + * break here too! */ + if (np->u.n->byte_num > byte_num) + break; + /* Subtle: bit numbers are "backwards" for comparison */ + if (np->u.n->byte_num == byte_num && np->u.n->bit_num < bit_num) + break; + + if (np->u.n->byte_num < len) { + u8 c = bytes[np->u.n->byte_num]; + direction = (c >> np->u.n->bit_num) & 1; + } + np = &np->u.n->child[direction]; + } + + newn->child[!new_dir]= *np; + np->u.n = newn; + return true; +} + +char *strset_del(struct strset *set, const char *member) +{ + size_t len = strlen(member); + const u8 *bytes = (const u8 *)member; + struct strset *parent = NULL, *n; + const char *ret = NULL; + u8 direction = 0; /* prevent bogus gcc warning. */ + + /* Empty set? */ + if (!set->u.n) { + errno = ENOENT; + return NULL; + } + + /* Find closest, but keep track of parent. */ + n = set; + /* Anything with first byte 0 is a node. */ + while (!n->u.s[0]) { + u8 c = 0; + + /* Special node which represents the empty string. */ + if (unlikely(n->u.n->byte_num == (size_t)-1)) { + const char *empty_str = n->u.n->child[0].u.s; + + if (member[0]) { + errno = ENOENT; + return NULL; + } + + /* Sew empty string back so remaining logic works */ + free(n->u.n); + n->u.s = empty_str; + break; + } + + parent = n; + if (n->u.n->byte_num < len) { + c = bytes[n->u.n->byte_num]; + direction = (c >> n->u.n->bit_num) & 1; + } else + direction = 0; + n = &n->u.n->child[direction]; + } + + /* Did we find it? */ + if (!streq(member, n->u.s)) { + errno = ENOENT; + return NULL; + } + + ret = n->u.s; + + if (!parent) { + /* We deleted last node. */ + set->u.n = NULL; + } else { + struct node *old = parent->u.n; + /* Raise other node to parent. */ + *parent = old->child[!direction]; + free(old); + } + + return (char *)ret; +} + +static bool iterate(struct strset n, + bool (*handle)(const char *, void *), const void *data) +{ + if (n.u.s[0]) + return handle(n.u.s, (void *)data); + if (unlikely(n.u.n->byte_num == (size_t)-1)) + return handle(n.u.n->child[0].u.s, (void *)data); + + return iterate(n.u.n->child[0], handle, data) + && iterate(n.u.n->child[1], handle, data); +} + +void strset_iterate_(const struct strset *set, + bool (*handle)(const char *, void *), const void *data) +{ + /* Empty set? */ + if (!set->u.n) + return; + + iterate(*set, handle, data); +} + +const struct strset *strset_prefix(const struct strset *set, const char *prefix) +{ + const struct strset *n, *top; + size_t len = strlen(prefix); + const u8 *bytes = (const u8 *)prefix; + + /* Empty set -> return empty set. */ + if (!set->u.n) + return set; + + top = n = set; + + /* We walk to find the top, but keep going to check prefix matches. */ + while (!n->u.s[0]) { + u8 c = 0, direction; + + /* Special node which represents the empty string. */ + if (unlikely(n->u.n->byte_num == (size_t)-1)) { + n = &n->u.n->child[0]; + break; + } + + if (n->u.n->byte_num < len) + c = bytes[n->u.n->byte_num]; + + direction = (c >> n->u.n->bit_num) & 1; + n = &n->u.n->child[direction]; + if (c) + top = n; + } + + if (!strstarts(n->u.s, prefix)) { + /* Convenient return for prefixes which do not appear in set. */ + static const struct strset empty_set; + return &empty_set; + } + + return top; +} + +static void clear(struct strset n) +{ + if (!n.u.s[0]) { + if (likely(n.u.n->byte_num != (size_t)-1)) { + clear(n.u.n->child[0]); + clear(n.u.n->child[1]); + } + free(n.u.n); + } +} + +void strset_clear(struct strset *set) +{ + if (set->u.n) + clear(*set); + set->u.n = NULL; +} diff --git a/ccan/ccan/strset/strset.h b/ccan/ccan/strset/strset.h new file mode 100644 index 0000000000..9d6f1ae343 --- /dev/null +++ b/ccan/ccan/strset/strset.h @@ -0,0 +1,167 @@ +#ifndef CCAN_STRSET_H +#define CCAN_STRSET_H +#include "config.h" +#include +#include +#include + +/** + * struct strset - representation of a string set + * + * It's exposed here to allow you to embed it and so we can inline the + * trivial functions. + */ +struct strset { + union { + struct node *n; + const char *s; + } u; +}; + +/** + * strset_init - initialize a string set (empty) + * + * For completeness; if you've arranged for it to be NULL already you don't + * need this. + * + * Example: + * struct strset set; + * + * strset_init(&set); + */ +static inline void strset_init(struct strset *set) +{ + set->u.n = NULL; +} + +/** + * strset_empty - is this string set empty? + * @set: the set. + * + * Example: + * if (!strset_empty(&set)) + * abort(); + */ +static inline bool strset_empty(const struct strset *set) +{ + return set->u.n == NULL; +} + +/** + * strset_get - is this a member of this string set? + * @set: the set. + * @member: the string to search for. + * + * Returns the member, or NULL if it isn't in the set (and sets errno + * = ENOENT). + * + * Example: + * if (strset_get(&set, "hello")) + * printf("hello is in the set\n"); + */ +char *strset_get(const struct strset *set, const char *member); + +/** + * strset_add - place a member in the string set. + * @set: the set. + * @member: the string to place in the set. + * + * This returns false if we run out of memory (errno = ENOMEM), or + * (more normally) if that string already appears in the set (EEXIST). + * + * Note that the pointer is placed in the set, the string is not copied. If + * you want a copy in the set, use strdup(). + * + * Example: + * if (!strset_add(&set, "goodbye")) + * printf("goodbye was already in the set\n"); + */ +bool strset_add(struct strset *set, const char *member); + +/** + * strset_del - remove a member from the string set. + * @set: the set. + * @member: the string to remove from the set. + * + * This returns the string which was passed to strset_add(), or NULL if + * the string was not in the map (in which case it sets errno = ENOENT). + * + * This means that if you allocated a string (eg. using strdup()), you can + * free it here. + * + * Example: + * if (!strset_del(&set, "goodbye")) + * printf("goodbye was not in the set?\n"); + */ +char *strset_del(struct strset *set, const char *member); + +/** + * strset_clear - remove every member from the set. + * @set: the set. + * + * The set will be empty after this. + * + * Example: + * strset_clear(&set); + */ +void strset_clear(struct strset *set); + +/** + * strset_iterate - ordered iteration over a set + * @set: the set. + * @handle: the function to call. + * @arg: the argument for the function (types should match). + * + * You should not alter the set within the @handle function! If it returns + * false, the iteration will stop. + * + * Example: + * static bool dump_some(const char *member, int *num) + * { + * // Only dump out num nodes. + * if (*(num--) == 0) + * return false; + * printf("%s\n", member); + * return true; + * } + * + * static void dump_set(const struct strset *set) + * { + * int max = 100; + * strset_iterate(set, dump_some, &max); + * if (max < 0) + * printf("... (truncated to 100 entries)\n"); + * } + */ +#define strset_iterate(set, handle, arg) \ + strset_iterate_((set), typesafe_cb_preargs(bool, void *, \ + (handle), (arg), \ + const char *), \ + (arg)) +void strset_iterate_(const struct strset *set, + bool (*handle)(const char *, void *), const void *data); + + +/** + * strset_prefix - return a subset matching a prefix + * @set: the set. + * @prefix: the prefix. + * + * This returns a pointer into @set, so don't alter @set while using + * the return value. You can use strset_iterate(), strset_test() or + * strset_empty() on the returned pointer. + * + * Example: + * static void dump_prefix(const struct strset *set, const char *prefix) + * { + * int max = 100; + * printf("Nodes with prefix %s:\n", prefix); + * strset_iterate(strset_prefix(set, prefix), dump_some, &max); + * if (max < 0) + * printf("... (truncated to 100 entries)\n"); + * } + */ +const struct strset *strset_prefix(const struct strset *set, + const char *prefix); + +#endif /* CCAN_STRSET_H */ diff --git a/ccan/ccan/typesafe_cb/LICENSE b/ccan/ccan/typesafe_cb/LICENSE new file mode 120000 index 0000000000..b7951dabdc --- /dev/null +++ b/ccan/ccan/typesafe_cb/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/typesafe_cb/typesafe_cb.h b/ccan/ccan/typesafe_cb/typesafe_cb.h new file mode 100644 index 0000000000..126d325c78 --- /dev/null +++ b/ccan/ccan/typesafe_cb/typesafe_cb.h @@ -0,0 +1,134 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_TYPESAFE_CB_H +#define CCAN_TYPESAFE_CB_H +#include "config.h" + +#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P +/** + * typesafe_cb_cast - only cast an expression if it matches a given type + * @desttype: the type to cast to + * @oktype: the type we allow + * @expr: the expression to cast + * + * This macro is used to create functions which allow multiple types. + * The result of this macro is used somewhere that a @desttype type is + * expected: if @expr is exactly of type @oktype, then it will be + * cast to @desttype type, otherwise left alone. + * + * This macro can be used in static initializers. + * + * This is merely useful for warnings: if the compiler does not + * support the primitives required for typesafe_cb_cast(), it becomes an + * unconditional cast, and the @oktype argument is not used. In + * particular, this means that @oktype can be a type which uses the + * "typeof": it will not be evaluated if typeof is not supported. + * + * Example: + * // We can take either an unsigned long or a void *. + * void _set_some_value(void *val); + * #define set_some_value(e) \ + * _set_some_value(typesafe_cb_cast(void *, unsigned long, (e))) + */ +#define typesafe_cb_cast(desttype, oktype, expr) \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \ + oktype), \ + (desttype)(expr), (expr)) +#else +#define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr)) +#endif + +/** + * typesafe_cb_cast3 - only cast an expression if it matches given types + * @desttype: the type to cast to + * @ok1: the first type we allow + * @ok2: the second type we allow + * @ok3: the third type we allow + * @expr: the expression to cast + * + * This is a convenient wrapper for multiple typesafe_cb_cast() calls. + * You can chain them inside each other (ie. use typesafe_cb_cast() + * for expr) if you need more than 3 arguments. + * + * Example: + * // We can take either a long, unsigned long, void * or a const void *. + * void _set_some_value(void *val); + * #define set_some_value(expr) \ + * _set_some_value(typesafe_cb_cast3(void *,, \ + * long, unsigned long, const void *,\ + * (expr))) + */ +#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \ + typesafe_cb_cast(desttype, ok1, \ + typesafe_cb_cast(desttype, ok2, \ + typesafe_cb_cast(desttype, ok3, \ + (expr)))) + +/** + * typesafe_cb - cast a callback function if it matches the arg + * @rtype: the return type of the callback function + * @atype: the (pointer) type which the callback function expects. + * @fn: the callback function to cast + * @arg: the (pointer) argument to hand to the callback function. + * + * If a callback function takes a single argument, this macro does + * appropriate casts to a function which takes a single atype argument if the + * callback provided matches the @arg. + * + * It is assumed that @arg is of pointer type: usually @arg is passed + * or assigned to a void * elsewhere anyway. + * + * Example: + * void _register_callback(void (*fn)(void *arg), void *arg); + * #define register_callback(fn, arg) \ + * _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg)) + */ +#define typesafe_cb(rtype, atype, fn, arg) \ + typesafe_cb_cast(rtype (*)(atype), \ + rtype (*)(__typeof__(arg)), \ + (fn)) + +/** + * typesafe_cb_preargs - cast a callback function if it matches the arg + * @rtype: the return type of the callback function + * @atype: the (pointer) type which the callback function expects. + * @fn: the callback function to cast + * @arg: the (pointer) argument to hand to the callback function. + * + * This is a version of typesafe_cb() for callbacks that take other arguments + * before the @arg. + * + * Example: + * void _register_callback(void (*fn)(int, void *arg), void *arg); + * #define register_callback(fn, arg) \ + * _register_callback(typesafe_cb_preargs(void, void *, \ + * (fn), (arg), int), \ + * (arg)) + */ +#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \ + typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \ + rtype (*)(__VA_ARGS__, __typeof__(arg)), \ + (fn)) + +/** + * typesafe_cb_postargs - cast a callback function if it matches the arg + * @rtype: the return type of the callback function + * @atype: the (pointer) type which the callback function expects. + * @fn: the callback function to cast + * @arg: the (pointer) argument to hand to the callback function. + * + * This is a version of typesafe_cb() for callbacks that take other arguments + * after the @arg. + * + * Example: + * void _register_callback(void (*fn)(void *arg, int), void *arg); + * #define register_callback(fn, arg) \ + * _register_callback(typesafe_cb_postargs(void, (fn), void *, \ + * (arg), int), \ + * (arg)) + */ +#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \ + typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \ + rtype (*)(__typeof__(arg), __VA_ARGS__), \ + (fn)) +#endif /* CCAN_CAST_IF_TYPE_H */ diff --git a/ccan/licenses/LGPL-2.1 b/ccan/licenses/LGPL-2.1 new file mode 100644 index 0000000000..2d2d780e60 --- /dev/null +++ b/ccan/licenses/LGPL-2.1 @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ccan/meson.build b/ccan/meson.build index 4ba3b5fa55..35d2b881d4 100644 --- a/ccan/meson.build +++ b/ccan/meson.build @@ -1,9 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-or-later sources += files([ + 'ccan/hash/hash.c', + 'ccan/htable/htable.c', + 'ccan/ilog/ilog.c', + 'ccan/likely/likely.c', 'ccan/list/list.c', 'ccan/str/debug.c', 'ccan/str/str.c', + 'ccan/strset/strset.c', ]) if get_option('buildtype') == 'debug' diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..b63481aada --- /dev/null +++ b/codecov.yml @@ -0,0 +1,6 @@ +--- +ignore: + - 'subprojects' + - 'ccan' + - 'tests' + - 'unit' diff --git a/common.h b/common.h index 6a904e1013..b1161189b3 100644 --- a/common.h +++ b/common.h @@ -11,6 +11,11 @@ #define min(x, y) ((x) > (y) ? (y) : (x)) #define max(x, y) ((x) > (y) ? (x) : (y)) +#ifdef __packed +#else /* __packed */ +#define __packed __attribute__((__packed__)) +#endif /* __packed */ + static inline uint32_t mmio_read32(void *addr) { leint32_t *p = addr; @@ -27,7 +32,7 @@ static inline uint64_t mmio_read64(void *addr) low = le32_to_cpu(*p); high = le32_to_cpu(*(p + 1)); - return ((uint64_t) high << 32) | low; + return ((uint64_t)high << 32) | low; } #endif diff --git a/completions/_nvme b/completions/_nvme index fc6b9676ce..e90fc4288b 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -1,6 +1,5 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - #compdef _nvme nvme +# SPDX-License-Identifier: GPL-2.0-or-later # zsh completions for the nvme command-line interface, # very loosely based on git and adb command completion @@ -9,8 +8,11 @@ _nvme () { local -a _cmds _cmds=( + 'list:identify basic information for all NVMe namespaces' + 'list-subsys:identify information for subsystems' 'id-ctrl:display information about the controller' 'id-ns:display information about the namespace' + 'id-ns-granularity:display namespace granularity list' 'id-ns-lba-format:display information about the namespace capability fields for specific LBA format' 'list-ns:identify all namespace(s) attached' 'cmdset-ind-id-ns:display I/O Command Set Independent information about the namespace' @@ -23,47 +25,90 @@ _nvme () { 'list-ctrl:identify all controller(s) attached' 'nvm-id-ctrl:display information about the nvm command set' 'nvm-id-ns:display information about the namespace of nvm command set' - 'id-ns-lba-format:display information about the namespace of nvm command set capability fields for specific LBA format' + 'nvm-id-ns-lba-format:display information about the namespace of nvm command set capability fields for specific LBA format' + 'primary-ctrl-caps:display primary controller capabilities' + 'list-secondary:identify secondary controller list associated with the primary controller' + 'ns-descs:display namespace identification descriptors' + 'id-nvmset:display entries for NVM Set identifiers' + 'id-uuid:display list of supported Vendor Specific UUIDs' 'list-endgrp:display information about nvme endurance group list' 'get-ns-id:get namespace id of opened block device' 'get-log:retrieve any log in raw format' 'predictable-lat-log:retrieve predictable latency per nvmset log' 'pred-lat-event-agg-log:retrieve predictable latency event aggregate log' - 'persistent-event-log:retrieve presistent event log' + 'persistent-event-log:retrieve persistent event log' + 'telemetry-log:retrieve telemetry log' 'fw-log:retrieve fw log' + 'changed-ns-list-log:retrieve changed namespaces log' 'smart-log:retrieve SMART log' 'smart-log-add:retrieve additional SMART log' + 'ana-log:retrieve ANA log' 'error-log:retrieve error log' + 'effects-log:retrieve command effects log page and print the table' + 'endurance-log:retrieves endurance groups log page and prints the log' 'endurance-event-agg-log:retrieve endurance group event aggregate log' 'lba-status-log:retrieve lba status log' - 'resv-notif-log: retrieve reservation notification log' + 'resv-notif-log:retrieve reservation notification log' 'get-feature:display a controller feature' + 'device-self-test:implementing the device self-test feature' + 'self-test-log:retrieve the self-test log' 'set-feature:set a controller feature and show results' + 'set-property:writes and shows the defined NVMe controller property for NVMe over Fabric' + 'get-property:Reads and shows the defined NVMe controller property for NVMe over Fabric' 'format:apply new block format to namespace' 'fw-activate:activate a firmware on the device' 'fw-download:download a firmware to the device' - 'admin-passthru:submit a passthrough IOCTL' - 'io-passthru:submit a passthrough IOCTL' + 'admin-passthru:submit a passthrough admin command IOCTL' + 'io-passthru:submit a passthrough io command IOCTL' 'security-send:send security/secure data to controller' 'security-recv:ask for security/secure data from controller' + 'get-lba-status:display information about potentially unrecoverable LBAs' 'resv-acquire:acquire reservation on a namespace' 'resv-register:register reservation on a namespace' 'resv-release:release reservation on a namespace' 'resv-report:report reservation on a namespace' + 'dsm:submit a Data Set Management command' 'copy:submit a simple copy command' 'flush:submit a flush' 'compare:compare data on device to data elsewhere' 'read:submit a read command' 'write:submit a write command' - 'capacity-mgmt: submit capacity management command' - 'show-regs:shows the controller registers; requires admin character device' - 'boot-part-log: retrieve boot partition log' + 'capacity-mgmt:submit capacity management command' + 'write-zeroes:submit an NVMe write zeroes command' + 'write-uncor:submit an NVMe write uncorrectable command' + 'verify:submit an NVMe Verify command' + 'sanitize:submit a sanitize command' + 'sanitize-log:retrieve sanitize log and show it' + 'reset:reset the NVMe controller' + 'subsystem-reset:reset the NVMe subsystem' + 'ns-rescan:rescan the NVMe namespaces' + 'show-regs:show the controller registers; require admin character device' + 'boot-part-log:retrieve boot partition log' 'fid-support-effects-log:retrieve fid support and effects log' - 'supported-log-pages: retrieve support log pages details' + 'supported-log-pages:retrieve support log pages details' 'lockdown:submit a lockdown command' - 'media-unit-stat-log: retrieve media unit status log pages details' - 'supported-cap-config-log: retrieve support log pages details' + 'media-unit-stat-log:retrieve media unit status log pages details' + 'supported-cap-config-log:retrieve the list of Supported Capacity Configuration Descriptors' + 'discover:send Get Log Page request to Discovery Controller' + 'connect-all:discover NVMeoF subsystems and connect to them' + 'connect:connect to NVMeoF subsystem' + 'dim:send Discovery Information Management command to a Discovery Controller (DC)' + 'disconnect:disconnect from NVMeoF subsystem' + 'disconnect-all:disconnect from all connected NVMeoF subsystems' + 'gen-hostnqn:generate a host NVMe Qualified Name' + 'show-hostnqn:show the host NQN configured for the system' + 'dir-receive:read directive parameters of the specified directive type' + 'dir-send:set directive parameters of the specified directive type' + 'virt-mgmt:submit a Virtualization Management command' + 'rpmb:submit an NVMe RPMB command' + 'show-topology:show subsystem topology' + 'nvme-mi-recv:send a NVMe-MI receive command' + 'nvme-mi-send:send a NVMe-MI send command' + 'version:show the program version' + 'ocp:OCP cloud SSD extensions' + 'solidigm:Solidigm plug-in extensions' 'help:print brief descriptions of all nvme commands' + 'json:dump output in json format' ) local expl @@ -73,8 +118,377 @@ _nvme () { if (( CURRENT == 1 )); then _describe -t commands "nvme subcommands" _cmds return + elif (( CURRENT > 2 )); then + case ${words[1]} in + (ocp) + case ${words[2]} in + (smart-add-log) + local _smart_add_log + _smart_add_log=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp smart-add-log options" _smart_add_log + ;; + (latency-monitor-log) + local _latency_monitor_log + _latency_monitor_log=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp latency-monitor-log options" _latency_monitor_log + ;; + (set-latency-monitor-feature) + local _set_latency_monitor_feature + _set_latency_monitor_feature=( + /dev/nvme':supply a device to use (required)' + --active_bucket_timer_threshold=':Active Bucket Timer Threshold' + -t':alias for --active_bucket_timer_threshold' + --active_threshold_a=':Active Threshold A' + -a':alias for --active_threshold_a' + --active_threshold_a=':Active Threshold B' + -b':alias for --active_threshold_b' + --active_threshold_c=':Active Threshold C' + -c':alias for --active_threshold_c' + --active_threshold_d=':Active Threshold D' + -d':alias for --active_threshold_d' + --active_latency_config=':Active Latency Configuration' + -f':alias for --active_latency_config' + --active_latency_minimum_window=':Active Latency Minimum Window' + -w':alias for --active_latency_minimum_window' + --debug_log_trigger_enable='Debug Log Trigger Enable' + -r':alias for --debug_log_trigger_enable' + --discard_debug_log='Discard Debug Log' + -l':alias for --discard_debug_log' + --latency_monitor_feature_enable='Latency Monitor Feature Enable' + -e':alias for --latency_monitor_feature_enable' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp set-latency-monitor-feature options" _set_latency_monitor_feature + ;; + (internal-log) + local _internal_log + _internal_log=( + /dev/nvme':supply a device to use (required)' + --telemetry_type=':Telemetry Type; host (Create bit) or controller' + -t':alias for --telemetry_type' + --telemetry_data_area=':Telemetry Data Area; 1 or 3' + -a':alias for --telemetry_data_area' + --output-file=':Output file name with path' + -o':alias for --output-file' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp internal-log options" _internal_log + ;; + (clear-fw-activate-history) + local _clear_fw_activate_history + _clear_fw_activate_history=( + /dev/nvme':supply a device to use (required)' + --no-uuid':Skip UUID index search' + -n':alias for --no-uuid' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp clear-fw-activate-history options" _clear_fw_activate_history + ;; + (eol-plp-failure-mode) + local _eol_plp_failure_mode + _eol_plp_failure_mode=( + /dev/nvme':supply a device to use (required)' + --mode=':0-3: default/rom/wtm/normal' + -m':alias for --mode' + --save':Specifies that the controller shall save the attribute' + -s':alias for --save' + --sel=':0-3,8: current/default/saved/supported/changed:' + -S':alias for --sel' + --no-uuid':Skip UUID index search' + -n':alias for --no-uuid' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp eol-plp-failure-mode options" _eol_plp_failure_mode + ;; + (clear-pcie-correctable-error-counters) + local _clear_pcie_correctable_error_counters + _clear_pcie_correctable_error_counters=( + /dev/nvme':supply a device to use (required)' + --no-uuid':Skip UUID index search' + -n':alias for --no-uuid' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp clear-pcie-correctable-error-counters options" _clear_pcie_correctable_error_counters + ;; + (fw-activate-history) + local _fw_activate_history + _fw_activate_history=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp fw-activate-history options" _fw_activate_history + ;; + (device-capability-log) + local _device_capability_log + _device_capability_log=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp device-capability-log options" _device_capability_log + ;; + (set-dssd-power-state-feature) + local _set_dssd_power_state_feature + _set_dssd_power_state_feature=( + /dev/nvme':supply a device to use (required)' + --power-state=':DSSD Power State to set in watts' + -p':alias for --power-state' + --save':Specifies that the controller shall save the attribute' + -s':alias for --save' + --no-uuid':Skip UUID index search' + -n':alias for --no-uuid' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp set-dssd-power-state-feature options" _set_dssd_power_state_feature + ;; + (telemetry-string-log) + local _telemetry_string_log + _telemetry_string_log=( + /dev/nvme':supply a device to use (required)' + --output-file=':Output file name with path' + -o':alias for --output-file' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp telemetry-string-log options" _telemetry_string_log + ;; + (*) + _files + ;; + esac + ;; + (solidigm) + case ${words[2]} in + (id-ctrl) + local _id_ctrl + _id_ctrl=( + --verbose':Increase output verbosity' + -v':alias for --verbose' + --output-format':Output format: normal|json|binary' + -o':alias for --output-format' + --vendor-specific':dump binary vendor field' + -V':alias for --vendor-specific' + --raw-binary':show identify in binary format' + -b':alias for --raw-binary' + --human-readable':show identify in readable format' + -H':alias for --human-readable' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm id-ctrl options" _id_ctrl + ;; + (smart-log-add) + local _smart_log_add + _smart_log_add=( + --namespace-id':(optional) desired namespace' + -n':alias for --namespace-id' + --output-format':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm smart-log-add options" _smart_log_add + ;; + (vs-smart-add-log) + local _vs_smart_add_log + _vs_smart_add_log=( + --output-format':output Format: normal|json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm vs-smart-add-log options" _vs_smart_add_log + ;; + (vs-internal-log) + local _vs_internal_log + _vs_internal_log=( + --type':Log type: ALL, + CONTROLLERINITTELEMETRY, + HOSTINITTELEMETRY, + HOSTINITTELEMETRYNOGEN, NLOG, + ASSERT, EVENT. Defaults to ALL.' + -t':alias for --type' + --namespace-id':Namespace to get logs from.' + -n':alias for --namespace-id' + --dir-prefix':Output dir prefix; defaults to device serial number.' + -p':alias for --dir-prefix' + --verbose':To print out verbose info.' + -v':alias for --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm vs-internal-log" _vs_internal_log + ;; + (garbage-collect-log) + local _garbage_collect_log + _garbage_collect_log=( + --output-format':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm garbage-collect-log" _garbage_collect_log + ;; + (market-log) + local _market_log + _market_log=( + --raw-binary':dump output in binary format' + -b':alias for --raw-binary' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm market-log" _market_log + ;; + (latency-tracking-log) + local _latency_tracking_log + _latency_tracking_log=( + --enable':Enable Latency Tracking' + -e':alias for --enable' + --disable':Disable Latency Tracking' + -d':alias for --disable' + --read':Get read statistics' + -r':alias for --read' + --write':Get write statistics' + -w':alias for --write' + --type':Log type to get' + -t':alias for --type' + --output-format':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm latency-tracking-log" _latency_tracking_log + ;; + (parse-telemetry-log) + local _parse_telemetry_log + _parse_telemetry_log=( + --host-generate':Controls when to generate new + host initiated report. Default + value '1' generates new host + initiated report, value '0' + causes retrieval of existing + log.' + -g':alias for --host-generate' + --controller-init':Gather report generated by the controller.' + -c':alias for --controller-init' + --data-area':Pick which telemetry data area to + report. Default is 3 to fetch + areas 1-3. Valid options are 1, + 2, 3, 4.' + -d':alias for --data-area' + --config-file':JSON configuration file' + -j':alias for --config-file' + --source-file':data source is binary + file containing log dump instead + of block or character device' + -s':alias for --source-file' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm parse-telemetry-log" _parse_telemetry_log + ;; + (clear-pcie-correctable-errors) + local _clear_pcie_correctable_errors + _clear_pcie_correctable_errors=( + --no-uuid':Skip UUID index search (UUID index not required for OCP 1.0)' + -n':alias for --no-uuid' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm clear-pcie-correctable-errors" _clear_pcie_correctable_errors + ;; + (clear-fw-activate-history) + local _clear_fw_activate_history + _clear_fw_activate_history=( + --no-uuid':Skip UUID index search (UUID index not required for OCP 1.0)' + -n':alias for --no-uuid' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm clear-fw-activate-history" _clear_fw_activate_history + ;; + (vs-fw-activate-history) + local _vs_fw_activate_history + _vs_fw_activate_history=( + --output-format':output format : normal | json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm vs-fw-activate-history" _vs_fw_activate_history + ;; + (log-page-directory) + local _log_page_directory + _log_page_directory=( + --output-format':output format : normal | json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm log-page-directory" _log_page_directory + ;; + (temp-stats) + local _temp_stats + _temp_stats=( + --raw-binary':dump output in binary format' + -b':alias for --raw-binary' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm temp-stats" _temp_stats + ;; + (vs-drive-info) + local _vs_drive_info + _vs_drive_info=( + --output-format':output format : normal | json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm vs-drive-info" _vs_drive_info + ;; + (*) + _files + ;; + esac + ;; + (sanitize) + case ${words[CURRENT-1]} in + (--sanact=|-a) + _values '' 'exit-failure' 'start-block-erase' 'start-overwrite' 'start-crypto-erase' + ;; + (*) + _files + ;; + esac + ;; + (*) + _files + ;; + esac + return else case ${words[CURRENT-1]} in + (list) + local _list + _list=( + --output-format=':Output format: normal|json' + -o':alias for --output-format' + --verbose':show infos verbosely' + -v':alias of --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme list options" _list + ;; + (list-subsys) + local _listsubsys + _listsubsys=( + --output-format=':Output format: normal|json' + -o':alias for --output-format' + --verbose':show infos verbosely' + -v':alias of --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme list-subsys options" _listsubsys + ;; (id-ctrl) local _idctrl _idctrl=( @@ -84,9 +498,8 @@ _nvme () { --human-readable':show infos in readable format' -H':alias of --human-readable' --vendor-specific':also dump binary vendor infos' - -v':alias of --vendor-specific' + -V':alias of --vendor-specific' ) - _arguments '*:: :->subcmds' _describe -t commands "nvme id-ctrl options" _idctrl ;; @@ -101,11 +514,21 @@ _nvme () { --human-readable':show infos in readable format' -H':alias of --human-readable' --vendor-specific':also dump binary vendor infos' - -v':alias of --vendor-specific' + -V':alias of --vendor-specific' ) _arguments '*:: :->subcmds' _describe -t commands "nvme id-ns options" _idns ;; + (id-ns-granularity) + local _idns_granularity + _idns_granularity=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme id-ns-granularity options" _idns_granularity + ;; (id-ns-lba-format) local _idns_lba_format _idns_lba_format=( @@ -130,6 +553,10 @@ _nvme () { -n':alias of --namespace-id' --csi=':command set identifier' -y':alias of --csi' + --all':show all namespaces in the subsystem, whether attached or inactive' + -a':alias of --all' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' ) _arguments '*:: :->subcmds' _describe -t commands "nvme list-ns options" _listns @@ -192,7 +619,7 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme nvm-id-ns options" _nvmidns ;; - (id-ns-lba-format) + (nvm-id-ns-lba-format) local _nvm_idns_lba_format _nvm_idns_lba_format=( /dev/nvme':supply a device to use (required)' @@ -208,6 +635,76 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme nvm-id-ns-lba-format options" _nvm_idns_lba_format ;; + (primary-ctrl-caps) + local _primary_ctrl_caps + _primary_ctrl_caps=( + /dev/nvme':supply a device to use (required)' + --cntlid=':show infos for controller ' + -c':alias of --cntlid' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme primary-ctrl-caps options" _primary_ctrl_caps + ;; + (list-secondary) + local _listsecondary + _listsecondary=( + /dev/nvme':supply a device to use (required)' + --cntid=':show infos for lowest controller ' + -c':alias of --cntid' + --namespace-id=':show infos for namespace ' + -n':alias of --namespace-id' + --num-entries=':number of entries to retrieve' + -e':alias of --num-entries' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme list-secondary options" _listsecondary + ;; + (ns-descs) + local _ns_descs + _ns_descs=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':show infos for namespace ' + -n':alias of --namespace-id' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --raw-binary':dump infos in binary format' + -b':alias of --raw-binary' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ns-descs options" _ns_descs + ;; + (id-nvmset) + local _id_nvmset + _id_nvmset=( + /dev/nvme':supply a device to use (required)' + --nvmset_id=':NVM Set Identify value' + -i':alias of --nvmset_id' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme id-nvmset options" _id_nvmset + ;; + (id-uuid) + local _id_uuid + _id_uuid=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --raw-binary':dump infos in binary format' + -b':alias of --raw-binary' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme id-uuid options" _id_uuid + ;; (list-endgrp) local _listendgrp _listendgrp=( @@ -216,7 +713,7 @@ _nvme () { -i':alias of --endgrp-id' ) _arguments '*:: :->subcmds' - _describe -t commands "nvme list-ns options" _listendgrp + _describe -t commands "nvme list-endgrp options" _listendgrp ;; (create-ns) local _createns @@ -231,9 +728,35 @@ _nvme () { --dps=':data protection?' -d':alias of --dps' --nmic=':multipath and sharing' - -n':alias of --nmic' + -m':alias of --nmic' + --anagrp-id=':ANA Group Identifier' + -a':alias of --anagrp-id' + --nvmset-id=':NVM Set Identifier' + -i':alias of --nvmset-id' + --endg-id=':Endurance Group Identifier' + -e':alias of --endg-id' + --block-size=':target block size' + -b':alias of --block-size' + --timeout=':value for timeout' + -t':alias of --timeout' --csi=':command set identifier' -y':alias of --csi' + --lbstm=':logical block storage tag mask' + -l':alias of --lbstm' + --nsze-si=':size of ns (NSZE) in standard SI units' + -S':alias of --nsze-si' + --ncap-si=':capacity of ns (NCAP) in standard SI units' + -C':alias of --ncap-si' + --azr=':Allocate ZRWA Resources (AZR) for Zoned Namespace Command Set' + -z':alias of --azr' + --rar=':Requested Active Resources (RAR) for Zoned Namespace Command Set' + -r':alias of --rar' + --ror=':Requested Open Resources (ROR) for Zoned Namespace Command Set' + -O':alias of --ror' + --rnumzrwa=':Requested Number of ZRWA Resources (RNUMZRWA) for Zoned Namespace Command Set' + -u':alias of --rnumzrwa' + --phndls=':Comma separated list of Placement Handle Associated RUH' + -p':alias of --phndls' ) _arguments '*:: :->subcmds' _describe -t commands "nvme create-ns options" _createns @@ -244,6 +767,8 @@ _nvme () { /dev/nvme':supply a device to use (required)' --namespace-id=':namespace to delete' -n':alias of --namespace-id' + --timeout=':value for timeout' + -t':alias of --timeout' ) _arguments '*:: :->subcmds' _describe -t commands "nvme delete-ns options" _deletens @@ -304,6 +829,22 @@ _nvme () { -n':alias of --namespace-id' --raw-binary':dump infos in binary format' -b':alias of --raw-binary' + --aen=':result of the aen, use to override log id' + -a':alias of --aen' + --lpo=':log page offset specifies the location within a log page from where to start returning data' + -L':alias of --lpo' + --lsi=':log specific identifier specifies an identifier that is required for a particular log page' + -S':alias of --lsi' + --rae':Retain an Asynchronous Event' + -r':alias of --rae' + --uuid-index=':uuid index' + -U':alias for --uuid-index' + --csi=':command set identifier' + -y':alias of --csi' + --ot':offset type' + -O':alias of --ot' + --xfer-len=':read chunk size (default 4k)' + -x':alias of --xfer-len' ) _arguments '*:: :->subcmds' _describe -t commands "nvme get-log options" _getlog @@ -312,7 +853,7 @@ _nvme () { local _persistenteventlog _persistenteventlog=( /dev/nvme':supply a device to use (required)' - --action=': action the controller shall take for this log page' + --action=':action the controller shall take for this log page' -a':alias to --action' --log-len=':number of bytes to show for requested log' -l':alias of --log-len' @@ -320,15 +861,35 @@ _nvme () { -b':alias of --raw-binary' ) _arguments '*:: :->subcmds' - _describe -t commands "persistent-event-log options" _persistenteventlog + _describe -t commands "nvme persistent-event-log options" _persistenteventlog + ;; + (telemetry-log) + local _telemetry_log + _telemetry_log=( + /dev/nvme':supply a device to use (required)' + --output-file=':telemetry data output write' + -O':alias for --output-file' + --host-generate=':Have the host tell the controller to generate the report' + -g':alias to --host-generate' + --controller-init':Gather report generated by the controller' + -c':alias of --controller-init' + --data-area':Pick which telemetry data area to report' + -d':alias of --data-area' + --data-area':Pick which telemetry data area to report' + -d':alias of --data-area' + --rae':Retain an Asynchronous Event' + -r':alias to --rae' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme telemetry-log options" _telemetry_log ;; (pred-lat-event-agg-log) local _predlateventagglog _predlateventagglog=( /dev/nvme':supply a device to use (required)' - --log-entries=': Number of pending NVM Set Entries log list' + --log-entries=':Number of pending NVM Set Entries log list' -e':alias to --log-entries' - --rae': Retain an Asynchronous Event' + --rae':Retain an Asynchronous Event' -r':alias to --rae' --raw-binary':dump infos in binary format' -b':alias of --raw-binary' @@ -340,7 +901,7 @@ _nvme () { local _predictablelatlog _predictablelatlog=( /dev/nvme':supply a device to use (required)' - --nvmset-id=': NVM Set Identifier on which log page retrieve info' + --nvmset-id=':NVM Set Identifier on which log page retrieve info' -i':alias to --nvmset-id' --raw-binary':dump infos in binary format' -b':alias of --raw-binary' @@ -358,6 +919,18 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme fw-log options" _fwlog ;; + (changed-ns-list-log) + local _changed_ns_list_log + _changed_ns_list_log=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --raw-binary':dump infos in binary format' + -b':alias of --raw-binary' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme changed-ns-list-log options" _changed_ns_list_log + ;; (smart-log) local _smartlog _smartlog=( @@ -382,6 +955,18 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme smart-log-add options" _add ;; + (ana-log) + local _ana_log + _ana_log=( + /dev/nvme':supply a device to use (required)' + --groups':Return ANA groups only' + -g':alias to --groups' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ana-log options" _ana_log + ;; (error-log) local _errlog _errlog=( @@ -396,13 +981,41 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme error-log options" _errlog ;; + (effects-log) + local _effects_log + _effects_log=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + --raw-binary':dump infos in binary format' + -b':alias to --raw-binary' + --csi=':command set identifier' + -c':alias of --csi' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme effects-log options" _effects_log + ;; + (endurance-log) + local _endurance_log + _endurance_log=( + /dev/nvme':supply a device to use (required)' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --group-id=':The endurance group identifier' + -g':alias of --group-id' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme endurance-log options" _endurance_log + ;; (endurance-event-agg-log) local _enduranceeventagglog _enduranceeventagglog=( /dev/nvme':supply a device to use (required)' - --log-entries=': Number of Endurance Group Event Agg Entries log list' + --log-entries=':Number of Endurance Group Event Agg Entries log list' -e':alias to --log-entries' - --rae': Retain an Asynchronous Event' + --rae':Retain an Asynchronous Event' -r':alias to --rae' --raw-binary':dump infos in binary format' -b':alias of --raw-binary' @@ -414,7 +1027,7 @@ _nvme () { local _lbastatuslog _lbastatuslog=( /dev/nvme':supply a device to use (required)' - --rae': Retain an Asynchronous Event' + --rae':Retain an Asynchronous Event' -r':alias to --rae' ) _arguments '*:: :->subcmds' @@ -432,9 +1045,9 @@ _nvme () { local _bootpartlog _bootpartlog=( /dev/nvme':supply a device to use (required)' - --lsp=': log specific field' + --lsp=':log specific field' -s':alias to --lsp' - --output-file=': boot partition data output write' + --output-file=':boot partition data output write' -f':alias for --output-file' ) _arguments '*:: :->subcmds' @@ -461,12 +1074,40 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme get-feature options" _getf ;; + (device-self-test) + local _device_self_test + _device_self_test=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':Indicate the namespace in which the device self-test has to be carried out' + -n':alias to --namespace-id' + --self-test-code=':This field specifies the action taken by the device self-test command' + -s':alias for --self-test-code' + --wait':Wait for the test to finish' + -w':alias to --wait' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme device-self-test options" _device_self_test + ;; + (self-test-log) + local _self_test_log + _self_test_log=( + /dev/nvme':supply a device to use (required)' + --dst-entries=':Indicate how many DST log entries to be retrieved' + -e':alias to --dst-entries' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --verbose':show infos verbosely' + -v':alias of --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme self-test-log options" _self_test_log + ;; (lockdown) local _lockdown _lockdown=( /dev/nvme':supply a device to use (required)' - --ofi=': Opcode or Feature Identifier(OFI) (required)' - -o':alias of --ofi' + --ofi=':Opcode or Feature Identifier(OFI) (required)' + -O':alias of --ofi' --ifc=':Interface (INF) field Information (required)' -f':alias of --ifc' --prhbt=':Prohibit(PRHBT) bit field (required)' @@ -492,19 +1133,45 @@ _nvme () { --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' + -V'alias to --value' --uuid-index=':uuid index' -U':alias for --uuid-index' ) _arguments '*:: :->subcmds' _describe -t commands "nvme set-feature options" _setf ;; + (set-property) + local _set_property + _set_property=( + /dev/nvme':supply a device to use (required)' + --offset=':the offset of the property' + -O':alias to --offset' + --value=':the value of the property to be set' + -V':alias to --value' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme set-property options" _set_property + ;; + (get-property) + local _get_property + _get_property=( + /dev/nvme':supply a device to use (required)' + --offset=':the offset of the property' + -O':alias to --offset' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme get-property options" _get_property + ;; (format) local _format _format=( /dev/nvme':supply a device to use (required)' --namespace-id=': of namespace to format (required)' -n':alias of --namespace-id' + --timeout=':value for timeout' + -t':alias of --timeout' --lbaf=':LBA format to apply to namespace (required)' -l':alias of --lbaf' --ses=':secure erase? 0 - no-op (default), 1 - user-data erase, 2 - cryptographic erase' @@ -540,7 +1207,7 @@ _nvme () { --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' + -O':alias of --offset' ) _arguments '*:: :->subcmds' _describe -t commands "nvme fw-download options" _fwd @@ -550,7 +1217,7 @@ _nvme () { _fwd=( /dev/nvme':supply a device to use (required)' --operation=':Operation to be performed by the controller' - -o':alias of --operation' + -O':alias of --operation' --element-id=':specific to the value of the Operation field' -i':alias of --element-id' --cap-lower=':Least significant 32 bits of the capacity in bytes' @@ -561,6 +1228,150 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme capacity-mgmt options" _fwd ;; + (write-zeroes) + local _write_zeroes + _write_zeroes=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --start-block=':64-bit address of the first logical block to be written' + -s':alias of --start-block' + --block-count=':number of logical blocks on device to write' + -c':alias of --block-count' + --dir-type=':directive type' + -T':alias of --dir-type' + --deac':Set DEAC bit, requesting controller to deallocate specified logical blocks' + -d':alias of --deac' + --limited-retry':if included, controller should try less hard to send data to media (if not included, all available data-recovery means used)' + -l':alias of --limited-retry' + --force-unit-access':data shall be written to nonvolatile media before command completion is indicated' + -f':alias of --force-unit-access' + --prinfo=':protection information and check field' + -p':alias of --prinfo' + --ref-tag=':reference tag (for end to end PI)' + -r':alias of --ref-tag' + --app-tag-mask=':application tag mask (for end to end PI)' + -m':alias of --app-tag-mask' + --app-tag=':application tag (for end to end PI)' + -a':alias of --app-tag' + --storage-tag=':storage tag for end-to-end PI' + -S':alias of --storage-tag' + --storage-tag-check':Storage Tag field shall be checked as part of end-to-end data protection processing' + -C':alias of --storage-tag-check' + --dir-spec=':directive specific' + -D':alias of --dir-spec' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme write-zeroes options" _write_zeroes + ;; + (write-uncor) + local _write_uncor + _write_uncor=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --start-block=':64-bit address of the first logical block to be written' + -s':alias of --start-block' + --block-count=':number of logical blocks on device to write' + -c':alias of --block-count' + --dir-type=':directive type' + -T':alias of --dir-type' + --dir-spec':directive specific' + -S':alias of --dir-spec' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme write-uncor options" _write_uncor + ;; + (verify) + local _verify + _verify=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --start-block=':64-bit address of the first logical block to be verified' + -s':alias of --start-block' + --block-count=':number of logical blocks on device to verify' + -c':alias of --block-count' + --limited-retry':if included, controller should try less hard to send data to media (if not included, all available data-recovery means used)' + -l':alias of --limited-retry' + --force-unit-access':data shall be verified from nonvolatile media before command completion is indicated' + -f':alias of --force-unit-access' + --prinfo=':protection information and check field' + -p':alias of --prinfo' + --ref-tag=':reference tag (for end to end PI)' + -r':alias of --ref-tag' + --app-tag=':application tag (for end to end PI)' + -a':alias of --app-tag' + --app-tag-mask=':application tag mask (for end to end PI)' + -m':alias of --app-tag-mask' + --storage-tag=':storage tag for end-to-end PI' + -S':alias of --storage-tag' + --storage-tag-check':Storage Tag field shall be checked as part of end-to-end data protection processing' + -C':alias of --storage-tag-check' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme verify options" _verify + ;; + (sanitize) + local _sanitize + _sanitize=( + /dev/nvme':supply a device to use (required)' + --no-dealloc':No deallocate after sanitize' + -d':alias of --no-dealloc' + --oipbp':Overwrite invert pattern between passes' + -i':alias of --oipbp' + --owpass=':Overwrite pass count' + -n':alias of --owpass' + --ause':Allow unrestricted sanitize exit' + -u':alias of --ause' + --sanact=':Sanitize action: 1 = Exit failure mode, 2 = Start block erase, 3 = Start overwrite, 4 = Start crypto erase' + -a':alias of --sanact' + --ovrpat=':Overwrite pattern' + -p':alias of --ovrpat' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme sanitize options" _sanitize + ;; + (sanitize-log) + local _sanitize_log + _sanitize_log=( + /dev/nvme':supply a device to use (required)' + --rae':Retain an Asynchronous Event' + -r':alias of --rae' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + --raw-binary':dump infos in binary format' + -b':alias of --raw-binary' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme sanitize-log options" _sanitize_log + ;; + (reset) + local _reset + _reset=( + /dev/nvme':supply a device to use (required)' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme reset options" _reset + ;; + (subsystem-reset) + local _subsystem_reset + _subsystem_reset=( + /dev/nvme':supply a device to use (required)' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme subsystem-reset options" _subsystem_reset + ;; + (ns-rescan) + local _ns_rescan + _ns_rescan=( + /dev/nvme':supply a device to use (required)' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ns-rescan options" _ns_rescan + ;; (supported-log-pages) local _support _support=( @@ -600,7 +1411,7 @@ _nvme () { _admin=( /dev/nvme':supply a device to use (required)' --opcode=':hexadecimal opcode to send (required)' - -o':alias of --opcode' + -O':alias of --opcode' --flags=':command flags' -f':alias of --flags' --rsvd=':value for reserved field' @@ -650,7 +1461,7 @@ _nvme () { _io=( /dev/nvme':supply a device to use (required)' --opcode=':hexadecimal opcode to send (required)' - -o':alias of --opcode' + -O':alias of --opcode' --flags=':command flags' -f':alias of --flags' --rsvd=':value for reserved field' @@ -729,6 +1540,28 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme security-recv options" _srecv ;; + (get-lba-status) + local _get_lba_status + _get_lba_status=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':show infos for namespace ' + -n':alias of --namespace-id' + --start-lba=':Starting LBA(SLBA) in 64-bit address of the first logical block' + -s':alias for --start-lba' + --max-dw=':Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return' + -m':alias for --max-dw' + --action=':Action Type(ATYPE) specifies the mechanism' + -a':alias for --action' + --range-len=':Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA' + -l':alias for --range-len' + --timeout':value for timeout' + -t':alias for --timeout' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme get-lba-status options" _get_lba_status + ;; (resv-acquire) local _acq _acq=( @@ -801,6 +1634,30 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme resv-register options" _reg ;; + (dsm) + local _dsm + _dsm=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --ctx-attrs=':Comma separated list of the context attributes in each range' + -a':alias of --ctx-attrs' + --blocks':Comma separated list of the number of blocks in each range' + -b':alias of --blocks' + --slbs':Comma separated list of the starting block in each range' + -s':alias of --slbs' + --ad':Attribute Deallocate' + -d':alias of --ad' + --idw':Attribute Integral Dataset for Write' + -w':alias of --idw' + --idr':Attribute Integral Dataset for Read' + -r':alias of --idr' + --cdw11=':value for command dword 11' + -c':alias for --cdw11' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme dsm options" _dsm + ;; (copy) local _copy _copy=( @@ -831,11 +1688,11 @@ _nvme () { -m':alias of --app-tag-mask' --expected-app-tag-masks=':expected lba application tag masks (read part, comma-separated list)' -M':alias of --expected-app-tag-masks' - --dir-type':directive type (write part)' + --dir-type=':directive type (write part)' -T':alias of --dir-type' - --dir-spec':directive specific (write part)' + --dir-spec=':directive specific (write part)' -S':alias of --dir-spec' - --format':source range entry format' + --format=':source range entry format' -F':alias of --format' ) _arguments '*:: :->subcmds' @@ -876,7 +1733,7 @@ _nvme () { --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' + -V':alias of --show-command' --dry-run':show command instead of sending to device' -w':alias of --show-command' ) @@ -905,14 +1762,14 @@ _nvme () { -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)' + --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' + -V':alias of --show-command' --dry-run':show command instead of sending to device' -w':alias of --show-command' ) @@ -941,14 +1798,14 @@ _nvme () { -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)' + --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' + -V':alias of --show-command' --dry-run':show command instead of sending to device' -w':alias of --show-command' ) @@ -971,6 +1828,461 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme fid-support-effects-log options" _fidsupporteffectslog ;; + (discover) + local _discover + _discover=( + --device=':use existing discovery controller device' + -d':alias for --device' + --transport=':transport type' + -t':alias for --transport' + --nqn=':subsystem nqn' + -n':alias for --nqn' + --traddr=':transport address' + -a':alias for --traddr' + --trsvcid=':transport service id (e.g. IP port)' + -s':alias for --trsvcid' + --host-traddr=':host traddr (e.g. FC WWN's)' + -w':alias for --host-traddr' + --host-iface=':host interface (for tcp transport)' + -f':alias for --host-iface' + --hostnqn=':user-defined hostnqn' + -q':alias for --hostnqn' + --hostid=':user-defined hostid (if default not used)' + -I':alias for --hostid' + --dhchap-secret=':user-defined dhchap key (if default not used)' + -S':alias for --dhchap-secret' + --nr-io-queues=':number of io queues to use (default is core count)' + -i':alias for --nr-io-queues' + --nr-write-queues=':number of write queues to use (default 0)' + -W':alias for --nr-write-queues' + --nr-poll-queues=':number of poll queues to use (default 0)' + -P':alias for --nr-poll-queues' + --queue-size=':number of io queue elements to use (default 128)' + -Q':alias for --queue-size' + --keep-alive-tmo=':keep alive timeout period in seconds' + -k':alias for --keep-alive-tmo' + --reconnect-delay=':reconnect timeout period in seconds' + -c':alias for --reconnect-delay' + --ctrl-loss-tmo=':controller loss timeout period in seconds' + -l':alias for --ctrl-loss-tmo' + --tos=':type of service' + -T':alias for --tos' + --keyring=':Keyring for TLS key lookup' + --tls_key=':TLS key to use' + --duplicate-connect':allow duplicate connections between same transport host and subsystem port' + -D':alias for --duplicate-connect' + --disable-sqflow':disable controller sq flow control (default false)' + -d':alias for --disable-sqflow' + --hdr-digest':enable transport protocol header digest (TCP transport)' + -g':alias for --hdr-digest' + --data-digest':enable transport protocol data digest (TCP transport)' + -G':alias for --data-digest' + --tls':enable TLS' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --raw':save raw output to file' + -r':alias of --raw' + --persistent':' + -p':alias for --' + --quiet':' + -S':alias for --' + --config=':Use specified JSON configuration file or none to disable' + -J':alias for --config' + --verbose':Increase logging verbosity' + -v':alias for --verbose' + --dump-config':Dump configuration file to stdout' + -O':alias for --dump-config' + --force':Force persistent discovery controller creation' + --nbft':Only look at NBFT tables' + --no-nbft':Do not look at NBFT tables' + --nbft-patch=':user-defined path for NBFT tables' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme discover options" _discover + ;; + (connect-all) + local _connect_all + _connect_all=( + --device=':use existing discovery controller device' + -d':alias for --device' + --transport=':transport type' + -t':alias for --transport' + --nqn=':subsystem nqn' + -n':alias for --nqn' + --traddr=':transport address' + -a':alias for --traddr' + --trsvcid=':transport service id (e.g. IP port)' + -s':alias for --trsvcid' + --host-traddr=':host traddr (e.g. FC WWN's)' + -w':alias for --host-traddr' + --host-iface=':host interface (for tcp transport)' + -f':alias for --host-iface' + --hostnqn=':user-defined hostnqn' + -q':alias for --hostnqn' + --hostid=':user-defined hostid (if default not used)' + -I':alias for --hostid' + --dhchap-secret=':user-defined dhchap key (if default not used)' + -S':alias for --dhchap-secret' + --nr-io-queues=':number of io queues to use (default is core count)' + -i':alias for --nr-io-queues' + --nr-write-queues=':number of write queues to use (default 0)' + -W':alias for --nr-write-queues' + --nr-poll-queues=':number of poll queues to use (default 0)' + -P':alias for --nr-poll-queues' + --queue-size=':number of io queue elements to use (default 128)' + -Q':alias for --queue-size' + --keep-alive-tmo=':keep alive timeout period in seconds' + -k':alias for --keep-alive-tmo' + --reconnect-delay=':reconnect timeout period in seconds' + -c':alias for --reconnect-delay' + --ctrl-loss-tmo=':controller loss timeout period in seconds' + -l':alias for --ctrl-loss-tmo' + --tos=':type of service' + -T':alias for --tos' + --keyring=':Keyring for TLS key lookup' + --tls_key=':TLS key to use' + --duplicate-connect':allow duplicate connections between same transport host and subsystem port' + -D':alias for --duplicate-connect' + --disable-sqflow':disable controller sq flow control (default false)' + -d':alias for --disable-sqflow' + --hdr-digest':enable transport protocol header digest (TCP transport)' + -g':alias for --hdr-digest' + --data-digest':enable transport protocol data digest (TCP transport)' + -G':alias for --data-digest' + --tls':enable TLS' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --raw':save raw output to file' + -r':alias of --raw' + --persistent':' + -p':alias for --' + --quiet':' + -S':alias for --' + --config=':Use specified JSON configuration file or none to disable' + -J':alias for --config' + --verbose':Increase logging verbosity' + -v':alias for --verbose' + --dump-config':Dump configuration file to stdout' + -O':alias for --dump-config' + --force':Force persistent discovery controller creation' + --nbft':Only look at NBFT tables' + --no-nbft':Do not look at NBFT tables' + --nbft-patch=':user-defined path for NBFT tables' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme connect-all options" _connect_all + ;; + (connect) + local _connect + _connect=( + --transport=':transport type' + -t':alias for --transport' + --nqn=':subsystem nqn' + -n':alias for --nqn' + --traddr=':transport address' + -a':alias for --traddr' + --trsvcid=':transport service id (e.g. IP port)' + -s':alias for --trsvcid' + --host-traddr=':host transport address' + -w':alias for --host-traddr' + --host-iface=':host interface (for tcp transport)' + -f':alias for --host-iface' + --hostnqn=':user-defined hostnqn' + -q':alias for --hostnqn' + --hostid=':user-defined hostid (if default not used)' + -I':alias for --hostid' + --dhchap-secret=':user-defined dhchap key (if default not used)' + -S':alias for --dhchap-secret' + --nr-io-queues=':number of io queues to use (default is core count)' + -i':alias for --nr-io-queues' + --nr-write-queues=':number of write queues to use (default 0)' + -W':alias for --nr-write-queues' + --nr-poll-queues=':number of poll queues to use (default 0)' + -P':alias for --nr-poll-queues' + --queue-size=':number of io queue elements to use (default 128)' + -Q':alias for --queue-size' + --keep-alive-tmo=':keep alive timeout period in seconds' + -k':alias for --keep-alive-tmo' + --reconnect-delay=':reconnect timeout period in seconds' + -c':alias for --reconnect-delay' + --ctrl-loss-tmo=':controller loss timeout period in seconds' + -l':alias for --ctrl-loss-tmo' + --tos=':type of service' + -T':alias for --tos' + --keyring=':Keyring for TLS key lookup' + --tls_key=':TLS key to use' + --duplicate-connect':allow duplicate connections between same transport host and subsystem port' + -D':alias for --duplicate-connect' + --disable-sqflow':disable controller sq flow control (default false)' + -d':alias for --disable-sqflow' + --hdr-digest':enable transport protocol header digest (TCP transport)' + -g':alias for --hdr-digest' + --data-digest':enable transport protocol data digest (TCP transport)' + -G':alias for --data-digest' + --tls':enable TLS' + --dhchap-ctrl-secret=':user-defined dhchap controller key (for bi-directional authentication)' + -C':alias for --dhchap-ctrl-secret' + --config=':Use specified JSON configuration file or none to disable' + -J':alias for --config' + --verbose':Increase logging verbosity' + -v':alias for --verbose' + --dump-config':Dump configuration file to stdout' + -O':alias for --dump-config' + --output-format=':Output format: normal|json' + -o':alias for --output-format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme connect options" _connect + ;; + (dim) + local _dim + _dim=( + --nqn=':Comma-separated list of DC nqn' + -n':alias for --nqn' + --device=':Comma-separated list of DC nvme device handle' + -d':alias for --device' + --task=':The task to perform: register|deregister' + -t':alias for --task' + --verbose':Increase logging verbosity' + -v':alias for --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme dim options" _dim + ;; + (disconnect) + local _disconnect + _disconnect=( + --nqn=':subsystem nqn' + -n':alias for --nqn' + --device=':nvme device handle' + -d':alias for --device' + --verbose':Increase logging verbosity' + -v':alias for --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme disconnect options" _disconnect + ;; + (disconnect-all) + local _disconnect_all + _disconnect_all=( + --transport=':transport type' + -r':alias for --transport' + --verbose':Increase logging verbosity' + -v':alias for --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme disconnect-all options" _disconnect_all + ;; + (gen-hostnqn) + local _gen_hostnqn + _gen_hostnqn=( + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme gen-hostnqn options" _gen_hostnqn + ;; + (show-hostnqn) + local _show_hostnqn + _show_hostnqn=( + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme show-hostnqn options" _show_hostnqn + ;; + (dir-receive) + local _dir_receive + _dir_receive=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --data-len=':length for data buffer' + -l':alias of --data-len' + --raw-binary':dump output in binary format' + -b':alias for --raw-binary' + --dir-type=':directive type' + -D':alias of --dir-type' + --dir-spec=':directive specific' + -S':alias of --dir-spec' + --dir-oper=':directive operation' + -O':alias of --dir-oper' + --req-resource=':namespace stream requested' + -r':alias of --req-resource' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme dir-receive options" _dir_receive + ;; + (dir-send) + local _dir_send + _dir_send=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --data-len=':length for data buffer' + -l':alias of --data-len' + --dir-type=':directive type' + -D':alias of --dir-type' + --target-dir=':target directive type to be enabled/disabled' + -T':alias of --target-dir' + --dir-spec=':directive specific' + -S':alias of --dir-spec' + --dir-oper=':directive operation' + -O':alias of --dir-oper' + --endir=':directive enable' + -e':alias of --endir' + --human-readable':show infos in readable format' + -H':alias of --human-readable' + --raw-binary':dump output in binary format' + -b':alias for --raw-binary' + --input-file=':write/send file (default stdin)' + -i':alias of --input-file' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme dir-send options" _dir_send + ;; + (virt-mgmt) + local _virt_mgmt + _virt_mgmt=( + /dev/nvme':supply a device to use (required)' + --cntlid=':Controller Identifier(CNTLID)' + -c':alias of --cntlid' + --rt=':Resource Type(RT): 0|1' + -r':alias of --rt' + --act=':Action(ACT): 1|7|8|9' + -a':alias of --act' + --nr=':Number of Controller Resources(NR)' + -n':alias of --nr' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme virt-mgmt options" _virt_mgmt + ;; + (rpmb) + local _rpmb + _rpmb=( + /dev/nvme':supply a device to use (required)' + --cmd=':RPMB action: info|program-key|read-counter|write-data|read-data|write-config|read-config' + -c':alias of --cmd' + --msgfile=':data file for read/write-data, read/write-config options' + -f':alias of --msgfile' + --keyfile=':key file that has authentication key to be used' + -g':alias of --keyfile' + --key=':key to be used for authentication' + -k':alias of --key' + --msg=':data to be written on write-data or write-config commands' + -d':alias of --msg' + --address=':Sector offset to read from or write to for an RPMB target, default 0' + -o':alias of --address' + --blocks=':Number of 512 blocks to read or write' + -b':alias of --blocks' + --target=':RPMB target - numerical value of 0 to 6, default 0' + -t':alias of --target' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme rpmb options" _rpmb + ;; + (show-topology) + local _showtopology + _showtopology=( + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --verbose':show infos verbosely' + -v':alias of --verbose' + --ranking=':Ranking order: namespace|ctrl' + -r':alias for --ranking' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme show-topology options" _showtopology + ;; + (nvme-mi-recv) + local _nvme_mi_recv + _nvme_mi_recv=( + --opcode=':NVMe-MI opcode to send' + -O':alias of --opcode' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --data-len=':length for data buffer' + -l':alias of --data-len' + --nmimt':value for NVMe-MI message type' + -m':alias of --nmimt' + --nmd0':value for NVMe management request dword 0' + -0':alias of --nmd0' + --nmd1':value for NVMe management request dword 1' + -1':alias of --nmd1' + --input-file=':defaults to stdin; input for write (send direction)' + -i':alias for --input-file' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme nvme-mi-recv options" _nvme_mi_recv + ;; + (nvme-mi-send) + local _nvme_mi_send + _nvme_mi_send=( + --opcode=':NVMe-MI opcode to send' + -O':alias of --opcode' + --namespace-id=':value for nsid' + -n':alias of --namespace-id' + --data-len=':length for data buffer' + -l':alias of --data-len' + --nmimt':value for NVMe-MI message type' + -m':alias of --nmimt' + --nmd0':value for NVMe management request dword 0' + -0':alias of --nmd0' + --nmd1':value for NVMe management request dword 1' + -1':alias of --nmd1' + --input-file=':defaults to stdin; input for write (send direction)' + -i':alias for --input-file' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme nvme-mi-send options" _nvme_mi_send + ;; + (version) + local _version + _version=( + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme version options" _version + ;; + (ocp) + local _ocp + _ocp=( + smart-add-log':Retrieve extended SMART Information' + latency-monitor-log':Get Latency Monitor Log Page' + set-latency-monitor-feature':Set Latency Monitor feature' + internal-log':Retrieve and save internal device telemetry log' + clear-fw-activate-history':Clear firmware update history log"' + eol-plp-failure-mode':Define EOL or PLP circuitry failure mode' + clear-pcie-correctable-error-counters':Clear PCIe correctable error counters' + vs-fw-activate-history':Get firmware activation history log' + device-capability-log':Get Device capability log' + set-dssd-power-state-feature':Set DSSD Power State' + telemetry-string-log':Retrieve Telemetry string Log Page' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme ocp options" _ocp + ;; + (solidigm) + local _solidigm + _solidigm=( + id-ctrl':Send NVMe Identify Controller' + smart-log-add':Retrieve Solidigm SMART Log' + vs-smart-add-log':Get SMART / health extended log (redirects to ocp plug-in)' + vs-internal-log':Retrieve Debug log binaries' + garbage-collect-log':Retrieve Garbage Collection Log' + market-log':Retrieve Market Log' + latency-tracking-log':Enable/Retrieve Latency tracking Log' + parse-telemetry-log':Parse Telemetry Log binary' + clear-pcie-correctable-errors':Clear PCIe Correctable Error Counters (redirects to ocp plug-in)' + clear-fw-activate-history':Clear firmware update history log (redirects to ocp plug-in)' + vs-fw-activate-history':Get firmware activation history log (redirects to ocp plug-in)' + log-page-directory':Retrieve log page directory' + temp-stats':Retrieve Temperature Statistics log' + vs-drive-info':Retrieve drive information' + cloud-SSDplugin-version':Prints plug-in OCP version' + version':Shows the program version' + help':Display this help' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme solidigm options" _solidigm + ;; (help) local _h _h=( id-ctrl id-ns list-ns id-iocs create-ns delete-ns attach-ns detach-ns @@ -978,11 +2290,18 @@ _nvme () { set-feature format fw-activate fw-download admin-passthru io-passthru security-send security-recv resv-acquire resv-register resv-release resv-report flush compare read write copy show-regs persistent-event-log - pred-lat-event-agg-log nvm-id-ctrl endurance-event-agg-log lba-status-log - resv-notif-log capacity-mgmt id-domain boot-part-log fid-support-effects-log - supported-log-pages lockdown media-unit-stat-log id-ns-lba-format nvm-id-ns - nvm-id-ns-lba-format supported-cap-config-log - ) + pred-lat-event-agg-log nvm-id-ctrl endurance-event-agg-log lba-status-log + resv-notif-log capacity-mgmt id-domain boot-part-log fid-support-effects-log + supported-log-pages lockdown media-unit-stat-log id-ns-lba-format nvm-id-ns + nvm-id-ns-lba-format supported-cap-config-log show-topology + list list-subsys id-ns-granularity primary-ctrl-caps list-secondary ns-descs + id-nvmset id-uuid list-endgrp telemetry-log changed-ns-list-log ana-log + effects-log endurance-log device-self-test self-test-log set-property + get-property write-zeroes write-uncor verify sanitize sanitize-log reset + subsystem-reset ns-rescan get-lba-status dsm discover connect-all connect + dim disconnect disconnect-all gen-hostnqn show-hostnqn dir-receive dir-send + virt-mgmt rpmb version ocp solidigm + ) _arguments '*:: :->subcmds' _describe -t commands "help: infos on a specific nvme command, or provide no option to see a synopsis of all nvme commands" _h ;; diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh index e8177018aa..d862aab0ab 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -4,117 +4,12 @@ # (unfortunately, bash won't let me add descriptions to cmds) # Kelly Kaoudis kelly.n.kaoudis at intel.com, Aug. 2015 -# Constant to indicate command has no options -NO_OPTS="" -readonly NO_OPTS - -# Associative array of plugins and associated subcommands -# Order here is same as PLUGIN_OBJS in Makefile -typeset -Ar _plugin_subcmds=( - [intel]="id-ctrl internal-log lat-stats \ - set-bucket-thresholds lat-stats-tracking \ - market-name smart-log-add temp-stats" - [amzn]="id-ctrl" - [memblaze]="smart-log-add get-pm-status set-pm-status \ - select-download lat-stats lat-stats-print lat-log \ - lat-log-print clear-error-log" - [wdc]="cap-diag drive-log get-crash-dump get-pfail-dump \ - id-ctrl purge purge-monitor vs-internal-log \ - vs-nand-stats vs-smart-add-log clear-pcie-correctable-errors \ - drive-essentials get-drive-status clear-assert-dump \ - drive-resize vs-fw-activate-history clear-fw-activate-history \ - enc-get-log vs-telemetry-controller-option \ - vs-error-reason-identifier log-page-directory \ - namespace-resize vs-drive-info vs-temperature-stats \ - capabilities cloud-SSD-plugin-version vs-pcie-stats" - [huawei]="list id-ctrl" - [netapp]="smdevices ontapdevices" - [toshiba]="vs-smart-add-log vs-internal-log \ - clear-pcie-correctable-errors" - [micron]="select-download vs-temperature-stats vs-pcie-stats \ - clear-pcie-correctable-errors vs-internal-log \ - vs-telemetry-controller-option vs-nand-stats \ - vs-drive-info plugin-version cloud-SSD-plugin-version \ - log-page-directory vs-fw-activate-history \ - vs-error-reason-identifier vs-smart-add-log \ - clear-fw-activate-history vs-smbus-option" - [seagate]="vs-temperature-stats vs-log-page-sup \ - vs-smart-add-log vs-pcie-stats clear-pcie-correctable-errors \ - get-host-tele get-ctrl-tele vs-internal-log \ - plugin-version" - [virtium]="save-smart-to-vtview-log show-identify" - [shannon]="smart-log-add get-feature-add set-feature-add id-ctrl" - [dera]="smart-log-add" - [sfx]="smart-log-add lat-stats get-bad-block query-cap \ - change-cap set-feature get-feature" - [transcend]="healthvalue badblock" - [zns]="id-ctrl id-ns zone-mgmt-recv \ - zone-mgmt-send report-zones close-zone \ - finish-zone open-zone reset-zone offline-zone \ - set-zone-desc zone-append changed-zone-list" - [nvidia]="id-ctrl" - [ymtc]="smart-log-add" -) -readonly _plugin_subcmds - -# Associative array mapping plugins to coresponding option completions -typeset -Ar _plugin_funcs=( - [intel]="plugin_intel_opts" - [amzn]="plugin_amzn_opts" - [memblaze]="plugin_memblaze_opts" - [wdc]="plugin_wdc_opts" - [huawei]="plugin_huawei_opts" - [toshiba]="plugin_toshiba_opts" - [micron]="plugin_micron_opts" - [seagate]="plugin_seagate_opts" - [virtium]="plugin_virtium_opts" - [shannon]="plugin_shannon_opts" - [dera]="plugin_dera_opts" - [sfx]="pluginx_sfx_opts" - [transcend]="plugin_transcend_opts" - [zns]="plugin_zns_opts" - [nvidia]="plugin_nvidia_opts" - [ymtc]="plugin_ymtc_opts" -) -readonly _plugin_funcs - -# Top level commands -_cmds="list list-subsys id-ctrl id-ns \ - id-ns-granularity list-ns list-ctrl \ - id-ns-lba-format nvm-id-ns nvm-id-ns-lba-format \ - nvm-id-ctrl primary-ctrl-caps list-secondary \ - ns-descs id-nvmset id-uuid id-iocs create-ns \ - delete-ns get-ns-id get-log telemetry-log \ - fw-log changed-ns-list-log smart-log ana-log \ - error-log effects-log endurance-log \ - predictable-lat-log pred-lat-event-agg-log \ - persistent-event-log endurance-agg-log \ - lba-status-log resv-notif-log get-feature \ - device-self-test self-test-log set-feature \ - set-property get-property format fw-commit \ - fw-download admin-passthru io-passthru \ - security-send security-recv get-lba-status \ - resv-acquire resv-register resv-release \ - resv-report dsm copy flush compare read \ - write write-zeros write-uncor verify \ - sanitize sanitize-log reset subsystem-reset \ - ns-rescan show-regs discover connect-all \ - connect disconnect disconnect-all gen-hostnqn \ - show-hostnqn dir-receive dir-send virt-mgmt \ - rpmb boot-part-log fid-support-effects-log \ - supported-log-pages lockdown media-unit-stat-log \ - supported-cap-config-log dim" - -# Add plugins: -for plugin in "${!_plugin_subcmds[@]}"; do - _cmds+=" $plugin" -done - -cmds+=" version help" - nvme_list_opts () { - local opts="" + local opts="" local compargs="" + local vals="" + local opt="" + local val="" local nonopt_args=0 for (( i=0; i < ${#words[@]}-1; i++ )); do @@ -128,6 +23,19 @@ nvme_list_opts () { fi opts+=" " + vals+=" " + + if [[ $cur != -* ]] && [[ $cur != "" ]] && [[ $prev == "=" ]] && [[ ${words[$cword-2]} == --* ]]; then + opt+="${words[$cword-2]}" + val+="$cur" + elif [[ $cur == "" ]] && [[ $prev != "=" ]] || [[ $cur == "=" ]] && [[ $prev == --* ]]; then + opt+="$prev" + elif [[ $cur != "=" ]] && [[ $prev != --* ]] && [[ $prev != "=" ]]; then + opt+="$prev" + val+="$cur" + else + opt+="$cur" + fi # Listed here in the same order as in nvme-builtin.h case "$1" in @@ -139,11 +47,11 @@ nvme_list_opts () { ;; "id-ctrl") opts+=" --raw-binary -b --human-readable -H \ - --vendor-specific -v --output-format= -o" + --vendor-specific -V --output-format= -o" ;; "id-ns") opts+=" --namespace-id= -n --raw-binary -b \ - --human-readable -H --vendor-specific -v \ + --human-readable -H --vendor-specific -V \ --force -f --output-format= -o" ;; "id-ns-granularity") @@ -196,12 +104,17 @@ nvme_list_opts () { opts+=" --endgrp-id= -i --output-format= -o" ;; "id-iocs") - opts+=" --controller-id= -c --output-format= -o --human-readable -H" + opts+=" --controller-id= -c" + ;; + "id-domain") + opts+=" --domain-id= -c --output-format= -o" ;; "create-ns") opts+=" --nsze= -s --ncap= -c --flbas= -f \ - --dps= -d --nmic= -n --anagrp-id= -a --nvmset-id= -i \ - --block-size= -b --timeout= -t--csi= -y" + --dps= -d --nmic= -m --anagrp-id= -a --nvmset-id= -i \ + --block-size= -b --timeout= -t --csi= -y --lbstm= -l \ + --nphndls= -n --nsze-si= -S --ncap-si= -C --azr -z --rar= -r \ + --ror= -O --rnumzrwa= -u --phndls= -p --endg-id= -e" ;; "delete-ns") opts+=" -namespace-id= -n --timeout= -t" @@ -217,7 +130,7 @@ nvme_list_opts () { ;; "get-log") opts+=" --log-id= -i --log-len= -l --namespace-id= -n \ - --aen= -a --lpo= -o --lsp= -s --lsi= -S \ + --aen= -a --lpo= -O --lsp= -s --lsi= -S \ --rae -r --uuid-index= -U --csi= -y --ot -O \ --raw-binary -b" ;; @@ -225,7 +138,7 @@ nvme_list_opts () { opts+=" --output-format= -o --human-readable -H" ;; "telemetry-log") - opts+=" --output-file= -o --host-generate= -g \ + opts+=" --output-file= -O --host-generate= -g \ --controller-init -c --data-area= -d" ;; "fw-log") @@ -307,10 +220,10 @@ nvme_list_opts () { --cdw12= -c" ;; "set-property") - opts+=" --offset= -o --value= -v" + opts+=" --offset= -O --value= -V" ;; "get-property") - opts=+" --offset= -o --human-readable -H" + opts=+" --offset= -O --human-readable -H" ;; "format") opts+=" --namespace-id= -n --timeout= -t --lbaf= -l \ @@ -320,18 +233,17 @@ nvme_list_opts () { opts+=" --slot= -s --action= -a --bpid= -b" ;; "fw-download") - opts+=" --fw= -f --xfer= -x --offset= -o" + opts+=" --fw= -f --xfer= -x --offset= -O" ;; "capacity-mgmt") - opts+=" --operation= -f --element-id= -i --cap-lower= -l \ - --cap-upper= -u" + opts+=" --operation= -O --element-id= -i --cap-lower= -l \ + --cap-upper= -u" ;; "lockdown") - opts+=" --ofi= -O --ifc= -F --prhbt= -P \ - -scp= -S --uuid -U" + opts+=" --ofi= -O --ifc= -f --prhbt= -p --scp= -s --uuid -U" ;; "admin-passthru") - opts+=" --opcode= -o --flags= -f --prefil= -p --rsvd= -R \ + 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 \ @@ -340,7 +252,7 @@ nvme_list_opts () { --latency -T" ;; "io-passthru") - opts+=" --opcode= -o --flags= -f --prefill= -p --rsvd= -R \ + 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 \ @@ -399,7 +311,7 @@ nvme_list_opts () { --metadata= -M --prinfo= -p --app-tag-mask= -m \ --app-tag= -a --limited-retry -l \ --force-unit-access -f --storage-tag-check -C \ - --dir-type= -T --dir-spec= -S --dsm= -D --show-command -v \ + --dir-type= -T --dir-spec= -S --dsm= -D --show-command -V \ --dry-run -w --latency -t" ;; "read") @@ -408,7 +320,7 @@ nvme_list_opts () { --metadata= -M --prinfo= -p --app-tag-mask= -m \ --app-tag= -a --limited-retry -l \ --force-unit-access -f --storage-tag-check -C \ - --dir-type= -T --dir-spec= -S --dsm= -D --show-command -v \ + --dir-type= -T --dir-spec= -S --dsm= -D --show-command -V \ --dry-run -w --latency -t" ;; "write") @@ -417,19 +329,20 @@ nvme_list_opts () { --metadata= -M --prinfo= -p --app-tag-mask= -m \ --app-tag= -a --limited-retry -l \ --force-unit-access -f --storage-tag-check -C \ - --dir-type= -T --dir-spec= -S --dsm= -D --show-command -v \ + --dir-type= -T --dir-spec= -S --dsm= -D --show-command -V \ --dry-run -w --latency -t" ;; - "write-zeros") + "write-zeroes") opts+=" --namespace-id= -n --start-block= -s \ --block-count= -c --deac -d --limited-retry -l \ --force-unit-access -f --prinfo= -p --ref-tag= -r \ --app-tag-mask= -m --app-tag= -a \ - --storage-tag= -S --storage-tag-check -C" + --storage-tag= -S --storage-tag-check -C \ + --dir-type= -T --dir-spec= -S" ;; "write-uncor") opts+=" --namespace-id= -n --start-block= -s \ - --block-count= -c" + --block-count= -c --dir-type= -T --dir-spec= -S" ;; "verify") opts+=" --namespace-id= -n --start-block= -s \ @@ -441,6 +354,11 @@ nvme_list_opts () { "sanitize") opts+=" --no-dealloc -d --oipbp -i --owpass= -n \ --ause -u --sanact= -a --ovrpat= -p" + case $opt in + --sanact|-a) + vals+=" exit-failure start-block-erase start-overwrite start-crypto-erase" + ;; + esac ;; "sanitize-log") opts+=" --rae -r --output-format= -o --human-readable -H \ @@ -524,6 +442,17 @@ nvme_list_opts () { --key= -k --msg= -d --address= -o --blocks= -b \ --target= -t" ;; + "show-topology") + opts+=" --output-format= -o --verbose -v --ranking= -r" + ;; + "nvme-mi-recv") + opts+=" --opcode= -O --namespace-id= -n --data-len= -l \ + --nmimt= -m --nmd0= -0 --nmd1= -1 --input-file= -i" + ;; + "nvme-mi-send") + opts+=" --opcode= -O --namespace-id= -n --data-len= -l \ + --nmimt= -m --nmd0= -0 --nmd1= -1 --input-file= -i" + ;; "version") opts+=$NO_OPTS ;; @@ -532,9 +461,13 @@ nvme_list_opts () { ;; esac - opts+=" -h --help" + opts+=" -h --help -j --json" - COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + if [[ $vals == " " ]]; then + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + else + COMPREPLY+=( $( compgen $compargs -W "$vals" -- $val ) ) + fi return 0 } @@ -1057,7 +990,7 @@ plugin_shannon_opts () { --data-len= -l --raw-binary -b --cdw11= -c --human-readable -H" ;; "set-feature-add") - opts+=" --namespace-id= -n --feature-id= -f --value= -v \ + opts+=" --namespace-id= -n --feature-id= -f --value= -V \ --data-len= -l --data= -d --save -s" ;; "id-ctrl") @@ -1154,6 +1087,89 @@ plugin_sfx_opts () { return 0 } +plugin_solidigm_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o \ + --verbose -v " + ;; + "vs-smart-add-log") + opts+="--output-format= -o" + ;; + "garbage-collect-log") + opts+="--output-format= -o" + ;; + "vs-internal-log") + opts+=" --type= -t --namespace-id= -n \ + --file-prefix= -p --verbose -v" + ;; + "latency-tracking-log") + opts+=" --enable -e --disable -d \ + --read -r --write -w \ + --type -t --output-format -o" + ;; + "clear-pcie-correctable-errors") + opts+=" --no-uuid -n" + ;; + "parse-telemetry-log") + opts+=" --host-generate -g --controller-init -c \ + --data-area -d --config-file -j \ + --source-file -s" + ;; + "clear-fw-activate-history") + opts+=" --no-uuid -n" + ;; + "vs-fw-activate-history") + opts+=" --output-format -o" + ;; + "log-page-directory") + opts+=" --output-format -o" + ;; + "vs-drive-info") + opts+=" " + ;; + "cloud-SSDplugin-version") + opts+=$NO_OPTS + ;; + "market-log") + opts+=" --raw-binary -b" + ;; + "smart-log-add") + opts+=" --namespace-id= -n --output-format -o" + ;; + "temp-stats") + opts+=" --raw-binary -b" + ;; + "version") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + plugin_transcend_opts () { local opts="" local compargs="" @@ -1330,7 +1346,106 @@ plugin_ymtc_opts () { opts+=" --namespace-id= -n --raw-binary -b" ;; "help") - opts+=NO_OPTS + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_inspur_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "nvme-vendor-log") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_ocp_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "smart-add-log") + opts+=" --output-format= -o" + ;; + "latency-monitor-log") + opts+=" --output-format= -o" + ;; + "set-latency-monitor-feature") + opts+=" --active_bucket_timer_threshold= -t \ + --active_threshold_a= -a --active_threshold_b= -b \ + --active_threshold_c= -c --active_threshold_d= -d \ + --active_latency_config= -f \ + --active_latency_minimum_window= -w \ + --debug_log_trigger_enable -r --discard_debug_log= -l \ + --latency_monitor_feature_enable= -e" + ;; + "internal-log") + opts+=" --telemetry_type= -t --telemetry_data_area= -a \ + --output-file= -o" + ;; + "clear-fw-activate-history") + opts+=" --no-uuid -n" + ;; + "eol-plp-failure-mode") + opts+=" --mode= -m --save -s --sel= -S --no-uuid -n" + ;; + "clear-pcie-correctable-error-counters") + opts+=" --no-uuid -n" + ;; + "fw-activate-history") + opts+=" --output-format= -o" + ;; + "device-capability-log") + opts+=" --output-format= -o" + ;; + "set-dssd-power-state-feature") + opts+=" --power-state= -p --no-uuid -n --save -s" + ;; + "telemetry-string-log") + opts+=" --output-file= -o" + ;; + "help") + opts+=$NO_OPTS ;; esac @@ -1343,6 +1458,128 @@ _nvme_subcmds () { local cur prev words cword _init_completion || return + # Constant to indicate command has no options + NO_OPTS="" + + # Associative array of plugins and associated subcommands + # Order here is same as PLUGIN_OBJS in Makefile + typeset -Ar _plugin_subcmds=( + [intel]="id-ctrl internal-log lat-stats \ + set-bucket-thresholds lat-stats-tracking \ + market-name smart-log-add temp-stats" + [amzn]="id-ctrl" + [memblaze]="smart-log-add get-pm-status set-pm-status \ + select-download lat-stats lat-stats-print lat-log \ + lat-log-print clear-error-log" + [wdc]="cap-diag drive-log get-crash-dump get-pfail-dump \ + id-ctrl purge purge-monitor vs-internal-log \ + vs-nand-stats vs-smart-add-log clear-pcie-correctable-errors \ + drive-essentials get-drive-status clear-assert-dump \ + drive-resize vs-fw-activate-history clear-fw-activate-history \ + enc-get-log vs-telemetry-controller-option \ + vs-error-reason-identifier log-page-directory \ + namespace-resize vs-drive-info vs-temperature-stats \ + capabilities cloud-SSD-plugin-version vs-pcie-stats" + [huawei]="list id-ctrl" + [netapp]="smdevices ontapdevices" + [toshiba]="vs-smart-add-log vs-internal-log \ + clear-pcie-correctable-errors" + [micron]="select-download vs-temperature-stats vs-pcie-stats \ + clear-pcie-correctable-errors vs-internal-log \ + vs-telemetry-controller-option vs-nand-stats \ + vs-drive-info plugin-version cloud-SSD-plugin-version \ + log-page-directory vs-fw-activate-history \ + vs-error-reason-identifier vs-smart-add-log \ + clear-fw-activate-history vs-smbus-option" + [seagate]="vs-temperature-stats vs-log-page-sup \ + vs-smart-add-log vs-pcie-stats clear-pcie-correctable-errors \ + get-host-tele get-ctrl-tele vs-internal-log \ + plugin-version" + [virtium]="save-smart-to-vtview-log show-identify" + [shannon]="smart-log-add get-feature-add set-feature-add id-ctrl" + [dera]="smart-log-add" + [sfx]="smart-log-add lat-stats get-bad-block query-cap \ + change-cap set-feature get-feature" + [solidigm]="id-ctrl vs-smart-add-log garbage-collect-log \ + vs-internal-log latency-tracking-log \ + clear-pcie-correctable-errors parse-telemetry-log \ + clear-fw-activate-history vs-fw-activate-history log-page-directory \ + vs-drive-info cloud-SSDplugin-version market-log \ + smart-log-add temp-stats version help" + [transcend]="healthvalue badblock" + [zns]="id-ctrl id-ns zone-mgmt-recv \ + zone-mgmt-send report-zones close-zone \ + finish-zone open-zone reset-zone offline-zone \ + set-zone-desc zone-append changed-zone-list" + [nvidia]="id-ctrl" + [ymtc]="smart-log-add" + [inspur]="nvme-vendor-log" + [ocp]="smart-add-log latency-monitor-log \ + set-latency-monitor-feature internal-log \ + clear-fw-activate-history eol-plp-failure-mode \ + clear-pcie-correctable-error-counters \ + vs-fw-activate-history device-capability-log \ + set-dssd-power-state-feature telemetry-string-log" + ) + + # Associative array mapping plugins to corresponding option completions + typeset -Ar _plugin_funcs=( + [intel]="plugin_intel_opts" + [amzn]="plugin_amzn_opts" + [memblaze]="plugin_memblaze_opts" + [wdc]="plugin_wdc_opts" + [huawei]="plugin_huawei_opts" + [toshiba]="plugin_toshiba_opts" + [micron]="plugin_micron_opts" + [seagate]="plugin_seagate_opts" + [virtium]="plugin_virtium_opts" + [shannon]="plugin_shannon_opts" + [dera]="plugin_dera_opts" + [sfx]="plugin_sfx_opts" + [solidigm]="plugin_solidigm_opts" + [transcend]="plugin_transcend_opts" + [zns]="plugin_zns_opts" + [nvidia]="plugin_nvidia_opts" + [ymtc]="plugin_ymtc_opts" + [inspur]="plugin_inspur_opts" + [ocp]="plugin_ocp_opts" + ) + + # Top level commands + _cmds="list list-subsys id-ctrl id-ns \ + id-ns-granularity list-ns list-ctrl \ + id-ns-lba-format nvm-id-ns nvm-id-ns-lba-format \ + nvm-id-ctrl primary-ctrl-caps list-secondary \ + ns-descs id-nvmset id-uuid id-iocs id-domain create-ns \ + delete-ns get-ns-id get-log telemetry-log \ + fw-log changed-ns-list-log smart-log ana-log \ + error-log effects-log endurance-log \ + predictable-lat-log pred-lat-event-agg-log \ + persistent-event-log endurance-agg-log \ + lba-status-log resv-notif-log get-feature \ + device-self-test self-test-log set-feature \ + set-property get-property format fw-commit \ + fw-download admin-passthru io-passthru \ + security-send security-recv get-lba-status \ + resv-acquire resv-register resv-release \ + resv-report dsm copy flush compare read \ + write write-zeros write-uncor verify \ + sanitize sanitize-log reset subsystem-reset \ + ns-rescan show-regs discover connect-all \ + connect disconnect disconnect-all gen-hostnqn \ + show-hostnqn dir-receive dir-send virt-mgmt \ + rpmb boot-part-log fid-support-effects-log \ + supported-log-pages lockdown media-unit-stat-log \ + supported-cap-config-log dim show-topology list-endgrp \ + nvme-mi-recv nvme-mi-send" + + # Add plugins: + for plugin in "${!_plugin_subcmds[@]}"; do + _cmds+=" $plugin" + done + + _cmds+=" version help" + if [[ ${#words[*]} -lt 3 ]]; then COMPREPLY+=( $(compgen -W "$_cmds" -- $cur ) ) else diff --git a/fabrics.c b/fabrics.c index 43ca5f422d..6273c7814e 100644 --- a/fabrics.c +++ b/fabrics.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Intel Corporation. All rights reserved. * Copyright (c) 2016 HGST, a Western Digital Company. @@ -38,13 +38,18 @@ #include #include +#include + #include "common.h" #include "nvme.h" -#include "libnvme.h" +#include "nbft.h" #include "nvme-print.h" +#include "fabrics.h" +#include "util/logging.h" #define PATH_NVMF_DISC SYSCONFDIR "/nvme/discovery.conf" #define PATH_NVMF_CONFIG SYSCONFDIR "/nvme/config.json" +#define PATH_NVMF_RUNDIR RUNDIR "/nvme" #define MAX_DISC_ARGS 32 #define MAX_DISC_RETRIES 10 @@ -74,54 +79,74 @@ static const char *nvmf_keep_alive_tmo = "keep alive timeout period in seconds"; static const char *nvmf_reconnect_delay = "reconnect timeout period in seconds"; static const char *nvmf_ctrl_loss_tmo = "controller loss timeout period in seconds"; static const char *nvmf_tos = "type of service"; +static const char *nvmf_keyring = "Keyring for TLS key lookup"; +static const char *nvmf_tls_key = "TLS key to use"; static const char *nvmf_dup_connect = "allow duplicate connections between same transport host and subsystem port"; static const char *nvmf_disable_sqflow = "disable controller sq flow control (default false)"; static const char *nvmf_hdr_digest = "enable transport protocol header digest (TCP transport)"; static const char *nvmf_data_digest = "enable transport protocol data digest (TCP transport)"; +static const char *nvmf_tls = "enable TLS"; +static const char *nvmf_concat = "enable secure concatenation"; static const char *nvmf_config_file = "Use specified JSON configuration file or 'none' to disable"; +static const char *nvmf_context = "execution context identification string"; + +#define NVMF_ARGS(n, c, ...) \ + struct argconfig_commandline_options n[] = { \ + OPT_STRING("transport", 't', "STR", &transport, nvmf_tport), \ + OPT_STRING("nqn", 'n', "STR", &subsysnqn, nvmf_nqn), \ + OPT_STRING("traddr", 'a', "STR", &traddr, nvmf_traddr), \ + OPT_STRING("trsvcid", 's', "STR", &trsvcid, nvmf_trsvcid), \ + OPT_STRING("host-traddr", 'w', "STR", &c.host_traddr, nvmf_htraddr), \ + OPT_STRING("host-iface", 'f', "STR", &c.host_iface, nvmf_hiface), \ + OPT_STRING("hostnqn", 'q', "STR", &hostnqn, nvmf_hostnqn), \ + OPT_STRING("hostid", 'I', "STR", &hostid, nvmf_hostid), \ + OPT_STRING("dhchap-secret", 'S', "STR", &hostkey, nvmf_hostkey), \ + OPT_INT("nr-io-queues", 'i', &c.nr_io_queues, nvmf_nr_io_queues), \ + OPT_INT("nr-write-queues", 'W', &c.nr_write_queues, nvmf_nr_write_queues), \ + OPT_INT("nr-poll-queues", 'P', &c.nr_poll_queues, nvmf_nr_poll_queues), \ + OPT_INT("queue-size", 'Q', &c.queue_size, nvmf_queue_size), \ + OPT_INT("keep-alive-tmo", 'k', &c.keep_alive_tmo, nvmf_keep_alive_tmo), \ + OPT_INT("reconnect-delay", 'c', &c.reconnect_delay, nvmf_reconnect_delay), \ + OPT_INT("ctrl-loss-tmo", 'l', &c.ctrl_loss_tmo, nvmf_ctrl_loss_tmo), \ + OPT_INT("tos", 'T', &c.tos, nvmf_tos), \ + OPT_INT("keyring", 0, &c.keyring, nvmf_keyring), \ + OPT_INT("tls_key", 0, &c.tls_key, nvmf_tls_key), \ + OPT_FLAG("duplicate-connect", 'D', &c.duplicate_connect, nvmf_dup_connect), \ + OPT_FLAG("disable-sqflow", 'd', &c.disable_sqflow, nvmf_disable_sqflow), \ + OPT_FLAG("hdr-digest", 'g', &c.hdr_digest, nvmf_hdr_digest), \ + OPT_FLAG("data-digest", 'G', &c.data_digest, nvmf_data_digest), \ + OPT_FLAG("tls", 0, &c.tls, nvmf_tls), \ + OPT_FLAG("concat", 0, &c.concat, nvmf_concat), \ + __VA_ARGS__, \ + OPT_END() \ + } -#define NVMF_OPTS(c) \ - OPT_STRING("transport", 't', "STR", &transport, nvmf_tport), \ - OPT_STRING("traddr", 'a', "STR", &traddr, nvmf_traddr), \ - OPT_STRING("trsvcid", 's', "STR", &trsvcid, nvmf_trsvcid), \ - OPT_STRING("host-traddr", 'w', "STR", &c.host_traddr, nvmf_htraddr), \ - OPT_STRING("host-iface", 'f', "STR", &c.host_iface, nvmf_hiface), \ - OPT_STRING("hostnqn", 'q', "STR", &hostnqn, nvmf_hostnqn), \ - OPT_STRING("hostid", 'I', "STR", &hostid, nvmf_hostid), \ - OPT_STRING("nqn", 'n', "STR", &subsysnqn, nvmf_nqn), \ - OPT_STRING("dhchap-secret", 'S', "STR", &hostkey, nvmf_hostkey), \ - OPT_INT("nr-io-queues", 'i', &c.nr_io_queues, nvmf_nr_io_queues), \ - OPT_INT("nr-write-queues", 'W', &c.nr_write_queues, nvmf_nr_write_queues),\ - OPT_INT("nr-poll-queues", 'P', &c.nr_poll_queues, nvmf_nr_poll_queues), \ - OPT_INT("queue-size", 'Q', &c.queue_size, nvmf_queue_size), \ - OPT_INT("keep-alive-tmo", 'k', &c.keep_alive_tmo, nvmf_keep_alive_tmo), \ - OPT_INT("reconnect-delay", 'c', &c.reconnect_delay, nvmf_reconnect_delay),\ - OPT_INT("ctrl-loss-tmo", 'l', &c.ctrl_loss_tmo, nvmf_ctrl_loss_tmo), \ - OPT_INT("tos", 'T', &c.tos, nvmf_tos), \ - OPT_FLAG("duplicate-connect", 'D', &c.duplicate_connect, nvmf_dup_connect), \ - OPT_FLAG("disable-sqflow", 'd', &c.disable_sqflow, nvmf_disable_sqflow), \ - OPT_FLAG("hdr-digest", 'g', &c.hdr_digest, nvmf_hdr_digest), \ - OPT_FLAG("data-digest", 'G', &c.data_digest, nvmf_data_digest) \ - -struct tr_config { - char *subsysnqn; - char *transport; - char *traddr; - char *host_traddr; - char *host_iface; - char *trsvcid; -}; - -static void space_strip_len(int max, char *str) +static bool is_persistent_discovery_ctrl(nvme_host_t h, nvme_ctrl_t c) { - int i; + if (nvme_host_is_pdc_enabled(h, DEFAULT_PDC_ENABLED)) + return nvme_ctrl_is_unique_discovery_ctrl(c); + + return false; +} + +nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg) +{ + nvme_subsystem_t s; + nvme_ctrl_t c; - for (i = max - 1; i >= 0; i--) { - if (str[i] != '\0' && str[i] != ' ') - return; - else - str[i] = '\0'; + nvme_for_each_subsystem(h, s) { + c = nvme_ctrl_find(s, + trcfg->transport, + trcfg->traddr, + trcfg->trsvcid, + trcfg->subsysnqn, + trcfg->host_traddr, + trcfg->host_iface); + if (c) + return c; } + + return NULL; } static int set_discovery_kato(struct nvme_fabrics_config *cfg) @@ -152,6 +177,8 @@ static nvme_ctrl_t __create_discover_ctrl(nvme_root_t r, nvme_host_t h, return NULL; nvme_ctrl_set_discovery_ctrl(c, true); + nvme_ctrl_set_unique_discovery_ctrl(c, + strcmp(trcfg->subsysnqn, NVME_DISC_SUBSYS_NAME)); tmo = set_discovery_kato(cfg); errno = 0; @@ -159,7 +186,6 @@ static nvme_ctrl_t __create_discover_ctrl(nvme_root_t r, nvme_host_t h, cfg->keep_alive_tmo = tmo; if (ret) { - errno = ret; nvme_free_ctrl(c); return NULL; } @@ -177,11 +203,12 @@ static nvme_ctrl_t create_discover_ctrl(nvme_root_t r, nvme_host_t h, if (!c) return NULL; - if (!persistent) + if (nvme_ctrl_is_unique_discovery_ctrl(c)) return c; /* Find out the name of discovery controller */ struct nvme_id_ctrl id = { 0 }; + if (nvme_ctrl_identify(c, &id)) { fprintf(stderr, "failed to identify controller, error %s\n", nvme_strerror(errno)); @@ -204,123 +231,19 @@ static nvme_ctrl_t create_discover_ctrl(nvme_root_t r, nvme_host_t h, return __create_discover_ctrl(r, h, cfg, trcfg); } -static void print_discovery_log(struct nvmf_discovery_log *log, int numrec) -{ - int i; - - printf("\nDiscovery Log Number of Records %d, " - "Generation counter %"PRIu64"\n", - numrec, le64_to_cpu(log->genctr)); - - for (i = 0; i < numrec; i++) { - struct nvmf_disc_log_entry *e = &log->entries[i]; - - space_strip_len(NVMF_TRSVCID_SIZE, e->trsvcid); - space_strip_len(NVMF_TRADDR_SIZE, e->traddr); - - printf("=====Discovery Log Entry %d======\n", i); - printf("trtype: %s\n", nvmf_trtype_str(e->trtype)); - printf("adrfam: %s\n", - strlen(e->traddr) ? - nvmf_adrfam_str(e->adrfam): ""); - printf("subtype: %s\n", nvmf_subtype_str(e->subtype)); - printf("treq: %s\n", nvmf_treq_str(e->treq)); - printf("portid: %d\n", e->portid); - printf("trsvcid: %s\n", e->trsvcid); - printf("subnqn: %s\n", e->subnqn); - printf("traddr: %s\n", e->traddr); - printf("eflags: %s\n", nvmf_eflags_str(e->eflags)); - - switch (e->trtype) { - case NVMF_TRTYPE_RDMA: - printf("rdma_prtype: %s\n", - nvmf_prtype_str(e->tsas.rdma.prtype)); - printf("rdma_qptype: %s\n", - nvmf_qptype_str(e->tsas.rdma.qptype)); - printf("rdma_cms: %s\n", - nvmf_cms_str(e->tsas.rdma.cms)); - printf("rdma_pkey: 0x%04x\n", - le16_to_cpu(e->tsas.rdma.pkey)); - break; - case NVMF_TRTYPE_TCP: - printf("sectype: %s\n", - nvmf_sectype_str(e->tsas.tcp.sectype)); - break; - } - } -} - -static void json_discovery_log(struct nvmf_discovery_log *log, int numrec) -{ - struct json_object *root; - struct json_object *entries; - int i; - - root = json_create_object(); - entries = json_create_array(); - json_object_add_value_uint64(root, "genctr", le64_to_cpu(log->genctr)); - json_object_add_value_array(root, "records", entries); - - for (i = 0; i < numrec; i++) { - struct nvmf_disc_log_entry *e = &log->entries[i]; - struct json_object *entry = json_create_object(); - - nvme_strip_spaces(e->trsvcid, NVMF_TRSVCID_SIZE); - nvme_strip_spaces(e->subnqn, NVMF_NQN_SIZE); - nvme_strip_spaces(e->traddr, NVMF_TRADDR_SIZE); - - json_object_add_value_string(entry, "trtype", - nvmf_trtype_str(e->trtype)); - json_object_add_value_string(entry, "adrfam", - nvmf_adrfam_str(e->adrfam)); - json_object_add_value_string(entry, "subtype", - nvmf_subtype_str(e->subtype)); - json_object_add_value_string(entry,"treq", - nvmf_treq_str(e->treq)); - json_object_add_value_uint(entry, "portid", - le16_to_cpu(e->portid)); - json_object_add_value_string(entry, "trsvcid", e->trsvcid); - json_object_add_value_string(entry, "subnqn", e->subnqn); - json_object_add_value_string(entry, "traddr", e->traddr); - json_object_add_value_uint(entry, "eflags", e->eflags); - - switch (e->trtype) { - case NVMF_TRTYPE_RDMA: - json_object_add_value_string(entry, "rdma_prtype", - nvmf_prtype_str(e->tsas.rdma.prtype)); - json_object_add_value_string(entry, "rdma_qptype", - nvmf_qptype_str(e->tsas.rdma.qptype)); - json_object_add_value_string(entry, "rdma_cms", - nvmf_cms_str(e->tsas.rdma.cms)); - json_object_add_value_uint(entry, "rdma_pkey", - le16_to_cpu(e->tsas.rdma.pkey)); - break; - case NVMF_TRTYPE_TCP: - json_object_add_value_string(entry, "sectype", - nvmf_sectype_str(e->tsas.tcp.sectype)); - break; - } - json_array_add_value_object(entries, entry); - } - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) { uint64_t numrec = le64_to_cpu(log->numrec); int fd, len, ret; - fd = open(raw, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); + fd = open(raw, O_CREAT | O_RDWR | O_TRUNC, 0600); if (fd < 0) { - fprintf(stderr, "failed to open %s: %s\n", - raw, strerror(errno)); + fprintf(stderr, "failed to open %s: %s\n", raw, strerror(errno)); return; } - len = sizeof(struct nvmf_discovery_log) + - numrec * sizeof(struct nvmf_disc_log_entry); + len = sizeof(struct nvmf_discovery_log) + numrec * sizeof(struct nvmf_disc_log_entry); + ret = write(fd, log, len); if (ret < 0) fprintf(stderr, "failed to write to %s: %s\n", @@ -331,23 +254,6 @@ static void save_discovery_log(char *raw, struct nvmf_discovery_log *log) close(fd); } -static void print_connect_msg(nvme_ctrl_t c) -{ - printf("device: %s\n", nvme_ctrl_get_name(c)); -} - -static void json_connect_msg(nvme_ctrl_t c) -{ - struct json_object *root; - - root = json_create_object(); - json_object_add_value_string(root, "device", nvme_ctrl_get_name(c)); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg, char *raw, bool connect, bool persistent, enum nvme_print_flags flags) @@ -356,42 +262,87 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg, nvme_subsystem_t s = nvme_ctrl_get_subsystem(c); nvme_host_t h = nvme_subsystem_get_host(s); uint64_t numrec; - int err; - - err = nvmf_get_discovery_log(c, &log, MAX_DISC_RETRIES); - if (err) { - if (err > 0) - nvme_show_status(err); - else - fprintf(stderr, "failed to get discovery log: %s\n", - nvme_strerror(errno)); - return err; - } + struct nvme_get_discovery_args args = { + .c = c, + .args_size = sizeof(args), + .max_retries = MAX_DISC_RETRIES, + .result = 0, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lsp = 0, + }; + + log = nvmf_get_discovery_wargs(&args); + if (!log) { + fprintf(stderr, "failed to get discovery log: %s\n", + nvme_strerror(errno)); + return -errno; + } numrec = le64_to_cpu(log->numrec); if (raw) save_discovery_log(raw, log); else if (!connect) { - if (flags == JSON) - json_discovery_log(log, numrec); - else - print_discovery_log(log, numrec); + nvme_show_discovery_log(log, numrec, flags); } else if (connect) { int i; for (i = 0; i < numrec; i++) { struct nvmf_disc_log_entry *e = &log->entries[i]; + nvme_ctrl_t cl; bool discover = false; + bool disconnect; nvme_ctrl_t child; int tmo = defcfg->keep_alive_tmo; + struct tr_config trcfg = { + .subsysnqn = e->subnqn, + .transport = nvmf_trtype_str(e->trtype), + .traddr = e->traddr, + .host_traddr = defcfg->host_traddr, + .host_iface = defcfg->host_iface, + .trsvcid = e->trsvcid, + }; + + /* Already connected ? */ + cl = lookup_ctrl(h, &trcfg); + if (cl && nvme_ctrl_get_name(cl)) + continue; + /* Skip connect if the transport types don't match */ - if (strcmp(nvme_ctrl_get_transport(c), nvmf_trtype_str(e->trtype))) + if (strcmp(nvme_ctrl_get_transport(c), + nvmf_trtype_str(e->trtype))) continue; - if (e->subtype == NVME_NQN_DISC) + if (e->subtype == NVME_NQN_DISC || + e->subtype == NVME_NQN_CURR) { + __u16 eflags = le16_to_cpu(e->eflags); + /* + * Does this discovery controller return the + * same information? + */ + if (eflags & NVMF_DISC_EFLAGS_DUPRETINFO) + continue; + + /* Are we supposed to keep the discovery controller around? */ + disconnect = !persistent; + + if (strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)) { + /* + * Does this discovery controller doesn't + * support explicit persistent connection? + */ + if (!(eflags & NVMF_DISC_EFLAGS_EPCSD)) + disconnect = true; + else + disconnect = false; + } + set_discovery_kato(defcfg); + } else { + /* NVME_NQN_NVME */ + disconnect = false; + } errno = 0; child = nvmf_connect_disc_entry(h, e, defcfg, @@ -403,15 +354,14 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg, if (discover) __discover(child, defcfg, raw, true, persistent, flags); - if (e->subtype != NVME_NQN_NVME && - !persistent) { + + if (disconnect) { nvme_disconnect_ctrl(child); nvme_free_ctrl(child); } } else if (errno == ENVME_CONNECT_ALREADY && !quiet) { char *traddr = log->entries[i].traddr; - space_strip_len(NVMF_TRADDR_SIZE, traddr); fprintf(stderr, "traddr=%s is already connected\n", traddr); @@ -423,75 +373,17 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg, return 0; } -/* - * Compare two C strings and handle NULL pointers gracefully. - * If either of the two strings is NULL, return 0 - * to let caller ignore the compare. - */ -static inline int strcmp0(const char *s1, const char *s2) -{ - if (!s1 || !s2) - return 0; - return strcmp(s1, s2); -} - -/* - * Compare two C strings and handle NULL pointers gracefully. - * If either of the two strings is NULL, return 0 - * to let caller ignore the compare. - */ -static inline int strcasecmp0(const char *s1, const char *s2) -{ - if (!s1 || !s2) - return 0; - return strcasecmp(s1, s2); -} - -static bool ctrl_config_match(nvme_ctrl_t c, struct tr_config *trcfg) -{ - if (!strcmp0(nvme_ctrl_get_transport(c), trcfg->transport) && - !strcasecmp0(nvme_ctrl_get_traddr(c), trcfg->traddr) && - !strcmp0(nvme_ctrl_get_trsvcid(c), trcfg->trsvcid) && - !strcmp0(nvme_ctrl_get_host_traddr(c), trcfg->host_traddr) && - !strcmp0(nvme_ctrl_get_host_iface(c), trcfg->host_iface)) - return true; - - return false; -} - -static nvme_ctrl_t lookup_discover_ctrl(nvme_root_t r, struct tr_config *trcfg) -{ - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ctrl(s, c) { - if (!nvme_ctrl_is_discovery_ctrl(c)) - continue; - if (ctrl_config_match(c, trcfg)) - return c; - } - } - } - - return NULL; -} - static char *get_default_trsvcid(const char *transport, - bool discovery_ctrl) + bool discovery_ctrl) { if (!transport) return NULL; if (!strcmp(transport, "tcp")) { - if (discovery_ctrl) { + if (discovery_ctrl) /* Default port for NVMe/TCP discovery controllers */ return stringify(NVME_DISC_IP_PORT); - } else { - /* Default port for NVMe/TCP io controllers */ - return stringify(NVME_RDMA_IP_PORT); - } + /* Default port for NVMe/TCP io controllers */ + return stringify(NVME_RDMA_IP_PORT); } else if (!strcmp(transport, "rdma")) { /* Default port for NVMe/RDMA controllers */ return stringify(NVME_RDMA_IP_PORT); @@ -516,22 +408,21 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h, struct nvme_fabrics_config cfg; bool force = false; - OPT_ARGS(opts) = { - NVMF_OPTS(cfg), - OPT_FMT("output-format", 'o', &format, output_format), - OPT_FILE("raw", 'r', &raw, "save raw output to file"), - OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), - OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), - OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), - OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation"), - OPT_END() - }; + NVMF_ARGS(opts, cfg, + OPT_FMT("output-format", 'o', &format, output_format), + OPT_FILE("raw", 'r', &raw, "save raw output to file"), + OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), + OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), + OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), + OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation")); nvmf_default_config(&cfg); - ret = flags = validate_output_format(format); - if (ret < 0) + ret = validate_output_format(format, &flags); + if (ret < 0) { + nvme_show_error("Invalid output format"); return ret; + } f = fopen(PATH_NVMF_DISC, "r"); if (f == NULL) { @@ -581,7 +472,7 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h, }; if (!force) { - c = lookup_discover_ctrl(r, &trcfg); + c = lookup_ctrl(h, &trcfg); if (c) { __discover(c, &cfg, raw, connect, true, flags); @@ -594,7 +485,7 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h, goto next; __discover(c, &cfg, raw, connect, persistent, flags); - if (!persistent) + if (!(persistent || is_persistent_discovery_ctrl(h, c))) ret = nvme_disconnect_ctrl(c); nvme_free_ctrl(c); @@ -607,13 +498,180 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h, return ret; } +static int discover_from_json_config_file(nvme_root_t r, nvme_host_t h, + const char *desc, bool connect, + const struct nvme_fabrics_config *defcfg, + enum nvme_print_flags flags, + bool force) +{ + const char *transport, *traddr, *host_traddr, *host_iface, *trsvcid, *subsysnqn; + nvme_subsystem_t s; + nvme_ctrl_t c, cn; + struct nvme_fabrics_config cfg; + int ret = 0; + + nvme_for_each_subsystem(h, s) { + nvme_subsystem_for_each_ctrl(s, c) { + transport = nvme_ctrl_get_transport(c); + traddr = nvme_ctrl_get_traddr(c); + host_traddr = nvme_ctrl_get_host_traddr(c); + host_iface = nvme_ctrl_get_host_iface(c); + + if (!transport && !traddr) + continue; + + /* ignore none fabric transports */ + if (strcmp(transport, "tcp") && + strcmp(transport, "rdma") && + strcmp(transport, "fc")) + continue; + + /* ignore if no host_traddr for fc */ + if (!strcmp(transport, "fc")) { + if (!host_traddr) { + fprintf(stderr, "host_traddr required for fc\n"); + continue; + } + } + + /* ignore if host_iface set for any transport other than tcp */ + if (!strcmp(transport, "rdma") || !strcmp(transport, "fc")) { + if (host_iface) { + fprintf(stderr, "host_iface not permitted for rdma or fc\n"); + continue; + } + } + + trsvcid = nvme_ctrl_get_trsvcid(c); + if (!trsvcid || !strcmp(trsvcid, "")) + trsvcid = get_default_trsvcid(transport, true); + + if (force) + subsysnqn = nvme_ctrl_get_subsysnqn(c); + else + subsysnqn = NVME_DISC_SUBSYS_NAME; + + if (nvme_ctrl_is_persistent(c)) + persistent = true; + + memcpy(&cfg, defcfg, sizeof(cfg)); + + struct tr_config trcfg = { + .subsysnqn = subsysnqn, + .transport = transport, + .traddr = traddr, + .host_traddr = host_traddr, + .host_iface = host_iface, + .trsvcid = trsvcid, + }; + + if (!force) { + cn = lookup_ctrl(h, &trcfg); + if (cn) { + __discover(cn, &cfg, raw, connect, + true, flags); + continue; + } + } + + cn = create_discover_ctrl(r, h, &cfg, &trcfg); + if (!cn) + continue; + + __discover(cn, &cfg, raw, connect, persistent, flags); + if (!(persistent || is_persistent_discovery_ctrl(h, cn))) + ret = nvme_disconnect_ctrl(cn); + nvme_free_ctrl(cn); + } + } + + return ret; +} + +static int nvme_read_volatile_config(nvme_root_t r) +{ + char *filename, *ext; + struct dirent *dir; + DIR *d; + int ret = -ENOENT; + + d = opendir(PATH_NVMF_RUNDIR); + if (!d) + return -ENOTDIR; + + while ((dir = readdir(d))) { + if (dir->d_type != DT_REG) + continue; + + ext = strchr(dir->d_name, '.'); + if (!ext || strcmp("json", ext + 1)) + continue; + + if (asprintf(&filename, "%s/%s", PATH_NVMF_RUNDIR, dir->d_name) < 0) { + ret = -ENOMEM; + break; + } + + if (nvme_read_config(r, filename)) + ret = 0; + + free(filename); + } + closedir(d); + + return ret; +} + +char *nvmf_hostid_from_hostnqn(const char *hostnqn) +{ + const char *uuid; + + if (!hostnqn) + return NULL; + + uuid = strstr(hostnqn, "uuid:"); + if (!uuid) + return NULL; + + return strdup(uuid + strlen("uuid:")); +} + +void nvmf_check_hostid_and_hostnqn(const char *hostid, const char *hostnqn, unsigned int verbose) +{ + char *hostid_from_file, *hostid_from_hostnqn; + + if (!hostid) + return; + + hostid_from_file = nvmf_hostid_from_file(); + if (hostid_from_file && strcmp(hostid_from_file, hostid)) { + if (verbose) + fprintf(stderr, + "warning: use generated hostid instead of hostid file\n"); + free(hostid_from_file); + } + + if (!hostnqn) + return; + + hostid_from_hostnqn = nvmf_hostid_from_hostnqn(hostnqn); + if (hostid_from_hostnqn && strcmp(hostid_from_hostnqn, hostid)) { + if (verbose) + fprintf(stderr, + "warning: use hostid which does not match uuid in hostnqn\n"); + free(hostid_from_hostnqn); + } +} + int nvmf_discover(const char *desc, int argc, char **argv, bool connect) { char *subsysnqn = NVME_DISC_SUBSYS_NAME; char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL; + char *hostnqn_arg, *hostid_arg; char *transport = NULL, *traddr = NULL, *trsvcid = NULL; char *config_file = PATH_NVMF_CONFIG; char *hnqn = NULL, *hid = NULL; + char *context = NULL; enum nvme_print_flags flags; nvme_root_t r; nvme_host_t h; @@ -624,20 +682,24 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) struct nvme_fabrics_config cfg; char *device = NULL; bool force = false; - - OPT_ARGS(opts) = { - OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"), - NVMF_OPTS(cfg), - OPT_FMT("output-format", 'o', &format, output_format), - OPT_FILE("raw", 'r', &raw, "save raw output to file"), - OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), - OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), - OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), - OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), - OPT_FLAG("dump-config", 'O', &dump_config, "Dump configuration file to stdout"), - OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation"), - OPT_END() - }; + bool json_config = false; + bool nbft = false, nonbft = false; + char *nbft_path = NBFT_SYSFS_PATH; + + NVMF_ARGS(opts, cfg, + OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"), + OPT_FMT("output-format", 'o', &format, output_format), + OPT_FILE("raw", 'r', &raw, "save raw output to file"), + OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"), + OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), + OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), + OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), + OPT_FLAG("dump-config", 'O', &dump_config, "Dump configuration file to stdout"), + OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation"), + OPT_FLAG("nbft", 0, &nbft, "Only look at NBFT tables"), + OPT_FLAG("no-nbft", 0, &nonbft, "Do not look at NBFT tables"), + OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"), + OPT_STRING("context", 0, "STR", &context, nvmf_context)); nvmf_default_config(&cfg); @@ -645,19 +707,25 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) if (ret) return ret; - ret = flags = validate_output_format(format); - if (ret < 0) + ret = validate_output_format(format, &flags); + if (ret < 0) { + nvme_show_error("Invalid output format"); return ret; + } if (!strcmp(config_file, "none")) config_file = NULL; - r = nvme_create_root(stderr, map_log_level(verbose, quiet)); + log_level = map_log_level(verbose, quiet); + + r = nvme_create_root(stderr, log_level); if (!r) { fprintf(stderr, "Failed to create topology root: %s\n", nvme_strerror(errno)); return -errno; } + if (context) + nvme_root_set_application(r, context); ret = nvme_scan_topology(r, NULL, NULL); if (ret < 0) { fprintf(stderr, "Failed to scan topology: %s\n", @@ -665,14 +733,25 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) nvme_free_tree(r); return ret; } - nvme_read_config(r, config_file); + if (!nvme_read_config(r, config_file)) + json_config = true; + if (!nvme_read_volatile_config(r)) + json_config = true; + + hostnqn_arg = hostnqn; + hostid_arg = hostid; if (!hostnqn) hostnqn = hnqn = nvmf_hostnqn_from_file(); - if (!hostnqn) + if (!hostnqn) { hostnqn = hnqn = nvmf_hostnqn_generate(); + hostid = hid = nvmf_hostid_from_hostnqn(hostnqn); + } if (!hostid) hostid = hid = nvmf_hostid_from_file(); + if (!hostid && hostnqn) + hostid = hid = nvmf_hostid_from_hostnqn(hostnqn); + nvmf_check_hostid_and_hostnqn(hostid, hostnqn, verbose); h = nvme_lookup_host(r, hostnqn, hostid); if (!h) { ret = ENOMEM; @@ -688,6 +767,21 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) nvme_host_set_dhchap_key(h, hostkey); if (!device && !transport && !traddr) { + if (!nonbft) + discover_from_nbft(r, hostnqn_arg, hostid_arg, + hostnqn, hostid, desc, connect, + &cfg, nbft_path, flags, verbose); + + if (nbft) + goto out_free; + + if (json_config) + ret = discover_from_json_config_file(r, h, desc, + connect, &cfg, + flags, force); + if (ret || access(PATH_NVMF_DISC, F_OK)) + goto out_free; + ret = discover_from_conf_file(r, h, desc, connect, &cfg); goto out_free; } @@ -708,17 +802,16 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) c = nvme_scan_ctrl(r, device); if (c) { /* Check if device matches command-line options */ - if (!ctrl_config_match(c, &trcfg)) { + if (!nvme_ctrl_config_match(c, transport, traddr, trsvcid, subsysnqn, + cfg.host_traddr, cfg.host_iface)) { fprintf(stderr, - "ctrl device %s found, ignoring " - "non matching command-line options\n", - device); + "ctrl device %s found, ignoring non matching command-line options\n", + device); } if (!nvme_ctrl_is_discovery_ctrl(c)) { fprintf(stderr, - "ctrl device %s found, ignoring " - "non discovery controller\n", + "ctrl device %s found, ignoring non discovery controller\n", device); nvme_free_ctrl(c); @@ -731,6 +824,20 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) * on exit. */ persistent = true; + /* + * When --host-traddr/--host-iface are not specified on the + * command line, use the discovery controller's (c) host- + * traddr/host-iface for the connections to controllers + * returned in the Discovery Log Pages. This is essential + * when invoking "connect-all" with --device to reuse an + * existing persistent discovery controller (as is done + * for the udev rules). This ensures that host-traddr/ + * host-iface are consistent with the discovery controller (c). + */ + if (!cfg.host_traddr) + cfg.host_traddr = (char *)nvme_ctrl_get_host_traddr(c); + if (!cfg.host_iface) + cfg.host_iface = (char *)nvme_ctrl_get_host_iface(c); } } else { /* @@ -744,25 +851,25 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) } } if (!c && !force) { - c = lookup_discover_ctrl(r, &trcfg); + c = lookup_ctrl(h, &trcfg); if (c) persistent = true; } if (!c) { /* No device or non-matching device, create a new controller */ c = create_discover_ctrl(r, h, &cfg, &trcfg); - if (!c) { - fprintf(stderr, - "failed to add controller, error %s\n", - nvme_strerror(errno)); + if (!c) { + if (errno != ENVME_CONNECT_IGNORED) + fprintf(stderr, + "failed to add controller, error %s\n", + nvme_strerror(errno)); ret = errno; goto out_free; } } - ret = __discover(c, &cfg, raw, connect, - persistent, flags); - if (!persistent) + ret = __discover(c, &cfg, raw, connect, persistent, flags); + if (!(persistent || is_persistent_discovery_ctrl(h, c))) nvme_disconnect_ctrl(c); nvme_free_ctrl(c); @@ -784,24 +891,24 @@ int nvmf_connect(const char *desc, int argc, char **argv) char *hostkey = NULL, *ctrlkey = NULL; char *hnqn = NULL, *hid = NULL; char *config_file = PATH_NVMF_CONFIG; + char *context = NULL; unsigned int verbose = 0; nvme_root_t r; nvme_host_t h; nvme_ctrl_t c; int ret; - struct nvme_fabrics_config cfg; - enum nvme_print_flags flags = -1; - char *format = ""; + enum nvme_print_flags flags; + struct nvme_fabrics_config cfg = { 0 }; + char *format = "normal"; - OPT_ARGS(opts) = { - NVMF_OPTS(cfg), - OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), - OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), - OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), - OPT_FLAG("dump-config", 'O', &dump_config, "Dump JSON configuration to stdout"), - OPT_FMT("output-format", 'o', &format, "Output format: normal|json"), - OPT_END() - }; + + NVMF_ARGS(opts, cfg, + OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), + OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), + OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), + OPT_FLAG("dump-config", 'O', &dump_config, "Dump JSON configuration to stdout"), + OPT_FMT("output-format", 'o', &format, "Output format: normal|json"), + OPT_STRING("context", 0, "STR", &context, nvmf_context)); nvmf_default_config(&cfg); @@ -809,25 +916,22 @@ int nvmf_connect(const char *desc, int argc, char **argv) if (ret) return ret; - if (!strcmp(format, "")) - flags = -1; - else if (!strcmp(format, "normal")) - flags = NORMAL; - else if (!strcmp(format, "json")) - flags = JSON; - else - return EINVAL; + ret = validate_output_format(format, &flags); + if (ret < 0) { + nvme_show_error("Invalid output format"); + return ret; + } if (!subsysnqn) { fprintf(stderr, "required argument [--nqn | -n] not specified\n"); - return EINVAL; + return -EINVAL; } if (!transport) { fprintf(stderr, "required argument [--transport | -t] not specified\n"); - return EINVAL; + return -EINVAL; } if (strcmp(transport, "loop")) { @@ -835,19 +939,23 @@ int nvmf_connect(const char *desc, int argc, char **argv) fprintf(stderr, "required argument [--traddr | -a] not specified for transport %s\n", transport); - return EINVAL; + return -EINVAL; } } if (!strcmp(config_file, "none")) config_file = NULL; - r = nvme_create_root(stderr, map_log_level(verbose, quiet)); + log_level = map_log_level(verbose, quiet); + + r = nvme_create_root(stderr, log_level); if (!r) { fprintf(stderr, "Failed to create topology root: %s\n", nvme_strerror(errno)); return -errno; } + if (context) + nvme_root_set_application(r, context); ret = nvme_scan_topology(r, NULL, NULL); if (ret < 0) { fprintf(stderr, "Failed to scan topology: %s\n", @@ -856,13 +964,19 @@ int nvmf_connect(const char *desc, int argc, char **argv) return ret; } nvme_read_config(r, config_file); + nvme_read_volatile_config(r); if (!hostnqn) hostnqn = hnqn = nvmf_hostnqn_from_file(); - if (!hostnqn) + if (!hostnqn) { hostnqn = hnqn = nvmf_hostnqn_generate(); + hostid = hid = nvmf_hostid_from_hostnqn(hostnqn); + } if (!hostid) hostid = hid = nvmf_hostid_from_file(); + if (!hostid && hostnqn) + hostid = hid = nvmf_hostid_from_hostnqn(hostnqn); + nvmf_check_hostid_and_hostnqn(hostid, hostnqn, verbose); h = nvme_lookup_host(r, hostnqn, hostid); if (!h) { errno = ENOMEM; @@ -872,6 +986,23 @@ int nvmf_connect(const char *desc, int argc, char **argv) nvme_host_set_dhchap_key(h, hostkey); if (!trsvcid) trsvcid = get_default_trsvcid(transport, false); + + struct tr_config trcfg = { + .subsysnqn = subsysnqn, + .transport = transport, + .traddr = traddr, + .host_traddr = cfg.host_traddr, + .host_iface = cfg.host_iface, + .trsvcid = trsvcid, + }; + + c = lookup_ctrl(h, &trcfg); + if (c && nvme_ctrl_get_name(c)) { + fprintf(stderr, "already connected\n"); + errno = EALREADY; + goto out_free; + } + c = nvme_create_ctrl(r, subsysnqn, transport, traddr, cfg.host_traddr, cfg.host_iface, trsvcid); if (!c) { @@ -884,14 +1015,12 @@ int nvmf_connect(const char *desc, int argc, char **argv) errno = 0; ret = nvmf_add_ctrl(h, c, &cfg); if (ret) - fprintf(stderr, "no controller found: %s\n", + fprintf(stderr, "could not add new controller: %s\n", nvme_strerror(errno)); else { errno = 0; - if (flags == NORMAL) - print_connect_msg(c); - else if (flags == JSON) - json_connect_msg(c); + if (flags != -EINVAL) + nvme_show_connect_msg(c, flags); } out_free: @@ -900,7 +1029,7 @@ int nvmf_connect(const char *desc, int argc, char **argv) if (dump_config) nvme_dump_config(r); nvme_free_tree(r); - return errno; + return -errno; } static nvme_ctrl_t lookup_nvme_ctrl(nvme_root_t r, const char *name) @@ -920,12 +1049,36 @@ static nvme_ctrl_t lookup_nvme_ctrl(nvme_root_t r, const char *name) return NULL; } +static void nvmf_disconnect_nqn(nvme_root_t r, char *nqn) +{ + int i = 0; + char *n = nqn; + char *p; + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + + while ((p = strsep(&n, ",")) != NULL) { + if (!strlen(p)) + continue; + nvme_for_each_host(r, h) { + nvme_for_each_subsystem(h, s) { + if (strcmp(nvme_subsystem_get_nqn(s), p)) + continue; + nvme_subsystem_for_each_ctrl(s, c) { + if (!nvme_disconnect_ctrl(c)) + i++; + } + } + } + } + printf("NQN:%s disconnected %d controller(s)\n", nqn, i); +} + int nvmf_disconnect(const char *desc, int argc, char **argv) { const char *device = "nvme device handle"; nvme_root_t r; - nvme_host_t h; - nvme_subsystem_t s; nvme_ctrl_t c; char *p; int ret; @@ -939,9 +1092,9 @@ int nvmf_disconnect(const char *desc, int argc, char **argv) struct config cfg = { 0 }; OPT_ARGS(opts) = { - OPT_STRING("nqn", 'n', "NAME", &cfg.nqn, nvmf_nqn), - OPT_STRING("device", 'd', "DEV", &cfg.device, device), - OPT_INCR("verbose", 'v', &cfg.verbose, "Increase logging verbosity"), + OPT_STRING("nqn", 'n', "NAME", &cfg.nqn, nvmf_nqn), + OPT_STRING("device", 'd', "DEV", &cfg.device, device), + OPT_INCR("verbose", 'v', &cfg.verbose, "Increase logging verbosity"), OPT_END() }; @@ -952,10 +1105,12 @@ int nvmf_disconnect(const char *desc, int argc, char **argv) if (!cfg.nqn && !cfg.device) { fprintf(stderr, "Neither device name [--device | -d] nor NQN [--nqn | -n] provided\n"); - return EINVAL; + return -EINVAL; } - r = nvme_create_root(stderr, map_log_level(cfg.verbose, false)); + log_level = map_log_level(cfg.verbose, false); + + r = nvme_create_root(stderr, log_level); if (!r) { fprintf(stderr, "Failed to create topology root: %s\n", nvme_strerror(errno)); @@ -969,26 +1124,8 @@ int nvmf_disconnect(const char *desc, int argc, char **argv) return ret; } - if (cfg.nqn) { - int i = 0; - char *n = cfg.nqn; - - while ((p = strsep(&n, ",")) != NULL) { - if (!strlen(p)) - continue; - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - if (strcmp(nvme_subsystem_get_nqn(s), p)) - continue; - nvme_subsystem_for_each_ctrl(s, c) { - if (!nvme_disconnect_ctrl(c)) - i++; - } - } - } - } - printf("NQN:%s disconnected %d controller(s)\n", cfg.nqn, i); - } + if (cfg.nqn) + nvmf_disconnect_nqn(r, cfg.nqn); if (cfg.device) { char *d; @@ -1002,7 +1139,7 @@ int nvmf_disconnect(const char *desc, int argc, char **argv) fprintf(stderr, "Did not find device %s\n", p); nvme_free_tree(r); - return errno; + return -errno; } ret = nvme_disconnect_ctrl(c); if (ret) @@ -1041,7 +1178,9 @@ int nvmf_disconnect_all(const char *desc, int argc, char **argv) if (ret) return ret; - r = nvme_create_root(stderr, map_log_level(cfg.verbose, false)); + log_level = map_log_level(cfg.verbose, false); + + r = nvme_create_root(stderr, log_level); if (!r) { fprintf(stderr, "Failed to create topology root: %s\n", nvme_strerror(errno)); @@ -1091,17 +1230,14 @@ int nvmf_config(const char *desc, int argc, char **argv) struct nvme_fabrics_config cfg; bool scan_tree = false, modify_config = false, update_config = false; - OPT_ARGS(opts) = { - NVMF_OPTS(cfg), - OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), - OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), - OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), - OPT_FLAG("scan", 'R', &scan_tree, "Scan current NVMeoF topology"), - OPT_FLAG("modify", 'M', &modify_config, "Modify JSON configuration file"), - OPT_FLAG("dump", 'O', &dump_config, "Dump JSON configuration to stdout"), - OPT_FLAG("update", 'U', &update_config, "Update JSON configuration file"), - OPT_END() - }; + NVMF_ARGS(opts, cfg, + OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey), + OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file), + OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"), + OPT_FLAG("scan", 'R', &scan_tree, "Scan current NVMeoF topology"), + OPT_FLAG("modify", 'M', &modify_config, "Modify JSON configuration file"), + OPT_FLAG("dump", 'O', &dump_config, "Dump JSON configuration to stdout"), + OPT_FLAG("update", 'U', &update_config, "Update JSON configuration file")); nvmf_default_config(&cfg); @@ -1112,7 +1248,9 @@ int nvmf_config(const char *desc, int argc, char **argv) if (!strcmp(config_file, "none")) config_file = NULL; - r = nvme_create_root(stderr, map_log_level(verbose, quiet)); + log_level = map_log_level(verbose, quiet); + + r = nvme_create_root(stderr, log_level); if (!r) { fprintf(stderr, "Failed to create topology root: %s\n", nvme_strerror(errno)); @@ -1134,6 +1272,18 @@ int nvmf_config(const char *desc, int argc, char **argv) nvme_subsystem_t s; nvme_ctrl_t c; + if (!subsysnqn) { + fprintf(stderr, + "required argument [--nqn | -n] needed with --modify\n"); + return -EINVAL; + } + + if (!transport) { + fprintf(stderr, + "required argument [--transport | -t] needed with --modify\n"); + return -EINVAL; + } + if (!hostnqn) hostnqn = hnqn = nvmf_hostnqn_from_file(); if (!hostid && hnqn) @@ -1177,16 +1327,16 @@ int nvmf_config(const char *desc, int argc, char **argv) if (hnqn) free(hnqn); nvme_free_tree(r); - return errno; + return -errno; } -static void dim_operation(nvme_ctrl_t c, enum nvmf_dim_tas tas, const char * name) +static void dim_operation(nvme_ctrl_t c, enum nvmf_dim_tas tas, const char *name) { static const char * const task[] = { [NVMF_DIM_TAS_REGISTER] = "register", [NVMF_DIM_TAS_DEREGISTER] = "deregister", }; - const char * t; + const char *t; int status; __u32 result; @@ -1233,13 +1383,13 @@ int nvmf_dim(const char *desc, int argc, char **argv) if (!cfg.nqn && !cfg.device) { fprintf(stderr, "Neither device name [--device | -d] nor NQN [--nqn | -n] provided\n"); - return EINVAL; + return -EINVAL; } if (!cfg.tas) { fprintf(stderr, "Task [--task | -t] must be specified\n"); - return EINVAL; + return -EINVAL; } /* Allow partial name (e.g. "reg" for "register" */ @@ -1249,10 +1399,12 @@ int nvmf_dim(const char *desc, int argc, char **argv) tas = NVMF_DIM_TAS_DEREGISTER; } else { fprintf(stderr, "Invalid --task: %s\n", cfg.tas); - return EINVAL; + return -EINVAL; } - r = nvme_create_root(stderr, map_log_level(cfg.verbose, false)); + log_level = map_log_level(cfg.verbose, false); + + r = nvme_create_root(stderr, log_level); if (!r) { fprintf(stderr, "Failed to create topology root: %s\n", nvme_strerror(errno)); @@ -1298,7 +1450,7 @@ int nvmf_dim(const char *desc, int argc, char **argv) "Did not find device %s: %s\n", p, nvme_strerror(errno)); nvme_free_tree(r); - return errno; + return -errno; } dim_operation(c, tas, p); } diff --git a/fabrics.h b/fabrics.h index d1e16fc57c..c16df60472 100644 --- a/fabrics.h +++ b/fabrics.h @@ -2,6 +2,16 @@ #ifndef _FABRICS_H #define _FABRICS_H +struct tr_config { + const char *subsysnqn; + const char *transport; + const char *traddr; + const char *host_traddr; + const char *host_iface; + const char *trsvcid; +}; + +extern nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg); extern int nvmf_discover(const char *desc, int argc, char **argv, bool connect); extern int nvmf_connect(const char *desc, int argc, char **argv); extern int nvmf_disconnect(const char *desc, int argc, char **argv); diff --git a/libnvme-wrap.c b/libnvme-wrap.c new file mode 100644 index 0000000000..b5b48383b6 --- /dev/null +++ b/libnvme-wrap.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * This file is part of nvme-cli + * + * Copyright (c) 2022 Daniel Wagner, SUSE + */ + +#include +#include +#include + +#include +#include "nvme-print.h" + +#define PROTO(args...) args +#define ARGS(args...) args + +#define VOID_FN(name, proto, args) \ +void __attribute__((weak)) name(proto) \ +{ \ + void (*fn)(proto); \ + fn = dlsym(RTLD_NEXT, #name); \ + if (!fn) { \ + nvme_show_error("libnvme function " #name " not found");\ + exit(EXIT_FAILURE); \ + } \ + fn(args); \ +} + +#define FN(name, rtype, proto, args, defret) \ +rtype __attribute__((weak)) name(proto) \ +{ \ + rtype (*fn)(proto); \ + fn = dlsym(RTLD_NEXT, #name); \ + if (fn) \ + return fn(args); \ + return defret; \ +} + +FN(nvme_get_version, + const char *, PROTO(enum nvme_version type), + ARGS(type), "n/a") + +VOID_FN(nvme_init_copy_range_f1, + PROTO(struct nvme_copy_range_f1 *copy, __u16 *nlbs, + __u64 *slbas, __u64 *eilbrts, __u32 *elbatms, + __u32 *elbats, __u16 nr), + ARGS(copy, nlbs, slbas, eilbrts, elbatms, elbats, nr)) + +VOID_FN(nvme_init_copy_range_f2, + PROTO(struct nvme_copy_range_f2 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, __u32 *eilbrts, + __u32 *elbatms, __u32 *elbats, __u16 nr), + ARGS(copy, snsids, nlbs, slbas, sopts, eilbrts, elbatms, elbats, nr)) + +VOID_FN(nvme_init_copy_range_f3, + PROTO(struct nvme_copy_range_f3 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, __u64 *eilbrts, + __u32 *elbatms, __u32 *elbats, __u16 nr), + ARGS(copy, snsids, nlbs, slbas, sopts, eilbrts, elbatms, elbats, nr)) + +FN(nvme_get_feature_length2, + int, + PROTO(int fid, __u32 cdw11, enum nvme_data_tfr dir, + __u32 *len), + ARGS(fid, cdw11, dir, len), + -EEXIST) + +FN(nvme_ctrl_is_persistent, + bool, + PROTO(nvme_ctrl_t c), + ARGS(c), + false) diff --git a/meson.build b/meson.build index 5333b02d2f..1b316033fa 100644 --- a/meson.build +++ b/meson.build @@ -2,14 +2,16 @@ ################################################################################ project( 'nvme-cli', ['c'], - meson_version: '>= 0.47.0', + meson_version: '>= 0.50.0', license: 'GPL-2.0-only', - version: '2.1.2', + version: '2.8', default_options: [ 'c_std=gnu99', - 'buildtype=release', - 'prefix=/usr', + 'buildtype=debug', + 'prefix=/usr/local', 'warning_level=1', + 'sysconfdir=etc', + 'wrap_mode=nofallback', ] ) @@ -25,6 +27,7 @@ sysconfdir = join_paths(prefixdir, get_option('sysconfdir')) udevrulesdir = join_paths(prefixdir, get_option('udevrulesdir')) dracutrulesdir = join_paths(prefixdir, get_option('dracutrulesdir')) systemddir = join_paths(prefixdir, get_option('systemddir')) +rundir = join_paths(prefixdir, get_option('rundir')) ############################################################################### conf = configuration_data() @@ -34,7 +37,7 @@ version_tag = get_option('version-tag') if version_tag != '' conf.set('GIT_VERSION', '"@0@"'.format(version_tag)) else - r = run_command('meson-vcs-tag.sh', + r = run_command('scripts/meson-vcs-tag.sh', meson.current_source_dir(), meson.project_version(), check: true) @@ -42,46 +45,34 @@ else endif conf.set('SYSCONFDIR', '"@0@"'.format(sysconfdir)) +conf.set('RUNDIR', '"@0@"'.format(rundir)) # Check for libnvme availability -libnvme_dep = dependency('libnvme', version: '>=1.1', required: true, +libnvme_dep = dependency('libnvme', version: '>=1.8', required: true, fallback : ['libnvme', 'libnvme_dep']) libnvme_mi_dep = dependency('libnvme-mi', required: true, fallback : ['libnvme', 'libnvme_mi_dep']) -# Check for libuuid availability -libuuid_dep = dependency('uuid', required: true, - fallback : ['uuid', 'uuid_dep']) -conf.set('CONFIG_LIBUUID', libuuid_dep.found(), description: 'Is libuuid available?') - # Check for libjson-c availability -json_c_dep = dependency('json-c', required: true, version: '>=0.13', - fallback : ['json-c', 'json_c_dep']) -if json_c_dep.version().version_compare('>=0.14') - conf.set('CONFIG_JSONC_14', true, description: 'Is json-c at least 0.14?') - requires = 'Requires: json-c >= 0.14' +if get_option('json-c').disabled() + json_c_dep = dependency('', required: false) else - requires = 'Requires: json-c >= 0.13' + json_c_dep = dependency('json-c', required: get_option('json-c'), version: '>=0.13', + fallback : ['json-c', 'json_c_dep']) + if json_c_dep.version().version_compare('>=0.14') + conf.set('CONFIG_JSONC_14', true, description: 'Is json-c at least 0.14?') + requires = 'Requires: json-c >= 0.14' + else + requires = 'Requires: json-c >= 0.13' + endif endif - -# Check for zlib availability -libz_dep = dependency('zlib', required: true, - fallback : ['zlib', 'zlib_dep']) - -# Check for libhugetlbfs availability (optional) -if cc.has_header('hugetlbfs.h') - libhugetlbfs_dep = cc.find_library('hugetlbfs', - required : false) - have_libhugetlbfs = libhugetlbfs_dep.found() -else - libhugetlbfs_dep = [] - have_libhugetlbfs = false -endif -conf.set('CONFIG_LIBHUGETLBFS', have_libhugetlbfs, description: 'Is libhugetlbfs available?') +conf.set('CONFIG_JSONC', json_c_dep.found(), description: 'Is json-c available?') # Set the nvme-cli version conf.set('NVME_VERSION', '"' + meson.project_version() + '"') +conf.set10('DEFAULT_PDC_ENABLED', get_option('pdc-enabled')) + # local (cross-compilable) implementations of ccan configure steps conf.set10( 'HAVE_BUILTIN_TYPES_COMPATIBLE_P', @@ -129,12 +120,12 @@ conf.set10( ) conf.set10( 'HAVE_LITTLE_ENDIAN', - build_machine.endian() == 'little', + host_machine.endian() == 'little', description: 'Building for little-endian' ) conf.set10( 'HAVE_BIG_ENDIAN', - build_machine.endian() == 'big', + host_machine.endian() == 'big', description: 'Building for big-endian' ) conf.set10( @@ -157,6 +148,40 @@ conf.set10( ), description: 'Is sys/random.h(getrandom) include-able?' ) +conf.set10( + 'HAVE_ATTRIBUTE_UNUSED', + cc.get_id() == 'clang', + description: 'Is compiler warning about unused static line function?' +) +conf.set10( + 'HAVE_SED_OPAL', + cc.compiles( + '''#include ''', + name: 'linux/sed-opal.h' + + ), + description: 'Is linux/sed-opa.h include-able?' +) +conf.set10( + 'HAVE_KEY_TYPE', + cc.compiles( + ''' + #include + int main(void) { + struct opal_key key; + key.key_type = OPAL_INCLUDED; + } + ''', + name: 'key_type' + ), + description: 'Does struct opal_key have a key_type field?' +) + +if cc.has_function_attribute('fallthrough') + conf.set('fallthrough', '__attribute__((__fallthrough__))') +else + conf.set('fallthrough', 'do {} while (0) /* fallthrough */') +endif configure_file( output: 'config.h', @@ -178,6 +203,7 @@ substs.set('DRACUTRILESDIR', dracutrulesdir) substs.set('REQUIRES', requires) substs.set('DATADIR', datadir) substs.set('MANDIR', mandir) +substs.set('RUNDIR', rundir) substs.set('SBINDIR', sbindir) substs.set('SYSCONFDIR', sysconfdir) substs.set('SYSTEMDDIR', systemddir) @@ -210,6 +236,7 @@ endforeach systemd_files = [ 'nvmefc-boot-connections.service', 'nvmf-autoconnect.service', + 'nvmf-connect-nbft.service', 'nvmf-connect.target', 'nvmf-connect@.service', ] @@ -223,8 +250,9 @@ foreach file : systemd_files endforeach udev_files = [ + '65-persistent-net-nbft.rules', '70-nvmf-autoconnect.rules', - '71-nvmf-iopolicy-netapp.rules', + '71-nvmf-netapp.rules', ] foreach file : udev_files @@ -242,27 +270,37 @@ incdir = include_directories(['ccan']) ################################################################################ sources = [ + 'nbft.c', 'fabrics.c', 'nvme.c', 'nvme-models.c', 'nvme-print.c', + 'nvme-print-stdout.c', + 'nvme-print-binary.c', 'nvme-rpmb.c', 'nvme-wrap.c', 'plugin.c', - 'wrapper.c', + 'libnvme-wrap.c', ] +if json_c_dep.found() + sources += [ + 'nvme-print-json.c', + ] +endif subdir('ccan') subdir('plugins') -subdir('tests') +subdir('unit') +if get_option('nvme-tests') + subdir('tests') +endif subdir('util') subdir('Documentation') executable( 'nvme', sources, - dependencies: [ libnvme_dep, libnvme_mi_dep, libuuid_dep, json_c_dep, libz_dep, - libhugetlbfs_dep ], + dependencies: [ libnvme_dep, libnvme_mi_dep, json_c_dep ], link_args: '-ldl', include_directories: incdir, install: true, @@ -293,3 +331,28 @@ endforeach install_data(disc, install_dir: join_paths(sysconfdir, 'nvme')) + +################################################################################ +if meson.version().version_compare('>=0.53.0') + path_dict = { + 'prefixdir': prefixdir, + 'sysconfdir': sysconfdir, + 'sbindir': sbindir, + 'datadir': datadir, + 'mandir': mandir, + 'udevrulesdir': udevrulesdir, + 'dracutrulesdir': dracutrulesdir, + 'rundir': rundir, + 'systemddir': systemddir, + 'build location': meson.current_build_dir(), + } + summary(path_dict, section: 'Paths') + dep_dict = { + 'json-c': json_c_dep.found(), + } + summary(dep_dict, section: 'Dependencies') + conf_dict = { + 'pdc enabled': get_option('pdc-enabled') + } + summary(conf_dict, section: 'Configuration') +endif diff --git a/meson_options.txt b/meson_options.txt index fd9051101f..c61dae0fff 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,10 +1,72 @@ # SPDX-License-Identifier: GPL-2.0-or-later -option('version-tag', type : 'string', description : 'override the git version string') -option('udevrulesdir', type : 'string', value : 'lib/udev/rules.d', description : 'directory for udev rules files') -option('dracutrulesdir', type : 'string', value : 'lib/dracut/dracut.conf.d/', description : 'directory for dracut rules files') -option('systemddir', type : 'string', value : 'lib/systemd/system', description : 'directory for systemd files') -option('htmldir', type : 'string', value : '', description : 'directory for HTML documentation') -option('systemctl', type : 'string', value : '/usr/bin/systemctl', description : 'path to systemctl binary') - -option('docs', type : 'combo', choices : ['false', 'html', 'man', 'all'], description : 'install documentation') -option('docs-build', type : 'boolean', value : false, description : 'build documentation') +option( + 'docs', + type : 'combo', + choices : ['false', 'html', 'man', 'all'], + description : 'install documentation' +) +option( + 'docs-build', + type : 'boolean', + value : false, + description : 'build documentation' +) +option( + 'dracutrulesdir', + type : 'string', + value : 'lib/dracut/dracut.conf.d/', + description : 'directory for dracut rules files' +) +option( + 'htmldir', + type : 'string', + value : '', + description : 'directory for HTML documentation' +) +option( + 'json-c', + type: 'feature', + value: 'auto', + description: 'JSON suppport' +) +option( + 'nvme-tests', + type : 'boolean', + value : false, + description: 'Run tests against real hardware' +) +option( + 'pdc-enabled', + type: 'boolean', + value : false, + description : 'set default Persistent Discovery Controllers behavior' +) +option( + 'rundir', + type: 'string', + value: 'run', + description: 'directory for volatile configuration files', +) +option( + 'systemctl', + type : 'string', + value : '/usr/bin/systemctl', + description : 'path to systemctl binary' +) +option( + 'systemddir', + type : 'string', + value : 'lib/systemd/system', + description : 'directory for systemd files' +) +option( + 'udevrulesdir', + type : 'string', + value : 'lib/udev/rules.d', + description : 'directory for udev rules files' +) +option( + 'version-tag', + type : 'string', + description : 'override the git version string' +) diff --git a/nbft.c b/nbft.c new file mode 100644 index 0000000000..ff36119d22 --- /dev/null +++ b/nbft.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include + +#include "nvme.h" +#include "nbft.h" +#include "fabrics.h" +#include "nvme-print.h" + +#include "util/types.h" + +#define NBFT_SYSFS_FILENAME "NBFT*" + +static void print_connect_msg(nvme_ctrl_t c) +{ + printf("device: %s\n", nvme_ctrl_get_name(c)); +} + +static void json_connect_msg(nvme_ctrl_t c) +{ +#ifdef CONFIG_JSONC + struct json_object *root; + + root = json_create_object(); + json_object_add_value_string(root, "device", nvme_ctrl_get_name(c)); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +#endif +} + +int nbft_filter(const struct dirent *dent) +{ + return !fnmatch(NBFT_SYSFS_FILENAME, dent->d_name, FNM_PATHNAME); +} + +int read_nbft_files(struct list_head *nbft_list, char *path) +{ + struct dirent **dent; + char filename[PATH_MAX]; + int i, count, ret; + struct nbft_file_entry *entry; + struct nbft_info *nbft; + + count = scandir(path, &dent, nbft_filter, NULL); + if (count < 0) + return -errno; + + for (i = 0; i < count; i++) { + snprintf(filename, sizeof(filename), "%s/%s", path, dent[i]->d_name); + ret = nvme_nbft_read(&nbft, filename); + if (!ret) { + entry = calloc(1, sizeof(*entry)); + entry->nbft = nbft; + list_add_tail(nbft_list, &entry->node); + } + free(dent[i]); + } + free(dent); + return 0; +} + +void free_nbfts(struct list_head *nbft_list) +{ + struct nbft_file_entry *entry; + + while ((entry = list_pop(nbft_list, struct nbft_file_entry, node))) { + nvme_nbft_free(entry->nbft); + free(entry); + } +} + +int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + char *hostnqn_sys, char *hostid_sys, + const char *desc, bool connect, + const struct nvme_fabrics_config *cfg, char *nbft_path, + enum nvme_print_flags flags, bool verbose) +{ + char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; + nvme_host_t h; + nvme_ctrl_t c; + int ret, i; + struct list_head nbft_list; + struct nbft_file_entry *entry; + struct nbft_info_subsystem_ns **ss; + struct nbft_info_hfi *hfi; + + if (!connect) + /* to do: print discovery-type info from NBFT tables */ + return 0; + + list_head_init(&nbft_list); + ret = read_nbft_files(&nbft_list, nbft_path); + if (ret) { + if (ret != ENOENT) + nvme_show_perror("Failed to access ACPI tables directory"); + goto out_free_2; + } + + list_for_each(&nbft_list, entry, node) + for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) + for (i = 0; i < (*ss)->num_hfis; i++) { + nvme_ctrl_t cl; + + hfi = (*ss)->hfis[i]; + if (hostnqn_arg) + hostnqn = hostnqn_arg; + else { + hostnqn = entry->nbft->host.nqn; + if (!hostnqn) + hostnqn = hostnqn_sys; + } + + if (hostid_arg) + hostid = hostid_arg; + else if (*entry->nbft->host.id) { + hostid = (char *)util_uuid_to_string(entry->nbft->host.id); + if (!hostid) + hostid = hostid_sys; + } + + h = nvme_lookup_host(r, hostnqn, hostid); + if (!h) { + errno = ENOMEM; + goto out_free; + } + + if (!cfg->host_traddr) { + host_traddr = NULL; + if (!strncmp((*ss)->transport, "tcp", 3)) + host_traddr = hfi->tcp_info.ipaddr; + } + + struct tr_config trcfg = { + .subsysnqn = (*ss)->subsys_nqn, + .transport = (*ss)->transport, + .traddr = (*ss)->traddr, + .host_traddr = host_traddr, + .host_iface = NULL, + .trsvcid = (*ss)->trsvcid, + }; + + /* Already connected ? */ + cl = lookup_ctrl(h, &trcfg); + if (cl && nvme_ctrl_get_name(cl)) + continue; + + c = nvme_create_ctrl(r, (*ss)->subsys_nqn, (*ss)->transport, + (*ss)->traddr, host_traddr, NULL, + (*ss)->trsvcid); + if (!c) { + errno = ENOMEM; + goto out_free; + } + + errno = 0; + ret = nvmf_add_ctrl(h, c, cfg); + + /* + * With TCP/DHCP, it can happen that the OS + * obtains a different local IP address than the + * firmware had. Retry without host_traddr. + */ + if (ret == -1 && errno == ENVME_CONNECT_ADDRNOTAVAIL && + !strcmp((*ss)->transport, "tcp") && + strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { + nvme_free_ctrl(c); + + trcfg.host_traddr = NULL; + cl = lookup_ctrl(h, &trcfg); + if (cl && nvme_ctrl_get_name(cl)) + continue; + + c = nvme_create_ctrl(r, (*ss)->subsys_nqn, (*ss)->transport, + (*ss)->traddr, + NULL, NULL, (*ss)->trsvcid); + if (!c) { + errno = ENOMEM; + goto out_free; + } + errno = 0; + ret = nvmf_add_ctrl(h, c, cfg); + if (ret == 0 && verbose >= 1) + fprintf(stderr, + "connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", + host_traddr); + } + + if (ret) + fprintf(stderr, "no controller found\n"); + else { + if (flags == NORMAL) + print_connect_msg(c); + else if (flags == JSON) + json_connect_msg(c); + } +out_free: + if (errno == ENOMEM) + goto out_free_2; + } +out_free_2: + free_nbfts(&nbft_list); + return errno; +} diff --git a/nbft.h b/nbft.h new file mode 100644 index 0000000000..0e09733f5f --- /dev/null +++ b/nbft.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include + +#define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables" + +struct nbft_file_entry { + struct list_node node; + struct nbft_info *nbft; +}; + +int read_nbft_files(struct list_head *nbft_list, char *path); +void free_nbfts(struct list_head *nbft_list); + +extern int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + char *hostnqn_sys, char *hostid_sys, + const char *desc, bool connect, + const struct nvme_fabrics_config *cfg, char *nbft_path, + enum nvme_print_flags flags, bool verbose); diff --git a/nvme-builtin.h b/nvme-builtin.h index 43041ca923..2d2bead38b 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -44,11 +44,12 @@ COMMAND_LIST( ENTRY("endurance-log", "Retrieve Endurance Group Log, show it", get_endurance_log) ENTRY("predictable-lat-log", "Retrieve Predictable Latency per Nvmset Log, show it", get_pred_lat_per_nvmset_log) ENTRY("pred-lat-event-agg-log", "Retrieve Predictable Latency Event Aggregate Log, show it", get_pred_lat_event_agg_log) - ENTRY("persistent-event-log", "Retrieve Presistent Event Log, show it", get_persistent_event_log) + ENTRY("persistent-event-log", "Retrieve Persistent Event Log, show it", get_persistent_event_log) ENTRY("endurance-event-agg-log", "Retrieve Endurance Group Event Aggregate Log, show it", get_endurance_event_agg_log) ENTRY("lba-status-log", "Retrieve LBA Status Information Log, show it", get_lba_status_log) ENTRY("resv-notif-log", "Retrieve Reservation Notification Log, show it", get_resv_notif_log) ENTRY("boot-part-log", "Retrieve Boot Partition Log, show it", get_boot_part_log) + ENTRY("phy-rx-eom-log", "Retrieve Physical Interface Receiver Eye Opening Measurement, show it", get_phy_rx_eom_log) ENTRY("get-feature", "Get feature and show the resulting value", get_feature) ENTRY("device-self-test", "Perform the necessary tests to observe the performance", device_self_test) ENTRY("self-test-log", "Retrieve the SELF-TEST Log, show it", self_test_log) @@ -60,7 +61,7 @@ COMMAND_LIST( 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("format", "Format namespace with new block format", format_cmd) ENTRY("fw-commit", "Verify and commit firmware to a specific slot (fw-activate in old version < 1.2)", fw_commit, "fw-activate") ENTRY("fw-download", "Download new firmware", fw_download) ENTRY("admin-passthru", "Submit an arbitrary admin command, return results", admin_passthru) @@ -74,15 +75,15 @@ COMMAND_LIST( ENTRY("resv-release", "Submit a Reservation Release, return results", resv_release) ENTRY("resv-report", "Submit a Reservation Report, return results", resv_report) ENTRY("dsm", "Submit a Data Set Management command, return results", dsm) - ENTRY("copy", "Submit a Simple Copy command, return results", copy) - ENTRY("flush", "Submit a Flush command, return results", flush) + ENTRY("copy", "Submit a Simple Copy command, return results", copy_cmd) + ENTRY("flush", "Submit a Flush command, return results", flush_cmd) ENTRY("compare", "Submit a Compare command, return results", compare) ENTRY("read", "Submit a read command, return results", read_cmd) ENTRY("write", "Submit a write command, return results", write_cmd) ENTRY("write-zeroes", "Submit a write zeroes command, return results", write_zeroes) ENTRY("write-uncor", "Submit a write uncorrectable command, return results", write_uncor) ENTRY("verify", "Submit a verify command, return results", verify_cmd) - ENTRY("sanitize", "Submit a sanitize command", sanitize) + ENTRY("sanitize", "Submit a sanitize command", sanitize_cmd) ENTRY("sanitize-log", "Retrieve sanitize log, show it", sanitize_log) ENTRY("reset", "Resets the controller", reset) ENTRY("subsystem-reset", "Resets the subsystem", subsystem_reset) @@ -102,10 +103,15 @@ COMMAND_LIST( ENTRY("check-tls-key", "Validate NVMeoF TLS PSK", check_tls_key) ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive) ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send) - ENTRY("virt-mgmt", "Manage Flexible Resources between Primary and Secondary Controller ", virtual_mgmt) + ENTRY("virt-mgmt", "Manage Flexible Resources between Primary and Secondary Controller", virtual_mgmt) ENTRY("rpmb", "Replay Protection Memory Block commands", rpmb_cmd) ENTRY("lockdown", "Submit a Lockdown command,return result", lockdown_cmd) - ENTRY("dim", "Send Discovery Information Management command to a Discovery Controller", dim_cmd) + ENTRY("dim", "Send Discovery Information Management command to a Discovery Controller", dim_cmd) \ + ENTRY("show-topology", "Show the topology", show_topology_cmd) \ + ENTRY("io-mgmt-recv", "I/O Management Receive", io_mgmt_recv) + ENTRY("io-mgmt-send", "I/O Management Send", io_mgmt_send) + ENTRY("nvme-mi-recv", "Submit a NVMe-MI Receive command, return results", nmi_recv) + ENTRY("nvme-mi-send", "Submit a NVMe-MI Send command, return results", nmi_send) ); #endif diff --git a/nvme-print-binary.c b/nvme-print-binary.c new file mode 100644 index 0000000000..e9371e52fd --- /dev/null +++ b/nvme-print-binary.c @@ -0,0 +1,386 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "nvme-print.h" + +static struct print_ops binary_print_ops; + +static void binary_predictable_latency_per_nvmset( + struct nvme_nvmset_predictable_lat_log *plpns_log, + __u16 nvmset_id, const char *devname) +{ + d_raw((unsigned char *)plpns_log, sizeof(*plpns_log)); +} + +static void binary_predictable_latency_event_agg_log( + struct nvme_aggregate_predictable_lat_event *pea_log, + __u64 log_entries, __u32 size, const char *devname) +{ + d_raw((unsigned char *)pea_log, size); +} + +static void binary_persistent_event_log(void *pevent_log_info, + __u8 action, __u32 size, const char *devname) +{ + d_raw((unsigned char *)pevent_log_info, size); +} + +static void binary_endurance_group_event_agg_log( + struct nvme_aggregate_predictable_lat_event *endurance_log, + __u64 log_entries, __u32 size, const char *devname) +{ + d_raw((unsigned char *)endurance_log, size); +} + +static void binary_lba_status_log(void *lba_status, __u32 size, + const char *devname) +{ + d_raw((unsigned char *)lba_status, size); +} + +static void binary_resv_notif_log(struct nvme_resv_notification_log *resv, + const char *devname) +{ + d_raw((unsigned char *)resv, sizeof(*resv)); +} + +static void binary_fid_support_effects_log( + struct nvme_fid_supported_effects_log *fid_log, + const char *devname) +{ + d_raw((unsigned char *)fid_log, sizeof(*fid_log)); +} + +static void binary_mi_cmd_support_effects_log( + struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, + const char *devname) +{ + d_raw((unsigned char *)mi_cmd_log, sizeof(*mi_cmd_log)); +} + +static void binary_boot_part_log(void *bp_log, const char *devname, + __u32 size) +{ + d_raw((unsigned char *)bp_log, size); +} + +static void binary_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, + __u16 controller) +{ + size_t len; + if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) + len = log->hsize + log->dsize * log->nd; + else + len = log->hsize; + + d_raw((unsigned char *)log, len); +} + +static void binary_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log) +{ + d_raw((unsigned char *)mus_log, sizeof(*mus_log)); +} + +static void binary_fdp_configs(struct nvme_fdp_config_log *log, size_t len) +{ + d_raw((unsigned char *)log, len); +} + +static void binary_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len) +{ + + d_raw((unsigned char *)log, len); +} + +static void binary_fdp_stats(struct nvme_fdp_stats_log *log) +{ + d_raw((unsigned char*)log, sizeof(*log)); +} + +static void binary_fdp_events(struct nvme_fdp_events_log *log) +{ + d_raw((unsigned char*)log, sizeof(*log)); +} + +static void binary_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len) +{ + d_raw((unsigned char *)status, len); +} + +static void binary_supported_cap_config_log( + struct nvme_supported_cap_config_list_log *cap) +{ + d_raw((unsigned char *)cap, sizeof(*cap)); +} + +static void binary_ctrl_registers(void *bar, bool fabrics) +{ + const unsigned int reg_size = 0x0e1c; /* 0x0000 to 0x0e1b */ + + d_raw((unsigned char *)bar, reg_size); +} + +static void binary_id_ns(struct nvme_id_ns *ns, unsigned int nsid, + unsigned int lba_index, bool cap_only) +{ + d_raw((unsigned char *)ns, sizeof(*ns)); +} + + +static void binary_cmd_set_independent_id_ns( + struct nvme_id_independent_id_ns *ns, unsigned int nsid) +{ + d_raw((unsigned char *)ns, sizeof(*ns)); +} + +static void binary_id_ns_descs(void *data, unsigned nsid) +{ + d_raw((unsigned char *)data, 0x1000); +} + +static void binary_id_ctrl(struct nvme_id_ctrl *ctrl, + void (*vendor_show)(__u8 *vs, struct json_object *root)) +{ + d_raw((unsigned char *)ctrl, sizeof(*ctrl)); +} + +static void binary_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm) +{ + d_raw((unsigned char *)ctrl_nvm, sizeof(*ctrl_nvm)); +} + +static void binary_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, + struct nvme_id_ns *ns, unsigned int lba_index, + bool cap_only) +{ + d_raw((unsigned char *)nvm_ns, sizeof(*nvm_ns)); +} + +static void binary_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl) +{ + d_raw((unsigned char *)ctrl, sizeof(*ctrl)); +} + +static void binary_zns_id_ns(struct nvme_zns_id_ns *ns, struct nvme_id_ns *id_ns) +{ + d_raw((unsigned char *)ns, sizeof(*ns)); +} + +static void binary_zns_changed(struct nvme_zns_changed_zone_log *log) +{ + d_raw((unsigned char *)log, sizeof(*log)); +} + +static void binary_zns_report_zones(void *report, __u32 descs, + __u8 ext_size, __u32 report_size, + struct json_object *zone_list) +{ + d_raw((unsigned char *)report, report_size); +} + +static void binary_list_ctrl(struct nvme_ctrl_list *ctrl_list) +{ + d_raw((unsigned char *)ctrl_list, sizeof(*ctrl_list)); +} + +static void binary_id_nvmset(struct nvme_id_nvmset_list *nvmset, unsigned nvmset_id) +{ + d_raw((unsigned char *)nvmset, sizeof(*nvmset)); +} + +static void binary_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps) +{ + d_raw((unsigned char *)caps, sizeof(*caps)); +} + +static void binary_list_secondary_ctrl( + const struct nvme_secondary_ctrl_list *sc_list, + __u32 count) +{ + d_raw((unsigned char *)sc_list, sizeof(*sc_list)); +} + +static void binary_id_ns_granularity_list( + const struct nvme_id_ns_granularity_list *glist) +{ + d_raw((unsigned char *)glist, sizeof(*glist)); +} + +static void binary_id_uuid_list(const struct nvme_id_uuid_list *uuid_list) +{ + d_raw((unsigned char *)uuid_list, sizeof(*uuid_list)); +} + +static void binary_id_domain_list(struct nvme_id_domain_list *id_dom) +{ + d_raw((unsigned char *)id_dom, sizeof(*id_dom)); +} + +static void binary_error_log(struct nvme_error_log_page *err_log, int entries, + const char *devname) +{ + d_raw((unsigned char *)err_log, entries * sizeof(*err_log)); +} + +static void binary_resv_report(struct nvme_resv_status *status, int bytes, + bool eds) +{ + d_raw((unsigned char *)status, bytes); +} + +static void binary_fw_log(struct nvme_firmware_slot *fw_log, + const char *devname) +{ + d_raw((unsigned char *)fw_log, sizeof(*fw_log)); +} + +static void binary_changed_ns_list_log(struct nvme_ns_list *log, + const char *devname) +{ + d_raw((unsigned char *)log, sizeof(*log)); +} + + +static void binary_supported_log(struct nvme_supported_log_pages *support_log, + const char *devname) +{ + d_raw((unsigned char *)support_log, sizeof(*support_log)); +} + +static void binary_endurance_log(struct nvme_endurance_group_log *endurance_log, __u16 group_id, + const char *devname) +{ + return d_raw((unsigned char *)endurance_log, sizeof(*endurance_log)); +} + +static void binary_smart_log(struct nvme_smart_log *smart, unsigned int nsid, + const char *devname) +{ + d_raw((unsigned char *)smart, sizeof(*smart)); +} + +static void binary_ana_log(struct nvme_ana_log *ana_log, const char *devname, + size_t len) +{ + d_raw((unsigned char *)ana_log, len); +} + +static void binary_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries, + __u32 size, const char *devname) +{ + d_raw((unsigned char *)self_test, size); +} + +static void binary_sanitize_log(struct nvme_sanitize_log_page *sanitize, + const char *devname) +{ + d_raw((unsigned char *)sanitize, sizeof(*sanitize)); +} + +static void binary_directive(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, + void *buf, __u32 len) +{ + if (!buf) + return; + + d_raw(buf, len); +} + +static void binary_lba_status(struct nvme_lba_status *list, unsigned long len) +{ + d_raw((unsigned char *)list, len); +} + +static void binary_discovery_log(struct nvmf_discovery_log *log, int numrec) +{ + d_raw((unsigned char *)log, + sizeof(struct nvmf_discovery_log) + + numrec * sizeof(struct nvmf_disc_log_entry)); +} + +static struct print_ops binary_print_ops = { + /* libnvme types.h print functions */ + .ana_log = binary_ana_log, + .boot_part_log = binary_boot_part_log, + .phy_rx_eom_log = binary_phy_rx_eom_log, + .ctrl_list = binary_list_ctrl, + .ctrl_registers = binary_ctrl_registers, + .directive = binary_directive, + .discovery_log = binary_discovery_log, + .effects_log_list = NULL, + .endurance_group_event_agg_log = binary_endurance_group_event_agg_log, + .endurance_group_list = NULL, + .endurance_log = binary_endurance_log, + .error_log = binary_error_log, + .fdp_config_log = binary_fdp_configs, + .fdp_event_log = binary_fdp_events, + .fdp_ruh_status = binary_fdp_ruh_status, + .fdp_stats_log = binary_fdp_stats, + .fdp_usage_log = binary_fdp_usage, + .fid_supported_effects_log = binary_fid_support_effects_log, + .fw_log = binary_fw_log, + .id_ctrl = binary_id_ctrl, + .id_ctrl_nvm = binary_id_ctrl_nvm, + .id_domain_list = binary_id_domain_list, + .id_independent_id_ns = binary_cmd_set_independent_id_ns, + .id_iocs = NULL, + .id_ns = binary_id_ns, + .id_ns_descs = binary_id_ns_descs, + .id_ns_granularity_list = binary_id_ns_granularity_list, + .id_nvmset_list = binary_id_nvmset, + .id_uuid_list = binary_id_uuid_list, + .lba_status = binary_lba_status, + .lba_status_log = binary_lba_status_log, + .media_unit_stat_log = binary_media_unit_stat_log, + .mi_cmd_support_effects_log = binary_mi_cmd_support_effects_log, + .ns_list = NULL, + .ns_list_log = binary_changed_ns_list_log, + .nvm_id_ns = binary_nvm_id_ns, + .persistent_event_log = binary_persistent_event_log, + .predictable_latency_event_agg_log = binary_predictable_latency_event_agg_log, + .predictable_latency_per_nvmset = binary_predictable_latency_per_nvmset, + .primary_ctrl_cap = binary_primary_ctrl_cap, + .resv_notification_log = binary_resv_notif_log, + .resv_report = binary_resv_report, + .sanitize_log_page = binary_sanitize_log, + .secondary_ctrl_list = binary_list_secondary_ctrl, + .select_result = NULL, + .self_test_log = binary_self_test_log, + .single_property = NULL, + .smart_log = binary_smart_log, + .supported_cap_config_list_log = binary_supported_cap_config_log, + .supported_log_pages = binary_supported_log, + .zns_start_zone_list = NULL, + .zns_changed_zone_log = binary_zns_changed, + .zns_finish_zone_list = NULL, + .zns_id_ctrl = binary_zns_id_ctrl, + .zns_id_ns = binary_zns_id_ns, + .zns_report_zones = binary_zns_report_zones, + .show_feature = NULL, + .show_feature_fields = NULL, + .id_ctrl_rpmbs = NULL, + .lba_range = NULL, + .lba_status_info = NULL, + .d = NULL, + .show_init = NULL, + .show_finish = NULL, + + /* libnvme tree print functions */ + .list_item = NULL, + .list_items = NULL, + .print_nvme_subsystem_list = NULL, + .topology_ctrl = NULL, + .topology_namespace = NULL, + + /* status and error messages */ + .connect_msg = NULL, + .show_message = NULL, + .show_perror = NULL, + .show_status = NULL, + .show_error_status = NULL, +}; + +struct print_ops *nvme_get_binary_print_ops(enum nvme_print_flags flags) +{ + binary_print_ops.flags = flags; + return &binary_print_ops; +} diff --git a/nvme-print-json.c b/nvme-print-json.c new file mode 100644 index 0000000000..5ce50e02df --- /dev/null +++ b/nvme-print-json.c @@ -0,0 +1,4537 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "nvme-print.h" + +#include "util/json.h" +#include "nvme.h" +#include "common.h" + +#define ERROR_MSG_LEN 100 +#define STR_LEN 100 +#define NAME_LEN 128 +#define BUF_LEN 320 +#define VAL_LEN 4096 +#define BYTE_TO_BIT(byte) ((byte) * 8) +#define POWER_OF_TWO(exponent) (1 << (exponent)) +#define MS_TO_SEC(time) ((time) / 1000) +#define MS500_TO_MS(time) ((time) * 500) +#define MS500_TO_SEC(time) (MS_TO_SEC(MS500_TO_MS(time))) + +#define array_add_obj json_array_add_value_object +#define array_add_str json_array_add_value_string + +#define obj_add_array json_object_add_value_array +#define obj_add_int json_object_add_value_int +#define obj_add_obj json_object_add_value_object +#define obj_add_str json_object_add_value_string +#define obj_add_uint json_object_add_value_uint +#define obj_add_uint128 json_object_add_value_uint128 +#define obj_add_uint64 json_object_add_value_uint64 + +static const uint8_t zero_uuid[16] = { 0 }; +static struct print_ops json_print_ops; +static struct json_object *json_r = NULL; + +static void d_json(unsigned char *buf, int len, int width, int group, struct json_object *array) +{ + int i; + char ascii[32 + 1] = { 0 }; + + assert(width < sizeof(ascii)); + + for (i = 0; i < len; i++) { + ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.'; + if (!((i + 1) % width)) { + array_add_str(array, ascii); + memset(ascii, 0, sizeof(ascii)); + } + } + + if (strlen(ascii)) { + ascii[i % width + 1] = '\0'; + array_add_str(array, ascii); + } +} + +static void obj_add_uint_x(struct json_object *o, const char *k, __u32 v) +{ + char str[STR_LEN]; + + sprintf(str, "%x", v); + obj_add_str(o, k, str); +} + +static void obj_add_uint_0x(struct json_object *o, const char *k, __u32 v) +{ + char str[STR_LEN]; + + sprintf(str, "0x%x", v); + obj_add_str(o, k, str); +} + +static void obj_add_uint_02x(struct json_object *o, const char *k, __u32 v) +{ + char str[STR_LEN]; + + sprintf(str, "0x%02x", v); + obj_add_str(o, k, str); +} + +static void obj_add_uint_nx(struct json_object *o, const char *k, __u32 v) +{ + char str[STR_LEN]; + + sprintf(str, "%#x", v); + obj_add_str(o, k, str); +} + +static void obj_add_nprix64(struct json_object *o, const char *k, uint64_t v) +{ + char str[STR_LEN]; + + sprintf(str, "%#"PRIx64"", v); + obj_add_str(o, k, str); +} + +static void obj_add_prix64(struct json_object *o, const char *k, uint64_t v) +{ + char str[STR_LEN]; + + sprintf(str, "%"PRIx64"", v); + obj_add_str(o, k, str); +} + +static void obj_add_int_secs(struct json_object *o, const char *k, int v) +{ + char str[STR_LEN]; + + sprintf(str, "%d secs", v); + obj_add_str(o, k, str); +} + +static void obj_add_result(struct json_object *o, const char *v, ...) +{ + va_list ap; + va_start(ap, v); + char *value; + + if (vasprintf(&value, v, ap) < 0) + value = NULL; + + if (value) + obj_add_str(o, "Result", value); + else + obj_add_str(o, "Result", "Could not allocate string"); + + free(value); +} + +static void obj_add_key(struct json_object *o, const char *k, const char *v, ...) +{ + va_list ap; + va_start(ap, v); + char *value; + + if (vasprintf(&value, v, ap) < 0) + value = NULL; + + if (value) + obj_add_str(o, k, value); + else + obj_add_str(o, k, "Could not allocate string"); + + free(value); +} + +static struct json_object *obj_create_array_obj(struct json_object *o, const char *k) +{ + struct json_object *array = json_create_array(); + struct json_object *obj = json_create_object(); + + obj_add_array(o, k, array); + array_add_obj(array, obj); + + return obj; +} + +static struct json_object *obj_create(const char *k) +{ + struct json_object *array; + struct json_object *obj = json_create_object(); + + if (json_r) { + array = json_create_array(); + obj_add_array(json_r, k, array); + array_add_obj(array, obj); + } + + return obj; +} + +static void json_print(struct json_object *r) +{ + json_print_object(r, NULL); + printf("\n"); + json_free_object(r); +} + +static void obj_print(struct json_object *o) +{ + if (!json_r) + json_print(o); +} + +static bool human(void) +{ + return json_print_ops.flags & VERBOSE; +} + +static void json_id_iocs(struct nvme_id_iocs *iocs) +{ + struct json_object *r = json_create_object(); + char json_str[STR_LEN]; + __u16 i; + + for (i = 0; i < ARRAY_SIZE(iocs->iocsc); i++) { + if (iocs->iocsc[i]) { + sprintf(json_str, "I/O Command Set Combination[%u]", i); + obj_add_uint64(r, json_str, le64_to_cpu(iocs->iocsc[i])); + } + } + + json_print(r); +} + +static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int nsid, + unsigned int lba_index, bool cap_only) +{ + char nguid_buf[2 * sizeof(ns->nguid) + 1], + eui64_buf[2 * sizeof(ns->eui64) + 1]; + char *nguid = nguid_buf, *eui64 = eui64_buf; + struct json_object *r = json_create_object(); + struct json_object *lbafs = json_create_array(); + struct json_object *vs = json_create_array(); + int i; + nvme_uint128_t nvmcap = le128_to_cpu(ns->nvmcap); + + if (!cap_only) { + obj_add_uint64(r, "nsze", le64_to_cpu(ns->nsze)); + obj_add_uint64(r, "ncap", le64_to_cpu(ns->ncap)); + obj_add_uint64(r, "nuse", le64_to_cpu(ns->nuse)); + obj_add_int(r, "nsfeat", ns->nsfeat); + } + + obj_add_int(r, "nlbaf", ns->nlbaf); + + if (!cap_only) + obj_add_int(r, "flbas", ns->flbas); + + obj_add_int(r, "mc", ns->mc); + obj_add_int(r, "dpc", ns->dpc); + + if (!cap_only) { + obj_add_int(r, "dps", ns->dps); + obj_add_int(r, "nmic", ns->nmic); + obj_add_int(r, "rescap", ns->rescap); + obj_add_int(r, "fpi", ns->fpi); + obj_add_int(r, "dlfeat", ns->dlfeat); + obj_add_int(r, "nawun", le16_to_cpu(ns->nawun)); + obj_add_int(r, "nawupf", le16_to_cpu(ns->nawupf)); + obj_add_int(r, "nacwu", le16_to_cpu(ns->nacwu)); + obj_add_int(r, "nabsn", le16_to_cpu(ns->nabsn)); + obj_add_int(r, "nabo", le16_to_cpu(ns->nabo)); + obj_add_int(r, "nabspf", le16_to_cpu(ns->nabspf)); + obj_add_int(r, "noiob", le16_to_cpu(ns->noiob)); + obj_add_uint128(r, "nvmcap", nvmcap); + obj_add_int(r, "nsattr", ns->nsattr); + obj_add_int(r, "nvmsetid", le16_to_cpu(ns->nvmsetid)); + + if (ns->nsfeat & 0x10) { + obj_add_int(r, "npwg", le16_to_cpu(ns->npwg)); + obj_add_int(r, "npwa", le16_to_cpu(ns->npwa)); + obj_add_int(r, "npdg", le16_to_cpu(ns->npdg)); + obj_add_int(r, "npda", le16_to_cpu(ns->npda)); + obj_add_int(r, "nows", le16_to_cpu(ns->nows)); + } + + obj_add_int(r, "mssrl", le16_to_cpu(ns->mssrl)); + obj_add_uint(r, "mcl", le32_to_cpu(ns->mcl)); + obj_add_int(r, "msrc", ns->msrc); + } + + obj_add_int(r, "nulbaf", ns->nulbaf); + + if (!cap_only) { + obj_add_uint(r, "anagrpid", le32_to_cpu(ns->anagrpid)); + obj_add_int(r, "endgid", le16_to_cpu(ns->endgid)); + + memset(eui64, 0, sizeof(eui64_buf)); + + for (i = 0; i < sizeof(ns->eui64); i++) + eui64 += sprintf(eui64, "%02x", ns->eui64[i]); + + memset(nguid, 0, sizeof(nguid_buf)); + + for (i = 0; i < sizeof(ns->nguid); i++) + nguid += sprintf(nguid, "%02x", ns->nguid[i]); + + obj_add_str(r, "eui64", eui64_buf); + obj_add_str(r, "nguid", nguid_buf); + } + + obj_add_array(r, "lbafs", lbafs); + + for (i = 0; i <= ns->nlbaf; i++) { + struct json_object *lbaf = json_create_object(); + + obj_add_int(lbaf, "ms", le16_to_cpu(ns->lbaf[i].ms)); + obj_add_int(lbaf, "ds", ns->lbaf[i].ds); + obj_add_int(lbaf, "rp", ns->lbaf[i].rp); + + array_add_obj(lbafs, lbaf); + } + + d_json(ns->vs, strnlen((const char *)ns->vs, sizeof(ns->vs)), 16, 1, vs); + obj_add_array(r, "vs", vs); + + json_print(r); +} + + void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, + void (*vs)(__u8 *vs, struct json_object *r)) +{ + struct json_object *r = json_create_object(); + struct json_object *psds = json_create_array(); + nvme_uint128_t tnvmcap = le128_to_cpu(ctrl->tnvmcap); + nvme_uint128_t unvmcap = le128_to_cpu(ctrl->unvmcap); + nvme_uint128_t megcap = le128_to_cpu(ctrl->megcap); + nvme_uint128_t maxdna = le128_to_cpu(ctrl->maxdna); + char sn[sizeof(ctrl->sn) + 1], mn[sizeof(ctrl->mn) + 1], + fr[sizeof(ctrl->fr) + 1], subnqn[sizeof(ctrl->subnqn) + 1]; + __u32 ieee = ctrl->ieee[2] << 16 | ctrl->ieee[1] << 8 | ctrl->ieee[0]; + int i; + + snprintf(sn, sizeof(sn), "%-.*s", (int)sizeof(ctrl->sn), ctrl->sn); + snprintf(mn, sizeof(mn), "%-.*s", (int)sizeof(ctrl->mn), ctrl->mn); + snprintf(fr, sizeof(fr), "%-.*s", (int)sizeof(ctrl->fr), ctrl->fr); + snprintf(subnqn, sizeof(subnqn), "%-.*s", (int)sizeof(ctrl->subnqn), ctrl->subnqn); + + obj_add_int(r, "vid", le16_to_cpu(ctrl->vid)); + obj_add_int(r, "ssvid", le16_to_cpu(ctrl->ssvid)); + obj_add_str(r, "sn", sn); + obj_add_str(r, "mn", mn); + obj_add_str(r, "fr", fr); + obj_add_int(r, "rab", ctrl->rab); + obj_add_int(r, "ieee", ieee); + obj_add_int(r, "cmic", ctrl->cmic); + obj_add_int(r, "mdts", ctrl->mdts); + obj_add_int(r, "cntlid", le16_to_cpu(ctrl->cntlid)); + obj_add_uint(r, "ver", le32_to_cpu(ctrl->ver)); + obj_add_uint(r, "rtd3r", le32_to_cpu(ctrl->rtd3r)); + obj_add_uint(r, "rtd3e", le32_to_cpu(ctrl->rtd3e)); + obj_add_uint(r, "oaes", le32_to_cpu(ctrl->oaes)); + obj_add_uint(r, "ctratt", le32_to_cpu(ctrl->ctratt)); + obj_add_int(r, "rrls", le16_to_cpu(ctrl->rrls)); + obj_add_int(r, "cntrltype", ctrl->cntrltype); + obj_add_str(r, "fguid", util_uuid_to_string(ctrl->fguid)); + obj_add_int(r, "crdt1", le16_to_cpu(ctrl->crdt1)); + obj_add_int(r, "crdt2", le16_to_cpu(ctrl->crdt2)); + obj_add_int(r, "crdt3", le16_to_cpu(ctrl->crdt3)); + obj_add_int(r, "nvmsr", ctrl->nvmsr); + obj_add_int(r, "vwci", ctrl->vwci); + obj_add_int(r, "mec", ctrl->mec); + obj_add_int(r, "oacs", le16_to_cpu(ctrl->oacs)); + obj_add_int(r, "acl", ctrl->acl); + obj_add_int(r, "aerl", ctrl->aerl); + obj_add_int(r, "frmw", ctrl->frmw); + obj_add_int(r, "lpa", ctrl->lpa); + obj_add_int(r, "elpe", ctrl->elpe); + obj_add_int(r, "npss", ctrl->npss); + obj_add_int(r, "avscc", ctrl->avscc); + obj_add_int(r, "apsta", ctrl->apsta); + obj_add_int(r, "wctemp", le16_to_cpu(ctrl->wctemp)); + obj_add_int(r, "cctemp", le16_to_cpu(ctrl->cctemp)); + obj_add_int(r, "mtfa", le16_to_cpu(ctrl->mtfa)); + obj_add_uint(r, "hmpre", le32_to_cpu(ctrl->hmpre)); + obj_add_uint(r, "hmmin", le32_to_cpu(ctrl->hmmin)); + obj_add_uint128(r, "tnvmcap", tnvmcap); + obj_add_uint128(r, "unvmcap", unvmcap); + obj_add_uint(r, "rpmbs", le32_to_cpu(ctrl->rpmbs)); + obj_add_int(r, "edstt", le16_to_cpu(ctrl->edstt)); + obj_add_int(r, "dsto", ctrl->dsto); + obj_add_int(r, "fwug", ctrl->fwug); + obj_add_int(r, "kas", le16_to_cpu(ctrl->kas)); + obj_add_int(r, "hctma", le16_to_cpu(ctrl->hctma)); + obj_add_int(r, "mntmt", le16_to_cpu(ctrl->mntmt)); + obj_add_int(r, "mxtmt", le16_to_cpu(ctrl->mxtmt)); + obj_add_uint(r, "sanicap", le32_to_cpu(ctrl->sanicap)); + obj_add_uint(r, "hmminds", le32_to_cpu(ctrl->hmminds)); + obj_add_int(r, "hmmaxd", le16_to_cpu(ctrl->hmmaxd)); + obj_add_int(r, "nsetidmax", le16_to_cpu(ctrl->nsetidmax)); + obj_add_int(r, "endgidmax", le16_to_cpu(ctrl->endgidmax)); + obj_add_int(r, "anatt",ctrl->anatt); + obj_add_int(r, "anacap", ctrl->anacap); + obj_add_uint(r, "anagrpmax", le32_to_cpu(ctrl->anagrpmax)); + obj_add_uint(r, "nanagrpid", le32_to_cpu(ctrl->nanagrpid)); + obj_add_uint(r, "pels", le32_to_cpu(ctrl->pels)); + obj_add_int(r, "domainid", le16_to_cpu(ctrl->domainid)); + obj_add_uint128(r, "megcap", megcap); + obj_add_int(r, "sqes", ctrl->sqes); + obj_add_int(r, "cqes", ctrl->cqes); + obj_add_int(r, "maxcmd", le16_to_cpu(ctrl->maxcmd)); + obj_add_uint(r, "nn", le32_to_cpu(ctrl->nn)); + obj_add_int(r, "oncs", le16_to_cpu(ctrl->oncs)); + obj_add_int(r, "fuses", le16_to_cpu(ctrl->fuses)); + obj_add_int(r, "fna", ctrl->fna); + obj_add_int(r, "vwc", ctrl->vwc); + obj_add_int(r, "awun", le16_to_cpu(ctrl->awun)); + obj_add_int(r, "awupf", le16_to_cpu(ctrl->awupf)); + obj_add_int(r, "icsvscc", ctrl->icsvscc); + obj_add_int(r, "nwpc", ctrl->nwpc); + obj_add_int(r, "acwu", le16_to_cpu(ctrl->acwu)); + obj_add_int(r, "ocfs", le16_to_cpu(ctrl->ocfs)); + obj_add_uint(r, "sgls", le32_to_cpu(ctrl->sgls)); + obj_add_uint(r, "mnan", le32_to_cpu(ctrl->mnan)); + obj_add_uint128(r, "maxdna", maxdna); + obj_add_uint(r, "maxcna", le32_to_cpu(ctrl->maxcna)); + obj_add_uint(r, "oaqd", le32_to_cpu(ctrl->oaqd)); + + if (strlen(subnqn)) + obj_add_str(r, "subnqn", subnqn); + + obj_add_uint(r, "ioccsz", le32_to_cpu(ctrl->ioccsz)); + obj_add_uint(r, "iorcsz", le32_to_cpu(ctrl->iorcsz)); + obj_add_int(r, "icdoff", le16_to_cpu(ctrl->icdoff)); + obj_add_int(r, "fcatt", ctrl->fcatt); + obj_add_int(r, "msdbd", ctrl->msdbd); + obj_add_int(r, "ofcs", le16_to_cpu(ctrl->ofcs)); + + obj_add_array(r, "psds", psds); + + for (i = 0; i <= ctrl->npss; i++) { + struct json_object *psd = json_create_object(); + + obj_add_int(psd, "max_power", le16_to_cpu(ctrl->psd[i].mp)); + obj_add_int(psd, "max_power_scale", ctrl->psd[i].flags & 0x1); + obj_add_int(psd, "non-operational_state", (ctrl->psd[i].flags & 2) >> 1); + obj_add_uint(psd, "entry_lat", le32_to_cpu(ctrl->psd[i].enlat)); + obj_add_uint(psd, "exit_lat", le32_to_cpu(ctrl->psd[i].exlat)); + obj_add_int(psd, "read_tput", ctrl->psd[i].rrt); + obj_add_int(psd, "read_lat", ctrl->psd[i].rrl); + obj_add_int(psd, "write_tput", ctrl->psd[i].rwt); + obj_add_int(psd, "write_lat", ctrl->psd[i].rwl); + obj_add_int(psd, "idle_power", le16_to_cpu(ctrl->psd[i].idlp)); + obj_add_int(psd, "idle_scale", nvme_psd_power_scale(ctrl->psd[i].ips)); + obj_add_int(psd, "active_power", le16_to_cpu(ctrl->psd[i].actp)); + obj_add_int(psd, "active_power_work", ctrl->psd[i].apws & 7); + obj_add_int(psd, "active_scale", nvme_psd_power_scale(ctrl->psd[i].apws)); + + array_add_obj(psds, psd); + } + + if(vs) + vs(ctrl->vs, r); + + json_print(r); +} + +static void json_error_log(struct nvme_error_log_page *err_log, int entries, + const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *errors = json_create_array(); + int i; + + obj_add_array(r, "errors", errors); + + for (i = 0; i < entries; i++) { + struct json_object *error = json_create_object(); + + obj_add_uint64(error, "error_count", le64_to_cpu(err_log[i].error_count)); + obj_add_int(error, "sqid", le16_to_cpu(err_log[i].sqid)); + obj_add_int(error, "cmdid", le16_to_cpu(err_log[i].cmdid)); + obj_add_int(error, "status_field", le16_to_cpu(err_log[i].status_field >> 0x1)); + obj_add_int(error, "phase_tag", le16_to_cpu(err_log[i].status_field & 0x1)); + obj_add_int(error, "parm_error_location", + le16_to_cpu(err_log[i].parm_error_location)); + obj_add_uint64(error, "lba", le64_to_cpu(err_log[i].lba)); + obj_add_uint(error, "nsid", le32_to_cpu(err_log[i].nsid)); + obj_add_int(error, "vs", err_log[i].vs); + obj_add_int(error, "trtype", err_log[i].trtype); + obj_add_uint64(error, "cs", le64_to_cpu(err_log[i].cs)); + obj_add_int(error, "trtype_spec_info", le16_to_cpu(err_log[i].trtype_spec_info)); + + array_add_obj(errors, error); + } + + json_print(r); +} + +void json_nvme_resv_report(struct nvme_resv_status *status, + int bytes, bool eds) +{ + struct json_object *r = json_create_object(); + struct json_object *rcs = json_create_array(); + int i, j, entries; + int regctl = status->regctl[0] | (status->regctl[1] << 8); + + obj_add_uint(r, "gen", le32_to_cpu(status->gen)); + obj_add_int(r, "rtype", status->rtype); + obj_add_int(r, "regctl", regctl); + obj_add_int(r, "ptpls", status->ptpls); + + /* check Extended Data Structure bit */ + if (!eds) { + /* + * if status buffer was too small, don't loop past the end of + * the buffer + */ + entries = (bytes - 24) / 24; + if (entries < regctl) + regctl = entries; + + obj_add_array(r, "regctls", rcs); + for (i = 0; i < regctl; i++) { + struct json_object *rc = json_create_object(); + + obj_add_int(rc, "cntlid", le16_to_cpu(status->regctl_ds[i].cntlid)); + obj_add_int(rc, "rcsts", status->regctl_ds[i].rcsts); + obj_add_uint64(rc, "hostid", le64_to_cpu(status->regctl_ds[i].hostid)); + obj_add_uint64(rc, "rkey", le64_to_cpu(status->regctl_ds[i].rkey)); + + array_add_obj(rcs, rc); + } + } else { + char hostid[33]; + + /* if status buffer was too small, don't loop past the end of the buffer */ + entries = (bytes - 64) / 64; + + if (entries < regctl) + regctl = entries; + + obj_add_array(r, "regctlext", rcs); + + for (i = 0; i < regctl; i++) { + struct json_object *rc = json_create_object(); + + obj_add_int(rc, "cntlid", le16_to_cpu(status->regctl_eds[i].cntlid)); + obj_add_int(rc, "rcsts", status->regctl_eds[i].rcsts); + obj_add_uint64(rc, "rkey", le64_to_cpu(status->regctl_eds[i].rkey)); + + for (j = 0; j < 16; j++) + sprintf(hostid + j * 2, "%02x", status->regctl_eds[i].hostid[j]); + + obj_add_str(rc, "hostid", hostid); + array_add_obj(rcs, rc); + } + } + + json_print(r); +} + +void json_fw_log(struct nvme_firmware_slot *fw_log, const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *fwsi = json_create_object(); + char fmt[21]; + char str[32]; + int i; + __le64 *frs; + + obj_add_int(fwsi, "Active Firmware Slot (afi)", fw_log->afi); + + for (i = 0; i < 7; i++) { + if (fw_log->frs[i][0]) { + snprintf(fmt, sizeof(fmt), "Firmware Rev Slot %d", + i + 1); + frs = (__le64 *)&fw_log->frs[i]; + snprintf(str, sizeof(str), "%"PRIu64" (%s)", + le64_to_cpu(*frs), + util_fw_to_string(fw_log->frs[i])); + obj_add_str(fwsi, fmt, str); + } + } + + obj_add_obj(r, devname, fwsi); + + json_print(r); +} + +void json_changed_ns_list_log(struct nvme_ns_list *log, + const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *nsi = json_create_object(); + char fmt[32]; + char str[32]; + __u32 nsid; + int i; + + if (log->ns[0] == cpu_to_le32(0xffffffff)) + return; + + obj_add_str(r, "Changed Namespace List Log", devname); + + for (i = 0; i < NVME_ID_NS_LIST_MAX; i++) { + nsid = le32_to_cpu(log->ns[i]); + + if (nsid == 0) + break; + + snprintf(fmt, sizeof(fmt), "[%4u]", i + 1); + snprintf(str, sizeof(str), "%#x", nsid); + obj_add_str(nsi, fmt, str); + } + + obj_add_obj(r, devname, nsi); + + json_print(r); +} + +static void json_endurance_log(struct nvme_endurance_group_log *endurance_group, __u16 group_id, + const char *devname) +{ + struct json_object *r = json_create_object(); + nvme_uint128_t endurance_estimate = le128_to_cpu(endurance_group->endurance_estimate); + nvme_uint128_t data_units_read = le128_to_cpu(endurance_group->data_units_read); + nvme_uint128_t data_units_written = le128_to_cpu(endurance_group->data_units_written); + nvme_uint128_t media_units_written = le128_to_cpu(endurance_group->media_units_written); + nvme_uint128_t host_read_cmds = le128_to_cpu(endurance_group->host_read_cmds); + nvme_uint128_t host_write_cmds = le128_to_cpu(endurance_group->host_write_cmds); + nvme_uint128_t media_data_integrity_err = + le128_to_cpu(endurance_group->media_data_integrity_err); + nvme_uint128_t num_err_info_log_entries = + le128_to_cpu(endurance_group->num_err_info_log_entries); + nvme_uint128_t total_end_grp_cap = le128_to_cpu(endurance_group->total_end_grp_cap); + nvme_uint128_t unalloc_end_grp_cap = le128_to_cpu(endurance_group->unalloc_end_grp_cap); + + obj_add_int(r, "critical_warning", endurance_group->critical_warning); + obj_add_int(r, "endurance_group_features", endurance_group->endurance_group_features); + obj_add_int(r, "avl_spare", endurance_group->avl_spare); + obj_add_int(r, "avl_spare_threshold", endurance_group->avl_spare_threshold); + obj_add_int(r, "percent_used", endurance_group->percent_used); + obj_add_int(r, "domain_identifier", endurance_group->domain_identifier); + obj_add_uint128(r, "endurance_estimate", endurance_estimate); + obj_add_uint128(r, "data_units_read", data_units_read); + obj_add_uint128(r, "data_units_written", data_units_written); + obj_add_uint128(r, "media_units_written", media_units_written); + obj_add_uint128(r, "host_read_cmds", host_read_cmds); + obj_add_uint128(r, "host_write_cmds", host_write_cmds); + obj_add_uint128(r, "media_data_integrity_err", media_data_integrity_err); + obj_add_uint128(r, "num_err_info_log_entries", num_err_info_log_entries); + obj_add_uint128(r, "total_end_grp_cap", total_end_grp_cap); + obj_add_uint128(r, "unalloc_end_grp_cap", unalloc_end_grp_cap); + + json_print(r); +} + +static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid, + const char *devname) +{ + struct json_object *r = json_create_object(); + int c; + char key[21]; + unsigned int temperature = ((smart->temperature[1] << 8) | + smart->temperature[0]); + nvme_uint128_t data_units_read = le128_to_cpu(smart->data_units_read); + nvme_uint128_t data_units_written = le128_to_cpu(smart->data_units_written); + nvme_uint128_t host_read_commands = le128_to_cpu(smart->host_reads); + nvme_uint128_t host_write_commands = le128_to_cpu(smart->host_writes); + nvme_uint128_t controller_busy_time = le128_to_cpu(smart->ctrl_busy_time); + nvme_uint128_t power_cycles = le128_to_cpu(smart->power_cycles); + nvme_uint128_t power_on_hours = le128_to_cpu(smart->power_on_hours); + nvme_uint128_t unsafe_shutdowns = le128_to_cpu(smart->unsafe_shutdowns); + nvme_uint128_t media_errors = le128_to_cpu(smart->media_errors); + nvme_uint128_t num_err_log_entries = le128_to_cpu(smart->num_err_log_entries); + + if (human()) { + struct json_object *crt = json_create_object(); + + obj_add_int(crt, "value", smart->critical_warning); + obj_add_int(crt, "available_spare", smart->critical_warning & 1); + obj_add_int(crt, "temp_threshold", (smart->critical_warning & 2) >> 1); + obj_add_int(crt, "reliability_degraded", (smart->critical_warning & 4) >> 2); + obj_add_int(crt, "ro", (smart->critical_warning & 8) >> 3); + obj_add_int(crt, "vmbu_failed", (smart->critical_warning & 0x10) >> 4); + obj_add_int(crt, "pmr_ro", (smart->critical_warning & 0x20) >> 5); + + obj_add_obj(r, "critical_warning", crt); + } else { + obj_add_int(r, "critical_warning", smart->critical_warning); + } + + obj_add_int(r, "temperature", temperature); + obj_add_int(r, "avail_spare", smart->avail_spare); + obj_add_int(r, "spare_thresh", smart->spare_thresh); + obj_add_int(r, "percent_used", smart->percent_used); + obj_add_int(r, "endurance_grp_critical_warning_summary", smart->endu_grp_crit_warn_sumry); + obj_add_uint128(r, "data_units_read", data_units_read); + obj_add_uint128(r, "data_units_written", data_units_written); + obj_add_uint128(r, "host_read_commands", host_read_commands); + obj_add_uint128(r, "host_write_commands", host_write_commands); + obj_add_uint128(r, "controller_busy_time", controller_busy_time); + obj_add_uint128(r, "power_cycles", power_cycles); + obj_add_uint128(r, "power_on_hours", power_on_hours); + obj_add_uint128(r, "unsafe_shutdowns", unsafe_shutdowns); + obj_add_uint128(r, "media_errors", media_errors); + obj_add_uint128(r, "num_err_log_entries", num_err_log_entries); + obj_add_uint(r, "warning_temp_time", le32_to_cpu(smart->warning_temp_time)); + obj_add_uint(r, "critical_comp_time", le32_to_cpu(smart->critical_comp_time)); + + for (c = 0; c < 8; c++) { + __s32 temp = le16_to_cpu(smart->temp_sensor[c]); + + if (temp == 0) + continue; + + sprintf(key, "temperature_sensor_%d",c+1); + obj_add_int(r, key, temp); + } + + obj_add_uint(r, "thm_temp1_trans_count", le32_to_cpu(smart->thm_temp1_trans_count)); + obj_add_uint(r, "thm_temp2_trans_count", le32_to_cpu(smart->thm_temp2_trans_count)); + obj_add_uint(r, "thm_temp1_total_time", le32_to_cpu(smart->thm_temp1_total_time)); + obj_add_uint(r, "thm_temp2_total_time", le32_to_cpu(smart->thm_temp2_total_time)); + + json_print(r); +} + +static void json_ana_log(struct nvme_ana_log *ana_log, const char *devname, + size_t len) +{ + int offset = sizeof(struct nvme_ana_log); + struct nvme_ana_log *hdr = ana_log; + struct nvme_ana_group_desc *ana_desc; + struct json_object *desc_list = json_create_array(); + struct json_object *ns_list; + struct json_object *desc; + struct json_object *nsid; + struct json_object *r = json_create_object(); + size_t nsid_buf_size; + void *base = ana_log; + __u32 nr_nsids; + int i, j; + + obj_add_str(r, "Asymmetric Namespace Access Log for NVMe device", devname); + obj_add_uint64(r, "chgcnt", le64_to_cpu(hdr->chgcnt)); + obj_add_uint(r, "ngrps", le16_to_cpu(hdr->ngrps)); + + for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) { + desc = json_create_object(); + ana_desc = base + offset; + nr_nsids = le32_to_cpu(ana_desc->nnsids); + nsid_buf_size = nr_nsids * sizeof(__le32); + + offset += sizeof(*ana_desc); + obj_add_uint(desc, "grpid", le32_to_cpu(ana_desc->grpid)); + obj_add_uint(desc, "nnsids", le32_to_cpu(ana_desc->nnsids)); + obj_add_uint64(desc, "chgcnt", le64_to_cpu(ana_desc->chgcnt)); + obj_add_str(desc, "state", nvme_ana_state_to_string(ana_desc->state)); + + ns_list = json_create_array(); + for (j = 0; j < le32_to_cpu(ana_desc->nnsids); j++) { + nsid = json_create_object(); + obj_add_uint(nsid, "nsid", le32_to_cpu(ana_desc->nsids[j])); + array_add_obj(ns_list, nsid); + } + obj_add_array(desc, "NSIDS", ns_list); + offset += nsid_buf_size; + array_add_obj(desc_list, desc); + } + + obj_add_array(r, "ANA DESC LIST ", desc_list); + + json_print(r); +} + +static void json_select_result(enum nvme_features_id fid, __u32 result) +{ + struct json_object *r = json_r ? json_r : json_create_object(); + char json_str[STR_LEN]; + struct json_object *feature = json_create_array(); + + if (result & 0x1) + array_add_str(feature, "saveable"); + if (result & 0x2) + array_add_str(feature, "per-namespace"); + if (result & 0x4) + array_add_str(feature, "changeable"); + + sprintf(json_str, "Feature: %#0*x: select", fid ? 4 : 2, fid); + obj_add_array(r, json_str, feature); + + obj_print(r); +} + +static void json_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries, + __u32 size, const char *devname) +{ + struct json_object *valid_attrs; + struct json_object *r = json_create_object(); + struct json_object *valid = json_create_array(); + int i; + __u32 num_entries = min(dst_entries, NVME_LOG_ST_MAX_RESULTS); + + obj_add_int(r, "Current Device Self-Test Operation", self_test->current_operation); + obj_add_int(r, "Current Device Self-Test Completion", self_test->completion); + + for (i = 0; i < num_entries; i++) { + valid_attrs = json_create_object(); + obj_add_int(valid_attrs, "Self test result", self_test->result[i].dsts & 0xf); + + if ((self_test->result[i].dsts & 0xf) == 0xf) + goto add; + + obj_add_int(valid_attrs, "Self test code", + self_test->result[i].dsts >> 4); + obj_add_int(valid_attrs, "Segment number", + self_test->result[i].seg); + obj_add_int(valid_attrs, "Valid Diagnostic Information", + self_test->result[i].vdi); + obj_add_uint64(valid_attrs, "Power on hours", + le64_to_cpu(self_test->result[i].poh)); + + if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_NSID) + obj_add_uint(valid_attrs, "Namespace Identifier", + le32_to_cpu(self_test->result[i].nsid)); + + if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_FLBA) + obj_add_uint64(valid_attrs, "Failing LBA", + le64_to_cpu(self_test->result[i].flba)); + + if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SCT) + obj_add_int(valid_attrs, "Status Code Type", self_test->result[i].sct); + + if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SC) + obj_add_int(valid_attrs, "Status Code", self_test->result[i].sc); + + obj_add_int(valid_attrs, "Vendor Specific", + self_test->result[i].vs[1] << 8 | self_test->result[i].vs[0]); + +add: + array_add_obj(valid, valid_attrs); + } + + obj_add_array(r, "List of Valid Reports", valid); + + json_print(r); +} + +static void json_registers_cap(struct nvme_bar_cap *cap, struct json_object *r) +{ + char json_str[STR_LEN]; + struct json_object *cssa = json_create_array(); + struct json_object *csso = json_create_object(); + struct json_object *amsa = json_create_array(); + struct json_object *amso = json_create_object(); + + sprintf(json_str, "%"PRIx64"", *(uint64_t *)cap); + obj_add_str(r, "cap", json_str); + + obj_add_str(r, "Controller Ready With Media Support (CRWMS)", + cap->crwms ? "Supported" : "Not supported"); + obj_add_str(r, "Controller Ready Independent of Media Support (CRIMS)", + cap->crims ? "Supported" : "Not supported"); + obj_add_str(r, "NVM Subsystem Shutdown Supported (NSSS)", + cap->nsss ? "Supported" : "Not supported"); + obj_add_str(r, "Controller Memory Buffer Supported (CMBS):", + cap->cmbs ? "Supported" : "Not supported"); + obj_add_str(r, "Persistent Memory Region Supported (PMRS)", + cap->pmrs ? "Supported" : "Not supported"); + + sprintf(json_str, "%u bytes", 1 << (12 + cap->mpsmax)); + obj_add_str(r, "Memory Page Size Maximum (MPSMAX)", json_str); + + sprintf(json_str, "%u bytes", 1 << (12 + cap->mpsmin)); + obj_add_str(r, "Memory Page Size Minimum (MPSMIN)", json_str); + + obj_add_str(r, "Controller Power Scope (CPS)", !cap->cps ? "Not Reported" : cap->cps == 1 ? + "Controller scope" : cap->cps == 2 ? "Domain scope" : "NVM subsystem scope"); + obj_add_str(r, "Boot Partition Support (BPS)", cap->bps ? "Yes" : "No"); + + obj_add_array(r, "Command Sets Supported (CSS)", cssa); + obj_add_str(csso, "NVM command set", cap->css & 1 ? "Supported" : "Not supported"); + obj_add_str(csso, "One or more I/O Command Sets", + cap->css & 0x40 ? "Supported" : "Not supported"); + obj_add_str(csso, cap->css & 0x80 ? "Only Admin Command Set" : "I/O Command Set", + "Supported"); + array_add_obj(cssa, csso); + + obj_add_str(r, "NVM Subsystem Reset Supported (NSSRS)", cap->nssrs ? "Yes" : "No"); + + sprintf(json_str, "%u bytes", 1 << (2 + cap->dstrd)); + obj_add_str(r, "Doorbell Stride (DSTRD)", json_str); + + sprintf(json_str, "%u ms", MS500_TO_MS(cap->to)); + obj_add_str(r, "Timeout (TO)", json_str); + + obj_add_array(r, "Arbitration Mechanism Supported (AMS)", amsa); + obj_add_str(amso, "Weighted Round Robin with Urgent Priority Class", + cap->ams & 2 ? "Supported" : "Not supported"); + array_add_obj(amsa, amso); + + obj_add_str(r, "Contiguous Queues Required (CQR)", cap->cqr ? "Yes" : "No"); + obj_add_uint(r, "Maximum Queue Entries Supported (MQES)", cap->mqes + 1); +} + +static void json_registers_version(__u32 vs, struct json_object *r) +{ + char json_str[STR_LEN]; + + sprintf(json_str, "%x", vs); + obj_add_str(r, "Version", json_str); + + sprintf(json_str, "%d.%d", (vs & 0xffff0000) >> 16, (vs & 0x0000ff00) >> 8); + obj_add_str(r, "NVMe specification", json_str); +} + +static void json_registers_intms(__u32 intms, struct json_object *r) +{ + obj_add_uint_x(r, "intms", intms); + + obj_add_uint_x(r, "Interrupt Vector Mask Set (IVMS)", intms); +} + +static void json_registers_intmc(__u32 intmc, struct json_object *r) +{ + obj_add_uint_x(r, "intmc", intmc); + + obj_add_uint_x(r, "Interrupt Vector Mask Set (IVMC)", intmc); +} + +static void json_registers_cc_ams(__u8 ams, struct json_object *r) +{ + char json_str[STR_LEN]; + + switch (ams) { + case 0: + sprintf(json_str, "Round Robin"); + break; + case 1: + sprintf(json_str, "Weighted Round Robin with Urgent Priority Class"); + break; + case 7: + sprintf(json_str, "Vendor Specific"); + break; + default: + sprintf(json_str, "%s", "Reserved"); + break; + } + + obj_add_str(r, "Arbitration Mechanism Selected (AMS)", json_str); +} + +static void json_registers_cc_shn(__u8 shn, struct json_object *r) +{ + char json_str[STR_LEN]; + + switch (shn) { + case 0: + sprintf(json_str, "No notification; no effect"); + break; + case 1: + sprintf(json_str, "Normal shutdown notification"); + break; + case 2: + sprintf(json_str, "Abrupt shutdown notification"); + break; + default: + sprintf(json_str, "%s", "Reserved"); + break; + } + + obj_add_str(r, "Shutdown Notification (SHN)", json_str); +} + +static void json_registers_cc(__u32 cc, struct json_object *r) +{ + char json_str[STR_LEN]; + + sprintf(json_str, "%x", cc); + obj_add_str(r, "cc", json_str); + + obj_add_str(r, "Controller Ready Independent of Media Enable (CRIME)", + NVME_CC_CRIME(cc) ? "Enabled" : "Disabled"); + + sprintf(json_str, "%u bytes", POWER_OF_TWO(NVME_GET(cc, CC_IOCQES))); + obj_add_str(r, "I/O Completion Queue Entry Size (IOCQES): ", json_str); + + sprintf(json_str, "%u bytes", POWER_OF_TWO(NVME_GET(cc, CC_IOSQES))); + obj_add_str(r, "I/O Submission Queue Entry Size (IOSQES)", json_str); + + json_registers_cc_shn((cc & 0xc000) >> NVME_CC_SHN_SHIFT, r); + json_registers_cc_ams((cc & 0x3800) >> NVME_CC_AMS_SHIFT, r); + + sprintf(json_str, "%u bytes", POWER_OF_TWO(12 + NVME_GET(cc, CC_MPS))); + obj_add_str(r, "Memory Page Size (MPS)", json_str); + + obj_add_str(r, "I/O Command Set Selected (CSS)", (cc & 0x70) == 0x00 ? "NVM Command Set" : + (cc & 0x70) == 0x60 ? "All supported I/O Command Sets" : + (cc & 0x70) == 0x70 ? "Admin Command Set only" : "Reserved"); + obj_add_str(r, "Enable (EN)", cc & 1 ? "Yes" : "No"); +} + +static void json_registers_csts_shst(__u8 shst, struct json_object *r) +{ + char json_str[STR_LEN]; + + switch (shst) { + case 0: + sprintf(json_str, "Normal operation (no shutdown has been requested)"); + break; + case 1: + sprintf(json_str, "Shutdown processing occurring"); + break; + case 2: + sprintf(json_str, "Shutdown processing complete"); + break; + default: + sprintf(json_str, "%s", "Reserved"); + break; + } + + obj_add_str(r, "Shutdown Status (SHST)", json_str); +} + +static void json_registers_csts(__u32 csts, struct json_object *r) +{ + obj_add_uint_x(r, "csts", csts); + + obj_add_str(r, "Processing Paused (PP)", csts & 0x20 ? "Yes" : "No"); + obj_add_str(r, "NVM Subsystem Reset Occurred (NSSRO)", csts & 0x10 ? "Yes" : "No"); + + json_registers_csts_shst((csts & 0xc) >> 2, r); + + obj_add_str(r, "Controller Fatal Status (CFS)", csts & 2 ? "True" : "False"); + obj_add_str(r, "Ready (RDY)", csts & 1 ? "Yes" : "No"); +} + +static void json_registers_nssr(__u32 nssr, struct json_object *r) +{ + obj_add_uint_x(r, "nssr", nssr); + obj_add_uint(r, "NVM Subsystem Reset Control (NSSRC)", nssr); +} + +static void json_registers_nssd(__u32 nssd, struct json_object *r) +{ + obj_add_uint_nx(r, "NVM Subsystem Shutdown Control (NSSC)", nssd); +} + +static void json_registers_crto(__u32 crto, struct json_object *r) +{ + obj_add_uint_x(r, "crto", crto); + + obj_add_int_secs(r, "CRIMT", MS500_TO_SEC(NVME_CRTO_CRIMT(crto))); + obj_add_int_secs(r, "CRWMT", MS500_TO_SEC(NVME_CRTO_CRWMT(crto))); +} + +static void json_registers_aqa(uint32_t aqa, struct json_object *r) +{ + obj_add_uint_x(r, "aqa", aqa); + obj_add_uint(r, "Admin Completion Queue Size (ACQS)", ((aqa & 0xfff0000) >> 16) + 1); + obj_add_uint(r, "Admin Submission Queue Size (ASQS)", (aqa & 0xfff) + 1); +} + +static void json_registers_asq(uint64_t asq, struct json_object *r) +{ + obj_add_prix64(r, "asq", asq); + obj_add_prix64(r, "Admin Submission Queue Base (ASQB)", asq); +} + +static void json_registers_acq(uint64_t acq, struct json_object *r) +{ + obj_add_prix64(r, "acq", acq); + obj_add_prix64(r, "Admin Completion Queue Base (ACQB)", acq); +} + +static void json_registers_cmbloc(uint32_t cmbloc, void *bar, struct json_object *r) +{ + uint32_t cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); + + obj_add_uint_x(r, "cmbloc", cmbloc); + + if (!cmbsz) { + obj_add_result(r, "Controller Memory Buffer feature is not supported"); + return; + } + + obj_add_uint_0x(r, "Offset (OFST) (See cmbsz.szu for granularity)", + (cmbloc & 0xfffff000) >> 12); + obj_add_int(r, "CMB Queue Dword Alignment (CQDA)", (cmbloc & 0x100) >> 8); + obj_add_str(r, "CMB Data Metadata Mixed Memory Support (CDMMMS)", + (cmbloc & 0x00000080) >> 7 ? "Not enforced" : "Enforced"); + obj_add_str(r, "CMB Data Pointer and Command Independent Locations Support (CDPCILS)", + (cmbloc & 0x00000040) >> 6 ? "Not enforced" : "Enforced"); + obj_add_str(r, "CMB Data Pointer Mixed Locations Support (CDPMLS)", + (cmbloc & 0x00000020) >> 5 ? "Not enforced" : "Enforced"); + obj_add_str(r, "CMB Queue Physically Discontiguous Support (CQPDS)", + (cmbloc & 0x00000010) >> 4 ? "Not enforced" : "Enforced"); + obj_add_str(r, "CMB Queue Mixed Memory Support (CQMMS)", + (cmbloc & 0x00000008) >> 3 ? "Not enforced" : "Enforced"); + obj_add_uint_0x(r, "Base Indicator Register (BIR)", (cmbloc & 0x00000007)); +} + +static void json_registers_cmbsz(uint32_t cmbsz, struct json_object *r) +{ + obj_add_uint_x(r, "cmbsz", cmbsz); + + if (!cmbsz) { + obj_add_result(r, "Controller Memory Buffer feature is not supported"); + return; + } + + obj_add_uint(r, "Size (SZ)", (cmbsz & 0xfffff000) >> 12); + obj_add_str(r, "Size Units (SZU)", nvme_register_szu_to_string((cmbsz & 0xf00) >> 8)); + obj_add_str(r, "Write Data Support (WDS)", cmbsz & 0x10 ? "Supported" : "Not supported"); + obj_add_str(r, "Read Data Support (RDS)", cmbsz & 8 ? "Supported" : "Not supported"); + obj_add_str(r, "PRP SGL List Support (LISTS)", cmbsz & 4 ? "Supported" : "Not supported"); + obj_add_str(r, "Completion Queue Support (CQS)", cmbsz & 2 ? "Supported" : "Not supported"); + obj_add_str(r, "Submission Queue Support (SQS)", cmbsz & 1 ? "Supported" : "Not supported"); +} + +static void json_registers_bpinfo_brs(__u8 brs, struct json_object *r) +{ + char json_str[STR_LEN]; + + switch (brs) { + case 0: + sprintf(json_str, "No Boot Partition read operation requested"); + break; + case 1: + sprintf(json_str, "Boot Partition read in progress"); + break; + case 2: + sprintf(json_str, "Boot Partition read completed successfully"); + break; + case 3: + sprintf(json_str, "Error completing Boot Partition read"); + break; + default: + sprintf(json_str, "%s", "Invalid"); + break; + } + + obj_add_str(r, "Boot Read Status (BRS)", json_str); +} + +static void json_registers_bpinfo(uint32_t bpinfo, struct json_object *r) +{ + obj_add_uint_x(r, "bpinfo", bpinfo); + + obj_add_uint(r, "Active Boot Partition ID (ABPID)", (bpinfo & 0x80000000) >> 31); + json_registers_bpinfo_brs((bpinfo & 0x3000000) >> 24, r); + obj_add_uint(r, "Boot Partition Size (BPSZ)", bpinfo & 0x7fff); +} + +static void json_registers_bprsel(uint32_t bprsel, struct json_object *r) +{ + obj_add_uint_x(r, "bprsel", bprsel); + + obj_add_uint(r, "Boot Partition Identifier (BPID)", (bprsel & 0x80000000) >> 31); + obj_add_uint_x(r, "Boot Partition Read Offset (BPROF)", (bprsel & 0x3ffffc00) >> 10); + obj_add_uint_x(r, "Boot Partition Read Size (BPRSZ)", bprsel & 0x3ff); +} + +static void json_registers_bpmbl(uint64_t bpmbl, struct json_object *r) +{ + obj_add_prix64(r, "bpmbl", bpmbl); + + obj_add_prix64(r, "Boot Partition Memory Buffer Base Address (BMBBA)", bpmbl); +} + +static void json_registers_cmbmsc(uint64_t cmbmsc, struct json_object *r) +{ + obj_add_prix64(r, "cmbmsc", cmbmsc); + + obj_add_prix64(r, "Controller Base Address (CBA)", (cmbmsc & 0xfffffffffffff000) >> 12); + obj_add_prix64(r, "Controller Memory Space Enable (CMSE)", (cmbmsc & 2) >> 1); + obj_add_str(r, "Capabilities Registers Enabled (CRE)", + cmbmsc & 1 ? "Enabled" : "Not enabled"); +} + +static void json_registers_cmbsts(uint32_t cmbsts , struct json_object *r) +{ + obj_add_uint_x(r, "cmbsts", cmbsts); + + obj_add_uint_x(r, "Controller Base Address Invalid (CBAI)", cmbsts & 1); +} + +static void json_registers_pmrcap(uint32_t pmrcap, struct json_object *r) +{ + obj_add_uint_x(r, "pmrcap", pmrcap); + + obj_add_str(r, "Controller Memory Space Supported (CMSS)", + ((pmrcap & 0x01000000) >> 24) ? "Supported" : "Not supported"); + obj_add_uint_x(r, "Persistent Memory Region Timeout (PMRTO)", (pmrcap & 0xff0000) >> 16); + obj_add_uint_x(r, "Persistent Memory Region Write Barrier Mechanisms (PMRWBM)", + (pmrcap & 0x3c00) >> 10); + obj_add_str(r, "Persistent Memory Region Time Units (PMRTU)", + (pmrcap & 0x300) >> 8 ? "minutes" : "500 milliseconds"); + obj_add_uint_x(r, "Base Indicator Register (BIR)", (pmrcap & 0xe0) >> 5); + obj_add_str(r, "Write Data Support (WDS)", pmrcap & 0x10 ? "Supported" : "Not supported"); + obj_add_str(r, "Read Data Support (RDS)", pmrcap & 8 ? "Supported" : "Not supported"); +} + +static void json_registers_pmrctl(uint32_t pmrctl, struct json_object *r) +{ + obj_add_uint_x(r, "pmrctl", pmrctl); + + obj_add_str(r, "Enable (EN)", pmrctl & 1 ? "Ready" : "Disabled"); +} + +static void json_registers_pmrsts(uint32_t pmrsts, void *bar, struct json_object *r) +{ + uint32_t pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); + + obj_add_uint_x(r, "pmrsts", pmrsts); + + obj_add_uint_x(r, "Controller Base Address Invalid (CBAI)", (pmrsts & 0x1000) >> 12); + obj_add_str(r, "Health Status (HSTS)", + nvme_register_pmr_hsts_to_string((pmrsts & 0xe00) >> 9)); + obj_add_str(r, "Not Ready (NRDY)", + !(pmrsts & 0x100) && (pmrctl & 1) ? "Ready" : "Not ready"); + obj_add_uint_x(r, "Error (ERR)", pmrsts & 0xff); +} + +static void json_registers_pmrebs(uint32_t pmrebs, struct json_object *r) +{ + obj_add_uint_x(r, "pmrebs", pmrebs); + + obj_add_uint_x(r, "PMR Elasticity Buffer Size Base (PMRWBZ)", (pmrebs & 0xffffff00) >> 8); + obj_add_str(r, "Read Bypass Behavior", pmrebs & 0x10 ? "Shall" : "May"); + obj_add_str(r, "PMR Elasticity Buffer Size Units (PMRSZU)", + nvme_register_pmr_pmrszu_to_string(pmrebs & 0xf)); +} + +static void json_registers_pmrswtp(uint32_t pmrswtp, struct json_object *r) +{ + obj_add_uint_x(r, "pmrswtp", pmrswtp); + + obj_add_uint_x(r, "PMR Sustained Write Throughput (PMRSWTV)", (pmrswtp & 0xffffff00) >> 8); + obj_add_key(r, "PMR Sustained Write Throughput Units (PMRSWTU)", "%s/second", + nvme_register_pmr_pmrszu_to_string(pmrswtp & 0xf)); +} + +static void json_registers_pmrmscl(uint32_t pmrmscl, struct json_object *r) +{ + obj_add_uint_nx(r, "pmrmscl", pmrmscl); + + obj_add_uint_nx(r, "Controller Base Address (CBA)", (pmrmscl & 0xfffff000) >> 12); + obj_add_uint_nx(r, "Controller Memory Space Enable (CMSE)", (pmrmscl & 2) >> 1); +} + +static void json_registers_pmrmscu(uint32_t pmrmscu, struct json_object *r) +{ + obj_add_uint_nx(r, "pmrmscu", pmrmscu); + + obj_add_uint_nx(r, "Controller Base Address (CBA)", pmrmscu); +} + +static void json_registers_unknown(int offset, uint64_t value64, struct json_object *r) +{ + obj_add_uint_02x(r, "unknown property", offset); + obj_add_str(r, "name", nvme_register_to_string(offset)); + obj_add_prix64(r, "value", value64); +} + +static void json_single_property_human(int offset, uint64_t value64, struct json_object *r) +{ + uint32_t value32 = (uint32_t)value64; + + switch (offset) { + case NVME_REG_CAP: + json_registers_cap((struct nvme_bar_cap *)&value64, r); + break; + case NVME_REG_VS: + json_registers_version(value32, r); + break; + case NVME_REG_CC: + json_registers_cc(value32, r); + break; + case NVME_REG_CSTS: + json_registers_csts(value32, r); + break; + case NVME_REG_NSSR: + json_registers_nssr(value32, r); + break; + case NVME_REG_NSSD: + json_registers_nssd(value32, r); + break; + case NVME_REG_CRTO: + json_registers_crto(value32, r); + break; + default: + json_registers_unknown(offset, value64, r); + break; + } +} + +static void json_single_property(int offset, uint64_t value64) +{ + struct json_object *r = json_create_object(); + char json_str[STR_LEN]; + uint32_t value32 = (uint32_t)value64; + + if (human()) { + json_single_property_human(offset, value64, r); + } else { + sprintf(json_str, "0x%02x", offset); + obj_add_str(r, "property", json_str); + + obj_add_str(r, "name", nvme_register_to_string(offset)); + + if (nvme_is_64bit_reg(offset)) + sprintf(json_str, "%"PRIx64"", value64); + else + sprintf(json_str, "%x", value32); + + obj_add_str(r, "value", json_str); + } + + json_print(r); +} + +struct json_object* json_effects_log(enum nvme_csi csi, + struct nvme_cmd_effects_log *effects_log) +{ + struct json_object *r = json_create_object(); + struct json_object *acs = json_create_object(); + struct json_object *iocs = json_create_object(); + unsigned int opcode; + char key[128]; + __u32 effect; + + obj_add_uint(r, "command_set_identifier", csi); + + for (opcode = 0; opcode < 256; opcode++) { + effect = le32_to_cpu(effects_log->acs[opcode]); + if (effect & NVME_CMD_EFFECTS_CSUPP) { + sprintf(key, "ACS_%u (%s)", opcode, + nvme_cmd_to_string(1, opcode)); + obj_add_uint(acs, key, effect); + } + } + + obj_add_obj(r, "admin_cmd_set", acs); + + for (opcode = 0; opcode < 256; opcode++) { + effect = le32_to_cpu(effects_log->iocs[opcode]); + if (effect & NVME_CMD_EFFECTS_CSUPP) { + sprintf(key, "IOCS_%u (%s)", opcode, + nvme_cmd_to_string(0, opcode)); + obj_add_uint(iocs, key, effect); + } + } + + obj_add_obj(r, "io_cmd_set", iocs); + return r; +} + +static void json_effects_log_list(struct list_head *list) +{ + struct json_object *r = json_create_array(); + nvme_effects_log_node_t *node; + + list_for_each(list, node, node) { + struct json_object *json_page = + json_effects_log(node->csi, &node->effects); + array_add_obj(r, json_page); + } + + json_print(r); +} + +static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log, + const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *dev = json_create_object(); + struct json_object *sstat = json_create_object(); + const char *status_str; + char str[128]; + __u16 status = le16_to_cpu(sanitize_log->sstat); + + obj_add_int(dev, "sprog", le16_to_cpu(sanitize_log->sprog)); + obj_add_int(sstat, "global_erased", (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED) >> 8); + obj_add_int(sstat, "no_cmplted_passes", + (status >> NVME_SANITIZE_SSTAT_COMPLETED_PASSES_SHIFT) & + NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK); + + status_str = nvme_sstat_status_to_string(status); + sprintf(str, "(%d) %s", status & NVME_SANITIZE_SSTAT_STATUS_MASK, + status_str); + obj_add_str(sstat, status_str, str); + + obj_add_obj(dev, "sstat", sstat); + obj_add_uint(dev, "cdw10_info", le32_to_cpu(sanitize_log->scdw10)); + obj_add_uint(dev, "time_over_write", le32_to_cpu(sanitize_log->eto)); + obj_add_uint(dev, "time_block_erase", le32_to_cpu(sanitize_log->etbe)); + obj_add_uint(dev, "time_crypto_erase", le32_to_cpu(sanitize_log->etce)); + obj_add_uint(dev, "time_over_write_no_dealloc", le32_to_cpu(sanitize_log->etond)); + obj_add_uint(dev, "time_block_erase_no_dealloc", le32_to_cpu(sanitize_log->etbend)); + obj_add_uint(dev, "time_crypto_erase_no_dealloc", le32_to_cpu(sanitize_log->etcend)); + + obj_add_obj(r, devname, dev); + + json_print(r); +} + +static void json_predictable_latency_per_nvmset( + struct nvme_nvmset_predictable_lat_log *plpns_log, + __u16 nvmset_id, const char *devname) +{ + struct json_object *r = json_create_object(); + + obj_add_uint(r, "nvmset_id", le16_to_cpu(nvmset_id)); + obj_add_uint(r, "status", plpns_log->status); + obj_add_uint(r, "event_type", le16_to_cpu(plpns_log->event_type)); + obj_add_uint64(r, "dtwin_reads_typical", le64_to_cpu(plpns_log->dtwin_rt)); + obj_add_uint64(r, "dtwin_writes_typical", le64_to_cpu(plpns_log->dtwin_wt)); + obj_add_uint64(r, "dtwin_time_maximum", le64_to_cpu(plpns_log->dtwin_tmax)); + obj_add_uint64(r, "ndwin_time_minimum_high", le64_to_cpu(plpns_log->ndwin_tmin_hi)); + obj_add_uint64(r, "ndwin_time_minimum_low", le64_to_cpu(plpns_log->ndwin_tmin_lo)); + obj_add_uint64(r, "dtwin_reads_estimate", le64_to_cpu(plpns_log->dtwin_re)); + obj_add_uint64(r, "dtwin_writes_estimate", le64_to_cpu(plpns_log->dtwin_we)); + obj_add_uint64(r, "dtwin_time_estimate", le64_to_cpu(plpns_log->dtwin_te)); + + json_print(r); +} + +static void json_predictable_latency_event_agg_log( + struct nvme_aggregate_predictable_lat_event *pea_log, + __u64 log_entries, __u32 size, const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *valid_attrs; + struct json_object *valid = json_create_array(); + __u64 num_entries = le64_to_cpu(pea_log->num_entries); + __u64 num_iter = min(num_entries, log_entries); + + obj_add_uint64(r, "num_entries_avail", num_entries); + + for (int i = 0; i < num_iter; i++) { + valid_attrs = json_create_object(); + obj_add_uint(valid_attrs, "entry", le16_to_cpu(pea_log->entries[i])); + array_add_obj(valid, valid_attrs); + } + + obj_add_array(r, "list_of_entries", valid); + + json_print(r); +} + +static void json_add_bitmap(int i, __u8 seb, struct json_object *r) +{ + char evt_str[50]; + char key[128]; + + for (int bit = 0; bit < CHAR_BIT; bit++) { + if (nvme_pel_event_to_string(bit + i * CHAR_BIT)) { + sprintf(key, "bitmap_%x", (bit + i * CHAR_BIT)); + if ((seb >> bit) & 0x1) + snprintf(evt_str, sizeof(evt_str), "Support %s", + nvme_pel_event_to_string(bit + i * CHAR_BIT)); + obj_add_str(r, key, evt_str); + } + } +} + +static void json_pevent_log_head(struct nvme_persistent_event_log *pevent_log_head, + struct json_object *r) +{ + int i; + char sn[sizeof(pevent_log_head->sn) + 1]; + char mn[sizeof(pevent_log_head->mn) + 1]; + char subnqn[sizeof(pevent_log_head->subnqn) + 1]; + + snprintf(sn, sizeof(sn), "%-.*s", (int)sizeof(pevent_log_head->sn), pevent_log_head->sn); + snprintf(mn, sizeof(mn), "%-.*s", (int)sizeof(pevent_log_head->mn), pevent_log_head->mn); + snprintf(subnqn, sizeof(subnqn), "%-.*s", (int)sizeof(pevent_log_head->subnqn), + pevent_log_head->subnqn); + + obj_add_uint(r, "log_id", pevent_log_head->lid); + obj_add_uint(r, "total_num_of_events", le32_to_cpu(pevent_log_head->tnev)); + obj_add_uint64(r, "total_log_len", le64_to_cpu(pevent_log_head->tll)); + obj_add_uint(r, "log_revision", pevent_log_head->rv); + obj_add_uint(r, "log_header_len", le16_to_cpu(pevent_log_head->lhl)); + obj_add_uint64(r, "timestamp", le64_to_cpu(pevent_log_head->ts)); + obj_add_uint128(r, "power_on_hours", le128_to_cpu(pevent_log_head->poh)); + obj_add_uint64(r, "power_cycle_count", le64_to_cpu(pevent_log_head->pcc)); + obj_add_uint(r, "pci_vid", le16_to_cpu(pevent_log_head->vid)); + obj_add_uint(r, "pci_ssvid", le16_to_cpu(pevent_log_head->ssvid)); + obj_add_str(r, "sn", sn); + obj_add_str(r, "mn", mn); + obj_add_str(r, "subnqn", subnqn); + obj_add_uint(r, "gen_number", le16_to_cpu(pevent_log_head->gen_number)); + obj_add_uint(r, "rci", le32_to_cpu(pevent_log_head->rci)); + + for (i = 0; i < ARRAY_SIZE(pevent_log_head->seb); i++) { + if (!pevent_log_head->seb[i]) + continue; + json_add_bitmap(i, pevent_log_head->seb[i], r); + } +} + +static void json_pel_smart_health(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + char key[128]; + struct nvme_smart_log *smart_event = pevent_log_info + offset; + unsigned int temperature = (smart_event->temperature[1] << 8) | smart_event->temperature[0]; + nvme_uint128_t data_units_read = le128_to_cpu(smart_event->data_units_read); + nvme_uint128_t data_units_written = le128_to_cpu(smart_event->data_units_written); + nvme_uint128_t host_read_commands = le128_to_cpu(smart_event->host_reads); + nvme_uint128_t host_write_commands = le128_to_cpu(smart_event->host_writes); + nvme_uint128_t controller_busy_time = le128_to_cpu(smart_event->ctrl_busy_time); + nvme_uint128_t power_cycles = le128_to_cpu(smart_event->power_cycles); + nvme_uint128_t power_on_hours = le128_to_cpu(smart_event->power_on_hours); + nvme_uint128_t unsafe_shutdowns = le128_to_cpu(smart_event->unsafe_shutdowns); + nvme_uint128_t media_errors = le128_to_cpu(smart_event->media_errors); + nvme_uint128_t num_err_log_entries = le128_to_cpu(smart_event->num_err_log_entries); + int c; + __s32 temp; + + obj_add_int(valid_attrs, "critical_warning", smart_event->critical_warning); + obj_add_int(valid_attrs, "temperature", temperature); + obj_add_int(valid_attrs, "avail_spare", smart_event->avail_spare); + obj_add_int(valid_attrs, "spare_thresh", smart_event->spare_thresh); + obj_add_int(valid_attrs, "percent_used", smart_event->percent_used); + obj_add_int(valid_attrs, "endurance_grp_critical_warning_summary", + smart_event->endu_grp_crit_warn_sumry); + obj_add_uint128(valid_attrs, "data_units_read", data_units_read); + obj_add_uint128(valid_attrs, "data_units_written", data_units_written); + obj_add_uint128(valid_attrs, "host_read_commands", host_read_commands); + obj_add_uint128(valid_attrs, "host_write_commands", host_write_commands); + obj_add_uint128(valid_attrs, "controller_busy_time", controller_busy_time); + obj_add_uint128(valid_attrs, "power_cycles", power_cycles); + obj_add_uint128(valid_attrs, "power_on_hours", power_on_hours); + obj_add_uint128(valid_attrs, "unsafe_shutdowns", unsafe_shutdowns); + obj_add_uint128(valid_attrs, "media_errors", media_errors); + obj_add_uint128(valid_attrs, "num_err_log_entries", num_err_log_entries); + obj_add_uint(valid_attrs, "warning_temp_time", le32_to_cpu(smart_event->warning_temp_time)); + obj_add_uint(valid_attrs, "critical_comp_time", + le32_to_cpu(smart_event->critical_comp_time)); + + for (c = 0; c < 8; c++) { + temp = le16_to_cpu(smart_event->temp_sensor[c]); + if (!temp) + continue; + sprintf(key, "temperature_sensor_%d",c + 1); + obj_add_int(valid_attrs, key, temp); + } + + obj_add_uint(valid_attrs, "thm_temp1_trans_count", + le32_to_cpu(smart_event->thm_temp1_trans_count)); + obj_add_uint(valid_attrs, "thm_temp2_trans_count", + le32_to_cpu(smart_event->thm_temp2_trans_count)); + obj_add_uint(valid_attrs, "thm_temp1_total_time", + le32_to_cpu(smart_event->thm_temp1_total_time)); + obj_add_uint(valid_attrs, "thm_temp2_total_time", + le32_to_cpu(smart_event->thm_temp2_total_time)); +} + +static void json_pel_fw_commit(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs) +{ + char fw_str[50]; + struct nvme_fw_commit_event *fw_commit_event = pevent_log_info + offset; + + snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", le64_to_cpu(fw_commit_event->old_fw_rev), + util_fw_to_string((char *)&fw_commit_event->old_fw_rev)); + obj_add_str(valid_attrs, "old_fw_rev", fw_str); + snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", le64_to_cpu(fw_commit_event->new_fw_rev), + util_fw_to_string((char *)&fw_commit_event->new_fw_rev)); + obj_add_str(valid_attrs, "new_fw_rev", fw_str); + obj_add_uint(valid_attrs, "fw_commit_action", fw_commit_event->fw_commit_action); + obj_add_uint(valid_attrs, "fw_slot", fw_commit_event->fw_slot); + obj_add_uint(valid_attrs, "sct_fw", fw_commit_event->sct_fw); + obj_add_uint(valid_attrs, "sc_fw", fw_commit_event->sc_fw); + obj_add_uint(valid_attrs, "vu_assign_fw_commit_rc", + le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); +} + +static void json_pel_timestamp(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs) +{ + struct nvme_time_stamp_change_event *ts_change_event = pevent_log_info + offset; + + obj_add_uint64(valid_attrs, "prev_ts", le64_to_cpu(ts_change_event->previous_timestamp)); + obj_add_uint64(valid_attrs, "ml_secs_since_reset", + le64_to_cpu(ts_change_event->ml_secs_since_reset)); +} + +static void json_pel_power_on_reset(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs, __le16 vsil, __le16 el) +{ + __u64 *fw_rev; + char fw_str[50]; + struct nvme_power_on_reset_info_list *por_event; + __u32 por_info_len = le16_to_cpu(el) - le16_to_cpu(vsil) - sizeof(*fw_rev); + __u32 por_info_list = por_info_len / sizeof(*por_event); + int i; + + fw_rev = pevent_log_info + offset; + snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", le64_to_cpu(*fw_rev), + util_fw_to_string((char *)fw_rev)); + obj_add_str(valid_attrs, "fw_rev", fw_str); + + for (i = 0; i < por_info_list; i++) { + por_event = pevent_log_info + offset + sizeof(*fw_rev) + i * sizeof(*por_event); + obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(por_event->cid)); + obj_add_uint(valid_attrs, "fw_act", por_event->fw_act); + obj_add_uint(valid_attrs, "op_in_prog", por_event->op_in_prog); + obj_add_uint(valid_attrs, "ctrl_power_cycle", + le32_to_cpu(por_event->ctrl_power_cycle)); + obj_add_uint64(valid_attrs, "power_on_ml_secs", + le64_to_cpu(por_event->power_on_ml_seconds)); + obj_add_uint64(valid_attrs, "ctrl_time_stamp", + le64_to_cpu(por_event->ctrl_time_stamp)); + } +} + +static void json_pel_nss_hw_error(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + struct nvme_nss_hw_err_event *nss_hw_err_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "nss_hw_err_code", + le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code)); +} + +static void json_pel_change_ns(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs) +{ + struct nvme_change_ns_event *ns_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "nsmgt_cdw10", le32_to_cpu(ns_event->nsmgt_cdw10)); + obj_add_uint64(valid_attrs, "nsze", le64_to_cpu(ns_event->nsze)); + obj_add_uint64(valid_attrs, "nscap", le64_to_cpu(ns_event->nscap)); + obj_add_uint(valid_attrs, "flbas", ns_event->flbas); + obj_add_uint(valid_attrs, "dps", ns_event->dps); + obj_add_uint(valid_attrs, "nmic", ns_event->nmic); + obj_add_uint(valid_attrs, "ana_grp_id", le32_to_cpu(ns_event->ana_grp_id)); + obj_add_uint(valid_attrs, "nvmset_id", le16_to_cpu(ns_event->nvmset_id)); + obj_add_uint(valid_attrs, "nsid", le32_to_cpu(ns_event->nsid)); +} + +static void json_pel_format_start(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + struct nvme_format_nvm_start_event *format_start_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "nsid", le32_to_cpu(format_start_event->nsid)); + obj_add_uint(valid_attrs, "fna", format_start_event->fna); + obj_add_uint(valid_attrs, "format_nvm_cdw10", + le32_to_cpu(format_start_event->format_nvm_cdw10)); +} + +static void json_pel_format_completion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + struct nvme_format_nvm_compln_event *format_cmpln_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "nsid", le32_to_cpu(format_cmpln_event->nsid)); + obj_add_uint(valid_attrs, "smallest_fpi", format_cmpln_event->smallest_fpi); + obj_add_uint(valid_attrs, "format_nvm_status", format_cmpln_event->format_nvm_status); + obj_add_uint(valid_attrs, "compln_info", le16_to_cpu(format_cmpln_event->compln_info)); + obj_add_uint(valid_attrs, "status_field", le32_to_cpu(format_cmpln_event->status_field)); +} +static void json_pel_sanitize_start(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + struct nvme_sanitize_start_event *sanitize_start_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "SANICAP", le32_to_cpu(sanitize_start_event->sani_cap)); + obj_add_uint(valid_attrs, "sani_cdw10", le32_to_cpu(sanitize_start_event->sani_cdw10)); + obj_add_uint(valid_attrs, "sani_cdw11", le32_to_cpu(sanitize_start_event->sani_cdw11)); +} + +static void json_pel_sanitize_completion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + struct nvme_sanitize_compln_event *sanitize_cmpln_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "sani_prog", le16_to_cpu(sanitize_cmpln_event->sani_prog)); + obj_add_uint(valid_attrs, "sani_status", le16_to_cpu(sanitize_cmpln_event->sani_status)); + obj_add_uint(valid_attrs, "cmpln_info", le16_to_cpu(sanitize_cmpln_event->cmpln_info)); +} + +static void json_pel_thermal_excursion(void *pevent_log_info, __u32 offset, + struct json_object *valid_attrs) +{ + struct nvme_thermal_exc_event *thermal_exc_event = pevent_log_info + offset; + + obj_add_uint(valid_attrs, "over_temp", thermal_exc_event->over_temp); + obj_add_uint(valid_attrs, "threshold", thermal_exc_event->threshold); +} + +static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, const char *devname, + __u32 offset, struct json_object *valid) +{ + int i; + struct nvme_persistent_event_log *pevent_log_head = pevent_log_info; + struct nvme_persistent_event_entry *pevent_entry_head; + struct json_object *valid_attrs; + + for (i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) { + if (offset + sizeof(*pevent_entry_head) >= size) + break; + + pevent_entry_head = pevent_log_info + offset; + + if (offset + pevent_entry_head->ehl + 3 + le16_to_cpu(pevent_entry_head->el) >= + size) + break; + + valid_attrs = json_create_object(); + + obj_add_uint(valid_attrs, "event_number", i); + obj_add_str(valid_attrs, "event_type", + nvme_pel_event_to_string(pevent_entry_head->etype)); + obj_add_uint(valid_attrs, "event_type_rev", pevent_entry_head->etype_rev); + obj_add_uint(valid_attrs, "event_header_len", pevent_entry_head->ehl); + obj_add_uint(valid_attrs, "event_header_additional_info", pevent_entry_head->ehai); + obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(pevent_entry_head->cntlid)); + obj_add_uint64(valid_attrs, "event_time_stamp", + le64_to_cpu(pevent_entry_head->ets)); + obj_add_uint(valid_attrs, "port_id", le16_to_cpu(pevent_entry_head->pelpid)); + obj_add_uint(valid_attrs, "vu_info_len", le16_to_cpu(pevent_entry_head->vsil)); + obj_add_uint(valid_attrs, "event_len", le16_to_cpu(pevent_entry_head->el)); + + offset += pevent_entry_head->ehl + 3; + + switch (pevent_entry_head->etype) { + case NVME_PEL_SMART_HEALTH_EVENT: + json_pel_smart_health(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_FW_COMMIT_EVENT: + json_pel_fw_commit(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_TIMESTAMP_EVENT: + json_pel_timestamp(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_POWER_ON_RESET_EVENT: + json_pel_power_on_reset(pevent_log_info, offset, valid_attrs, + pevent_entry_head->el, pevent_entry_head->vsil); + break; + case NVME_PEL_NSS_HW_ERROR_EVENT: + json_pel_nss_hw_error(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_CHANGE_NS_EVENT: + json_pel_change_ns(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_FORMAT_START_EVENT: + json_pel_format_start(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_FORMAT_COMPLETION_EVENT: + json_pel_format_completion(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_SANITIZE_START_EVENT: + json_pel_sanitize_start(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_SANITIZE_COMPLETION_EVENT: + json_pel_sanitize_completion(pevent_log_info, offset, valid_attrs); + break; + case NVME_PEL_THERMAL_EXCURSION_EVENT: + json_pel_thermal_excursion(pevent_log_info, offset, valid_attrs); + break; + default: + break; + } + + array_add_obj(valid, valid_attrs); + offset += le16_to_cpu(pevent_entry_head->el); + } +} + +static void json_persistent_event_log(void *pevent_log_info, __u8 action, + __u32 size, const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *valid = json_create_array(); + __u32 offset = sizeof(struct nvme_persistent_event_log); + + if (size >= offset) { + json_pevent_log_head(pevent_log_info, r); + json_pevent_entry(pevent_log_info, action, size, devname, offset, valid); + obj_add_array(r, "list_of_event_entries", valid); + } else { + obj_add_result(r, "No log data can be shown with this log len at least " \ + "512 bytes is required or can be 0 to read the complete "\ + "log page after context established"); + } + + json_print(r); +} + +static void json_endurance_group_event_agg_log( + struct nvme_aggregate_predictable_lat_event *endurance_log, + __u64 log_entries, __u32 size, const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *valid_attrs; + struct json_object *valid = json_create_array(); + + obj_add_uint64(r, "num_entries_avail", le64_to_cpu(endurance_log->num_entries)); + + for (int i = 0; i < log_entries; i++) { + valid_attrs = json_create_object(); + obj_add_uint(valid_attrs, "entry", le16_to_cpu(endurance_log->entries[i])); + array_add_obj(valid, valid_attrs); + } + + obj_add_array(r, "list_of_entries", valid); + + json_print(r); +} + +static void json_lba_status(struct nvme_lba_status *list, + unsigned long len) +{ + struct json_object *r = json_create_object(); + int idx; + struct nvme_lba_status_desc *e; + struct json_object *lsde; + char json_str[STR_LEN]; + + obj_add_uint(r, "Number of LBA Status Descriptors (NLSD)", le32_to_cpu(list->nlsd)); + obj_add_uint(r, "Completion Condition (CMPC)", list->cmpc); + + switch (list->cmpc) { + case 1: + obj_add_str(r, "cmpc-definition", + "Completed due to transferring the amount of data specified in the MNDW field"); + break; + case 2: + obj_add_str(r, "cmpc-definition", + "Completed due to having performed the action specified in the Action Type field over the number of logical blocks specified in the Range Length field"); + break; + default: + break; + } + + for (idx = 0; idx < list->nlsd; idx++) { + lsde = json_create_array(); + sprintf(json_str, "LSD entry %d", idx); + obj_add_array(r, json_str, lsde); + e = &list->descs[idx]; + sprintf(json_str, "0x%016"PRIu64"", le64_to_cpu(e->dslba)); + obj_add_str(lsde, "DSLBA", json_str); + sprintf(json_str, "0x%08x", le32_to_cpu(e->nlb)); + obj_add_str(lsde, "NLB", json_str); + sprintf(json_str, "0x%02x", e->status); + obj_add_str(lsde, "status", json_str); + } + + json_print(r); +} + +static void json_lba_status_log(void *lba_status, __u32 size, const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *desc; + struct json_object *element; + struct json_object *desc_list; + struct json_object *elements_list = json_create_array(); + struct nvme_lba_status_log *hdr = lba_status; + struct nvme_lbas_ns_element *ns_element; + struct nvme_lba_rd *range_desc; + int offset = sizeof(*hdr); + __u32 num_lba_desc; + __u32 num_elements = le32_to_cpu(hdr->nlslne); + int ele; + int i; + + obj_add_uint(r, "lslplen", le32_to_cpu(hdr->lslplen)); + obj_add_uint(r, "nlslne", num_elements); + obj_add_uint(r, "estulb", le32_to_cpu(hdr->estulb)); + obj_add_uint(r, "lsgc", le16_to_cpu(hdr->lsgc)); + + for (ele = 0; ele < num_elements; ele++) { + ns_element = lba_status + offset; + element = json_create_object(); + obj_add_uint(element, "neid", le32_to_cpu(ns_element->neid)); + num_lba_desc = le32_to_cpu(ns_element->nlrd); + obj_add_uint(element, "nlrd", num_lba_desc); + obj_add_uint(element, "ratype", ns_element->ratype); + + offset += sizeof(*ns_element); + desc_list = json_create_array(); + + if (num_lba_desc != 0xffffffff) { + for (i = 0; i < num_lba_desc; i++) { + range_desc = lba_status + offset; + desc = json_create_object(); + obj_add_uint64(desc, "rslba", le64_to_cpu(range_desc->rslba)); + obj_add_uint(desc, "rnlb", le32_to_cpu(range_desc->rnlb)); + + offset += sizeof(*range_desc); + array_add_obj(desc_list, desc); + } + } else { + obj_add_result(r, "Number of LBA Range Descriptors (NLRD) set to %#x for NS element %d", + num_lba_desc, ele); + } + + obj_add_array(element, "descs", desc_list); + array_add_obj(elements_list, element); + } + + obj_add_array(r, "ns_elements", elements_list); + + json_print(r); +} + +static void json_resv_notif_log(struct nvme_resv_notification_log *resv, + const char *devname) +{ + struct json_object *r = json_create_object(); + + obj_add_uint64(r, "count", le64_to_cpu(resv->lpc)); + obj_add_uint(r, "rn_log_type", resv->rnlpt); + obj_add_uint(r, "num_logs", resv->nalp); + obj_add_uint(r, "NSID", le32_to_cpu(resv->nsid)); + + json_print(r); +} + +static void json_fid_support_effects_log( + struct nvme_fid_supported_effects_log *fid_log, + const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *fids; + struct json_object *fids_list = json_create_array(); + unsigned int fid; + char key[128]; + __u32 fid_support; + + for (fid = 0; fid < NVME_LOG_FID_SUPPORTED_EFFECTS_MAX; fid++) { + fid_support = le32_to_cpu(fid_log->fid_support[fid]); + if (fid_support & NVME_FID_SUPPORTED_EFFECTS_FSUPP) { + fids = json_create_object(); + sprintf(key, "fid_%u", fid); + obj_add_uint(fids, key, fid_support); + array_add_obj(fids_list, fids); + } + } + + obj_add_obj(r, "fid_support", fids_list); + + json_print(r); +} + +static void json_mi_cmd_support_effects_log( + struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, + const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *mi_cmds; + struct json_object *mi_cmds_list = json_create_array(); + unsigned int mi_cmd; + char key[128]; + __u32 mi_cmd_support; + + for (mi_cmd = 0; mi_cmd < NVME_LOG_MI_CMD_SUPPORTED_EFFECTS_MAX; mi_cmd++) { + mi_cmd_support = le32_to_cpu(mi_cmd_log->mi_cmd_support[mi_cmd]); + if (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_CSUPP) { + mi_cmds = json_create_object(); + sprintf(key, "mi_cmd_%u", mi_cmd); + obj_add_uint(mi_cmds, key, mi_cmd_support); + array_add_obj(mi_cmds_list, mi_cmds); + } + } + + obj_add_obj(r, "mi_command_support", mi_cmds_list); + + json_print(r); +} + +static void json_boot_part_log(void *bp_log, const char *devname, + __u32 size) +{ + struct nvme_boot_partition *hdr = bp_log; + struct json_object *r = json_create_object(); + + obj_add_uint(r, "count", hdr->lid); + obj_add_uint(r, "abpid", (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1); + obj_add_uint(r, "bpsz", le32_to_cpu(hdr->bpinfo) & 0x7fff); + + json_print(r); +} + +/* Printable Eye string is allocated and returned, caller must free */ +static char *json_eom_printable_eye(struct nvme_eom_lane_desc *lane, + struct json_object *r) +{ + char *eye = (char *)lane->eye_desc; + char *printable = malloc(lane->nrows * lane->ncols + lane->ncols); + char *printable_start = printable; + int i, j; + + if (!printable) + goto exit; + + for (i = 0; i < lane->nrows; i++) { + for (j = 0; j < lane->ncols; j++, printable++) + sprintf(printable, "%c", eye[i * lane->ncols + j]); + sprintf(printable++, "\n"); + } + + obj_add_str(r, "printable_eye", printable_start); + +exit: + return printable_start; +} + +static void json_phy_rx_eom_descs(struct nvme_phy_rx_eom_log *log, + struct json_object *r, char **allocated_eyes) +{ + void *p = log->descs; + uint16_t num_descs = le16_to_cpu(log->nd); + int i; + struct json_object *descs = json_create_array(); + + obj_add_array(r, "descs", descs); + + for (i = 0; i < num_descs; i++) { + struct nvme_eom_lane_desc *desc = p; + struct json_object *jdesc = json_create_object(); + + obj_add_uint(jdesc, "lid", desc->mstatus); + obj_add_uint(jdesc, "lane", desc->lane); + obj_add_uint(jdesc, "eye", desc->eye); + obj_add_uint(jdesc, "top", le16_to_cpu(desc->top)); + obj_add_uint(jdesc, "bottom", le16_to_cpu(desc->bottom)); + obj_add_uint(jdesc, "left", le16_to_cpu(desc->left)); + obj_add_uint(jdesc, "right", le16_to_cpu(desc->right)); + obj_add_uint(jdesc, "nrows", le16_to_cpu(desc->nrows)); + obj_add_uint(jdesc, "ncols", le16_to_cpu(desc->ncols)); + obj_add_uint(jdesc, "edlen", le16_to_cpu(desc->edlen)); + + if (log->odp & NVME_EOM_PRINTABLE_EYE_PRESENT) + allocated_eyes[i] = json_eom_printable_eye(desc, r); + + /* Eye Data field is vendor specific, doesn't map to JSON */ + + array_add_obj(descs, jdesc); + + p += log->dsize; + } +} + +static void json_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller) +{ + char **allocated_eyes = NULL; + int i; + struct json_object *r = json_create_object(); + + obj_add_uint(r, "lid", log->lid); + obj_add_uint(r, "eomip", log->eomip); + obj_add_uint(r, "hsize", le16_to_cpu(log->hsize)); + obj_add_uint(r, "rsize", le32_to_cpu(log->rsize)); + obj_add_uint(r, "eomdgn", log->eomdgn); + obj_add_uint(r, "lr", log->lr); + obj_add_uint(r, "lanes", log->lanes); + obj_add_uint(r, "epl", log->epl); + obj_add_uint(r, "lspfc", log->lspfc); + obj_add_uint(r, "li", log->li); + obj_add_uint(r, "lsic", le16_to_cpu(log->lsic)); + obj_add_uint(r, "dsize", le32_to_cpu(log->dsize)); + obj_add_uint(r, "nd", le16_to_cpu(log->nd)); + obj_add_uint(r, "maxtb", le16_to_cpu(log->maxtb)); + obj_add_uint(r, "maxlr", le16_to_cpu(log->maxlr)); + obj_add_uint(r, "etgood", le16_to_cpu(log->etgood)); + obj_add_uint(r, "etbetter", le16_to_cpu(log->etbetter)); + obj_add_uint(r, "etbest", le16_to_cpu(log->etbest)); + + if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) { + /* Save Printable Eye strings allocated to free later */ + allocated_eyes = malloc(log->nd * sizeof(char *)); + if (allocated_eyes) + json_phy_rx_eom_descs(log, r, allocated_eyes); + } + + if (allocated_eyes) { + for (i = 0; i < log->nd; i++) { + /* Free any Printable Eye strings allocated */ + if (allocated_eyes[i]) + free(allocated_eyes[i]); + } + free(allocated_eyes); + } + + json_print(r); +} + +static void json_media_unit_stat_log(struct nvme_media_unit_stat_log *mus) +{ + struct json_object *r = json_create_object(); + struct json_object *entries = json_create_array(); + struct json_object *entry; + int i; + + obj_add_uint(r, "nmu", le16_to_cpu(mus->nmu)); + obj_add_uint(r, "cchans", le16_to_cpu(mus->cchans)); + obj_add_uint(r, "sel_config", le16_to_cpu(mus->sel_config)); + + for (i = 0; i < mus->nmu; i++) { + entry = json_create_object(); + obj_add_uint(entry, "muid", le16_to_cpu(mus->mus_desc[i].muid)); + obj_add_uint(entry, "domainid", le16_to_cpu(mus->mus_desc[i].domainid)); + obj_add_uint(entry, "endgid", le16_to_cpu(mus->mus_desc[i].endgid)); + obj_add_uint(entry, "nvmsetid", le16_to_cpu(mus->mus_desc[i].nvmsetid)); + obj_add_uint(entry, "cap_adj_fctr", le16_to_cpu(mus->mus_desc[i].cap_adj_fctr)); + obj_add_uint(entry, "avl_spare", mus->mus_desc[i].avl_spare); + obj_add_uint(entry, "percent_used", mus->mus_desc[i].percent_used); + obj_add_uint(entry, "mucs", mus->mus_desc[i].mucs); + obj_add_uint(entry, "cio", mus->mus_desc[i].cio); + array_add_obj(entries, entry); + } + + obj_add_array(r, "mus_list", entries); + + json_print(r); +} + +static void json_supported_cap_config_log( + struct nvme_supported_cap_config_list_log *cap_log) +{ + struct json_object *r = json_create_object(); + struct json_object *cap_list = json_create_array(); + struct json_object *capacity; + struct json_object *end_list; + struct json_object *set_list; + struct json_object *set; + struct json_object *chan_list; + struct json_object *channel; + struct json_object *media_list; + struct json_object *media; + struct json_object *endurance; + struct nvme_end_grp_chan_desc *chan_desc; + int i, j, k, l, m, egcn, egsets, egchans, chmus; + int sccn = cap_log->sccn; + + obj_add_uint(r, "sccn", cap_log->sccn); + for (i = 0; i < sccn; i++) { + capacity = json_create_object(); + obj_add_uint(capacity, "cap_config_id", + le16_to_cpu(cap_log->cap_config_desc[i].cap_config_id)); + obj_add_uint(capacity, "domainid", + le16_to_cpu(cap_log->cap_config_desc[i].domainid)); + obj_add_uint(capacity, "egcn", le16_to_cpu(cap_log->cap_config_desc[i].egcn)); + end_list = json_create_array(); + egcn = le16_to_cpu(cap_log->cap_config_desc[i].egcn); + for (j = 0; j < egcn; j++) { + endurance = json_create_object(); + obj_add_uint(endurance, "endgid", + le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].endgid)); + obj_add_uint(endurance, "cap_adj_factor", + le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].cap_adj_factor)); + obj_add_uint128(endurance, "tegcap", + le128_to_cpu(cap_log->cap_config_desc[i].egcd[j].tegcap)); + obj_add_uint128(endurance, "segcap", + le128_to_cpu(cap_log->cap_config_desc[i].egcd[j].segcap)); + obj_add_uint(endurance, "egsets", + le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].egsets)); + egsets = le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].egsets); + set_list = json_create_array(); + for (k = 0; k < egsets; k++) { + set = json_create_object(); + obj_add_uint(set, "nvmsetid", + le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].nvmsetid[k])); + array_add_obj(set_list, set); + } + chan_desc = (struct nvme_end_grp_chan_desc *) + (cap_log->cap_config_desc[i].egcd[j].nvmsetid[0] * sizeof(__u16) * egsets); + egchans = le16_to_cpu(chan_desc->egchans); + obj_add_uint(endurance, "egchans", le16_to_cpu(chan_desc->egchans)); + chan_list = json_create_array(); + for (l = 0; l < egchans; l++) { + channel = json_create_object(); + obj_add_uint(channel, "chanid", + le16_to_cpu(chan_desc->chan_config_desc[l].chanid)); + obj_add_uint(channel, "chmus", + le16_to_cpu(chan_desc->chan_config_desc[l].chmus)); + chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus); + media_list = json_create_array(); + for (m = 0; m < chmus; m++) { + media = json_create_object(); + obj_add_uint(media, "chanid", + le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid)); + obj_add_uint(media, "chmus", + le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].mudl)); + array_add_obj(media_list, media); + } + obj_add_array(channel, "Media Descriptor", media_list); + array_add_obj(chan_list, channel); + } + obj_add_array(endurance, "Channel Descriptor", chan_list); + obj_add_array(endurance, "NVM Set IDs", set_list); + array_add_obj(end_list, endurance); + } + obj_add_array(capacity, "Endurance Descriptor", end_list); + array_add_obj(cap_list, capacity); + } + + obj_add_array(r, "Capacity Descriptor", cap_list); + + json_print(r); +} + +static void json_nvme_fdp_configs(struct nvme_fdp_config_log *log, size_t len) +{ + struct json_object *r, *obj_configs; + uint16_t n; + + void *p = log->configs; + + r = json_create_object(); + obj_configs = json_create_array(); + + n = le16_to_cpu(log->n); + + obj_add_uint(r, "n", n); + + for (int i = 0; i < n + 1; i++) { + struct nvme_fdp_config_desc *config = p; + + struct json_object *obj_config = json_create_object(); + struct json_object *obj_ruhs = json_create_array(); + + obj_add_uint(obj_config, "fdpa", config->fdpa); + obj_add_uint(obj_config, "vss", config->vss); + obj_add_uint(obj_config, "nrg", le32_to_cpu(config->nrg)); + obj_add_uint(obj_config, "nruh", le16_to_cpu(config->nruh)); + obj_add_uint(obj_config, "nnss", le32_to_cpu(config->nnss)); + obj_add_uint64(obj_config, "runs", le64_to_cpu(config->runs)); + obj_add_uint(obj_config, "erutl", le32_to_cpu(config->erutl)); + + for (int j = 0; j < le16_to_cpu(config->nruh); j++) { + struct nvme_fdp_ruh_desc *ruh = &config->ruhs[j]; + + struct json_object *obj_ruh = json_create_object(); + + obj_add_uint(obj_ruh, "ruht", ruh->ruht); + + array_add_obj(obj_ruhs, obj_ruh); + } + + array_add_obj(obj_configs, obj_config); + + p += config->size; + } + + obj_add_array(r, "configs", obj_configs); + + json_print(r); +} + +static void json_nvme_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len) +{ + struct json_object *r, *obj_ruhus; + uint16_t nruh; + + r = json_create_object(); + obj_ruhus = json_create_array(); + + nruh = le16_to_cpu(log->nruh); + + obj_add_uint(r, "nruh", nruh); + + for (int i = 0; i < nruh; i++) { + struct nvme_fdp_ruhu_desc *ruhu = &log->ruhus[i]; + + struct json_object *obj_ruhu = json_create_object(); + + obj_add_uint(obj_ruhu, "ruha", ruhu->ruha); + + array_add_obj(obj_ruhus, obj_ruhu); + } + + obj_add_array(r, "ruhus", obj_ruhus); + + json_print(r); +} + +static void json_nvme_fdp_stats(struct nvme_fdp_stats_log *log) +{ + struct json_object *r = json_create_object(); + + obj_add_uint128(r, "hbmw", le128_to_cpu(log->hbmw)); + obj_add_uint128(r, "mbmw", le128_to_cpu(log->mbmw)); + obj_add_uint128(r, "mbe", le128_to_cpu(log->mbe)); + + json_print(r); +} + +static void json_nvme_fdp_events(struct nvme_fdp_events_log *log) +{ + struct json_object *r, *obj_events; + uint32_t n; + + r = json_create_object(); + obj_events = json_create_array(); + + n = le32_to_cpu(log->n); + + obj_add_uint(r, "n", n); + + for (unsigned int i = 0; i < n; i++) { + struct nvme_fdp_event *event = &log->events[i]; + + struct json_object *obj_event = json_create_object(); + + obj_add_uint(obj_event, "type", event->type); + obj_add_uint(obj_event, "fdpef", event->flags); + obj_add_uint(obj_event, "pid", le16_to_cpu(event->pid)); + obj_add_uint64(obj_event, "timestamp", le64_to_cpu(*(uint64_t *)&event->ts)); + obj_add_uint(obj_event, "nsid", le32_to_cpu(event->nsid)); + + if (event->type == NVME_FDP_EVENT_REALLOC) { + struct nvme_fdp_event_realloc *mr; + mr = (struct nvme_fdp_event_realloc *)&event->type_specific; + + obj_add_uint(obj_event, "nlbam", le16_to_cpu(mr->nlbam)); + + if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV) + obj_add_uint64(obj_event, "lba", le64_to_cpu(mr->lba)); + } + + array_add_obj(obj_events, obj_event); + } + + obj_add_array(r, "events", obj_events); + + json_print(r); +} + +static void json_nvme_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len) +{ + struct json_object *r, *obj_ruhss; + uint16_t nruhsd; + + r = json_create_object(); + obj_ruhss = json_create_array(); + + nruhsd = le16_to_cpu(status->nruhsd); + + obj_add_uint(r, "nruhsd", nruhsd); + + for (unsigned int i = 0; i < nruhsd; i++) { + struct nvme_fdp_ruh_status_desc *ruhs = &status->ruhss[i]; + + struct json_object *obj_ruhs = json_create_object(); + + obj_add_uint(obj_ruhs, "pid", le16_to_cpu(ruhs->pid)); + obj_add_uint(obj_ruhs, "ruhid", le16_to_cpu(ruhs->ruhid)); + obj_add_uint(obj_ruhs, "earutr", le32_to_cpu(ruhs->earutr)); + obj_add_uint64(obj_ruhs, "ruamw", le64_to_cpu(ruhs->ruamw)); + + array_add_obj(obj_ruhss, obj_ruhs); + } + + obj_add_array(r, "ruhss", obj_ruhss); + + json_print(r); +} + +static unsigned int json_print_nvme_subsystem_multipath(nvme_subsystem_t s, json_object *paths) +{ + nvme_ns_t n; + nvme_path_t p; + unsigned int i = 0; + + n = nvme_subsystem_first_ns(s); + if (!n) + return 0; + + nvme_namespace_for_each_path(n, p) { + struct json_object *path_attrs; + nvme_ctrl_t c = nvme_path_get_ctrl(p); + + path_attrs = json_create_object(); + obj_add_str(path_attrs, "Name", nvme_ctrl_get_name(c)); + obj_add_str(path_attrs, "Transport", nvme_ctrl_get_transport(c)); + obj_add_str(path_attrs, "Address", nvme_ctrl_get_address(c)); + obj_add_str(path_attrs, "State", nvme_ctrl_get_state(c)); + obj_add_str(path_attrs, "ANAState", nvme_path_get_ana_state(p)); + array_add_obj(paths, path_attrs); + i++; + } + + return i; +} + +static void json_print_nvme_subsystem_ctrls(nvme_subsystem_t s, + json_object *paths) +{ + nvme_ctrl_t c; + + nvme_subsystem_for_each_ctrl(s, c) { + struct json_object *path_attrs; + + path_attrs = json_create_object(); + obj_add_str(path_attrs, "Name", nvme_ctrl_get_name(c)); + obj_add_str(path_attrs, "Transport", nvme_ctrl_get_transport(c)); + obj_add_str(path_attrs, "Address", nvme_ctrl_get_address(c)); + obj_add_str(path_attrs, "State", nvme_ctrl_get_state(c)); + array_add_obj(paths, path_attrs); + } +} + +static void json_print_nvme_subsystem_list(nvme_root_t r, bool show_ana) +{ + struct json_object *host_attrs, *subsystem_attrs; + struct json_object *subsystems, *paths; + struct json_object *a = json_create_array(); + nvme_host_t h; + + nvme_for_each_host(r, h) { + nvme_subsystem_t s; + const char *hostid; + + host_attrs = json_create_object(); + obj_add_str(host_attrs, "HostNQN", nvme_host_get_hostnqn(h)); + hostid = nvme_host_get_hostid(h); + if (hostid) + obj_add_str(host_attrs, "HostID", hostid); + subsystems = json_create_array(); + nvme_for_each_subsystem(h, s) { + subsystem_attrs = json_create_object(); + obj_add_str(subsystem_attrs, "Name", nvme_subsystem_get_name(s)); + obj_add_str(subsystem_attrs, "NQN", nvme_subsystem_get_nqn(s)); + obj_add_str(subsystem_attrs, "IOPolicy", nvme_subsystem_get_iopolicy(s)); + + array_add_obj(subsystems, subsystem_attrs); + paths = json_create_array(); + + if (!show_ana || !json_print_nvme_subsystem_multipath(s, paths)) + json_print_nvme_subsystem_ctrls(s, paths); + + obj_add_array(subsystem_attrs, "Paths", paths); + } + obj_add_array(host_attrs, "Subsystems", subsystems); + array_add_obj(a, host_attrs); + } + + json_print(a); +} + +static void json_ctrl_registers_cap(void *bar, struct json_object *r) +{ + uint64_t cap = mmio_read64(bar + NVME_REG_CAP); + + if (human()) + json_registers_cap((struct nvme_bar_cap *)&cap, obj_create_array_obj(r, "cap")); + else + obj_add_uint64(r, "cap", cap); +} + +static void json_ctrl_registers_vs(void *bar, struct json_object *r) +{ + uint32_t vs = mmio_read32(bar + NVME_REG_VS); + + if (human()) + json_registers_version(vs, obj_create_array_obj(r, "vs")); + else + obj_add_int(r, "vs", vs); +} + +static void json_ctrl_registers_intms(void *bar, struct json_object *r) +{ + uint32_t intms = mmio_read32(bar + NVME_REG_INTMS); + + if (human()) + json_registers_intms(intms, obj_create_array_obj(r, "intms")); + else + obj_add_int(r, "intms", intms); +} + +static void json_ctrl_registers_intmc(void *bar, struct json_object *r) +{ + uint32_t intmc = mmio_read32(bar + NVME_REG_INTMC); + + if (human()) + json_registers_intmc(intmc, obj_create_array_obj(r, "intmc")); + else + obj_add_int(r, "intmc", intmc); +} + +static void json_ctrl_registers_cc(void *bar, struct json_object *r) +{ + uint32_t cc = mmio_read32(bar + NVME_REG_CC); + + if (human()) + json_registers_cc(cc, obj_create_array_obj(r, "cc")); + else + obj_add_int(r, "cc", cc); +} + +static void json_ctrl_registers_csts(void *bar, struct json_object *r) +{ + uint32_t csts = mmio_read32(bar + NVME_REG_CSTS); + + if (human()) + json_registers_csts(csts, obj_create_array_obj(r, "csts")); + else + obj_add_int(r, "csts", csts); +} + +static void json_ctrl_registers_nssr(void *bar, struct json_object *r) +{ + uint32_t nssr = mmio_read32(bar + NVME_REG_NSSR); + + if (human()) + json_registers_nssr(nssr, obj_create_array_obj(r, "nssr")); + else + obj_add_int(r, "nssr", nssr); +} + +static void json_ctrl_registers_nssd(void *bar, struct json_object *r) +{ + uint32_t nssd = mmio_read32(bar + NVME_REG_NSSD); + + if (human()) + json_registers_nssd(nssd, obj_create_array_obj(r, "nssd")); + else + obj_add_int(r, "nssd", nssd); +} + +static void json_ctrl_registers_crto(void *bar, struct json_object *r) +{ + uint32_t crto = mmio_read32(bar + NVME_REG_CRTO); + + if (human()) + json_registers_crto(crto, obj_create_array_obj(r, "crto")); + else + obj_add_int(r, "crto", crto); +} + +static void json_ctrl_registers_aqa(void *bar, struct json_object *r) +{ + uint32_t aqa = mmio_read32(bar + NVME_REG_AQA); + + if (human()) + json_registers_aqa(aqa, obj_create_array_obj(r, "aqa")); + else + obj_add_int(r, "aqa", aqa); +} + +static void json_ctrl_registers_asq(void *bar, struct json_object *r) +{ + uint64_t asq = mmio_read64(bar + NVME_REG_ASQ); + + if (human()) + json_registers_asq(asq, obj_create_array_obj(r, "asq")); + else + obj_add_uint64(r, "asq", asq); +} + +static void json_ctrl_registers_acq(void *bar, struct json_object *r) +{ + uint64_t acq = mmio_read64(bar + NVME_REG_ACQ); + + if (human()) + json_registers_acq(acq, obj_create_array_obj(r, "acq")); + else + obj_add_uint64(r, "acq", acq); +} + +static void json_ctrl_registers_cmbloc(void *bar, struct json_object *r) +{ + uint32_t cmbloc = mmio_read32(bar + NVME_REG_CMBLOC); + + if (human()) + json_registers_cmbloc(cmbloc, bar, obj_create_array_obj(r, "cmbloc")); + else + obj_add_int(r, "cmbloc", cmbloc); +} + +static void json_ctrl_registers_cmbsz(void *bar, struct json_object *r) +{ + uint32_t cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); + + if (human()) + json_registers_cmbsz(cmbsz, obj_create_array_obj(r, "cmbsz")); + else + obj_add_int(r, "cmbsz", cmbsz); +} + +static void json_ctrl_registers_bpinfo(void *bar, struct json_object *r) +{ + uint32_t bpinfo = mmio_read32(bar + NVME_REG_BPINFO); + + if (human()) + json_registers_bpinfo(bpinfo, obj_create_array_obj(r, "bpinfo")); + else + obj_add_int(r, "bpinfo", bpinfo); +} + +static void json_ctrl_registers_bprsel(void *bar, struct json_object *r) +{ + uint32_t bprsel = mmio_read32(bar + NVME_REG_BPRSEL); + + if (human()) + json_registers_bprsel(bprsel, obj_create_array_obj(r, "bprsel")); + else + obj_add_int(r, "bprsel", bprsel); +} + +static void json_ctrl_registers_bpmbl(void *bar, struct json_object *r) +{ + uint64_t bpmbl = mmio_read64(bar + NVME_REG_BPMBL); + + if (human()) + json_registers_bpmbl(bpmbl, obj_create_array_obj(r, "bpmbl")); + else + obj_add_uint64(r, "bpmbl", bpmbl); +} + +static void json_ctrl_registers_cmbmsc(void *bar, struct json_object *r) +{ + uint64_t cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC); + + if (human()) + json_registers_cmbmsc(cmbmsc, obj_create_array_obj(r, "cmbmsc")); + else + obj_add_uint64(r, "cmbmsc", cmbmsc); +} + +static void json_ctrl_registers_cmbsts(void *bar, struct json_object *r) +{ + uint32_t cmbsts = mmio_read32(bar + NVME_REG_CMBSTS); + + if (human()) + json_registers_cmbsts(cmbsts, obj_create_array_obj(r, "cmbsts")); + else + obj_add_int(r, "cmbsts", cmbsts); +} + +static void json_ctrl_registers_pmrcap(void *bar, struct json_object *r) +{ + uint32_t pmrcap = mmio_read32(bar + NVME_REG_PMRCAP); + + if (human()) + json_registers_pmrcap(pmrcap, obj_create_array_obj(r, "pmrcap")); + else + obj_add_int(r, "pmrcap", pmrcap); +} + +static void json_ctrl_registers_pmrctl(void *bar, struct json_object *r) +{ + uint32_t pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); + + if (human()) + json_registers_pmrctl(pmrctl, obj_create_array_obj(r, "pmrctl")); + else + obj_add_int(r, "pmrctl", pmrctl); +} + +static void json_ctrl_registers_pmrsts(void *bar, struct json_object *r) +{ + uint32_t pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); + + if (human()) + json_registers_pmrsts(pmrsts, bar, obj_create_array_obj(r, "pmrsts")); + else + obj_add_int(r, "pmrsts", pmrsts); +} + +static void json_ctrl_registers_pmrebs(void *bar, struct json_object *r) +{ + uint32_t pmrebs = mmio_read32(bar + NVME_REG_PMREBS); + + if (human()) + json_registers_pmrebs(pmrebs, obj_create_array_obj(r, "pmrebs")); + else + obj_add_int(r, "pmrebs", pmrebs); +} + +static void json_ctrl_registers_pmrswtp(void *bar, struct json_object *r) +{ + uint32_t pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); + + if (human()) + json_registers_pmrswtp(pmrswtp, obj_create_array_obj(r, "pmrswtp")); + else + obj_add_int(r, "pmrswtp", pmrswtp); +} + +static void json_ctrl_registers_pmrmscl(void *bar, struct json_object *r) +{ + uint32_t pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); + + if (human()) + json_registers_pmrmscl(pmrmscl, obj_create_array_obj(r, "pmrmscl")); + else + obj_add_uint(r, "pmrmscl", pmrmscl); +} + +static void json_ctrl_registers_pmrmscu(void *bar, struct json_object *r) +{ + uint32_t pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); + + if (human()) + json_registers_pmrmscu(pmrmscu, obj_create_array_obj(r, "pmrmscu")); + else + obj_add_uint(r, "pmrmscu", pmrmscu); +} + +static void json_ctrl_registers(void *bar, bool fabrics) +{ + struct json_object *r = json_create_object(); + + json_ctrl_registers_cap(bar, r); + json_ctrl_registers_vs(bar, r); + json_ctrl_registers_intms(bar, r); + json_ctrl_registers_intmc(bar, r); + json_ctrl_registers_cc(bar, r); + json_ctrl_registers_csts(bar, r); + json_ctrl_registers_nssr(bar, r); + json_ctrl_registers_nssd(bar, r); + json_ctrl_registers_crto(bar, r); + json_ctrl_registers_aqa(bar, r); + json_ctrl_registers_asq(bar, r); + json_ctrl_registers_acq(bar, r); + json_ctrl_registers_cmbloc(bar, r); + json_ctrl_registers_cmbsz(bar, r); + json_ctrl_registers_bpinfo(bar, r); + json_ctrl_registers_bprsel(bar, r); + json_ctrl_registers_bpmbl(bar, r); + json_ctrl_registers_cmbmsc(bar, r); + json_ctrl_registers_cmbsts(bar, r); + json_ctrl_registers_pmrcap(bar, r); + json_ctrl_registers_pmrctl(bar, r); + json_ctrl_registers_pmrsts(bar, r); + json_ctrl_registers_pmrebs(bar, r); + json_ctrl_registers_pmrswtp(bar, r); + json_ctrl_registers_pmrmscl(bar, r); + json_ctrl_registers_pmrmscu(bar, r); + + json_print(r); +} + +static void json_nvme_cmd_set_independent_id_ns(struct nvme_id_independent_id_ns *ns, + unsigned int nsid) +{ + struct json_object *r = json_create_object(); + + obj_add_int(r, "nsfeat", ns->nsfeat); + obj_add_int(r, "nmic", ns->nmic); + obj_add_int(r, "rescap", ns->rescap); + obj_add_int(r, "fpi", ns->fpi); + obj_add_uint(r, "anagrpid", le32_to_cpu(ns->anagrpid)); + obj_add_int(r, "nsattr", ns->nsattr); + obj_add_int(r, "nvmsetid", le16_to_cpu(ns->nvmsetid)); + obj_add_int(r, "endgid", le16_to_cpu(ns->endgid)); + obj_add_int(r, "nstat", ns->nstat); + + json_print(r); +} + +static void json_nvme_id_ns_descs(void *data, unsigned int nsid) +{ + /* large enough to hold uuid str (37) or nguid str (32) + zero byte */ + char json_str[STR_LEN]; + char *json_str_p; + union { + __u8 eui64[NVME_NIDT_EUI64_LEN]; + __u8 nguid[NVME_NIDT_NGUID_LEN]; + __u8 uuid[NVME_UUID_LEN]; + __u8 csi; + } desc; + struct json_object *r = json_create_object(); + struct json_object *json_array = NULL; + off_t off; + int pos, len = 0; + int i; + + for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) { + struct nvme_ns_id_desc *cur = data + pos; + const char *nidt_name = NULL; + + if (cur->nidl == 0) + break; + + memset(json_str, 0, sizeof(json_str)); + json_str_p = json_str; + off = pos + sizeof(*cur); + + switch (cur->nidt) { + case NVME_NIDT_EUI64: + memcpy(desc.eui64, data + off, sizeof(desc.eui64)); + for (i = 0; i < sizeof(desc.eui64); i++) + json_str_p += sprintf(json_str_p, "%02x", desc.eui64[i]); + len = sizeof(desc.eui64); + nidt_name = "eui64"; + break; + case NVME_NIDT_NGUID: + memcpy(desc.nguid, data + off, sizeof(desc.nguid)); + for (i = 0; i < sizeof(desc.nguid); i++) + json_str_p += sprintf(json_str_p, "%02x", desc.nguid[i]); + len = sizeof(desc.nguid); + nidt_name = "nguid"; + break; + case NVME_NIDT_UUID: + memcpy(desc.uuid, data + off, sizeof(desc.uuid)); + nvme_uuid_to_string(desc.uuid, json_str); + len = sizeof(desc.uuid); + nidt_name = "uuid"; + break; + case NVME_NIDT_CSI: + memcpy(&desc.csi, data + off, sizeof(desc.csi)); + sprintf(json_str_p, "%#x", desc.csi); + len += sizeof(desc.csi); + nidt_name = "csi"; + break; + default: + /* Skip unknown types */ + len = cur->nidl; + break; + } + + if (nidt_name) { + struct json_object *elem = json_create_object(); + + obj_add_int(elem, "loc", pos); + obj_add_int(elem, "nidt", (int)cur->nidt); + obj_add_int(elem, "nidl", (int)cur->nidl); + obj_add_str(elem, "Type", nidt_name); + obj_add_str(elem, nidt_name, json_str); + + if (!json_array) + json_array = json_create_array(); + array_add_obj(json_array, elem); + } + + len += sizeof(*cur); + } + + if (json_array) + obj_add_array(r, "ns-descs", json_array); + + json_print(r); +} + +static void json_nvme_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm) +{ + struct json_object *r = json_create_object(); + + obj_add_uint(r, "vsl", ctrl_nvm->vsl); + obj_add_uint(r, "wzsl", ctrl_nvm->wzsl); + obj_add_uint(r, "wusl", ctrl_nvm->wusl); + obj_add_uint(r, "dmrl", ctrl_nvm->dmrl); + obj_add_uint(r, "dmrsl", le32_to_cpu(ctrl_nvm->dmrsl)); + obj_add_uint64(r, "dmsl", le64_to_cpu(ctrl_nvm->dmsl)); + + json_print(r); +} + +static void json_nvme_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, + unsigned int nsid, struct nvme_id_ns *ns, + unsigned int lba_index, bool cap_only) + +{ + struct json_object *r = json_create_object(); + struct json_object *elbafs = json_create_array(); + int i; + + if (!cap_only) + obj_add_uint64(r, "lbstm", le64_to_cpu(nvm_ns->lbstm)); + + obj_add_int(r, "pic", nvm_ns->pic); + + obj_add_array(r, "elbafs", elbafs); + + for (i = 0; i <= ns->nlbaf; i++) { + struct json_object *elbaf = json_create_object(); + unsigned int elbaf_val = le32_to_cpu(nvm_ns->elbaf[i]); + + obj_add_uint(elbaf, "sts", elbaf_val & 0x7F); + obj_add_uint(elbaf, "pif", (elbaf_val >> 7) & 0x3); + + array_add_obj(elbafs, elbaf); + } + + json_print(r); +} + +static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl) +{ + struct json_object *r = json_create_object(); + + obj_add_int(r, "zasl", ctrl->zasl); + + json_print(r); +} + +static void json_nvme_zns_id_ns(struct nvme_zns_id_ns *ns, + struct nvme_id_ns *id_ns) +{ + struct json_object *r = json_create_object(); + struct json_object *lbafs = json_create_array(); + int i; + + obj_add_int(r, "zoc", le16_to_cpu(ns->zoc)); + obj_add_int(r, "ozcs", le16_to_cpu(ns->ozcs)); + obj_add_uint(r, "mar", le32_to_cpu(ns->mar)); + obj_add_uint(r, "mor", le32_to_cpu(ns->mor)); + obj_add_uint(r, "rrl", le32_to_cpu(ns->rrl)); + obj_add_uint(r, "frl", le32_to_cpu(ns->frl)); + obj_add_uint(r, "rrl1", le32_to_cpu(ns->rrl1)); + obj_add_uint(r, "rrl2", le32_to_cpu(ns->rrl2)); + obj_add_uint(r, "rrl3", le32_to_cpu(ns->rrl3)); + obj_add_uint(r, "frl1", le32_to_cpu(ns->frl1)); + obj_add_uint(r, "frl2", le32_to_cpu(ns->frl2)); + obj_add_uint(r, "frl3", le32_to_cpu(ns->frl3)); + obj_add_uint(r, "numzrwa", le32_to_cpu(ns->numzrwa)); + obj_add_int(r, "zrwafg", le16_to_cpu(ns->zrwafg)); + obj_add_int(r, "zrwasz", le16_to_cpu(ns->zrwasz)); + obj_add_int(r, "zrwacap", ns->zrwacap); + + obj_add_array(r, "lbafe", lbafs); + + for (i = 0; i <= id_ns->nlbaf; i++) { + struct json_object *lbaf = json_create_object(); + + obj_add_uint64(lbaf, "zsze", le64_to_cpu(ns->lbafe[i].zsze)); + obj_add_int(lbaf, "zdes", ns->lbafe[i].zdes); + + array_add_obj(lbafs, lbaf); + } + + json_print(r); +} + +static void json_nvme_list_ns(struct nvme_ns_list *ns_list) +{ + struct json_object *r = json_create_object(); + struct json_object *valid_attrs; + struct json_object *valid = json_create_array(); + int i; + + for (i = 0; i < 1024; i++) { + if (ns_list->ns[i]) { + valid_attrs = json_create_object(); + obj_add_uint(valid_attrs, "nsid", le32_to_cpu(ns_list->ns[i])); + array_add_obj(valid, valid_attrs); + } + } + + obj_add_array(r, "nsid_list", valid); + + json_print(r); +} + +static void json_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list) +{ + *zone_list = json_create_array(); +} + +static void json_zns_changed(struct nvme_zns_changed_zone_log *log) +{ + struct json_object *r = json_create_object(); + char json_str[STR_LEN]; + uint16_t nrzid = le16_to_cpu(log->nrzid); + int i; + + if (nrzid == 0xFFFF) { + obj_add_result(r, "Too many zones have changed to fit into the log. Use report zones for changes."); + } else { + obj_add_uint(r, "nrzid", nrzid); + for (i = 0; i < nrzid; i++) { + sprintf(json_str, "zid %03d", i); + obj_add_uint64(r, json_str, (uint64_t)le64_to_cpu(log->zid[i])); + } + } + + json_print(r); +} + +static void json_zns_finish_zone_list(__u64 nr_zones, + struct json_object *zone_list) +{ + struct json_object *r = json_create_object(); + + obj_add_uint(r, "nr_zones", nr_zones); + obj_add_array(r, "zone_list", zone_list); + + json_print(r); +} + +static void json_nvme_zns_report_zones(void *report, __u32 descs, + __u8 ext_size, __u32 report_size, + struct json_object *zone_list) +{ + struct json_object *zone; + struct json_object *ext_data; + struct nvme_zone_report *r = report; + struct nvme_zns_desc *desc; + int i; + + for (i = 0; i < descs; i++) { + desc = (struct nvme_zns_desc *) + (report + sizeof(*r) + i * (sizeof(*desc) + ext_size)); + zone = json_create_object(); + + obj_add_uint64(zone, "slba", le64_to_cpu(desc->zslba)); + obj_add_uint64(zone, "wp", le64_to_cpu(desc->wp)); + obj_add_uint64(zone, "cap", le64_to_cpu(desc->zcap)); + obj_add_str(zone, "state", nvme_zone_state_to_string(desc->zs >> 4)); + obj_add_str(zone, "type", nvme_zone_type_to_string(desc->zt)); + obj_add_uint(zone, "attrs", desc->za); + obj_add_uint(zone, "attrs_info", desc->zai); + + if (ext_size) { + if (desc->za & NVME_ZNS_ZA_ZDEV) { + ext_data = json_create_array(); + d_json((unsigned char *)desc + sizeof(*desc), + ext_size, 16, 1, ext_data); + obj_add_array(zone, "ext_data", ext_data); + } else { + obj_add_str(zone, "ext_data", "Not valid"); + } + } + + array_add_obj(zone_list, zone); + } +} + +static void json_feature_show_fields_arbitration(struct json_object *r, unsigned int result) +{ + char json_str[STR_LEN]; + + obj_add_uint(r, "High Priority Weight (HPW)", ((result & 0xff000000) >> 24) + 1); + obj_add_uint(r, "Medium Priority Weight (MPW)", ((result & 0xff0000) >> 16) + 1); + obj_add_uint(r, "Low Priority Weight (LPW)", ((result & 0xff00) >> 8) + 1); + + if ((result & 7) == 7) + sprintf(json_str, "No limit"); + else + sprintf(json_str, "%u", 1 << (result & 7)); + + obj_add_str(r, "Arbitration Burst (AB)", json_str); +} + +static void json_feature_show_fields_power_mgmt(struct json_object *r, unsigned int result) +{ + __u8 field = (result & 0xe0) >> 5; + + obj_add_uint(r, "Workload Hint (WH)", field); + obj_add_str(r, "WH description", nvme_feature_wl_hints_to_string(field)); + obj_add_uint(r, "Power State (PS)", result & 0x1f); +} + +static void json_lba_range_entry(struct nvme_lba_range_type *lbrt, int nr_ranges, + struct json_object *r) +{ + char json_str[STR_LEN]; + struct json_object *lbare; + int i; + int j; + struct json_object *lbara = json_create_array(); + + obj_add_array(r, "LBA Ranges", lbara); + + for (i = 0; i <= nr_ranges; i++) { + lbare = json_create_object(); + array_add_obj(lbara, lbare); + + obj_add_int(lbare, "LBA range", i); + + obj_add_uint_nx(lbare, "type", lbrt->entry[i].type); + + obj_add_str(lbare, "type description", + nvme_feature_lba_type_to_string(lbrt->entry[i].type)); + + obj_add_uint_nx(lbare, "attributes", lbrt->entry[i].attributes); + + obj_add_str(lbare, "attribute[0]", lbrt->entry[i].attributes & 1 ? + "LBA range may be overwritten" : "LBA range should not be overwritten"); + + obj_add_str(lbare, "attribute[1]", lbrt->entry[i].attributes & 2 ? + "LBA range should be hidden from the OS/EFI/BIOS" : + "LBA range should be visible from the OS/EFI/BIOS"); + + obj_add_nprix64(lbare, "slba", le64_to_cpu(lbrt->entry[i].slba)); + + obj_add_nprix64(lbare, "nlb", le64_to_cpu(lbrt->entry[i].nlb)); + + for (j = 0; j < ARRAY_SIZE(lbrt->entry[i].guid); j++) + sprintf(&json_str[j * 2], "%02x", lbrt->entry[i].guid[j]); + + obj_add_str(lbare, "guid", json_str); + } +} + +static void json_feature_show_fields_lba_range(struct json_object *r, __u8 field, + unsigned char *buf) +{ + obj_add_uint(r, "Number of LBA Ranges (NUM)", field + 1); + + if (buf) + json_lba_range_entry((struct nvme_lba_range_type *)buf, field, r); +} + +static void json_feature_show_fields_temp_thresh(struct json_object *r, unsigned int result) +{ + __u8 field = (result & 0x300000) >> 20; + char json_str[STR_LEN]; + + obj_add_uint(r, "Threshold Type Select (THSEL)", field); + obj_add_str(r, "THSEL description", nvme_feature_temp_type_to_string(field)); + + field = (result & 0xf0000) >> 16; + + obj_add_uint(r, "Threshold Temperature Select (TMPSEL)", field); + obj_add_str(r, "TMPSEL description", nvme_feature_temp_sel_to_string(field)); + + sprintf(json_str, "%ld Celsius", kelvin_to_celsius(result & 0xffff)); + obj_add_str(r, "Temperature Threshold (TMPTH)", json_str); + + sprintf(json_str, "%u K", result & 0xffff); + obj_add_str(r, "TMPTH kelvin", json_str); +} + +static void json_feature_show_fields_err_recovery(struct json_object *r, unsigned int result) +{ + char json_str[STR_LEN]; + + obj_add_str(r, "Deallocated or Unwritten Logical Block Error Enable (DULBE)", + (result & 0x10000) >> 16 ? "Enabled" : "Disabled"); + + sprintf(json_str, "%u ms", (result & 0xffff) * 100); + obj_add_str(r, "Time Limited Error Recovery (TLER)", json_str); +} + +static void json_feature_show_fields_volatile_wc(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Volatile Write Cache Enable (WCE)", result & 1 ? "Enabled" : "Disabled"); +} + +static void json_feature_show_fields_num_queues(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "Number of IO Completion Queues Allocated (NCQA)", + ((result & 0xffff0000) >> 16) + 1); + obj_add_uint(r, "Number of IO Submission Queues Allocated (NSQA)", (result & 0xffff) + 1); +} + +static void json_feature_show_fields_irq_coalesce(struct json_object *r, unsigned int result) +{ + char json_str[STR_LEN]; + + sprintf(json_str, "%u usec", ((result & 0xff00) >> 8) * 100); + obj_add_str(r, "Aggregation Time (TIME)", json_str); + + obj_add_uint(r, "Aggregation Threshold (THR)", (result & 0xff) + 1); +} + +static void json_feature_show_fields_irq_config(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Coalescing Disable (CD)", (result & 0x10000) >> 16 ? "True" : "False"); + obj_add_uint(r, "Interrupt Vector (IV)", result & 0xffff); +} + +static void json_feature_show_fields_write_atomic(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Disable Normal (DN)", result & 1 ? "True" : "False"); +} + +static void json_feature_show_fields_async_event(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Discovery Log Page Change Notices", (result & 0x80000000) >> 31 ? + "Send async event" : "Do not send async event"); + obj_add_str(r, "Endurance Group Event Aggregate Log Change Notices", (result & 0x4000) >> 14 ? + "Send async event" : "Do not send async event"); + obj_add_str(r, "LBA Status Information Notices", (result & 0x2000) >> 13 ? + "Send async event" : "Do not send async event"); + obj_add_str(r, "Predictable Latency Event Aggregate Log Change Notices", + (result & 0x1000) >> 12 ? "Send async event" : "Do not send async event"); + obj_add_str(r, "Asymmetric Namespace Access Change Notices", (result & 0x800) >> 11 ? + "Send async event" : "Do not send async event"); + obj_add_str(r, "Telemetry Log Notices", (result & 0x400) >> 10 ? "Send async event" : + "Do not send async event"); + obj_add_str(r, "Firmware Activation Notices", (result & 0x200) >> 9 ? "Send async event" : + "Do not send async event"); + obj_add_str(r, "Namespace Attribute Notices", (result & 0x100) >> 8 ? "Send async event" : + "Do not send async event"); + obj_add_str(r, "SMART / Health Critical Warnings", result & 0xff ? "Send async event" : + "Do not send async event"); +} + +static void json_auto_pst(struct nvme_feat_auto_pst *apst, struct json_object *r) +{ + int i; + __u64 value; + char json_str[STR_LEN]; + struct json_object *apsta = json_create_array(); + struct json_object *apste; + + obj_add_array(r, "Auto PST Entries", apsta); + + for (i = 0; i < ARRAY_SIZE(apst->apst_entry); i++) { + apste = json_create_object(); + array_add_obj(apsta, apste); + sprintf(json_str, "%2d", i); + obj_add_str(apste, "entry", json_str); + value = le64_to_cpu(apst->apst_entry[i]); + sprintf(json_str, "%u ms", (__u32)NVME_GET(value, APST_ENTRY_ITPT)); + obj_add_str(apste, "Idle Time Prior to Transition (ITPT)", json_str); + obj_add_uint(apste, "Idle Transition Power State (ITPS)", + (__u32)NVME_GET(value, APST_ENTRY_ITPS)); + } +} + +static void json_feature_show_fields_auto_pst(struct json_object *r, unsigned int result, + unsigned char *buf) +{ + obj_add_str(r, "Autonomous Power State Transition Enable (APSTE)", result & 1 ? "Enabled" : + "Disabled"); + + if (buf) + json_auto_pst((struct nvme_feat_auto_pst *)buf, r); +} + +static void json_host_mem_buffer(struct nvme_host_mem_buf_attrs *hmb, struct json_object *r) +{ + char json_str[STR_LEN]; + + obj_add_uint(r, "Host Memory Descriptor List Entry Count (HMDLEC)", le32_to_cpu(hmb->hmdlec)); + + sprintf(json_str, "0x%x", le32_to_cpu(hmb->hmdlau)); + obj_add_str(r, "Host Memory Descriptor List Address (HMDLAU)", json_str); + + sprintf(json_str, "0x%x", le32_to_cpu(hmb->hmdlal)); + obj_add_str(r, "Host Memory Descriptor List Address (HMDLAL)", json_str); + + obj_add_uint(r, "Host Memory Buffer Size (HSIZE)", le32_to_cpu(hmb->hsize)); +} + +static void json_feature_show_fields_host_mem_buf(struct json_object *r, unsigned int result, + unsigned char *buf) +{ + obj_add_str(r, "Enable Host Memory (EHM)", result & 1 ? "Enabled" : "Disabled"); + + if (buf) + json_host_mem_buffer((struct nvme_host_mem_buf_attrs *)buf, r); +} + +static void json_timestamp(struct json_object *r, struct nvme_timestamp *ts) +{ + char buffer[BUF_LEN]; + time_t timestamp = int48_to_long(ts->timestamp) / 1000; + struct tm *tm = localtime(×tamp); + + obj_add_uint64(r, "timestamp", int48_to_long(ts->timestamp)); + + if(!strftime(buffer, sizeof(buffer), "%c %Z", tm)) + sprintf(buffer, "%s", "-"); + + obj_add_str(r, "timestamp string", buffer); + + obj_add_str(r, "timestamp origin", ts->attr & 2 ? + "The Timestamp field was initialized with a Timestamp value using a Set Features command." : + "The Timestamp field was initialized to 0h by a Controller Level Reset."); + + obj_add_str(r, "synch", ts->attr & 1 ? + "The controller may have stopped counting during vendor specific intervals after the Timestamp value was initialized." : + "The controller counted time in milliseconds continuously since the Timestamp value was initialized."); +} + +static void json_feature_show_fields_timestamp(struct json_object *r, unsigned char *buf) +{ + if (buf) + json_timestamp(r, (struct nvme_timestamp *)buf); +} + +static void json_feature_show_fields_kato(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "Keep Alive Timeout (KATO) in milliseconds", result); +} + +static void json_feature_show_fields_hctm(struct json_object *r, unsigned int result) +{ + char json_str[STR_LEN]; + + sprintf(json_str, "%u K", result >> 16); + obj_add_str(r, "Thermal Management Temperature 1 (TMT1)", json_str); + + sprintf(json_str, "%ld Celsius", kelvin_to_celsius(result >> 16)); + obj_add_str(r, "TMT1 celsius", json_str); + + sprintf(json_str, "%u K", result & 0xffff); + obj_add_str(r, "Thermal Management Temperature 2", json_str); + + sprintf(json_str, "%ld Celsius", kelvin_to_celsius(result & 0xffff)); + obj_add_str(r, "TMT2 celsius", json_str); +} + +static void json_feature_show_fields_nopsc(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Non-Operational Power State Permissive Mode Enable (NOPPME)", result & 1 ? + "True" : "False"); +} + +static void json_feature_show_fields_rrl(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "Read Recovery Level (RRL)", result & 0xf); +} + +static void json_plm_config(struct nvme_plm_config *plmcfg, struct json_object *r) +{ + char json_str[STR_LEN]; + + sprintf(json_str, "%04x", le16_to_cpu(plmcfg->ee)); + obj_add_str(r, "Enable Event", json_str); + + obj_add_uint64(r, "DTWIN Reads Threshold", le64_to_cpu(plmcfg->dtwinrt)); + obj_add_uint64(r, "DTWIN Writes Threshold", le64_to_cpu(plmcfg->dtwinwt)); + obj_add_uint64(r, "DTWIN Time Threshold", le64_to_cpu(plmcfg->dtwintt)); +} + +static void json_feature_show_fields_plm_config(struct json_object *r, unsigned int result, + unsigned char *buf) +{ + obj_add_str(r, "Predictable Latency Window Enabled", result & 1 ? "True" : "False"); + + if (buf) + json_plm_config((struct nvme_plm_config *)buf, r); +} + +static void json_feature_show_fields_plm_window(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Window Select", nvme_plm_window_to_string(result)); +} + +static void json_feature_show_fields_lba_sts_interval(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "LBA Status Information Poll Interval (LSIPI)", result >> 16); + obj_add_uint(r, "LBA Status Information Report Interval (LSIRI)", result & 0xffff); +} + +static void json_feature_show_fields_host_behavior(struct json_object *r, unsigned char *buf) +{ + if (buf) + obj_add_str(r, "Host Behavior Support", buf[0] & 0x1 ? "True" : "False"); +} + +static void json_feature_show_fields_sanitize(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "No-Deallocate Response Mode (NODRM)", result & 1); +} + +static void json_feature_show_fields_endurance_evt_cfg(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "Endurance Group Identifier (ENDGID)", result & 0xffff); + obj_add_uint(r, "Endurance Group Critical Warnings", result >> 16 & 0xff); +} + +static void json_feature_show_fields_iocs_profile(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "I/O Command Set Profile", result & 0x1 ? "True" : "False"); +} + +static void json_feature_show_fields_spinup_control(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Spinup control feature Enabled", result & 1 ? "True" : "False"); +} + +static void json_host_metadata(struct json_object *r, enum nvme_features_id fid, + struct nvme_host_metadata *data) +{ + struct nvme_metadata_element_desc *desc = &data->descs[0]; + int i; + char val[VAL_LEN]; + __u16 len; + char json_str[STR_LEN]; + struct json_object *desca = json_create_array(); + struct json_object *desce; + + obj_add_int(r, "Num Metadata Element Descriptors", data->ndesc); + + obj_add_array(r, "Metadata Element Descriptors", desca); + + for (i = 0; i < data->ndesc; i++) { + desce = json_create_object(); + array_add_obj(desca, desce); + + obj_add_int(desce, "Element", i); + + sprintf(json_str, "0x%02x", desc->type); + obj_add_str(desce, "Type", json_str); + + obj_add_str(desce, "Type definition", + nvme_host_metadata_type_to_string(fid, desc->type)); + + obj_add_int(desce, "Revision", desc->rev); + + len = le16_to_cpu(desc->len); + obj_add_int(desce, "Length", len); + + strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len)); + obj_add_str(desce, "Value", val); + + desc = (struct nvme_metadata_element_desc *)&desc->val[desc->len]; + } +} + +static void json_feature_show_fields_ns_metadata(struct json_object *r, enum nvme_features_id fid, + unsigned char *buf) +{ + if (buf) + json_host_metadata(r, fid, (struct nvme_host_metadata *)buf); +} + +static void json_feature_show_fields_sw_progress(struct json_object *r, unsigned int result) +{ + obj_add_uint(r, "Pre-boot Software Load Count (PBSLC)", result & 0xff); +} + +static void json_feature_show_fields_host_id(struct json_object *r, unsigned char *buf) +{ + uint64_t ull = 0; + int i; + + if (buf) { + for (i = sizeof(ull) / sizeof(*buf); i; i--) { + ull |= buf[i - 1]; + if (i - 1) + ull <<= BYTE_TO_BIT(sizeof(buf[i])); + } + obj_add_uint64(r, "Host Identifier (HOSTID)", ull); + } +} + +static void json_feature_show_fields_resv_mask(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Mask Reservation Preempted Notification (RESPRE)", (result & 8) >> 3 ? + "True" : "False"); + obj_add_str(r, "Mask Reservation Released Notification (RESREL)", (result & 4) >> 2 ? + "True" : "False"); + obj_add_str(r, "Mask Registration Preempted Notification (REGPRE)", (result & 2) >> 1 ? + "True" : "False"); +} + +static void json_feature_show_fields_resv_persist(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Persist Through Power Loss (PTPL)", result & 1 ? "True" : "False"); +} + +static void json_feature_show_fields_write_protect(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Namespace Write Protect", nvme_ns_wp_cfg_to_string(result)); +} + +static void json_feature_show_fields_fdp(struct json_object *r, unsigned int result) +{ + obj_add_str(r, "Flexible Direct Placement Enable (FDPE)", result & 1 ? "Yes" : "No"); + obj_add_uint(r, "Flexible Direct Placement Configuration Index", result >> 8 & 0xf); +} + +static void json_feature_show_fields_fdp_events(struct json_object *r, unsigned int result, + unsigned char *buf) +{ + unsigned int i; + struct nvme_fdp_supported_event_desc *d; + char json_str[STR_LEN]; + + for (i = 0; i < result; i++) { + d = &((struct nvme_fdp_supported_event_desc *)buf)[i]; + sprintf(json_str, "%s", d->evta & 0x1 ? "Enabled" : "Not enabled"); + obj_add_str(r, nvme_fdp_event_to_string(d->evt), json_str); + } +} + +static void json_feature_show(enum nvme_features_id fid, int sel, unsigned int result) +{ + struct json_object *r; + char json_str[STR_LEN]; + + sprintf(json_str, "feature: %#0*x", fid ? 4 : 2, fid); + r = obj_create(json_str); + + obj_add_str(r, "name", nvme_feature_to_string(fid)); + + sprintf(json_str, "%#0*x", result ? 10 : 8, result); + obj_add_str(r, nvme_select_to_string(sel), json_str); + + obj_print(r); +} + +static void json_feature_show_fields(enum nvme_features_id fid, unsigned int result, + unsigned char *buf) +{ + struct json_object *r; + char json_str[STR_LEN]; + + sprintf(json_str, "Feature: %#0*x", fid ? 4 : 2, fid); + r = obj_create(json_str); + + switch (fid) { + case NVME_FEAT_FID_ARBITRATION: + json_feature_show_fields_arbitration(r, result); + break; + case NVME_FEAT_FID_POWER_MGMT: + json_feature_show_fields_power_mgmt(r, result); + break; + case NVME_FEAT_FID_LBA_RANGE: + json_feature_show_fields_lba_range(r, result & 0x3f, buf); + break; + case NVME_FEAT_FID_TEMP_THRESH: + json_feature_show_fields_temp_thresh(r, result); + break; + case NVME_FEAT_FID_ERR_RECOVERY: + json_feature_show_fields_err_recovery(r, result); + break; + case NVME_FEAT_FID_VOLATILE_WC: + json_feature_show_fields_volatile_wc(r, result); + break; + case NVME_FEAT_FID_NUM_QUEUES: + json_feature_show_fields_num_queues(r, result); + break; + case NVME_FEAT_FID_IRQ_COALESCE: + json_feature_show_fields_irq_coalesce(r, result); + break; + case NVME_FEAT_FID_IRQ_CONFIG: + json_feature_show_fields_irq_config(r, result); + break; + case NVME_FEAT_FID_WRITE_ATOMIC: + json_feature_show_fields_write_atomic(r, result); + break; + case NVME_FEAT_FID_ASYNC_EVENT: + json_feature_show_fields_async_event(r, result); + break; + case NVME_FEAT_FID_AUTO_PST: + json_feature_show_fields_auto_pst(r, result, buf); + break; + case NVME_FEAT_FID_HOST_MEM_BUF: + json_feature_show_fields_host_mem_buf(r, result, buf); + break; + case NVME_FEAT_FID_TIMESTAMP: + json_feature_show_fields_timestamp(r, buf); + break; + case NVME_FEAT_FID_KATO: + json_feature_show_fields_kato(r, result); + break; + case NVME_FEAT_FID_HCTM: + json_feature_show_fields_hctm(r, result); + break; + case NVME_FEAT_FID_NOPSC: + json_feature_show_fields_nopsc(r, result); + break; + case NVME_FEAT_FID_RRL: + json_feature_show_fields_rrl(r, result); + break; + case NVME_FEAT_FID_PLM_CONFIG: + json_feature_show_fields_plm_config(r, result, buf); + break; + case NVME_FEAT_FID_PLM_WINDOW: + json_feature_show_fields_plm_window(r, result); + break; + case NVME_FEAT_FID_LBA_STS_INTERVAL: + json_feature_show_fields_lba_sts_interval(r, result); + break; + case NVME_FEAT_FID_HOST_BEHAVIOR: + json_feature_show_fields_host_behavior(r, buf); + break; + case NVME_FEAT_FID_SANITIZE: + json_feature_show_fields_sanitize(r, result); + break; + case NVME_FEAT_FID_ENDURANCE_EVT_CFG: + json_feature_show_fields_endurance_evt_cfg(r, result); + break; + case NVME_FEAT_FID_IOCS_PROFILE: + json_feature_show_fields_iocs_profile(r, result); + break; + case NVME_FEAT_FID_SPINUP_CONTROL: + json_feature_show_fields_spinup_control(r, result); + break; + case NVME_FEAT_FID_ENH_CTRL_METADATA: + case NVME_FEAT_FID_CTRL_METADATA: + case NVME_FEAT_FID_NS_METADATA: + json_feature_show_fields_ns_metadata(r, fid, buf); + break; + case NVME_FEAT_FID_SW_PROGRESS: + json_feature_show_fields_sw_progress(r, result); + break; + case NVME_FEAT_FID_HOST_ID: + json_feature_show_fields_host_id(r, buf); + break; + case NVME_FEAT_FID_RESV_MASK: + json_feature_show_fields_resv_mask(r, result); + break; + case NVME_FEAT_FID_RESV_PERSIST: + json_feature_show_fields_resv_persist(r, result); + break; + case NVME_FEAT_FID_WRITE_PROTECT: + json_feature_show_fields_write_protect(r, result); + break; + case NVME_FEAT_FID_FDP: + json_feature_show_fields_fdp(r, result); + break; + case NVME_FEAT_FID_FDP_EVENTS: + json_feature_show_fields_fdp_events(r, result, buf); + break; + default: + break; + } + + obj_print(r); +} + +void json_id_ctrl_rpmbs(__le32 ctrl_rpmbs) +{ + struct json_object *r = json_create_object(); + __u32 rpmbs = le32_to_cpu(ctrl_rpmbs); + __u32 asz = (rpmbs & 0xFF000000) >> 24; + __u32 tsz = (rpmbs & 0xFF0000) >> 16; + __u32 rsvd = (rpmbs & 0xFFC0) >> 6; + __u32 auth = (rpmbs & 0x38) >> 3; + __u32 rpmb = rpmbs & 7; + + obj_add_uint_nx(r, "[31:24]: Access Size", asz); + obj_add_uint_nx(r, "[23:16]: Total Size", tsz); + + if (rsvd) + obj_add_uint_nx(r, "[15:6]: Reserved", rsvd); + + obj_add_uint_nx(r, "[5:3]: Authentication Method", auth); + obj_add_uint_nx(r, "[2:0]: Number of RPMB Units", rpmb); + + json_print(r); +} + +static void json_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges) +{ + struct json_object *r = json_create_object(); + + json_lba_range_entry(lbrt, nr_ranges, r); + + json_print(r); +} + +static void json_lba_status_info(__u32 result) +{ + struct json_object *r = json_create_object(); + + obj_add_uint(r, "LBA Status Information Poll Interval (LSIPI)", (result >> 16) & 0xffff); + obj_add_uint(r, "LBA Status Information Report Interval (LSIRI)", result & 0xffff); + + json_print(r); +} + +void json_d(unsigned char *buf, int len, int width, int group) +{ + struct json_object *r = json_r ? json_r : json_create_object(); + char json_str[STR_LEN]; + struct json_object *data = json_create_array(); + + sprintf(json_str, "data: buf=%p len=%d width=%d group=%d", buf, len, width, group); + d_json(buf, len, width, group, data); + obj_add_array(r, json_str, data); + + obj_print(r); +} + +static void json_nvme_list_ctrl(struct nvme_ctrl_list *ctrl_list) +{ + __u16 num = le16_to_cpu(ctrl_list->num); + struct json_object *r = json_create_object(); + struct json_object *valid_attrs; + struct json_object *valid = json_create_array(); + int i; + + obj_add_uint(r, "num_ctrl", le16_to_cpu(ctrl_list->num)); + + for (i = 0; i < min(num, 2047); i++) { + valid_attrs = json_create_object(); + obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(ctrl_list->identifier[i])); + array_add_obj(valid, valid_attrs); + } + + obj_add_array(r, "ctrl_list", valid); + + json_print(r); +} + +static void json_nvme_id_nvmset(struct nvme_id_nvmset_list *nvmset, + unsigned int nvmeset_id) +{ + __u32 nent = nvmset->nid; + struct json_object *entries = json_create_array(); + struct json_object *r = json_create_object(); + int i; + + obj_add_int(r, "nid", nent); + + for (i = 0; i < nent; i++) { + struct json_object *entry = json_create_object(); + + obj_add_int(entry, "nvmset_id", le16_to_cpu(nvmset->ent[i].nvmsetid)); + obj_add_int(entry, "endurance_group_id", le16_to_cpu(nvmset->ent[i].endgid)); + obj_add_uint(entry, "random_4k_read_typical", le32_to_cpu(nvmset->ent[i].rr4kt)); + obj_add_uint(entry, "optimal_write_size", le32_to_cpu(nvmset->ent[i].ows)); + obj_add_uint128(entry, "total_nvmset_cap", le128_to_cpu(nvmset->ent[i].tnvmsetcap)); + obj_add_uint128(entry, "unalloc_nvmset_cap", + le128_to_cpu(nvmset->ent[i].unvmsetcap)); + array_add_obj(entries, entry); + } + + obj_add_array(r, "NVMSet", entries); + + json_print(r); +} + +static void json_nvme_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps) +{ + struct json_object *r = json_create_object(); + + obj_add_uint(r, "cntlid", le16_to_cpu(caps->cntlid)); + obj_add_uint(r, "portid", le16_to_cpu(caps->portid)); + obj_add_uint(r, "crt", caps->crt); + + obj_add_uint(r, "vqfrt", le32_to_cpu(caps->vqfrt)); + obj_add_uint(r, "vqrfa", le32_to_cpu(caps->vqrfa)); + obj_add_int(r, "vqrfap", le16_to_cpu(caps->vqrfap)); + obj_add_int(r, "vqprt", le16_to_cpu(caps->vqprt)); + obj_add_int(r, "vqfrsm", le16_to_cpu(caps->vqfrsm)); + obj_add_int(r, "vqgran", le16_to_cpu(caps->vqgran)); + + obj_add_uint(r, "vifrt", le32_to_cpu(caps->vifrt)); + obj_add_uint(r, "virfa", le32_to_cpu(caps->virfa)); + obj_add_int(r, "virfap", le16_to_cpu(caps->virfap)); + obj_add_int(r, "viprt", le16_to_cpu(caps->viprt)); + obj_add_int(r, "vifrsm", le16_to_cpu(caps->vifrsm)); + obj_add_int(r, "vigran", le16_to_cpu(caps->vigran)); + + json_print(r); +} + +static void json_nvme_list_secondary_ctrl(const struct nvme_secondary_ctrl_list *sc_list, + __u32 count) +{ + const struct nvme_secondary_ctrl *sc_entry = &sc_list->sc_entry[0]; + __u32 nent = min(sc_list->num, count); + struct json_object *entries = json_create_array(); + struct json_object *r = json_create_object(); + int i; + + obj_add_int(r, "num", nent); + + for (i = 0; i < nent; i++) { + struct json_object *entry = json_create_object(); + + obj_add_int(entry, "secondary-controller-identifier", + le16_to_cpu(sc_entry[i].scid)); + obj_add_int(entry, "primary-controller-identifier", le16_to_cpu(sc_entry[i].pcid)); + obj_add_int(entry, "secondary-controller-state", sc_entry[i].scs); + obj_add_int(entry, "virtual-function-number", le16_to_cpu(sc_entry[i].vfn)); + obj_add_int(entry, "num-virtual-queues", le16_to_cpu(sc_entry[i].nvq)); + obj_add_int(entry, "num-virtual-interrupts", le16_to_cpu(sc_entry[i].nvi)); + array_add_obj(entries, entry); + } + + obj_add_array(r, "secondary-controllers", entries); + + json_print(r); +} + +static void json_nvme_id_ns_granularity_list( + const struct nvme_id_ns_granularity_list *glist) +{ + int i; + struct json_object *r = json_create_object(); + struct json_object *entries = json_create_array(); + + obj_add_int(r, "attributes", glist->attributes); + obj_add_int(r, "num-descriptors", glist->num_descriptors); + + for (i = 0; i <= glist->num_descriptors; i++) { + struct json_object *entry = json_create_object(); + + obj_add_uint64(entry, "namespace-size-granularity", + le64_to_cpu(glist->entry[i].nszegran)); + obj_add_uint64(entry, "namespace-capacity-granularity", + le64_to_cpu(glist->entry[i].ncapgran)); + array_add_obj(entries, entry); + } + + obj_add_array(r, "namespace-granularity-list", entries); + + json_print(r); +} + +static void json_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list) +{ + struct json_object *r = json_create_object(); + struct json_object *entries = json_create_array(); + int i; + + for (i = 0; i < NVME_ID_UUID_LIST_MAX; i++) { + __u8 uuid[NVME_UUID_LEN]; + struct json_object *entry = json_create_object(); + + /* The list is terminated by a zero UUID value */ + if (memcmp(uuid_list->entry[i].uuid, zero_uuid, sizeof(zero_uuid)) == 0) + break; + memcpy(&uuid, uuid_list->entry[i].uuid, sizeof(uuid)); + obj_add_int(entry, "association", + uuid_list->entry[i].header & 0x3); + obj_add_str(entry, "uuid", + util_uuid_to_string(uuid)); + array_add_obj(entries, entry); + } + + obj_add_array(r, "UUID-list", entries); + + json_print(r); +} + +static void json_id_domain_list(struct nvme_id_domain_list *id_dom) +{ + struct json_object *r = json_create_object(); + struct json_object *entries = json_create_array(); + struct json_object *entry; + int i; + nvme_uint128_t dom_cap, unalloc_dom_cap, max_egrp_dom_cap; + + obj_add_uint(r, "num_dom_entries", id_dom->num); + + for (i = 0; i < id_dom->num; i++) { + entry = json_create_object(); + dom_cap = le128_to_cpu(id_dom->domain_attr[i].dom_cap); + unalloc_dom_cap = le128_to_cpu(id_dom->domain_attr[i].unalloc_dom_cap); + max_egrp_dom_cap = le128_to_cpu(id_dom->domain_attr[i].max_egrp_dom_cap); + + obj_add_uint(entry, "dom_id", le16_to_cpu(id_dom->domain_attr[i].dom_id)); + obj_add_uint128(entry, "dom_cap", dom_cap); + obj_add_uint128(entry, "unalloc_dom_cap", unalloc_dom_cap); + obj_add_uint128(entry, "max_egrp_dom_cap", max_egrp_dom_cap); + + array_add_obj(entries, entry); + } + + obj_add_array(r, "domain_list", entries); + + json_print(r); +} + +static void json_nvme_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list) +{ + struct json_object *r = json_create_object(); + struct json_object *valid_attrs; + struct json_object *valid = json_create_array(); + int i; + + obj_add_uint(r, "num_endgrp_id", le16_to_cpu(endgrp_list->num)); + + for (i = 0; i < min(le16_to_cpu(endgrp_list->num), 2047); i++) { + valid_attrs = json_create_object(); + obj_add_uint(valid_attrs, "endgrp_id", le16_to_cpu(endgrp_list->identifier[i])); + array_add_obj(valid, valid_attrs); + } + + obj_add_array(r, "endgrp_list", valid); + + json_print(r); +} + +static void json_support_log(struct nvme_supported_log_pages *support_log, + const char *devname) +{ + struct json_object *r = json_create_object(); + struct json_object *valid = json_create_array(); + struct json_object *valid_attrs; + unsigned int lid; + char key[128]; + __u32 support; + + for (lid = 0; lid < 256; lid++) { + support = le32_to_cpu(support_log->lid_support[lid]); + if (support & 0x1) { + valid_attrs = json_create_object(); + sprintf(key, "lid_0x%x ", lid); + obj_add_uint(valid_attrs, key, support); + array_add_obj(valid, valid_attrs); + } + } + + obj_add_array(r, "supported_logs", valid); + + json_print(r); +} + +static void json_detail_list(nvme_root_t t) +{ + struct json_object *r = json_create_object(); + struct json_object *jdev = json_create_array(); + + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + nvme_path_t p; + nvme_ns_t n; + + nvme_for_each_host(t, h) { + struct json_object *hss = json_create_object(); + struct json_object *jsslist = json_create_array(); + const char *hostid; + + obj_add_str(hss, "HostNQN", nvme_host_get_hostnqn(h)); + hostid = nvme_host_get_hostid(h); + if (hostid) + obj_add_str(hss, "HostID", hostid); + + nvme_for_each_subsystem(h , s) { + struct json_object *jss = json_create_object(); + struct json_object *jctrls = json_create_array(); + struct json_object *jnss = json_create_array(); + + obj_add_str(jss, "Subsystem", nvme_subsystem_get_name(s)); + obj_add_str(jss, "SubsystemNQN", nvme_subsystem_get_nqn(s)); + + nvme_subsystem_for_each_ctrl(s, c) { + struct json_object *jctrl = json_create_object(); + struct json_object *jnss = json_create_array(); + struct json_object *jpaths = json_create_array(); + + obj_add_str(jctrl, "Controller", nvme_ctrl_get_name(c)); + obj_add_str(jctrl, "SerialNumber", nvme_ctrl_get_serial(c)); + obj_add_str(jctrl, "ModelNumber", nvme_ctrl_get_model(c)); + obj_add_str(jctrl, "Firmware", nvme_ctrl_get_firmware(c)); + obj_add_str(jctrl, "Transport", nvme_ctrl_get_transport(c)); + obj_add_str(jctrl, "Address", nvme_ctrl_get_address(c)); + obj_add_str(jctrl, "Slot", nvme_ctrl_get_phy_slot(c)); + + nvme_ctrl_for_each_ns(c, n) { + struct json_object *jns = json_create_object(); + int lba = nvme_ns_get_lba_size(n); + uint64_t nsze = nvme_ns_get_lba_count(n) * lba; + uint64_t nuse = nvme_ns_get_lba_util(n) * lba; + + obj_add_str(jns, "NameSpace", nvme_ns_get_name(n)); + obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n)); + obj_add_int(jns, "NSID", nvme_ns_get_nsid(n)); + obj_add_uint64(jns, "UsedBytes", nuse); + obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n)); + obj_add_uint64(jns, "PhysicalSize", nsze); + obj_add_int(jns, "SectorSize", lba); + + array_add_obj(jnss, jns); + } + obj_add_obj(jctrl, "Namespaces", jnss); + + nvme_ctrl_for_each_path(c, p) { + struct json_object *jpath = json_create_object(); + + obj_add_str(jpath, "Path", nvme_path_get_name(p)); + obj_add_str(jpath, "ANAState", nvme_path_get_ana_state(p)); + + array_add_obj(jpaths, jpath); + } + obj_add_obj(jctrl, "Paths", jpaths); + + array_add_obj(jctrls, jctrl); + } + obj_add_obj(jss, "Controllers", jctrls); + + nvme_subsystem_for_each_ns(s, n) { + struct json_object *jns = json_create_object(); + + int lba = nvme_ns_get_lba_size(n); + uint64_t nsze = nvme_ns_get_lba_count(n) * lba; + uint64_t nuse = nvme_ns_get_lba_util(n) * lba; + + obj_add_str(jns, "NameSpace", nvme_ns_get_name(n)); + obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n)); + obj_add_int(jns, "NSID", nvme_ns_get_nsid(n)); + obj_add_uint64(jns, "UsedBytes", nuse); + obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n)); + obj_add_uint64(jns, "PhysicalSize", nsze); + obj_add_int(jns, "SectorSize", lba); + + array_add_obj(jnss, jns); + } + obj_add_obj(jss, "Namespaces", jnss); + + array_add_obj(jsslist, jss); + } + + obj_add_obj(hss, "Subsystems", jsslist); + array_add_obj(jdev, hss); + } + + obj_add_array(r, "Devices", jdev); + + json_print(r); +} + +static struct json_object *json_list_item_obj(nvme_ns_t n) +{ + struct json_object *r = json_create_object(); + char devname[NAME_LEN] = { 0 }; + char genname[NAME_LEN] = { 0 }; + int lba = nvme_ns_get_lba_size(n); + uint64_t nsze = nvme_ns_get_lba_count(n) * lba; + uint64_t nuse = nvme_ns_get_lba_util(n) * lba; + + nvme_dev_full_path(n, devname, sizeof(devname)); + nvme_generic_full_path(n, genname, sizeof(genname)); + + obj_add_int(r, "NameSpace", nvme_ns_get_nsid(n)); + obj_add_str(r, "DevicePath", devname); + obj_add_str(r, "GenericPath", genname); + obj_add_str(r, "Firmware", nvme_ns_get_firmware(n)); + obj_add_str(r, "ModelNumber", nvme_ns_get_model(n)); + obj_add_str(r, "SerialNumber", nvme_ns_get_serial(n)); + obj_add_uint64(r, "UsedBytes", nuse); + obj_add_uint64(r, "MaximumLBA", nvme_ns_get_lba_count(n)); + obj_add_uint64(r, "PhysicalSize", nsze); + obj_add_int(r, "SectorSize", lba); + + return r; +} + +static void json_simple_list(nvme_root_t t) +{ + struct json_object *r = json_create_object(); + struct json_object *jdevices = json_create_array(); + + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + nvme_ns_t n; + + nvme_for_each_host(t, h) { + nvme_for_each_subsystem(h, s) { + nvme_subsystem_for_each_ns(s, n) + array_add_obj(jdevices, json_list_item_obj(n)); + + nvme_subsystem_for_each_ctrl(s, c) + nvme_ctrl_for_each_ns(c, n) + array_add_obj(jdevices, json_list_item_obj(n)); + } + } + + obj_add_array(r, "Devices", jdevices); + + json_print(r); +} + +static void json_list_item(nvme_ns_t n) +{ + struct json_object *r = json_list_item_obj(n); + + json_print(r); +} + +static void json_print_list_items(nvme_root_t t) +{ + if (json_print_ops.flags & VERBOSE) + json_detail_list(t); + else + json_simple_list(t); +} + +static unsigned int json_subsystem_topology_multipath(nvme_subsystem_t s, + json_object *namespaces) +{ + nvme_ns_t n; + nvme_path_t p; + unsigned int i = 0; + + nvme_subsystem_for_each_ns(s, n) { + struct json_object *ns_attrs; + struct json_object *paths; + + ns_attrs = json_create_object(); + obj_add_int(ns_attrs, "NSID", nvme_ns_get_nsid(n)); + + paths = json_create_array(); + nvme_namespace_for_each_path(n, p) { + struct json_object *path_attrs; + + nvme_ctrl_t c = nvme_path_get_ctrl(p); + + path_attrs = json_create_object(); + obj_add_str(path_attrs, "Name", nvme_ctrl_get_name(c)); + obj_add_str(path_attrs, "Transport", nvme_ctrl_get_transport(c)); + obj_add_str(path_attrs, "Address", nvme_ctrl_get_address(c)); + obj_add_str(path_attrs, "State", nvme_ctrl_get_state(c)); + obj_add_str(path_attrs, "ANAState", nvme_path_get_ana_state(p)); + array_add_obj(paths, path_attrs); + } + obj_add_array(ns_attrs, "Paths", paths); + array_add_obj(namespaces, ns_attrs); + i++; + } + + return i; +} + +static void json_print_nvme_subsystem_topology(nvme_subsystem_t s, + json_object *namespaces) +{ + nvme_ctrl_t c; + nvme_ns_t n; + + nvme_subsystem_for_each_ctrl(s, c) { + nvme_ctrl_for_each_ns(c, n) { + struct json_object *ctrl_attrs; + struct json_object *ns_attrs; + struct json_object *ctrl; + + ns_attrs = json_create_object(); + obj_add_int(ns_attrs, "NSID", nvme_ns_get_nsid(n)); + + ctrl = json_create_array(); + ctrl_attrs = json_create_object(); + obj_add_str(ctrl_attrs, "Name", + nvme_ctrl_get_name(c)); + obj_add_str(ctrl_attrs, "Transport", + nvme_ctrl_get_transport(c)); + obj_add_str(ctrl_attrs, "Address", + nvme_ctrl_get_address(c)); + obj_add_str(ctrl_attrs, "State", + nvme_ctrl_get_state(c)); + + array_add_obj(ctrl, ctrl_attrs); + obj_add_array(ns_attrs, "Controller", ctrl); + array_add_obj(namespaces, ns_attrs); + } + } +} + +static void json_simple_topology(nvme_root_t r) +{ + struct json_object *host_attrs, *subsystem_attrs; + struct json_object *subsystems, *namespaces; + struct json_object *a = json_create_array(); + nvme_host_t h; + + nvme_for_each_host(r, h) { + nvme_subsystem_t s; + const char *hostid; + + host_attrs = json_create_object(); + obj_add_str(host_attrs, "HostNQN", nvme_host_get_hostnqn(h)); + hostid = nvme_host_get_hostid(h); + if (hostid) + obj_add_str(host_attrs, "HostID", hostid); + subsystems = json_create_array(); + nvme_for_each_subsystem(h, s) { + subsystem_attrs = json_create_object(); + obj_add_str(subsystem_attrs, "Name", nvme_subsystem_get_name(s)); + obj_add_str(subsystem_attrs, "NQN", nvme_subsystem_get_nqn(s)); + obj_add_str(subsystem_attrs, "IOPolicy", nvme_subsystem_get_iopolicy(s)); + + array_add_obj(subsystems, subsystem_attrs); + namespaces = json_create_array(); + + if (!json_subsystem_topology_multipath(s, namespaces)) + json_print_nvme_subsystem_topology(s, namespaces); + + obj_add_array(subsystem_attrs, "Namespaces", namespaces); + } + obj_add_array(host_attrs, "Subsystems", subsystems); + array_add_obj(a, host_attrs); + } + + json_print(a); +} + +static void json_directive_show_fields_identify(__u8 doper, __u8 *field, struct json_object *r) +{ + struct json_object *support; + struct json_object *enabled; + struct json_object *persistent; + + switch (doper) { + case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM: + support = json_create_array(); + obj_add_array(r, "Directive support", support); + obj_add_str(support, "Identify Directive", + *field & 0x1 ? "Supported" : "Not supported"); + obj_add_str(support, "Stream Directive", + *field & 0x2 ? "Supported" : "Not supported"); + obj_add_str(support, "Data Placement Directive", + *field & 0x4 ? "Supported" : "Not supported"); + enabled = json_create_array(); + obj_add_array(r, "Directive enabled", enabled); + obj_add_str(enabled, "Identify Directive", + *(field + 32) & 0x1 ? "Enabled" : "Disabled"); + obj_add_str(enabled, "Stream Directive", + *(field + 32) & 0x2 ? "Enabled" : "Disabled"); + obj_add_str(enabled, "Data Placement Directive", + *(field + 32) & 0x4 ? "Enabled" : "Disabled"); + persistent = json_create_array(); + obj_add_array(r, "Directive Persistent Across Controller Level Resets", + persistent); + obj_add_str(persistent, "Identify Directive", + *(field + 64) & 0x1 ? "Enabled" : "Disabled"); + obj_add_str(persistent, "Stream Directive", + *(field + 64) & 0x2 ? "Enabled" : "Disabled"); + obj_add_str(persistent, "Data Placement Directive", + *(field + 64) & 0x4 ? "Enabled" : "Disabled"); + break; + default: + obj_add_str(r, "Error", "invalid directive operations for Identify Directives"); + break; + } +} + +static void json_directive_show_fields_streams(__u8 doper, unsigned int result, __u16 *field, + struct json_object *r) +{ + int count; + int i; + char json_str[STR_LEN]; + + switch (doper) { + case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM: + obj_add_uint(r, "Max Streams Limit (MSL)", le16_to_cpu(*field)); + obj_add_uint(r, "NVM Subsystem Streams Available (NSSA)", le16_to_cpu(*(field + 2))); + obj_add_uint(r, "NVM Subsystem Streams Open (NSSO)", le16_to_cpu(*(field + 4))); + obj_add_uint(r, "NVM Subsystem Stream Capability (NSSC)", le16_to_cpu(*(field + 6))); + obj_add_uint(r, "Stream Write Size (in unit of LB size) (SWS)", + le16_to_cpu(*(__u32 *)(field + 16))); + obj_add_uint(r, "Stream Granularity Size (in unit of SWS) (SGS)", + le16_to_cpu(*(field + 20))); + obj_add_uint(r, "Namespace Streams Allocated (NSA)", le16_to_cpu(*(field + 22))); + obj_add_uint(r, "Namespace Streams Open (NSO)", le16_to_cpu(*(field + 24))); + break; + case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS: + count = *field; + obj_add_uint(r, "Open Stream Count", le16_to_cpu(*field)); + for (i = 0; i < count; i++) { + sprintf(json_str, "Stream Identifier %.6u", i + 1); + obj_add_uint(r, json_str, le16_to_cpu(*(field + (i + 1) * 2))); + } + break; + case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE: + obj_add_uint(r, "Namespace Streams Allocated (NSA)", result & 0xffff); + break; + default: + obj_add_str(r, "Error", + "invalid directive operations for Streams Directives"); + break; + } +} + +static void json_directive_show_fields(__u8 dtype, __u8 doper, unsigned int result, + __u8 *field, struct json_object *r) +{ + switch (dtype) { + case NVME_DIRECTIVE_DTYPE_IDENTIFY: + json_directive_show_fields_identify(doper, field, r); + break; + case NVME_DIRECTIVE_DTYPE_STREAMS: + json_directive_show_fields_streams(doper, result, (__u16 *)field, r); + break; + default: + obj_add_str(r, "Error", "invalid directive type"); + break; + } +} + +static void json_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, + void *buf, __u32 len) +{ + struct json_object *r = json_create_object(); + struct json_object *data; + char json_str[STR_LEN]; + + sprintf(json_str, "%#x", type); + obj_add_str(r, "Type", json_str); + sprintf(json_str, "%#x", oper); + obj_add_str(r, "Operation", json_str); + sprintf(json_str, "%#x", spec); + obj_add_str(r, "spec", json_str); + sprintf(json_str, "%#x", nsid); + obj_add_str(r, "NSID", json_str); + sprintf(json_str, "%#x", result); + obj_add_result(r, json_str); + + if (json_print_ops.flags & VERBOSE) { + json_directive_show_fields(type, oper, result, buf, r); + } else if (buf) { + data = json_create_array(); + d_json((unsigned char *)buf, len, 16, 1, data); + obj_add_array(r, "data", data); + } + + json_print(r); +} + +static void json_discovery_log(struct nvmf_discovery_log *log, int numrec) +{ + struct json_object *r = json_create_object(); + struct json_object *entries = json_create_array(); + int i; + + obj_add_uint64(r, "genctr", le64_to_cpu(log->genctr)); + obj_add_array(r, "records", entries); + + for (i = 0; i < numrec; i++) { + struct nvmf_disc_log_entry *e = &log->entries[i]; + struct json_object *entry = json_create_object(); + + obj_add_str(entry, "trtype", nvmf_trtype_str(e->trtype)); + obj_add_str(entry, "adrfam", nvmf_adrfam_str(e->adrfam)); + obj_add_str(entry, "subtype", nvmf_subtype_str(e->subtype)); + obj_add_str(entry,"treq", nvmf_treq_str(e->treq)); + obj_add_uint(entry, "portid", le16_to_cpu(e->portid)); + obj_add_str(entry, "trsvcid", e->trsvcid); + obj_add_str(entry, "subnqn", e->subnqn); + obj_add_str(entry, "traddr", e->traddr); + obj_add_str(entry, "eflags", nvmf_eflags_str(le16_to_cpu(e->eflags))); + + switch (e->trtype) { + case NVMF_TRTYPE_RDMA: + obj_add_str(entry, "rdma_prtype", nvmf_prtype_str(e->tsas.rdma.prtype)); + obj_add_str(entry, "rdma_qptype", nvmf_qptype_str(e->tsas.rdma.qptype)); + obj_add_str(entry, "rdma_cms", nvmf_cms_str(e->tsas.rdma.cms)); + obj_add_uint(entry, "rdma_pkey", le16_to_cpu(e->tsas.rdma.pkey)); + break; + case NVMF_TRTYPE_TCP: + obj_add_str(entry, "sectype", nvmf_sectype_str(e->tsas.tcp.sectype)); + break; + default: + break; + } + array_add_obj(entries, entry); + } + + json_print(r); +} + +static void json_connect_msg(nvme_ctrl_t c) +{ + struct json_object *r = json_create_object(); + + obj_add_str(r, "device", nvme_ctrl_get_name(c)); + + json_print(r); +} + +static void json_output_object(struct json_object *r) +{ + json_print(r); +} + +static void json_output_status(int status) +{ + struct json_object *r; + char json_str[STR_LEN]; + int val; + int type; + + sprintf(json_str, "status: %d", status); + r = obj_create(json_str); + + if (status < 0) { + obj_add_str(r, "error", nvme_strerror(errno)); + obj_print(r); + return; + } + + val = nvme_status_get_value(status); + type = nvme_status_get_type(status); + + switch (type) { + case NVME_STATUS_TYPE_NVME: + obj_add_str(r, "error", nvme_status_to_string(val, false)); + obj_add_str(r, "type", "nvme"); + break; + case NVME_STATUS_TYPE_MI: + obj_add_str(r, "error", nvme_mi_status_to_string(val)); + obj_add_str(r, "type", "nvme-mi"); + break; + default: + obj_add_str(r, "type", "Unknown"); + break; + } + + obj_print(r); +} + +static void json_output_error_status(int status, const char *msg, va_list ap) +{ + struct json_object *r; + char json_str[STR_LEN]; + char *value; + int val; + int type; + + if (vasprintf(&value, msg, ap) < 0) + value = NULL; + + sprintf(json_str, "Error: %s", value ? value : "Could not allocate string"); + r = obj_create(json_str); + + free(value); + + if (status < 0) { + obj_add_str(r, "error", nvme_strerror(errno)); + obj_print(r); + return; + } + + val = nvme_status_get_value(status); + type = nvme_status_get_type(status); + + switch (type) { + case NVME_STATUS_TYPE_NVME: + obj_add_str(r, "status", nvme_status_to_string(val, false)); + obj_add_str(r, "type", "nvme"); + break; + case NVME_STATUS_TYPE_MI: + obj_add_str(r, "status", nvme_mi_status_to_string(val)); + obj_add_str(r, "type", "nvme-mi"); + break; + default: + obj_add_str(r, "type", "Unknown"); + break; + } + + obj_add_int(r, "value", val); + + obj_print(r); +} + +static void json_output_message(bool error, const char *msg, va_list ap) +{ + struct json_object *r = json_r ? json_r : json_create_object(); + char *value; + + if (vasprintf(&value, msg, ap) < 0) + value = NULL; + + obj_add_str(r, error ? "error" : "result", value ? value : "Could not allocate string"); + + free(value); + + obj_print(r); +} + +static void json_output_perror(const char *msg) +{ + struct json_object *r = json_create_object(); + char *error; + + if (asprintf(&error, "%s: %s", msg, strerror(errno)) < 0) + error = NULL; + + if (error) + obj_add_str(r, "error", error); + else + obj_add_str(r, "error", "Could not allocate string"); + + json_output_object(r); + + free(error); +} + +void json_show_init(void) +{ + json_r = json_create_object(); +} + +void json_show_finish(void) +{ + if (json_r) + json_output_object(json_r); + + json_r = NULL; +} + +static struct print_ops json_print_ops = { + /* libnvme types.h print functions */ + .ana_log = json_ana_log, + .boot_part_log = json_boot_part_log, + .phy_rx_eom_log = json_phy_rx_eom_log, + .ctrl_list = json_nvme_list_ctrl, + .ctrl_registers = json_ctrl_registers, + .directive = json_directive_show, + .discovery_log = json_discovery_log, + .effects_log_list = json_effects_log_list, + .endurance_group_event_agg_log = json_endurance_group_event_agg_log, + .endurance_group_list = json_nvme_endurance_group_list, + .endurance_log = json_endurance_log, + .error_log = json_error_log, + .fdp_config_log = json_nvme_fdp_configs, + .fdp_event_log = json_nvme_fdp_events, + .fdp_ruh_status = json_nvme_fdp_ruh_status, + .fdp_stats_log = json_nvme_fdp_stats, + .fdp_usage_log = json_nvme_fdp_usage, + .fid_supported_effects_log = json_fid_support_effects_log, + .fw_log = json_fw_log, + .id_ctrl = json_nvme_id_ctrl, + .id_ctrl_nvm = json_nvme_id_ctrl_nvm, + .id_domain_list = json_id_domain_list, + .id_independent_id_ns = json_nvme_cmd_set_independent_id_ns, + .id_iocs = json_id_iocs, + .id_ns = json_nvme_id_ns, + .id_ns_descs = json_nvme_id_ns_descs, + .id_ns_granularity_list = json_nvme_id_ns_granularity_list, + .id_nvmset_list = json_nvme_id_nvmset, + .id_uuid_list = json_nvme_id_uuid_list, + .lba_status = json_lba_status, + .lba_status_log = json_lba_status_log, + .media_unit_stat_log = json_media_unit_stat_log, + .mi_cmd_support_effects_log = json_mi_cmd_support_effects_log, + .ns_list = json_nvme_list_ns, + .ns_list_log = json_changed_ns_list_log, + .nvm_id_ns = json_nvme_nvm_id_ns, + .persistent_event_log = json_persistent_event_log, + .predictable_latency_event_agg_log = json_predictable_latency_event_agg_log, + .predictable_latency_per_nvmset = json_predictable_latency_per_nvmset, + .primary_ctrl_cap = json_nvme_primary_ctrl_cap, + .resv_notification_log = json_resv_notif_log, + .resv_report = json_nvme_resv_report, + .sanitize_log_page = json_sanitize_log, + .secondary_ctrl_list = json_nvme_list_secondary_ctrl, + .select_result = json_select_result, + .self_test_log = json_self_test_log, + .single_property = json_single_property, + .smart_log = json_smart_log, + .supported_cap_config_list_log = json_supported_cap_config_log, + .supported_log_pages = json_support_log, + .zns_start_zone_list = json_zns_start_zone_list, + .zns_changed_zone_log = json_zns_changed, + .zns_finish_zone_list = json_zns_finish_zone_list, + .zns_id_ctrl = json_nvme_zns_id_ctrl, + .zns_id_ns = json_nvme_zns_id_ns, + .zns_report_zones = json_nvme_zns_report_zones, + .show_feature = json_feature_show, + .show_feature_fields = json_feature_show_fields, + .id_ctrl_rpmbs = json_id_ctrl_rpmbs, + .lba_range = json_lba_range, + .lba_status_info = json_lba_status_info, + .d = json_d, + .show_init = json_show_init, + .show_finish = json_show_finish, + + /* libnvme tree print functions */ + .list_item = json_list_item, + .list_items = json_print_list_items, + .print_nvme_subsystem_list = json_print_nvme_subsystem_list, + .topology_ctrl = json_simple_topology, + .topology_namespace = json_simple_topology, + + /* status and error messages */ + .connect_msg = json_connect_msg, + .show_message = json_output_message, + .show_perror = json_output_perror, + .show_status = json_output_status, + .show_error_status = json_output_error_status, +}; + +struct print_ops *nvme_get_json_print_ops(enum nvme_print_flags flags) +{ + json_print_ops.flags = flags; + return &json_print_ops; +} diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c new file mode 100644 index 0000000000..158fa308e8 --- /dev/null +++ b/nvme-print-stdout.c @@ -0,0 +1,5203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nvme.h" +#include "libnvme.h" +#include "nvme-print.h" +#include "nvme-models.h" +#include "util/suffix.h" +#include "util/types.h" +#include "common.h" + +static const uint8_t zero_uuid[16] = { 0 }; +static const uint8_t invalid_uuid[16] = {[0 ... 15] = 0xff }; +static const char dash[100] = {[0 ... 99] = '-'}; + +static struct print_ops stdout_print_ops; + +static const char *subsys_key(const struct nvme_subsystem *s) +{ + return nvme_subsystem_get_name((nvme_subsystem_t)s); +} + +static const char *ctrl_key(const struct nvme_ctrl *c) +{ + return nvme_ctrl_get_name((nvme_ctrl_t)c); +} + +static const char *ns_key(const struct nvme_ns *n) +{ + return nvme_ns_get_name((nvme_ns_t)n); +} + +static bool subsys_cmp(const struct nvme_subsystem *s, const char *name) +{ + return !strcmp(nvme_subsystem_get_name((nvme_subsystem_t)s), name); +} + +static bool ctrl_cmp(const struct nvme_ctrl *c, const char *name) +{ + return !strcmp(nvme_ctrl_get_name((nvme_ctrl_t)c), name); +} + +static bool ns_cmp(const struct nvme_ns *n, const char *name) +{ + return !strcmp(nvme_ns_get_name((nvme_ns_t)n), name); +} + +HTABLE_DEFINE_TYPE(struct nvme_subsystem, subsys_key, hash_string, + subsys_cmp, htable_subsys); +HTABLE_DEFINE_TYPE(struct nvme_ctrl, ctrl_key, hash_string, + ctrl_cmp, htable_ctrl); +HTABLE_DEFINE_TYPE(struct nvme_ns, ns_key, hash_string, + ns_cmp, htable_ns); + +static void htable_ctrl_add_unique(struct htable_ctrl *ht, nvme_ctrl_t c) +{ + if (htable_ctrl_get(ht, nvme_ctrl_get_name(c))) + return; + + htable_ctrl_add(ht, c); +} + +static void htable_ns_add_unique(struct htable_ns *ht, nvme_ns_t n) +{ + struct htable_ns_iter it; + nvme_ns_t _n; + + /* + * Test if namespace pointer is already in the hash, and thus avoid + * inserting severaltimes the same pointer. + */ + for (_n = htable_ns_getfirst(ht, nvme_ns_get_name(n), &it); + _n; + _n = htable_ns_getnext(ht, nvme_ns_get_name(n), &it)) { + if (_n == n) + return; + } + htable_ns_add(ht, n); +} + +struct nvme_resources { + nvme_root_t r; + + struct htable_subsys ht_s; + struct htable_ctrl ht_c; + struct htable_ns ht_n; + struct strset subsystems; + struct strset ctrls; + struct strset namespaces; +}; + +static int nvme_resources_init(nvme_root_t r, struct nvme_resources *res) +{ + nvme_host_t h; + nvme_subsystem_t s; + nvme_ctrl_t c; + nvme_ns_t n; + nvme_path_t p; + + res->r = r; + htable_subsys_init(&res->ht_s); + htable_ctrl_init(&res->ht_c); + htable_ns_init(&res->ht_n); + strset_init(&res->subsystems); + strset_init(&res->ctrls); + strset_init(&res->namespaces); + + nvme_for_each_host(r, h) { + nvme_for_each_subsystem(h, s) { + htable_subsys_add(&res->ht_s, s); + strset_add(&res->subsystems, nvme_subsystem_get_name(s)); + + nvme_subsystem_for_each_ctrl(s, c) { + htable_ctrl_add_unique(&res->ht_c, c); + strset_add(&res->ctrls, nvme_ctrl_get_name(c)); + + nvme_ctrl_for_each_ns(c, n) { + htable_ns_add_unique(&res->ht_n, n); + strset_add(&res->namespaces, nvme_ns_get_name(n)); + } + + nvme_ctrl_for_each_path(c, p) { + n = nvme_path_get_ns(p); + if (n) { + htable_ns_add_unique(&res->ht_n, n); + strset_add(&res->namespaces, nvme_ns_get_name(n)); + } + } + } + + nvme_subsystem_for_each_ns(s, n) { + htable_ns_add_unique(&res->ht_n, n); + strset_add(&res->namespaces, nvme_ns_get_name(n)); + } + } + } + + return 0; +} + +static void nvme_resources_free(struct nvme_resources *res) +{ + strset_clear(&res->namespaces); + strset_clear(&res->ctrls); + strset_clear(&res->subsystems); + htable_ns_clear(&res->ht_n); + htable_ctrl_clear(&res->ht_c); + htable_subsys_clear(&res->ht_s); +} + +static void stdout_feature_show_fields(enum nvme_features_id fid, + unsigned int result, + unsigned char *buf); +static void stdout_smart_log(struct nvme_smart_log *smart, + unsigned int nsid, + const char *devname); + +static void stdout_predictable_latency_per_nvmset( + struct nvme_nvmset_predictable_lat_log *plpns_log, + __u16 nvmset_id, const char *devname) +{ + printf("Predictable Latency Per NVM Set Log for device: %s\n", + devname); + printf("Predictable Latency Per NVM Set Log for NVM Set ID: %u\n", + le16_to_cpu(nvmset_id)); + printf("Status: %u\n", plpns_log->status); + printf("Event Type: %u\n", + le16_to_cpu(plpns_log->event_type)); + printf("DTWIN Reads Typical: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_rt)); + printf("DTWIN Writes Typical: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_wt)); + printf("DTWIN Time Maximum: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_tmax)); + printf("NDWIN Time Minimum High: %"PRIu64"\n", + le64_to_cpu(plpns_log->ndwin_tmin_hi)); + printf("NDWIN Time Minimum Low: %"PRIu64"\n", + le64_to_cpu(plpns_log->ndwin_tmin_lo)); + printf("DTWIN Reads Estimate: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_re)); + printf("DTWIN Writes Estimate: %"PRIu64"\n", + le64_to_cpu(plpns_log->dtwin_we)); + printf("DTWIN Time Estimate: %"PRIu64"\n\n\n", + le64_to_cpu(plpns_log->dtwin_te)); +} + +static void stdout_predictable_latency_event_agg_log( + struct nvme_aggregate_predictable_lat_event *pea_log, + __u64 log_entries, __u32 size, const char *devname) +{ + __u64 num_iter; + __u64 num_entries; + + num_entries = le64_to_cpu(pea_log->num_entries); + printf("Predictable Latency Event Aggregate Log for device: %s\n", devname); + + printf("Number of Entries Available: %"PRIu64"\n", (uint64_t)num_entries); + + num_iter = min(num_entries, log_entries); + for (int i = 0; i < num_iter; i++) + printf("Entry[%d]: %u\n", i + 1, le16_to_cpu(pea_log->entries[i])); +} + +static void stdout_persistent_event_log_rci(__le32 pel_header_rci) +{ + __u32 rci = le32_to_cpu(pel_header_rci); + __u32 rsvd19 = NVME_PEL_RCI_RSVD(rci); + __u8 rce = NVME_PEL_RCI_RCE(rci); + __u8 rcpit = NVME_PEL_RCI_RCPIT(rci); + __u16 rcpid = NVME_PEL_RCI_RCPID(rci); + + if (rsvd19) + printf(" [31:19] : %#x\tReserved\n", rsvd19); + printf("\tReporting Context Exists (RCE): %s(%u)\n", rce ? "true" : "false", rce); + printf("\tReporting Context Port Identifier Type (RCPIT): %u(%s)\n", rcpit, + nvme_pel_rci_rcpit_to_string(rcpit)); + printf("\tReporting Context Port Identifier (RCPID): %#x\n\n", rcpid); +} + +static void stdout_persistent_event_entry_ehai(__u8 ehai) +{ + __u8 rsvd1 = (ehai & 0xfc) >> 2; + __u8 pit = ehai & 0x03; + + printf(" [7:2] : %#x\tReserved\n", rsvd1); + printf("\tPort Identifier Type (PIT): %u(%s)\n", pit, + (pit == 0x00) ? "PIT not reported and PELPID does not apply" : + (pit == 0x01) ? "NVM subsystem port" : + (pit == 0x02) ? "NVMe-MI port" : + "Event not associated with any port and PELPID does not apply"); +} + +static void stdout_add_bitmap(int i, __u8 seb) +{ + for (int bit = 0; bit < CHAR_BIT; bit++) { + if (nvme_pel_event_to_string(bit + i * CHAR_BIT)) { + if ((seb >> bit) & 0x1) + printf(" Support %s\n", + nvme_pel_event_to_string(bit + i * CHAR_BIT)); + } + } +} + +static void stdout_persistent_event_log(void *pevent_log_info, + __u8 action, __u32 size, + const char *devname) +{ + __u32 offset, por_info_len, por_info_list; + __u64 *fw_rev; + int fid, cdw11, dword_cnt; + unsigned char *mem_buf = NULL; + struct nvme_smart_log *smart_event; + struct nvme_fw_commit_event *fw_commit_event; + struct nvme_time_stamp_change_event *ts_change_event; + struct nvme_power_on_reset_info_list *por_event; + struct nvme_nss_hw_err_event *nss_hw_err_event; + struct nvme_change_ns_event *ns_event; + struct nvme_format_nvm_start_event *format_start_event; + struct nvme_format_nvm_compln_event *format_cmpln_event; + struct nvme_sanitize_start_event *sanitize_start_event; + struct nvme_sanitize_compln_event *sanitize_cmpln_event; + struct nvme_set_feature_event *set_feat_event; + struct nvme_thermal_exc_event *thermal_exc_event; + struct nvme_persistent_event_log *pevent_log_head; + struct nvme_persistent_event_entry *pevent_entry_head; + + int human = stdout_print_ops.flags & VERBOSE; + + offset = sizeof(*pevent_log_head); + + printf("Persistent Event Log for device: %s\n", devname); + printf("Action for Persistent Event Log: %u\n", action); + if (size >= offset) { + pevent_log_head = pevent_log_info; + printf("Log Identifier: %u\n", pevent_log_head->lid); + printf("Total Number of Events: %u\n", + le32_to_cpu(pevent_log_head->tnev)); + printf("Total Log Length : %"PRIu64"\n", + le64_to_cpu(pevent_log_head->tll)); + printf("Log Revision: %u\n", pevent_log_head->rv); + printf("Log Header Length: %u\n", pevent_log_head->lhl); + printf("Timestamp: %"PRIu64"\n", + le64_to_cpu(pevent_log_head->ts)); + printf("Power On Hours (POH): %s", + uint128_t_to_l10n_string(le128_to_cpu(pevent_log_head->poh))); + printf("Power Cycle Count: %"PRIu64"\n", + le64_to_cpu(pevent_log_head->pcc)); + printf("PCI Vendor ID (VID): %u\n", + le16_to_cpu(pevent_log_head->vid)); + printf("PCI Subsystem Vendor ID (SSVID): %u\n", + le16_to_cpu(pevent_log_head->ssvid)); + printf("Serial Number (SN): %-.*s\n", + (int)sizeof(pevent_log_head->sn), pevent_log_head->sn); + printf("Model Number (MN): %-.*s\n", + (int)sizeof(pevent_log_head->mn), pevent_log_head->mn); + printf("NVM Subsystem NVMe Qualified Name (SUBNQN): %-.*s\n", + (int)sizeof(pevent_log_head->subnqn), + pevent_log_head->subnqn); + printf("Generation Number: %u\n", + le16_to_cpu(pevent_log_head->gen_number)); + printf("Reporting Context Information (RCI): %u\n", + le32_to_cpu(pevent_log_head->rci)); + if (human) + stdout_persistent_event_log_rci(pevent_log_head->rci); + printf("Supported Events Bitmap:\n"); + for (int i = 0; i < 32; i++) { + if (pevent_log_head->seb[i] == 0) + continue; + stdout_add_bitmap(i, pevent_log_head->seb[i]); + } + } else { + printf("No log data can be shown with this log len at least " \ + "512 bytes is required or can be 0 to read the complete "\ + "log page after context established\n"); + return; + } + printf("\n"); + printf("\nPersistent Event Entries:\n"); + for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) { + if (offset + sizeof(*pevent_entry_head) >= size) + break; + + pevent_entry_head = pevent_log_info + offset; + + if ((offset + pevent_entry_head->ehl + 3 + + le16_to_cpu(pevent_entry_head->el)) >= size) + break; + printf("Event Number: %u\n", i); + printf("Event Type: %s\n", nvme_pel_event_to_string(pevent_entry_head->etype)); + printf("Event Type Revision: %u\n", pevent_entry_head->etype_rev); + printf("Event Header Length: %u\n", pevent_entry_head->ehl); + printf("Event Header Additional Info: %u\n", pevent_entry_head->ehai); + if (human) + stdout_persistent_event_entry_ehai(pevent_entry_head->ehai); + printf("Controller Identifier: %u\n", + le16_to_cpu(pevent_entry_head->cntlid)); + printf("Event Timestamp: %"PRIu64"\n", + le64_to_cpu(pevent_entry_head->ets)); + printf("Port Identifier: %u\n", + le16_to_cpu(pevent_entry_head->pelpid)); + printf("Vendor Specific Information Length: %u\n", + le16_to_cpu(pevent_entry_head->vsil)); + printf("Event Length: %u\n", le16_to_cpu(pevent_entry_head->el)); + + offset += pevent_entry_head->ehl + 3; + + switch (pevent_entry_head->etype) { + case NVME_PEL_SMART_HEALTH_EVENT: + smart_event = pevent_log_info + offset; + printf("Smart Health Event Entry:\n"); + stdout_smart_log(smart_event, NVME_NSID_ALL, devname); + break; + case NVME_PEL_FW_COMMIT_EVENT: + fw_commit_event = pevent_log_info + offset; + printf("FW Commit Event Entry:\n"); + printf("Old Firmware Revision: %"PRIu64" (%s)\n", + le64_to_cpu(fw_commit_event->old_fw_rev), + util_fw_to_string((char *)&fw_commit_event->old_fw_rev)); + printf("New Firmware Revision: %"PRIu64" (%s)\n", + le64_to_cpu(fw_commit_event->new_fw_rev), + util_fw_to_string((char *)&fw_commit_event->new_fw_rev)); + printf("FW Commit Action: %u\n", + fw_commit_event->fw_commit_action); + printf("FW Slot: %u\n", fw_commit_event->fw_slot); + printf("Status Code Type for Firmware Commit Command: %u\n", + fw_commit_event->sct_fw); + printf("Status Returned for Firmware Commit Command: %u\n", + fw_commit_event->sc_fw); + printf("Vendor Assigned Firmware Commit Result Code: %u\n", + le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); + break; + case NVME_PEL_TIMESTAMP_EVENT: + ts_change_event = pevent_log_info + offset; + printf("Time Stamp Change Event Entry:\n"); + printf("Previous Timestamp: %"PRIu64"\n", + le64_to_cpu(ts_change_event->previous_timestamp)); + printf("Milliseconds Since Reset: %"PRIu64"\n", + le64_to_cpu(ts_change_event->ml_secs_since_reset)); + break; + case NVME_PEL_POWER_ON_RESET_EVENT: + por_info_len = (le16_to_cpu(pevent_entry_head->el) - + le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev)); + + por_info_list = por_info_len / sizeof(*por_event); + + printf("Power On Reset Event Entry:\n"); + fw_rev = pevent_log_info + offset; + printf("Firmware Revision: %"PRIu64" (%s)\n", le64_to_cpu(*fw_rev), + util_fw_to_string((char *)fw_rev)); + printf("Reset Information List:\n"); + + for (int i = 0; i < por_info_list; i++) { + por_event = pevent_log_info + offset + + sizeof(*fw_rev) + i * sizeof(*por_event); + printf("Controller ID: %u\n", le16_to_cpu(por_event->cid)); + printf("Firmware Activation: %u\n", + por_event->fw_act); + printf("Operation in Progress: %u\n", + por_event->op_in_prog); + printf("Controller Power Cycle: %u\n", + le32_to_cpu(por_event->ctrl_power_cycle)); + printf("Power on milliseconds: %"PRIu64"\n", + le64_to_cpu(por_event->power_on_ml_seconds)); + printf("Controller Timestamp: %"PRIu64"\n", + le64_to_cpu(por_event->ctrl_time_stamp)); + } + break; + case NVME_PEL_NSS_HW_ERROR_EVENT: + nss_hw_err_event = pevent_log_info + offset; + printf("NVM Subsystem Hardware Error Event Code Entry: %u, %s\n", + le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code), + nvme_nss_hw_error_to_string(nss_hw_err_event->nss_hw_err_event_code)); + break; + case NVME_PEL_CHANGE_NS_EVENT: + ns_event = pevent_log_info + offset; + printf("Change Namespace Event Entry:\n"); + printf("Namespace Management CDW10: %u\n", + le32_to_cpu(ns_event->nsmgt_cdw10)); + printf("Namespace Size: %"PRIu64"\n", + le64_to_cpu(ns_event->nsze)); + printf("Namespace Capacity: %"PRIu64"\n", + le64_to_cpu(ns_event->nscap)); + printf("Formatted LBA Size: %u\n", ns_event->flbas); + printf("End-to-end Data Protection Type Settings: %u\n", + ns_event->dps); + printf("Namespace Multi-path I/O and Namespace Sharing" \ + " Capabilities: %u\n", ns_event->nmic); + printf("ANA Group Identifier: %u\n", + le32_to_cpu(ns_event->ana_grp_id)); + printf("NVM Set Identifier: %u\n", le16_to_cpu(ns_event->nvmset_id)); + printf("Namespace ID: %u\n", le32_to_cpu(ns_event->nsid)); + break; + case NVME_PEL_FORMAT_START_EVENT: + format_start_event = pevent_log_info + offset; + printf("Format NVM Start Event Entry:\n"); + printf("Namespace Identifier: %u\n", + le32_to_cpu(format_start_event->nsid)); + printf("Format NVM Attributes: %u\n", + format_start_event->fna); + printf("Format NVM CDW10: %u\n", + le32_to_cpu(format_start_event->format_nvm_cdw10)); + break; + case NVME_PEL_FORMAT_COMPLETION_EVENT: + format_cmpln_event = pevent_log_info + offset; + printf("Format NVM Completion Event Entry:\n"); + printf("Namespace Identifier: %u\n", + le32_to_cpu(format_cmpln_event->nsid)); + printf("Smallest Format Progress Indicator: %u\n", + format_cmpln_event->smallest_fpi); + printf("Format NVM Status: %u\n", + format_cmpln_event->format_nvm_status); + printf("Completion Information: %u\n", + le16_to_cpu(format_cmpln_event->compln_info)); + printf("Status Field: %u\n", + le32_to_cpu(format_cmpln_event->status_field)); + break; + case NVME_PEL_SANITIZE_START_EVENT: + sanitize_start_event = pevent_log_info + offset; + printf("Sanitize Start Event Entry:\n"); + printf("SANICAP: %u\n", sanitize_start_event->sani_cap); + printf("Sanitize CDW10: %u\n", + le32_to_cpu(sanitize_start_event->sani_cdw10)); + printf("Sanitize CDW11: %u\n", + le32_to_cpu(sanitize_start_event->sani_cdw11)); + break; + case NVME_PEL_SANITIZE_COMPLETION_EVENT: + sanitize_cmpln_event = pevent_log_info + offset; + printf("Sanitize Completion Event Entry:\n"); + printf("Sanitize Progress: %u\n", + le16_to_cpu(sanitize_cmpln_event->sani_prog)); + printf("Sanitize Status: %u\n", + le16_to_cpu(sanitize_cmpln_event->sani_status)); + printf("Completion Information: %u\n", + le16_to_cpu(sanitize_cmpln_event->cmpln_info)); + break; + case NVME_PEL_SET_FEATURE_EVENT: + set_feat_event = pevent_log_info + offset; + printf("Set Feature Event Entry:\n"); + dword_cnt = set_feat_event->layout & 0x03; + fid = le32_to_cpu(set_feat_event->cdw_mem[0]) & 0x000f; + cdw11 = le32_to_cpu(set_feat_event->cdw_mem[1]); + + printf("Set Feature ID :%#02x (%s), value:%#08x\n", fid, + nvme_feature_to_string(fid), cdw11); + if (((set_feat_event->layout & 0xff) >> 2) != 0) { + mem_buf = (unsigned char *)(set_feat_event + 4 + dword_cnt * 4); + stdout_feature_show_fields(fid, cdw11, mem_buf); + } + break; + case NVME_PEL_TELEMETRY_CRT: + d(pevent_log_info + offset, 512, 16, 1); + break; + case NVME_PEL_THERMAL_EXCURSION_EVENT: + thermal_exc_event = pevent_log_info + offset; + printf("Thermal Excursion Event Entry:\n"); + printf("Over Temperature: %u\n", thermal_exc_event->over_temp); + printf("Threshold: %u\n", thermal_exc_event->threshold); + break; + default: + printf("Reserved Event\n\n"); + break; + } + offset += le16_to_cpu(pevent_entry_head->el); + printf("\n"); + } +} + +static void stdout_endurance_group_event_agg_log( + struct nvme_aggregate_predictable_lat_event *endurance_log, + __u64 log_entries, __u32 size, const char *devname) +{ + printf("Endurance Group Event Aggregate Log for device: %s\n", devname); + + printf("Number of Entries Available: %"PRIu64"\n", + le64_to_cpu(endurance_log->num_entries)); + + for (int i = 0; i < log_entries; i++) { + printf("Entry[%d]: %u\n", i + 1, + le16_to_cpu(endurance_log->entries[i])); + } +} + +static void stdout_lba_status_log(void *lba_status, __u32 size, + const char *devname) +{ + struct nvme_lba_status_log *hdr; + struct nvme_lbas_ns_element *ns_element; + struct nvme_lba_rd *range_desc; + int offset = sizeof(*hdr); + __u32 num_lba_desc, num_elements; + + hdr = lba_status; + printf("LBA Status Log for device: %s\n", devname); + printf("LBA Status Log Page Length: %"PRIu32"\n", + le32_to_cpu(hdr->lslplen)); + num_elements = le32_to_cpu(hdr->nlslne); + printf("Number of LBA Status Log Namespace Elements: %"PRIu32"\n", + num_elements); + printf("Estimate of Unrecoverable Logical Blocks: %"PRIu32"\n", + le32_to_cpu(hdr->estulb)); + printf("LBA Status Generation Counter: %"PRIu16"\n", le16_to_cpu(hdr->lsgc)); + for (int ele = 0; ele < num_elements; ele++) { + ns_element = lba_status + offset; + printf("Namespace Element Identifier: %"PRIu32"\n", + le32_to_cpu(ns_element->neid)); + num_lba_desc = le32_to_cpu(ns_element->nlrd); + printf("Number of LBA Range Descriptors: %"PRIu32"\n", num_lba_desc); + printf("Recommended Action Type: %u\n", ns_element->ratype); + + offset += sizeof(*ns_element); + if (num_lba_desc != 0xffffffff) { + for (int i = 0; i < num_lba_desc; i++) { + range_desc = lba_status + offset; + printf("RSLBA[%d]: %"PRIu64"\n", i, + le64_to_cpu(range_desc->rslba)); + printf("RNLB[%d]: %"PRIu32"\n", i, + le32_to_cpu(range_desc->rnlb)); + offset += sizeof(*range_desc); + } + } else { + printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\ + "NS element %d\n", num_lba_desc, ele); + } + } +} + +static void stdout_resv_notif_log(struct nvme_resv_notification_log *resv, + const char *devname) +{ + printf("Reservation Notif Log for device: %s\n", devname); + printf("Log Page Count : %"PRIx64"\n", + le64_to_cpu(resv->lpc)); + printf("Resv Notif Log Page Type : %u (%s)\n", + resv->rnlpt, + nvme_resv_notif_to_string(resv->rnlpt)); + printf("Num of Available Log Pages : %u\n", resv->nalp); + printf("Namespace ID: : %"PRIx32"\n", + le32_to_cpu(resv->nsid)); +} + +static void stdout_fid_support_effects_log_human(__u32 fid_support) +{ + const char *set = "+"; + const char *clr = "-"; + __u16 fsp; + + printf(" FSUPP+"); + printf(" UDCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_UDCC) ? set : clr); + printf(" NCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_NCC) ? set : clr); + printf(" NIC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_NIC) ? set : clr); + printf(" CCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_CCC) ? set : clr); + printf(" USS%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_UUID_SEL) ? set : clr); + + fsp = (fid_support >> NVME_FID_SUPPORTED_EFFECTS_SCOPE_SHIFT) & NVME_FID_SUPPORTED_EFFECTS_SCOPE_MASK; + + printf(" NAMESPACE SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NS) ? set : clr); + printf(" CONTROLLER SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_CTRL) ? set : clr); + printf(" NVM SET SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NVM_SET) ? set : clr); + printf(" ENDURANCE GROUP SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_ENDGRP) ? set : clr); + printf(" DOMAIN SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_DOMAIN) ? set : clr); + printf(" NVM Subsystem SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NSS) ? set : clr); +} + +static void stdout_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log, + const char *devname) +{ + __u32 fid_effect; + int i, human = stdout_print_ops.flags & VERBOSE; + + printf("FID Supports Effects Log for device: %s\n", devname); + printf("Admin Command Set\n"); + for (i = 0; i < 256; i++) { + fid_effect = le32_to_cpu(fid_log->fid_support[i]); + if (fid_effect & NVME_FID_SUPPORTED_EFFECTS_FSUPP) { + printf("FID %02x -> Support Effects Log: %08x", i, + fid_effect); + if (human) + stdout_fid_support_effects_log_human(fid_effect); + else + printf("\n"); + } + } +} + +static void stdout_mi_cmd_support_effects_log_human(__u32 mi_cmd_support) +{ + const char *set = "+"; + const char *clr = "-"; + __u16 csp; + + printf(" CSUPP+"); + printf(" UDCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_UDCC) ? set : clr); + printf(" NCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_NCC) ? set : clr); + printf(" NIC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_NIC) ? set : clr); + printf(" CCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_CCC) ? set : clr); + + csp = (mi_cmd_support >> NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_SHIFT) & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_MASK; + + printf(" NAMESPACE SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NS) ? set : clr); + printf(" CONTROLLER SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_CTRL) ? set : clr); + printf(" NVM SET SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NVM_SET) ? set : clr); + printf(" ENDURANCE GROUP SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_ENDGRP) ? set : clr); + printf(" DOMAIN SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_DOMAIN) ? set : clr); + printf(" NVM Subsystem SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NSS) ? set : clr); +} + +static void stdout_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, + const char *devname) +{ + __u32 mi_cmd_effect; + int i, human = stdout_print_ops.flags & VERBOSE; + + printf("MI Commands Support Effects Log for device: %s\n", devname); + printf("Admin Command Set\n"); + for (i = 0; i < NVME_LOG_MI_CMD_SUPPORTED_EFFECTS_MAX; i++) { + mi_cmd_effect = le32_to_cpu(mi_cmd_log->mi_cmd_support[i]); + if (mi_cmd_effect & NVME_MI_CMD_SUPPORTED_EFFECTS_CSUPP) { + printf("MI CMD %02x -> Support Effects Log: %08x", i, + mi_cmd_effect); + if (human) + stdout_mi_cmd_support_effects_log_human(mi_cmd_effect); + else + printf("\n"); + } + } +} + +static void stdout_boot_part_log(void *bp_log, const char *devname, + __u32 size) +{ + struct nvme_boot_partition *hdr; + + hdr = bp_log; + printf("Boot Partition Log for device: %s\n", devname); + printf("Log ID: %u\n", hdr->lid); + printf("Boot Partition Size: %u KiB\n", le32_to_cpu(hdr->bpinfo) & 0x7fff); + printf("Active BPID: %u\n", (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1); +} + +static const char *eomip_to_string(__u8 eomip) +{ + const char *string; + + switch (eomip) { + case NVME_PHY_RX_EOM_NOT_STARTED: + string = "Not Started"; + break; + case NVME_PHY_RX_EOM_IN_PROGRESS: + string = "In Progress"; + break; + case NVME_PHY_RX_EOM_COMPLETED: + string = "Completed"; + break; + default: + string = "Unknown"; + break; + } + return string; +} + +static void stdout_phy_rx_eom_odp(uint8_t odp) +{ + __u8 rsvd = (odp >> 2) & 0x3F; + __u8 edfp = (odp >> 1) & 0x1; + __u8 pefp = odp & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tEye Data Field %sPresent\n", + edfp, edfp ? "" : "Not "); + printf(" [0:0] : %#x\tPrintable Eye Field %sPresent\n", + pefp, pefp ? "" : "Not "); +} + +static void stdout_eom_printable_eye(struct nvme_eom_lane_desc *lane) +{ + char *eye = (char *)lane->eye_desc; + int i, j; + + for (i = 0; i < lane->nrows; i++) { + for (j = 0; j < lane->ncols; j++) + printf("%c", eye[i * lane->ncols + j]); + printf("\n"); + } +} + +static void stdout_phy_rx_eom_descs(struct nvme_phy_rx_eom_log *log) +{ + void *p = log->descs; + int i; + + for (i = 0; i < log->nd; i++) { + struct nvme_eom_lane_desc *desc = p; + + printf("Measurement Status: %s\n", + desc->mstatus ? "Successful" : "Not Successful"); + printf("Lane: %u\n", desc->lane); + printf("Eye: %u\n", desc->eye); + printf("Top: %u\n", le16_to_cpu(desc->top)); + printf("Bottom: %u\n", le16_to_cpu(desc->bottom)); + printf("Left: %u\n", le16_to_cpu(desc->left)); + printf("Right: %u\n", le16_to_cpu(desc->right)); + printf("Number of Rows: %u\n", le16_to_cpu(desc->nrows)); + printf("Number of Columns: %u\n", le16_to_cpu(desc->ncols)); + printf("Eye Data Length: %u\n", le16_to_cpu(desc->edlen)); + + if (log->odp & NVME_EOM_PRINTABLE_EYE_PRESENT) + stdout_eom_printable_eye(desc); + + /* Eye Data field is vendor specific */ + + p += log->dsize; + } +} + +static void stdout_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller) +{ + int human = stdout_print_ops.flags & VERBOSE; + + printf("Physical Interface Receiver Eye Opening Measurement Log for controller ID: %u\n", controller); + printf("Log ID: %u\n", log->lid); + printf("EOM In Progress: %s\n", eomip_to_string(log->eomip)); + printf("Header Size: %u\n", le16_to_cpu(log->hsize)); + printf("Result Size: %u\n", le32_to_cpu(log->rsize)); + printf("EOM Data Generation Number: %u\n", log->eomdgn); + printf("Log Revision: %u\n", log->lr); + printf("Optional Data Present: %u\n", log->odp); + if (human) + stdout_phy_rx_eom_odp(log->odp); + printf("Lanes: %u\n", log->lanes); + printf("Eyes Per Lane: %u\n", log->epl); + printf("Log Specific Parameter Field Copy: %u\n", log->lspfc); + printf("Link Information: %u\n", log->li); + printf("Log Specific Identifier Copy: %u\n", le16_to_cpu(log->lsic)); + printf("Descriptor Size: %u\n", le32_to_cpu(log->dsize)); + printf("Number of Descriptors: %u\n", le16_to_cpu(log->nd)); + printf("Maximum Top Bottom: %u\n", le16_to_cpu(log->maxtb)); + printf("Maximum Left Right: %u\n", le16_to_cpu(log->maxlr)); + printf("Estimated Time for Good Quality: %u\n", le16_to_cpu(log->etgood)); + printf("Estimated Time for Better Quality: %u\n", le16_to_cpu(log->etbetter)); + printf("Estimated Time for Best Quality: %u\n", le16_to_cpu(log->etbest)); + + if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) + stdout_phy_rx_eom_descs(log); +} + +static void stdout_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log) +{ + int i; + int nmu = le16_to_cpu(mus_log->nmu); + + printf("Number of Media Unit Status Descriptors: %u\n", nmu); + printf("Number of Channels: %u\n", le16_to_cpu(mus_log->cchans)); + printf("Selected Configuration: %u\n", le16_to_cpu(mus_log->sel_config)); + for (i = 0; i < nmu; i++) { + printf("Media Unit Status Descriptor: %u\n", i); + printf("Media Unit Identifier: %u\n", + le16_to_cpu(mus_log->mus_desc[i].muid)); + printf("Domain Identifier: %u\n", + le16_to_cpu(mus_log->mus_desc[i].domainid)); + printf("Endurance Group Identifier: %u\n", + le16_to_cpu(mus_log->mus_desc[i].endgid)); + printf("NVM Set Identifier: %u\n", + le16_to_cpu(mus_log->mus_desc[i].nvmsetid)); + printf("Capacity Adjustment Factor: %u\n", + le16_to_cpu(mus_log->mus_desc[i].cap_adj_fctr)); + printf("Available Spare: %u\n", mus_log->mus_desc[i].avl_spare); + printf("Percentage Used: %u\n", mus_log->mus_desc[i].percent_used); + printf("Number of Channels: %u\n", mus_log->mus_desc[i].mucs); + printf("Channel Identifiers Offset: %u\n", mus_log->mus_desc[i].cio); + } +} + +static void stdout_fdp_config_fdpa(uint8_t fdpa) +{ + __u8 valid = (fdpa >> 7) & 0x1; + __u8 rsvd = (fdpa >> 5) & 0x3; + __u8 fdpvwc = (fdpa >> 4) & 0x1; + __u8 rgif = fdpa & 0xf; + + printf(" [7:7] : %#x\tFDP Configuration %sValid\n", + valid, valid ? "" : "Not "); + if (rsvd) + printf(" [6:5] : %#x\tReserved\n", rsvd); + printf(" [4:4] : %#x\tFDP Volatile Write Cache %sPresent\n", + fdpvwc, fdpvwc ? "" : "Not "); + printf(" [3:0] : %#x\tReclaim Group Identifier Format\n", rgif); +} + +static void stdout_fdp_configs(struct nvme_fdp_config_log *log, size_t len) +{ + void *p = log->configs; + int human = stdout_print_ops.flags & VERBOSE; + uint16_t n; + + n = le16_to_cpu(log->n) + 1; + + for (int i = 0; i < n; i++) { + struct nvme_fdp_config_desc *config = p; + + printf("FDP Attributes: %#x\n", config->fdpa); + if (human) + stdout_fdp_config_fdpa(config->fdpa); + + printf("Vendor Specific Size: %u\n", config->vss); + printf("Number of Reclaim Groups: %"PRIu32"\n", le32_to_cpu(config->nrg)); + printf("Number of Reclaim Unit Handles: %"PRIu16"\n", le16_to_cpu(config->nruh)); + printf("Number of Namespaces Supported: %"PRIu32"\n", le32_to_cpu(config->nnss)); + printf("Reclaim Unit Nominal Size: %"PRIu64"\n", le64_to_cpu(config->runs)); + printf("Estimated Reclaim Unit Time Limit: %"PRIu32"\n", le32_to_cpu(config->erutl)); + + printf("Reclaim Unit Handle List:\n"); + for (int j = 0; j < le16_to_cpu(config->nruh); j++) { + struct nvme_fdp_ruh_desc *ruh = &config->ruhs[j]; + + printf(" [%d]: %s\n", j, ruh->ruht == NVME_FDP_RUHT_INITIALLY_ISOLATED ? "Initially Isolated" : "Persistently Isolated"); + } + + p += config->size; + } +} + +static void stdout_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len) +{ + uint16_t nruh = le16_to_cpu(log->nruh); + + for (int i = 0; i < nruh; i++) { + struct nvme_fdp_ruhu_desc *ruhu = &log->ruhus[i]; + + printf("Reclaim Unit Handle %d Attributes: 0x%"PRIx8" (%s)\n", i, ruhu->ruha, + ruhu->ruha == 0x0 ? "Unused" : ( + ruhu->ruha == 0x1 ? "Host Specified" : ( + ruhu->ruha == 0x2 ? "Controller Specified" : "Unknown"))); + } +} + +static void stdout_fdp_stats(struct nvme_fdp_stats_log *log) +{ + printf("Host Bytes with Metadata Written (HBMW): %s\n", + uint128_t_to_l10n_string(le128_to_cpu(log->hbmw))); + printf("Media Bytes with Metadata Written (MBMW): %s\n", + uint128_t_to_l10n_string(le128_to_cpu(log->mbmw))); + printf("Media Bytes Erased (MBE): %s\n", + uint128_t_to_l10n_string(le128_to_cpu(log->mbe))); +} + +static void stdout_fdp_events(struct nvme_fdp_events_log *log) +{ + struct tm *tm; + char buffer[320]; + time_t ts; + uint32_t n = le32_to_cpu(log->n); + + for (unsigned int i = 0; i < n; i++) { + struct nvme_fdp_event *event = &log->events[i]; + + ts = int48_to_long(event->ts.timestamp) / 1000; + tm = localtime(&ts); + + printf("Event[%u]\n", i); + printf(" Event Type: 0x%"PRIx8" (%s)\n", event->type, nvme_fdp_event_to_string(event->type)); + printf(" Event Timestamp: %"PRIu64" (%s)\n", int48_to_long(event->ts.timestamp), + strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-"); + + if (event->flags & NVME_FDP_EVENT_F_PIV) + printf(" Placement Identifier (PID): 0x%"PRIx16"\n", le16_to_cpu(event->pid)); + + if (event->flags & NVME_FDP_EVENT_F_NSIDV) + printf(" Namespace Identifier (NSID): %"PRIu32"\n", le32_to_cpu(event->nsid)); + + if (event->type == NVME_FDP_EVENT_REALLOC) { + struct nvme_fdp_event_realloc *mr; + + mr = (struct nvme_fdp_event_realloc *)&event->type_specific; + + printf(" Number of LBAs Moved (NLBAM): %"PRIu16"\n", le16_to_cpu(mr->nlbam)); + + if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV) + printf(" Logical Block Address (LBA): 0x%"PRIx64"\n", le64_to_cpu(mr->lba)); + } + + if (event->flags & NVME_FDP_EVENT_F_LV) { + printf(" Reclaim Group Identifier: %"PRIu16"\n", le16_to_cpu(event->rgid)); + printf(" Reclaim Unit Handle Identifier %"PRIu8"\n", event->ruhid); + } + + printf("\n"); + } +} + +static void stdout_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len) +{ + uint16_t nruhsd = le16_to_cpu(status->nruhsd); + + for (unsigned int i = 0; i < nruhsd; i++) { + struct nvme_fdp_ruh_status_desc *ruhs = &status->ruhss[i]; + + printf("Placement Identifier %"PRIu16"; Reclaim Unit Handle Identifier %"PRIu16"\n", + le16_to_cpu(ruhs->pid), le16_to_cpu(ruhs->ruhid)); + printf(" Estimated Active Reclaim Unit Time Remaining (EARUTR): %"PRIu32"\n", + le32_to_cpu(ruhs->earutr)); + printf(" Reclaim Unit Available Media Writes (RUAMW): %"PRIu64"\n", + le64_to_cpu(ruhs->ruamw)); + + printf("\n"); + } +} + +static void stdout_supported_cap_config_log(struct nvme_supported_cap_config_list_log *cap) +{ + struct nvme_end_grp_chan_desc *chan_desc; + int i, j, k, l, m, sccn, egcn, egsets, egchans, chmus; + + sccn = cap->sccn; + printf("Number of Supported Capacity Configurations: %u\n", sccn); + for (i = 0; i < sccn; i++) { + printf("Capacity Configuration Descriptor: %u\n", i); + printf("Capacity Configuration Identifier: %u\n", + le16_to_cpu(cap->cap_config_desc[i].cap_config_id)); + printf("Domain Identifier: %u\n", + le16_to_cpu(cap->cap_config_desc[i].domainid)); + egcn = le16_to_cpu(cap->cap_config_desc[i].egcn); + printf("Number of Endurance Group Configuration Descriptors: %u\n", egcn); + for (j = 0; j < egcn; j++) { + printf("Endurance Group Identifier: %u\n", + le16_to_cpu(cap->cap_config_desc[i].egcd[j].endgid)); + printf("Capacity Adjustment Factor: %u\n", + le16_to_cpu(cap->cap_config_desc[i].egcd[j].cap_adj_factor)); + printf("Total Endurance Group Capacity: %s\n", + uint128_t_to_l10n_string(le128_to_cpu( + cap->cap_config_desc[i].egcd[j].tegcap))); + printf("Spare Endurance Group Capacity: %s\n", + uint128_t_to_l10n_string(le128_to_cpu( + cap->cap_config_desc[i].egcd[j].segcap))); + printf("Endurance Estimate: %s\n", + uint128_t_to_l10n_string(le128_to_cpu( + cap->cap_config_desc[i].egcd[j].end_est))); + egsets = le16_to_cpu(cap->cap_config_desc[i].egcd[j].egsets); + printf("Number of NVM Sets: %u\n", egsets); + for (k = 0; k < egsets; k++) + printf("NVM Set %d Identifier: %u\n", i, + le16_to_cpu(cap->cap_config_desc[i].egcd[j].nvmsetid[k])); + + chan_desc = (struct nvme_end_grp_chan_desc *) + &cap->cap_config_desc[i].egcd[j].nvmsetid[egsets]; + egchans = le16_to_cpu(chan_desc->egchans); + printf("Number of Channels: %u\n", egchans); + for (l = 0; l < egchans; l++) { + printf("Channel Identifier: %u\n", + le16_to_cpu(chan_desc->chan_config_desc[l].chanid)); + chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus); + printf("Number of Channel Media Units: %u\n", chmus); + for (m = 0; m < chmus; m++) { + printf("Media Unit Identifier: %u\n", + le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid)); + printf("Media Unit Descriptor Length: %u\n", + le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].mudl)); + } + } + } + } +} + +static unsigned int stdout_subsystem_multipath(nvme_subsystem_t s) +{ + nvme_ns_t n; + nvme_path_t p; + unsigned int i = 0; + + n = nvme_subsystem_first_ns(s); + if (!n) + return 0; + + nvme_namespace_for_each_path(n, p) { + nvme_ctrl_t c = nvme_path_get_ctrl(p); + const char *ana_state = ana_state = nvme_path_get_ana_state(p); + + printf(" +- %s %s %s %s %s\n", + nvme_ctrl_get_name(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c), + nvme_ctrl_get_state(c), + ana_state); + i++; + } + + return i; +} + +static void stdout_subsystem_ctrls(nvme_subsystem_t s) +{ + nvme_ctrl_t c; + + nvme_subsystem_for_each_ctrl(s, c) { + printf(" +- %s %s %s %s\n", + nvme_ctrl_get_name(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c), + nvme_ctrl_get_state(c)); + } +} + +static void stdout_subsystem(nvme_root_t r, bool show_ana) +{ + nvme_host_t h; + bool first = true; + + nvme_for_each_host(r, h) { + nvme_subsystem_t s; + + nvme_for_each_subsystem(h, s) { + int len = strlen(nvme_subsystem_get_name(s)); + + if (!first) + printf("\n"); + first = false; + + printf("%s - NQN=%s\n", nvme_subsystem_get_name(s), + nvme_subsystem_get_nqn(s)); + printf("%*s hostnqn=%s\n", len, " ", + nvme_host_get_hostnqn(nvme_subsystem_get_host(s))); + printf("%*s iopolicy=%s\n", len, " ", + nvme_subsystem_get_iopolicy(s)); + printf("\\\n"); + + if (!show_ana || !stdout_subsystem_multipath(s)) + stdout_subsystem_ctrls(s); + } + } +} + +static void stdout_subsystem_list(nvme_root_t r, bool show_ana) +{ + stdout_subsystem(r, show_ana); +} + +static void stdout_registers_cap(struct nvme_bar_cap *cap) +{ + printf("\tController Ready With Media Support (CRWMS): %s\n", + cap->crwms ? "Supported" : "Not Supported"); + printf("\tController Ready Independent of Media Support (CRIMS): %s\n", + cap->crims ? "Supported" : "Not Supported"); + printf("\tNVM Subsystem Shutdown Supported (NSSS): %s\n", cap->nsss ? "Supported" : "Not Supported"); + printf("\tController Memory Buffer Supported (CMBS): The Controller Memory Buffer is %s\n", + cap->cmbs ? "Supported" : "Not Supported"); + printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n", + cap->pmrs ? "Supported" : "Not Supported"); + printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n", 1 << (12 + cap->mpsmax)); + printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n", 1 << (12 + cap->mpsmin)); + printf("\tController Power Scope (CPS): %s\n", + !cap->cps ? "Not Reported" : cap->cps == 1 ? "Controller scope" : + cap->cps == 2 ? "Domain scope" : "NVM subsystem scope"); + printf("\tBoot Partition Support (BPS): %s\n", cap->bps ? "Yes" : "No"); + printf("\tCommand Sets Supported (CSS): NVM command set is %s\n", + cap->css & 0x01 ? "Supported" : "Not Supported"); + printf("\t One or more I/O Command Sets are %s\n", + cap->css & 0x40 ? "Supported" : "Not Supported"); + printf("\t %s\n", + cap->css & 0x80 ? "Only Admin Command Set Supported" : "I/O Command Set is Supported"); + printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", cap->nssrs ? "Yes" : "No"); + printf("\tDoorbell Stride (DSTRD): %u bytes\n", 1 << (2 + cap->dstrd)); + printf("\tTimeout (TO): %u ms\n", cap->to * 500); + printf("\tArbitration Mechanism Supported (AMS): Weighted Round Robin with Urgent Priority Class is %s\n", + cap->ams & 0x02 ? "Supported" : "Not supported"); + printf("\tContiguous Queues Required (CQR): %s\n", cap->cqr ? "Yes" : "No"); + printf("\tMaximum Queue Entries Supported (MQES): %u\n\n", cap->mqes + 1); +} + +static void stdout_registers_version(__u32 vs) +{ + printf("\tNVMe specification %d.%d\n\n", (vs & 0xffff0000) >> 16, + (vs & 0x0000ff00) >> 8); +} + +static void stdout_registers_cc_ams(__u8 ams) +{ + printf("\tArbitration Mechanism Selected (AMS): "); + switch (ams) { + case 0: + printf("Round Robin\n"); + break; + case 1: + printf("Weighted Round Robin with Urgent Priority Class\n"); + break; + case 7: + printf("Vendor Specific\n"); + break; + default: + printf("Reserved\n"); + break; + } +} + +static void stdout_registers_cc_shn(__u8 shn) +{ + printf("\tShutdown Notification (SHN): "); + switch (shn) { + case 0: + printf("No notification; no effect\n"); + break; + case 1: + printf("Normal shutdown notification\n"); + break; + case 2: + printf("Abrupt shutdown notification\n"); + break; + default: + printf("Reserved\n"); + break; + } +} + +static void stdout_registers_cc(__u32 cc) +{ + printf("\tController Ready Independent of Media Enable (CRIME): %s\n", + NVME_CC_CRIME(cc) ? "Enabled" : "Disabled"); + + printf("\tI/O Completion Queue Entry Size (IOCQES): %u bytes\n", + 1 << ((cc & 0x00f00000) >> NVME_CC_IOCQES_SHIFT)); + printf("\tI/O Submission Queue Entry Size (IOSQES): %u bytes\n", + 1 << ((cc & 0x000f0000) >> NVME_CC_IOSQES_SHIFT)); + stdout_registers_cc_shn((cc & 0x0000c000) >> NVME_CC_SHN_SHIFT); + stdout_registers_cc_ams((cc & 0x00003800) >> NVME_CC_AMS_SHIFT); + printf("\tMemory Page Size (MPS): %u bytes\n", + 1 << (12 + ((cc & 0x00000780) >> NVME_CC_MPS_SHIFT))); + printf("\tI/O Command Set Selected (CSS): %s\n", + (cc & 0x00000070) == 0x00 ? "NVM Command Set" : + (cc & 0x00000070) == 0x60 ? "All supported I/O Command Sets" : + (cc & 0x00000070) == 0x70 ? "Admin Command Set only" : "Reserved"); + printf("\tEnable (EN): %s\n\n", + (cc & 0x00000001) ? "Yes" : "No"); +} + +static void stdout_registers_csts_shst(__u8 shst) +{ + printf("\tShutdown Status (SHST): "); + switch (shst) { + case 0: + printf("Normal operation (no shutdown has been requested)\n"); + break; + case 1: + printf("Shutdown processing occurring\n"); + break; + case 2: + printf("Shutdown processing complete\n"); + break; + default: + printf("Reserved\n"); + break; + } +} + +static void stdout_registers_csts(__u32 csts) +{ + printf("\tProcessing Paused (PP): %s\n", + (csts & 0x00000020) ? "Yes" : "No"); + printf("\tNVM Subsystem Reset Occurred (NSSRO): %s\n", + (csts & 0x00000010) ? "Yes" : "No"); + stdout_registers_csts_shst((csts & 0x0000000c) >> 2); + printf("\tController Fatal Status (CFS): %s\n", + (csts & 0x00000002) ? "True" : "False"); + printf("\tReady (RDY): %s\n\n", + (csts & 0x00000001) ? "Yes" : "No"); + +} + +static void stdout_registers_nssd(__u32 nssd) +{ + printf("\tNVM Subsystem Shutdown Control (NSSC): %#x\n\n", nssd); +} + +static void stdout_registers_crto(__u32 crto) +{ + printf("\tCRIMT : %d secs\n", NVME_CRTO_CRIMT(crto) / 2); + printf("\tCRWMT : %d secs\n", NVME_CRTO_CRWMT(crto) / 2); +} + +static void stdout_registers_aqa(__u32 aqa) +{ + printf("\tAdmin Completion Queue Size (ACQS): %u\n", + ((aqa & 0x0fff0000) >> 16) + 1); + printf("\tAdmin Submission Queue Size (ASQS): %u\n\n", + (aqa & 0x00000fff) + 1); + +} + +static void stdout_registers_cmbloc(__u32 cmbloc, __u32 cmbsz) +{ + static const char * const enforced[] = { "Enforced", "Not Enforced" }; + + if (cmbsz == 0) { + printf("\tController Memory Buffer feature is not supported\n\n"); + return; + } + printf("\tOffset (OFST): 0x%x (See cmbsz.szu for granularity)\n", + (cmbloc & 0xfffff000) >> 12); + + printf("\tCMB Queue Dword Alignment (CQDA): %d\n", + (cmbloc & 0x00000100) >> 8); + + printf("\tCMB Data Metadata Mixed Memory Support (CDMMMS): %s\n", + enforced[(cmbloc & 0x00000080) >> 7]); + + printf("\tCMB Data Pointer and Command Independent Locations Support (CDPCILS): %s\n", + enforced[(cmbloc & 0x00000040) >> 6]); + + printf("\tCMB Data Pointer Mixed Locations Support (CDPMLS): %s\n", + enforced[(cmbloc & 0x00000020) >> 5]); + + printf("\tCMB Queue Physically Discontiguous Support (CQPDS): %s\n", + enforced[(cmbloc & 0x00000010) >> 4]); + + printf("\tCMB Queue Mixed Memory Support (CQMMS): %s\n", + enforced[(cmbloc & 0x00000008) >> 3]); + + printf("\tBase Indicator Register (BIR): 0x%x\n\n", + (cmbloc & 0x00000007)); +} + +static void stdout_registers_cmbsz(__u32 cmbsz) +{ + if (cmbsz == 0) { + printf("\tController Memory Buffer feature is not supported\n\n"); + return; + } + printf("\tSize (SZ): %u\n", (cmbsz & 0xfffff000) >> 12); + printf("\tSize Units (SZU): %s\n", + nvme_register_szu_to_string((cmbsz & 0x00000f00) >> 8)); + printf("\tWrite Data Support (WDS): Write Data and metadata transfer in Controller Memory Buffer is %s\n", + (cmbsz & 0x00000010) ? "Supported" : "Not supported"); + printf("\tRead Data Support (RDS): Read Data and metadata transfer in Controller Memory Buffer is %s\n", + (cmbsz & 0x00000008) ? "Supported" : "Not supported"); + printf("\tPRP SGL List Support (LISTS): PRP/SG Lists in Controller Memory Buffer is %s\n", + (cmbsz & 0x00000004) ? "Supported" : "Not supported"); + printf("\tCompletion Queue Support (CQS): Admin and I/O Completion Queues in Controller Memory Buffer is %s\n", + (cmbsz & 0x00000002) ? "Supported" : "Not supported"); + printf("\tSubmission Queue Support (SQS): Admin and I/O Submission Queues in Controller Memory Buffer is %s\n\n", + (cmbsz & 0x00000001) ? "Supported" : "Not supported"); +} + +static void stdout_registers_bpinfo_brs(__u8 brs) +{ + printf("\tBoot Read Status (BRS): "); + switch (brs) { + case 0: + printf("No Boot Partition read operation requested\n"); + break; + case 1: + printf("Boot Partition read in progress\n"); + break; + case 2: + printf("Boot Partition read completed successfully\n"); + break; + case 3: + printf("Error completing Boot Partition read\n"); + break; + default: + printf("Invalid\n"); + break; + } +} + +static void stdout_registers_bpinfo(__u32 bpinfo) +{ + printf("\tActive Boot Partition ID (ABPID): %u\n", + (bpinfo & 0x80000000) >> 31); + stdout_registers_bpinfo_brs((bpinfo & 0x03000000) >> 24); + printf("\tBoot Partition Size (BPSZ): %u\n", + bpinfo & 0x00007fff); +} + +static void stdout_registers_bprsel(__u32 bprsel) +{ + printf("\tBoot Partition Identifier (BPID): %u\n", + (bprsel & 0x80000000) >> 31); + printf("\tBoot Partition Read Offset (BPROF): %x\n", + (bprsel & 0x3ffffc00) >> 10); + printf("\tBoot Partition Read Size (BPRSZ): %x\n", + bprsel & 0x000003ff); +} + +static void stdout_registers_bpmbl(uint64_t bpmbl) +{ + printf("\tBoot Partition Memory Buffer Base Address (BMBBA): %"PRIx64"\n", + bpmbl); +} + +static void stdout_registers_cmbmsc(uint64_t cmbmsc) +{ + printf("\tController Base Address (CBA): %" PRIx64 "\n", + (cmbmsc & 0xfffffffffffff000) >> 12); + printf("\tController Memory Space Enable (CMSE): %" PRIx64 "\n", + (cmbmsc & 0x0000000000000002) >> 1); + printf("\tCapabilities Registers Enabled (CRE): CMBLOC and "\ + "CMBSZ registers are%senabled\n\n", + (cmbmsc & 0x0000000000000001) ? " " : " NOT "); +} + +static void stdout_registers_cmbsts(__u32 cmbsts) +{ + printf("\tController Base Address Invalid (CBAI): %x\n\n", + (cmbsts & 0x00000001)); +} + +static void stdout_registers_pmrcap(__u32 pmrcap) +{ + printf("\tController Memory Space Supported (CMSS): "); + printf("Referencing PMR with host supplied addresses is %sSupported\n", + NVME_PMRCAP_CMSS(pmrcap) ? "" : "Not "); + printf("\tPersistent Memory Region Timeout (PMRTO): %x\n", + NVME_PMRCAP_PMRTO(pmrcap)); + printf("\tPersistent Memory Region Write Barrier Mechanisms (PMRWBM): %x\n", + NVME_PMRCAP_PMRWMB(pmrcap)); + printf("\tPersistent Memory Region Time Units (PMRTU): "); + printf("PMR time unit is %s\n", NVME_PMRCAP_PMRTU(pmrcap) ? "minutes" : "500 milliseconds"); + printf("\tBase Indicator Register (BIR): %x\n", + NVME_PMRCAP_BIR(pmrcap)); + printf("\tWrite Data Support (WDS): "); + printf("Write data to the PMR is %ssupported\n", NVME_PMRCAP_WDS(pmrcap) ? "" : "not "); + printf("\tRead Data Support (RDS): "); + printf("Read data from the PMR is %ssupported\n", NVME_PMRCAP_RDS(pmrcap) ? "" : "not "); +} + +static void stdout_registers_pmrctl(__u32 pmrctl) +{ + printf("\tEnable (EN): PMR is %s\n", NVME_PMRCTL_EN(pmrctl) ? "READY" : "Disabled"); +} + +static void stdout_registers_pmrsts(__u32 pmrsts, __u32 pmrctl) +{ + printf("\tController Base Address Invalid (CBAI): %x\n", NVME_PMRSTS_CBAI(pmrsts)); + printf("\tHealth Status (HSTS): %s\n", + nvme_register_pmr_hsts_to_string(NVME_PMRSTS_HSTS(pmrsts))); + printf("\tNot Ready (NRDY): "); + printf("The Persistent Memory Region is %s to process ", + !NVME_PMRSTS_NRDY(pmrsts) && NVME_PMRCTL_EN(pmrctl) ? "READY" : "Not Ready"); + printf("PCI Express memory read and write requests\n"); + printf("\tError (ERR): %x\n", NVME_PMRSTS_ERR(pmrsts)); +} + +static void stdout_registers_pmrebs(__u32 pmrebs) +{ + printf("\tPMR Elasticity Buffer Size Base (PMRWBZ): %x\n", NVME_PMREBS_PMRWBZ(pmrebs)); + printf("\tRead Bypass Behavior : "); + printf("memory reads not conflicting with memory writes "); + printf("in the PMR Elasticity Buffer %s bypass those memory writes\n", + NVME_PMREBS_RBB(pmrebs) ? "SHALL" : "MAY"); + printf("\tPMR Elasticity Buffer Size Units (PMRSZU): %s\n", + nvme_register_pmr_pmrszu_to_string(NVME_PMREBS_PMRSZU(pmrebs))); +} + +static void stdout_registers_pmrswtp(__u32 pmrswtp) +{ + printf("\tPMR Sustained Write Throughput (PMRSWTV): %x\n", + NVME_PMRSWTP_PMRSWTV(pmrswtp)); + printf("\tPMR Sustained Write Throughput Units (PMRSWTU): %s/second\n", + nvme_register_pmr_pmrszu_to_string(NVME_PMRSWTP_PMRSWTU(pmrswtp))); +} + +static void stdout_registers_pmrmscl(uint32_t pmrmscl) +{ + printf("\tController Base Address (CBA): %#x\n", + (uint32_t)NVME_PMRMSC_CBA(pmrmscl)); + printf("\tController Memory Space Enable (CMSE): %#x\n\n", NVME_PMRMSC_CMSE(pmrmscl)); +} + +static void stdout_registers_pmrmscu(uint32_t pmrmscu) +{ + printf("\tController Base Address (CBA): %#x\n", + pmrmscu); +} + +void stdout_ctrl_registers(void *bar, bool fabrics) +{ + uint64_t cap, asq, acq, bpmbl, cmbmsc; + uint32_t vs, intms, intmc, cc, csts, nssr, crto, aqa, cmbsz, cmbloc, bpinfo, + bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp, + pmrmscl, pmrmscu; + int human = stdout_print_ops.flags & VERBOSE; + + cap = mmio_read64(bar + NVME_REG_CAP); + vs = mmio_read32(bar + NVME_REG_VS); + intms = mmio_read32(bar + NVME_REG_INTMS); + intmc = mmio_read32(bar + NVME_REG_INTMC); + cc = mmio_read32(bar + NVME_REG_CC); + csts = mmio_read32(bar + NVME_REG_CSTS); + nssr = mmio_read32(bar + NVME_REG_NSSR); + crto = mmio_read32(bar + NVME_REG_CRTO); + aqa = mmio_read32(bar + NVME_REG_AQA); + asq = mmio_read64(bar + NVME_REG_ASQ); + acq = mmio_read64(bar + NVME_REG_ACQ); + cmbloc = mmio_read32(bar + NVME_REG_CMBLOC); + cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); + bpinfo = mmio_read32(bar + NVME_REG_BPINFO); + bprsel = mmio_read32(bar + NVME_REG_BPRSEL); + bpmbl = mmio_read64(bar + NVME_REG_BPMBL); + cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC); + cmbsts = mmio_read32(bar + NVME_REG_CMBSTS); + pmrcap = mmio_read32(bar + NVME_REG_PMRCAP); + pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); + pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); + pmrebs = mmio_read32(bar + NVME_REG_PMREBS); + pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); + pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); + pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); + + if (human) { + if (cap != 0xffffffff) { + printf("cap : %"PRIx64"\n", cap); + stdout_registers_cap((struct nvme_bar_cap *)&cap); + } + if (vs != 0xffffffff) { + printf("version : %x\n", vs); + stdout_registers_version(vs); + } + if (cc != 0xffffffff) { + printf("cc : %x\n", cc); + stdout_registers_cc(cc); + } + if (csts != 0xffffffff) { + printf("csts : %x\n", csts); + stdout_registers_csts(csts); + } + if (nssr != 0xffffffff) { + printf("nssr : %x\n", nssr); + printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", + nssr); + } + if (crto != 0xffffffff) { + printf("crto : %x\n", crto); + stdout_registers_crto(crto); + } + if (!fabrics) { + printf("intms : %x\n", intms); + printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n", + intms); + + printf("intmc : %x\n", intmc); + printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n", + intmc); + printf("aqa : %x\n", aqa); + stdout_registers_aqa(aqa); + + printf("asq : %"PRIx64"\n", asq); + printf("\tAdmin Submission Queue Base (ASQB): %"PRIx64"\n\n", + asq); + + printf("acq : %"PRIx64"\n", acq); + printf("\tAdmin Completion Queue Base (ACQB): %"PRIx64"\n\n", + acq); + + printf("cmbloc : %x\n", cmbloc); + stdout_registers_cmbloc(cmbloc, cmbsz); + + printf("cmbsz : %x\n", cmbsz); + stdout_registers_cmbsz(cmbsz); + + printf("bpinfo : %x\n", bpinfo); + stdout_registers_bpinfo(bpinfo); + + printf("bprsel : %x\n", bprsel); + stdout_registers_bprsel(bprsel); + + printf("bpmbl : %"PRIx64"\n", bpmbl); + stdout_registers_bpmbl(bpmbl); + + printf("cmbmsc : %"PRIx64"\n", cmbmsc); + stdout_registers_cmbmsc(cmbmsc); + + printf("cmbsts : %x\n", cmbsts); + stdout_registers_cmbsts(cmbsts); + + printf("pmrcap : %x\n", pmrcap); + stdout_registers_pmrcap(pmrcap); + + printf("pmrctl : %x\n", pmrctl); + stdout_registers_pmrctl(pmrctl); + + printf("pmrsts : %x\n", pmrsts); + stdout_registers_pmrsts(pmrsts, pmrctl); + + printf("pmrebs : %x\n", pmrebs); + stdout_registers_pmrebs(pmrebs); + + printf("pmrswtp : %x\n", pmrswtp); + stdout_registers_pmrswtp(pmrswtp); + + printf("pmrmscl : %#x\n", pmrmscl); + stdout_registers_pmrmscl(pmrmscl); + + printf("pmrmscu : %#x\n", pmrmscu); + stdout_registers_pmrmscu(pmrmscu); + } + } else { + if (cap != 0xffffffff) + printf("cap : %"PRIx64"\n", cap); + if (vs != 0xffffffff) + printf("version : %x\n", vs); + if (cc != 0xffffffff) + printf("cc : %x\n", cc); + if (csts != 0xffffffff) + printf("csts : %x\n", csts); + if (nssr != 0xffffffff) + printf("nssr : %x\n", nssr); + if (crto != 0xffffffff) + printf("crto : %x\n", crto); + if (!fabrics) { + printf("intms : %x\n", intms); + printf("intmc : %x\n", intmc); + printf("aqa : %x\n", aqa); + printf("asq : %"PRIx64"\n", asq); + printf("acq : %"PRIx64"\n", acq); + printf("cmbloc : %x\n", cmbloc); + printf("cmbsz : %x\n", cmbsz); + printf("bpinfo : %x\n", bpinfo); + printf("bprsel : %x\n", bprsel); + printf("bpmbl : %"PRIx64"\n", bpmbl); + printf("cmbmsc : %"PRIx64"\n", cmbmsc); + printf("cmbsts : %x\n", cmbsts); + printf("pmrcap : %x\n", pmrcap); + printf("pmrctl : %x\n", pmrctl); + printf("pmrsts : %x\n", pmrsts); + printf("pmrebs : %x\n", pmrebs); + printf("pmrswtp : %x\n", pmrswtp); + printf("pmrmscl : %#x\n", pmrmscl); + printf("pmrmscu : %#x\n", pmrmscu); + } + } +} + +static void stdout_single_property(int offset, uint64_t value64) +{ + int human = stdout_print_ops.flags & VERBOSE; + uint32_t value32 = (uint32_t)value64; + + if (!human) { + if (nvme_is_64bit_reg(offset)) + printf("property: 0x%02x (%s), value: %"PRIx64"\n", + offset, nvme_register_to_string(offset), value64); + else + printf("property: 0x%02x (%s), value: %x\n", offset, + nvme_register_to_string(offset), value32); + return; + } + + switch (offset) { + case NVME_REG_CAP: + printf("cap : %"PRIx64"\n", value64); + stdout_registers_cap((struct nvme_bar_cap *)&value64); + break; + case NVME_REG_VS: + printf("version : %x\n", value32); + stdout_registers_version(value32); + break; + case NVME_REG_CC: + printf("cc : %x\n", value32); + stdout_registers_cc(value32); + break; + case NVME_REG_CSTS: + printf("csts : %x\n", value32); + stdout_registers_csts(value32); + break; + case NVME_REG_NSSR: + printf("nssr : %x\n", value32); + printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", value32); + break; + case NVME_REG_NSSD: + printf("nssd : %x\n", value32); + stdout_registers_nssd(value32); + break; + case NVME_REG_CRTO: + printf("crto : %x\n", value32); + stdout_registers_crto(value32); + break; + default: + printf("unknown property: 0x%02x (%s), value: %"PRIx64"\n", + offset, nvme_register_to_string(offset), value64); + break; + } +} + +static void stdout_status(int status) +{ + int val; + int type; + + /* + * Callers should be checking for negative values first, but provide a + * sensible fallback anyway + */ + if (status < 0) { + fprintf(stderr, "Error: %s\n", nvme_strerror(errno)); + return; + } + + val = nvme_status_get_value(status); + type = nvme_status_get_type(status); + + switch (type) { + case NVME_STATUS_TYPE_NVME: + fprintf(stderr, "NVMe status: %s(%#x)\n", + nvme_status_to_string(val, false), val); + break; + case NVME_STATUS_TYPE_MI: + fprintf(stderr, "NVMe-MI status: %s(%#x)\n", + nvme_mi_status_to_string(val), val); + break; + default: + fprintf(stderr, "Unknown status type %d, value %#x\n", type, + val); + break; + } +} + +static void stdout_error_status(int status, const char *msg, va_list ap) +{ + vfprintf(stderr, msg, ap); + fprintf(stderr, ": "); + stdout_status(status); +} + +static void stdout_id_ctrl_cmic(__u8 cmic) +{ + __u8 rsvd = (cmic & 0xF0) >> 4; + __u8 ana = (cmic & 0x8) >> 3; + __u8 sriov = (cmic & 0x4) >> 2; + __u8 mctl = (cmic & 0x2) >> 1; + __u8 mp = cmic & 0x1; + + if (rsvd) + printf(" [7:4] : %#x\tReserved\n", rsvd); + printf(" [3:3] : %#x\tANA %ssupported\n", ana, ana ? "" : "not "); + printf(" [2:2] : %#x\t%s\n", sriov, sriov ? "SR-IOV" : "PCI"); + printf(" [1:1] : %#x\t%s Controller\n", + mctl, mctl ? "Multi" : "Single"); + printf(" [0:0] : %#x\t%s Port\n", mp, mp ? "Multi" : "Single"); + printf("\n"); +} + +static void stdout_id_ctrl_oaes(__le32 ctrl_oaes) +{ + __u32 oaes = le32_to_cpu(ctrl_oaes); + __u32 disc = (oaes >> 31) & 0x1; + __u32 rsvd0 = (oaes & 0x70000000) >> 28; + __u32 zicn = (oaes & 0x08000000) >> 27; + __u32 rsvd1 = (oaes & 0x07FF0000) >> 16; + __u32 normal_shn = (oaes >> 15) & 0x1; + __u32 egealpcn = (oaes & 0x4000) >> 14; + __u32 lbasin = (oaes & 0x2000) >> 13; + __u32 plealcn = (oaes & 0x1000) >> 12; + __u32 anacn = (oaes & 0x800) >> 11; + __u32 rsvd2 = (oaes >> 10) & 0x1; + __u32 fan = (oaes & 0x200) >> 9; + __u32 nace = (oaes & 0x100) >> 8; + __u32 rsvd3 = oaes & 0xFF; + + printf(" [31:31] : %#x\tDiscovery Log Change Notice %sSupported\n", + disc, disc ? "" : "Not "); + if (rsvd0) + printf(" [30:28] : %#x\tReserved\n", rsvd0); + printf(" [27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", + zicn, zicn ? "" : "Not "); + if (rsvd1) + printf(" [26:16] : %#x\tReserved\n", rsvd1); + printf(" [15:15] : %#x\tNormal NSS Shutdown Event %sSupported\n", + normal_shn, normal_shn ? "" : "Not "); + printf(" [14:14] : %#x\tEndurance Group Event Aggregate Log Page"\ + " Change Notice %sSupported\n", + egealpcn, egealpcn ? "" : "Not "); + printf(" [13:13] : %#x\tLBA Status Information Notices %sSupported\n", + lbasin, lbasin ? "" : "Not "); + printf(" [12:12] : %#x\tPredictable Latency Event Aggregate Log Change"\ + " Notices %sSupported\n", + plealcn, plealcn ? "" : "Not "); + printf(" [11:11] : %#x\tAsymmetric Namespace Access Change Notices"\ + " %sSupported\n", anacn, anacn ? "" : "Not "); + if (rsvd2) + printf(" [10:10] : %#x\tReserved\n", rsvd2); + printf(" [9:9] : %#x\tFirmware Activation Notices %sSupported\n", + fan, fan ? "" : "Not "); + printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n", + nace, nace ? "" : "Not "); + if (rsvd3) + printf(" [7:0] : %#x\tReserved\n", rsvd3); + printf("\n"); +} + +static void stdout_id_ctrl_ctratt(__le32 ctrl_ctratt) +{ + __u32 ctratt = le32_to_cpu(ctrl_ctratt); + __u32 rsvd20 = (ctratt >> 20); + __u32 fdps = (ctratt >> 19) & 0x1; + __u32 rsvd16 = (ctratt >> 16) & 0x7; + __u32 elbas = (ctratt >> 15) & 0x1; + __u32 delnvmset = (ctratt >> 14) & 0x1; + __u32 delegrp = (ctratt >> 13) & 0x1; + __u32 vcap = (ctratt >> 12) & 0x1; + __u32 fcap = (ctratt >> 11) & 0x1; + __u32 mds = (ctratt >> 10) & 0x1; + __u32 hostid128 = (ctratt & NVME_CTRL_CTRATT_128_ID) >> 0; + __u32 psp = (ctratt & NVME_CTRL_CTRATT_NON_OP_PSP) >> 1; + __u32 sets = (ctratt & NVME_CTRL_CTRATT_NVM_SETS) >> 2; + __u32 rrl = (ctratt & NVME_CTRL_CTRATT_READ_RECV_LVLS) >> 3; + __u32 eg = (ctratt & NVME_CTRL_CTRATT_ENDURANCE_GROUPS) >> 4; + __u32 iod = (ctratt & NVME_CTRL_CTRATT_PREDICTABLE_LAT) >> 5; + __u32 tbkas = (ctratt & NVME_CTRL_CTRATT_TBKAS) >> 6; + __u32 ng = (ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) >> 7; + __u32 sqa = (ctratt & NVME_CTRL_CTRATT_SQ_ASSOCIATIONS) >> 8; + __u32 uuidlist = (ctratt & NVME_CTRL_CTRATT_UUID_LIST) >> 9; + + if (rsvd20) + printf(" [31:20] : %#x\tReserved\n", rsvd20); + printf(" [19:19] : %#x\tFlexible Data Placement %sSupported\n", + fdps, fdps ? "" : "Not "); + if (rsvd16) + printf(" [18:16] : %#x\tReserved\n", rsvd16); + printf(" [15:15] : %#x\tExtended LBA Formats %sSupported\n", + elbas, elbas ? "" : "Not "); + printf(" [14:14] : %#x\tDelete NVM Set %sSupported\n", + delnvmset, delnvmset ? "" : "Not "); + printf(" [13:13] : %#x\tDelete Endurance Group %sSupported\n", + delegrp, delegrp ? "" : "Not "); + printf(" [12:12] : %#x\tVariable Capacity Management %sSupported\n", + vcap, vcap ? "" : "Not "); + printf(" [11:11] : %#x\tFixed Capacity Management %sSupported\n", + fcap, fcap ? "" : "Not "); + printf(" [10:10] : %#x\tMulti Domain Subsystem %sSupported\n", + mds, mds ? "" : "Not "); + printf(" [9:9] : %#x\tUUID List %sSupported\n", + uuidlist, uuidlist ? "" : "Not "); + printf(" [8:8] : %#x\tSQ Associations %sSupported\n", + sqa, sqa ? "" : "Not "); + printf(" [7:7] : %#x\tNamespace Granularity %sSupported\n", + ng, ng ? "" : "Not "); + printf(" [6:6] : %#x\tTraffic Based Keep Alive %sSupported\n", + tbkas, tbkas ? "" : "Not "); + printf(" [5:5] : %#x\tPredictable Latency Mode %sSupported\n", + iod, iod ? "" : "Not "); + printf(" [4:4] : %#x\tEndurance Groups %sSupported\n", + eg, eg ? "" : "Not "); + printf(" [3:3] : %#x\tRead Recovery Levels %sSupported\n", + rrl, rrl ? "" : "Not "); + printf(" [2:2] : %#x\tNVM Sets %sSupported\n", + sets, sets ? "" : "Not "); + printf(" [1:1] : %#x\tNon-Operational Power State Permissive %sSupported\n", + psp, psp ? "" : "Not "); + printf(" [0:0] : %#x\t128-bit Host Identifier %sSupported\n", + hostid128, hostid128 ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_cntrltype(__u8 cntrltype) +{ + __u8 rsvd = (cntrltype & 0xFC) >> 2; + __u8 cntrl = cntrltype & 0x3; + + static const char * const type[] = { + "Controller type not reported", + "I/O Controller", + "Discovery Controller", + "Administrative Controller" + }; + + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:0] : %#x\t%s\n", cntrltype, type[cntrl]); +} + +static void stdout_id_ctrl_nvmsr(__u8 nvmsr) +{ + __u8 rsvd = (nvmsr >> 2) & 0xfc; + __u8 nvmee = (nvmsr >> 1) & 0x1; + __u8 nvmesd = nvmsr & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tNVM subsystem %spart of an Enclosure\n", + nvmee, nvmee ? "" : "Not "); + printf(" [0:0] : %#x\tNVM subsystem %spart of a Storage Device\n", + nvmesd, nvmesd ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_vwci(__u8 vwci) +{ + __u8 vwcrv = (vwci >> 7) & 0x1; + __u8 vwcr = vwci & 0xfe; + + printf(" [7:7] : %#x\tVPD Write Cycles Remaining field is %svalid.\n", + vwcrv, vwcrv ? "" : "Not "); + printf(" [6:0] : %#x\tVPD Write Cycles Remaining\n", vwcr); + printf("\n"); + +} + +static void stdout_id_ctrl_mec(__u8 mec) +{ + __u8 rsvd = (mec >> 2) & 0xfc; + __u8 pcieme = (mec >> 1) & 0x1; + __u8 smbusme = mec & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tNVM subsystem %scontains a Management Endpoint"\ + " on a PCIe port\n", pcieme, pcieme ? "" : "Not "); + printf(" [0:0] : %#x\tNVM subsystem %scontains a Management Endpoint"\ + " on an SMBus/I2C port\n", smbusme, smbusme ? "" : "Not "); + printf("\n"); + +} + +static void stdout_id_ctrl_oacs(__le16 ctrl_oacs) +{ + __u16 oacs = le16_to_cpu(ctrl_oacs); + __u16 rsvd = (oacs & 0xF800) >> 11; + __u16 lock = (oacs >> 10) & 0x1; + __u16 glbas = (oacs & 0x200) >> 9; + __u16 dbc = (oacs & 0x100) >> 8; + __u16 vir = (oacs & 0x80) >> 7; + __u16 nmi = (oacs & 0x40) >> 6; + __u16 dir = (oacs & 0x20) >> 5; + __u16 sft = (oacs & 0x10) >> 4; + __u16 nsm = (oacs & 0x8) >> 3; + __u16 fwc = (oacs & 0x4) >> 2; + __u16 fmt = (oacs & 0x2) >> 1; + __u16 sec = oacs & 0x1; + + if (rsvd) + printf(" [15:11] : %#x\tReserved\n", rsvd); + printf(" [10:10] : %#x\tLockdown Command and Feature %sSupported\n", + lock, lock ? "" : "Not "); + printf(" [9:9] : %#x\tGet LBA Status Capability %sSupported\n", + glbas, glbas ? "" : "Not "); + printf(" [8:8] : %#x\tDoorbell Buffer Config %sSupported\n", + dbc, dbc ? "" : "Not "); + printf(" [7:7] : %#x\tVirtualization Management %sSupported\n", + vir, vir ? "" : "Not "); + printf(" [6:6] : %#x\tNVMe-MI Send and Receive %sSupported\n", + nmi, nmi ? "" : "Not "); + printf(" [5:5] : %#x\tDirectives %sSupported\n", + dir, dir ? "" : "Not "); + printf(" [4:4] : %#x\tDevice Self-test %sSupported\n", + sft, sft ? "" : "Not "); + printf(" [3:3] : %#x\tNS Management and Attachment %sSupported\n", + nsm, nsm ? "" : "Not "); + printf(" [2:2] : %#x\tFW Commit and Download %sSupported\n", + fwc, fwc ? "" : "Not "); + printf(" [1:1] : %#x\tFormat NVM %sSupported\n", + fmt, fmt ? "" : "Not "); + printf(" [0:0] : %#x\tSecurity Send and Receive %sSupported\n", + sec, sec ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_frmw(__u8 frmw) +{ + __u8 rsvd = (frmw & 0xC0) >> 6; + __u8 smud = (frmw >> 5) & 0x1; + __u8 fawr = (frmw & 0x10) >> 4; + __u8 nfws = (frmw & 0xE) >> 1; + __u8 s1ro = frmw & 0x1; + + if (rsvd) + printf(" [7:6] : %#x\tReserved\n", rsvd); + printf(" [5:5] : %#x\tMultiple FW or Boot Update Detection %sSupported\n", + smud, smud ? "" : "Not "); + printf(" [4:4] : %#x\tFirmware Activate Without Reset %sSupported\n", + fawr, fawr ? "" : "Not "); + printf(" [3:1] : %#x\tNumber of Firmware Slots\n", nfws); + printf(" [0:0] : %#x\tFirmware Slot 1 Read%s\n", + s1ro, s1ro ? "-Only" : "/Write"); + printf("\n"); +} + +static void stdout_id_ctrl_lpa(__u8 lpa) +{ + __u8 rsvd = (lpa & 0x80) >> 7; + __u8 tel = (lpa >> 6) & 0x1; + __u8 lid_sup = (lpa >> 5) & 0x1; + __u8 persevnt = (lpa & 0x10) >> 4; + __u8 telem = (lpa & 0x8) >> 3; + __u8 ed = (lpa & 0x4) >> 2; + __u8 celp = (lpa & 0x2) >> 1; + __u8 smlp = lpa & 0x1; + + if (rsvd) + printf(" [7:7] : %#x\tReserved\n", rsvd); + printf(" [6:6] : %#x\tTelemetry Log Data Area 4 %sSupported\n", + tel, tel ? "" : "Not "); + printf(" [5:5] : %#x\tLID 0x0, Scope of each command in LID 0x5, "\ + "0x12, 0x13 %sSupported\n", lid_sup, lid_sup ? "" : "Not "); + printf(" [4:4] : %#x\tPersistent Event log %sSupported\n", + persevnt, persevnt ? "" : "Not "); + printf(" [3:3] : %#x\tTelemetry host/controller initiated log page %sSupported\n", + telem, telem ? "" : "Not "); + printf(" [2:2] : %#x\tExtended data for Get Log Page %sSupported\n", + ed, ed ? "" : "Not "); + printf(" [1:1] : %#x\tCommand Effects Log Page %sSupported\n", + celp, celp ? "" : "Not "); + printf(" [0:0] : %#x\tSMART/Health Log Page per NS %sSupported\n", + smlp, smlp ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_elpe(__u8 elpe) +{ + printf(" [7:0] : %d (0's based)\tError Log Page Entries (ELPE)\n", + elpe); + printf("\n"); +} + +static void stdout_id_ctrl_npss(__u8 npss) +{ + printf(" [7:0] : %d (0's based)\tNumber of Power States Support (NPSS)\n", + npss); + printf("\n"); +} + +static void stdout_id_ctrl_avscc(__u8 avscc) +{ + __u8 rsvd = (avscc & 0xFE) >> 1; + __u8 fmt = avscc & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tAdmin Vendor Specific Commands uses %s Format\n", + fmt, fmt ? "NVMe" : "Vendor Specific"); + printf("\n"); +} + +static void stdout_id_ctrl_apsta(__u8 apsta) +{ + __u8 rsvd = (apsta & 0xFE) >> 1; + __u8 apst = apsta & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tAutonomous Power State Transitions %sSupported\n", + apst, apst ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_wctemp(__le16 wctemp) +{ + printf(" [15:0] : %ld °C (%u K)\tWarning Composite Temperature Threshold (WCTEMP)\n", + kelvin_to_celsius(le16_to_cpu(wctemp)), le16_to_cpu(wctemp)); + printf("\n"); +} + +static void stdout_id_ctrl_cctemp(__le16 cctemp) +{ + printf(" [15:0] : %ld °C (%u K)\tCritical Composite Temperature Threshold (CCTEMP)\n", + kelvin_to_celsius(le16_to_cpu(cctemp)), le16_to_cpu(cctemp)); + printf("\n"); +} + +static void stdout_id_ctrl_tnvmcap(__u8 *tnvmcap) +{ + printf("[127:0] : %s\n", uint128_t_to_l10n_string(le128_to_cpu(tnvmcap))); + printf("\tTotal NVM Capacity (TNVMCAP)\n\n"); +} + +static void stdout_id_ctrl_unvmcap(__u8 *unvmcap) +{ + printf("[127:0] : %s\n", uint128_t_to_l10n_string(le128_to_cpu(unvmcap))); + printf("\tUnallocated NVM Capacity (UNVMCAP)\n\n"); +} + +void stdout_id_ctrl_rpmbs(__le32 ctrl_rpmbs) +{ + __u32 rpmbs = le32_to_cpu(ctrl_rpmbs); + __u32 asz = (rpmbs & 0xFF000000) >> 24; + __u32 tsz = (rpmbs & 0xFF0000) >> 16; + __u32 rsvd = (rpmbs & 0xFFC0) >> 6; + __u32 auth = (rpmbs & 0x38) >> 3; + __u32 rpmb = rpmbs & 0x7; + + printf(" [31:24]: %#x\tAccess Size\n", asz); + printf(" [23:16]: %#x\tTotal Size\n", tsz); + if (rsvd) + printf(" [15:6] : %#x\tReserved\n", rsvd); + printf(" [5:3] : %#x\tAuthentication Method\n", auth); + printf(" [2:0] : %#x\tNumber of RPMB Units\n", rpmb); + printf("\n"); +} + +static void stdout_id_ctrl_hctma(__le16 ctrl_hctma) +{ + __u16 hctma = le16_to_cpu(ctrl_hctma); + __u16 rsvd = (hctma & 0xFFFE) >> 1; + __u16 hctm = hctma & 0x1; + + if (rsvd) + printf(" [15:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tHost Controlled Thermal Management %sSupported\n", + hctm, hctm ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_mntmt(__le16 mntmt) +{ + printf(" [15:0] : %ld °C (%u K)\tMinimum Thermal Management Temperature (MNTMT)\n", + kelvin_to_celsius(le16_to_cpu(mntmt)), le16_to_cpu(mntmt)); + printf("\n"); +} + +static void stdout_id_ctrl_mxtmt(__le16 mxtmt) +{ + printf(" [15:0] : %ld °C (%u K)\tMaximum Thermal Management Temperature (MXTMT)\n", + kelvin_to_celsius(le16_to_cpu(mxtmt)), le16_to_cpu(mxtmt)); + printf("\n"); +} + +static void stdout_id_ctrl_sanicap(__le32 ctrl_sanicap) +{ + __u32 sanicap = le32_to_cpu(ctrl_sanicap); + __u32 rsvd = (sanicap & 0x1FFFFFF8) >> 3; + __u32 owr = (sanicap & 0x4) >> 2; + __u32 ber = (sanicap & 0x2) >> 1; + __u32 cer = sanicap & 0x1; + __u32 ndi = (sanicap & 0x20000000) >> 29; + __u32 nodmmas = (sanicap & 0xC0000000) >> 30; + + static const char * const modifies_media[] = { + "Additional media modification after sanitize operation completes successfully is not defined", + "Media is not additionally modified after sanitize operation completes successfully", + "Media is additionally modified after sanitize operation completes successfully", + "Reserved" + }; + + printf(" [31:30] : %#x\t%s\n", nodmmas, modifies_media[nodmmas]); + printf(" [29:29] : %#x\tNo-Deallocate After Sanitize bit in Sanitize command %sSupported\n", + ndi, ndi ? "Not " : ""); + if (rsvd) + printf(" [28:3] : %#x\tReserved\n", rsvd); + printf(" [2:2] : %#x\tOverwrite Sanitize Operation %sSupported\n", + owr, owr ? "" : "Not "); + printf(" [1:1] : %#x\tBlock Erase Sanitize Operation %sSupported\n", + ber, ber ? "" : "Not "); + printf(" [0:0] : %#x\tCrypto Erase Sanitize Operation %sSupported\n", + cer, cer ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_anacap(__u8 anacap) +{ + __u8 nz = (anacap & 0x80) >> 7; + __u8 grpid_static = (anacap & 0x40) >> 6; + __u8 rsvd = (anacap & 0x20) >> 5; + __u8 ana_change = (anacap & 0x10) >> 4; + __u8 ana_persist_loss = (anacap & 0x08) >> 3; + __u8 ana_inaccessible = (anacap & 0x04) >> 2; + __u8 ana_nonopt = (anacap & 0x02) >> 1; + __u8 ana_opt = (anacap & 0x01); + + printf(" [7:7] : %#x\tNon-zero group ID %sSupported\n", + nz, nz ? "" : "Not "); + printf(" [6:6] : %#x\tGroup ID does %schange\n", + grpid_static, grpid_static ? "not " : ""); + if (rsvd) + printf(" [5:5] : %#x\tReserved\n", rsvd); + printf(" [4:4] : %#x\tANA Change state %sSupported\n", + ana_change, ana_change ? "" : "Not "); + printf(" [3:3] : %#x\tANA Persistent Loss state %sSupported\n", + ana_persist_loss, ana_persist_loss ? "" : "Not "); + printf(" [2:2] : %#x\tANA Inaccessible state %sSupported\n", + ana_inaccessible, ana_inaccessible ? "" : "Not "); + printf(" [1:1] : %#x\tANA Non-optimized state %sSupported\n", + ana_nonopt, ana_nonopt ? "" : "Not "); + printf(" [0:0] : %#x\tANA Optimized state %sSupported\n", + ana_opt, ana_opt ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_sqes(__u8 sqes) +{ + __u8 msqes = (sqes & 0xF0) >> 4; + __u8 rsqes = sqes & 0xF; + + printf(" [7:4] : %#x\tMax SQ Entry Size (%d)\n", msqes, 1 << msqes); + printf(" [3:0] : %#x\tMin SQ Entry Size (%d)\n", rsqes, 1 << rsqes); + printf("\n"); +} + +static void stdout_id_ctrl_cqes(__u8 cqes) +{ + __u8 mcqes = (cqes & 0xF0) >> 4; + __u8 rcqes = cqes & 0xF; + + printf(" [7:4] : %#x\tMax CQ Entry Size (%d)\n", mcqes, 1 << mcqes); + printf(" [3:0] : %#x\tMin CQ Entry Size (%d)\n", rcqes, 1 << rcqes); + printf("\n"); +} + +static void stdout_id_ctrl_oncs(__le16 ctrl_oncs) +{ + __u16 oncs = le16_to_cpu(ctrl_oncs); + __u16 rsvd = oncs >> 11; + bool afc = !!(oncs & NVME_CTRL_ONCS_ALL_FAST_COPY); + bool csa = !!(oncs & NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY); + bool copy = !!(oncs & NVME_CTRL_ONCS_COPY); + bool vrfy = !!(oncs & NVME_CTRL_ONCS_VERIFY); + bool tmst = !!(oncs & NVME_CTRL_ONCS_TIMESTAMP); + bool resv = !!(oncs & NVME_CTRL_ONCS_RESERVATIONS); + bool save = !!(oncs & NVME_CTRL_ONCS_SAVE_FEATURES); + bool wzro = !!(oncs & NVME_CTRL_ONCS_WRITE_ZEROES); + bool dsms = !!(oncs & NVME_CTRL_ONCS_DSM); + bool wunc = !!(oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE); + bool cmp = !!(oncs & NVME_CTRL_ONCS_COMPARE); + + if (rsvd) + printf(" [15:11] : %#x\tReserved\n", rsvd); + printf(" [10:10] : %#x\tAll Fast Copy %sSupported\n", + afc, afc ? "" : "Not "); + printf(" [9:9] : %#x\tCopy Single Atomicity %sSupported\n", + csa, csa ? "" : "Not "); + printf(" [8:8] : %#x\tCopy %sSupported\n", + copy, copy ? "" : "Not "); + printf(" [7:7] : %#x\tVerify %sSupported\n", + vrfy, vrfy ? "" : "Not "); + printf(" [6:6] : %#x\tTimestamp %sSupported\n", + tmst, tmst ? "" : "Not "); + printf(" [5:5] : %#x\tReservations %sSupported\n", + resv, resv ? "" : "Not "); + printf(" [4:4] : %#x\tSave and Select %sSupported\n", + save, save ? "" : "Not "); + printf(" [3:3] : %#x\tWrite Zeroes %sSupported\n", + wzro, wzro ? "" : "Not "); + printf(" [2:2] : %#x\tData Set Management %sSupported\n", + dsms, dsms ? "" : "Not "); + printf(" [1:1] : %#x\tWrite Uncorrectable %sSupported\n", + wunc, wunc ? "" : "Not "); + printf(" [0:0] : %#x\tCompare %sSupported\n", + cmp, cmp ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_fuses(__le16 ctrl_fuses) +{ + __u16 fuses = le16_to_cpu(ctrl_fuses); + __u16 rsvd = (fuses & 0xFE) >> 1; + __u16 cmpw = fuses & 0x1; + + if (rsvd) + printf(" [15:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tFused Compare and Write %sSupported\n", + cmpw, cmpw ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_fna(__u8 fna) +{ + __u8 rsvd = (fna & 0xF0) >> 4; + __u8 bcnsid = (fna & 0x8) >> 3; + __u8 cese = (fna & 0x4) >> 2; + __u8 cens = (fna & 0x2) >> 1; + __u8 fmns = fna & 0x1; + + if (rsvd) + printf(" [7:4] : %#x\tReserved\n", rsvd); + printf(" [3:3] : %#x\tFormat NVM Broadcast NSID (FFFFFFFFh) %sSupported\n", + bcnsid, bcnsid ? "Not " : ""); + printf(" [2:2] : %#x\tCrypto Erase %sSupported as part of Secure Erase\n", + cese, cese ? "" : "Not "); + printf(" [1:1] : %#x\tCrypto Erase Applies to %s Namespace(s)\n", + cens, cens ? "All" : "Single"); + printf(" [0:0] : %#x\tFormat Applies to %s Namespace(s)\n", + fmns, fmns ? "All" : "Single"); + printf("\n"); +} + +static void stdout_id_ctrl_vwc(__u8 vwc) +{ + __u8 rsvd = (vwc & 0xF8) >> 3; + __u8 flush = (vwc & 0x6) >> 1; + __u8 vwcp = vwc & 0x1; + + static const char * const flush_behavior[] = { + "Support for the NSID field set to FFFFFFFFh is not indicated", + "Reserved", + "The Flush command does not support NSID set to FFFFFFFFh", + "The Flush command supports NSID set to FFFFFFFFh" + }; + + if (rsvd) + printf(" [7:3] : %#x\tReserved\n", rsvd); + printf(" [2:1] : %#x\t%s\n", flush, flush_behavior[flush]); + printf(" [0:0] : %#x\tVolatile Write Cache %sPresent\n", vwcp, vwcp ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_icsvscc(__u8 icsvscc) +{ + __u8 rsvd = (icsvscc & 0xFE) >> 1; + __u8 fmt = icsvscc & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tNVM Vendor Specific Commands uses %s Format\n", + fmt, fmt ? "NVMe" : "Vendor Specific"); + printf("\n"); +} + +static void stdout_id_ctrl_nwpc(__u8 nwpc) +{ + __u8 no_wp_wp = (nwpc & 0x01); + __u8 wp_power_cycle = (nwpc & 0x02) >> 1; + __u8 wp_permanent = (nwpc & 0x04) >> 2; + __u8 rsvd = (nwpc & 0xF8) >> 3; + + if (rsvd) + printf(" [7:3] : %#x\tReserved\n", rsvd); + + printf(" [2:2] : %#x\tPermanent Write Protect %sSupported\n", + wp_permanent, wp_permanent ? "" : "Not "); + printf(" [1:1] : %#x\tWrite Protect Until Power Supply %sSupported\n", + wp_power_cycle, wp_power_cycle ? "" : "Not "); + printf(" [0:0] : %#x\tNo Write Protect and Write Protect Namespace %sSupported\n", + no_wp_wp, no_wp_wp ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ctrl_ocfs(__le16 ctrl_ocfs) +{ + __u16 ocfs = le16_to_cpu(ctrl_ocfs); + __u16 rsvd = ocfs >> 4; + __u8 copy_fmt_supported; + int copy_fmt; + + if (rsvd) + printf(" [15:4] : %#x\tReserved\n", rsvd); + for (copy_fmt = 3; copy_fmt >= 0; copy_fmt--) { + copy_fmt_supported = ocfs >> copy_fmt & 1; + printf(" [%d:%d] : %#x\tController Copy Format %xh %sSupported\n", copy_fmt, copy_fmt, + copy_fmt_supported, copy_fmt, copy_fmt_supported ? "" : "Not "); + } + printf("\n"); +} + +static void stdout_id_ctrl_sgls(__le32 ctrl_sgls) +{ + __u32 sgls = le32_to_cpu(ctrl_sgls); + __u32 rsvd0 = (sgls & 0xFFC00000) >> 22; + __u32 trsdbd = (sgls & 0x200000) >> 21; + __u32 aofdsl = (sgls & 0x100000) >> 20; + __u32 mpcsd = (sgls & 0x80000) >> 19; + __u32 sglltb = (sgls & 0x40000) >> 18; + __u32 bacmdb = (sgls & 0x20000) >> 17; + __u32 bbs = (sgls & 0x10000) >> 16; + __u32 sdt = (sgls >> 8) & 0xff; + __u32 rsvd1 = (sgls & 0xF8) >> 3; + __u32 key = (sgls & 0x4) >> 2; + __u32 sglsp = sgls & 0x3; + + if (rsvd0) + printf(" [31:22]: %#x\tReserved\n", rsvd0); + if (sglsp || (!sglsp && trsdbd)) + printf(" [21:21]: %#x\tTransport SGL Data Block Descriptor %sSupported\n", + trsdbd, trsdbd ? "" : "Not "); + if (sglsp || (!sglsp && aofdsl)) + printf(" [20:20]: %#x\tAddress Offsets %sSupported\n", + aofdsl, aofdsl ? "" : "Not "); + if (sglsp || (!sglsp && mpcsd)) + printf(" [19:19]: %#x\tMetadata Pointer Containing " + "SGL Descriptor is %sSupported\n", + mpcsd, mpcsd ? "" : "Not "); + if (sglsp || (!sglsp && sglltb)) + printf(" [18:18]: %#x\tSGL Length Larger than Buffer %sSupported\n", + sglltb, sglltb ? "" : "Not "); + if (sglsp || (!sglsp && bacmdb)) + printf(" [17:17]: %#x\tByte-Aligned Contig. MD Buffer %sSupported\n", + bacmdb, bacmdb ? "" : "Not "); + if (sglsp || (!sglsp && bbs)) + printf(" [16:16]: %#x\tSGL Bit-Bucket %sSupported\n", + bbs, bbs ? "" : "Not "); + printf(" [15:8] : %#x\tSGL Descriptor Threshold\n", sdt); + if (rsvd1) + printf(" [7:3] : %#x\tReserved\n", rsvd1); + if (sglsp || (!sglsp && key)) + printf(" [2:2] : %#x\tKeyed SGL Data Block descriptor %sSupported\n", + key, key ? "" : "Not "); + if (sglsp == 0x3) + printf(" [1:0] : %#x\tReserved\n", sglsp); + else if (sglsp == 0x2) + printf(" [1:0] : %#x\tScatter-Gather Lists Supported." + " Dword alignment required.\n", sglsp); + else if (sglsp == 0x1) + printf(" [1:0] : %#x\tScatter-Gather Lists Supported." + " No Dword alignment required.\n", sglsp); + else + printf(" [1:0] : %#x\tScatter-Gather Lists Not Supported\n", sglsp); + printf("\n"); +} + +static void stdout_id_ctrl_fcatt(__u8 fcatt) +{ + __u8 rsvd = (fcatt & 0xFE) >> 1; + __u8 scm = fcatt & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\t%s Controller Model\n", + scm, scm ? "Static" : "Dynamic"); + printf("\n"); +} + +static void stdout_id_ctrl_ofcs(__le16 ofcs) +{ + __u16 rsvd = (ofcs & 0xfffe) >> 1; + __u8 disconn = ofcs & 0x1; + + if (rsvd) + printf(" [15:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tDisconnect command %s Supported\n", + disconn, disconn ? "" : "Not"); + printf("\n"); + +} + +static void stdout_id_ns_nsfeat(__u8 nsfeat) +{ + __u8 rsvd = (nsfeat & 0xE0) >> 5; + __u8 ioopt = (nsfeat & 0x10) >> 4; + __u8 uidreuse = (nsfeat & 0x8) >> 3; + __u8 dulbe = (nsfeat & 0x4) >> 2; + __u8 na = (nsfeat & 0x2) >> 1; + __u8 thin = nsfeat & 0x1; + + if (rsvd) + printf(" [7:5] : %#x\tReserved\n", rsvd); + printf(" [4:4] : %#x\tNPWG, NPWA, NPDG, NPDA, and NOWS are %sSupported\n", + ioopt, ioopt ? "" : "Not "); + printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n", + uidreuse, uidreuse ? "Never " : ""); + printf(" [2:2] : %#x\tDeallocated or Unwritten Logical Block error %sSupported\n", + dulbe, dulbe ? "" : "Not "); + printf(" [1:1] : %#x\tNamespace uses %s\n", + na, na ? "NAWUN, NAWUPF, and NACWU" : "AWUN, AWUPF, and ACWU"); + printf(" [0:0] : %#x\tThin Provisioning %sSupported\n", + thin, thin ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ns_flbas(__u8 flbas) +{ + __u8 rsvd = (flbas & 0x80) >> 7; + __u8 msb2_lbaf = (flbas & NVME_NS_FLBAS_HIGHER_MASK) >> 5; + __u8 mdedata = (flbas & 0x10) >> 4; + __u8 lsb4_lbaf = flbas & NVME_NS_FLBAS_LOWER_MASK; + + if (rsvd) + printf(" [7:7] : %#x\tReserved\n", rsvd); + printf(" [6:5] : %#x\tMost significant 2 bits of Current LBA Format Selected\n", + msb2_lbaf); + printf(" [4:4] : %#x\tMetadata Transferred %s\n", + mdedata, mdedata ? "at End of Data LBA" : "in Separate Contiguous Buffer"); + printf(" [3:0] : %#x\tLeast significant 4 bits of Current LBA Format Selected\n", + lsb4_lbaf); + printf("\n"); +} + +static void stdout_id_ns_mc(__u8 mc) +{ + __u8 rsvd = (mc & 0xFC) >> 2; + __u8 mdp = (mc & 0x2) >> 1; + __u8 extdlba = mc & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tMetadata Pointer %sSupported\n", + mdp, mdp ? "" : "Not "); + printf(" [0:0] : %#x\tMetadata as Part of Extended Data LBA %sSupported\n", + extdlba, extdlba ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ns_dpc(__u8 dpc) +{ + __u8 rsvd = (dpc & 0xE0) >> 5; + __u8 pil8 = (dpc & 0x10) >> 4; + __u8 pif8 = (dpc & 0x8) >> 3; + __u8 pit3 = (dpc & 0x4) >> 2; + __u8 pit2 = (dpc & 0x2) >> 1; + __u8 pit1 = dpc & 0x1; + + if (rsvd) + printf(" [7:5] : %#x\tReserved\n", rsvd); + printf(" [4:4] : %#x\tProtection Information Transferred as Last Bytes of Metadata %sSupported\n", + pil8, pil8 ? "" : "Not "); + printf(" [3:3] : %#x\tProtection Information Transferred as First Bytes of Metadata %sSupported\n", + pif8, pif8 ? "" : "Not "); + printf(" [2:2] : %#x\tProtection Information Type 3 %sSupported\n", + pit3, pit3 ? "" : "Not "); + printf(" [1:1] : %#x\tProtection Information Type 2 %sSupported\n", + pit2, pit2 ? "" : "Not "); + printf(" [0:0] : %#x\tProtection Information Type 1 %sSupported\n", + pit1, pit1 ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ns_dps(__u8 dps) +{ + __u8 rsvd = (dps & 0xF0) >> 4; + __u8 pif8 = (dps & 0x8) >> 3; + __u8 pit = dps & 0x7; + + if (rsvd) + printf(" [7:4] : %#x\tReserved\n", rsvd); + printf(" [3:3] : %#x\tProtection Information is Transferred as %s Bytes of Metadata\n", + pif8, pif8 ? "First" : "Last"); + printf(" [2:0] : %#x\tProtection Information %s\n", pit, + pit == 3 ? "Type 3 Enabled" : + pit == 2 ? "Type 2 Enabled" : + pit == 1 ? "Type 1 Enabled" : + pit == 0 ? "Disabled" : "Reserved Enabled"); + printf("\n"); +} + +static void stdout_id_ns_nmic(__u8 nmic) +{ + __u8 rsvd = (nmic & 0xFE) >> 1; + __u8 mp = nmic & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tNamespace Multipath %sCapable\n", + mp, mp ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ns_rescap(__u8 rescap) +{ + __u8 iekr = (rescap & 0x80) >> 7; + __u8 eaar = (rescap & 0x40) >> 6; + __u8 wear = (rescap & 0x20) >> 5; + __u8 earo = (rescap & 0x10) >> 4; + __u8 wero = (rescap & 0x8) >> 3; + __u8 ea = (rescap & 0x4) >> 2; + __u8 we = (rescap & 0x2) >> 1; + __u8 ptpl = rescap & 0x1; + + printf(" [7:7] : %#x\tIgnore Existing Key - Used as defined in revision %s\n", + iekr, iekr ? "1.3 or later" : "1.2.1 or earlier"); + printf(" [6:6] : %#x\tExclusive Access - All Registrants %sSupported\n", + eaar, eaar ? "" : "Not "); + printf(" [5:5] : %#x\tWrite Exclusive - All Registrants %sSupported\n", + wear, wear ? "" : "Not "); + printf(" [4:4] : %#x\tExclusive Access - Registrants Only %sSupported\n", + earo, earo ? "" : "Not "); + printf(" [3:3] : %#x\tWrite Exclusive - Registrants Only %sSupported\n", + wero, wero ? "" : "Not "); + printf(" [2:2] : %#x\tExclusive Access %sSupported\n", + ea, ea ? "" : "Not "); + printf(" [1:1] : %#x\tWrite Exclusive %sSupported\n", + we, we ? "" : "Not "); + printf(" [0:0] : %#x\tPersist Through Power Loss %sSupported\n", + ptpl, ptpl ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ns_fpi(__u8 fpi) +{ + __u8 fpis = (fpi & 0x80) >> 7; + __u8 fpii = fpi & 0x7F; + + printf(" [7:7] : %#x\tFormat Progress Indicator %sSupported\n", + fpis, fpis ? "" : "Not "); + if (fpis || (!fpis && fpii)) + printf(" [6:0] : %#x\tFormat Progress Indicator (Remaining %d%%)\n", + fpii, fpii); + printf("\n"); +} + +static void stdout_id_ns_nsattr(__u8 nsattr) +{ + __u8 rsvd = (nsattr & 0xFE) >> 1; + __u8 write_protected = nsattr & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\tNamespace %sWrite Protected\n", + write_protected, write_protected ? "" : "Not "); + printf("\n"); +} + +static void stdout_id_ns_dlfeat(__u8 dlfeat) +{ + __u8 rsvd = (dlfeat & 0xE0) >> 5; + __u8 guard = (dlfeat & 0x10) >> 4; + __u8 dwz = (dlfeat & 0x8) >> 3; + __u8 val = dlfeat & 0x7; + + if (rsvd) + printf(" [7:5] : %#x\tReserved\n", rsvd); + printf(" [4:4] : %#x\tGuard Field of Deallocated Logical Blocks is set to %s\n", + guard, guard ? "CRC of The Value Read" : "0xFFFF"); + printf(" [3:3] : %#x\tDeallocate Bit in the Write Zeroes Command is %sSupported\n", + dwz, dwz ? "" : "Not "); + printf(" [2:0] : %#x\tBytes Read From a Deallocated Logical Block and its Metadata are %s\n", + val, val == 2 ? "0xFF" : + val == 1 ? "0x00" : + val == 0 ? "Not Reported" : "Reserved Value"); + printf("\n"); +} + +static void stdout_id_ns(struct nvme_id_ns *ns, unsigned int nsid, + unsigned int lba_index, bool cap_only) +{ + bool human = stdout_print_ops.flags & VERBOSE; + int vs = stdout_print_ops.flags & VS; + int i; + __u8 flbas; + char *in_use = "(in use)"; + + if (!cap_only) { + printf("NVME Identify Namespace %d:\n", nsid); + printf("nsze : %#"PRIx64"\n", le64_to_cpu(ns->nsze)); + printf("ncap : %#"PRIx64"\n", le64_to_cpu(ns->ncap)); + printf("nuse : %#"PRIx64"\n", le64_to_cpu(ns->nuse)); + printf("nsfeat : %#x\n", ns->nsfeat); + if (human) + stdout_id_ns_nsfeat(ns->nsfeat); + } else + printf("NVMe Identify Namespace for LBA format[%d]:\n", lba_index); + + printf("nlbaf : %d\n", ns->nlbaf); + if (!cap_only) { + printf("flbas : %#x\n", ns->flbas); + if (human) + stdout_id_ns_flbas(ns->flbas); + } else + in_use = ""; + + printf("mc : %#x\n", ns->mc); + if (human) + stdout_id_ns_mc(ns->mc); + printf("dpc : %#x\n", ns->dpc); + if (human) + stdout_id_ns_dpc(ns->dpc); + if (!cap_only) { + printf("dps : %#x\n", ns->dps); + if (human) + stdout_id_ns_dps(ns->dps); + printf("nmic : %#x\n", ns->nmic); + if (human) + stdout_id_ns_nmic(ns->nmic); + printf("rescap : %#x\n", ns->rescap); + if (human) + stdout_id_ns_rescap(ns->rescap); + printf("fpi : %#x\n", ns->fpi); + if (human) + stdout_id_ns_fpi(ns->fpi); + printf("dlfeat : %d\n", ns->dlfeat); + if (human) + stdout_id_ns_dlfeat(ns->dlfeat); + printf("nawun : %d\n", le16_to_cpu(ns->nawun)); + printf("nawupf : %d\n", le16_to_cpu(ns->nawupf)); + printf("nacwu : %d\n", le16_to_cpu(ns->nacwu)); + printf("nabsn : %d\n", le16_to_cpu(ns->nabsn)); + printf("nabo : %d\n", le16_to_cpu(ns->nabo)); + printf("nabspf : %d\n", le16_to_cpu(ns->nabspf)); + printf("noiob : %d\n", le16_to_cpu(ns->noiob)); + printf("nvmcap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(ns->nvmcap))); + if (ns->nsfeat & 0x10) { + printf("npwg : %u\n", le16_to_cpu(ns->npwg)); + printf("npwa : %u\n", le16_to_cpu(ns->npwa)); + printf("npdg : %u\n", le16_to_cpu(ns->npdg)); + printf("npda : %u\n", le16_to_cpu(ns->npda)); + printf("nows : %u\n", le16_to_cpu(ns->nows)); + } + printf("mssrl : %u\n", le16_to_cpu(ns->mssrl)); + printf("mcl : %u\n", le32_to_cpu(ns->mcl)); + printf("msrc : %u\n", ns->msrc); + } + printf("nulbaf : %u\n", ns->nulbaf); + if (!cap_only) { + printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); + printf("nsattr : %u\n", ns->nsattr); + printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid)); + printf("endgid : %d\n", le16_to_cpu(ns->endgid)); + + printf("nguid : "); + for (i = 0; i < 16; i++) + printf("%02x", ns->nguid[i]); + printf("\n"); + + printf("eui64 : "); + for (i = 0; i < 8; i++) + printf("%02x", ns->eui64[i]); + printf("\n"); + } + + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas); + for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) { + if (human) + printf("LBA Format %2d : Metadata Size: %-3d bytes - " + "Data Size: %-2d bytes - Relative Performance: %#x %s %s\n", + i, le16_to_cpu(ns->lbaf[i].ms), + 1 << ns->lbaf[i].ds, ns->lbaf[i].rp, + ns->lbaf[i].rp == 3 ? "Degraded" : + ns->lbaf[i].rp == 2 ? "Good" : + ns->lbaf[i].rp == 1 ? "Better" : "Best", + i == flbas ? in_use : ""); + else + printf("lbaf %2d : ms:%-3d lbads:%-2d rp:%#x %s\n", i, + le16_to_cpu(ns->lbaf[i].ms), ns->lbaf[i].ds, + ns->lbaf[i].rp, i == flbas ? in_use : ""); + } + + if (vs && !cap_only) { + printf("vs[]:\n"); + d(ns->vs, sizeof(ns->vs), 16, 1); + } +} + +static void stdout_cmd_set_independent_id_ns_nsfeat(__u8 nsfeat) +{ + __u8 rsvd6 = (nsfeat & 0xE0) >> 6; + __u8 vwcnp = (nsfeat & 0x20) >> 5; + __u8 rmedia = (nsfeat & 0x10) >> 4; + __u8 uidreuse = (nsfeat & 0x8) >> 3; + __u8 rsvd0 = (nsfeat & 0x7); + + if (rsvd6) + printf(" [7:6] : %#x\tReserved\n", rsvd6); + printf(" [5:5] : %#x\tVolatile Write Cache is %sPresent\n", + vwcnp, vwcnp ? "" : "Not "); + printf(" [4:4] : %#x\tNamespace %sstore data on rotational media\n", + rmedia, rmedia ? "" : "does not "); + printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n", + uidreuse, uidreuse ? "Never " : ""); + if (rsvd0) + printf(" [2:0] : %#x\tReserved\n", rsvd0); + printf("\n"); +} + +static void stdout_cmd_set_independent_id_ns_nstat(__u8 nstat) +{ + __u8 rsvd1 = (nstat & 0xfe) >> 1; + __u8 nrdy = nstat & 0x1; + + if (rsvd1) + printf(" [7:1] : %#x\tReserved\n", rsvd1); + printf(" [0:0] : %#x\tName space is %sready\n", + nrdy, nrdy ? "" : "not "); + printf("\n"); +} + +static void stdout_cmd_set_independent_id_ns(struct nvme_id_independent_id_ns *ns, + unsigned int nsid) +{ + int human = stdout_print_ops.flags & VERBOSE; + + printf("NVME Identify Command Set Independent Namespace %d:\n", nsid); + printf("nsfeat : %#x\n", ns->nsfeat); + if (human) + stdout_cmd_set_independent_id_ns_nsfeat(ns->nsfeat); + printf("nmic : %#x\n", ns->nmic); + if (human) + stdout_id_ns_nmic(ns->nmic); + printf("rescap : %#x\n", ns->rescap); + if (human) + stdout_id_ns_rescap(ns->rescap); + printf("fpi : %#x\n", ns->fpi); + if (human) + stdout_id_ns_fpi(ns->fpi); + printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); + printf("nsattr : %u\n", ns->nsattr); + if (human) + stdout_id_ns_nsattr(ns->nsattr); + printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid)); + printf("endgid : %d\n", le16_to_cpu(ns->endgid)); + + printf("nstat : %#x\n", ns->nstat); + if (human) + stdout_cmd_set_independent_id_ns_nstat(ns->nstat); +} + +static void stdout_id_ns_descs(void *data, unsigned int nsid) +{ + int pos, len = 0; + int i, verbose = stdout_print_ops.flags & VERBOSE; + __u8 uuid[NVME_UUID_LEN]; + char uuid_str[NVME_UUID_LEN_STRING]; + __u8 eui64[8]; + __u8 nguid[16]; + __u8 csi; + + printf("NVME Namespace Identification Descriptors NS %d:\n", nsid); + for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) { + struct nvme_ns_id_desc *cur = data + pos; + + if (cur->nidl == 0) + break; + + if (verbose) { + printf("loc : %d\n", pos); + printf("nidt : %d\n", (int)cur->nidt); + printf("nidl : %d\n", (int)cur->nidl); + } + + switch (cur->nidt) { + case NVME_NIDT_EUI64: + memcpy(eui64, data + pos + sizeof(*cur), sizeof(eui64)); + if (verbose) + printf("type : eui64\n"); + 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)); + if (verbose) + printf("type : nguid\n"); + printf("nguid : "); + for (i = 0; i < 16; i++) + printf("%02x", nguid[i]); + printf("\n"); + len = sizeof(nguid); + break; + case NVME_NIDT_UUID: + memcpy(uuid, data + pos + sizeof(*cur), 16); + nvme_uuid_to_string(uuid, uuid_str); + if (verbose) + printf("type : uuid\n"); + printf("uuid : %s\n", uuid_str); + len = sizeof(uuid); + break; + case NVME_NIDT_CSI: + memcpy(&csi, data + pos + sizeof(*cur), 1); + if (verbose) + printf("type : csi\n"); + printf("csi : %#x\n", csi); + len += sizeof(csi); + break; + default: + /* Skip unknown types */ + len = cur->nidl; + break; + } + + len += sizeof(*cur); + } +} + +static void print_psd_workload(__u8 apw) +{ + switch (apw & 0x7) { + case NVME_PSD_WORKLOAD_NP: + /* Unknown or not provided */ + printf("-"); + break; + case 1: + /* Extended idle period with burst of random write */ + printf("1MiB 32 RW, 30s idle"); + break; + case 2: + /* Heavy sequential writes */ + printf("80K 128KiB SW"); + break; + default: + printf("reserved"); + break; + } +} + +static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale) +{ + __u16 power = le16_to_cpu(ctr_power); + + switch (scale & 0x3) { + case NVME_PSD_PS_NOT_REPORTED: + /* Not reported for this power state */ + printf("-"); + break; + case NVME_PSD_PS_100_MICRO_WATT: + /* Units of 0.0001W */ + printf("%01u.%04uW", power / 10000, power % 10000); + break; + case NVME_PSD_PS_10_MILLI_WATT: + /* Units of 0.01W */ + printf("%01u.%02uW", power / 100, power % 100); + break; + default: + printf("reserved"); + break; + } +} + +static void stdout_id_ctrl_power(struct nvme_id_ctrl *ctrl) +{ + int i; + + for (i = 0; i <= ctrl->npss; i++) { + __u16 max_power = le16_to_cpu(ctrl->psd[i].mp); + + printf("ps %4d : mp:", i); + + if (ctrl->psd[i].flags & NVME_PSD_FLAGS_MXPS) + printf("%01u.%04uW ", max_power / 10000, max_power % 10000); + else + printf("%01u.%02uW ", max_power / 100, max_power % 100); + + if (ctrl->psd[i].flags & NVME_PSD_FLAGS_NOPS) + printf("non-"); + + printf("operational enlat:%d exlat:%d rrt:%d rrl:%d\n" + " rwt:%d rwl:%d idle_power:", + le32_to_cpu(ctrl->psd[i].enlat), + le32_to_cpu(ctrl->psd[i].exlat), + ctrl->psd[i].rrt, ctrl->psd[i].rrl, + ctrl->psd[i].rwt, ctrl->psd[i].rwl); + print_ps_power_and_scale(ctrl->psd[i].idlp, + nvme_psd_power_scale(ctrl->psd[i].ips)); + printf(" active_power:"); + print_ps_power_and_scale(ctrl->psd[i].actp, + nvme_psd_power_scale(ctrl->psd[i].apws)); + printf("\n active_power_workload:"); + print_psd_workload(ctrl->psd[i].apws); + printf("\n"); + + } +} + +static void stdout_id_ctrl(struct nvme_id_ctrl *ctrl, + void (*vendor_show)(__u8 *vs, struct json_object *root)) +{ + bool human = stdout_print_ops.flags & VERBOSE, vs = stdout_print_ops.flags & VS; + + printf("NVME Identify Controller:\n"); + printf("vid : %#x\n", le16_to_cpu(ctrl->vid)); + printf("ssvid : %#x\n", le16_to_cpu(ctrl->ssvid)); + printf("sn : %-.*s\n", (int)sizeof(ctrl->sn), ctrl->sn); + printf("mn : %-.*s\n", (int)sizeof(ctrl->mn), ctrl->mn); + printf("fr : %-.*s\n", (int)sizeof(ctrl->fr), ctrl->fr); + printf("rab : %d\n", ctrl->rab); + printf("ieee : %02x%02x%02x\n", + ctrl->ieee[2], ctrl->ieee[1], ctrl->ieee[0]); + printf("cmic : %#x\n", ctrl->cmic); + if (human) + stdout_id_ctrl_cmic(ctrl->cmic); + printf("mdts : %d\n", ctrl->mdts); + printf("cntlid : %#x\n", le16_to_cpu(ctrl->cntlid)); + printf("ver : %#x\n", le32_to_cpu(ctrl->ver)); + printf("rtd3r : %#x\n", le32_to_cpu(ctrl->rtd3r)); + printf("rtd3e : %#x\n", le32_to_cpu(ctrl->rtd3e)); + printf("oaes : %#x\n", le32_to_cpu(ctrl->oaes)); + if (human) + stdout_id_ctrl_oaes(ctrl->oaes); + printf("ctratt : %#x\n", le32_to_cpu(ctrl->ctratt)); + if (human) + stdout_id_ctrl_ctratt(ctrl->ctratt); + printf("rrls : %#x\n", le16_to_cpu(ctrl->rrls)); + printf("cntrltype : %d\n", ctrl->cntrltype); + if (human) + stdout_id_ctrl_cntrltype(ctrl->cntrltype); + printf("fguid : %s\n", util_uuid_to_string(ctrl->fguid)); + printf("crdt1 : %u\n", le16_to_cpu(ctrl->crdt1)); + printf("crdt2 : %u\n", le16_to_cpu(ctrl->crdt2)); + printf("crdt3 : %u\n", le16_to_cpu(ctrl->crdt3)); + printf("nvmsr : %u\n", ctrl->nvmsr); + if (human) + stdout_id_ctrl_nvmsr(ctrl->nvmsr); + printf("vwci : %u\n", ctrl->vwci); + if (human) + stdout_id_ctrl_vwci(ctrl->vwci); + printf("mec : %u\n", ctrl->mec); + if (human) + stdout_id_ctrl_mec(ctrl->mec); + + printf("oacs : %#x\n", le16_to_cpu(ctrl->oacs)); + if (human) + stdout_id_ctrl_oacs(ctrl->oacs); + printf("acl : %d\n", ctrl->acl); + printf("aerl : %d\n", ctrl->aerl); + printf("frmw : %#x\n", ctrl->frmw); + if (human) + stdout_id_ctrl_frmw(ctrl->frmw); + printf("lpa : %#x\n", ctrl->lpa); + if (human) + stdout_id_ctrl_lpa(ctrl->lpa); + printf("elpe : %d\n", ctrl->elpe); + if (human) + stdout_id_ctrl_elpe(ctrl->elpe); + printf("npss : %d\n", ctrl->npss); + if (human) + stdout_id_ctrl_npss(ctrl->npss); + printf("avscc : %#x\n", ctrl->avscc); + if (human) + stdout_id_ctrl_avscc(ctrl->avscc); + printf("apsta : %#x\n", ctrl->apsta); + if (human) + stdout_id_ctrl_apsta(ctrl->apsta); + printf("wctemp : %d\n", le16_to_cpu(ctrl->wctemp)); + if (human) + stdout_id_ctrl_wctemp(ctrl->wctemp); + printf("cctemp : %d\n", le16_to_cpu(ctrl->cctemp)); + if (human) + stdout_id_ctrl_cctemp(ctrl->cctemp); + printf("mtfa : %d\n", le16_to_cpu(ctrl->mtfa)); + printf("hmpre : %u\n", le32_to_cpu(ctrl->hmpre)); + printf("hmmin : %u\n", le32_to_cpu(ctrl->hmmin)); + printf("tnvmcap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(ctrl->tnvmcap))); + if (human) + stdout_id_ctrl_tnvmcap(ctrl->tnvmcap); + printf("unvmcap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(ctrl->unvmcap))); + if (human) + stdout_id_ctrl_unvmcap(ctrl->unvmcap); + printf("rpmbs : %#x\n", le32_to_cpu(ctrl->rpmbs)); + if (human) + stdout_id_ctrl_rpmbs(ctrl->rpmbs); + printf("edstt : %d\n", le16_to_cpu(ctrl->edstt)); + printf("dsto : %d\n", ctrl->dsto); + printf("fwug : %d\n", ctrl->fwug); + printf("kas : %d\n", le16_to_cpu(ctrl->kas)); + printf("hctma : %#x\n", le16_to_cpu(ctrl->hctma)); + if (human) + stdout_id_ctrl_hctma(ctrl->hctma); + printf("mntmt : %d\n", le16_to_cpu(ctrl->mntmt)); + if (human) + stdout_id_ctrl_mntmt(ctrl->mntmt); + printf("mxtmt : %d\n", le16_to_cpu(ctrl->mxtmt)); + if (human) + stdout_id_ctrl_mxtmt(ctrl->mxtmt); + printf("sanicap : %#x\n", le32_to_cpu(ctrl->sanicap)); + if (human) + stdout_id_ctrl_sanicap(ctrl->sanicap); + printf("hmminds : %u\n", le32_to_cpu(ctrl->hmminds)); + printf("hmmaxd : %d\n", le16_to_cpu(ctrl->hmmaxd)); + printf("nsetidmax : %d\n", le16_to_cpu(ctrl->nsetidmax)); + printf("endgidmax : %d\n", le16_to_cpu(ctrl->endgidmax)); + printf("anatt : %d\n", ctrl->anatt); + printf("anacap : %d\n", ctrl->anacap); + if (human) + stdout_id_ctrl_anacap(ctrl->anacap); + printf("anagrpmax : %u\n", ctrl->anagrpmax); + printf("nanagrpid : %u\n", le32_to_cpu(ctrl->nanagrpid)); + printf("pels : %u\n", le32_to_cpu(ctrl->pels)); + printf("domainid : %d\n", le16_to_cpu(ctrl->domainid)); + printf("megcap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(ctrl->megcap))); + printf("sqes : %#x\n", ctrl->sqes); + if (human) + stdout_id_ctrl_sqes(ctrl->sqes); + printf("cqes : %#x\n", ctrl->cqes); + if (human) + stdout_id_ctrl_cqes(ctrl->cqes); + printf("maxcmd : %d\n", le16_to_cpu(ctrl->maxcmd)); + printf("nn : %u\n", le32_to_cpu(ctrl->nn)); + printf("oncs : %#x\n", le16_to_cpu(ctrl->oncs)); + if (human) + stdout_id_ctrl_oncs(ctrl->oncs); + printf("fuses : %#x\n", le16_to_cpu(ctrl->fuses)); + if (human) + stdout_id_ctrl_fuses(ctrl->fuses); + printf("fna : %#x\n", ctrl->fna); + if (human) + stdout_id_ctrl_fna(ctrl->fna); + printf("vwc : %#x\n", ctrl->vwc); + if (human) + stdout_id_ctrl_vwc(ctrl->vwc); + printf("awun : %d\n", le16_to_cpu(ctrl->awun)); + printf("awupf : %d\n", le16_to_cpu(ctrl->awupf)); + printf("icsvscc : %d\n", ctrl->icsvscc); + if (human) + stdout_id_ctrl_icsvscc(ctrl->icsvscc); + printf("nwpc : %d\n", ctrl->nwpc); + if (human) + stdout_id_ctrl_nwpc(ctrl->nwpc); + printf("acwu : %d\n", le16_to_cpu(ctrl->acwu)); + printf("ocfs : %#x\n", le16_to_cpu(ctrl->ocfs)); + if (human) + stdout_id_ctrl_ocfs(ctrl->ocfs); + printf("sgls : %#x\n", le32_to_cpu(ctrl->sgls)); + if (human) + stdout_id_ctrl_sgls(ctrl->sgls); + printf("mnan : %u\n", le32_to_cpu(ctrl->mnan)); + printf("maxdna : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(ctrl->maxdna))); + printf("maxcna : %u\n", le32_to_cpu(ctrl->maxcna)); + printf("oaqd : %u\n", le32_to_cpu(ctrl->oaqd)); + printf("subnqn : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn); + printf("ioccsz : %u\n", le32_to_cpu(ctrl->ioccsz)); + printf("iorcsz : %u\n", le32_to_cpu(ctrl->iorcsz)); + printf("icdoff : %d\n", le16_to_cpu(ctrl->icdoff)); + printf("fcatt : %#x\n", ctrl->fcatt); + if (human) + stdout_id_ctrl_fcatt(ctrl->fcatt); + printf("msdbd : %d\n", ctrl->msdbd); + printf("ofcs : %d\n", le16_to_cpu(ctrl->ofcs)); + if (human) + stdout_id_ctrl_ofcs(ctrl->ofcs); + + stdout_id_ctrl_power(ctrl); + if (vendor_show) + vendor_show(ctrl->vs, NULL); + else if (vs) { + printf("vs[]:\n"); + d(ctrl->vs, sizeof(ctrl->vs), 16, 1); + } +} + +static void stdout_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm) +{ + printf("NVMe Identify Controller NVM:\n"); + printf("vsl : %u\n", ctrl_nvm->vsl); + printf("wzsl : %u\n", ctrl_nvm->wzsl); + printf("wusl : %u\n", ctrl_nvm->wusl); + printf("dmrl : %u\n", ctrl_nvm->dmrl); + printf("dmrsl : %u\n", le32_to_cpu(ctrl_nvm->dmrsl)); + printf("dmsl : %"PRIu64"\n", le64_to_cpu(ctrl_nvm->dmsl)); +} + +static void stdout_nvm_id_ns_pic(__u8 pic) +{ + __u8 rsvd = (pic & 0xF8) >> 3; + __u8 stcrs = (pic & 0x3) >> 2; + __u8 pic_16bpistm = (pic & 0x2) >> 1; + __u8 pic_16bpists = pic & 0x1; + + if (rsvd) + printf(" [7:3] : %#x\tReserved\n", rsvd); + printf(" [2:2] : %#x\tStorage Tag Check Read Support\n", stcrs); + printf(" [1:1] : %#x\t16b Guard Protection Information Storage Tag Mask\n", + pic_16bpistm); + printf(" [0:0] : %#x\t16b Guard Protection Information Storage Tag Support\n", + pic_16bpists); + printf("\n"); +} + +static void stdout_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, + struct nvme_id_ns *ns, unsigned int lba_index, + bool cap_only) +{ + int i, verbose = stdout_print_ops.flags & VERBOSE; + __u32 elbaf; + int pif, sts; + char *in_use = "(in use)"; + + if (!cap_only) { + printf("NVMe NVM Identify Namespace %d:\n", nsid); + printf("lbstm : %#"PRIx64"\n", le64_to_cpu(nvm_ns->lbstm)); + } else { + printf("NVMe NVM Identify Namespace for LBA format[%d]:\n", lba_index); + in_use = ""; + } + printf("pic : %#x\n", nvm_ns->pic); + if (verbose) + stdout_nvm_id_ns_pic(nvm_ns->pic); + + for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) { + elbaf = le32_to_cpu(nvm_ns->elbaf[i]); + pif = (elbaf >> 7) & 0x3; + sts = elbaf & 0x7f; + if (verbose) + printf("Extended LBA Format %2d : Protection Information Format: " + "%s(%d) - Storage Tag Size (MSB): %-2d %s\n", + i, pif == 3 ? "Reserved" : + pif == 2 ? "64b Guard" : + pif == 1 ? "32b Guard" : "16b Guard", + pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); + else + printf("elbaf %2d : pif:%d sts:%-2d %s\n", i, + pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); + } +} + +static void stdout_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl) +{ + printf("NVMe ZNS Identify Controller:\n"); + printf("zasl : %u\n", ctrl->zasl); +} + +static void show_nvme_id_ns_zoned_zoc(__le16 ns_zoc) +{ + __u16 zoc = le16_to_cpu(ns_zoc); + __u8 rsvd = (zoc & 0xfffc) >> 2; + __u8 ze = (zoc & 0x2) >> 1; + __u8 vzc = zoc & 0x1; + + if (rsvd) + printf(" [15:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\t Zone Active Excursions: %s\n", + ze, ze ? "Yes (Host support required)" : "No"); + printf(" [0:0] : %#x\t Variable Zone Capacity: %s\n", + vzc, vzc ? "Yes (Host support required)" : "No"); + printf("\n"); +} + +static void show_nvme_id_ns_zoned_ozcs(__le16 ns_ozcs) +{ + __u16 ozcs = le16_to_cpu(ns_ozcs); + __u8 rsvd = (ozcs & 0xfffc) >> 2; + __u8 razb = ozcs & 0x1; + __u8 zrwasup = (ozcs & 0x2) >> 1; + + if (rsvd) + printf(" [15:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\t Read Across Zone Boundaries: %s\n", + razb, razb ? "Yes" : "No"); + printf(" [1:1] : %#x\t Zone Random Write Area: %s\n", zrwasup, + zrwasup ? "Yes" : "No"); +} + +static void stdout_zns_id_ns_recommended_limit(__le32 ns_rl, int human, + const char *target_limit) +{ + unsigned int recommended_limit = le32_to_cpu(ns_rl); + + if (!recommended_limit && human) + printf("%s : Not Reported\n", target_limit); + else + printf("%s : %u\n", target_limit, recommended_limit); +} + +static void stdout_zns_id_ns_zrwacap(__u8 zrwacap) +{ + __u8 rsvd = (zrwacap & 0xfe) >> 1; + __u8 expflushsup = zrwacap & 0x1; + + if (rsvd) + printf(" [7:1] : %#x\tReserved\n", rsvd); + printf(" [0:0] : %#x\t Explicit ZRWA Flush Operations: %s\n", + expflushsup, expflushsup ? "Yes" : "No"); +} + +static void stdout_zns_id_ns(struct nvme_zns_id_ns *ns, + struct nvme_id_ns *id_ns) +{ + int human = stdout_print_ops.flags & VERBOSE, vs = stdout_print_ops.flags & VS; + uint8_t lbaf; + int i; + + nvme_id_ns_flbas_to_lbaf_inuse(id_ns->flbas, &lbaf); + + printf("ZNS Command Set Identify Namespace:\n"); + + if (human) { + printf("zoc : %u\tZone Operation Characteristics\n", le16_to_cpu(ns->zoc)); + show_nvme_id_ns_zoned_zoc(ns->zoc); + } else { + printf("zoc : %u\n", le16_to_cpu(ns->zoc)); + } + + if (human) { + printf("ozcs : %u\tOptional Zoned Command Support\n", le16_to_cpu(ns->ozcs)); + show_nvme_id_ns_zoned_ozcs(ns->ozcs); + } else { + printf("ozcs : %u\n", le16_to_cpu(ns->ozcs)); + } + + if (human) { + if (ns->mar == 0xffffffff) + printf("mar : No Active Resource Limit\n"); + else + printf("mar : %u\tActive Resources\n", le32_to_cpu(ns->mar) + 1); + } else { + printf("mar : %#x\n", le32_to_cpu(ns->mar)); + } + + if (human) { + if (ns->mor == 0xffffffff) + printf("mor : No Open Resource Limit\n"); + else + printf("mor : %u\tOpen Resources\n", le32_to_cpu(ns->mor) + 1); + } else { + printf("mor : %#x\n", le32_to_cpu(ns->mor)); + } + + stdout_zns_id_ns_recommended_limit(ns->rrl, human, "rrl "); + stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl "); + stdout_zns_id_ns_recommended_limit(ns->rrl1, human, "rrl1"); + stdout_zns_id_ns_recommended_limit(ns->rrl2, human, "rrl2"); + stdout_zns_id_ns_recommended_limit(ns->rrl3, human, "rrl3"); + stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl1"); + stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl2"); + stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl3"); + + printf("numzrwa : %#x\n", le32_to_cpu(ns->numzrwa)); + printf("zrwafg : %u\n", le16_to_cpu(ns->zrwafg)); + printf("zrwasz : %u\n", le16_to_cpu(ns->zrwasz)); + if (human) { + printf("zrwacap : %u\tZone Random Write Area Capability\n", ns->zrwacap); + stdout_zns_id_ns_zrwacap(ns->zrwacap); + } else { + printf("zrwacap : %u\n", ns->zrwacap); + } + + for (i = 0; i <= id_ns->nlbaf; i++) { + if (human) + printf("LBA Format Extension %2d : Zone Size: 0x%"PRIx64" LBAs - " + "Zone Descriptor Extension Size: %-1d bytes%s\n", + i, le64_to_cpu(ns->lbafe[i].zsze), ns->lbafe[i].zdes << 6, + i == lbaf ? " (in use)" : ""); + else + printf("lbafe %2d: zsze:0x%"PRIx64" zdes:%u%s\n", i, + (uint64_t)le64_to_cpu(ns->lbafe[i].zsze), + ns->lbafe[i].zdes, i == lbaf ? " (in use)" : ""); + } + + if (vs) { + printf("vs[] :\n"); + d(ns->vs, sizeof(ns->vs), 16, 1); + } +} + +static void stdout_list_ns(struct nvme_ns_list *ns_list) +{ + int i; + + for (i = 0; i < 1024; i++) { + if (ns_list->ns[i]) + printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list->ns[i])); + } +} + +static void stdout_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list) +{ + printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(nr_zones)); +} + +static void stdout_zns_changed(struct nvme_zns_changed_zone_log *log) +{ + uint16_t nrzid; + int i; + + nrzid = le16_to_cpu(log->nrzid); + printf("NVMe Changed Zone List:\n"); + + if (nrzid == 0xFFFF) { + printf("Too many zones have changed to fit into the log. Use report zones for changes.\n"); + return; + } + + printf("nrzid: %u\n", nrzid); + for (i = 0; i < nrzid; i++) + printf("zid %03d: %"PRIu64"\n", i, (uint64_t)le64_to_cpu(log->zid[i])); +} + +static void stdout_zns_report_zone_attributes(__u8 za, __u8 zai) +{ + const char * const recommended_limit[4] = {"", "1", "2", "3"}; + + printf("Attrs: Zone Descriptor Extension is %sVaild\n", + za & NVME_ZNS_ZA_ZDEV ? "" : "Not "); + + if (za & NVME_ZNS_ZA_RZR) + printf(" Reset Zone Recommended with Reset Recommended Limit%s\n", + recommended_limit[(zai&0xd)>>2]); + + if (za & NVME_ZNS_ZA_FZR) + printf(" Finish Zone Recommended with Finish Recommended Limit%s\n", + recommended_limit[zai&0x3]); + + if (za & NVME_ZNS_ZA_ZFC) + printf(" Zone Finished by Controller\n"); +} + +static void stdout_zns_report_zones(void *report, __u32 descs, + __u8 ext_size, __u32 report_size, + struct json_object *zone_list) +{ + struct nvme_zone_report *r = report; + struct nvme_zns_desc *desc; + int i, verbose = stdout_print_ops.flags & VERBOSE; + __u64 nr_zones = le64_to_cpu(r->nr_zones); + + if (nr_zones < descs) + descs = nr_zones; + + for (i = 0; i < descs; i++) { + desc = (struct nvme_zns_desc *) + (report + sizeof(*r) + i * (sizeof(*desc) + ext_size)); + if (verbose) { + printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %-12s Type: %-14s\n", + (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), + (uint64_t)le64_to_cpu(desc->zcap), nvme_zone_state_to_string(desc->zs >> 4), + nvme_zone_type_to_string(desc->zt)); + stdout_zns_report_zone_attributes(desc->za, desc->zai); + } else { + printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %#-4x Type: %#-4x Attrs: %#-4x AttrsInfo: %#-4x\n", + (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), + (uint64_t)le64_to_cpu(desc->zcap), desc->zs, desc->zt, + desc->za, desc->zai); + } + + if (ext_size && (desc->za & NVME_ZNS_ZA_ZDEV)) { + printf("Extension Data: "); + d((unsigned char *)desc + sizeof(*desc), ext_size, 16, 1); + printf("..\n"); + } + } +} + +static void stdout_list_ctrl(struct nvme_ctrl_list *ctrl_list) +{ + __u16 num = le16_to_cpu(ctrl_list->num); + int i; + + printf("num of ctrls present: %u\n", num); + for (i = 0; i < min(num, 2047); i++) + printf("[%4u]:%#x\n", i, le16_to_cpu(ctrl_list->identifier[i])); +} + +static void stdout_id_nvmset(struct nvme_id_nvmset_list *nvmset, + unsigned int nvmset_id) +{ + int i; + + printf("NVME Identify NVM Set List %d:\n", nvmset_id); + printf("nid : %d\n", nvmset->nid); + printf(".................\n"); + for (i = 0; i < nvmset->nid; i++) { + printf(" NVM Set Attribute Entry[%2d]\n", i); + printf(".................\n"); + printf("nvmset_id : %d\n", + le16_to_cpu(nvmset->ent[i].endgid)); + printf("endurance_group_id : %d\n", + le16_to_cpu(nvmset->ent[i].endgid)); + printf("random_4k_read_typical : %u\n", + le32_to_cpu(nvmset->ent[i].rr4kt)); + printf("optimal_write_size : %u\n", + le32_to_cpu(nvmset->ent[i].ows)); + printf("total_nvmset_cap : %s\n", + uint128_t_to_l10n_string( + le128_to_cpu(nvmset->ent[i].tnvmsetcap))); + printf("unalloc_nvmset_cap : %s\n", + uint128_t_to_l10n_string( + le128_to_cpu(nvmset->ent[i].unvmsetcap))); + printf(".................\n"); + } +} + +static void stdout_primary_ctrl_caps_crt(__u8 crt) +{ + __u8 rsvd = (crt & 0xFC) >> 2; + __u8 vi = (crt & 0x2) >> 1; + __u8 vq = crt & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] %#x\tVI Resources are %ssupported\n", vi, vi ? "" : "not "); + printf(" [0:0] %#x\tVQ Resources are %ssupported\n", vq, vq ? "" : "not "); +} + +static void stdout_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps) +{ + int human = stdout_print_ops.flags & VERBOSE; + + printf("NVME Identify Primary Controller Capabilities:\n"); + printf("cntlid : %#x\n", le16_to_cpu(caps->cntlid)); + printf("portid : %#x\n", le16_to_cpu(caps->portid)); + printf("crt : %#x\n", caps->crt); + if (human) + stdout_primary_ctrl_caps_crt(caps->crt); + printf("vqfrt : %u\n", le32_to_cpu(caps->vqfrt)); + printf("vqrfa : %u\n", le32_to_cpu(caps->vqrfa)); + printf("vqrfap : %d\n", le16_to_cpu(caps->vqrfap)); + printf("vqprt : %d\n", le16_to_cpu(caps->vqprt)); + printf("vqfrsm : %d\n", le16_to_cpu(caps->vqfrsm)); + printf("vqgran : %d\n", le16_to_cpu(caps->vqgran)); + printf("vifrt : %u\n", le32_to_cpu(caps->vifrt)); + printf("virfa : %u\n", le32_to_cpu(caps->virfa)); + printf("virfap : %d\n", le16_to_cpu(caps->virfap)); + printf("viprt : %d\n", le16_to_cpu(caps->viprt)); + printf("vifrsm : %d\n", le16_to_cpu(caps->vifrsm)); + printf("vigran : %d\n", le16_to_cpu(caps->vigran)); +} + +static void stdout_list_secondary_ctrl(const struct nvme_secondary_ctrl_list *sc_list, + __u32 count) +{ + const struct nvme_secondary_ctrl *sc_entry = + &sc_list->sc_entry[0]; + static const char * const state_desc[] = { "Offline", "Online" }; + + __u16 num = sc_list->num; + __u32 entries = min(num, count); + int i; + + printf("Identify Secondary Controller List:\n"); + printf(" NUMID : Number of Identifiers : %d\n", num); + + for (i = 0; i < entries; i++) { + printf(" SCEntry[%-3d]:\n", i); + printf("................\n"); + printf(" SCID : Secondary Controller Identifier : 0x%.04x\n", + le16_to_cpu(sc_entry[i].scid)); + printf(" PCID : Primary Controller Identifier : 0x%.04x\n", + le16_to_cpu(sc_entry[i].pcid)); + printf(" SCS : Secondary Controller State : 0x%.04x (%s)\n", + sc_entry[i].scs, + state_desc[sc_entry[i].scs & 0x1]); + printf(" VFN : Virtual Function Number : 0x%.04x\n", + le16_to_cpu(sc_entry[i].vfn)); + printf(" NVQ : Num VQ Flex Resources Assigned : 0x%.04x\n", + le16_to_cpu(sc_entry[i].nvq)); + printf(" NVI : Num VI Flex Resources Assigned : 0x%.04x\n", + le16_to_cpu(sc_entry[i].nvi)); + } +} + +static void stdout_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist) +{ + int i; + + printf("Identify Namespace Granularity List:\n"); + printf(" ATTR : Namespace Granularity Attributes: 0x%x\n", + glist->attributes); + printf(" NUMD : Number of Descriptors : %d\n", + glist->num_descriptors); + + /* Number of Descriptors is a 0's based value */ + for (i = 0; i <= glist->num_descriptors; i++) { + printf("\n Entry[%2d] :\n", i); + printf("................\n"); + printf(" NSG : Namespace Size Granularity : 0x%"PRIx64"\n", + le64_to_cpu(glist->entry[i].nszegran)); + printf(" NCG : Namespace Capacity Granularity : 0x%"PRIx64"\n", + le64_to_cpu(glist->entry[i].ncapgran)); + } +} + +static void stdout_id_uuid_list(const struct nvme_id_uuid_list *uuid_list) +{ + int i, human = stdout_print_ops.flags & VERBOSE; + + printf("NVME Identify UUID:\n"); + + for (i = 0; i < NVME_ID_UUID_LIST_MAX; i++) { + __u8 uuid[NVME_UUID_LEN]; + char *association = ""; + uint8_t identifier_association = uuid_list->entry[i].header & 0x3; + /* The list is terminated by a zero UUID value */ + if (memcmp(uuid_list->entry[i].uuid, zero_uuid, NVME_UUID_LEN) == 0) + break; + memcpy(&uuid, uuid_list->entry[i].uuid, NVME_UUID_LEN); + if (human) { + switch (identifier_association) { + case 0x0: + association = "No association reported"; + break; + case 0x1: + association = "associated with PCI Vendor ID"; + break; + case 0x2: + association = "associated with PCI Subsystem Vendor ID"; + break; + default: + association = "Reserved"; + break; + } + } + printf(" Entry[%3d]\n", i+1); + printf(".................\n"); + printf("association : 0x%x %s\n", identifier_association, association); + printf("UUID : %s", util_uuid_to_string(uuid)); + if (memcmp(uuid_list->entry[i].uuid, invalid_uuid, + sizeof(zero_uuid)) == 0) + printf(" (Invalid UUID)"); + printf("\n.................\n"); + } +} + +static void stdout_id_domain_list(struct nvme_id_domain_list *id_dom) +{ + int i; + + printf("Number of Domain Entries: %u\n", id_dom->num); + for (i = 0; i < id_dom->num; i++) { + printf("Domain Id for Attr Entry[%u]: %u\n", i, + le16_to_cpu(id_dom->domain_attr[i].dom_id)); + printf("Domain Capacity for Attr Entry[%u]: %s\n", i, + uint128_t_to_l10n_string( + le128_to_cpu(id_dom->domain_attr[i].dom_cap))); + printf("Unallocated Domain Capacity for Attr Entry[%u]: %s\n", i, + uint128_t_to_l10n_string( + le128_to_cpu(id_dom->domain_attr[i].unalloc_dom_cap))); + printf("Max Endurance Group Domain Capacity for Attr Entry[%u]: %s\n", i, + uint128_t_to_l10n_string( + le128_to_cpu(id_dom->domain_attr[i].max_egrp_dom_cap))); + } +} + +static void stdout_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list) +{ + int i; + __u16 num = le16_to_cpu(endgrp_list->num); + + printf("num of endurance group ids: %u\n", num); + for (i = 0; i < min(num, 2047); i++) + printf("[%4u]:%#x\n", i, le16_to_cpu(endgrp_list->identifier[i])); +} + +static void stdout_id_iocs(struct nvme_id_iocs *iocs) +{ + __u16 i; + + for (i = 0; i < ARRAY_SIZE(iocs->iocsc); i++) + if (iocs->iocsc[i]) + printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i, + (uint64_t)le64_to_cpu(iocs->iocsc[i])); +} + +static void stdout_error_log(struct nvme_error_log_page *err_log, int entries, + const char *devname) +{ + int i; + + printf("Error Log Entries for device:%s entries:%d\n", devname, + entries); + printf(".................\n"); + for (i = 0; i < entries; i++) { + __u16 status = le16_to_cpu(err_log[i].status_field) >> 0x1; + + printf(" Entry[%2d]\n", i); + printf(".................\n"); + printf("error_count : %"PRIu64"\n", + le64_to_cpu(err_log[i].error_count)); + printf("sqid : %d\n", err_log[i].sqid); + printf("cmdid : %#x\n", err_log[i].cmdid); + printf("status_field : %#x(%s)\n", status, + nvme_status_to_string(status, false)); + printf("phase_tag : %#x\n", + le16_to_cpu(err_log[i].status_field & 0x1)); + printf("parm_err_loc : %#x\n", + err_log[i].parm_error_location); + printf("lba : %#"PRIx64"\n", + le64_to_cpu(err_log[i].lba)); + printf("nsid : %#x\n", err_log[i].nsid); + printf("vs : %d\n", err_log[i].vs); + printf("trtype : %s\n", + nvme_trtype_to_string(err_log[i].trtype)); + printf("csi : %d\n", err_log[i].csi); + printf("opcode : %#x\n", err_log[i].opcode); + printf("cs : %#"PRIx64"\n", + le64_to_cpu(err_log[i].cs)); + printf("trtype_spec_info: %#x\n", err_log[i].trtype_spec_info); + printf("log_page_version: %d\n", err_log[i].log_page_version); + printf(".................\n"); + } +} + +static void stdout_resv_report(struct nvme_resv_status *status, int bytes, + bool eds) +{ + int i, j, regctl, entries; + + regctl = status->regctl[0] | (status->regctl[1] << 8); + + printf("\nNVME Reservation status:\n\n"); + printf("gen : %u\n", le32_to_cpu(status->gen)); + printf("rtype : %d\n", status->rtype); + printf("regctl : %d\n", regctl); + printf("ptpls : %d\n", status->ptpls); + + /* check Extended Data Structure bit */ + if (!eds) { + /* + * if status buffer was too small, don't loop past the end of + * the buffer + */ + entries = (bytes - 24) / 24; + if (entries < regctl) + regctl = entries; + + for (i = 0; i < regctl; i++) { + printf("regctl[%d] :\n", i); + printf(" cntlid : %x\n", + le16_to_cpu(status->regctl_ds[i].cntlid)); + printf(" rcsts : %x\n", + status->regctl_ds[i].rcsts); + printf(" hostid : %"PRIx64"\n", + le64_to_cpu(status->regctl_ds[i].hostid)); + printf(" rkey : %"PRIx64"\n", + le64_to_cpu(status->regctl_ds[i].rkey)); + } + } else { + /* if status buffer was too small, don't loop past the end of the buffer */ + entries = (bytes - 64) / 64; + if (entries < regctl) + regctl = entries; + + for (i = 0; i < regctl; i++) { + printf("regctlext[%d] :\n", i); + printf(" cntlid : %x\n", + le16_to_cpu(status->regctl_eds[i].cntlid)); + printf(" rcsts : %x\n", + status->regctl_eds[i].rcsts); + printf(" rkey : %"PRIx64"\n", + le64_to_cpu(status->regctl_eds[i].rkey)); + printf(" hostid : "); + for (j = 0; j < 16; j++) + printf("%02x", + status->regctl_eds[i].hostid[j]); + printf("\n"); + } + } + printf("\n"); +} + +static void stdout_fw_log(struct nvme_firmware_slot *fw_log, + const char *devname) +{ + int i; + __le64 *frs; + + printf("Firmware Log for device:%s\n", devname); + printf("afi : %#x\n", fw_log->afi); + for (i = 0; i < 7; i++) { + if (fw_log->frs[i][0]) { + frs = (__le64 *)&fw_log->frs[i]; + printf("frs%d : %#016"PRIx64" (%s)\n", i + 1, + le64_to_cpu(*frs), + util_fw_to_string(fw_log->frs[i])); + } + } +} + +static void stdout_changed_ns_list_log(struct nvme_ns_list *log, + const char *devname) +{ + __u32 nsid; + int i; + + if (log->ns[0] != cpu_to_le32(NVME_NSID_ALL)) { + for (i = 0; i < NVME_ID_NS_LIST_MAX; i++) { + nsid = le32_to_cpu(log->ns[i]); + if (nsid == 0) + break; + + printf("[%4u]:%#x\n", i, nsid); + } + } else + printf("more than %d ns changed\n", + NVME_ID_NS_LIST_MAX); +} + +static void stdout_effects_log_human(FILE *stream, __u32 effect) +{ + const char *set = "+"; + const char *clr = "-"; + + fprintf(stream, " CSUPP+"); + fprintf(stream, " LBCC%s", (effect & NVME_CMD_EFFECTS_LBCC) ? set : clr); + fprintf(stream, " NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr); + fprintf(stream, " NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr); + fprintf(stream, " CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr); + fprintf(stream, " USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr); + + if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 0) + fprintf(stream, " No command restriction\n"); + else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 1) + fprintf(stream, " No other command for same namespace\n"); + else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 2) + fprintf(stream, " No other command for any namespace\n"); + else + fprintf(stream, " Reserved CSE\n"); +} + +static void stdout_effects_entry(FILE *stream, int admin, int index, + __le32 entry, unsigned int human) +{ + __u32 effect; + char *format_string; + + format_string = admin ? "ACS%-6d[%-32s] %08x" : "IOCS%-5d[%-32s] %08x"; + + effect = le32_to_cpu(entry); + if (effect & NVME_CMD_EFFECTS_CSUPP) { + fprintf(stream, format_string, index, nvme_cmd_to_string(admin, index), + effect); + if (human) + stdout_effects_log_human(stream, effect); + else + fprintf(stream, "\n"); + } +} + +static void stdout_effects_log_segment(int admin, int a, int b, + struct nvme_cmd_effects_log *effects, + char *header, int human) +{ + FILE *stream; + char *stream_location; + size_t stream_size; + + stream = open_memstream(&stream_location, &stream_size); + if (!stream) { + perror("Failed to open stream"); + return; + } + + for (int i = a; i < b; i++) { + if (admin) + stdout_effects_entry(stream, admin, i, effects->acs[i], human); + else + stdout_effects_entry(stream, admin, i, effects->iocs[i], human); + } + + fclose(stream); + + if (stream_size && header) { + printf("%s\n", header); + fwrite(stream_location, stream_size, 1, stdout); + printf("\n"); + } + + free(stream_location); +} + +static void stdout_effects_log_page(enum nvme_csi csi, + struct nvme_cmd_effects_log *effects) +{ + int human = stdout_print_ops.flags & VERBOSE; + + switch (csi) { + case NVME_CSI_NVM: + printf("NVM Command Set Log Page\n"); + printf("%-.80s\n", dash); + break; + case NVME_CSI_ZNS: + printf("ZNS Command Set Log Page\n"); + printf("%-.80s\n", dash); + break; + default: + printf("Unknown Command Set Log Page\n"); + printf("%-.80s\n", dash); + break; + } + + stdout_effects_log_segment(1, 0, 0xbf, effects, "Admin Commands", human); + stdout_effects_log_segment(1, 0xc0, 0xff, effects, "Vendor Specific Admin Commands", human); + stdout_effects_log_segment(0, 0, 0x80, effects, "I/O Commands", human); + stdout_effects_log_segment(0, 0x80, 0x100, effects, "Vendor Specific I/O Commands", human); +} + +static void stdout_effects_log_pages(struct list_head *list) +{ + nvme_effects_log_node_t *node; + + list_for_each(list, node, node) { + stdout_effects_log_page(node->csi, &node->effects); + } +} + +static void stdout_support_log_human(__u32 support, __u8 lid) +{ + const char *set = "supported"; + const char *clr = "not supported"; + + printf(" LSUPP is %s\n", (support & 0x1) ? set : clr); + printf(" IOS is %s\n", ((support >> 0x1) & 0x1) ? set : clr); + if (lid == NVME_LOG_LID_PERSISTENT_EVENT) { + printf(" Establish Context and Read 512 Bytes of Header is %s\n", + ((support >> 0x16) & 0x1) ? set : clr); + } +} + +static void stdout_supported_log(struct nvme_supported_log_pages *support_log, + const char *devname) +{ + int lid, human = stdout_print_ops.flags & VERBOSE; + __u32 support = 0; + + printf("Support Log Pages Details for %s:\n", devname); + for (lid = 0; lid < 256; lid++) { + support = le32_to_cpu(support_log->lid_support[lid]); + if (support & 0x1) { + printf("LID 0x%x - %s\n", lid, nvme_log_to_string(lid)); + if (human) + stdout_support_log_human(support, lid); + } + } +} + +static void stdout_endurance_log(struct nvme_endurance_group_log *endurance_log, __u16 group_id, + const char *devname) +{ + printf("Endurance Group Log for NVME device:%s Group ID:%x\n", devname, group_id); + printf("critical_warning : %u\n", endurance_log->critical_warning); + printf("endurance_group_features: %u\n", endurance_log->endurance_group_features); + printf("avl_spare : %u\n", endurance_log->avl_spare); + printf("avl_spare_threshold : %u\n", endurance_log->avl_spare_threshold); + printf("percent_used : %u%%\n", endurance_log->percent_used); + printf("domain_identifier : %u\n", endurance_log->domain_identifier); + printf("endurance_estimate : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->endurance_estimate))); + printf("data_units_read : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->data_units_read))); + printf("data_units_written : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->data_units_written))); + printf("media_units_written : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->media_units_written))); + printf("host_read_cmds : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->host_read_cmds))); + printf("host_write_cmds : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->host_write_cmds))); + printf("media_data_integrity_err: %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->media_data_integrity_err))); + printf("num_err_info_log_entries: %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->num_err_info_log_entries))); + printf("total_end_grp_cap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->total_end_grp_cap))); + printf("unalloc_end_grp_cap : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(endurance_log->unalloc_end_grp_cap))); +} + +static void stdout_smart_log(struct nvme_smart_log *smart, unsigned int nsid, + const char *devname) +{ + __u16 temperature = smart->temperature[1] << 8 | smart->temperature[0]; + int i; + bool human = stdout_print_ops.flags & VERBOSE; + + printf("Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid); + printf("critical_warning : %#x\n", + smart->critical_warning); + + if (human) { + printf(" Available Spare[0] : %d\n", smart->critical_warning & 0x01); + printf(" Temp. Threshold[1] : %d\n", (smart->critical_warning & 0x02) >> 1); + printf(" NVM subsystem Reliability[2] : %d\n", (smart->critical_warning & 0x04) >> 2); + printf(" Read-only[3] : %d\n", (smart->critical_warning & 0x08) >> 3); + printf(" Volatile mem. backup failed[4] : %d\n", (smart->critical_warning & 0x10) >> 4); + printf(" Persistent Mem. RO[5] : %d\n", (smart->critical_warning & 0x20) >> 5); + } + + printf("temperature : %ld °C (%u K)\n", + kelvin_to_celsius(temperature), temperature); + printf("available_spare : %u%%\n", + smart->avail_spare); + printf("available_spare_threshold : %u%%\n", + smart->spare_thresh); + printf("percentage_used : %u%%\n", + smart->percent_used); + printf("endurance group critical warning summary: %#x\n", + smart->endu_grp_crit_warn_sumry); + printf("Data Units Read : %s (%s)\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->data_units_read)), + uint128_t_to_si_string(le128_to_cpu(smart->data_units_read), + 1000 * 512)); + printf("Data Units Written : %s (%s)\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->data_units_written)), + uint128_t_to_si_string(le128_to_cpu(smart->data_units_written), + 1000 * 512)); + printf("host_read_commands : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->host_reads))); + printf("host_write_commands : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->host_writes))); + printf("controller_busy_time : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->ctrl_busy_time))); + printf("power_cycles : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->power_cycles))); + printf("power_on_hours : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->power_on_hours))); + printf("unsafe_shutdowns : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->unsafe_shutdowns))); + printf("media_errors : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->media_errors))); + printf("num_err_log_entries : %s\n", + uint128_t_to_l10n_string(le128_to_cpu(smart->num_err_log_entries))); + printf("Warning Temperature Time : %u\n", + le32_to_cpu(smart->warning_temp_time)); + printf("Critical Composite Temperature Time : %u\n", + le32_to_cpu(smart->critical_comp_time)); + for (i = 0; i < 8; i++) { + __s32 temp = le16_to_cpu(smart->temp_sensor[i]); + + if (temp == 0) + continue; + printf("Temperature Sensor %d : %ld °C (%u K)\n", + i + 1, kelvin_to_celsius(temp), temp); + } + printf("Thermal Management T1 Trans Count : %u\n", + le32_to_cpu(smart->thm_temp1_trans_count)); + printf("Thermal Management T2 Trans Count : %u\n", + le32_to_cpu(smart->thm_temp2_trans_count)); + printf("Thermal Management T1 Total Time : %u\n", + le32_to_cpu(smart->thm_temp1_total_time)); + printf("Thermal Management T2 Total Time : %u\n", + le32_to_cpu(smart->thm_temp2_total_time)); +} + +static void stdout_ana_log(struct nvme_ana_log *ana_log, const char *devname, + size_t len) +{ + int offset = sizeof(struct nvme_ana_log); + struct nvme_ana_log *hdr = ana_log; + struct nvme_ana_group_desc *desc; + size_t nsid_buf_size; + void *base = ana_log; + __u32 nr_nsids; + int i, j; + + printf("Asymmetric Namespace Access Log for NVMe device: %s\n", + devname); + printf("ANA LOG HEADER :-\n"); + printf("chgcnt : %"PRIu64"\n", + le64_to_cpu(hdr->chgcnt)); + printf("ngrps : %u\n", le16_to_cpu(hdr->ngrps)); + printf("ANA Log Desc :-\n"); + + for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) { + desc = base + offset; + nr_nsids = le32_to_cpu(desc->nnsids); + nsid_buf_size = nr_nsids * sizeof(__le32); + + offset += sizeof(*desc); + printf("grpid : %u\n", le32_to_cpu(desc->grpid)); + printf("nnsids : %u\n", le32_to_cpu(desc->nnsids)); + printf("chgcnt : %"PRIu64"\n", + le64_to_cpu(desc->chgcnt)); + printf("state : %s\n", + nvme_ana_state_to_string(desc->state)); + for (j = 0; j < le32_to_cpu(desc->nnsids); j++) + printf(" nsid : %u\n", + le32_to_cpu(desc->nsids[j])); + printf("\n"); + offset += nsid_buf_size; + } +} + +static void stdout_self_test_result(struct nvme_st_result *res) +{ + static const char * const test_res[] = { + "Operation completed without error", + "Operation was aborted by a Device Self-test command", + "Operation was aborted by a Controller Level Reset", + "Operation was aborted due to a removal of a namespace from the namespace inventory", + "Operation was aborted due to the processing of a Format NVM command", + "A fatal error or unknown test error occurred while the controller was executing the"\ + " device self-test operation and the operation did not complete", + "Operation completed with a segment that failed and the segment that failed is not known", + "Operation completed with one or more failed segments and the first segment that failed "\ + "is indicated in the SegmentNumber field", + "Operation was aborted for unknown reason", + "Operation was aborted due to a sanitize operation", + "Reserved", + [NVME_ST_RESULT_NOT_USED] = "Entry not used (does not contain a result)", + }; + __u8 op, code; + + op = res->dsts & NVME_ST_RESULT_MASK; + printf(" Operation Result : %#x", op); + if (stdout_print_ops.flags & VERBOSE) + printf(" %s", (op < ARRAY_SIZE(test_res) && test_res[op]) ? + test_res[op] : test_res[ARRAY_SIZE(test_res) - 1]); + printf("\n"); + if (op == NVME_ST_RESULT_NOT_USED) + return; + + code = res->dsts >> NVME_ST_CODE_SHIFT; + printf(" Self Test Code : %x", code); + + if (stdout_print_ops.flags & VERBOSE) { + switch (code) { + case NVME_ST_CODE_SHORT: + printf(" Short device self-test operation"); + break; + case NVME_ST_CODE_EXTENDED: + printf(" Extended device self-test operation"); + break; + case NVME_ST_CODE_VS: + printf(" Vendor specific"); + break; + default: + printf(" Reserved"); + break; + } + } + printf("\n"); + + if (op == NVME_ST_RESULT_KNOWN_SEG_FAIL) + printf(" Segment Number : %#x\n", res->seg); + + printf(" Valid Diagnostic Information : %#x\n", res->vdi); + printf(" Power on hours (POH) : %#"PRIx64"\n", + (uint64_t)le64_to_cpu(res->poh)); + + if (res->vdi & NVME_ST_VALID_DIAG_INFO_NSID) + printf(" Namespace Identifier : %#x\n", + le32_to_cpu(res->nsid)); + if (res->vdi & NVME_ST_VALID_DIAG_INFO_FLBA) + printf(" Failing LBA : %#"PRIx64"\n", + (uint64_t)le64_to_cpu(res->flba)); + if (res->vdi & NVME_ST_VALID_DIAG_INFO_SCT) + printf(" Status Code Type : %#x\n", res->sct); + if (res->vdi & NVME_ST_VALID_DIAG_INFO_SC) { + printf(" Status Code : %#x", res->sc); + if (stdout_print_ops.flags & VERBOSE) + printf(" %s", nvme_status_to_string( + (res->sct & 7) << 8 | res->sc, false)); + printf("\n"); + } + printf(" Vendor Specific : %#x %#x\n", + res->vs[0], res->vs[1]); +} + +static void stdout_self_test_log(struct nvme_self_test_log *self_test, + __u8 dst_entries, __u32 size, + const char *devname) +{ + int i; + __u8 num_entries; + + printf("Device Self Test Log for NVME device:%s\n", devname); + printf("Current operation : %#x\n", self_test->current_operation); + printf("Current Completion : %u%%\n", self_test->completion); + num_entries = min(dst_entries, NVME_LOG_ST_MAX_RESULTS); + for (i = 0; i < num_entries; i++) { + printf("Self Test Result[%d]:\n", i); + stdout_self_test_result(&self_test->result[i]); + } +} + +static void stdout_sanitize_log_sprog(__u32 sprog) +{ + double percent; + + percent = (((double)sprog * 100) / 0x10000); + printf("\t(%f%%)\n", percent); +} + +static void stdout_sanitize_log_sstat(__u16 status) +{ + const char *str = nvme_sstat_status_to_string(status); + + printf("\t[2:0]\t%s\n", str); + str = "Number of completed passes if most recent operation was overwrite"; + printf("\t[7:3]\t%s:\t%u\n", str, + (status >> NVME_SANITIZE_SSTAT_COMPLETED_PASSES_SHIFT) & + NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK); + + printf("\t [8]\t"); + if (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED) + str = "Global Data Erased set: no NS LB in the NVM subsystem "\ + "has been written to and no PMR in the NVM subsystem "\ + "has been enabled"; + else + str = "Global Data Erased cleared: a NS LB in the NVM "\ + "subsystem has been written to or a PMR in the NVM "\ + "subsystem has been enabled"; + printf("%s\n", str); +} + +static void stdout_estimate_sanitize_time(const char *text, uint32_t value) +{ + printf("%s: %u%s\n", text, value, + value == 0xffffffff ? " (No time period reported)" : ""); +} + +static void stdout_sanitize_log(struct nvme_sanitize_log_page *sanitize, + const char *devname) +{ + int human = stdout_print_ops.flags & VERBOSE; + __u16 status = le16_to_cpu(sanitize->sstat) & NVME_SANITIZE_SSTAT_STATUS_MASK; + + printf("Sanitize Progress (SPROG) : %u", + le16_to_cpu(sanitize->sprog)); + + if (human && status == NVME_SANITIZE_SSTAT_STATUS_IN_PROGESS) + stdout_sanitize_log_sprog(le16_to_cpu(sanitize->sprog)); + else + printf("\n"); + + printf("Sanitize Status (SSTAT) : %#x\n", + le16_to_cpu(sanitize->sstat)); + if (human) + stdout_sanitize_log_sstat(le16_to_cpu(sanitize->sstat)); + + printf("Sanitize Command Dword 10 Information (SCDW10) : %#x\n", + le32_to_cpu(sanitize->scdw10)); + stdout_estimate_sanitize_time("Estimated Time For Overwrite ", + le32_to_cpu(sanitize->eto)); + stdout_estimate_sanitize_time("Estimated Time For Block Erase ", + le32_to_cpu(sanitize->etbe)); + stdout_estimate_sanitize_time("Estimated Time For Crypto Erase ", + le32_to_cpu(sanitize->etce)); + stdout_estimate_sanitize_time("Estimated Time For Overwrite (No-Deallocate) ", + le32_to_cpu(sanitize->etond)); + stdout_estimate_sanitize_time("Estimated Time For Block Erase (No-Deallocate) ", + le32_to_cpu(sanitize->etbend)); + stdout_estimate_sanitize_time("Estimated Time For Crypto Erase (No-Deallocate)", + le32_to_cpu(sanitize->etcend)); +} + +static void stdout_select_result(enum nvme_features_id fid, __u32 result) +{ + if (result & 0x1) + printf(" Feature is saveable\n"); + if (result & 0x2) + printf(" Feature is per-namespace\n"); + if (result & 0x4) + printf(" Feature is changeable\n"); +} + +static void stdout_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges) +{ + int i, j; + + for (i = 0; i <= nr_ranges; i++) { + printf("\ttype : %#x - %s\n", lbrt->entry[i].type, + nvme_feature_lba_type_to_string(lbrt->entry[i].type)); + printf("\tattributes : %#x - %s, %s\n", lbrt->entry[i].attributes, + (lbrt->entry[i].attributes & 0x0001) ? + "LBA range may be overwritten" : + "LBA range should not be overwritten", + ((lbrt->entry[i].attributes & 0x0002) >> 1) ? + "LBA range should be hidden from the OS/EFI/BIOS" : + "LBA range should be visible from the OS/EFI/BIOS"); + printf("\tslba : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].slba)); + printf("\tnlb : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].nlb)); + printf("\tguid : "); + for (j = 0; j < ARRAY_SIZE(lbrt->entry[i].guid); j++) + printf("%02x", lbrt->entry[i].guid[j]); + printf("\n"); + } +} + +static void stdout_auto_pst(struct nvme_feat_auto_pst *apst) +{ + int i; + __u64 value; + + printf("\tAuto PST Entries"); + printf("\t.................\n"); + for (i = 0; i < ARRAY_SIZE(apst->apst_entry); i++) { + value = le64_to_cpu(apst->apst_entry[i]); + + printf("\tEntry[%2d]\n", i); + printf("\t.................\n"); + printf("\tIdle Time Prior to Transition (ITPT): %u ms\n", + (__u32)NVME_GET(value, APST_ENTRY_ITPT)); + printf("\tIdle Transition Power State (ITPS): %u\n", + (__u32)NVME_GET(value, APST_ENTRY_ITPS)); + printf("\t.................\n"); + } +} + +static void stdout_timestamp(struct nvme_timestamp *ts) +{ + struct tm *tm; + char buffer[320]; + time_t timestamp = int48_to_long(ts->timestamp) / 1000; + + tm = localtime(×tamp); + + printf("\tThe timestamp is : %'"PRIu64" (%s)\n", + int48_to_long(ts->timestamp), + strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-"); + printf("\t%s\n", (ts->attr & 2) ? + "The Timestamp field was initialized with a "\ + "Timestamp value using a Set Features command." : + "The Timestamp field was initialized "\ + "to ‘0’ by a Controller Level Reset."); + printf("\t%s\n", (ts->attr & 1) ? + "The controller may have stopped counting during vendor specific "\ + "intervals after the Timestamp value was initialized" : + "The controller counted time in milliseconds "\ + "continuously since the Timestamp value was initialized."); +} + +static void stdout_host_mem_buffer(struct nvme_host_mem_buf_attrs *hmb) +{ + printf("\tHost Memory Descriptor List Entry Count (HMDLEC): %u\n", + le32_to_cpu(hmb->hmdlec)); + printf("\tHost Memory Descriptor List Address (HMDLAU): 0x%x\n", + le32_to_cpu(hmb->hmdlau)); + printf("\tHost Memory Descriptor List Address (HMDLAL): 0x%x\n", + le32_to_cpu(hmb->hmdlal)); + printf("\tHost Memory Buffer Size (HSIZE): %u\n", + le32_to_cpu(hmb->hsize)); +} + +static void stdout_directive_show_fields(__u8 dtype, __u8 doper, + unsigned int result, unsigned char *buf) +{ + __u8 *field = buf; + int count, i; + + switch (dtype) { + case NVME_DIRECTIVE_DTYPE_IDENTIFY: + switch (doper) { + case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM: + printf("\tDirective support\n"); + printf("\t\tIdentify Directive : %s\n", + (*field & 0x1) ? "supported" : "not supported"); + printf("\t\tStream Directive : %s\n", + (*field & 0x2) ? "supported" : "not supported"); + printf("\t\tData Placement Directive : %s\n", + (*field & 0x4) ? "supported" : "not supported"); + printf("\tDirective enabled\n"); + printf("\t\tIdentify Directive : %s\n", + (*(field + 32) & 0x1) ? "enabled" : "disabled"); + printf("\t\tStream Directive : %s\n", + (*(field + 32) & 0x2) ? "enabled" : "disabled"); + printf("\t\tData Placement Directive : %s\n", + (*(field + 32) & 0x4) ? "enabled" : "disabled"); + printf("\tDirective Persistent Across Controller Level Resets\n"); + printf("\t\tIdentify Directive : %s\n", + (*(field + 64) & 0x1) ? "enabled" : "disabled"); + printf("\t\tStream Directive : %s\n", + (*(field + 64) & 0x2) ? "enabled" : "disabled"); + printf("\t\tData Placement Directive : %s\n", + (*(field + 64) & 0x4) ? "enabled" : "disabled"); + break; + default: + fprintf(stderr, + "invalid directive operations for Identify Directives\n"); + break; + } + break; + case NVME_DIRECTIVE_DTYPE_STREAMS: + switch (doper) { + case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM: + printf("\tMax Streams Limit (MSL): %u\n", + *(__u16 *)field); + printf("\tNVM Subsystem Streams Available (NSSA): %u\n", + *(__u16 *)(field + 2)); + printf("\tNVM Subsystem Streams Open (NSSO): %u\n", + *(__u16 *)(field + 4)); + printf("\tNVM Subsystem Stream Capability (NSSC): %u\n", + *(__u16 *)(field + 6)); + printf("\tStream Write Size (in unit of LB size) (SWS): %u\n", + *(__u32 *)(field + 16)); + printf("\tStream Granularity Size (in unit of SWS) (SGS): %u\n", + *(__u16 *)(field + 20)); + printf("\tNamespace Streams Allocated (NSA): %u\n", + *(__u16 *)(field + 22)); + printf("\tNamespace Streams Open (NSO): %u\n", + *(__u16 *)(field + 24)); + break; + case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS: + count = *(__u16 *)field; + printf("\tOpen Stream Count : %u\n", *(__u16 *)field); + for (i = 0; i < count; i++) + printf("\tStream Identifier %.6u : %u\n", i + 1, + *(__u16 *)(field + ((i + 1) * 2))); + break; + case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE: + printf("\tNamespace Streams Allocated (NSA): %u\n", + result & 0xffff); + break; + default: + fprintf(stderr, + "invalid directive operations for Streams Directives\n"); + break; + } + break; + default: + fprintf(stderr, "invalid directive type\n"); + break; + } +} + +static void stdout_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, + void *buf, __u32 len) +{ + printf("dir-receive: type:%#x operation:%#x spec:%#x nsid:%#x result:%#x\n", + type, oper, spec, nsid, result); + if (stdout_print_ops.flags & VERBOSE) + stdout_directive_show_fields(type, oper, result, buf); + else if (buf) + d(buf, len, 16, 1); +} + +static void stdout_lba_status_info(__u32 result) +{ + printf("\tLBA Status Information Poll Interval (LSIPI) : %u\n", (result >> 16) & 0xffff); + printf("\tLBA Status Information Report Interval (LSIRI): %u\n", result & 0xffff); +} + +void stdout_d(unsigned char *buf, int len, int width, int group) +{ + int i, offset = 0; + char ascii[32 + 1] = { 0 }; + + assert(width < sizeof(ascii)); + + printf(" "); + + for (i = 0; i <= 15; i++) + printf("%3x", i); + + for (i = 0; i < len; i++) { + if (!(i % width)) + printf("\n%04x:", offset); + if (i % group) + printf("%02x", buf[i]); + else + printf(" %02x", buf[i]); + ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.'; + if (!((i + 1) % width)) { + printf(" \"%.*s\"", width, ascii); + offset += width; + memset(ascii, 0, sizeof(ascii)); + } + } + + if (strlen(ascii)) { + unsigned int b = width - (i % width); + + printf(" %*s \"%.*s\"", 2 * b + b / group + (b % group ? 1 : 0), "", width, ascii); + } + + printf("\n"); +} + +static void stdout_plm_config(struct nvme_plm_config *plmcfg) +{ + printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->ee)); + printf("\tDTWIN Reads Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwinrt)); + printf("\tDTWIN Writes Threshold:%"PRIu64"\n", le64_to_cpu(plmcfg->dtwinwt)); + printf("\tDTWIN Time Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwintt)); +} + +static void stdout_host_metadata(enum nvme_features_id fid, + struct nvme_host_metadata *data) +{ + struct nvme_metadata_element_desc *desc = &data->descs[0]; + int i; + char val[4096]; + __u16 len; + + printf("\tNum Metadata Element Descriptors: %d\n", data->ndesc); + for (i = 0; i < data->ndesc; i++) { + len = le16_to_cpu(desc->len); + strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len)); + + printf("\tElement[%-3d]:\n", i); + printf("\t\tType : 0x%02x (%s)\n", desc->type, + nvme_host_metadata_type_to_string(fid, desc->type)); + printf("\t\tRevision : %d\n", desc->rev); + printf("\t\tLength : %d\n", len); + printf("\t\tValue : %s\n", val); + + desc = (struct nvme_metadata_element_desc *)&desc->val[desc->len]; + } +} + +static void stdout_feature_show(enum nvme_features_id fid, int sel, unsigned int result) +{ + printf("get-feature:%#0*x (%s), %s value:%#0*x\n", fid ? 4 : 2, fid, + nvme_feature_to_string(fid), nvme_select_to_string(sel), result ? 10 : 8, result); +} + +static void stdout_feature_show_fields(enum nvme_features_id fid, + unsigned int result, + unsigned char *buf) +{ + __u8 field; + uint64_t ull; + + switch (fid) { + case NVME_FEAT_FID_ARBITRATION: + printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1); + printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1); + printf("\tLow Priority Weight (LPW): %u\n", ((result & 0x0000ff00) >> 8) + 1); + printf("\tArbitration Burst (AB): "); + if ((result & 0x00000007) == 7) + printf("No limit\n"); + else + printf("%u\n", 1 << (result & 0x00000007)); + break; + case NVME_FEAT_FID_POWER_MGMT: + field = (result & 0x000000E0) >> 5; + printf("\tWorkload Hint (WH): %u - %s\n", field, nvme_feature_wl_hints_to_string(field)); + printf("\tPower State (PS): %u\n", result & 0x0000001f); + break; + case NVME_FEAT_FID_LBA_RANGE: + field = result & 0x0000003f; + printf("\tNumber of LBA Ranges (NUM): %u\n", field + 1); + if (buf) + stdout_lba_range((struct nvme_lba_range_type *)buf, field); + break; + case NVME_FEAT_FID_TEMP_THRESH: + field = (result & 0x00300000) >> 20; + printf("\tThreshold Type Select (THSEL): %u - %s\n", field, + nvme_feature_temp_type_to_string(field)); + field = (result & 0x000f0000) >> 16; + printf("\tThreshold Temperature Select (TMPSEL): %u - %s\n", + field, nvme_feature_temp_sel_to_string(field)); + printf("\tTemperature Threshold (TMPTH): %ld °C (%u K)\n", + kelvin_to_celsius(result & 0x0000ffff), result & 0x0000ffff); + break; + case NVME_FEAT_FID_ERR_RECOVERY: + printf("\tDeallocated or Unwritten Logical Block Error Enable (DULBE): %s\n", + ((result & 0x00010000) >> 16) ? "Enabled" : "Disabled"); + printf("\tTime Limited Error Recovery (TLER): %u ms\n", + (result & 0x0000ffff) * 100); + break; + case NVME_FEAT_FID_VOLATILE_WC: + printf("\tVolatile Write Cache Enable (WCE): %s\n", (result & 0x00000001) ? "Enabled" : "Disabled"); + break; + case NVME_FEAT_FID_NUM_QUEUES: + printf("\tNumber of IO Completion Queues Allocated (NCQA): %u\n", ((result & 0xffff0000) >> 16) + 1); + printf("\tNumber of IO Submission Queues Allocated (NSQA): %u\n", (result & 0x0000ffff) + 1); + break; + case NVME_FEAT_FID_IRQ_COALESCE: + printf("\tAggregation Time (TIME): %u usec\n", ((result & 0x0000ff00) >> 8) * 100); + printf("\tAggregation Threshold (THR): %u\n", (result & 0x000000ff) + 1); + break; + case NVME_FEAT_FID_IRQ_CONFIG: + printf("\tCoalescing Disable (CD): %s\n", ((result & 0x00010000) >> 16) ? "True" : "False"); + printf("\tInterrupt Vector (IV): %u\n", result & 0x0000ffff); + break; + case NVME_FEAT_FID_WRITE_ATOMIC: + printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True" : "False"); + break; + case NVME_FEAT_FID_ASYNC_EVENT: + printf("\tDiscovery Log Page Change Notices : %s\n", + ((result & 0x80000000) >> 31) ? "Send async event" : "Do not send async event"); + printf("\tEndurance Group Event Aggregate Log Change Notices : %s\n", + ((result & 0x00004000) >> 14) ? "Send async event" : "Do not send async event"); + printf("\tLBA Status Information Notices : %s\n", + ((result & 0x00002000) >> 13) ? "Send async event" : "Do not send async event"); + printf("\tPredictable Latency Event Aggregate Log Change Notices : %s\n", + ((result & 0x00001000) >> 12) ? "Send async event" : "Do not send async event"); + printf("\tAsymmetric Namespace Access Change Notices : %s\n", + ((result & 0x00000800) >> 11) ? "Send async event" : "Do not send async event"); + printf("\tTelemetry Log Notices : %s\n", + ((result & 0x00000400) >> 10) ? "Send async event" : "Do not send async event"); + printf("\tFirmware Activation Notices : %s\n", + ((result & 0x00000200) >> 9) ? "Send async event" : "Do not send async event"); + printf("\tNamespace Attribute Notices : %s\n", + ((result & 0x00000100) >> 8) ? "Send async event" : "Do not send async event"); + printf("\tSMART / Health Critical Warnings : %s\n", + (result & 0x000000ff) ? "Send async event" : "Do not send async event"); + break; + case NVME_FEAT_FID_AUTO_PST: + printf("\tAutonomous Power State Transition Enable (APSTE): %s\n", + (result & 0x00000001) ? "Enabled" : "Disabled"); + if (buf) + stdout_auto_pst((struct nvme_feat_auto_pst *)buf); + break; + case NVME_FEAT_FID_HOST_MEM_BUF: + printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled" : "Disabled"); + if (buf) + stdout_host_mem_buffer((struct nvme_host_mem_buf_attrs *)buf); + break; + case NVME_FEAT_FID_TIMESTAMP: + if (buf) + stdout_timestamp((struct nvme_timestamp *)buf); + break; + case NVME_FEAT_FID_KATO: + printf("\tKeep Alive Timeout (KATO) in milliseconds: %u\n", result); + break; + case NVME_FEAT_FID_HCTM: + printf("\tThermal Management Temperature 1 (TMT1) : %u K (%ld °C)\n", + result >> 16, kelvin_to_celsius(result >> 16)); + printf("\tThermal Management Temperature 2 (TMT2) : %u K (%ld °C)\n", + result & 0x0000ffff, kelvin_to_celsius(result & 0x0000ffff)); + break; + case NVME_FEAT_FID_NOPSC: + printf("\tNon-Operational Power State Permissive Mode Enable (NOPPME): %s\n", + (result & 1) ? "True" : "False"); + break; + case NVME_FEAT_FID_RRL: + printf("\tRead Recovery Level (RRL): %u\n", result & 0xf); + break; + case NVME_FEAT_FID_PLM_CONFIG: + printf("\tPredictable Latency Window Enabled: %s\n", result & 0x1 ? "True" : "False"); + if (buf) + stdout_plm_config((struct nvme_plm_config *)buf); + break; + case NVME_FEAT_FID_PLM_WINDOW: + printf("\tWindow Select: %s", nvme_plm_window_to_string(result)); + break; + case NVME_FEAT_FID_LBA_STS_INTERVAL: + stdout_lba_status_info(result); + break; + case NVME_FEAT_FID_HOST_BEHAVIOR: + if (buf) { + struct nvme_feat_host_behavior *host_behavior = + (struct nvme_feat_host_behavior *)buf; + printf("\tAdvanced Command Retry Enable (ACRE): %s\n", + host_behavior->acre ? "True" : "False"); + printf("\tExtended Telemetry Data Area 4 Supported (ETDAS): %s\n", + host_behavior->etdas ? "True" : "False"); + printf("\tLBA Format Extension Enable (LBAFEE): %s\n", + host_behavior->lbafee ? "True" : "False"); + printf("\tCopy Descriptor Format 2h Enabled (CDFE): %s\n", + host_behavior->cdfe & (1 << 2) ? "True" : "False"); + printf("\tCopy Descriptor Format 3h Enabled (CDFE): %s\n", + host_behavior->cdfe & (1 << 3) ? "True" : "False"); + } + break; + case NVME_FEAT_FID_SANITIZE: + printf("\tNo-Deallocate Response Mode (NODRM) : %u\n", result & 0x1); + break; + case NVME_FEAT_FID_ENDURANCE_EVT_CFG: + printf("\tEndurance Group Identifier (ENDGID): %u\n", result & 0xffff); + printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff); + break; + case NVME_FEAT_FID_IOCS_PROFILE: + printf("\tI/O Command Set Profile: %s\n", result & 0x1 ? "True" : "False"); + break; + case NVME_FEAT_FID_SPINUP_CONTROL: + printf("\tSpinup control feature Enabled: %s\n", (result & 1) ? "True" : "False"); + break; + case NVME_FEAT_FID_ENH_CTRL_METADATA: + case NVME_FEAT_FID_CTRL_METADATA: + case NVME_FEAT_FID_NS_METADATA: + if (buf) + stdout_host_metadata(fid, (struct nvme_host_metadata *)buf); + break; + case NVME_FEAT_FID_SW_PROGRESS: + printf("\tPre-boot Software Load Count (PBSLC): %u\n", result & 0x000000ff); + break; + case NVME_FEAT_FID_HOST_ID: + if (buf) { + ull = buf[7]; ull <<= 8; ull |= buf[6]; ull <<= 8; ull |= buf[5]; ull <<= 8; + ull |= buf[4]; ull <<= 8; ull |= buf[3]; ull <<= 8; ull |= buf[2]; ull <<= 8; + ull |= buf[1]; ull <<= 8; ull |= buf[0]; + printf("\tHost Identifier (HOSTID): %" PRIu64 "\n", ull); + } + break; + case NVME_FEAT_FID_RESV_MASK: + printf("\tMask Reservation Preempted Notification (RESPRE): %s\n", + ((result & 0x00000008) >> 3) ? "True" : "False"); + printf("\tMask Reservation Released Notification (RESREL): %s\n", + ((result & 0x00000004) >> 2) ? "True" : "False"); + printf("\tMask Registration Preempted Notification (REGPRE): %s\n", + ((result & 0x00000002) >> 1) ? "True" : "False"); + break; + case NVME_FEAT_FID_RESV_PERSIST: + printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True" : "False"); + break; + case NVME_FEAT_FID_WRITE_PROTECT: + printf("\tNamespace Write Protect: %s\n", nvme_ns_wp_cfg_to_string(result)); + break; + case NVME_FEAT_FID_FDP: + printf("\tFlexible Direct Placement Enable (FDPE) : %s\n", + (result & 0x1) ? "Yes" : "No"); + printf("\tFlexible Direct Placement Configuration Index : %u\n", + (result >> 8) & 0xf); + break; + case NVME_FEAT_FID_FDP_EVENTS: + for (unsigned int i = 0; i < result; i++) { + struct nvme_fdp_supported_event_desc *d; + + d = &((struct nvme_fdp_supported_event_desc *)buf)[i]; + + printf("\t%-53s: %sEnabled\n", nvme_fdp_event_to_string(d->evt), + d->evta & 0x1 ? "" : "Not "); + } + break; + default: + break; + } +} + +static void stdout_lba_status(struct nvme_lba_status *list, + unsigned long len) +{ + int idx; + + printf("Number of LBA Status Descriptors(NLSD): %" PRIu32 "\n", + le32_to_cpu(list->nlsd)); + printf("Completion Condition(CMPC): %u\n", list->cmpc); + + switch (list->cmpc) { + case 1: + printf("\tCompleted due to transferring the amount of data"\ + " specified in the MNDW field\n"); + break; + case 2: + printf("\tCompleted due to having performed the action\n"\ + "\tspecified in the Action Type field over the\n"\ + "\tnumber of logical blocks specified in the\n"\ + "\tRange Length field\n"); + break; + default: + break; + } + + for (idx = 0; idx < list->nlsd; idx++) { + struct nvme_lba_status_desc *e = &list->descs[idx]; + + printf("{ DSLBA: 0x%016"PRIu64", NLB: 0x%08x, Status: 0x%02x }\n", + le64_to_cpu(e->dslba), le32_to_cpu(e->nlb), + e->status); + } +} + +static void stdout_dev_full_path(nvme_ns_t n, char *path, size_t len) +{ + struct stat st; + + snprintf(path, len, "/dev/%s", nvme_ns_get_name(n)); + if (stat(path, &st) == 0) + return; + + snprintf(path, len, "/dev/spdk/%s", nvme_ns_get_name(n)); + if (stat(path, &st) == 0) + return; + + /* + * We could start trying to search for it but let's make + * it simple and just don't show the path at all. + */ + snprintf(path, len, "%s", nvme_ns_get_name(n)); +} + +static void stdout_generic_full_path(nvme_ns_t n, char *path, size_t len) +{ + int head_instance; + int instance; + struct stat st; + + if (sscanf(nvme_ns_get_name(n), "nvme%dn%d", &instance, &head_instance) != 2) + return; + + snprintf(path, len, "/dev/ng%dn%d", instance, head_instance); + + if (stat(path, &st) == 0) + return; + + snprintf(path, len, "/dev/spdk/ng%dn%d", instance, head_instance); + if (stat(path, &st) == 0) + return; + /* + * We could start trying to search for it but let's make + * it simple and just don't show the path at all. + */ + snprintf(path, len, "ng%dn%d", instance, head_instance); +} + +static void stdout_list_item(nvme_ns_t n) +{ + char usage[128] = { 0 }, format[128] = { 0 }; + char devname[128] = { 0 }; char genname[128] = { 0 }; + + long long lba = nvme_ns_get_lba_size(n); + double nsze = nvme_ns_get_lba_count(n) * lba; + double nuse = nvme_ns_get_lba_util(n) * lba; + + const char *s_suffix = suffix_si_get(&nsze); + const char *u_suffix = suffix_si_get(&nuse); + const char *l_suffix = suffix_binary_get(&lba); + + snprintf(usage, sizeof(usage), "%6.2f %2sB / %6.2f %2sB", nuse, + u_suffix, nsze, s_suffix); + snprintf(format, sizeof(format), "%3.0f %2sB + %2d B", (double)lba, + l_suffix, nvme_ns_get_meta_size(n)); + + stdout_dev_full_path(n, devname, sizeof(devname)); + stdout_generic_full_path(n, genname, sizeof(genname)); + + printf("%-21s %-21s %-20s %-40s %#-10x %-26s %-16s %-8s\n", + devname, genname, nvme_ns_get_serial(n), + nvme_ns_get_model(n), nvme_ns_get_nsid(n), usage, format, + nvme_ns_get_firmware(n)); +} + +static bool stdout_simple_ns(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + nvme_ns_t n; + + n = htable_ns_get(&res->ht_n, name); + stdout_list_item(n); + + return true; +} + +static void stdout_simple_list(nvme_root_t r) +{ + struct nvme_resources res; + + nvme_resources_init(r, &res); + + printf("%-21s %-21s %-20s %-40s %-10s %-26s %-16s %-8s\n", + "Node", "Generic", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev"); + printf("%-.21s %-.21s %-.20s %-.40s %-.10s %-.26s %-.16s %-.8s\n", + dash, dash, dash, dash, dash, dash, dash, dash); + strset_iterate(&res.namespaces, stdout_simple_ns, &res); + + nvme_resources_free(&res); +} + +static void stdout_ns_details(nvme_ns_t n) +{ + char usage[128] = { 0 }, format[128] = { 0 }; + char devname[128] = { 0 }, genname[128] = { 0 }; + + long long lba = nvme_ns_get_lba_size(n); + double nsze = nvme_ns_get_lba_count(n) * lba; + double nuse = nvme_ns_get_lba_util(n) * lba; + + const char *s_suffix = suffix_si_get(&nsze); + const char *u_suffix = suffix_si_get(&nuse); + const char *l_suffix = suffix_binary_get(&lba); + + sprintf(usage, "%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix); + sprintf(format, "%3.0f %2sB + %2d B", (double)lba, l_suffix, + nvme_ns_get_meta_size(n)); + + nvme_dev_full_path(n, devname, sizeof(devname)); + nvme_generic_full_path(n, genname, sizeof(genname)); + + printf("%-12s %-12s %#-10x %-26s %-16s ", devname, + genname, nvme_ns_get_nsid(n), usage, format); +} + +static bool stdout_detailed_name(const char *name, void *arg) +{ + bool *first = arg; + + printf("%s%s", *first ? "" : ", ", name); + *first = false; + + return true; +} + +static bool stdout_detailed_subsys(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + struct htable_subsys_iter it; + struct strset ctrls; + nvme_subsystem_t s; + nvme_ctrl_t c; + bool first; + + strset_init(&ctrls); + first = true; + for (s = htable_subsys_getfirst(&res->ht_s, name, &it); + s; + s = htable_subsys_getnext(&res->ht_s, name, &it)) { + if (first) { + printf("%-16s %-96s ", name, nvme_subsystem_get_nqn(s)); + first = false; + } + + nvme_subsystem_for_each_ctrl(s, c) + strset_add(&ctrls, nvme_ctrl_get_name(c)); + } + + first = true; + strset_iterate(&ctrls, stdout_detailed_name, &first); + strset_clear(&ctrls); + printf("\n"); + + return true; +} + +static bool stdout_detailed_ctrl(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + struct strset namespaces; + nvme_ctrl_t c; + nvme_path_t p; + nvme_ns_t n; + bool first; + + c = htable_ctrl_get(&res->ht_c, name); + assert(c); + + printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s ", + nvme_ctrl_get_name(c), + nvme_ctrl_get_serial(c), + nvme_ctrl_get_model(c), + nvme_ctrl_get_firmware(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c), + nvme_ctrl_get_phy_slot(c), + nvme_subsystem_get_name(nvme_ctrl_get_subsystem(c))); + + strset_init(&namespaces); + + nvme_ctrl_for_each_ns(c, n) + strset_add(&namespaces, nvme_ns_get_name(n)); + nvme_ctrl_for_each_path(c, p) { + n = nvme_path_get_ns(p); + if (!n) + continue; + strset_add(&namespaces, nvme_ns_get_name(n)); + } + + first = true; + strset_iterate(&namespaces, stdout_detailed_name, &first); + strset_clear(&namespaces); + + printf("\n"); + + return true; +} + +static bool stdout_detailed_ns(const char *name, void *arg) +{ + struct nvme_resources *res = arg; + struct htable_ns_iter it; + struct strset ctrls; + nvme_ctrl_t c; + nvme_path_t p; + nvme_ns_t n; + bool first; + + strset_init(&ctrls); + first = true; + for (n = htable_ns_getfirst(&res->ht_n, name, &it); + n; + n = htable_ns_getnext(&res->ht_n, name, &it)) { + if (first) { + stdout_ns_details(n); + first = false; + } + + if (nvme_ns_get_ctrl(n)) { + printf("%s\n", nvme_ctrl_get_name(nvme_ns_get_ctrl(n))); + return true; + } + + nvme_namespace_for_each_path(n, p) { + c = nvme_path_get_ctrl(p); + strset_add(&ctrls, nvme_ctrl_get_name(c)); + } + } + + first = true; + strset_iterate(&ctrls, stdout_detailed_name, &first); + strset_clear(&ctrls); + + printf("\n"); + return true; +} + +static void stdout_detailed_list(nvme_root_t r) +{ + struct nvme_resources res; + + nvme_resources_init(r, &res); + + printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers"); + printf("%-.16s %-.96s %-.16s\n", dash, dash, dash); + strset_iterate(&res.subsystems, stdout_detailed_subsys, &res); + printf("\n"); + + printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s %-16s\n", "Device", + "SN", "MN", "FR", "TxPort", "Address", "Slot", "Subsystem", "Namespaces"); + printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.6s %-.12s %-.16s\n", dash, + dash, dash, dash, dash, dash, dash, dash, dash); + strset_iterate(&res.ctrls, stdout_detailed_ctrl, &res); + printf("\n"); + + printf("%-12s %-12s %-10s %-26s %-16s %-16s\n", "Device", "Generic", + "NSID", "Usage", "Format", "Controllers"); + printf("%-.12s %-.12s %-.10s %-.26s %-.16s %-.16s\n", dash, dash, dash, + dash, dash, dash); + strset_iterate(&res.namespaces, stdout_detailed_ns, &res); + + nvme_resources_free(&res); +} + +static void stdout_list_items(nvme_root_t r) +{ + if (stdout_print_ops.flags & VERBOSE) + stdout_detailed_list(r); + else + stdout_simple_list(r); +} + +static bool nvme_is_multipath(nvme_subsystem_t s) +{ + nvme_ns_t n; + nvme_path_t p; + + nvme_subsystem_for_each_ns(s, n) + nvme_namespace_for_each_path(n, p) + return true; + + return false; +} + +static void stdout_subsystem_topology_multipath(nvme_subsystem_t s, + enum nvme_cli_topo_ranking ranking) +{ + nvme_ns_t n; + nvme_path_t p; + nvme_ctrl_t c; + + if (ranking == NVME_CLI_TOPO_NAMESPACE) { + nvme_subsystem_for_each_ns(s, n) { + if (!nvme_namespace_first_path(n)) + continue; + + printf(" +- ns %d\n", nvme_ns_get_nsid(n)); + printf(" \\\n"); + + nvme_namespace_for_each_path(n, p) { + c = nvme_path_get_ctrl(p); + + printf(" +- %s %s %s %s %s\n", + nvme_ctrl_get_name(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c), + nvme_ctrl_get_state(c), + nvme_path_get_ana_state(p)); + } + } + } else { + /* NVME_CLI_TOPO_CTRL */ + nvme_subsystem_for_each_ctrl(s, c) { + printf(" +- %s %s %s\n", + nvme_ctrl_get_name(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c)); + printf(" \\\n"); + + nvme_subsystem_for_each_ns(s, n) { + nvme_namespace_for_each_path(n, p) { + if (nvme_path_get_ctrl(p) != c) + continue; + + printf(" +- ns %d %s %s\n", + nvme_ns_get_nsid(n), + nvme_ctrl_get_state(c), + nvme_path_get_ana_state(p)); + } + } + } + } +} + +static void stdout_subsystem_topology(nvme_subsystem_t s, + enum nvme_cli_topo_ranking ranking) +{ + nvme_ctrl_t c; + nvme_ns_t n; + + if (ranking == NVME_CLI_TOPO_NAMESPACE) { + nvme_subsystem_for_each_ctrl(s, c) { + nvme_ctrl_for_each_ns(c, n) { + printf(" +- ns %d\n", nvme_ns_get_nsid(n)); + printf(" \\\n"); + printf(" +- %s %s %s %s\n", + nvme_ctrl_get_name(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c), + nvme_ctrl_get_state(c)); + } + } + } else { + /* NVME_CLI_TOPO_CTRL */ + nvme_subsystem_for_each_ctrl(s, c) { + printf(" +- %s %s %s\n", + nvme_ctrl_get_name(c), + nvme_ctrl_get_transport(c), + nvme_ctrl_get_address(c)); + printf(" \\\n"); + nvme_ctrl_for_each_ns(c, n) { + printf(" +- ns %d %s\n", + nvme_ns_get_nsid(n), + nvme_ctrl_get_state(c)); + } + } + } +} + +static void stdout_simple_topology(nvme_root_t r, + enum nvme_cli_topo_ranking ranking) +{ + nvme_host_t h; + nvme_subsystem_t s; + bool first = true; + + nvme_for_each_host(r, h) { + nvme_for_each_subsystem(h, s) { + int len = strlen(nvme_subsystem_get_name(s)); + + if (!first) + printf("\n"); + first = false; + + printf("%s - NQN=%s\n", nvme_subsystem_get_name(s), + nvme_subsystem_get_nqn(s)); + printf("%*s hostnqn=%s\n", len, " ", + nvme_host_get_hostnqn(nvme_subsystem_get_host(s))); + printf("%*s iopolicy=%s\n", len, " ", + nvme_subsystem_get_iopolicy(s)); + printf("\\\n"); + + if (nvme_is_multipath(s)) + stdout_subsystem_topology_multipath(s, ranking); + else + stdout_subsystem_topology(s, ranking); + } + } +} + +static void stdout_topology_namespace(nvme_root_t r) +{ + stdout_simple_topology(r, NVME_CLI_TOPO_NAMESPACE); +} + +static void stdout_topology_ctrl(nvme_root_t r) +{ + stdout_simple_topology(r, NVME_CLI_TOPO_CTRL); +} + +static void stdout_message(bool error, const char *msg, va_list ap) +{ + vfprintf(error ? stderr : stdout, msg, ap); + + fprintf(error ? stderr : stdout, "\n"); +} + +static void stdout_perror(const char *msg) +{ + perror(msg); +} + +static void stdout_discovery_log(struct nvmf_discovery_log *log, int numrec) +{ + int i; + + printf("\nDiscovery Log Number of Records %d, Generation counter %"PRIu64"\n", + numrec, le64_to_cpu(log->genctr)); + + for (i = 0; i < numrec; i++) { + struct nvmf_disc_log_entry *e = &log->entries[i]; + + printf("=====Discovery Log Entry %d======\n", i); + printf("trtype: %s\n", nvmf_trtype_str(e->trtype)); + printf("adrfam: %s\n", + strlen(e->traddr) ? + nvmf_adrfam_str(e->adrfam) : ""); + printf("subtype: %s\n", nvmf_subtype_str(e->subtype)); + printf("treq: %s\n", nvmf_treq_str(e->treq)); + printf("portid: %d\n", le16_to_cpu(e->portid)); + printf("trsvcid: %s\n", e->trsvcid); + printf("subnqn: %s\n", e->subnqn); + printf("traddr: %s\n", e->traddr); + printf("eflags: %s\n", + nvmf_eflags_str(le16_to_cpu(e->eflags))); + + switch (e->trtype) { + case NVMF_TRTYPE_RDMA: + printf("rdma_prtype: %s\n", + nvmf_prtype_str(e->tsas.rdma.prtype)); + printf("rdma_qptype: %s\n", + nvmf_qptype_str(e->tsas.rdma.qptype)); + printf("rdma_cms: %s\n", + nvmf_cms_str(e->tsas.rdma.cms)); + printf("rdma_pkey: 0x%04x\n", + le16_to_cpu(e->tsas.rdma.pkey)); + break; + case NVMF_TRTYPE_TCP: + printf("sectype: %s\n", + nvmf_sectype_str(e->tsas.tcp.sectype)); + break; + } + } +} + +static void stdout_connect_msg(nvme_ctrl_t c) +{ + printf("connecting to device: %s\n", nvme_ctrl_get_name(c)); +} + +static struct print_ops stdout_print_ops = { + /* libnvme types.h print functions */ + .ana_log = stdout_ana_log, + .boot_part_log = stdout_boot_part_log, + .phy_rx_eom_log = stdout_phy_rx_eom_log, + .ctrl_list = stdout_list_ctrl, + .ctrl_registers = stdout_ctrl_registers, + .directive = stdout_directive_show, + .discovery_log = stdout_discovery_log, + .effects_log_list = stdout_effects_log_pages, + .endurance_group_event_agg_log = stdout_endurance_group_event_agg_log, + .endurance_group_list = stdout_endurance_group_list, + .endurance_log = stdout_endurance_log, + .error_log = stdout_error_log, + .fdp_config_log = stdout_fdp_configs, + .fdp_event_log = stdout_fdp_events, + .fdp_ruh_status = stdout_fdp_ruh_status, + .fdp_stats_log = stdout_fdp_stats, + .fdp_usage_log = stdout_fdp_usage, + .fid_supported_effects_log = stdout_fid_support_effects_log, + .fw_log = stdout_fw_log, + .id_ctrl = stdout_id_ctrl, + .id_ctrl_nvm = stdout_id_ctrl_nvm, + .id_domain_list = stdout_id_domain_list, + .id_independent_id_ns = stdout_cmd_set_independent_id_ns, + .id_iocs = stdout_id_iocs, + .id_ns = stdout_id_ns, + .id_ns_descs = stdout_id_ns_descs, + .id_ns_granularity_list = stdout_id_ns_granularity_list, + .id_nvmset_list = stdout_id_nvmset, + .id_uuid_list = stdout_id_uuid_list, + .lba_status = stdout_lba_status, + .lba_status_log = stdout_lba_status_log, + .media_unit_stat_log = stdout_media_unit_stat_log, + .mi_cmd_support_effects_log = stdout_mi_cmd_support_effects_log, + .ns_list = stdout_list_ns, + .ns_list_log = stdout_changed_ns_list_log, + .nvm_id_ns = stdout_nvm_id_ns, + .persistent_event_log = stdout_persistent_event_log, + .predictable_latency_event_agg_log = stdout_predictable_latency_event_agg_log, + .predictable_latency_per_nvmset = stdout_predictable_latency_per_nvmset, + .primary_ctrl_cap = stdout_primary_ctrl_cap, + .resv_notification_log = stdout_resv_notif_log, + .resv_report = stdout_resv_report, + .sanitize_log_page = stdout_sanitize_log, + .secondary_ctrl_list = stdout_list_secondary_ctrl, + .select_result = stdout_select_result, + .self_test_log = stdout_self_test_log, + .single_property = stdout_single_property, + .smart_log = stdout_smart_log, + .supported_cap_config_list_log = stdout_supported_cap_config_log, + .supported_log_pages = stdout_supported_log, + .zns_start_zone_list = stdout_zns_start_zone_list, + .zns_changed_zone_log = stdout_zns_changed, + .zns_finish_zone_list = NULL, + .zns_id_ctrl = stdout_zns_id_ctrl, + .zns_id_ns = stdout_zns_id_ns, + .zns_report_zones = stdout_zns_report_zones, + .show_feature = stdout_feature_show, + .show_feature_fields = stdout_feature_show_fields, + .id_ctrl_rpmbs = stdout_id_ctrl_rpmbs, + .lba_range = stdout_lba_range, + .lba_status_info = stdout_lba_status_info, + .d = stdout_d, + .show_init = NULL, + .show_finish = NULL, + + /* libnvme tree print functions */ + .list_item = stdout_list_item, + .list_items = stdout_list_items, + .print_nvme_subsystem_list = stdout_subsystem_list, + .topology_ctrl = stdout_topology_ctrl, + .topology_namespace = stdout_topology_namespace, + + /* status and error messages */ + .connect_msg = stdout_connect_msg, + .show_message = stdout_message, + .show_perror = stdout_perror, + .show_status = stdout_status, + .show_error_status = stdout_error_status, +}; + +struct print_ops *nvme_get_stdout_print_ops(enum nvme_print_flags flags) +{ + stdout_print_ops.flags = flags; + return &stdout_print_ops; +} diff --git a/nvme-print.c b/nvme-print.c index 7deb216270..ba0b4acac7 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -6,48 +6,40 @@ #include #include #include -#include #include "nvme.h" #include "libnvme.h" #include "nvme-print.h" #include "nvme-models.h" #include "util/suffix.h" +#include "util/types.h" #include "common.h" -#define ABSOLUTE_ZERO_CELSIUS -273 +#define nvme_print(name, flags, ...) \ + do { \ + struct print_ops *ops = nvme_print_ops(flags); \ + if (ops && ops->name) \ + ops->name(__VA_ARGS__); \ + } while (false) -static inline long kelvin_to_celsius(long t) -{ - return t + ABSOLUTE_ZERO_CELSIUS; -} - -static const uint8_t zero_uuid[16] = { 0 }; -static const uint8_t invalid_uuid[16] = {[0 ... 15] = 0xff }; -static const char dash[100] = {[0 ... 99] = '-'}; - -struct nvme_bar_cap { - __u16 mqes; - __u8 ams_cqr; - __u8 to; - __u16 bps_css_nssrs_dstrd; - __u8 mpsmax_mpsmin; - __u8 rsvd_crms_nsss_cmbs_pmrs; -}; +#define nvme_print_output_format(name, ...) \ + nvme_print(name, nvme_is_output_format_json() ? JSON : NORMAL, ##__VA_ARGS__); -static long double int128_to_double(__u8 *data) +static struct print_ops *nvme_print_ops(enum nvme_print_flags flags) { - int i; - long double result = 0; + struct print_ops *ops = NULL; - for (i = 0; i < 16; i++) { - result *= 256; - result += data[15 - i]; - } - return result; + if (flags & JSON || nvme_is_output_format_json()) + ops = nvme_get_json_print_ops(flags); + else if (flags & BINARY) + ops = nvme_get_binary_print_ops(flags); + else + ops = nvme_get_stdout_print_ops(flags); + + return ops; } -static const char *nvme_ana_state_to_string(enum nvme_ana_state state) +const char *nvme_ana_state_to_string(enum nvme_ana_state state) { switch (state) { case NVME_ANA_STATE_OPTIMIZED: @@ -120,18 +112,7 @@ const char *nvme_cmd_to_string(int admin, __u8 opcode) return "Unknown"; } -static const char *fw_to_string(char *c) -{ - static char ret[9]; - int i; - - for (i = 0; i < 8; i++) - ret[i] = c[i] >= '!' && c[i] <= '~' ? c[i] : '.'; - ret[i] = '\0'; - return ret; -} - -static const char *get_sanitize_log_sstat_status_str(__u16 status) +const char *nvme_sstat_status_to_string(__u16 status) { switch (status & NVME_SANITIZE_SSTAT_STATUS_MASK) { case NVME_SANITIZE_SSTAT_STATUS_NEVER_SANITIZED: @@ -149,894 +130,13 @@ static const char *get_sanitize_log_sstat_status_str(__u16 status) } } -static void json_nvme_id_ns(struct nvme_id_ns *ns, bool cap_only) -{ - char nguid_buf[2 * sizeof(ns->nguid) + 1], - eui64_buf[2 * sizeof(ns->eui64) + 1]; - char *nguid = nguid_buf, *eui64 = eui64_buf; - struct json_object *root; - struct json_object *lbafs; - int i; - - long double nvmcap = int128_to_double(ns->nvmcap); - - root = json_create_object(); - - if (!cap_only) { - json_object_add_value_uint64(root, "nsze", le64_to_cpu(ns->nsze)); - json_object_add_value_uint64(root, "ncap", le64_to_cpu(ns->ncap)); - json_object_add_value_uint64(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); - if (!cap_only) - 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); - if (!cap_only) { - 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, "dlfeat", ns->dlfeat); - 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_double(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, "mssrl", le16_to_cpu(ns->mssrl)); - json_object_add_value_int(root, "mcl", le32_to_cpu(ns->mcl)); - json_object_add_value_int(root, "msrc", ns->msrc); - } - json_object_add_value_int(root, "nulbaf", ns->nulbaf); - - if (!cap_only) { - 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, - void (*vs)(__u8 *vs, struct json_object *root)) -{ - struct json_object *root; - struct json_object *psds; - - long double tnvmcap = int128_to_double(ctrl->tnvmcap); - long double unvmcap = int128_to_double(ctrl->unvmcap); - long double megcap = int128_to_double(ctrl->megcap); - long double maxdna = int128_to_double(ctrl->maxdna); - - char sn[sizeof(ctrl->sn) + 1], mn[sizeof(ctrl->mn) + 1], - fr[sizeof(ctrl->fr) + 1], subnqn[sizeof(ctrl->subnqn) + 1]; - __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, "nvmsr", ctrl->nvmsr); - json_object_add_value_int(root, "vwci", ctrl->vwci); - json_object_add_value_int(root, "mec", ctrl->mec); - json_object_add_value_int(root, "oacs", le16_to_cpu(ctrl->oacs)); - json_object_add_value_int(root, "acl", ctrl->acl); - json_object_add_value_int(root, "aerl", ctrl->aerl); - 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_double(root, "tnvmcap", tnvmcap); - json_object_add_value_double(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, "domainid", le16_to_cpu(ctrl->domainid)); - json_object_add_value_double(root, "megcap", megcap); - json_object_add_value_int(root, "sqes", ctrl->sqes); - json_object_add_value_int(root, "cqes", ctrl->cqes); - json_object_add_value_int(root, "maxcmd", le16_to_cpu(ctrl->maxcmd)); - 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, "icsvscc", ctrl->icsvscc); - json_object_add_value_int(root, "nwpc", ctrl->nwpc); - json_object_add_value_int(root, "acwu", le16_to_cpu(ctrl->acwu)); - json_object_add_value_int(root, "ocfs", le16_to_cpu(ctrl->ocfs)); - json_object_add_value_int(root, "sgls", le32_to_cpu(ctrl->sgls)); - json_object_add_value_double(root, "maxdna", maxdna); - json_object_add_value_int(root, "maxcna", le32_to_cpu(ctrl->maxcna)); - - if (strlen(subnqn)) - json_object_add_value_string(root, "subnqn", subnqn); - - 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, "fcatt", ctrl->fcatt); - json_object_add_value_int(root, "msdbd", ctrl->msdbd); - json_object_add_value_int(root, "ofcs", le16_to_cpu(ctrl->ofcs)); - - psds = json_create_array(); - json_object_add_value_array(root, "psds", psds); - - 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].mp)); - 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].enlat)); - json_object_add_value_uint(psd, "exit_lat", - le32_to_cpu(ctrl->psd[i].exlat)); - json_object_add_value_int(psd, "read_tput", - ctrl->psd[i].rrt); - json_object_add_value_int(psd, "read_lat", - ctrl->psd[i].rrl); - json_object_add_value_int(psd, "write_tput", - ctrl->psd[i].rwt); - json_object_add_value_int(psd, "write_lat", - ctrl->psd[i].rwl); - json_object_add_value_int(psd, "idle_power", - le16_to_cpu(ctrl->psd[i].idlp)); - json_object_add_value_int(psd, "idle_scale", - nvme_psd_power_scale(ctrl->psd[i].ips)); - json_object_add_value_int(psd, "active_power", - le16_to_cpu(ctrl->psd[i].actp)); - json_object_add_value_int(psd, "active_power_work", - ctrl->psd[i].apws & 0x7); - json_object_add_value_int(psd, "active_scale", - nvme_psd_power_scale(ctrl->psd[i].apws)); - - 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_object *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_uint64(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 >> 0x1)); - json_object_add_value_int(error, "phase_tag", - le16_to_cpu(err_log[i].status_field & 0x1)); - json_object_add_value_int(error, "parm_error_location", - le16_to_cpu(err_log[i].parm_error_location)); - json_object_add_value_uint64(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_uint64(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_resv_status *status, - int bytes, bool eds) -{ - struct json_object *root; - struct json_object *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 (!eds) { - /* - * if status buffer was too small, don't loop past the end of - * the buffer - */ - entries = (bytes - 24) / 24; - if (entries < regctl) - regctl = entries; - - 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_uint64(rc, "hostid", - le64_to_cpu(status->regctl_ds[i].hostid)); - json_object_add_value_uint64(rc, "rkey", - le64_to_cpu(status->regctl_ds[i].rkey)); - - json_array_add_value_object(rcs, rc); - } - } else { - char hostid[33]; - - /* if status buffer was too small, don't loop past the end of the buffer */ - entries = (bytes - 64) / 64; - if (entries < regctl) - regctl = entries; - - 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(status->regctl_eds[i].cntlid)); - json_object_add_value_int(rc, "rcsts", - status->regctl_eds[i].rcsts); - json_object_add_value_uint64(rc, "rkey", - le64_to_cpu(status->regctl_eds[i].rkey)); - for (j = 0; j < 16; j++) - sprintf(hostid + j * 2, "%02x", - status->regctl_eds[i].hostid[j]); - - 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_slot *fw_log, const char *devname) -{ - struct json_object *root; - struct json_object *fwsi; - char fmt[21]; - char str[32]; - int i; - __le64 *frs; - - 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][0]) { - snprintf(fmt, sizeof(fmt), "Firmware Rev Slot %d", - i + 1); - frs = (__le64 *)&fw_log->frs[i]; - snprintf(str, sizeof(str), "%"PRIu64" (%s)", - le64_to_cpu(*frs), - 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_ns_list *log, - const char *devname) -{ - struct json_object *root; - struct json_object *nsi; - char fmt[32]; - char str[32]; - __u32 nsid; - int i; - - if (log->ns[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_ID_NS_LIST_MAX; i++) { - nsid = le32_to_cpu(log->ns[i]); - - if (nsid == 0) - break; - - snprintf(fmt, sizeof(fmt), "[%4u]", i + 1); - snprintf(str, sizeof(str), "%#x", nsid); - 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_double(root, "endurance_estimate", - endurance_estimate); - json_object_add_value_double(root, "data_units_read", data_units_read); - json_object_add_value_double(root, "data_units_written", - data_units_written); - json_object_add_value_double(root, "mediate_write_commands", - media_units_written); - json_object_add_value_double(root, "host_read_cmds", host_read_cmds); - json_object_add_value_double(root, "host_write_cmds", host_write_cmds); - json_object_add_value_double(root, "media_data_integrity_err", - media_data_integrity_err); - json_object_add_value_double(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_double(root, "data_units_read", data_units_read); - json_object_add_value_double(root, "data_units_written", - data_units_written); - json_object_add_value_double(root, "host_read_commands", - host_read_commands); - json_object_add_value_double(root, "host_write_commands", - host_write_commands); - json_object_add_value_double(root, "controller_busy_time", - controller_busy_time); - json_object_add_value_double(root, "power_cycles", power_cycles); - json_object_add_value_double(root, "power_on_hours", power_on_hours); - json_object_add_value_double(root, "unsafe_shutdowns", unsafe_shutdowns); - json_object_add_value_double(root, "media_errors", media_errors); - json_object_add_value_double(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_log *ana_log, const char *devname) -{ - int offset = sizeof(struct nvme_ana_log); - struct nvme_ana_log *hdr = ana_log; - struct nvme_ana_group_desc *ana_desc; - struct json_object *desc_list; - struct json_object *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, - "Asymmetric Namespace Access Log for NVMe device", - devname); - json_object_add_value_uint64(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, __u8 dst_entries) -{ - struct json_object *valid_attrs; - struct json_object *root; - struct json_object *valid; - int i; - __u32 num_entries; - - root = json_create_object(); - json_object_add_value_int(root, "Current Device Self-Test Operation", - self_test->current_operation); - json_object_add_value_int(root, "Current Device Self-Test Completion", - self_test->completion); - valid = json_create_array(); - - num_entries = min(dst_entries, NVME_LOG_ST_MAX_RESULTS); - for (i = 0; i < num_entries; i++) { - valid_attrs = json_create_object(); - json_object_add_value_int(valid_attrs, "Self test result", - self_test->result[i].dsts & 0xf); - 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_uint64(valid_attrs, "Power on hours", - le64_to_cpu(self_test->result[i].poh)); - if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_NSID) - 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_DIAG_INFO_FLBA) { - json_object_add_value_uint64(valid_attrs, "Failing LBA", - le64_to_cpu(self_test->result[i].flba)); - } - if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SCT) - json_object_add_value_int(valid_attrs, "Status Code Type", - self_test->result[i].sct); - if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_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); -} - -struct json_object* json_effects_log(enum nvme_csi csi, - struct nvme_cmd_effects_log *effects_log) -{ - struct json_object *root; - struct json_object *acs; - struct json_object *iocs; - unsigned int opcode; - char key[128]; - __u32 effect; - - root = json_create_object(); - json_object_add_value_uint(root, "command_set_identifier", csi); - - acs = json_create_object(); - for (opcode = 0; opcode < 256; opcode++) { - effect = le32_to_cpu(effects_log->acs[opcode]); - if (effect & NVME_CMD_EFFECTS_CSUPP) { - sprintf(key, "ACS_%u (%s)", opcode, - nvme_cmd_to_string(1, opcode)); - json_object_add_value_uint(acs, key, effect); - } - } - - json_object_add_value_object(root, "admin_cmd_set", acs); - - iocs = json_create_object(); - for (opcode = 0; opcode < 256; opcode++) { - effect = le32_to_cpu(effects_log->iocs[opcode]); - if (effect & NVME_CMD_EFFECTS_CSUPP) { - sprintf(key, "IOCS_%u (%s)", opcode, - nvme_cmd_to_string(0, opcode)); - json_object_add_value_uint(iocs, key, effect); - } - } - - json_object_add_value_object(root, "io_cmd_set", iocs); - return root; -} - -void json_effects_log_list(struct list_head *list) { - struct json_object *json_list; - nvme_effects_log_node_t *node; - - json_list = json_create_array(); - - list_for_each(list, node, node) { - struct json_object *json_page = - json_effects_log(node->csi, &node->effects); - json_array_add_value_object(json_list, json_page); - } - - json_print_object(json_list, NULL); - printf("\n"); - json_free_object(json_list); -} - -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->sstat); - - root = json_create_object(); - dev = json_create_object(); - sstat = json_create_object(); - - json_object_add_value_int(dev, "sprog", - le16_to_cpu(sanitize_log->sprog)); - json_object_add_value_int(sstat, "global_erased", - (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED) >> 8); - json_object_add_value_int(sstat, "no_cmplted_passes", - (status >> NVME_SANITIZE_SSTAT_COMPLETED_PASSES_SHIFT) & - NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK); - - status_str = get_sanitize_log_sstat_status_str(status); - sprintf(str, "(%d) %s", status & NVME_SANITIZE_SSTAT_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->scdw10)); - json_object_add_value_uint(dev, "time_over_write", - le32_to_cpu(sanitize_log->eto)); - json_object_add_value_uint(dev, "time_block_erase", - le32_to_cpu(sanitize_log->etbe)); - json_object_add_value_uint(dev, "time_crypto_erase", - le32_to_cpu(sanitize_log->etce)); - - json_object_add_value_uint(dev, "time_over_write_no_dealloc", - le32_to_cpu(sanitize_log->etond)); - json_object_add_value_uint(dev, "time_block_erase_no_dealloc", - le32_to_cpu(sanitize_log->etbend)); - json_object_add_value_uint(dev, "time_crypto_erase_no_dealloc", - le32_to_cpu(sanitize_log->etcend)); - - json_object_add_value_object(root, devname, dev); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -static void json_predictable_latency_per_nvmset( - struct nvme_nvmset_predictable_lat_log *plpns_log, - __u16 nvmset_id) -{ - struct json_object *root; - - root = json_create_object(); - json_object_add_value_uint(root, "nvmset_id", - le16_to_cpu(nvmset_id)); - json_object_add_value_uint(root, "status", - plpns_log->status); - json_object_add_value_uint(root, "event_type", - le16_to_cpu(plpns_log->event_type)); - json_object_add_value_uint64(root, "dtwin_reads_typical", - le64_to_cpu(plpns_log->dtwin_rt)); - json_object_add_value_uint64(root, "dtwin_writes_typical", - le64_to_cpu(plpns_log->dtwin_wt)); - json_object_add_value_uint64(root, "dtwin_time_maximum", - le64_to_cpu(plpns_log->dtwin_tmax)); - json_object_add_value_uint64(root, "ndwin_time_minimum_high", - le64_to_cpu(plpns_log->ndwin_tmin_hi)); - json_object_add_value_uint64(root, "ndwin_time_minimum_low", - le64_to_cpu(plpns_log->ndwin_tmin_lo)); - json_object_add_value_uint64(root, "dtwin_reads_estimate", - le64_to_cpu(plpns_log->dtwin_re)); - json_object_add_value_uint64(root, "dtwin_writes_estimate", - le64_to_cpu(plpns_log->dtwin_we)); - json_object_add_value_uint64(root, "dtwin_time_estimate", - le64_to_cpu(plpns_log->dtwin_te)); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - void nvme_show_predictable_latency_per_nvmset( struct nvme_nvmset_predictable_lat_log *plpns_log, __u16 nvmset_id, const char *devname, enum nvme_print_flags flags) { - if (flags & BINARY) - return d_raw((unsigned char *)plpns_log, - sizeof(*plpns_log)); - if (flags & JSON) - return json_predictable_latency_per_nvmset(plpns_log, - nvmset_id); - - printf("Predictable Latency Per NVM Set Log for device: %s\n", - devname); - printf("Predictable Latency Per NVM Set Log for NVM Set ID: %u\n", - le16_to_cpu(nvmset_id)); - printf("Status: %u\n", plpns_log->status); - printf("Event Type: %u\n", - le16_to_cpu(plpns_log->event_type)); - printf("DTWIN Reads Typical: %"PRIu64"\n", - le64_to_cpu(plpns_log->dtwin_rt)); - printf("DTWIN Writes Typical: %"PRIu64"\n", - le64_to_cpu(plpns_log->dtwin_wt)); - printf("DTWIN Time Maximum: %"PRIu64"\n", - le64_to_cpu(plpns_log->dtwin_tmax)); - printf("NDWIN Time Minimum High: %"PRIu64" \n", - le64_to_cpu(plpns_log->ndwin_tmin_hi)); - printf("NDWIN Time Minimum Low: %"PRIu64"\n", - le64_to_cpu(plpns_log->ndwin_tmin_lo)); - printf("DTWIN Reads Estimate: %"PRIu64"\n", - le64_to_cpu(plpns_log->dtwin_re)); - printf("DTWIN Writes Estimate: %"PRIu64"\n", - le64_to_cpu(plpns_log->dtwin_we)); - printf("DTWIN Time Estimate: %"PRIu64"\n\n\n", - le64_to_cpu(plpns_log->dtwin_te)); -} - -static void json_predictable_latency_event_agg_log( - struct nvme_aggregate_predictable_lat_event *pea_log, - __u64 log_entries) -{ - struct json_object *root; - struct json_object *valid_attrs; - struct json_object *valid; - __u64 num_iter; - __u64 num_entries; - - root = json_create_object(); - num_entries = le64_to_cpu(pea_log->num_entries); - json_object_add_value_uint64(root, "num_entries_avail", - num_entries); - valid = json_create_array(); - - num_iter = min(num_entries, log_entries); - for (int i = 0; i < num_iter; i++) { - valid_attrs = json_create_object(); - json_object_add_value_uint(valid_attrs, "entry", - le16_to_cpu(pea_log->entries[i])); - json_array_add_value_object(valid, valid_attrs); - } - json_object_add_value_array(root, "list_of_entries", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(predictable_latency_per_nvmset, flags, + plpns_log, nvmset_id, devname); } void nvme_show_predictable_latency_event_agg_log( @@ -1044,27 +144,8 @@ void nvme_show_predictable_latency_event_agg_log( __u64 log_entries, __u32 size, const char *devname, enum nvme_print_flags flags) { - __u64 num_iter; - __u64 num_entries; - - if (flags & BINARY) - return d_raw((unsigned char *)pea_log, size); - if (flags & JSON) - return json_predictable_latency_event_agg_log(pea_log, - log_entries); - - num_entries = le64_to_cpu(pea_log->num_entries); - printf("Predictable Latency Event Aggregate Log for"\ - " device: %s\n", devname); - - printf("Number of Entries Available: %"PRIu64"\n", - (uint64_t)num_entries); - - num_iter = min(num_entries, log_entries); - for (int i = 0; i < num_iter; i++) { - printf("Entry[%d]: %u\n", i + 1, - le16_to_cpu(pea_log->entries[i])); - } + nvme_print(predictable_latency_event_agg_log, flags, + pea_log, log_entries, size, devname); } const char *nvme_pel_event_to_string(int type) @@ -1087,7 +168,7 @@ const char *nvme_pel_event_to_string(int type) } } -static const char *nvme_show_nss_hw_error(__u16 error_code) +const char *nvme_nss_hw_error_to_string(__u16 error_code) { switch (error_code) { case 0x01: @@ -1117,678 +198,12 @@ static const char *nvme_show_nss_hw_error(__u16 error_code) } } -static void add_bitmap(int i, __u8 seb, struct json_object *root, int json_flag) -{ - char evt_str[50]; - char key[128]; - - for (int bit = 0; bit < 8; bit++) { - if (nvme_pel_event_to_string(bit + i * 8)) { - if (json_flag == 1) { - sprintf(key, "bitmap_%x", (bit + i * 8)); - if ((seb >> bit) & 0x1) - snprintf(evt_str, sizeof(evt_str), "Support %s", - nvme_pel_event_to_string(bit + i * 8)); - json_object_add_value_string(root, key, evt_str); - } else { - if (nvme_pel_event_to_string(bit + i * 8)) - if ((seb >> bit) & 0x1) - printf(" Support %s\n", - nvme_pel_event_to_string(bit + i * 8)); - } - } - } -} - -static void json_persistent_event_log(void *pevent_log_info, __u32 size) -{ - struct json_object *root; - struct json_object *valid_attrs; - struct json_object *valid; - __u32 offset, por_info_len, por_info_list; - __u64 *fw_rev; - char key[128]; - char fw_str[50]; - - struct nvme_smart_log *smart_event; - struct nvme_fw_commit_event *fw_commit_event; - struct nvme_time_stamp_change_event *ts_change_event; - struct nvme_power_on_reset_info_list *por_event; - struct nvme_nss_hw_err_event *nss_hw_err_event; - struct nvme_change_ns_event *ns_event; - struct nvme_format_nvm_start_event *format_start_event; - struct nvme_format_nvm_compln_event *format_cmpln_event; - struct nvme_sanitize_start_event *sanitize_start_event; - struct nvme_sanitize_compln_event *sanitize_cmpln_event; - struct nvme_thermal_exc_event *thermal_exc_event; - struct nvme_persistent_event_log *pevent_log_head; - struct nvme_persistent_event_entry *pevent_entry_head; - - root = json_create_object(); - valid = json_create_array(); - - offset = sizeof(*pevent_log_head); - if (size >= offset) { - pevent_log_head = pevent_log_info; - char sn[sizeof(pevent_log_head->sn) + 1], - mn[sizeof(pevent_log_head->mn) + 1], - subnqn[sizeof(pevent_log_head->subnqn) + 1]; - - snprintf(sn, sizeof(sn), "%-.*s", - (int)sizeof(pevent_log_head->sn), pevent_log_head->sn); - snprintf(mn, sizeof(mn), "%-.*s", - (int)sizeof(pevent_log_head->mn), pevent_log_head->mn); - snprintf(subnqn, sizeof(subnqn), "%-.*s", - (int)sizeof(pevent_log_head->subnqn), pevent_log_head->subnqn); - - json_object_add_value_uint(root, "log_id", - pevent_log_head->lid); - json_object_add_value_uint(root, "total_num_of_events", - le32_to_cpu(pevent_log_head->tnev)); - json_object_add_value_uint64(root, "total_log_len", - le64_to_cpu(pevent_log_head->tll)); - json_object_add_value_uint(root, "log_revision", - pevent_log_head->rv); - json_object_add_value_uint(root, "log_header_len", - le16_to_cpu(pevent_log_head->lhl)); - json_object_add_value_uint64(root, "timestamp", - le64_to_cpu(pevent_log_head->ts)); - json_object_add_value_double(root, "power_on_hours", - int128_to_double(pevent_log_head->poh)); - json_object_add_value_uint64(root, "power_cycle_count", - le64_to_cpu(pevent_log_head->pcc)); - json_object_add_value_uint(root, "pci_vid", - le16_to_cpu(pevent_log_head->vid)); - json_object_add_value_uint(root, "pci_ssvid", - le16_to_cpu(pevent_log_head->ssvid)); - json_object_add_value_string(root, "sn", sn); - json_object_add_value_string(root, "mn", mn); - json_object_add_value_string(root, "subnqn", subnqn); - json_object_add_value_uint(root, "gen_number", - le16_to_cpu(pevent_log_head->gen_number)); - json_object_add_value_uint(root, "rci", - le32_to_cpu(pevent_log_head->rci)); - for (int i = 0; i < 32; i++) { - if (pevent_log_head->seb[i] == 0) - continue; - add_bitmap(i, pevent_log_head->seb[i], root, 1); - } - } else { - printf("No log data can be shown with this log len at least " \ - "512 bytes is required or can be 0 to read the complete "\ - "log page after context established\n"); - return; - } - for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) { - if (offset + sizeof(*pevent_entry_head) >= size) - break; - - pevent_entry_head = pevent_log_info + offset; - - if ((offset + pevent_entry_head->ehl + 3 + - le16_to_cpu(pevent_entry_head->el)) >= size) - break; - valid_attrs = json_create_object(); - - json_object_add_value_uint(valid_attrs, "event_number", i); - json_object_add_value_string(valid_attrs, "event_type", - nvme_pel_event_to_string(pevent_entry_head->etype)); - json_object_add_value_uint(valid_attrs, "event_type_rev", - pevent_entry_head->etype_rev); - json_object_add_value_uint(valid_attrs, "event_header_len", - pevent_entry_head->ehl); - json_object_add_value_uint(valid_attrs, "event_header_additional_info", - pevent_entry_head->ehai); - json_object_add_value_uint(valid_attrs, "ctrl_id", - le16_to_cpu(pevent_entry_head->cntlid)); - json_object_add_value_uint64(valid_attrs, "event_time_stamp", - le64_to_cpu(pevent_entry_head->ets)); - json_object_add_value_uint(valid_attrs, "port_id", - le16_to_cpu(pevent_entry_head->pelpid)); - json_object_add_value_uint(valid_attrs, "vu_info_len", - le16_to_cpu(pevent_entry_head->vsil)); - json_object_add_value_uint(valid_attrs, "event_len", - le16_to_cpu(pevent_entry_head->el)); - - offset += pevent_entry_head->ehl + 3; - - switch (pevent_entry_head->etype) { - case NVME_PEL_SMART_HEALTH_EVENT: - smart_event = pevent_log_info + offset; - unsigned int temperature = ((smart_event->temperature[1] << 8) | - smart_event->temperature[0]); - - long double data_units_read = int128_to_double(smart_event->data_units_read); - long double data_units_written = int128_to_double(smart_event->data_units_written); - long double host_read_commands = int128_to_double(smart_event->host_reads); - long double host_write_commands = int128_to_double(smart_event->host_writes); - long double controller_busy_time = int128_to_double(smart_event->ctrl_busy_time); - long double power_cycles = int128_to_double(smart_event->power_cycles); - long double power_on_hours = int128_to_double(smart_event->power_on_hours); - long double unsafe_shutdowns = int128_to_double(smart_event->unsafe_shutdowns); - long double media_errors = int128_to_double(smart_event->media_errors); - long double num_err_log_entries = int128_to_double(smart_event->num_err_log_entries); - json_object_add_value_int(valid_attrs, "critical_warning", - smart_event->critical_warning); - - json_object_add_value_int(valid_attrs, "temperature", - temperature); - json_object_add_value_int(valid_attrs, "avail_spare", - smart_event->avail_spare); - json_object_add_value_int(valid_attrs, "spare_thresh", - smart_event->spare_thresh); - json_object_add_value_int(valid_attrs, "percent_used", - smart_event->percent_used); - json_object_add_value_int(valid_attrs, - "endurance_grp_critical_warning_summary", - smart_event->endu_grp_crit_warn_sumry); - json_object_add_value_double(valid_attrs, "data_units_read", - data_units_read); - json_object_add_value_double(valid_attrs, "data_units_written", - data_units_written); - json_object_add_value_double(valid_attrs, "host_read_commands", - host_read_commands); - json_object_add_value_double(valid_attrs, "host_write_commands", - host_write_commands); - json_object_add_value_double(valid_attrs, "controller_busy_time", - controller_busy_time); - json_object_add_value_double(valid_attrs, "power_cycles", - power_cycles); - json_object_add_value_double(valid_attrs, "power_on_hours", - power_on_hours); - json_object_add_value_double(valid_attrs, "unsafe_shutdowns", - unsafe_shutdowns); - json_object_add_value_double(valid_attrs, "media_errors", - media_errors); - json_object_add_value_double(valid_attrs, "num_err_log_entries", - num_err_log_entries); - json_object_add_value_uint(valid_attrs, "warning_temp_time", - le32_to_cpu(smart_event->warning_temp_time)); - json_object_add_value_uint(valid_attrs, "critical_comp_time", - le32_to_cpu(smart_event->critical_comp_time)); - - for (int c = 0; c < 8; c++) { - __s32 temp = le16_to_cpu(smart_event->temp_sensor[c]); - if (temp == 0) - continue; - sprintf(key, "temperature_sensor_%d",c + 1); - json_object_add_value_int(valid_attrs, key, temp); - } - - json_object_add_value_uint(valid_attrs, "thm_temp1_trans_count", - le32_to_cpu(smart_event->thm_temp1_trans_count)); - json_object_add_value_uint(valid_attrs, "thm_temp2_trans_count", - le32_to_cpu(smart_event->thm_temp2_trans_count)); - json_object_add_value_uint(valid_attrs, "thm_temp1_total_time", - le32_to_cpu(smart_event->thm_temp1_total_time)); - json_object_add_value_uint(valid_attrs, "thm_temp2_total_time", - le32_to_cpu(smart_event->thm_temp2_total_time)); - break; - case NVME_PEL_FW_COMMIT_EVENT: - fw_commit_event = pevent_log_info + offset; - snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", - le64_to_cpu(fw_commit_event->old_fw_rev), - fw_to_string((char *)&fw_commit_event->old_fw_rev)); - json_object_add_value_string(valid_attrs, "old_fw_rev", fw_str); - snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", - le64_to_cpu(fw_commit_event->new_fw_rev), - fw_to_string((char *)&fw_commit_event->new_fw_rev)); - json_object_add_value_string(valid_attrs, "new_fw_rev", fw_str); - json_object_add_value_uint(valid_attrs, "fw_commit_action", - fw_commit_event->fw_commit_action); - json_object_add_value_uint(valid_attrs, "fw_slot", - fw_commit_event->fw_slot); - json_object_add_value_uint(valid_attrs, "sct_fw", - fw_commit_event->sct_fw); - json_object_add_value_uint(valid_attrs, "sc_fw", - fw_commit_event->sc_fw); - json_object_add_value_uint(valid_attrs, - "vu_assign_fw_commit_rc", - le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); - break; - case NVME_PEL_TIMESTAMP_EVENT: - ts_change_event = pevent_log_info + offset; - json_object_add_value_uint64(valid_attrs, "prev_ts", - le64_to_cpu(ts_change_event->previous_timestamp)); - json_object_add_value_uint64(valid_attrs, - "ml_secs_since_reset", - le64_to_cpu(ts_change_event->ml_secs_since_reset)); - break; - case NVME_PEL_POWER_ON_RESET_EVENT: - por_info_len = (le16_to_cpu(pevent_entry_head->el) - - le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev)); - - por_info_list = por_info_len / sizeof(*por_event); - - fw_rev = pevent_log_info + offset; - snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", - le64_to_cpu(*fw_rev), - fw_to_string((char *)fw_rev)); - json_object_add_value_string(valid_attrs, "fw_rev", fw_str); - for (int i = 0; i < por_info_list; i++) { - por_event = pevent_log_info + offset + - sizeof(*fw_rev) + i * sizeof(*por_event); - json_object_add_value_uint(valid_attrs, "ctrl_id", - le16_to_cpu(por_event->cid)); - json_object_add_value_uint(valid_attrs, "fw_act", - por_event->fw_act); - json_object_add_value_uint(valid_attrs, "op_in_prog", - por_event->op_in_prog); - json_object_add_value_uint(valid_attrs, "ctrl_power_cycle", - le32_to_cpu(por_event->ctrl_power_cycle)); - json_object_add_value_uint64(valid_attrs, "power_on_ml_secs", - le64_to_cpu(por_event->power_on_ml_seconds)); - json_object_add_value_uint64(valid_attrs, "ctrl_time_stamp", - le64_to_cpu(por_event->ctrl_time_stamp)); - } - break; - case NVME_PEL_NSS_HW_ERROR_EVENT: - nss_hw_err_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "nss_hw_err_code", - le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code)); - break; - case NVME_PEL_CHANGE_NS_EVENT: - ns_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "nsmgt_cdw10", - le32_to_cpu(ns_event->nsmgt_cdw10)); - json_object_add_value_uint64(valid_attrs, "nsze", - le64_to_cpu(ns_event->nsze)); - json_object_add_value_uint64(valid_attrs, "nscap", - le64_to_cpu(ns_event->nscap)); - json_object_add_value_uint(valid_attrs, "flbas", - ns_event->flbas); - json_object_add_value_uint(valid_attrs, "dps", - ns_event->dps); - json_object_add_value_uint(valid_attrs, "nmic", - ns_event->nmic); - json_object_add_value_uint(valid_attrs, "ana_grp_id", - le32_to_cpu(ns_event->ana_grp_id)); - json_object_add_value_uint(valid_attrs, "nvmset_id", - le16_to_cpu(ns_event->nvmset_id)); - json_object_add_value_uint(valid_attrs, "nsid", - le32_to_cpu(ns_event->nsid)); - break; - case NVME_PEL_FORMAT_START_EVENT: - format_start_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "nsid", - le32_to_cpu(format_start_event->nsid)); - json_object_add_value_uint(valid_attrs, "fna", - format_start_event->fna); - json_object_add_value_uint(valid_attrs, "format_nvm_cdw10", - le32_to_cpu(format_start_event->format_nvm_cdw10)); - break; - case NVME_PEL_FORMAT_COMPLETION_EVENT: - format_cmpln_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "nsid", - le32_to_cpu(format_cmpln_event->nsid)); - json_object_add_value_uint(valid_attrs, "smallest_fpi", - format_cmpln_event->smallest_fpi); - json_object_add_value_uint(valid_attrs, "format_nvm_status", - format_cmpln_event->format_nvm_status); - json_object_add_value_uint(valid_attrs, "compln_info", - le16_to_cpu(format_cmpln_event->compln_info)); - json_object_add_value_uint(valid_attrs, "status_field", - le32_to_cpu(format_cmpln_event->status_field)); - break; - case NVME_PEL_SANITIZE_START_EVENT: - sanitize_start_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "SANICAP", - le32_to_cpu(sanitize_start_event->sani_cap)); - json_object_add_value_uint(valid_attrs, "sani_cdw10", - le32_to_cpu(sanitize_start_event->sani_cdw10)); - json_object_add_value_uint(valid_attrs, "sani_cdw11", - le32_to_cpu(sanitize_start_event->sani_cdw11)); - break; - case NVME_PEL_SANITIZE_COMPLETION_EVENT: - sanitize_cmpln_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "sani_prog", - le16_to_cpu(sanitize_cmpln_event->sani_prog)); - json_object_add_value_uint(valid_attrs, "sani_status", - le16_to_cpu(sanitize_cmpln_event->sani_status)); - json_object_add_value_uint(valid_attrs, "cmpln_info", - le16_to_cpu(sanitize_cmpln_event->cmpln_info)); - break; - case NVME_PEL_THERMAL_EXCURSION_EVENT: - thermal_exc_event = pevent_log_info + offset; - json_object_add_value_uint(valid_attrs, "over_temp", - thermal_exc_event->over_temp); - json_object_add_value_uint(valid_attrs, "threshold", - thermal_exc_event->threshold); - break; - } - - json_array_add_value_object(valid, valid_attrs); - offset += le16_to_cpu(pevent_entry_head->el); - } - - json_object_add_value_array(root, "list_of_event_entries", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -static void nvme_show_persistent_event_log_rci(__le32 pel_header_rci) -{ - __u32 rci = le32_to_cpu(pel_header_rci); - __u32 rsvd19 = (rci & 0xfff80000) >> 19; - __u8 rce = (rci & 0x40000) >> 18; - __u8 rcpit = (rci & 0x30000) >> 16; - __u16 rcpid = rci & 0xffff; - - if(rsvd19) - printf(" [31:19] : %#x\tReserved\n", rsvd19); - printf("\tReporting Context Exists (RCE): %s(%u)\n", - rce ? "true" : "false", rce); - printf("\tReporting Context Port Identifier Type (RCPIT): %u(%s)\n", rcpit, - (rcpit == 0x00) ? "Does not already exist" : - (rcpit == 0x01) ? "NVM subsystem port" : - (rcpit == 0x02) ? "NVMe-MI port" : "Reserved"); - printf("\tReporting Context Port Identifier (RCPID): %#x\n\n", rcpid); -} - -static void nvme_show_persistent_event_entry_ehai(__u8 ehai) -{ - __u8 rsvd1 = (ehai & 0xfc) >> 2; - __u8 pit = ehai & 0x03; - - printf(" [7:2] : %#x\tReserved\n", rsvd1); - printf("\tPort Identifier Type (PIT): %u(%s)\n", pit, - (pit == 0x00) ? "PIT not reported and PELPID does not apply" : - (pit == 0x01) ? "NVM subsystem port" : - (pit == 0x02) ? "NVMe-MI port" : - "Event not associated with any port and PELPID does not apply"); -} - void nvme_show_persistent_event_log(void *pevent_log_info, __u8 action, __u32 size, const char *devname, enum nvme_print_flags flags) { - __u32 offset, por_info_len, por_info_list; - __u64 *fw_rev; - int fid, cdw11, dword_cnt; - unsigned char *mem_buf = NULL; - struct nvme_smart_log *smart_event; - struct nvme_fw_commit_event *fw_commit_event; - struct nvme_time_stamp_change_event *ts_change_event; - struct nvme_power_on_reset_info_list *por_event; - struct nvme_nss_hw_err_event *nss_hw_err_event; - struct nvme_change_ns_event *ns_event; - struct nvme_format_nvm_start_event *format_start_event; - struct nvme_format_nvm_compln_event *format_cmpln_event; - struct nvme_sanitize_start_event *sanitize_start_event; - struct nvme_sanitize_compln_event *sanitize_cmpln_event; - struct nvme_set_feature_event *set_feat_event; - struct nvme_thermal_exc_event *thermal_exc_event; - struct nvme_persistent_event_log *pevent_log_head; - struct nvme_persistent_event_entry *pevent_entry_head; - - int human = flags & VERBOSE; - if (flags & BINARY) - return d_raw((unsigned char *)pevent_log_info, size); - if (flags & JSON) - return json_persistent_event_log(pevent_log_info, size); - - offset = sizeof(*pevent_log_head); - - printf("Persistent Event Log for device: %s\n", devname); - printf("Action for Persistent Event Log: %u\n", action); - if (size >= offset) { - pevent_log_head = pevent_log_info; - printf("Log Identifier: %u\n", pevent_log_head->lid); - printf("Total Number of Events: %u\n", - le32_to_cpu(pevent_log_head->tnev)); - printf("Total Log Length : %"PRIu64"\n", - le64_to_cpu(pevent_log_head->tll)); - printf("Log Revision: %u\n", pevent_log_head->rv); - printf("Log Header Length: %u\n", pevent_log_head->lhl); - printf("Timestamp: %"PRIu64"\n", - le64_to_cpu(pevent_log_head->ts)); - printf("Power On Hours (POH): %'.0Lf\n", - int128_to_double(pevent_log_head->poh)); - printf("Power Cycle Count: %"PRIu64"\n", - le64_to_cpu(pevent_log_head->pcc)); - printf("PCI Vendor ID (VID): %u\n", - le16_to_cpu(pevent_log_head->vid)); - printf("PCI Subsystem Vendor ID (SSVID): %u\n", - le16_to_cpu(pevent_log_head->ssvid)); - printf("Serial Number (SN): %-.*s\n", - (int)sizeof(pevent_log_head->sn), pevent_log_head->sn); - printf("Model Number (MN): %-.*s\n", - (int)sizeof(pevent_log_head->mn), pevent_log_head->mn); - printf("NVM Subsystem NVMe Qualified Name (SUBNQN): %-.*s\n", - (int)sizeof(pevent_log_head->subnqn), - pevent_log_head->subnqn); - printf("Generation Number: %u\n", - le16_to_cpu(pevent_log_head->gen_number)); - printf("Reporting Context Information (RCI): %u\n", - le32_to_cpu(pevent_log_head->rci)); - if (human) - nvme_show_persistent_event_log_rci(pevent_log_head->rci); - printf("Supported Events Bitmap: \n"); - for (int i = 0; i < 32; i++) { - if (pevent_log_head->seb[i] == 0) - continue; - add_bitmap(i, pevent_log_head->seb[i], NULL, 0); - } - } else { - printf("No log data can be shown with this log len at least " \ - "512 bytes is required or can be 0 to read the complete "\ - "log page after context established\n"); - return; - } - printf("\n"); - printf("\nPersistent Event Entries:\n"); - for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) { - if (offset + sizeof(*pevent_entry_head) >= size) - break; - - pevent_entry_head = pevent_log_info + offset; - - if ((offset + pevent_entry_head->ehl + 3 + - le16_to_cpu(pevent_entry_head->el)) >= size) - break; - printf("Event Number: %u\n", i); - printf("Event Type: %s\n", nvme_pel_event_to_string(pevent_entry_head->etype)); - printf("Event Type Revision: %u\n", pevent_entry_head->etype_rev); - printf("Event Header Length: %u\n", pevent_entry_head->ehl); - printf("Event Header Additional Info: %u\n", pevent_entry_head->ehai); - if (human) - nvme_show_persistent_event_entry_ehai(pevent_entry_head->ehai); - printf("Controller Identifier: %u\n", - le16_to_cpu(pevent_entry_head->cntlid)); - printf("Event Timestamp: %"PRIu64"\n", - le64_to_cpu(pevent_entry_head->ets)); - printf("Port Identifier: %u\n", - le16_to_cpu(pevent_entry_head->pelpid)); - printf("Vendor Specific Information Length: %u\n", - le16_to_cpu(pevent_entry_head->vsil)); - printf("Event Length: %u\n", le16_to_cpu(pevent_entry_head->el)); - - offset += pevent_entry_head->ehl + 3; - - switch (pevent_entry_head->etype) { - case NVME_PEL_SMART_HEALTH_EVENT: - smart_event = pevent_log_info + offset; - printf("Smart Health Event Entry: \n"); - nvme_show_smart_log(smart_event, NVME_NSID_ALL, devname, flags); - break; - case NVME_PEL_FW_COMMIT_EVENT: - fw_commit_event = pevent_log_info + offset; - printf("FW Commit Event Entry: \n"); - printf("Old Firmware Revision: %"PRIu64" (%s)\n", - le64_to_cpu(fw_commit_event->old_fw_rev), - fw_to_string((char *)&fw_commit_event->old_fw_rev)); - printf("New Firmware Revision: %"PRIu64" (%s)\n", - le64_to_cpu(fw_commit_event->new_fw_rev), - fw_to_string((char *)&fw_commit_event->new_fw_rev)); - printf("FW Commit Action: %u\n", - fw_commit_event->fw_commit_action); - printf("FW Slot: %u\n", fw_commit_event->fw_slot); - printf("Status Code Type for Firmware Commit Command: %u\n", - fw_commit_event->sct_fw); - printf("Status Returned for Firmware Commit Command: %u\n", - fw_commit_event->sc_fw); - printf("Vendor Assigned Firmware Commit Result Code: %u\n", - le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc)); - break; - case NVME_PEL_TIMESTAMP_EVENT: - ts_change_event = pevent_log_info + offset; - printf("Time Stamp Change Event Entry: \n"); - printf("Previous Timestamp: %"PRIu64"\n", - le64_to_cpu(ts_change_event->previous_timestamp)); - printf("Milliseconds Since Reset: %"PRIu64"\n", - le64_to_cpu(ts_change_event->ml_secs_since_reset)); - break; - case NVME_PEL_POWER_ON_RESET_EVENT: - por_info_len = (le16_to_cpu(pevent_entry_head->el) - - le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev)); - - por_info_list = por_info_len / sizeof(*por_event); - - printf("Power On Reset Event Entry: \n"); - fw_rev = pevent_log_info + offset; - printf("Firmware Revision: %"PRIu64" (%s)\n", le64_to_cpu(*fw_rev), - fw_to_string((char *)fw_rev)); - printf("Reset Information List: \n"); - - for (int i = 0; i < por_info_list; i++) { - por_event = pevent_log_info + offset + - sizeof(*fw_rev) + i * sizeof(*por_event); - printf("Controller ID: %u\n", le16_to_cpu(por_event->cid)); - printf("Firmware Activation: %u\n", - por_event->fw_act); - printf("Operation in Progress: %u\n", - por_event->op_in_prog); - printf("Controller Power Cycle: %u\n", - le32_to_cpu(por_event->ctrl_power_cycle)); - printf("Power on milliseconds: %"PRIu64"\n", - le64_to_cpu(por_event->power_on_ml_seconds)); - printf("Controller Timestamp: %"PRIu64"\n", - le64_to_cpu(por_event->ctrl_time_stamp)); - } - break; - case NVME_PEL_NSS_HW_ERROR_EVENT: - nss_hw_err_event = pevent_log_info + offset; - printf("NVM Subsystem Hardware Error Event Code Entry: %u, %s\n", - le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code), - nvme_show_nss_hw_error(nss_hw_err_event->nss_hw_err_event_code)); - break; - case NVME_PEL_CHANGE_NS_EVENT: - ns_event = pevent_log_info + offset; - printf("Change Namespace Event Entry: \n"); - printf("Namespace Management CDW10: %u\n", - le32_to_cpu(ns_event->nsmgt_cdw10)); - printf("Namespace Size: %"PRIu64"\n", - le64_to_cpu(ns_event->nsze)); - printf("Namespace Capacity: %"PRIu64"\n", - le64_to_cpu(ns_event->nscap)); - printf("Formatted LBA Size: %u\n", ns_event->flbas); - printf("End-to-end Data Protection Type Settings: %u\n", - ns_event->dps); - printf("Namespace Multi-path I/O and Namespace Sharing" \ - " Capabilities: %u\n", ns_event->nmic); - printf("ANA Group Identifier: %u\n", - le32_to_cpu(ns_event->ana_grp_id)); - printf("NVM Set Identifier: %u\n", le16_to_cpu(ns_event->nvmset_id)); - printf("Namespace ID: %u\n", le32_to_cpu(ns_event->nsid)); - break; - case NVME_PEL_FORMAT_START_EVENT: - format_start_event = pevent_log_info + offset; - printf("Format NVM Start Event Entry: \n"); - printf("Namespace Identifier: %u\n", - le32_to_cpu(format_start_event->nsid)); - printf("Format NVM Attributes: %u\n", - format_start_event->fna); - printf("Format NVM CDW10: %u\n", - le32_to_cpu(format_start_event->format_nvm_cdw10)); - break; - case NVME_PEL_FORMAT_COMPLETION_EVENT: - format_cmpln_event = pevent_log_info + offset; - printf("Format NVM Completion Event Entry: \n"); - printf("Namespace Identifier: %u\n", - le32_to_cpu(format_cmpln_event->nsid)); - printf("Smallest Format Progress Indicator: %u\n", - format_cmpln_event->smallest_fpi); - printf("Format NVM Status: %u\n", - format_cmpln_event->format_nvm_status); - printf("Completion Information: %u\n", - le16_to_cpu(format_cmpln_event->compln_info)); - printf("Status Field: %u\n", - le32_to_cpu(format_cmpln_event->status_field)); - break; - case NVME_PEL_SANITIZE_START_EVENT: - sanitize_start_event = pevent_log_info + offset; - printf("Sanitize Start Event Entry: \n"); - printf("SANICAP: %u\n", sanitize_start_event->sani_cap); - printf("Sanitize CDW10: %u\n", - le32_to_cpu(sanitize_start_event->sani_cdw10)); - printf("Sanitize CDW11: %u\n", - le32_to_cpu(sanitize_start_event->sani_cdw11)); - break; - case NVME_PEL_SANITIZE_COMPLETION_EVENT: - sanitize_cmpln_event = pevent_log_info + offset; - printf("Sanitize Completion Event Entry: \n"); - printf("Sanitize Progress: %u\n", - le16_to_cpu(sanitize_cmpln_event->sani_prog)); - printf("Sanitize Status: %u\n", - le16_to_cpu(sanitize_cmpln_event->sani_status)); - printf("Completion Information: %u\n", - le16_to_cpu(sanitize_cmpln_event->cmpln_info)); - break; - case NVME_PEL_SET_FEATURE_EVENT: - set_feat_event = pevent_log_info + offset; - printf("Set Feature Event Entry: \n"); - dword_cnt = set_feat_event->layout & 0x03; - fid = le32_to_cpu(set_feat_event->cdw_mem[0]) & 0x000f; - cdw11 = le32_to_cpu(set_feat_event->cdw_mem[1]); - - printf("Set Feature ID :%#02x (%s), value:%#08x\n", fid, - nvme_feature_to_string(fid), cdw11); - if (((set_feat_event->layout & 0xff) >> 2) != 0) { - mem_buf = (unsigned char *)(set_feat_event + 4 + dword_cnt * 4); - nvme_feature_show_fields(fid, cdw11, mem_buf); - } - break; - case NVME_PEL_TELEMETRY_CRT: - d(pevent_log_info + offset, 512, 16, 1); - break; - case NVME_PEL_THERMAL_EXCURSION_EVENT: - thermal_exc_event = pevent_log_info + offset; - printf("Thermal Excursion Event Entry: \n"); - printf("Over Temperature: %u\n", thermal_exc_event->over_temp); - printf("Threshold: %u\n", thermal_exc_event->threshold); - break; - default: - printf("Reserved Event\n\n"); - } - offset += le16_to_cpu(pevent_entry_head->el); - printf("\n"); - } -} - -void json_endurance_group_event_agg_log( - struct nvme_aggregate_predictable_lat_event *endurance_log, - __u64 log_entries) -{ - struct json_object *root; - struct json_object *valid_attrs; - struct json_object *valid; - - root = json_create_object(); - json_object_add_value_uint64(root, "num_entries_avail", - le64_to_cpu(endurance_log->num_entries)); - valid = json_create_array(); - - for (int i = 0; i < log_entries; i++) { - valid_attrs = json_create_object(); - json_object_add_value_uint(valid_attrs, "entry", - le16_to_cpu(endurance_log->entries[i])); - json_array_add_value_object(valid, valid_attrs); - } - json_object_add_value_array(root, "list_of_entries", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(persistent_event_log, flags, + pevent_log_info, action, size, devname); } void nvme_show_endurance_group_event_agg_log( @@ -1796,3364 +211,291 @@ void nvme_show_endurance_group_event_agg_log( __u64 log_entries, __u32 size, const char *devname, enum nvme_print_flags flags) { - - if (flags & BINARY) - return d_raw((unsigned char *)endurance_log, size); - if (flags & JSON) - return json_endurance_group_event_agg_log(endurance_log, - log_entries); - - printf("Endurance Group Event Aggregate Log for"\ - " device: %s\n", devname); - - printf("Number of Entries Available: %"PRIu64"\n", - le64_to_cpu(endurance_log->num_entries)); - - for (int i = 0; i < log_entries; i++) { - printf("Entry[%d]: %u\n", i + 1, - le16_to_cpu(endurance_log->entries[i])); - } -} - -static void json_lba_status_log(void *lba_status) -{ - struct json_object *root; - struct json_object *desc; - struct json_object *element; - struct json_object *desc_list; - struct json_object *elements_list; - struct nvme_lba_status_log *hdr; - struct nvme_lbas_ns_element *ns_element; - struct nvme_lba_rd *range_desc; - int offset = sizeof(*hdr); - __u32 num_lba_desc, num_elements; - - root = json_create_object(); - hdr = lba_status; - json_object_add_value_uint(root, "lslplen", le32_to_cpu(hdr->lslplen)); - num_elements = le32_to_cpu(hdr->nlslne); - json_object_add_value_uint(root, "nlslne", num_elements); - json_object_add_value_uint(root, "estulb", le32_to_cpu(hdr->estulb)); - json_object_add_value_uint(root, "lsgc", le16_to_cpu(hdr->lsgc)); - - elements_list = json_create_array(); - for (int ele = 0; ele < num_elements; ele++) { - ns_element = lba_status + offset; - element = json_create_object(); - json_object_add_value_uint(element, "neid", - le32_to_cpu(ns_element->neid)); - num_lba_desc = le32_to_cpu(ns_element->nlrd); - json_object_add_value_uint(element, "nlrd", num_lba_desc); - json_object_add_value_uint(element, "ratype", ns_element->ratype); - - offset += sizeof(*ns_element); - desc_list = json_create_array(); - if (num_lba_desc != 0xffffffff) { - for (int i = 0; i < num_lba_desc; i++) { - range_desc = lba_status + offset; - desc = json_create_object(); - json_object_add_value_uint64(desc, "rslba", - le64_to_cpu(range_desc->rslba)); - json_object_add_value_uint(desc, "rnlb", - le32_to_cpu(range_desc->rnlb)); - - offset += sizeof(*range_desc); - json_array_add_value_object(desc_list, desc); - } - } else { - printf("Number of LBA Range Descriptors (NLRD) set to %#x for " \ - "NS element %d", num_lba_desc, ele); - } - - json_object_add_value_array(element, "descs", desc_list); - json_array_add_value_object(elements_list, element); - } - - json_object_add_value_array(root, "ns_elements", elements_list); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(endurance_group_event_agg_log, flags, + endurance_log, log_entries, size, devname); } void nvme_show_lba_status_log(void *lba_status, __u32 size, const char *devname, enum nvme_print_flags flags) { - struct nvme_lba_status_log *hdr; - struct nvme_lbas_ns_element *ns_element; - struct nvme_lba_rd *range_desc; - int offset = sizeof(*hdr); - __u32 num_lba_desc, num_elements; - - if (flags & BINARY) - return d_raw((unsigned char *)lba_status, size); - if (flags & JSON) - return json_lba_status_log(lba_status); - - hdr = lba_status; - printf("LBA Status Log for device: %s\n", devname); - printf("LBA Status Log Page Length: %"PRIu32"\n", - le32_to_cpu(hdr->lslplen)); - num_elements = le32_to_cpu(hdr->nlslne); - printf("Number of LBA Status Log Namespace Elements: %"PRIu32"\n", - num_elements); - printf("Estimate of Unrecoverable Logical Blocks: %"PRIu32"\n", - le32_to_cpu(hdr->estulb)); - printf("LBA Status Generation Counter: %"PRIu16"\n", le16_to_cpu(hdr->lsgc)); - for (int ele = 0; ele < num_elements; ele++) { - ns_element = lba_status + offset; - printf("Namespace Element Identifier: %"PRIu32"\n", - le32_to_cpu(ns_element->neid)); - num_lba_desc = le32_to_cpu(ns_element->nlrd); - printf("Number of LBA Range Descriptors: %"PRIu32"\n", num_lba_desc); - printf("Recommended Action Type: %u\n", ns_element->ratype); - - offset += sizeof(*ns_element); - if (num_lba_desc != 0xffffffff) { - for (int i = 0; i < num_lba_desc; i++) { - range_desc = lba_status + offset; - printf("RSLBA[%d]: %"PRIu64"\n", i, - le64_to_cpu(range_desc->rslba)); - printf("RNLB[%d]: %"PRIu32"\n", i, - le32_to_cpu(range_desc->rnlb)); - offset += sizeof(*range_desc); - } - } else { - printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\ - "NS element %d\n", num_lba_desc, ele); - } - } + nvme_print(lba_status_log, flags, lba_status, size, devname); } -static const char *resv_notif_to_string(__u8 type) +const char *nvme_resv_notif_to_string(__u8 type) { switch (type) { - case 0x1: return "Empty Log Page"; - case 0x2: return "Registration Preempted"; - case 0x3: return "Reservation Released"; - case 0x4: return "Reservation Preempted"; + case 0x0: return "Empty Log Page"; + case 0x1: return "Registration Preempted"; + case 0x2: return "Reservation Released"; + case 0x3: return "Reservation Preempted"; default: return "Reserved"; } } -static void json_resv_notif_log(struct nvme_resv_notification_log *resv) -{ - struct json_object *root; - - root = json_create_object(); - json_object_add_value_uint64(root, "count", - le64_to_cpu(resv->lpc)); - json_object_add_value_uint(root, "rn_log_type", - resv->rnlpt); - json_object_add_value_uint(root, "num_logs", - resv->nalp); - json_object_add_value_uint(root, "nsid", - le32_to_cpu(resv->nsid)); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - void nvme_show_resv_notif_log(struct nvme_resv_notification_log *resv, const char *devname, enum nvme_print_flags flags) { - if (flags & BINARY) - return d_raw((unsigned char *)resv, sizeof(*resv)); - if (flags & JSON) - return json_resv_notif_log(resv); - - printf("Reservation Notif Log for device: %s\n", devname); - printf("Log Page Count : %"PRIx64"\n", - le64_to_cpu(resv->lpc)); - printf("Resv Notif Log Page Type : %u (%s)\n", - resv->rnlpt, - resv_notif_to_string(resv->rnlpt)); - printf("Num of Available Log Pages : %u\n", resv->nalp); - printf("Namespace ID: : %"PRIx32"\n", - le32_to_cpu(resv->nsid)); + nvme_print(resv_notification_log, flags, resv, devname); } -static void json_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log) +void nvme_show_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log, + const char *devname, enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *fids; - struct json_object *fids_list; - unsigned int fid; - char key[128]; - __u32 fid_support; - - root = json_create_object(); - fids_list = json_create_array(); - for (fid = 0; fid < 256; fid++) { - fid_support = le32_to_cpu(fid_log->fid_support[fid]); - if (fid_support & NVME_FID_SUPPORTED_EFFECTS_FSUPP) { - fids = json_create_object(); - sprintf(key, "fid_%u", fid); - json_object_add_value_uint(fids, key, fid_support); - json_array_add_value_object(fids_list, fids); - } - } - - json_object_add_value_object(root, "fid_support", fids_list); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(fid_supported_effects_log, flags, fid_log, devname); } -static void nvme_show_fid_support_effects_log_human(__u32 fid_support) +void nvme_show_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, + const char *devname, enum nvme_print_flags flags) { - const char *set = "+"; - const char *clr = "-"; - __u16 fsp; - - printf(" FSUPP+"); - printf(" UDCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_UDCC) ? set : clr); - printf(" NCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_NCC) ? set : clr); - printf(" NIC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_NIC) ? set : clr); - printf(" CCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_CCC) ? set : clr); - printf(" USS%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_UUID_SEL) ? set : clr); - - fsp = (fid_support >> NVME_FID_SUPPORTED_EFFECTS_SCOPE_SHIFT) & NVME_FID_SUPPORTED_EFFECTS_SCOPE_MASK; - - printf(" NAMESPACE SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NS) ? set : clr); - printf(" CONTROLLER SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_CTRL) ? set : clr); - printf(" NVM SET SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NVM_SET) ? set : clr); - printf(" ENDURANCE GROUP SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_ENDGRP) ? set : clr); - printf(" DOMAIN SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_DOMAIN) ? set : clr); - printf(" NVM Subsystem SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NSS) ? set : clr); + nvme_print(mi_cmd_support_effects_log, flags, + mi_cmd_log, devname); } -void nvme_show_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log, - const char *devname, enum nvme_print_flags flags) +void nvme_show_boot_part_log(void *bp_log, const char *devname, + __u32 size, enum nvme_print_flags flags) { - __u32 fid_effect; - int i, human = flags & VERBOSE; - - if (flags & BINARY) - return d_raw((unsigned char *)fid_log, sizeof(*fid_log)); - if (flags & JSON) - return json_fid_support_effects_log(fid_log); - - printf("FID Supports Effects Log for device: %s\n", devname); - printf("Admin Command Set\n"); - for (i = 0; i < 256; i++) { - fid_effect = le32_to_cpu(fid_log->fid_support[i]); - if (fid_effect & NVME_FID_SUPPORTED_EFFECTS_FSUPP) { - printf("FID %02x -> Support Effects Log: %08x", i, - fid_effect); - if (human) - nvme_show_fid_support_effects_log_human(fid_effect); - else - printf("\n"); - } - } + nvme_print(boot_part_log, flags, bp_log, devname, size); } -static void json_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log) +void nvme_show_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller, + enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *mi_cmds; - struct json_object *mi_cmds_list; - unsigned int mi_cmd; - char key[128]; - __u32 mi_cmd_support; - - root = json_create_object(); - mi_cmds_list = json_create_array(); - for (mi_cmd = 0; mi_cmd < 256; mi_cmd++) { - mi_cmd_support = le32_to_cpu(mi_cmd_log->mi_cmd_support[mi_cmd]); - if (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_CSUPP) { - mi_cmds = json_create_object(); - sprintf(key, "mi_cmd_%u", mi_cmd); - json_object_add_value_uint(mi_cmds, key, mi_cmd_support); - json_array_add_value_object(mi_cmds_list, mi_cmds); - } - } - - json_object_add_value_object(root, "mi_command_support", mi_cmds_list); - json_print_object(root, NULL); - printf("\n"); - - json_free_object(root); + nvme_print(phy_rx_eom_log, flags, log, controller); } -static void nvme_show_mi_cmd_support_effects_log_human(__u32 mi_cmd_support) +void nvme_show_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log, + enum nvme_print_flags flags) { - const char *set = "+"; - const char *clr = "-"; - __u16 csp; - - printf(" CSUPP+"); - printf(" UDCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_UDCC) ? set : clr); - printf(" NCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_NCC) ? set : clr); - printf(" NIC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_NIC) ? set : clr); - printf(" CCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_CCC) ? set : clr); - - csp = (mi_cmd_support >> NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_SHIFT) & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_MASK; - - printf(" NAMESPACE SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NS) ? set : clr); - printf(" CONTROLLER SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_CTRL) ? set : clr); - printf(" NVM SET SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NVM_SET) ? set : clr); - printf(" ENDURANCE GROUP SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_ENDGRP) ? set : clr); - printf(" DOMAIN SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_DOMAIN) ? set : clr); - printf(" NVM Subsystem SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NSS) ? set : clr); + nvme_print(media_unit_stat_log, flags, mus_log); } -void nvme_show_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, - const char *devname, enum nvme_print_flags flags) +void nvme_show_fdp_configs(struct nvme_fdp_config_log *log, size_t len, + enum nvme_print_flags flags) { - __u32 mi_cmd_effect; - int i, human = flags & VERBOSE; - - if (flags & BINARY) - return d_raw((unsigned char *)mi_cmd_log, sizeof(*mi_cmd_log)); - if (flags & JSON) - return json_mi_cmd_support_effects_log(mi_cmd_log); - - printf("MI Commands Support Effects Log for device: %s\n", devname); - printf("Admin Command Set\n"); - for (i = 0; i < NVME_LOG_MI_CMD_SUPPORTED_EFFECTS_MAX; i++) { - mi_cmd_effect = le32_to_cpu(mi_cmd_log->mi_cmd_support[i]); - if (mi_cmd_effect & NVME_MI_CMD_SUPPORTED_EFFECTS_CSUPP) { - printf("MI CMD %02x -> Support Effects Log: %08x", i, - mi_cmd_effect); - if (human) - nvme_show_mi_cmd_support_effects_log_human(mi_cmd_effect); - else - printf("\n"); - } - } + nvme_print(fdp_config_log, flags, log, len); } -static void json_boot_part_log(void *bp_log) +void nvme_show_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len, + enum nvme_print_flags flags) { - struct nvme_boot_partition *hdr; - struct json_object *root; - - hdr = bp_log; - root = json_create_object(); - - json_object_add_value_uint(root, "count", hdr->lid); - json_object_add_value_uint(root, "abpid", - (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1); - json_object_add_value_uint(root, "bpsz", - le32_to_cpu(hdr->bpinfo) & 0x7fff); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(fdp_usage_log, flags,log, len); } -void nvme_show_boot_part_log(void *bp_log, const char *devname, - __u32 size, enum nvme_print_flags flags) +void nvme_show_fdp_stats(struct nvme_fdp_stats_log *log, + enum nvme_print_flags flags) { - struct nvme_boot_partition *hdr; - if (flags & BINARY) - return d_raw((unsigned char *)bp_log, size); - if (flags & JSON) - return json_boot_part_log(bp_log); - - hdr = bp_log; - printf("Boot Partition Log for device: %s\n", devname); - printf("Log ID: %u\n", hdr->lid); - printf("Boot Partition Size: %u KiB\n", le32_to_cpu(hdr->bpinfo) & 0x7fff); - printf("Active BPID: %u\n", (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1); + nvme_print(fdp_stats_log, flags, log); } -static void json_media_unit_stat_log(struct nvme_media_unit_stat_log *mus) +const char *nvme_fdp_event_to_string(enum nvme_fdp_event_type event) { - struct json_object *root; - struct json_object *entries; - struct json_object *entry; - int i; - - root = json_create_object(); - entries = json_create_array(); - - json_object_add_value_uint(root, "nmu", le16_to_cpu(mus->nmu)); - json_object_add_value_uint(root, "cchans", le16_to_cpu(mus->cchans)); - json_object_add_value_uint(root, "sel_config", le16_to_cpu(mus->sel_config)); - - for (i = 0; i < mus->nmu; i++) { - entry = json_create_object(); - json_object_add_value_uint(entry, "muid", le16_to_cpu(mus->mus_desc[i].muid)); - json_object_add_value_uint(entry, "domainid", le16_to_cpu(mus->mus_desc[i].domainid)); - json_object_add_value_uint(entry, "endgid", le16_to_cpu(mus->mus_desc[i].endgid)); - json_object_add_value_uint(entry, "nvmsetid", le16_to_cpu(mus->mus_desc[i].nvmsetid)); - json_object_add_value_uint(entry, "cap_adj_fctr", le16_to_cpu(mus->mus_desc[i].cap_adj_fctr)); - json_object_add_value_uint(entry, "avl_spare", mus->mus_desc[i].avl_spare); - json_object_add_value_uint(entry, "percent_used", mus->mus_desc[i].percent_used); - json_object_add_value_uint(entry, "mucs", mus->mus_desc[i].mucs); - json_object_add_value_uint(entry, "cio", mus->mus_desc[i].cio); - json_array_add_value_object(entries, entry); + switch (event) { + case NVME_FDP_EVENT_RUNFW: return "Reclaim Unit Not Fully Written"; + case NVME_FDP_EVENT_RUTLE: return "Reclaim Unit Active Time Limit Exceeded"; + case NVME_FDP_EVENT_RESET: return "Controller Level Reset Modified Reclaim Unit Handles"; + case NVME_FDP_EVENT_PID: return "Invalid Placement Identifier"; + case NVME_FDP_EVENT_REALLOC: return "Media Reallocated"; + case NVME_FDP_EVENT_MODIFY: return "Implicitly Modified Reclaim Unit Handle"; } - json_object_add_value_array(root, "mus_list", entries); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + return "Unknown"; } -void nvme_show_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log, - enum nvme_print_flags flags) +void nvme_show_fdp_events(struct nvme_fdp_events_log *log, + enum nvme_print_flags flags) { - int i; - int nmu = le16_to_cpu(mus_log->nmu); - - if (flags & BINARY) - return d_raw((unsigned char *)mus_log, sizeof(*mus_log)); - else if (flags & JSON) - return json_media_unit_stat_log(mus_log); - - printf("Number of Media Unit Status Descriptors: %u\n", nmu); - printf("Number of Channels: %u\n", le16_to_cpu(mus_log->cchans)); - printf("Selected Configuration: %u\n", le16_to_cpu(mus_log->sel_config)); - for (i = 0; i < nmu; i++) { - printf("Media Unit Status Descriptor: %u\n", i); - printf("Media Unit Identifier: %u\n", - le16_to_cpu(mus_log->mus_desc[i].muid)); - printf("Domain Identifier: %u\n", - le16_to_cpu(mus_log->mus_desc[i].domainid)); - printf("Endurance Group Identifier: %u\n", - le16_to_cpu(mus_log->mus_desc[i].endgid)); - printf("NVM Set Identifier: %u\n", - le16_to_cpu(mus_log->mus_desc[i].nvmsetid)); - printf("Capacity Adjustment Factor: %u\n", - le16_to_cpu(mus_log->mus_desc[i].cap_adj_fctr)); - printf("Available Spare: %u\n", mus_log->mus_desc[i].avl_spare); - printf("Percentage Used: %u\n", mus_log->mus_desc[i].percent_used); - printf("Number of Channels: %u\n", mus_log->mus_desc[i].mucs); - printf("Channel Identifiers Offset: %u\n", mus_log->mus_desc[i].cio); - } + nvme_print(fdp_event_log, flags, log); } -static void json_supported_cap_config_log( - struct nvme_supported_cap_config_list_log *cap_log) +void nvme_show_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len, + enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *cap_list; - struct json_object *capacity; - struct json_object *end_list; - struct json_object *set_list; - struct json_object *set; - struct json_object *chan_list; - struct json_object *channel; - struct json_object *media_list; - struct json_object *media; - struct json_object *endurance; - struct nvme_end_grp_chan_desc *chan_desc; - int i, j, k, l, m, sccn, egcn, egsets, egchans, chmus; - - root = json_create_object(); - - json_object_add_value_uint(root, "sccn", cap_log->sccn); - cap_list = json_create_array(); - sccn = cap_log->sccn; - for (i = 0; i < sccn; i++) { - capacity = json_create_object(); - json_object_add_value_uint(capacity, "cap_config_id", - le16_to_cpu(cap_log->cap_config_desc[i].cap_config_id)); - json_object_add_value_uint(capacity, "domainid", - le16_to_cpu(cap_log->cap_config_desc[i].domainid)); - json_object_add_value_uint(capacity, "egcn", - le16_to_cpu(cap_log->cap_config_desc[i].egcn)); - end_list = json_create_array(); - egcn = le16_to_cpu(cap_log->cap_config_desc[i].egcn); - for (j = 0; j < egcn; j++) { - endurance = json_create_object(); - json_object_add_value_uint(endurance, "endgid", - le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].endgid)); - json_object_add_value_uint(endurance, "cap_adj_factor", - le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].cap_adj_factor)); - json_object_add_value_double(endurance, "tegcap", - int128_to_double(cap_log->cap_config_desc[i].egcd[j].tegcap)); - json_object_add_value_double(endurance, "segcap", - int128_to_double(cap_log->cap_config_desc[i].egcd[j].segcap)); - json_object_add_value_uint(endurance, "egsets", - le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].egsets)); - egsets = le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].egsets); - set_list = json_create_array(); - for (k = 0; k < egsets; k++) { - set = json_create_object(); - json_object_add_value_uint(set, "nvmsetid", - le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].nvmsetid[k])); - json_array_add_value_object(set_list, set); - } - chan_desc = (struct nvme_end_grp_chan_desc *) \ - ((cap_log->cap_config_desc[i].egcd[j].nvmsetid[0]) * (sizeof(__u16)*egsets)); - egchans = le16_to_cpu(chan_desc->egchans); - json_object_add_value_uint(endurance, "egchans", - le16_to_cpu(chan_desc->egchans)); - chan_list = json_create_array(); - for (l = 0; l < egchans; l++) { - channel = json_create_object(); - json_object_add_value_uint(channel, "chanid", - le16_to_cpu(chan_desc->chan_config_desc[l].chanid)); - json_object_add_value_uint(channel, "chmus", - le16_to_cpu(chan_desc->chan_config_desc[l].chmus)); - chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus); - media_list = json_create_array(); - for (m = 0; m < chmus; m++) { - media = json_create_object(); - json_object_add_value_uint(media, "chanid", - le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid)); - json_object_add_value_uint(media, "chmus", - le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].mudl)); - json_array_add_value_object(media_list, media); - } - json_object_add_value_array(channel, "Media Descriptor", media_list); - json_array_add_value_object(chan_list, channel); - } - json_object_add_value_array(endurance, "Channel Descriptor", chan_list); - json_object_add_value_array(endurance, "NVM Set IDs", set_list); - json_array_add_value_object(end_list, endurance); - } - json_object_add_value_array(capacity, "Endurance Descriptor", end_list); - json_array_add_value_object(cap_list, capacity); - } - - json_object_add_value_array(root, "Capacity Descriptor", cap_list); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(fdp_ruh_status, flags, status, len); } void nvme_show_supported_cap_config_log( struct nvme_supported_cap_config_list_log *cap, enum nvme_print_flags flags) { - struct nvme_end_grp_chan_desc *chan_desc; - int i, j, k, l, m, sccn, egcn, egsets, egchans, chmus; - - if (flags & BINARY) - return d_raw((unsigned char *)cap, sizeof(*cap)); - else if (flags & JSON) - return json_supported_cap_config_log(cap); - - sccn = cap->sccn; - printf("Number of Supported Capacity Configurations: %u\n", sccn); - for (i = 0; i < sccn; i++) { - printf("Capacity Configuration Descriptor: %u\n", i); - printf("Capacity Configuration Identifier: %u\n", - le16_to_cpu(cap->cap_config_desc[i].cap_config_id)); - printf("Domain Identifier: %u\n", - le16_to_cpu(cap->cap_config_desc[i].domainid)); - egcn = le16_to_cpu(cap->cap_config_desc[i].egcn); - printf("Number of Endurance Group Configuration Descriptors: %u\n", egcn); - for(j = 0; j < egcn; j++) { - printf("Endurance Group Identifier: %u\n", - le16_to_cpu(cap->cap_config_desc[i].egcd[j].endgid)); - printf("Capacity Adjustment Factor: %u\n", - le16_to_cpu(cap->cap_config_desc[i].egcd[j].cap_adj_factor)); - printf("Total Endurance Group Capacity: %'.0Lf\n", - int128_to_double(cap->cap_config_desc[i].egcd[j].tegcap)); - printf("Spare Endurance Group Capacity: %'.0Lf\n", - int128_to_double(cap->cap_config_desc[i].egcd[j].segcap)); - printf("Endurance Estimate: %'.0Lf\n", - int128_to_double(cap->cap_config_desc[i].egcd[j].end_est)); - egsets = le16_to_cpu(cap->cap_config_desc[i].egcd[j].egsets); - printf("Number of NVM Sets: %u\n", egsets); - for(k = 0; k < egsets; k++) { - printf("NVM Set %d Identifier: %u\n", i, - le16_to_cpu(cap->cap_config_desc[i].egcd[j].nvmsetid[k])); - } - chan_desc = (struct nvme_end_grp_chan_desc *) \ - ((cap->cap_config_desc[i].egcd[j].nvmsetid[0]) * (sizeof(__u16)*egsets)); - egchans = le16_to_cpu(chan_desc->egchans); - printf("Number of Channels: %u\n", egchans); - for(l = 0; l < egchans; l++) { - printf("Channel Identifier: %u\n", - le16_to_cpu(chan_desc->chan_config_desc[l].chanid)); - chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus); - printf("Number of Channel Media Units: %u\n", chmus); - for(m = 0; m < chmus; m++) { - printf("Media Unit Identifier: %u\n", - le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid)); - printf("Media Unit Descriptor Length: %u\n", - le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].mudl)); - } - } - } - } + nvme_print(supported_cap_config_list_log, flags, cap); } -static unsigned int nvme_show_subsystem_multipath(nvme_subsystem_t s, - bool show_ana) +void nvme_show_subsystem_list(nvme_root_t r, bool show_ana, + enum nvme_print_flags flags) { - nvme_ns_t n; - nvme_path_t p; - unsigned int i = 0; - - n = nvme_subsystem_first_ns(s); - if (!n) - return 0; - - nvme_namespace_for_each_path(n, p) { - nvme_ctrl_t c = nvme_path_get_ctrl(p); - const char *ana_state = ""; - - if (show_ana) - ana_state = nvme_path_get_ana_state(p); - - printf(" +- %s %s %s %s %s\n", - nvme_ctrl_get_name(c), - nvme_ctrl_get_transport(c), - nvme_ctrl_get_address(c), - nvme_ctrl_get_state(c), - ana_state); - i++; - } - - return i; + nvme_print(print_nvme_subsystem_list, flags, r, show_ana); } -static void nvme_show_subsystem_ctrls(nvme_subsystem_t s) +const char *nvme_register_szu_to_string(__u8 szu) { - nvme_ctrl_t c; - - nvme_subsystem_for_each_ctrl(s, c) { - printf(" +- %s %s %s %s\n", - nvme_ctrl_get_name(c), - nvme_ctrl_get_transport(c), - nvme_ctrl_get_address(c), - nvme_ctrl_get_state(c)); + 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_subsystem(nvme_root_t r, bool show_ana) +const char *nvme_register_pmr_hsts_to_string(__u8 hsts) { - nvme_host_t h; - - nvme_for_each_host(r, h) { - nvme_subsystem_t s; - - nvme_for_each_subsystem(h, s) { - printf("%s - NQN=%s\n", nvme_subsystem_get_name(s), - nvme_subsystem_get_nqn(s)); - printf("\\\n"); - - if (!nvme_show_subsystem_multipath(s, show_ana)) - nvme_show_subsystem_ctrls(s); - } + 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 unsigned int json_print_nvme_subsystem_multipath(nvme_subsystem_t s, - bool show_ana, - json_object *paths) +const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu) { - nvme_ns_t n; - nvme_path_t p; - unsigned int i = 0; - - n = nvme_subsystem_first_ns(s); - if (!n) - return 0; - - nvme_namespace_for_each_path(n, p) { - struct json_object *path_attrs; - nvme_ctrl_t c = nvme_path_get_ctrl(p); - - path_attrs = json_create_object(); - json_object_add_value_string(path_attrs, "Name", - nvme_ctrl_get_name(c)); - json_object_add_value_string(path_attrs, "Transport", - nvme_ctrl_get_transport(c)); - json_object_add_value_string(path_attrs, "Address", - nvme_ctrl_get_address(c)); - json_object_add_value_string(path_attrs, "State", - nvme_ctrl_get_state(c)); - if (show_ana) - json_object_add_value_string(path_attrs, "ANAState", - nvme_path_get_ana_state(p)); - json_array_add_value_object(paths, path_attrs); - i++; + switch (pmrszu) { + case 0: return "Bytes"; + case 1: return "One KB"; + case 2: return "One MB"; + case 3: return "One GB"; + default: return "Reserved"; } - - return i; } -static void json_print_nvme_subsystem_ctrls(nvme_subsystem_t s, - json_object *paths) +void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags) { - nvme_ctrl_t c; - - nvme_subsystem_for_each_ctrl(s, c) { - struct json_object *path_attrs; - - path_attrs = json_create_object(); - json_object_add_value_string(path_attrs, "Name", - nvme_ctrl_get_name(c)); - json_object_add_value_string(path_attrs, "Transport", - nvme_ctrl_get_transport(c)); - json_object_add_value_string(path_attrs, "Address", - nvme_ctrl_get_address(c)); - json_object_add_value_string(path_attrs, "State", - nvme_ctrl_get_state(c)); - json_array_add_value_object(paths, path_attrs); - } + nvme_print(ctrl_registers, flags, bar, fabrics); } -static void json_print_nvme_subsystem_list(nvme_root_t r, bool show_ana) +void nvme_show_single_property(int offset, uint64_t value64, enum nvme_print_flags flags) { - struct json_object *host_attrs, *subsystem_attrs; - struct json_object *subsystems, *paths; - struct json_object *root; - nvme_host_t h; - - root = json_create_array(); - - nvme_for_each_host(r, h) { - nvme_subsystem_t s; - - host_attrs = json_create_object(); - json_object_add_value_string(host_attrs, "HostNQN", - nvme_host_get_hostnqn(h)); - json_object_add_value_string(host_attrs, "HostID", - nvme_host_get_hostid(h)); - subsystems = json_create_array(); - nvme_for_each_subsystem(h, s) { - subsystem_attrs = json_create_object(); - json_object_add_value_string(subsystem_attrs, "Name", - nvme_subsystem_get_name(s)); - json_object_add_value_string(subsystem_attrs, "NQN", - nvme_subsystem_get_nqn(s)); - - json_array_add_value_object(subsystems, subsystem_attrs); - paths = json_create_array(); - - if (!json_print_nvme_subsystem_multipath(s, show_ana, paths)) - json_print_nvme_subsystem_ctrls(s, paths); - - json_object_add_value_array(subsystem_attrs, "Paths", - paths); - } - json_object_add_value_array(host_attrs, "Subsystems", subsystems); - json_array_add_value_object(root, host_attrs); - } - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(single_property, flags, offset, value64); } -void nvme_show_subsystem_list(nvme_root_t r, bool show_ana, - enum nvme_print_flags flags) +void nvme_show_relatives(const char *name) { - if (flags & JSON) - return json_print_nvme_subsystem_list(r, show_ana); - nvme_show_subsystem(r, show_ana); + /* XXX: TBD */ } -static void nvme_show_registers_cap(struct nvme_bar_cap *cap) +void d(unsigned char *buf, int len, int width, int group) { - printf("\tController Ready With Media Support (CRWMS): %s\n", - ((cap->rsvd_crms_nsss_cmbs_pmrs & 0x08) >> 3) ? "Supported" : "Not Supported"); - printf("\tController Ready Independent of Media Support (CRIMS): %s\n", - ((cap->rsvd_crms_nsss_cmbs_pmrs & 0x10) >> 4) ? "Supported" : "Not Supported"); - printf("\tController Memory Buffer Supported (CMBS): The Controller Memory Buffer is %s\n", - ((cap->rsvd_crms_nsss_cmbs_pmrs & 0x02) >> 1) ? "Supported" : - "Not Supported"); - printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n", - (cap->rsvd_crms_nsss_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("\t One or more I/O Command Sets are %s\n", - (cap->bps_css_nssrs_dstrd & 0x0800) ? "Supported" : "Not Supported"); - printf("\t %s\n", - (cap->bps_css_nssrs_dstrd & 0x1000) ? "Only Admin Command Set Supported" : - "I/O Command Set is Supported"); - printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", - (cap->bps_css_nssrs_dstrd & 0x0010) ? "Yes":"No"); - printf("\tDoorbell Stride (DSTRD): %u bytes\n", - 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); + nvme_print(d, NORMAL, buf, len, width, group); } -static void nvme_show_registers_version(__u32 vs) +void d_raw(unsigned char *buf, unsigned len) { - printf("\tNVMe specification %d.%d\n\n", (vs & 0xffff0000) >> 16, - (vs & 0x0000ff00) >> 8); + unsigned i; + for (i = 0; i < len; i++) + putchar(*(buf+i)); } -static void nvme_show_registers_cc_ams (__u8 ams) +void nvme_show_status(int status) { - 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"); - } + struct print_ops *ops = nvme_print_ops(NORMAL); + + if (nvme_is_output_format_json()) + ops = nvme_print_ops(JSON); + + if (ops && ops->show_status) + ops->show_status(status); } -static void nvme_show_registers_cc_shn (__u8 shn) +void nvme_show_error_status(int status, const char *msg, ...) { - 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("\tController Ready Independent of Media Enable (CRIME): %s\n", - NVME_CC_CRIME(cc) ? "Enabled":"Disabled"); - - printf("\tI/O Completion Queue Entry Size (IOCQES): %u bytes\n", - 1 << ((cc & 0x00f00000) >> NVME_CC_IOCQES_SHIFT)); - printf("\tI/O Submission Queue Entry Size (IOSQES): %u bytes\n", - 1 << ((cc & 0x000f0000) >> NVME_CC_IOSQES_SHIFT)); - 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 Set Selected (CSS): %s\n", - (cc & 0x00000070) == 0x00 ? "NVM Command Set" : - (cc & 0x00000070) == 0x60 ? "All supported I/O Command Sets" : - (cc & 0x00000070) == 0x70 ? "Admin Command Set only" : "Reserved"); - printf("\tEnable (EN): %s\n\n", - (cc & 0x00000001) ? "Yes":"No"); -} - -static void 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_crto(__u32 crto) -{ - printf("\tCRIMT : %d secs\n", - NVME_CRTO_CRIMT(crto)/2 ); - printf("\tCRWMT : %d secs\n", - NVME_CRTO_CRWMT(crto)/2 ); -} - -static void 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) -{ - 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) -{ - 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) -{ - - 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_pmrmscl(uint32_t pmrmscl) -{ - printf("\tController Base Address (CBA): %#x\n", - (pmrmscl & 0xfffff000) >> 12); - printf("\tController Memory Space Enable (CMSE): %#x\n\n", - (pmrmscl & 0x00000002) >> 1); -} - -static void nvme_show_registers_pmrmscu(uint32_t pmrmscu) -{ - printf("\tController Base Address (CBA): %#x\n", - pmrmscu); -} - -static void json_ctrl_registers(void *bar) -{ - uint64_t cap, asq, acq, bpmbl, cmbmsc; - uint32_t vs, intms, intmc, cc, csts, nssr, crto, aqa, cmbsz, cmbloc, - bpinfo, bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp, - pmrmscl, pmrmscu; - 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); - crto = mmio_read32(bar + NVME_REG_CRTO); - aqa = mmio_read32(bar + NVME_REG_AQA); - asq = mmio_read64(bar + NVME_REG_ASQ); - acq = mmio_read64(bar + NVME_REG_ACQ); - cmbloc = mmio_read32(bar + NVME_REG_CMBLOC); - cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); - bpinfo = mmio_read32(bar + NVME_REG_BPINFO); - bprsel = mmio_read32(bar + NVME_REG_BPRSEL); - bpmbl = mmio_read64(bar + NVME_REG_BPMBL); - cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC); - cmbsts = mmio_read32(bar + NVME_REG_CMBSTS); - pmrcap = mmio_read32(bar + NVME_REG_PMRCAP); - pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); - pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); - pmrebs = mmio_read32(bar + NVME_REG_PMREBS); - pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); - pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); - pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); - - root = json_create_object(); - json_object_add_value_uint64(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, "crto", crto); - json_object_add_value_int(root, "aqa", aqa); - json_object_add_value_uint64(root, "asq", asq); - json_object_add_value_uint64(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_uint64(root, "bpmbl", bpmbl); - json_object_add_value_uint64(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, "pmrmscl", pmrmscl); - json_object_add_value_uint(root, "pmrmscu", pmrmscu); - 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 = 0x0e1c; /* 0x0000 to 0x0e1b */ - uint64_t cap, asq, acq, bpmbl, cmbmsc; - uint32_t vs, intms, intmc, cc, csts, nssr, crto, aqa, cmbsz, cmbloc, bpinfo, - bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp, - pmrmscl, pmrmscu; - int human = 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); - crto = mmio_read32(bar + NVME_REG_CRTO); - aqa = mmio_read32(bar + NVME_REG_AQA); - asq = mmio_read64(bar + NVME_REG_ASQ); - acq = mmio_read64(bar + NVME_REG_ACQ); - cmbloc = mmio_read32(bar + NVME_REG_CMBLOC); - cmbsz = mmio_read32(bar + NVME_REG_CMBSZ); - bpinfo = mmio_read32(bar + NVME_REG_BPINFO); - bprsel = mmio_read32(bar + NVME_REG_BPRSEL); - bpmbl = mmio_read64(bar + NVME_REG_BPMBL); - cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC); - cmbsts = mmio_read32(bar + NVME_REG_CMBSTS); - pmrcap = mmio_read32(bar + NVME_REG_PMRCAP); - pmrctl = mmio_read32(bar + NVME_REG_PMRCTL); - pmrsts = mmio_read32(bar + NVME_REG_PMRSTS); - pmrebs = mmio_read32(bar + NVME_REG_PMREBS); - pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP); - pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL); - pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU); - - if (human) { - if (cap != 0xffffffff) { - printf("cap : %"PRIx64"\n", cap); - 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 (crto != 0xffffffff) { - printf("crto : %x\n", crto); - nvme_show_registers_crto(crto); - } - if (!fabrics) { - printf("intms : %x\n", intms); - printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n", - intms); - - printf("intmc : %x\n", intmc); - printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n", - intmc); - printf("aqa : %x\n", aqa); - 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("pmrmscl : %#x\n", pmrmscl); - nvme_show_registers_pmrmscl(pmrmscl); - - printf("pmrmscu : %#x\n", pmrmscu); - nvme_show_registers_pmrmscu(pmrmscu); - } - } else { - if (cap != 0xffffffff) - printf("cap : %"PRIx64"\n", cap); - if (vs != 0xffffffff) - printf("version : %x\n", vs); - if (cc != 0xffffffff) - printf("cc : %x\n", cc); - if (csts != 0xffffffff) - printf("csts : %x\n", csts); - if (nssr != 0xffffffff) - printf("nssr : %x\n", nssr); - if (crto != 0xffffffff) - printf("crto : %x\n", crto); - if (!fabrics) { - printf("intms : %x\n", intms); - printf("intmc : %x\n", intmc); - printf("aqa : %x\n", aqa); - printf("asq : %"PRIx64"\n", asq); - printf("acq : %"PRIx64"\n", acq); - printf("cmbloc : %x\n", cmbloc); - printf("cmbsz : %x\n", cmbsz); - printf("bpinfo : %x\n", bpinfo); - printf("bprsel : %x\n", bprsel); - printf("bpmbl : %"PRIx64"\n", bpmbl); - printf("cmbmsc : %"PRIx64"\n", cmbmsc); - printf("cmbsts : %x\n", cmbsts); - printf("pmrcap : %x\n", pmrcap); - printf("pmrctl : %x\n", pmrctl); - printf("pmrsts : %x\n", pmrsts); - printf("pmrebs : %x\n", pmrebs); - printf("pmrswtp : %x\n", pmrswtp); - printf("pmrmscl : %#x\n", pmrmscl); - printf("pmrmscu : %#x\n", pmrmscu); - } - } -} - -void nvme_show_single_property(int offset, uint64_t value64, int human) -{ - uint32_t value32; - - if (!human) { - if (nvme_is_64bit_reg(offset)) - printf("property: 0x%02x (%s), value: %"PRIx64"\n", - offset, nvme_register_to_string(offset), - value64); - else - printf("property: 0x%02x (%s), value: %x\n", offset, - nvme_register_to_string(offset), - (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; - - case NVME_REG_CRTO: - printf("crto : %x\n", value32); - nvme_show_registers_crto(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) -{ - /* XXX: TBD */ -} - -static void d_json(unsigned char *buf, int len, int width, int group, - struct json_object *array) -{ - int i, line_done = 0; - char ascii[32 + 1]; - assert(width < sizeof(ascii)); - - for (i = 0; i < len; i++) { - line_done = 0; - ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.'; - if (((i + 1) % width) == 0) { - ascii[i % width + 1] = '\0'; - json_array_add_value_string(array, ascii); - line_done = 1; - } - } - if (!line_done) { - ascii[i % width + 1] = '\0'; - json_array_add_value_string(array, ascii); - } -} - -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, false), status); -} - -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]; - - uuid_unparse_lower(uuid, uuid_str); - - 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 disc = (oaes >> 31) & 0x1; - __u32 rsvd0 = (oaes & 0x70000000) >> 28; - __u32 zicn = (oaes & 0x08000000) >> 27; - __u32 rsvd1 = (oaes & 0x07FF0000) >> 16; - __u32 normal_shn = (oaes >> 15) & 0x1; - __u32 egealpcn = (oaes & 0x4000) >> 14; - __u32 lbasin = (oaes & 0x2000) >> 13; - __u32 plealcn = (oaes & 0x1000) >> 12; - __u32 anacn = (oaes & 0x800) >> 11; - __u32 rsvd2 = (oaes >> 10) & 0x1; - __u32 fan = (oaes & 0x200) >> 9; - __u32 nace = (oaes & 0x100) >> 8; - __u32 rsvd3 = oaes & 0xFF; - - printf(" [31:31] : %#x\tDiscovery Log Change Notice %sSupported\n", - disc, disc ? "" : "Not "); - if (rsvd0) - printf(" [30:28] : %#x\tReserved\n", rsvd0); - printf(" [27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", - zicn, zicn ? "" : "Not "); - if (rsvd1) - printf(" [26:16] : %#x\tReserved\n", rsvd1); - printf(" [15:15] : %#x\tNormal NSS Shutdown Event %sSupported\n", - normal_shn, normal_shn ? "" : "Not "); - printf(" [14:14] : %#x\tEndurance Group Event Aggregate Log Page"\ - " Change Notice %sSupported\n", - egealpcn, egealpcn ? "" : "Not "); - printf(" [13:13] : %#x\tLBA Status Information Notices %sSupported\n", - lbasin, lbasin ? "" : "Not "); - printf(" [12:12] : %#x\tPredictable Latency Event Aggregate Log Change"\ - " Notices %sSupported\n", - plealcn, plealcn ? "" : "Not "); - printf(" [11:11] : %#x\tAsymmetric Namespace Access Change Notices"\ - " %sSupported\n", anacn, anacn ? "" : "Not "); - if (rsvd2) - printf(" [10:10] : %#x\tReserved\n", rsvd2); - printf(" [9:9] : %#x\tFirmware Activation Notices %sSupported\n", - fan, fan ? "" : "Not "); - printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n", - nace, nace ? "" : "Not "); - if (rsvd3) - printf(" [7:0] : %#x\tReserved\n", rsvd3); - printf("\n"); -} - -static void nvme_show_id_ctrl_ctratt(__le32 ctrl_ctratt) -{ - __u32 ctratt = le32_to_cpu(ctrl_ctratt); - __u32 rsvd = ctratt >> 16; - __u32 elbas = (ctratt >> 15) & 0x1; - __u32 delnvmset = (ctratt >> 14) & 0x1; - __u32 delegrp = (ctratt >> 13) & 0x1; - __u32 vcap = (ctratt >> 12) & 0x1; - __u32 fcap = (ctratt >> 11) & 0x1; - __u32 mds = (ctratt >> 10) & 0x1; - __u32 hostid128 = (ctratt & NVME_CTRL_CTRATT_128_ID) >> 0; - __u32 psp = (ctratt & NVME_CTRL_CTRATT_NON_OP_PSP) >> 1; - __u32 sets = (ctratt & NVME_CTRL_CTRATT_NVM_SETS) >> 2; - __u32 rrl = (ctratt & NVME_CTRL_CTRATT_READ_RECV_LVLS) >> 3; - __u32 eg = (ctratt & NVME_CTRL_CTRATT_ENDURANCE_GROUPS) >> 4; - __u32 iod = (ctratt & NVME_CTRL_CTRATT_PREDICTABLE_LAT) >> 5; - __u32 tbkas = (ctratt & NVME_CTRL_CTRATT_TBKAS) >> 6; - __u32 ng = (ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) >> 7; - __u32 sqa = (ctratt & NVME_CTRL_CTRATT_SQ_ASSOCIATIONS) >> 8; - __u32 uuidlist = (ctratt & NVME_CTRL_CTRATT_UUID_LIST) >> 9; - - if (rsvd) - printf(" [31:16] : %#x\tReserved\n", rsvd); - printf(" [15:15] : %#x\tExtended LBA Formats %sSupported\n", - elbas, elbas ? "" : "Not "); - printf(" [14:14] : %#x\tDelete NVM Set %sSupported\n", - delnvmset, delnvmset ? "" : "Not "); - printf(" [13:13] : %#x\tDelete Endurance Group %sSupported\n", - delegrp, delegrp ? "" : "Not "); - printf(" [12:12] : %#x\tVariable Capacity Management %sSupported\n", - vcap, vcap ? "" : "Not "); - printf(" [11:11] : %#x\tFixed Capacity Management %sSupported\n", - fcap, fcap ? "" : "Not "); - printf(" [10:10] : %#x\tMulti Domain Subsystem %sSupported\n", - mds, mds ? "" : "Not "); - printf(" [9:9] : %#x\tUUID List %sSupported\n", - uuidlist, uuidlist ? "" : "Not "); - printf(" [8:8] : %#x\tSQ Associations %sSupported\n", - sqa, sqa ? "" : "Not "); - printf(" [7:7] : %#x\tNamespace Granularity %sSupported\n", - ng, ng ? "" : "Not "); - printf(" [6:6] : %#x\tTraffic Based Keep Alive %sSupported\n", - tbkas, tbkas ? "" : "Not "); - printf(" [5:5] : %#x\tPredictable Latency Mode %sSupported\n", - iod, iod ? "" : "Not "); - printf(" [4:4] : %#x\tEndurance Groups %sSupported\n", - eg, eg ? "" : "Not "); - printf(" [3:3] : %#x\tRead Recovery Levels %sSupported\n", - rrl, rrl ? "" : "Not "); - printf(" [2:2] : %#x\tNVM Sets %sSupported\n", - sets, sets ? "" : "Not "); - printf(" [1:1] : %#x\tNon-Operational Power State Permissive %sSupported\n", - psp, psp ? "" : "Not "); - printf(" [0:0] : %#x\t128-bit Host Identifier %sSupported\n", - hostid128, hostid128 ? "" : "Not "); - printf("\n"); -} - -static void 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_nvmsr(__u8 nvmsr) -{ - __u8 rsvd = (nvmsr >> 2) & 0xfc; - __u8 nvmee = (nvmsr >> 1) & 0x1; - __u8 nvmesd = nvmsr & 0x1; - - if (rsvd) - printf(" [7:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] : %#x\tNVM subsystem %spart of an Enclosure\n", - nvmee, nvmee ? "" : "Not "); - printf(" [0:0] : %#x\tNVM subsystem %spart of an Storage Device\n", - nvmesd, nvmesd ? "" : "Not "); - printf("\n"); -} - -static void nvme_show_id_ctrl_vwci(__u8 vwci) -{ - __u8 vwcrv = (vwci >> 7) & 0x1; - __u8 vwcr = vwci & 0xfe; - - printf(" [7:7] : %#x\tVPD Write Cycles Remaining field is %svalid.\n", - vwcrv, vwcrv ? "" : "Not "); - printf(" [6:0] : %#x\tVPD Write Cycles Remaining \n", vwcr); - printf("\n"); - -} - -static void nvme_show_id_ctrl_mec(__u8 mec) -{ - __u8 rsvd = (mec >> 2) & 0xfc; - __u8 pcieme = (mec >> 1) & 0x1; - __u8 smbusme = mec & 0x1; - - if (rsvd) - printf(" [7:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] : %#x\tNVM subsystem %scontains a Management Endpoint"\ - " on a PCIe port\n", pcieme, pcieme ? "" : "Not "); - printf(" [0:0] : %#x\tNVM subsystem %scontains a Management Endpoint"\ - " on an SMBus/I2C port\n", smbusme, smbusme ? "" : "Not "); - printf("\n"); - -} - -static void nvme_show_id_ctrl_oacs(__le16 ctrl_oacs) -{ - __u16 oacs = le16_to_cpu(ctrl_oacs); - __u16 rsvd = (oacs & 0xF800) >> 11; - __u16 lock = (oacs >> 10) & 0x1; - __u16 glbas = (oacs & 0x200) >> 9; - __u16 dbc = (oacs & 0x100) >> 8; - __u16 vir = (oacs & 0x80) >> 7; - __u16 nmi = (oacs & 0x40) >> 6; - __u16 dir = (oacs & 0x20) >> 5; - __u16 sft = (oacs & 0x10) >> 4; - __u16 nsm = (oacs & 0x8) >> 3; - __u16 fwc = (oacs & 0x4) >> 2; - __u16 fmt = (oacs & 0x2) >> 1; - __u16 sec = oacs & 0x1; - - if (rsvd) - printf(" [15:11] : %#x\tReserved\n", rsvd); - printf(" [10:10] : %#x\tLockdown Command and Feature %sSupported\n", - lock, lock ? "" : "Not "); - printf(" [9:9] : %#x\tGet LBA Status Capability %sSupported\n", - glbas, glbas ? "" : "Not "); - printf(" [8:8] : %#x\tDoorbell Buffer Config %sSupported\n", - dbc, dbc ? "" : "Not "); - printf(" [7:7] : %#x\tVirtualization Management %sSupported\n", - vir, vir ? "" : "Not "); - printf(" [6:6] : %#x\tNVMe-MI Send and Receive %sSupported\n", - nmi, nmi ? "" : "Not "); - printf(" [5:5] : %#x\tDirectives %sSupported\n", - dir, dir ? "" : "Not "); - printf(" [4:4] : %#x\tDevice Self-test %sSupported\n", - sft, sft ? "" : "Not "); - printf(" [3:3] : %#x\tNS Management and Attachment %sSupported\n", - nsm, nsm ? "" : "Not "); - printf(" [2:2] : %#x\tFW Commit and Download %sSupported\n", - fwc, fwc ? "" : "Not "); - printf(" [1:1] : %#x\tFormat NVM %sSupported\n", - fmt, fmt ? "" : "Not "); - printf(" [0:0] : %#x\tSecurity Send and Receive %sSupported\n", - sec, sec ? "" : "Not "); - printf("\n"); -} - -static void nvme_show_id_ctrl_frmw(__u8 frmw) -{ - __u8 rsvd = (frmw & 0xC0) >> 6; - __u8 smud = (frmw >> 5) & 0x1; - __u8 fawr = (frmw & 0x10) >> 4; - __u8 nfws = (frmw & 0xE) >> 1; - __u8 s1ro = frmw & 0x1; - - if (rsvd) - printf(" [7:6] : %#x\tReserved\n", rsvd); - printf(" [5:5] : %#x\tMultiple FW or Boot Update Detection %sSupported\n", - smud, smud ? "" : "Not "); - printf(" [4:4] : %#x\tFirmware Activate Without Reset %sSupported\n", - fawr, fawr ? "" : "Not "); - printf(" [3:1] : %#x\tNumber of Firmware Slots\n", nfws); - printf(" [0:0] : %#x\tFirmware Slot 1 Read%s\n", - s1ro, s1ro ? "-Only" : "/Write"); - printf("\n"); -} - -static void nvme_show_id_ctrl_lpa(__u8 lpa) -{ - __u8 rsvd = (lpa & 0x80) >> 7; - __u8 tel = (lpa >> 6) & 0x1; - __u8 lid_sup = (lpa >> 5) & 0x1; - __u8 persevnt = (lpa & 0x10) >> 4; - __u8 telem = (lpa & 0x8) >> 3; - __u8 ed = (lpa & 0x4) >> 2; - __u8 celp = (lpa & 0x2) >> 1; - __u8 smlp = lpa & 0x1; - - if (rsvd) - printf(" [7:7] : %#x\tReserved\n", rsvd); - printf(" [6:6] : %#x\tTelemetry Log Data Area 4 %sSupported\n", - tel, tel ? "" : "Not "); - printf(" [5:5] : %#x\tLID 0x0, Scope of each command in LID 0x5, "\ - "0x12, 0x13 %sSupported\n", lid_sup, lid_sup ? "" : "Not "); - printf(" [4:4] : %#x\tPersistent Event log %sSupported\n", - persevnt, persevnt ? "" : "Not "); - printf(" [3:3] : %#x\tTelemetry host/controller initiated log page %sSupported\n", - telem, telem ? "" : "Not "); - printf(" [2:2] : %#x\tExtended data for Get Log Page %sSupported\n", - ed, ed ? "" : "Not "); - printf(" [1:1] : %#x\tCommand Effects Log Page %sSupported\n", - celp, celp ? "" : "Not "); - printf(" [0:0] : %#x\tSMART/Health Log Page per NS %sSupported\n", - smlp, smlp ? "" : "Not "); - printf("\n"); -} - -static void nvme_show_id_ctrl_elpe(__u8 elpe) -{ - printf(" [7:0] : %d (0's based)\tError Log Page Entries (ELPE)\n", - elpe); - printf("\n"); -} - -static void nvme_show_id_ctrl_npss(__u8 npss) -{ - printf(" [7:0] : %d (0's based)\tNumber of Power States Support (NPSS)\n", - npss); - 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_wctemp(__le16 wctemp) -{ - printf(" [15:0] : %ld°C (%u Kelvin)\tWarning Composite Temperature Threshold (WCTEMP)\n", - kelvin_to_celsius(le16_to_cpu(wctemp)), le16_to_cpu(wctemp)); - printf("\n"); -} - -static void nvme_show_id_ctrl_cctemp(__le16 cctemp) -{ - printf(" [15:0] : %ld°C (%u Kelvin)\tCritical Composite Temperature Threshold (CCTEMP)\n", - kelvin_to_celsius(le16_to_cpu(cctemp)), le16_to_cpu(cctemp)); - printf("\n"); -} - -static void nvme_show_id_ctrl_tnvmcap(__u8 *tnvmcap) -{ - printf("[127:0] : %.0Lf\tTotal NVM Capacity (TNVMCAP)\n", - int128_to_double(tnvmcap)); - printf("\n"); -} - -static void nvme_show_id_ctrl_unvmcap(__u8 *unvmcap) -{ - printf("[127:0] : %.0Lf\tUnallocated NVM Capacity (UNVMCAP)\n", - int128_to_double(unvmcap)); - printf("\n"); -} - -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_mntmt(__le16 mntmt) -{ - printf(" [15:0] : %ld°C (%u Kelvin)\tMinimum Thermal Management Temperature (MNTMT)\n", - kelvin_to_celsius(le16_to_cpu(mntmt)), le16_to_cpu(mntmt)); - printf("\n"); -} - -static void nvme_show_id_ctrl_mxtmt(__le16 mxtmt) -{ - printf(" [15:0] : %ld°C (%u Kelvin)\tMaximum Thermal Management Temperature (MXTMT)\n", - kelvin_to_celsius(le16_to_cpu(mxtmt)), le16_to_cpu(mxtmt)); - 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_static = (anacap & 0x40) >> 6; - __u8 rsvd = (anacap & 0x20) >> 5; - __u8 ana_change = (anacap & 0x10) >> 4; - __u8 ana_persist_loss = (anacap & 0x08) >> 3; - __u8 ana_inaccessible = (anacap & 0x04) >> 2; - __u8 ana_nonopt = (anacap & 0x02) >> 1; - __u8 ana_opt = (anacap & 0x01); - - printf(" [7:7] : %#x\tNon-zero group ID %sSupported\n", - nz, nz ? "" : "Not "); - printf(" [6:6] : %#x\tGroup ID does %schange\n", - grpid_static, grpid_static ? "not " : ""); - if (rsvd) - printf(" [5:5] : %#x\tReserved\n", rsvd); - printf(" [4:4] : %#x\tANA Change state %sSupported\n", - ana_change, ana_change ? "" : "Not "); - printf(" [3:3] : %#x\tANA Persistent Loss state %sSupported\n", - ana_persist_loss, ana_persist_loss ? "" : "Not "); - printf(" [2:2] : %#x\tANA Inaccessible state %sSupported\n", - ana_inaccessible, ana_inaccessible ? "" : "Not "); - printf(" [1:1] : %#x\tANA Non-optimized state %sSupported\n", - ana_nonopt, ana_nonopt ? "" : "Not "); - printf(" [0:0] : %#x\tANA Optimized state %sSupported\n", - ana_opt, ana_opt ? "" : "Not "); - printf("\n"); -} - -static void 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 & 0xFE00) >> 9; - __u16 copy = (oncs & 0x100) >> 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:9] : %#x\tReserved\n", rsvd); - printf(" [8:8] : %#x\tCopy %sSupported\n", - copy, copy ? "" : "Not "); - printf(" [7:7] : %#x\tVerify %sSupported\n", - vrfy, vrfy ? "" : "Not "); - printf(" [6:6] : %#x\tTimestamp %sSupported\n", - 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 & 0xF0) >> 4; - __u8 bcnsid = (fna & 0x8) >> 3; - __u8 cese = (fna & 0x4) >> 2; - __u8 cens = (fna & 0x2) >> 1; - __u8 fmns = fna & 0x1; - if (rsvd) - printf(" [7:4] : %#x\tReserved\n", rsvd); - printf(" [3:3] : %#x\tFormat NVM Broadcast NSID (FFFFFFFFh) %sSupported\n", - bcnsid, bcnsid ? "Not " : ""); - printf(" [2:2] : %#x\tCrypto Erase %sSupported as part of Secure Erase\n", - cese, cese ? "" : "Not "); - printf(" [1:1] : %#x\tCrypto Erase Applies to %s Namespace(s)\n", - cens, cens ? "All" : "Single"); - printf(" [0:0] : %#x\tFormat Applies to %s Namespace(s)\n", - fmns, fmns ? "All" : "Single"); - printf("\n"); -} - -static void 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_icsvscc(__u8 icsvscc) -{ - __u8 rsvd = (icsvscc & 0xFE) >> 1; - __u8 fmt = icsvscc & 0x1; - if (rsvd) - printf(" [7:1] : %#x\tReserved\n", rsvd); - printf(" [0:0] : %#x\tNVM Vendor Specific Commands uses %s Format\n", - fmt, fmt ? "NVMe" : "Vendor Specific"); - printf("\n"); -} - -static void 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_ocfs(__le16 ctrl_ocfs) -{ - __u16 ocfs = le16_to_cpu(ctrl_ocfs); - __u16 rsvd = (ocfs & 0xfffc) >> 2; - __u8 copy_fmt_1 = (ocfs >> 1) & 0x1; - __u8 copy_fmt_0 = ocfs & 0x1; - if (rsvd) - printf(" [15:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] : %#x\tController Copy Format 1h %sSupported\n", - copy_fmt_1, copy_fmt_1 ? "" : "Not "); - printf(" [0:0] : %#x\tController Copy Format 0h %sSupported\n", - copy_fmt_0, copy_fmt_0 ? "" : "Not "); - printf("\n"); -} - -static void nvme_show_id_ctrl_sgls(__le32 ctrl_sgls) -{ - __u32 sgls = le32_to_cpu(ctrl_sgls); - __u32 rsvd0 = (sgls & 0xFFC00000) >> 22; - __u32 trsdbd = (sgls & 0x200000) >> 21; - __u32 aofdsl = (sgls & 0x100000) >> 20; - __u32 mpcsd = (sgls & 0x80000) >> 19; - __u32 sglltb = (sgls & 0x40000) >> 18; - __u32 bacmdb = (sgls & 0x20000) >> 17; - __u32 bbs = (sgls & 0x10000) >> 16; - __u32 sdt = (sgls >> 8) & 0xff; - __u32 rsvd1 = (sgls & 0xF8) >> 3; - __u32 key = (sgls & 0x4) >> 2; - __u32 sglsp = sgls & 0x3; - - if (rsvd0) - printf(" [31:22]: %#x\tReserved\n", rsvd0); - if (sglsp || (!sglsp && trsdbd)) - printf(" [21:21]: %#x\tTransport SGL Data Block Descriptor %sSupported\n", - trsdbd, trsdbd ? "" : "Not "); - if (sglsp || (!sglsp && aofdsl)) - printf(" [20:20]: %#x\tAddress Offsets %sSupported\n", - aofdsl, aofdsl ? "" : "Not "); - if (sglsp || (!sglsp && mpcsd)) - printf(" [19:19]: %#x\tMetadata Pointer Containing " - "SGL Descriptor is %sSupported\n", - mpcsd, mpcsd ? "" : "Not "); - if (sglsp || (!sglsp && sglltb)) - printf(" [18:18]: %#x\tSGL Length Larger than Buffer %sSupported\n", - sglltb, sglltb ? "" : "Not "); - if (sglsp || (!sglsp && bacmdb)) - printf(" [17:17]: %#x\tByte-Aligned Contig. MD Buffer %sSupported\n", - bacmdb, bacmdb ? "" : "Not "); - if (sglsp || (!sglsp && bbs)) - printf(" [16:16]: %#x\tSGL Bit-Bucket %sSupported\n", - bbs, bbs ? "" : "Not "); - printf(" [15:8] : %#x\tSGL Descriptor Threshold\n", sdt); - if (rsvd1) - printf(" [7:3] : %#x\tReserved\n", rsvd1); - if (sglsp || (!sglsp && key)) - printf(" [2:2] : %#x\tKeyed SGL Data Block descriptor %sSupported\n", - key, key ? "" : "Not "); - if (sglsp == 0x3) - printf(" [1:0] : %#x\tReserved\n", sglsp); - else if (sglsp == 0x2) - printf(" [1:0] : %#x\tScatter-Gather Lists Supported." - " Dword alignment required.\n", sglsp); - else if (sglsp == 0x1) - printf(" [1:0] : %#x\tScatter-Gather Lists Supported." - " No Dword alignment required.\n", sglsp); - else - printf(" [1:0] : %#x\tScatter-Gather Lists Not Supported\n", sglsp); - printf("\n"); -} - -static void nvme_show_id_ctrl_fcatt(__u8 fcatt) -{ - __u8 rsvd = (fcatt & 0xFE) >> 1; - __u8 scm = fcatt & 0x1; - if (rsvd) - printf(" [7:1] : %#x\tReserved\n", rsvd); - printf(" [0:0] : %#x\t%s Controller Model\n", - scm, scm ? "Static" : "Dynamic"); - printf("\n"); -} - -static void nvme_show_id_ctrl_ofcs(__le16 ofcs) -{ - __u16 rsvd = (ofcs & 0xfffe) >> 1; - __u8 disconn = ofcs & 0x1; - if (rsvd) - printf(" [15:1] : %#x\tReserved\n", rsvd); - printf(" [0:0] : %#x\tDisconnect command %s Supported\n", - disconn, disconn ? "" : "Not"); - printf("\n"); - -} - -static void nvme_show_id_ns_nsfeat(__u8 nsfeat) -{ - __u8 rsvd = (nsfeat & 0xE0) >> 5; - __u8 ioopt = (nsfeat & 0x10) >> 4; - __u8 uidreuse = (nsfeat & 0x8) >> 3; - __u8 dulbe = (nsfeat & 0x4) >> 2; - __u8 na = (nsfeat & 0x2) >> 1; - __u8 thin = nsfeat & 0x1; - if (rsvd) - printf(" [7:5] : %#x\tReserved\n", rsvd); - printf(" [4:4] : %#x\tNPWG, NPWA, NPDG, NPDA, and NOWS are %sSupported\n", - ioopt, ioopt ? "" : "Not "); - printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n", - uidreuse, uidreuse ? "Never " : ""); - printf(" [2:2] : %#x\tDeallocated or Unwritten Logical Block error %sSupported\n", - dulbe, dulbe ? "" : "Not "); - printf(" [1:1] : %#x\tNamespace uses %s\n", - na, na ? "NAWUN, NAWUPF, and NACWU" : "AWUN, AWUPF, and ACWU"); - printf(" [0:0] : %#x\tThin Provisioning %sSupported\n", - thin, thin ? "" : "Not "); - printf("\n"); -} - -static void nvme_show_id_ns_flbas(__u8 flbas) -{ - __u8 rsvd = (flbas & 0x80) >> 7; - __u8 msb2_lbaf = (flbas & NVME_NS_FLBAS_HIGHER_MASK) >> 5; - __u8 mdedata = (flbas & 0x10) >> 4; - __u8 lsb4_lbaf = flbas & NVME_NS_FLBAS_LOWER_MASK; - - if (rsvd) - printf(" [7:7] : %#x\tReserved\n", rsvd); - printf(" [6:5] : %#x\tMost significant 2 bits of Current LBA Format Selected\n", - msb2_lbaf); - printf(" [4:4] : %#x\tMetadata Transferred %s\n", - mdedata, mdedata ? "at End of Data LBA" : "in Separate Contiguous Buffer"); - printf(" [3:0] : %#x\tLeast significant 4 bits of Current LBA Format Selected\n", - lsb4_lbaf); - printf("\n"); -} - -static void 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"); -} + struct print_ops *ops = nvme_print_ops(NORMAL); + va_list ap; -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"); -} + va_start(ap, msg); -static void nvme_show_id_ns_rescap(__u8 rescap) -{ - __u8 iekr = (rescap & 0x80) >> 7; - __u8 eaar = (rescap & 0x40) >> 6; - __u8 wear = (rescap & 0x20) >> 5; - __u8 earo = (rescap & 0x10) >> 4; - __u8 wero = (rescap & 0x8) >> 3; - __u8 ea = (rescap & 0x4) >> 2; - __u8 we = (rescap & 0x2) >> 1; - __u8 ptpl = rescap & 0x1; - - printf(" [7:7] : %#x\tIgnore Existing Key - Used as defined in revision %s\n", - iekr, iekr ? "1.3 or later" : "1.2.1 or earlier"); - printf(" [6:6] : %#x\tExclusive Access - All Registrants %sSupported\n", - eaar, eaar ? "" : "Not "); - printf(" [5:5] : %#x\tWrite Exclusive - All Registrants %sSupported\n", - wear, wear ? "" : "Not "); - printf(" [4:4] : %#x\tExclusive Access - Registrants Only %sSupported\n", - earo, earo ? "" : "Not "); - printf(" [3:3] : %#x\tWrite Exclusive - Registrants Only %sSupported\n", - wero, wero ? "" : "Not "); - printf(" [2:2] : %#x\tExclusive Access %sSupported\n", - ea, ea ? "" : "Not "); - printf(" [1:1] : %#x\tWrite Exclusive %sSupported\n", - we, we ? "" : "Not "); - printf(" [0:0] : %#x\tPersist Through Power Loss %sSupported\n", - ptpl, ptpl ? "" : "Not "); - printf("\n"); -} + if (nvme_is_output_format_json()) + ops = nvme_print_ops(JSON); -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"); -} + if (ops && ops->show_status) + ops->show_error_status(status, msg, ap); -static void nvme_show_id_ns_nsattr(__u8 nsattr) -{ - __u8 rsvd = (nsattr & 0xFE) >> 1; - __u8 write_protected = nsattr & 0x1; - if (rsvd) - printf(" [7:1] : %#x\tReserved\n", rsvd); - printf(" [0:0] : %#x\tNamespace %sWrite Protected\n", - write_protected, write_protected ? "" : "Not "); - printf("\n"); + va_end(ap); } -static void nvme_show_id_ns_dlfeat(__u8 dlfeat) +void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs, enum nvme_print_flags flags) { - __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"); + nvme_print(id_ctrl_rpmbs, flags, ctrl_rpmbs); } void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, unsigned int lba_index, bool cap_only, enum nvme_print_flags flags) { - bool human = flags & VERBOSE; - int vs = flags & VS; - int i; - __u8 flbas; - char *in_use = "(in use)"; - - if (flags & BINARY) - return d_raw((unsigned char *)ns, sizeof(*ns)); - if (flags & JSON) - return json_nvme_id_ns(ns, cap_only); - - if (!cap_only) { - printf("NVME Identify Namespace %d:\n", nsid); - printf("nsze : %#"PRIx64"\n", le64_to_cpu(ns->nsze)); - printf("ncap : %#"PRIx64"\n", le64_to_cpu(ns->ncap)); - printf("nuse : %#"PRIx64"\n", le64_to_cpu(ns->nuse)); - printf("nsfeat : %#x\n", ns->nsfeat); - if (human) - nvme_show_id_ns_nsfeat(ns->nsfeat); - } else - printf("NVMe Identify Namespace for LBA format[%d]:\n", lba_index); - - printf("nlbaf : %d\n", ns->nlbaf); - if (!cap_only) { - printf("flbas : %#x\n", ns->flbas); - if (human) - nvme_show_id_ns_flbas(ns->flbas); - } else - in_use = ""; - - 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); - if (!cap_only) { - 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("mssrl : %u\n", le16_to_cpu(ns->mssrl)); - printf("mcl : %d\n", le32_to_cpu(ns->mcl)); - printf("msrc : %u\n", ns->msrc); - } - printf("nulbaf : %u\n", ns->nulbaf); - if (!cap_only) { - printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); - printf("nsattr : %u\n", ns->nsattr); - printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid)); - printf("endgid : %d\n", le16_to_cpu(ns->endgid)); - - printf("nguid : "); - for (i = 0; i < 16; i++) - printf("%02x", ns->nguid[i]); - printf("\n"); - - printf("eui64 : "); - for (i = 0; i < 8; i++) - printf("%02x", ns->eui64[i]); - printf("\n"); - } - - nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas); - for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) { - if (human) - printf("LBA Format %2d : Metadata Size: %-3d bytes - " - "Data Size: %-2d bytes - Relative Performance: %#x %s %s\n", - i, le16_to_cpu(ns->lbaf[i].ms), - 1 << ns->lbaf[i].ds, ns->lbaf[i].rp, - ns->lbaf[i].rp == 3 ? "Degraded" : - ns->lbaf[i].rp == 2 ? "Good" : - ns->lbaf[i].rp == 1 ? "Better" : "Best", - i == flbas ? in_use : ""); - else - printf("lbaf %2d : ms:%-3d lbads:%-2d rp:%#x %s\n", i, - le16_to_cpu(ns->lbaf[i].ms), ns->lbaf[i].ds, - ns->lbaf[i].rp, i == flbas ? in_use : ""); - } - - if (vs && !cap_only) { - printf("vs[]:\n"); - d(ns->vs, sizeof(ns->vs), 16, 1); - } -} - -static void nvme_show_cmd_set_independent_id_ns_nsfeat(__u8 nsfeat) -{ - __u8 rsvd5 = (nsfeat & 0xE0) >> 5; - __u8 rmedia = (nsfeat & 0x10) >> 4; - __u8 uidreuse = (nsfeat & 0x8) >> 3; - __u8 rsvd0 = (nsfeat & 0x7); - if (rsvd5) - printf(" [7:5] : %#x\tReserved\n", rsvd5); - printf(" [4:4] : %#x\tNamespace %sstore data on rotational media\n", - rmedia, rmedia ? "" : "does not "); - printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n", - uidreuse, uidreuse ? "Never " : ""); - if (rsvd0) - printf(" [2:0] : %#x\tReserved\n", rsvd0); - printf("\n"); + nvme_print(id_ns, flags, ns, nsid, lba_index, cap_only); } -static void nvme_show_cmd_set_independent_id_ns_nstat(__u8 nstat) -{ - __u8 rsvd1 = (nstat & 0xfe) >> 1; - __u8 nrdy = nstat & 0x1; - if (rsvd1) - printf(" [7:1] : %#x\tReserved\n", rsvd1); - printf(" [0:0] : %#x\tName space is %sready\n", - nrdy, nrdy ? "" : "not "); - printf("\n"); -} - -static void json_nvme_cmd_set_independent_id_ns( - struct nvme_id_independent_id_ns *ns) -{ - struct json_object *root; - root = json_create_object(); - - json_object_add_value_int(root, "nsfeat", ns->nsfeat); - 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, "anagrpid", le32_to_cpu(ns->anagrpid)); - json_object_add_value_int(root, "nsattr", ns->nsattr); - json_object_add_value_int(root, "nvmsetid", le16_to_cpu(ns->nvmsetid)); - json_object_add_value_int(root, "endgid", le16_to_cpu(ns->endgid)); - json_object_add_value_int(root, "nstat", ns->nstat); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} void nvme_show_cmd_set_independent_id_ns( struct nvme_id_independent_id_ns *ns, unsigned int nsid, enum nvme_print_flags flags) { - int human = flags & VERBOSE; - - if (flags & BINARY) - return d_raw((unsigned char *)ns, sizeof(*ns)); - if (flags & JSON) - return json_nvme_cmd_set_independent_id_ns(ns); - - printf("NVME Identify Command Set Independent Namespace %d:\n", nsid); - printf("nsfeat : %#x\n", ns->nsfeat); - if (human) - nvme_show_cmd_set_independent_id_ns_nsfeat(ns->nsfeat); - 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("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); - printf("nsattr : %u\n", ns->nsattr); - if (human) - nvme_show_id_ns_nsattr(ns->nsattr); - printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid)); - printf("endgid : %d\n", le16_to_cpu(ns->endgid)); - - printf("nstat : %#x\n", ns->nstat); - if (human) - nvme_show_cmd_set_independent_id_ns_nstat(ns->nstat); -} - -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]; - uuid_t uuid; - __u8 csi; - } desc; - - struct json_object *root; - struct json_object *json_array = NULL; - - off_t off; - int pos, len = 0; - int i; - - for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) { - struct nvme_ns_id_desc *cur = data + pos; - const char *nidt_name = NULL; - - if (cur->nidl == 0) - break; - - memset(json_str, 0, sizeof(json_str)); - json_str_p = json_str; - off = pos + sizeof(*cur); - - switch (cur->nidt) { - case NVME_NIDT_EUI64: - memcpy(desc.eui64, data + off, sizeof(desc.eui64)); - for (i = 0; i < sizeof(desc.eui64); i++) - json_str_p += sprintf(json_str_p, "%02x", desc.eui64[i]); - len = sizeof(desc.eui64); - nidt_name = "eui64"; - break; - - case NVME_NIDT_NGUID: - memcpy(desc.nguid, data + off, sizeof(desc.nguid)); - for (i = 0; i < sizeof(desc.nguid); i++) - json_str_p += sprintf(json_str_p, "%02x", desc.nguid[i]); - len = sizeof(desc.nguid); - nidt_name = "nguid"; - break; - - case NVME_NIDT_UUID: - memcpy(desc.uuid, data + off, sizeof(desc.uuid)); - uuid_unparse_lower(desc.uuid, json_str); - len = sizeof(desc.uuid); - nidt_name = "uuid"; - break; - - case NVME_NIDT_CSI: - memcpy(&desc.csi, data + off, sizeof(desc.csi)); - sprintf(json_str_p, "%#x", desc.csi); - len += sizeof(desc.csi); - nidt_name = "csi"; - break; - default: - /* Skip unknown types */ - len = cur->nidl; - break; - } - - if (nidt_name) { - struct json_object *elem = json_create_object(); - - 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); + nvme_print(id_independent_id_ns, flags, ns, nsid); } void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags) { - int pos, len = 0; - int i; - uuid_t uuid; - char uuid_str[37]; - __u8 eui64[8]; - __u8 nguid[16]; - __u8 csi; - - 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; - 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; - case NVME_NIDT_CSI: - memcpy(&csi, data + pos + sizeof(*cur), 1); - printf("csi : %#x\n", csi); - len += sizeof(csi); - break; - default: - /* Skip unknown types */ - len = cur->nidl; - break; - } - - len += sizeof(*cur); - } -} - -static void print_psd_workload(__u8 apw) -{ - switch (apw & 0x7) { - case NVME_PSD_WORKLOAD_NP: - /* Unknown or not provided */ - printf("-"); - break; - - case 1: - /* Extended idle period with burst of random write */ - printf("1MiB 32 RW, 30s idle"); - break; - - case 2: - /* Heavy sequential writes */ - printf("80K 128KiB SW"); - break; - - default: - printf("reserved"); - } -} - -static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale) -{ - __u16 power = le16_to_cpu(ctr_power); - - switch (scale & 0x3) { - case NVME_PSD_PS_NOT_REPORTED: - /* Not reported for this power state */ - printf("-"); - break; - - case NVME_PSD_PS_100_MICRO_WATT: - /* Units of 0.0001W */ - printf("%01u.%04uW", power / 10000, power % 10000); - break; - - case NVME_PSD_PS_10_MILLI_WATT: - /* Units of 0.01W */ - printf("%01u.%02uW", power / 100, power % 100); - break; - - default: - printf("reserved"); - } -} - -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].mp); - - printf("ps %4d : mp:", i); - - if (ctrl->psd[i].flags & NVME_PSD_FLAGS_MXPS) - printf("%01u.%04uW ", max_power / 10000, max_power % 10000); - else - printf("%01u.%02uW ", max_power / 100, max_power % 100); - - if (ctrl->psd[i].flags & NVME_PSD_FLAGS_NOPS) - printf("non-"); - - printf("operational enlat:%d exlat:%d rrt:%d rrl:%d\n" - " rwt:%d rwl:%d idle_power:", - le32_to_cpu(ctrl->psd[i].enlat), - le32_to_cpu(ctrl->psd[i].exlat), - ctrl->psd[i].rrt, ctrl->psd[i].rrl, - ctrl->psd[i].rwt, ctrl->psd[i].rwl); - print_ps_power_and_scale(ctrl->psd[i].idlp, - nvme_psd_power_scale(ctrl->psd[i].ips)); - printf(" active_power:"); - print_ps_power_and_scale(ctrl->psd[i].actp, - nvme_psd_power_scale(ctrl->psd[i].apws)); - printf("\n active_power_workload:"); - print_psd_workload(ctrl->psd[i].apws); - printf("\n"); - - } + nvme_print(id_ns_descs, flags, data, nsid); } void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, void (*vendor_show)(__u8 *vs, struct json_object *root)) { - bool 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, 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("nvmsr : %u\n", ctrl->nvmsr); - if (human) - nvme_show_id_ctrl_nvmsr(ctrl->nvmsr); - printf("vwci : %u\n", ctrl->vwci); - if (human) - nvme_show_id_ctrl_vwci(ctrl->vwci); - printf("mec : %u\n", ctrl->mec); - if (human) - nvme_show_id_ctrl_mec(ctrl->mec); - - 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); - if (human) - nvme_show_id_ctrl_elpe(ctrl->elpe); - printf("npss : %d\n", ctrl->npss); - if (human) - nvme_show_id_ctrl_npss(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)); - if (human) - nvme_show_id_ctrl_wctemp(ctrl->wctemp); - printf("cctemp : %d\n", le16_to_cpu(ctrl->cctemp)); - if (human) - nvme_show_id_ctrl_cctemp(ctrl->cctemp); - printf("mtfa : %d\n", le16_to_cpu(ctrl->mtfa)); - printf("hmpre : %d\n", le32_to_cpu(ctrl->hmpre)); - printf("hmmin : %d\n", le32_to_cpu(ctrl->hmmin)); - printf("tnvmcap : %.0Lf\n", int128_to_double(ctrl->tnvmcap)); - if (human) - nvme_show_id_ctrl_tnvmcap(ctrl->tnvmcap); - printf("unvmcap : %.0Lf\n", int128_to_double(ctrl->unvmcap)); - if (human) - nvme_show_id_ctrl_unvmcap(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)); - if (human) - nvme_show_id_ctrl_mntmt(ctrl->mntmt); - printf("mxtmt : %d\n", le16_to_cpu(ctrl->mxtmt)); - if (human) - nvme_show_id_ctrl_mxtmt(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("domainid : %d\n", le16_to_cpu(ctrl->domainid)); - printf("megcap : %.0Lf\n", int128_to_double(ctrl->megcap)); - printf("sqes : %#x\n", ctrl->sqes); - if (human) - nvme_show_id_ctrl_sqes(ctrl->sqes); - 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("icsvscc : %d\n", ctrl->icsvscc); - if (human) - nvme_show_id_ctrl_icsvscc(ctrl->icsvscc); - 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("ocfs : %#x\n", le16_to_cpu(ctrl->ocfs)); - if (human) - nvme_show_id_ctrl_ocfs(ctrl->ocfs); - printf("sgls : %#x\n", le32_to_cpu(ctrl->sgls)); - if (human) - nvme_show_id_ctrl_sgls(ctrl->sgls); - printf("mnan : %d\n", le32_to_cpu(ctrl->mnan)); - printf("maxdna : %.0Lf\n", int128_to_double(ctrl->maxdna)); - printf("maxcna : %d\n", le32_to_cpu(ctrl->maxcna)); - printf("subnqn : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn); - printf("ioccsz : %d\n", le32_to_cpu(ctrl->ioccsz)); - printf("iorcsz : %d\n", le32_to_cpu(ctrl->iorcsz)); - printf("icdoff : %d\n", le16_to_cpu(ctrl->icdoff)); - printf("fcatt : %#x\n", ctrl->fcatt); - if (human) - nvme_show_id_ctrl_fcatt(ctrl->fcatt); - printf("msdbd : %d\n", ctrl->msdbd); - printf("ofcs : %d\n", le16_to_cpu(ctrl->ofcs)); - if (human) - nvme_show_id_ctrl_ofcs(ctrl->ofcs); - - nvme_show_id_ctrl_power(ctrl); - if (vendor_show) - vendor_show(ctrl->vs, NULL); - else if (vs) { - printf("vs[]:\n"); - d(ctrl->vs, sizeof(ctrl->vs), 16, 1); - } -} - -static void json_nvme_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm) -{ - struct json_object *root; - - root = json_create_object(); - json_object_add_value_uint(root, "vsl", ctrl_nvm->vsl); - json_object_add_value_uint(root, "wzsl", ctrl_nvm->wzsl); - json_object_add_value_uint(root, "wusl", ctrl_nvm->wusl); - json_object_add_value_uint(root, "dmrl", ctrl_nvm->dmrl); - json_object_add_value_uint(root, "dmrsl", le32_to_cpu(ctrl_nvm->dmrsl)); - json_object_add_value_uint64(root, "dmsl", le64_to_cpu(ctrl_nvm->dmsl)); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(id_ctrl, flags, ctrl, vendor_show); } void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm, enum nvme_print_flags flags) { - if (flags & BINARY) - return d_raw((unsigned char *)ctrl_nvm, sizeof(*ctrl_nvm)); - else if (flags & JSON) - return json_nvme_id_ctrl_nvm(ctrl_nvm); - - printf("NVMe Identify Controller NVM:\n"); - printf("vsl : %u\n", ctrl_nvm->vsl); - printf("wzsl : %u\n", ctrl_nvm->wzsl); - printf("wusl : %u\n", ctrl_nvm->wusl); - printf("dmrl : %u\n", ctrl_nvm->dmrl); - printf("dmrsl : %u\n", le32_to_cpu(ctrl_nvm->dmrsl)); - printf("dmsl : %"PRIu64"\n", le64_to_cpu(ctrl_nvm->dmsl)); -} - -static void json_nvme_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, - struct nvme_id_ns *ns, bool cap_only) -{ - struct json_object *root; - struct json_object *elbafs; - int i; - - root = json_create_object(); - - if (!cap_only) { - json_object_add_value_uint64(root, "lbstm", le64_to_cpu(nvm_ns->lbstm)); - } - json_object_add_value_int(root, "pic", nvm_ns->pic); - - elbafs = json_create_array(); - json_object_add_value_array(root, "elbafs", elbafs); - - for (i = 0; i <= ns->nlbaf; i++) { - struct json_object *elbaf = json_create_object(); - unsigned int elbaf_val = le32_to_cpu(nvm_ns->elbaf[i]); - - json_object_add_value_int(elbaf, "sts", elbaf_val & 0x7F); - json_object_add_value_int(elbaf, "pif", (elbaf_val >> 7) & 0x3); - - json_array_add_value_object(elbafs, elbaf); - } - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -static void nvme_show_nvm_id_ns_pic(__u8 pic) -{ - __u8 rsvd = (pic & 0xF8) >> 3; - __u8 stcrs = (pic & 0x3) >> 2; - __u8 pic_16bpistm = (pic & 0x2) >> 1; - __u8 pic_16bpists = pic & 0x1; - - if (rsvd) - printf(" [7:3] : %#x\tReserved\n", rsvd); - printf(" [2:2] : %#x\tStorage Tag Check Read Support\n", stcrs); - printf(" [1:1] : %#x\t16b Guard Protection Information Storage Tag Mask\n", - pic_16bpistm); - printf(" [0:0] : %#x\t16b Guard Protection Information Storage Tag Support\n", - pic_16bpists); - printf("\n"); + nvme_print(id_ctrl_nvm, flags, ctrl_nvm); } void nvme_show_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, struct nvme_id_ns *ns, unsigned int lba_index, bool cap_only, enum nvme_print_flags flags) { - int i, verbose = flags & VERBOSE; - __u32 elbaf; - int pif, sts; - char *in_use = "(in use)"; - - if (flags & BINARY) - return d_raw((unsigned char *)nvm_ns, sizeof(*nvm_ns)); - else if (flags & JSON) - return json_nvme_nvm_id_ns(nvm_ns, ns, cap_only); - - if (!cap_only) { - printf("NVMe NVM Identify Namespace %d:\n", nsid); - printf("lbstm : %#"PRIx64"\n", le64_to_cpu(nvm_ns->lbstm)); - } else { - printf("NVMe NVM Identify Namespace for LBA format[%d]:\n", lba_index); - in_use = ""; - } - printf("pic : %#x\n", nvm_ns->pic); - if (verbose) - nvme_show_nvm_id_ns_pic(nvm_ns->pic); - - for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) { - elbaf = le32_to_cpu(nvm_ns->elbaf[i]); - pif = (elbaf >> 7) & 0x3; - sts = elbaf & 0x7f; - if (verbose) - printf("Extended LBA Format %2d : Protection Information Format: " - "%s(%d) - Storage Tag Size (MSB): %-2d %s\n", - i, pif == 3 ? "Reserved" : - pif == 2 ? "64b Guard" : - pif == 1 ? "32b Guard" : "16b Guard", - pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); - else - printf("elbaf %2d : pif:%d lbads:%-2d %s\n", i, - pif, sts, i == (ns->flbas & 0xf) ? in_use : ""); - } -} - -static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl) -{ - struct json_object *root; - - root = json_create_object(); - json_object_add_value_int(root, "zasl", ctrl->zasl); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode) -{ - if (mode & BINARY) - return d_raw((unsigned char *)ctrl, sizeof(*ctrl)); - else if (mode & JSON) - return json_nvme_zns_id_ctrl(ctrl); - - printf("NVMe ZNS Identify Controller:\n"); - printf("zasl : %u\n", ctrl->zasl); -} - -static void json_nvme_zns_id_ns(struct nvme_zns_id_ns *ns, - struct nvme_id_ns *id_ns) -{ - struct json_object *root; - struct json_object *lbafs; - int i; - - root = json_create_object(); - json_object_add_value_int(root, "zoc", le16_to_cpu(ns->zoc)); - json_object_add_value_int(root, "ozcs", le16_to_cpu(ns->ozcs)); - json_object_add_value_int(root, "mar", le32_to_cpu(ns->mar)); - json_object_add_value_int(root, "mor", le32_to_cpu(ns->mor)); - json_object_add_value_int(root, "rrl", le32_to_cpu(ns->rrl)); - json_object_add_value_int(root, "frl", le32_to_cpu(ns->frl)); - json_object_add_value_int(root, "rrl1", le32_to_cpu(ns->rrl1)); - json_object_add_value_int(root, "rrl2", le32_to_cpu(ns->rrl2)); - json_object_add_value_int(root, "rrl3", le32_to_cpu(ns->rrl3)); - json_object_add_value_int(root, "frl1", le32_to_cpu(ns->frl1)); - json_object_add_value_int(root, "frl2", le32_to_cpu(ns->frl2)); - json_object_add_value_int(root, "frl3", le32_to_cpu(ns->frl3)); - json_object_add_value_int(root, "numzrwa", le32_to_cpu(ns->numzrwa)); - json_object_add_value_int(root, "zrwafg", le16_to_cpu(ns->zrwafg)); - json_object_add_value_int(root, "zrwasz", le16_to_cpu(ns->zrwasz)); - json_object_add_value_int(root, "zrwacap", ns->zrwacap); - - lbafs = json_create_array(); - json_object_add_value_array(root, "lbafe", lbafs); - - for (i = 0; i <= id_ns->nlbaf; i++) { - struct json_object *lbaf = json_create_object(); - - json_object_add_value_int(lbaf, "zsze", - le64_to_cpu(ns->lbafe[i].zsze)); - json_object_add_value_int(lbaf, "zdes", ns->lbafe[i].zdes); - - json_array_add_value_object(lbafs, lbaf); - } - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -static void show_nvme_id_ns_zoned_zoc(__le16 ns_zoc) -{ - __u16 zoc = le16_to_cpu(ns_zoc); - __u8 rsvd = (zoc & 0xfffc) >> 2; - __u8 ze = (zoc & 0x2) >> 1; - __u8 vzc = zoc & 0x1; - if (rsvd) - printf(" [15:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] : %#x\t Zone Active Excursions: %s\n", - ze, ze ? "Yes (Host support required)" : "No"); - printf(" [0:0] : %#x\t Variable Zone Capacity: %s\n", - vzc, vzc ? "Yes (Host support required)" : "No"); - printf("\n"); -} - -static void show_nvme_id_ns_zoned_ozcs(__le16 ns_ozcs) -{ - __u16 ozcs = le16_to_cpu(ns_ozcs); - __u8 rsvd = (ozcs & 0xfffc) >> 2; - __u8 razb = ozcs & 0x1; - __u8 zrwasup = (ozcs & 0x2) >> 1; - - if (rsvd) - printf(" [15:1] : %#x\tReserved\n", rsvd); - printf(" [0:0] : %#x\t Read Across Zone Boundaries: %s\n", - razb, razb ? "Yes" : "No"); - printf(" [1:1] : %#x\t Zone Random Write Area: %s\n", zrwasup, - zrwasup ? "Yes" : "No"); + nvme_print(nvm_id_ns, flags, nvm_ns, nsid, ns, lba_index, cap_only); } -static void nvme_show_zns_id_ns_recommended_limit(__le32 ns_rl, int human, - const char *target_limit) +void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, + enum nvme_print_flags flags) { - unsigned int recommended_limit = le32_to_cpu(ns_rl); - if (!recommended_limit && human) - printf("%s : Not Reported\n", target_limit); - else - printf("%s : %u\n", target_limit, recommended_limit); -} - -static void nvme_show_zns_id_ns_zrwacap(__u8 zrwacap) -{ - __u8 rsvd = (zrwacap & 0xfe) >> 1; - __u8 expflushsup = zrwacap & 0x1; - - if (rsvd) - printf(" [7:1] : %#x\tReserved\n", rsvd); - printf(" [0:0] : %#x\t Explicit ZRWA Flush Operations: %s\n", - expflushsup, expflushsup ? "Yes" : "No"); + nvme_print(zns_id_ctrl, flags, ctrl); } void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns, - struct nvme_id_ns *id_ns, unsigned long flags) + struct nvme_id_ns *id_ns, + enum nvme_print_flags flags) { - int human = flags & VERBOSE, vs = flags & VS; - uint8_t lbaf; - int i; - - nvme_id_ns_flbas_to_lbaf_inuse(id_ns->flbas, &lbaf); - - if (flags & BINARY) - return d_raw((unsigned char *)ns, sizeof(*ns)); - else if (flags & JSON) - return json_nvme_zns_id_ns(ns, id_ns); - - printf("ZNS Command Set Identify Namespace:\n"); - - if (human) { - printf("zoc : %u\tZone Operation Characteristics\n", le16_to_cpu(ns->zoc)); - show_nvme_id_ns_zoned_zoc(ns->zoc); - } else { - printf("zoc : %u\n", le16_to_cpu(ns->zoc)); - } - - if (human) { - printf("ozcs : %u\tOptional Zoned Command Support\n", le16_to_cpu(ns->ozcs)); - show_nvme_id_ns_zoned_ozcs(ns->ozcs); - } else { - printf("ozcs : %u\n", le16_to_cpu(ns->ozcs)); - } - - if (human) { - if (ns->mar == 0xffffffff) { - printf("mar : No Active Resource Limit\n"); - } else { - printf("mar : %u\tActive Resources\n", le32_to_cpu(ns->mar) + 1); - } - } else { - printf("mar : %#x\n", le32_to_cpu(ns->mar)); - } - - if (human) { - if (ns->mor == 0xffffffff) { - printf("mor : No Open Resource Limit\n"); - } else { - printf("mor : %u\tOpen Resources\n", le32_to_cpu(ns->mor) + 1); - } - } else { - printf("mor : %#x\n", le32_to_cpu(ns->mor)); - } - - nvme_show_zns_id_ns_recommended_limit(ns->rrl, human, "rrl "); - nvme_show_zns_id_ns_recommended_limit(ns->frl, human, "frl "); - nvme_show_zns_id_ns_recommended_limit(ns->rrl1, human, "rrl1"); - nvme_show_zns_id_ns_recommended_limit(ns->rrl2, human, "rrl2"); - nvme_show_zns_id_ns_recommended_limit(ns->rrl3, human, "rrl3"); - nvme_show_zns_id_ns_recommended_limit(ns->frl, human, "frl1"); - nvme_show_zns_id_ns_recommended_limit(ns->frl, human, "frl2"); - nvme_show_zns_id_ns_recommended_limit(ns->frl, human, "frl3"); - - printf("numzrwa : %#x\n", le32_to_cpu(ns->numzrwa)); - printf("zrwafg : %u\n", le16_to_cpu(ns->zrwafg)); - printf("zrwasz : %u\n", le16_to_cpu(ns->zrwasz)); - if (human) { - printf("zrwacap : %u\tZone Random Write Area Capability\n", ns->zrwacap); - nvme_show_zns_id_ns_zrwacap(ns->zrwacap); - } else { - printf("zrwacap : %u\n", ns->zrwacap); - } - - for (i = 0; i <= id_ns->nlbaf; i++){ - if (human) - printf("LBA Format Extension %2d : Zone Size: 0x%"PRIx64" LBAs - " - "Zone Descriptor Extension Size: %-1d bytes%s\n", - i, le64_to_cpu(ns->lbafe[i].zsze), ns->lbafe[i].zdes << 6, - i == lbaf ? " (in use)" : ""); - else - printf("lbafe %2d: zsze:0x%"PRIx64" zdes:%u%s\n", i, - (uint64_t)le64_to_cpu(ns->lbafe[i].zsze), - ns->lbafe[i].zdes, i == lbaf ? " (in use)" : ""); - } - - if (vs) { - printf("vs[] :\n"); - d(ns->vs, sizeof(ns->vs), 16, 1); - } + nvme_print(zns_id_ns, flags, ns, id_ns); } -static void json_nvme_list_ns(struct nvme_ns_list *ns_list) +void nvme_show_list_ns(struct nvme_ns_list *ns_list, enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *valid_attrs; - struct json_object *valid; - int i; - - root = json_create_object(); - valid = json_create_array(); - - for (i = 0; i < 1024; i++) { - if (ns_list->ns[i]) { - valid_attrs = json_create_object(); - json_object_add_value_uint(valid_attrs, "nsid", - le32_to_cpu(ns_list->ns[i])); - json_array_add_value_object(valid, valid_attrs); - } - } - json_object_add_value_array(root, "nsid_list", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(ns_list, flags, ns_list); } -void nvme_show_list_ns(struct nvme_ns_list *ns_list, enum nvme_print_flags flags) +void nvme_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list, + enum nvme_print_flags flags) { - int i; - if (flags & JSON) - return json_nvme_list_ns(ns_list); - - for (i = 0; i < 1024; i++) { - if (ns_list->ns[i]) - printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list->ns[i])); - } + nvme_print(zns_start_zone_list, flags, nr_zones, zone_list); } void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log, - unsigned long flags) + enum nvme_print_flags flags) { - uint16_t nrzid; - int i; - - if (flags & BINARY) - return d_raw((unsigned char *)log, sizeof(*log)); - - nrzid = le16_to_cpu(log->nrzid); - printf("NVMe Changed Zone List:\n"); - - if (nrzid == 0xFFFF) { - printf("Too many zones have changed to fit into the log. Use report zones for changes.\n"); - return; - } + nvme_print(zns_changed_zone_log, flags, log); +} - printf("nrzid: %u\n", nrzid); - for (i = 0; i < nrzid; i++) - printf("zid %03d: %"PRIu64"\n", i, (uint64_t)le64_to_cpu(log->zid[i])); +void nvme_zns_finish_zone_list(__u64 nr_zones, struct json_object *zone_list, + enum nvme_print_flags flags) +{ + nvme_print(zns_finish_zone_list, flags, nr_zones, zone_list); } -static char *zone_type_to_string(__u8 cond) +const char *nvme_zone_type_to_string(__u8 cond) { switch (cond) { case NVME_ZONE_TYPE_SEQWRITE_REQ: @@ -5163,7 +505,7 @@ static char *zone_type_to_string(__u8 cond) } } -static char *zone_state_to_string(__u8 state) +const char *nvme_zone_state_to_string(__u8 state) { switch (state) { case NVME_ZNS_ZS_EMPTY: @@ -5185,626 +527,73 @@ static char *zone_state_to_string(__u8 state) } } -void json_nvme_finish_zone_list(__u64 nr_zones, - struct json_object *zone_list) -{ - struct json_object *root = json_create_object(); - json_object_add_value_uint(root, "nr_zones", nr_zones); - json_object_add_value_array(root, "zone_list", zone_list); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -static void json_nvme_zns_report_zones(void *report, __u32 descs, - __u8 ext_size, __u32 report_size, - struct json_object *zone_list) -{ - struct json_object *zone; - struct json_object *ext_data; - struct nvme_zone_report *r = report; - struct nvme_zns_desc *desc; - int i; - - for (i = 0; i < descs; i++) { - desc = (struct nvme_zns_desc *) - (report + sizeof(*r) + i * (sizeof(*desc) + ext_size)); - zone = json_create_object(); - - json_object_add_value_uint64(zone, "slba", - le64_to_cpu(desc->zslba)); - json_object_add_value_uint64(zone, "wp", - le64_to_cpu(desc->wp)); - json_object_add_value_uint64(zone, "cap", - le64_to_cpu(desc->zcap)); - json_object_add_value_string(zone, "state", - zone_state_to_string(desc->zs >> 4)); - json_object_add_value_string(zone, "type", - zone_type_to_string(desc->zt)); - json_object_add_value_uint(zone, "attrs", desc->za); - json_object_add_value_uint(zone, "attrs", desc->zai); - - if (ext_size) { - if (desc->za & NVME_ZNS_ZA_ZDEV) { - ext_data = json_create_array(); - d_json((unsigned char *)desc + sizeof(*desc), - ext_size, 16, 1, ext_data); - json_object_add_value_array(zone, "ext_data", - ext_data); - } else { - json_object_add_value_string(zone, "ext_data", "Not valid"); - } - } - - json_array_add_value_object(zone_list, zone); - } -} - -static void nvme_show_zns_report_zone_attributes(__u8 za, __u8 zai) -{ - const char *const recommended_limit[4] = {"","1","2","3"}; - printf("Attrs: Zone Descriptor Extension is %sVaild\n", - (za & NVME_ZNS_ZA_ZDEV)? "" : "Not "); - if(za & NVME_ZNS_ZA_RZR) { - printf(" Reset Zone Recommended with Reset Recommended Limit%s\n", - recommended_limit[(zai&0xd)>>2]); - } - if (za & NVME_ZNS_ZA_FZR) { - printf(" Finish Zone Recommended with Finish Recommended Limit%s\n", - recommended_limit[zai&0x3]); - } - if (za & NVME_ZNS_ZA_ZFC) { - printf(" Zone Finished by Controller\n"); - } -} - void nvme_show_zns_report_zones(void *report, __u32 descs, - __u8 ext_size, __u32 report_size, unsigned long flags, - struct json_object *zone_list) -{ - struct nvme_zone_report *r = report; - struct nvme_zns_desc *desc; - int i, verbose = flags & VERBOSE; - __u64 nr_zones = le64_to_cpu(r->nr_zones); - - if (nr_zones < descs) - descs = nr_zones; - - if (flags & BINARY) - return d_raw((unsigned char *)report, report_size); - else if (flags & JSON) - return json_nvme_zns_report_zones(report, descs, - ext_size, report_size, zone_list); - - for (i = 0; i < descs; i++) { - desc = (struct nvme_zns_desc *) - (report + sizeof(*r) + i * (sizeof(*desc) + ext_size)); - if(verbose) { - printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %-12s Type: %-14s\n", - (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), - (uint64_t)le64_to_cpu(desc->zcap), zone_state_to_string(desc->zs >> 4), - zone_type_to_string(desc->zt)); - nvme_show_zns_report_zone_attributes(desc->za, desc->zai); - } - else { - printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %#-4x Type: %#-4x Attrs: %#-4x AttrsInfo: %#-4x\n", - (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp), - (uint64_t)le64_to_cpu(desc->zcap), desc->zs, desc->zt, - desc->za, desc->zai); - } - - if (ext_size && (desc->za & NVME_ZNS_ZA_ZDEV)) { - printf("Extension Data: "); - d((unsigned char *)desc + sizeof(*desc), ext_size, 16, 1); - printf("..\n"); - } - } -} - -static void json_nvme_list_ctrl(struct nvme_ctrl_list *ctrl_list, __u16 num) -{ - struct json_object *root; - struct json_object *valid_attrs; - struct json_object *valid; - int i; - - root = json_create_object(); - valid = json_create_array(); - - json_object_add_value_uint(root, "num_ctrl", - le16_to_cpu(ctrl_list->num)); - - for (i = 0; i < min(num, 2047); i++) { - - valid_attrs = json_create_object(); - json_object_add_value_uint(valid_attrs, "ctrl_id", - le16_to_cpu(ctrl_list->identifier[i])); - json_array_add_value_object(valid, valid_attrs); - } - - json_object_add_value_array(root, "ctrl_list", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -void nvme_show_list_ctrl(struct nvme_ctrl_list *ctrl_list, - enum nvme_print_flags flags) -{ - int i; - __u16 num = le16_to_cpu(ctrl_list->num); - - if (flags & BINARY) - return d_raw((unsigned char *)ctrl_list, sizeof(*ctrl_list)); - if (flags & JSON) - return json_nvme_list_ctrl(ctrl_list, num); - - printf("num of ctrls present: %u\n", num); - for (i = 0; i < min(num, 2047); i++) { - printf("[%4u]:%#x\n", i, le16_to_cpu(ctrl_list->identifier[i])); - } -} - -static void json_nvme_id_nvmset(struct nvme_id_nvmset_list *nvmset) -{ - __u32 nent = nvmset->nid; - struct json_object *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].nvmsetid)); - json_object_add_value_int(entry, "endurance_group_id", - le16_to_cpu(nvmset->ent[i].endgid)); - json_object_add_value_int(entry, "random_4k_read_typical", - le32_to_cpu(nvmset->ent[i].rr4kt)); - json_object_add_value_int(entry, "optimal_write_size", - le32_to_cpu(nvmset->ent[i].ows)); - json_object_add_value_double(entry, "total_nvmset_cap", - int128_to_double(nvmset->ent[i].tnvmsetcap)); - json_object_add_value_double(entry, "unalloc_nvmset_cap", - int128_to_double(nvmset->ent[i].unvmsetcap)); - 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_list *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].endgid)); - printf("endurance_group_id : %d\n", - le16_to_cpu(nvmset->ent[i].endgid)); - printf("random_4k_read_typical : %u\n", - le32_to_cpu(nvmset->ent[i].rr4kt)); - printf("optimal_write_size : %u\n", - le32_to_cpu(nvmset->ent[i].ows)); - printf("total_nvmset_cap : %.0Lf\n", - int128_to_double(nvmset->ent[i].tnvmsetcap)); - printf("unalloc_nvmset_cap : %.0Lf\n", - int128_to_double(nvmset->ent[i].unvmsetcap)); - printf(".................\n"); - } -} - -static void json_nvme_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps) -{ - struct json_object *root; - - root = json_create_object(); - - json_object_add_value_uint(root, "cntlid", le16_to_cpu(caps->cntlid)); - json_object_add_value_uint(root, "portid", le16_to_cpu(caps->portid)); - json_object_add_value_uint(root, "crt", caps->crt); - - json_object_add_value_int(root, "vqfrt", le32_to_cpu(caps->vqfrt)); - json_object_add_value_int(root, "vqrfa", le32_to_cpu(caps->vqrfa)); - json_object_add_value_int(root, "vqrfap", le16_to_cpu(caps->vqrfap)); - json_object_add_value_int(root, "vqprt", le16_to_cpu(caps->vqprt)); - json_object_add_value_int(root, "vqfrsm", le16_to_cpu(caps->vqfrsm)); - json_object_add_value_int(root, "vqgran", le16_to_cpu(caps->vqgran)); - - json_object_add_value_int(root, "vifrt", le32_to_cpu(caps->vifrt)); - json_object_add_value_int(root, "virfa", le32_to_cpu(caps->virfa)); - json_object_add_value_int(root, "virfap", le16_to_cpu(caps->virfap)); - json_object_add_value_int(root, "viprt", le16_to_cpu(caps->viprt)); - json_object_add_value_int(root, "vifrsm", le16_to_cpu(caps->vifrsm)); - json_object_add_value_int(root, "vigran", le16_to_cpu(caps->vigran)); - - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - -static void nvme_show_primary_ctrl_caps_crt(__u8 crt) -{ - __u8 rsvd = (crt & 0xFC) >> 2; - __u8 vi = (crt & 0x2) >> 1; - __u8 vq = crt & 0x1; - - if (rsvd) - printf(" [7:2] : %#x\tReserved\n", rsvd); - printf(" [1:1] %#x\tVI Resources are %ssupported\n", vi, vi ? "" : "not "); - printf(" [0:0] %#x\tVQ Resources are %ssupported\n", vq, vq ? "" : "not "); -} - -void nvme_show_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps, + __u8 ext_size, __u32 report_size, + struct json_object *zone_list, enum nvme_print_flags flags) { - int human = flags & VERBOSE; - - if (flags & BINARY) - return d_raw((unsigned char *)caps, sizeof(*caps)); - else if (flags & JSON) - return json_nvme_primary_ctrl_cap(caps); - - printf("NVME Identify Primary Controller Capabilities:\n"); - printf("cntlid : %#x\n", le16_to_cpu(caps->cntlid)); - printf("portid : %#x\n", le16_to_cpu(caps->portid)); - printf("crt : %#x\n", caps->crt); - if (human) - nvme_show_primary_ctrl_caps_crt(caps->crt); - printf("vqfrt : %d\n", le32_to_cpu(caps->vqfrt)); - printf("vqrfa : %d\n", le32_to_cpu(caps->vqrfa)); - printf("vqrfap : %d\n", le16_to_cpu(caps->vqrfap)); - printf("vqprt : %d\n", le16_to_cpu(caps->vqprt)); - printf("vqfrsm : %d\n", le16_to_cpu(caps->vqfrsm)); - printf("vqgran : %d\n", le16_to_cpu(caps->vqgran)); - printf("vifrt : %d\n", le32_to_cpu(caps->vifrt)); - printf("virfa : %d\n", le32_to_cpu(caps->virfa)); - printf("virfap : %d\n", le16_to_cpu(caps->virfap)); - printf("viprt : %d\n", le16_to_cpu(caps->viprt)); - printf("vifrsm : %d\n", le16_to_cpu(caps->vifrsm)); - printf("vigran : %d\n", le16_to_cpu(caps->vigran)); -} - -static void json_nvme_list_secondary_ctrl(const struct nvme_secondary_ctrl_list *sc_list, - __u32 count) -{ - const struct nvme_secondary_ctrl *sc_entry = &sc_list->sc_entry[0]; - __u32 nent = min(sc_list->num, count); - struct json_object *entries; - 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_ctrl_list *sc_list, - __u32 count, enum nvme_print_flags flags) -{ - const struct nvme_secondary_ctrl *sc_entry = - &sc_list->sc_entry[0]; - static const char * const state_desc[] = { "Offline", "Online" }; - - __u16 num = sc_list->num; - __u32 entries = min(num, count); - int i; - - 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_object *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_uint64(entry, "namespace-size-granularity", - le64_to_cpu(glist->entry[i].nszegran)); - json_object_add_value_uint64(entry, "namespace-capacity-granularity", - le64_to_cpu(glist->entry[i].ncapgran)); - 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); + nvme_print(zns_report_zones, flags, + report, descs, ext_size, report_size, zone_list); } -void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist, +void nvme_show_list_ctrl(struct nvme_ctrl_list *ctrl_list, 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].nszegran)); - printf(" NCG : Namespace Capacity Granularity : 0x%"PRIx64"\n", - le64_to_cpu(glist->entry[i].ncapgran)); - } + nvme_print(ctrl_list, flags, ctrl_list); } -static void json_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list) +void nvme_show_id_nvmset(struct nvme_id_nvmset_list *nvmset, unsigned nvmset_id, + enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *entries; - int i; - - root = json_create_object(); - entries = json_create_array(); - /* The 0th entry is reserved */ - for (i = 1; i < NVME_ID_UUID_LIST_MAX; 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); + nvme_print(id_nvmset_list, flags, nvmset, nvmset_id); } -void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, +void nvme_show_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps, 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 = 0; i < NVME_ID_UUID_LIST_MAX; 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+1); - 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"); - } + nvme_print(primary_ctrl_cap, flags, caps); } -static void json_id_domain_list(struct nvme_id_domain_list *id_dom) +void nvme_show_list_secondary_ctrl( + const struct nvme_secondary_ctrl_list *sc_list, + __u32 count, enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *entries; - struct json_object *entry; - int i; - long double dom_cap, unalloc_dom_cap, max_egrp_dom_cap; - - root = json_create_object(); - entries = json_create_array(); - - json_object_add_value_uint(root, "num_dom_entries", id_dom->num); - - for (i = 0; i < id_dom->num; i++) { - entry = json_create_object(); - dom_cap = int128_to_double(id_dom->domain_attr[i].dom_cap); - unalloc_dom_cap = int128_to_double(id_dom->domain_attr[i].unalloc_dom_cap); - max_egrp_dom_cap = int128_to_double(id_dom->domain_attr[i].max_egrp_dom_cap); - - json_object_add_value_uint(entry, "dom_id", le16_to_cpu(id_dom->domain_attr[i].dom_id)); - json_object_add_value_double(entry, "dom_cap", dom_cap); - json_object_add_value_double(entry, "unalloc_dom_cap", unalloc_dom_cap); - json_object_add_value_double(entry, "max_egrp_dom_cap", max_egrp_dom_cap); - - json_array_add_value_object(entries, entry); - } + __u16 num = sc_list->num; + __u32 entries = min(num, count); - json_object_add_value_array(root, "domain_list", entries); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); + nvme_print(secondary_ctrl_list, flags, sc_list, entries); } -void nvme_show_id_domain_list(struct nvme_id_domain_list *id_dom, +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 *)id_dom, sizeof(*id_dom)); - else if (flags & JSON) - return json_id_domain_list(id_dom); - - printf("Number of Domain Entries: %u\n", id_dom->num); - for (i = 0; i < id_dom->num; i++) { - printf("Domain Id for Attr Entry[%u]: %u\n", i, - le16_to_cpu(id_dom->domain_attr[i].dom_id)); - printf("Domain Capacity for Attr Entry[%u]: %.0Lf\\n", i, - int128_to_double(id_dom->domain_attr[i].dom_cap)); - printf("Unallocated Domain Capacity for Attr Entry[%u]: %.0Lf\n", i, - int128_to_double(id_dom->domain_attr[i].unalloc_dom_cap)); - printf("Max Endurance Group Domain Capacity for Attr Entry[%u]: %.0Lf\n", i, - int128_to_double(id_dom->domain_attr[i].max_egrp_dom_cap)); - } + nvme_print(id_ns_granularity_list, flags, glist); } -static void json_nvme_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list) +void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, + enum nvme_print_flags flags) { - struct json_object *root; - struct json_object *valid_attrs; - struct json_object *valid; - int i; - - root = json_create_object(); - valid = json_create_array(); - - json_object_add_value_uint(root, "num_endgrp_id", - le16_to_cpu(endgrp_list->num)); - - for (i = 0; i < min(le16_to_cpu(endgrp_list->num), 2047); i++) { - valid_attrs = json_create_object(); - json_object_add_value_uint(valid_attrs, "endgrp_id", - le16_to_cpu(endgrp_list->identifier[i])); - json_array_add_value_object(valid, valid_attrs); - } + nvme_print(id_uuid_list, flags, uuid_list); +} - json_object_add_value_array(root, "endgrp_list", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); +void nvme_show_id_domain_list(struct nvme_id_domain_list *id_dom, + enum nvme_print_flags flags) +{ + nvme_print(id_domain_list, flags, id_dom); } void nvme_show_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list, enum nvme_print_flags flags) { - int i; - __u16 num = le16_to_cpu(endgrp_list->num); - - if (flags & JSON) - return json_nvme_endurance_group_list(endgrp_list); - - printf("num of endurance group ids: %u\n", num); - for (i = 0; i < min(num, 2047); i++) { - printf("[%4u]:%#x\n", i, le16_to_cpu(endgrp_list->identifier[i])); - } + nvme_print(endurance_group_list, flags, endgrp_list); } -void nvme_show_id_iocs(struct nvme_id_iocs *iocs) +void nvme_show_id_iocs(struct nvme_id_iocs *iocs, enum nvme_print_flags flags) { - __u16 i; - - for (i = 0; i < 512; i++) - if (iocs->iocsc[i]) - printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i, - (uint64_t)le64_to_cpu(iocs->iocsc[i])); + nvme_print(id_iocs, flags, iocs); } -static const char *nvme_trtype_to_string(__u8 trtype) +const char *nvme_trtype_to_string(__u8 trtype) { switch (trtype) { case 0: return "The transport type is not indicated or the error "\ @@ -5818,268 +607,34 @@ static const char *nvme_trtype_to_string(__u8 trtype) } void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries, - const char *devname, enum nvme_print_flags flags) + 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++) { - __u16 status = le16_to_cpu(err_log[i].status_field) >> 0x1; - - printf(" Entry[%2d] \n", i); - printf(".................\n"); - printf("error_count : %"PRIu64"\n", - le64_to_cpu(err_log[i].error_count)); - printf("sqid : %d\n", err_log[i].sqid); - printf("cmdid : %#x\n", err_log[i].cmdid); - printf("status_field : %#x(%s)\n", status, - nvme_status_to_string(status, false)); - printf("phase_tag : %#x\n", - le16_to_cpu(err_log[i].status_field & 0x1)); - printf("parm_err_loc : %#x\n", - err_log[i].parm_error_location); - printf("lba : %#"PRIx64"\n", - le64_to_cpu(err_log[i].lba)); - printf("nsid : %#x\n", err_log[i].nsid); - printf("vs : %d\n", err_log[i].vs); - printf("trtype : %s\n", - nvme_trtype_to_string(err_log[i].trtype)); - printf("cs : %#"PRIx64"\n", - le64_to_cpu(err_log[i].cs)); - printf("trtype_spec_info: %#x\n", err_log[i].trtype_spec_info); - printf(".................\n"); - } + nvme_print(error_log, flags, err_log, entries, devname); } void nvme_show_resv_report(struct nvme_resv_status *status, int bytes, - bool eds, enum nvme_print_flags flags) + bool eds, 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, eds); - - 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 (!eds) { - /* - * if status buffer was too small, don't loop past the end of - * the buffer - */ - entries = (bytes - 24) / 24; - if (entries < regctl) - regctl = entries; - - for (i = 0; i < regctl; i++) { - printf("regctl[%d] :\n", i); - printf(" cntlid : %x\n", - le16_to_cpu(status->regctl_ds[i].cntlid)); - printf(" rcsts : %x\n", - status->regctl_ds[i].rcsts); - printf(" hostid : %"PRIx64"\n", - le64_to_cpu(status->regctl_ds[i].hostid)); - printf(" rkey : %"PRIx64"\n", - le64_to_cpu(status->regctl_ds[i].rkey)); - } - } else { - /* if status buffer was too small, don't loop past the end of the buffer */ - entries = (bytes - 64) / 64; - if (entries < regctl) - regctl = entries; - - for (i = 0; i < regctl; i++) { - printf("regctlext[%d] :\n", i); - printf(" cntlid : %x\n", - le16_to_cpu(status->regctl_eds[i].cntlid)); - printf(" rcsts : %x\n", - status->regctl_eds[i].rcsts); - printf(" rkey : %"PRIx64"\n", - le64_to_cpu(status->regctl_eds[i].rkey)); - printf(" hostid : "); - for (j = 0; j < 16; j++) - printf("%x", - status->regctl_eds[i].hostid[j]); - printf("\n"); - } - } - printf("\n"); + nvme_print(resv_report, flags, status, bytes, eds); } void nvme_show_fw_log(struct nvme_firmware_slot *fw_log, const char *devname, enum nvme_print_flags flags) { - int i; - __le64 *frs; - - 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][0]) { - frs = (__le64 *)&fw_log->frs[i]; - printf("frs%d : %#016"PRIx64" (%s)\n", i + 1, - le64_to_cpu(*frs), - fw_to_string(fw_log->frs[i])); - } - } + nvme_print(fw_log, flags, fw_log, devname); } void nvme_show_changed_ns_list_log(struct nvme_ns_list *log, const char *devname, enum nvme_print_flags flags) { - __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->ns[0] != cpu_to_le32(NVME_NSID_ALL)) { - for (i = 0; i < NVME_ID_NS_LIST_MAX; i++) { - nsid = le32_to_cpu(log->ns[i]); - if (nsid == 0) - break; - - printf("[%4u]:%#x\n", i, nsid); - } - } else - printf("more than %d ns changed\n", - NVME_ID_NS_LIST_MAX); -} - -static void nvme_show_effects_log_human(FILE *stream, __u32 effect) -{ - const char *set = "+"; - const char *clr = "-"; - - fprintf(stream, " CSUPP+"); - fprintf(stream, " LBCC%s", (effect & NVME_CMD_EFFECTS_LBCC) ? set : clr); - fprintf(stream, " NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr); - fprintf(stream, " NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr); - fprintf(stream, " CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr); - fprintf(stream, " USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr); - - if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 0) - fprintf(stream, " No command restriction\n"); - else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 1) - fprintf(stream, " No other command for same namespace\n"); - else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 2) - fprintf(stream, " No other command for any namespace\n"); - else - fprintf(stream, " Reserved CSE\n"); -} - -void nvme_print_effects_entry(FILE* stream, int admin, int index, __le32 entry, unsigned int human) { - __u32 effect; - char *format_string; - - format_string = admin ? "ACS%-6d[%-32s] %08x" : "IOCS%-5d[%-32s] %08x"; - - effect = le32_to_cpu(entry); - if (effect & NVME_CMD_EFFECTS_CSUPP) { - fprintf(stream, format_string, index, nvme_cmd_to_string(admin, index), - effect); - if (human) - nvme_show_effects_log_human(stream, effect); - else - fprintf(stream, "\n"); - } -} - -void nvme_print_effects_log_segment(int admin, int a, int b, struct nvme_cmd_effects_log *effects, char* header, int human) { - FILE *stream; - char *stream_location; - size_t stream_size; - - stream = open_memstream(&stream_location, &stream_size); - if (!stream) { - perror("Failed to open stream"); - return; - } - - for (int i = a; i < b; i++) { - if (admin) { - nvme_print_effects_entry(stream, admin, i, effects->acs[i], human); - } - else { - nvme_print_effects_entry(stream, admin, i, - effects->iocs[i], human); - } - } - - fclose(stream); - - if (stream_size && header) { - printf("%s\n", header); - fwrite(stream_location, stream_size, 1, stdout); - printf("\n"); - } - - free(stream_location); -} - -void nvme_print_effects_log_page(enum nvme_csi csi, struct nvme_cmd_effects_log *effects, int flags) { - int human = flags & VERBOSE; - - switch (csi) { - case NVME_CSI_NVM: - printf("NVM Command Set Log Page\n"); - printf("%-.80s\n", dash); - break; - case NVME_CSI_ZNS: - printf("ZNS Command Set Log Page\n"); - printf("%-.80s\n", dash); - break; - default: - printf("Unknown Command Set Log Page\n"); - printf("%-.80s\n", dash); - break; - } - - nvme_print_effects_log_segment(1, 0, 0xbf, effects, "Admin Commands", human); - nvme_print_effects_log_segment(1, 0xc0, 0xff, effects, "Vendor Specific Admin Commands", human); - nvme_print_effects_log_segment(0, 0, 0x80, effects, "I/O Commands", human); - nvme_print_effects_log_segment(0, 0x80, 0x100, effects, "Vendor Specific I/O Commands", human); + nvme_print(ns_list_log, flags, log, devname); } void nvme_print_effects_log_pages(struct list_head *list, - int flags) + enum nvme_print_flags flags) { - if (flags & JSON) - return json_effects_log_list(list); - - nvme_effects_log_node_t *node; - list_for_each(list, node, node) { - if (flags & BINARY) { - d_raw((unsigned char *)&node->effects, sizeof(node->effects)); - } - else { - nvme_print_effects_log_page(node->csi, &node->effects, flags); - } - } + nvme_print(effects_log_list, flags, list); } const char *nvme_log_to_string(__u8 lid) @@ -6097,12 +652,19 @@ const char *nvme_log_to_string(__u8 lid) case NVME_LOG_LID_ENDURANCE_GROUP: return "Endurance Group Information"; case NVME_LOG_LID_PREDICTABLE_LAT_NVMSET: return "Predictable Latency Per NVM Set"; case NVME_LOG_LID_PREDICTABLE_LAT_AGG: return "Predictable Latency Event Aggregate"; + case NVME_LOG_LID_MEDIA_UNIT_STATUS: return "Media Unit Status"; + case NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST: return "Supported Capacity Configuration List"; case NVME_LOG_LID_ANA: return "Asymmetric Namespace Access"; case NVME_LOG_LID_PERSISTENT_EVENT: return "Persistent Event Log"; case NVME_LOG_LID_LBA_STATUS: return "LBA Status Information"; case NVME_LOG_LID_ENDURANCE_GRP_EVT: return "Endurance Group Event Aggregate"; case NVME_LOG_LID_FID_SUPPORTED_EFFECTS: return "Feature Identifiers Supported and Effects"; + case NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS: return "NVMe-MI Commands Supported and Effects"; case NVME_LOG_LID_BOOT_PARTITION: return "Boot Partition"; + case NVME_LOG_LID_FDP_CONFIGS: return "FDP Configurations"; + case NVME_LOG_LID_FDP_RUH_USAGE: return "Reclaim Unit Handle Usage"; + case NVME_LOG_LID_FDP_STATS: return "FDP Statistics"; + case NVME_LOG_LID_FDP_EVENTS: return "FDP Events"; case NVME_LOG_LID_DISCOVER: return "Discovery"; case NVME_LOG_LID_RESERVATION: return "Reservation Notification"; case NVME_LOG_LID_SANITIZE: return "Sanitize Status"; @@ -6111,415 +673,41 @@ const char *nvme_log_to_string(__u8 lid) } } -static void nvme_show_support_log_human(__u32 support, __u8 lid) -{ - const char *set = "supported"; - const char *clr = "not supported"; - - printf(" LSUPP is %s\n", (support & 0x1) ? set : clr); - printf(" IOS is %s\n", ((support >> 0x1) & 0x1) ? set : clr); - if (lid == NVME_LOG_LID_PERSISTENT_EVENT) { - printf(" Establish Context and Read 512 Bytes of Header is %s\n", - ((support >> 0x16) & 0x1) ? set : clr); - } -} - -static void json_support_log(struct nvme_supported_log_pages *support_log) -{ - struct json_object *root; - struct json_object *valid; - struct json_object *valid_attrs; - unsigned int lid; - char key[128]; - __u32 support; - - root = json_create_object(); - valid = json_create_object(); - - for (lid = 0; lid < 256; lid++) { - support = le32_to_cpu(support_log->lid_support[lid]); - if (support & 0x1) { - valid_attrs = json_create_object(); - sprintf(key, "lid_0x%x ", lid); - json_object_add_value_uint(valid_attrs, key, support); - json_array_add_value_object(valid, valid_attrs); - } - } - - json_object_add_value_object(root, "supported_logs", valid); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); -} - void nvme_show_supported_log(struct nvme_supported_log_pages *support_log, const char *devname, enum nvme_print_flags flags) { - int lid, human = flags & VERBOSE; - __u32 support = 0; - - if (flags & BINARY) - return d_raw((unsigned char *)support_log, sizeof(*support_log)); - else if (flags & JSON) - return json_support_log(support_log); - - printf("Support Log Pages Details for %s:\n", devname); - for (lid = 0; lid < 256; lid++) { - support = le32_to_cpu(support_log->lid_support[lid]); - if (support & 0x1) { - printf("LID 0x%x (%s), supports 0x%x\n", lid, nvme_log_to_string(lid), - support); - if (human) - nvme_show_support_log_human(support, lid); - 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; + nvme_print(supported_log_pages, flags, support_log, devname); } void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log, __u16 group_id, const char *devname, enum nvme_print_flags flags) { - 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)); + nvme_print(endurance_log, flags, endurance_log, group_id, devname); } void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname, enum nvme_print_flags flags) { - __u16 temperature = smart->temperature[1] << 8 | smart->temperature[0]; - int i; - bool human = flags & VERBOSE; - - if (flags & BINARY) - return d_raw((unsigned char *)smart, sizeof(*smart)); - 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 : %ld°C (%u Kelvin)\n", - kelvin_to_celsius(temperature), temperature); - printf("available_spare : %u%%\n", - smart->avail_spare); - printf("available_spare_threshold : %u%%\n", - smart->spare_thresh); - printf("percentage_used : %u%%\n", - smart->percent_used); - printf("endurance group critical warning summary: %#x\n", - smart->endu_grp_crit_warn_sumry); - printf("data_units_read : %'.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 : %ld°C (%u Kelvin)\n", - i + 1, kelvin_to_celsius(temp), temp); - } - printf("Thermal Management T1 Trans Count : %u\n", - le32_to_cpu(smart->thm_temp1_trans_count)); - 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)); + nvme_print(smart_log, flags, smart, nsid, devname); } void nvme_show_ana_log(struct nvme_ana_log *ana_log, const char *devname, - enum nvme_print_flags flags, size_t len) + size_t len, enum nvme_print_flags flags) { - int offset = sizeof(struct nvme_ana_log); - struct nvme_ana_log *hdr = ana_log; - struct nvme_ana_group_desc *desc; - size_t nsid_buf_size; - void *base = ana_log; - __u32 nr_nsids; - int i, j; - - if (flags & BINARY) - return d_raw((unsigned char *)ana_log, len); - else if (flags & JSON) - return json_ana_log(ana_log, devname); - - printf("Asymmetric Namespace Access Log for NVMe device: %s\n", - devname); - printf("ANA LOG HEADER :-\n"); - printf("chgcnt : %"PRIu64"\n", - le64_to_cpu(hdr->chgcnt)); - printf("ngrps : %u\n", le16_to_cpu(hdr->ngrps)); - printf("ANA Log Desc :-\n"); - - for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) { - desc = base + offset; - nr_nsids = le32_to_cpu(desc->nnsids); - nsid_buf_size = nr_nsids * sizeof(__le32); - - offset += sizeof(*desc); - printf("grpid : %u\n", le32_to_cpu(desc->grpid)); - printf("nnsids : %u\n", le32_to_cpu(desc->nnsids)); - printf("chgcnt : %"PRIu64"\n", - le64_to_cpu(desc->chgcnt)); - printf("state : %s\n", - nvme_ana_state_to_string(desc->state)); - for (j = 0; j < le32_to_cpu(desc->nnsids); j++) - printf(" nsid : %u\n", - le32_to_cpu(desc->nsids[j])); - printf("\n"); - offset += nsid_buf_size; - } -} - -static void nvme_show_self_test_result(struct nvme_st_result *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_RESULT_NOT_USED] = "Entry not used (does not contain a result)", - }; - __u8 op, code; - - op = res->dsts & NVME_ST_RESULT_MASK; - printf(" Operation Result : %#x", op); - if (flags & VERBOSE) - printf(" %s", (op < ARRAY_SIZE(test_res) && test_res[op]) ? - test_res[op] : test_res[ARRAY_SIZE(test_res) - 1]); - printf("\n"); - if (op == NVME_ST_RESULT_NOT_USED) - return; - - code = res->dsts >> NVME_ST_CODE_SHIFT; - printf(" Self Test Code : %x", code); - - if (flags & VERBOSE) { - switch (code) { - case NVME_ST_CODE_SHORT: - printf(" Short device self-test operation"); - break; - case NVME_ST_CODE_EXTENDED: - printf(" Extended device self-test operation"); - break; - case NVME_ST_CODE_VS: - printf(" Vendor specific"); - break; - default: - printf(" Reserved"); - break; - } - } - printf("\n"); - - if (op == NVME_ST_RESULT_KNOWN_SEG_FAIL) - printf(" Segment Number : %#x\n", res->seg); - - printf(" Valid Diagnostic Information : %#x\n", res->vdi); - printf(" Power on hours (POH) : %#"PRIx64"\n", - (uint64_t)le64_to_cpu(res->poh)); - - if (res->vdi & NVME_ST_VALID_DIAG_INFO_NSID) - printf(" Namespace Identifier : %#x\n", - le32_to_cpu(res->nsid)); - if (res->vdi & NVME_ST_VALID_DIAG_INFO_FLBA) - printf(" Failing LBA : %#"PRIx64"\n", - (uint64_t)le64_to_cpu(res->flba)); - if (res->vdi & NVME_ST_VALID_DIAG_INFO_SCT) - printf(" Status Code Type : %#x\n", res->sct); - if (res->vdi & NVME_ST_VALID_DIAG_INFO_SC) { - printf(" Status Code : %#x", res->sc); - if (flags & VERBOSE) - printf(" %s", nvme_status_to_string( - (res->sct & 7) << 8 | res->sc, false)); - printf("\n"); - } - printf(" Vendor Specific : %#x %#x\n", - res->vs[0], res->vs[1]); + nvme_print(ana_log, flags, ana_log, devname, len); } void nvme_show_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries, __u32 size, const char *devname, enum nvme_print_flags flags) { - int i; - __u8 num_entries; - - if (flags & BINARY) - return d_raw((unsigned char *)self_test, size); - if (flags & JSON) - return json_self_test_log(self_test, dst_entries); - - printf("Device Self Test Log for NVME device:%s\n", devname); - printf("Current operation : %#x\n", self_test->current_operation); - printf("Current Completion : %u%%\n", self_test->completion); - num_entries = min(dst_entries, NVME_LOG_ST_MAX_RESULTS); - for (i = 0; i < num_entries; i++) { - printf("Self Test Result[%d]:\n", i); - 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_SSTAT_COMPLETED_PASSES_SHIFT) & - NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK); - - printf("\t [8]\t"); - if (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED) - str = "Global Data Erased set: no NS LB in the NVM subsystem "\ - "has been written to and no PMR in the NVM subsystem "\ - "has been enabled"; - else - str = "Global Data Erased cleared: a NS LB in the NVM "\ - "subsystem has been written to or a PMR in the NVM "\ - "subsystem has been enabled"; - printf("%s\n", str); -} - -static void nvme_show_estimate_sanitize_time(const char *text, uint32_t value) -{ - printf("%s: %u%s\n", text, value, - value == 0xffffffff ? " (No time period reported)" : ""); + nvme_print(self_test_log, flags, self_test, dst_entries, size, devname); } void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize, const char *devname, enum nvme_print_flags flags) { - int human = flags & VERBOSE; - __u16 status = le16_to_cpu(sanitize->sstat) & NVME_SANITIZE_SSTAT_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->sprog)); - - if (human && status == NVME_SANITIZE_SSTAT_STATUS_IN_PROGESS) - nvme_show_sanitize_log_sprog(le16_to_cpu(sanitize->sprog)); - else - printf("\n"); - - printf("Sanitize Status (SSTAT) : %#x\n", - le16_to_cpu(sanitize->sstat) & NVME_SANITIZE_SSTAT_STATUS_MASK); - if (human) - nvme_show_sanitize_log_sstat(le16_to_cpu(sanitize->sstat)); - - printf("Sanitize Command Dword 10 Information (SCDW10) : %#x\n", - le32_to_cpu(sanitize->scdw10)); - nvme_show_estimate_sanitize_time("Estimated Time For Overwrite ", - le32_to_cpu(sanitize->eto)); - nvme_show_estimate_sanitize_time("Estimated Time For Block Erase ", - le32_to_cpu(sanitize->etbe)); - nvme_show_estimate_sanitize_time("Estimated Time For Crypto Erase ", - le32_to_cpu(sanitize->etce)); - nvme_show_estimate_sanitize_time("Estimated Time For Overwrite (No-Deallocate) ", - le32_to_cpu(sanitize->etond)); - nvme_show_estimate_sanitize_time("Estimated Time For Block Erase (No-Deallocate) ", - le32_to_cpu(sanitize->etbend)); - nvme_show_estimate_sanitize_time("Estimated Time For Crypto Erase (No-Deallocate)", - le32_to_cpu(sanitize->etcend)); + nvme_print(sanitize_log_page, flags, sanitize, devname); } const char *nvme_feature_to_string(enum nvme_features_id feature) @@ -6559,6 +747,8 @@ const char *nvme_feature_to_string(enum nvme_features_id feature) case NVME_FEAT_FID_RESV_MASK: return "Reservation Notification Mask"; case NVME_FEAT_FID_RESV_PERSIST:return "Reservation Persistence"; case NVME_FEAT_FID_WRITE_PROTECT: return "Namespace Write Protect"; + case NVME_FEAT_FID_FDP: return "Flexible Direct Placement"; + case NVME_FEAT_FID_FDP_EVENTS: return "Flexible Direct Placement Events"; } /* * We don't use the "default:" statement to let the compiler warning if @@ -6599,17 +789,12 @@ const char *nvme_select_to_string(int sel) } } -void nvme_show_select_result(__u32 result) +void nvme_show_select_result(enum nvme_features_id fid, __u32 result) { - if (result & 0x1) - printf(" Feature is saveable\n"); - if (result & 0x2) - printf(" Feature is per-namespace\n"); - if (result & 0x4) - printf(" Feature is changeable\n"); + nvme_print(select_result, NORMAL, fid, result); } -static const char *nvme_feature_lba_type_to_string(__u8 type) +const char *nvme_feature_lba_type_to_string(__u8 type) { switch (type) { case 0: return "Reserved"; @@ -6625,31 +810,13 @@ static const char *nvme_feature_lba_type_to_string(__u8 type) } } -void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges) +void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges, + enum nvme_print_flags flags) { - int i, j; - - for (i = 0; i <= nr_ranges; i++) { - printf("\ttype : %#x - %s\n", lbrt->entry[i].type, - nvme_feature_lba_type_to_string(lbrt->entry[i].type)); - printf("\tattributes : %#x - %s, %s\n", lbrt->entry[i].attributes, - (lbrt->entry[i].attributes & 0x0001) ? - "LBA range may be overwritten" : - "LBA range should not be overwritten", - ((lbrt->entry[i].attributes & 0x0002) >> 1) ? - "LBA range should be hidden from the OS/EFI/BIOS" : - "LBA range should be visible from the OS/EFI/BIOS"); - printf("\tslba : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].slba)); - printf("\tnlb : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].nlb)); - printf("\tguid : "); - for (j = 0; j < 16; j++) - printf("%02x", lbrt->entry[i].guid[j]); - printf("\n"); - } + nvme_print(lba_range, flags, lbrt, nr_ranges); } - -static const char *nvme_feature_wl_hints_to_string(__u8 wh) +const char *nvme_feature_wl_hints_to_string(__u8 wh) { switch (wh) { case 0: return "No Workload"; @@ -6659,7 +826,7 @@ static const char *nvme_feature_wl_hints_to_string(__u8 wh) } } -static const char *nvme_feature_temp_type_to_string(__u8 type) +const char *nvme_feature_temp_type_to_string(__u8 type) { switch (type) { case 0: return "Over Temperature Threshold"; @@ -6668,7 +835,7 @@ static const char *nvme_feature_temp_type_to_string(__u8 type) } } -static const char *nvme_feature_temp_sel_to_string(__u8 sel) +const char *nvme_feature_temp_sel_to_string(__u8 sel) { switch (sel) { case 0: return "Composite Temperature"; @@ -6684,62 +851,7 @@ static const char *nvme_feature_temp_sel_to_string(__u8 sel) } } -static void nvme_show_auto_pst(struct nvme_feat_auto_pst *apst) -{ - int i; - __u64 value; - - printf( "\tAuto PST Entries"); - printf("\t.................\n"); - for (i = 0; i < 32; i++) { - value = le64_to_cpu(apst->apst_entry[i]); - - printf("\tEntry[%2d] \n", i); - printf("\t.................\n"); - printf("\tIdle Time Prior to Transition (ITPT): %u ms\n", - (__u32)(value >> NVME_APST_ENTRY_ITPT_SHIFT) & NVME_APST_ENTRY_ITPT_MASK); - printf("\tIdle Transition Power State (ITPS): %u\n", - (__u32)(value >> NVME_APST_ENTRY_ITPS_SHIFT ) & NVME_APST_ENTRY_ITPS_MASK); - printf("\t.................\n"); - } -} - -static void nvme_show_timestamp(struct nvme_timestamp *ts) -{ - struct tm *tm; - char buffer[320]; - time_t timestamp = int48_to_long(ts->timestamp) / 1000; - - tm = localtime(×tamp); - - printf("\tThe timestamp is : %'"PRIu64" (%s)\n", - int48_to_long(ts->timestamp), - strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-"); - printf("\t%s\n", (ts->attr & 2) ? - "The Timestamp field was initialized with a "\ - "Timestamp value using a Set Features command." : - "The Timestamp field was initialized "\ - "to ‘0’ by a Controller Level Reset."); - printf("\t%s\n", (ts->attr & 1) ? - "The controller may have stopped counting during vendor specific "\ - "intervals after the Timestamp value was initialized" : - "The controller counted time in milliseconds "\ - "continuously since the Timestamp value was initialized."); -} - -static void nvme_show_host_mem_buffer(struct nvme_host_mem_buf_attrs *hmb) -{ - printf("\tHost Memory Descriptor List Entry Count (HMDLEC): %u\n", - le32_to_cpu(hmb->hmdlec)); - printf("\tHost Memory Descriptor List Address (HMDLAU): 0x%x\n", - le32_to_cpu(hmb->hmdlau)); - printf("\tHost Memory Descriptor List Address (HMDLAL): 0x%x\n", - le32_to_cpu(hmb->hmdlal)); - printf("\tHost Memory Buffer Size (HSIZE): %u\n", - le32_to_cpu(hmb->hsize)); -} - -static const char *nvme_show_ns_wp_cfg(enum nvme_ns_write_protect_cfg state) +const char *nvme_ns_wp_cfg_to_string(enum nvme_ns_write_protect_cfg state) { switch (state) { case NVME_NS_WP_CFG_NONE: @@ -6755,94 +867,13 @@ static const char *nvme_show_ns_wp_cfg(enum nvme_ns_write_protect_cfg state) } } -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_DIRECTIVE_DTYPE_IDENTIFY: - switch (doper) { - case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM: - printf("\tDirective support \n"); - printf("\t\tIdentify Directive : %s\n", - (*field & 0x1) ? "supported":"not supported"); - printf("\t\tStream Directive : %s\n", - (*field & 0x2) ? "supported":"not supported"); - printf("\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_DIRECTIVE_DTYPE_STREAMS: - switch (doper) { - case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM: - printf("\tMax Streams Limit (MSL): %u\n", - *(__u16 *) field); - printf("\tNVM Subsystem Streams Available (NSSA): %u\n", - *(__u16 *) (field + 2)); - printf("\tNVM Subsystem Streams Open (NSSO): %u\n", - *(__u16 *) (field + 4)); - printf("\tNVM Subsystem Stream Capability (NSSC): %u\n", - *(__u16 *) (field + 6)); - printf("\tStream Write Size (in unit of LB size) (SWS): %u\n", - *(__u32 *) (field + 16)); - printf("\tStream Granularity Size (in unit of SWS) (SGS): %u\n", - *(__u16 *) (field + 20)); - printf("\tNamespace Streams Allocated (NSA): %u\n", - *(__u16 *) (field + 22)); - printf("\tNamespace Streams Open (NSO): %u\n", - *(__u16 *) (field + 24)); - break; - case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS: - count = *(__u16 *) field; - printf("\tOpen Stream Count : %u\n", *(__u16 *) field); - for ( i = 0; i < count; i++ ) { - printf("\tStream Identifier %.6u : %u\n", i + 1, - *(__u16 *) (field + ((i + 1) * 2))); - } - break; - case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE: - printf("\tNamespace Streams Allocated (NSA): %u\n", - result & 0xffff); - break; - default: - fprintf(stderr, - "invalid directive operations for Streams Directives\n"); - } - break; - 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) + 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); + nvme_print(directive, flags, type, oper, spec, nsid, result, buf, len); } -static const char *nvme_plm_window(__u32 plm) +const char *nvme_plm_window_to_string(__u32 plm) { switch (plm & 0x7) { case 1: @@ -6856,313 +887,100 @@ static const char *nvme_plm_window(__u32 plm) void nvme_show_lba_status_info(__u32 result) { - printf("\tLBA Status Information Poll Interval (LSIPI) : %u\n", (result >> 16) & 0xffff); - printf("\tLBA Status Information Report Interval (LSIRI): %u\n", result & 0xffff); + nvme_print(lba_status_info, NORMAL, result); } -static void nvme_show_plm_config(struct nvme_plm_config *plmcfg) +const char *nvme_host_metadata_type_to_string(enum nvme_features_id fid, __u8 type) { - printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->ee)); - printf("\tDTWIN Reads Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwinrt)); - printf("\tDTWIN Writes Threshold:%"PRIu64"\n", le64_to_cpu(plmcfg->dtwinwt)); - printf("\tDTWIN Time Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwintt)); + switch (fid) { + case NVME_FEAT_FID_ENH_CTRL_METADATA: + case NVME_FEAT_FID_CTRL_METADATA: + switch (type) { + case NVME_CTRL_METADATA_OS_CTRL_NAME: + return "Operating System Controller Name"; + case NVME_CTRL_METADATA_OS_DRIVER_NAME: + return "Operating System Driver Name"; + case NVME_CTRL_METADATA_OS_DRIVER_VER: + return "Operating System Driver Version"; + case NVME_CTRL_METADATA_PRE_BOOT_CTRL_NAME: + return "Pre-boot Controller Name"; + case NVME_CTRL_METADATA_PRE_BOOT_DRIVER_NAME: + return "Pre-boot Driver Name"; + case NVME_CTRL_METADATA_PRE_BOOT_DRIVER_VER: + return "Pre-boot Driver Version"; + case NVME_CTRL_METADATA_SYS_PROC_MODEL: + return "System Processor Model"; + case NVME_CTRL_METADATA_CHIPSET_DRV_NAME: + return "Chipset Driver Name"; + case NVME_CTRL_METADATA_CHIPSET_DRV_VERSION: + return "Chipset Driver Version"; + case NVME_CTRL_METADATA_OS_NAME_AND_BUILD: + return "Operating System Name and Build"; + case NVME_CTRL_METADATA_SYS_PROD_NAME: + return "System Product Name"; + case NVME_CTRL_METADATA_FIRMWARE_VERSION: + return "Firmware Version"; + case NVME_CTRL_METADATA_OS_DRIVER_FILENAME: + return "Operating System Driver Filename"; + case NVME_CTRL_METADATA_DISPLAY_DRV_NAME: + return "Display Driver Name"; + case NVME_CTRL_METADATA_DISPLAY_DRV_VERSION: + return "Display Driver Version"; + case NVME_CTRL_METADATA_HOST_DET_FAIL_REC: + return "Host-Determined Failure Record"; + default: + return "Unknown Controller Type"; + } + case NVME_FEAT_FID_NS_METADATA: + switch (type) { + case NVME_NS_METADATA_OS_NS_NAME: + return "Operating System Namespace Name"; + case NVME_NS_METADATA_PRE_BOOT_NS_NAME: + return "Pre-boot Namespace Name"; + case NVME_NS_METADATA_OS_NS_QUAL_1: + return "Operating System Namespace Name Qualifier 1"; + case NVME_NS_METADATA_OS_NS_QUAL_2: + return "Operating System Namespace Name Qualifier 2"; + default: + return "Unknown Namespace Type"; + } + default: + return "Unknown Feature"; + } } -static char *nvme_show_host_metadata_type_to_string(enum nvme_features_id fid, - __u8 type) +const char *nvme_pel_rci_rcpit_to_string(enum nvme_pel_rci_rcpit rcpit) { - switch (fid) { - case NVME_FEAT_FID_ENH_CTRL_METADATA: - case NVME_FEAT_FID_CTRL_METADATA: - switch (type) { - case NVME_CTRL_METADATA_OS_CTRL_NAME: - return "Operating System Controller Name"; - case NVME_CTRL_METADATA_OS_DRIVER_NAME: - return "Operating System Driver Name"; - case NVME_CTRL_METADATA_OS_DRIVER_VER: - return "Operating System Driver Version"; - case NVME_CTRL_METADATA_PRE_BOOT_CTRL_NAME: - return "Pre-boot Controller Name"; - case NVME_CTRL_METADATA_PRE_BOOT_DRIVER_NAME: - return "Pre-boot Driver Name"; - case NVME_CTRL_METADATA_PRE_BOOT_DRIVER_VER: - return "Pre-boot Driver Version"; - case NVME_CTRL_METADATA_SYS_PROC_MODEL: - return "System Processor Model"; - case NVME_CTRL_METADATA_CHIPSET_DRV_NAME: - return "Chipset Driver Name"; - case NVME_CTRL_METADATA_CHIPSET_DRV_VERSION: - return "Chipset Driver Version"; - case NVME_CTRL_METADATA_OS_NAME_AND_BUILD: - return "Operating System Name and Build"; - case NVME_CTRL_METADATA_SYS_PROD_NAME: - return "System Product Name"; - case NVME_CTRL_METADATA_FIRMWARE_VERSION: - return "Firmware Version"; - case NVME_CTRL_METADATA_OS_DRIVER_FILENAME: - return "Operating System Driver Filename"; - case NVME_CTRL_METADATA_DISPLAY_DRV_NAME: - return "Display Driver Name"; - case NVME_CTRL_METADATA_DISPLAY_DRV_VERSION: - return "Display Driver Version"; - case NVME_CTRL_METADATA_HOST_DET_FAIL_REC: - return "Host-Determined Failure Record"; - default: - return "Unknown Controller Type"; - } - case NVME_FEAT_FID_NS_METADATA: - switch (type) { - case NVME_NS_METADATA_OS_NS_NAME: - return "Operating System Namespace Name"; - case NVME_NS_METADATA_PRE_BOOT_NS_NAME: - return "Pre-boot Namespace Name"; - case NVME_NS_METADATA_OS_NS_QUAL_1: - return "Operating System Namespace Name Qualifier 1"; - case NVME_NS_METADATA_OS_NS_QUAL_2: - return "Operating System Namespace Name Qualifier 2"; - default: - return "Unknown Namespace Type"; - } - default: - return "Unknown Feature"; - } + switch (rcpit) { + case NVME_PEL_RCI_RCPIT_NOT_EXIST: + return "Does not already exist"; + case NVME_PEL_RCI_RCPIT_EST_PORT: + return "NVM subsystem port"; + case NVME_PEL_RCI_RCPIT_EST_ME: + return "NVMe-MI port"; + default: + break; + } + return "Reserved"; } -static void nvme_show_host_metadata(enum nvme_features_id fid, - struct nvme_host_metadata *data) +void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result) { - struct nvme_metadata_element_desc *desc = &data->descs[0]; - int i; - char val[4096]; - __u16 len; - - printf("\tNum Metadata Element Descriptors: %d\n", data->ndesc); - for (i = 0; i < data->ndesc; i++) { - len = le16_to_cpu(desc->len); - strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len)); - - printf("\tElement[%-3d]:\n", i); - printf("\t\tType : 0x%02x (%s)\n", desc->type, - nvme_show_host_metadata_type_to_string(fid, desc->type)); - printf("\t\tRevision : %d\n", desc->rev); - printf("\t\tLength : %d\n", len); - printf("\t\tValue : %s\n", val); - - desc = (struct nvme_metadata_element_desc *) - &desc->val[desc->len]; - } + nvme_print(show_feature, NORMAL, fid, sel, result); } void nvme_feature_show_fields(enum nvme_features_id fid, unsigned int result, unsigned char *buf) { - __u8 field; - uint64_t ull; - - switch (fid) { - case NVME_FEAT_FID_ARBITRATION: - printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1); - printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1); - printf("\tLow Priority Weight (LPW): %u\n", ((result & 0x0000ff00) >> 8) + 1); - printf("\tArbitration Burst (AB): "); - if ((result & 0x00000007) == 7) - printf("No limit\n"); - else - printf("%u\n", 1 << (result & 0x00000007)); - break; - case NVME_FEAT_FID_POWER_MGMT: - field = (result & 0x000000E0) >> 5; - printf("\tWorkload Hint (WH): %u - %s\n", field, nvme_feature_wl_hints_to_string(field)); - printf("\tPower State (PS): %u\n", result & 0x0000001f); - break; - case NVME_FEAT_FID_LBA_RANGE: - field = result & 0x0000003f; - printf("\tNumber of LBA Ranges (NUM): %u\n", field + 1); - if (buf) - nvme_show_lba_range((struct nvme_lba_range_type *)buf, field); - break; - case NVME_FEAT_FID_TEMP_THRESH: - field = (result & 0x00300000) >> 20; - printf("\tThreshold Type Select (THSEL): %u - %s\n", field, - nvme_feature_temp_type_to_string(field)); - field = (result & 0x000f0000) >> 16; - printf("\tThreshold Temperature Select (TMPSEL): %u - %s\n", - field, nvme_feature_temp_sel_to_string(field)); - printf("\tTemperature Threshold (TMPTH): %ld°C (%u Kelvin)\n", - kelvin_to_celsius(result & 0x0000ffff), result & 0x0000ffff); - break; - case NVME_FEAT_FID_ERR_RECOVERY: - printf("\tDeallocated or Unwritten Logical Block Error Enable (DULBE): %s\n", - ((result & 0x00010000) >> 16) ? "Enabled":"Disabled"); - printf("\tTime Limited Error Recovery (TLER): %u ms\n", - (result & 0x0000ffff) * 100); - break; - case NVME_FEAT_FID_VOLATILE_WC: - printf("\tVolatile Write Cache Enable (WCE): %s\n", (result & 0x00000001) ? "Enabled":"Disabled"); - break; - case NVME_FEAT_FID_NUM_QUEUES: - printf("\tNumber of IO Completion Queues Allocated (NCQA): %u\n", ((result & 0xffff0000) >> 16) + 1); - printf("\tNumber of IO Submission Queues Allocated (NSQA): %u\n", (result & 0x0000ffff) + 1); - break; - case NVME_FEAT_FID_IRQ_COALESCE: - printf("\tAggregation Time (TIME): %u usec\n", ((result & 0x0000ff00) >> 8) * 100); - printf("\tAggregation Threshold (THR): %u\n", (result & 0x000000ff) + 1); - break; - case NVME_FEAT_FID_IRQ_CONFIG: - printf("\tCoalescing Disable (CD): %s\n", ((result & 0x00010000) >> 16) ? "True":"False"); - printf("\tInterrupt Vector (IV): %u\n", result & 0x0000ffff); - break; - case NVME_FEAT_FID_WRITE_ATOMIC: - printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True":"False"); - break; - case NVME_FEAT_FID_ASYNC_EVENT: - printf("\tDiscovery Log Page Change Notices : %s\n", - ((result & 0x80000000) >> 31) ? "Send async event":"Do not send async event"); - printf("\tEndurance Group Event Aggregate Log Change Notices : %s\n", - ((result & 0x00004000) >> 14) ? "Send async event":"Do not send async event"); - printf("\tLBA Status Information Notices : %s\n", - ((result & 0x00002000) >> 13) ? "Send async event":"Do not send async event"); - printf("\tPredictable Latency Event Aggregate Log Change Notices : %s\n", - ((result & 0x00001000) >> 12) ? "Send async event":"Do not send async event"); - printf("\tAsymmetric Namespace Access Change Notices : %s\n", - ((result & 0x00000800) >> 11) ? "Send async event":"Do not send async event"); - printf("\tTelemetry Log Notices : %s\n", - ((result & 0x00000400) >> 10) ? "Send async event":"Do not send async event"); - printf("\tFirmware Activation Notices : %s\n", - ((result & 0x00000200) >> 9) ? "Send async event":"Do not send async event"); - printf("\tNamespace Attribute Notices : %s\n", - ((result & 0x00000100) >> 8) ? "Send async event":"Do not send async event"); - printf("\tSMART / Health Critical Warnings : %s\n", - (result & 0x000000ff) ? "Send async event":"Do not send async event"); - break; - case NVME_FEAT_FID_AUTO_PST: - printf("\tAutonomous Power State Transition Enable (APSTE): %s\n", - (result & 0x00000001) ? "Enabled":"Disabled"); - if (buf) - nvme_show_auto_pst((struct nvme_feat_auto_pst *)buf); - break; - case NVME_FEAT_FID_HOST_MEM_BUF: - printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled":"Disabled"); - if (buf) - nvme_show_host_mem_buffer((struct nvme_host_mem_buf_attrs *)buf); - break; - case NVME_FEAT_FID_TIMESTAMP: - if (buf) - nvme_show_timestamp((struct nvme_timestamp *)buf); - break; - case NVME_FEAT_FID_KATO: - printf("\tKeep Alive Timeout (KATO) in milliseconds: %u\n", result); - break; - case NVME_FEAT_FID_HCTM: - printf("\tThermal Management Temperature 1 (TMT1) : %u Kelvin (%ld°C)\n", - result >> 16, kelvin_to_celsius(result >> 16)); - printf("\tThermal Management Temperature 2 (TMT2) : %u Kelvin (%ld°C)\n", - result & 0x0000ffff, kelvin_to_celsius(result & 0x0000ffff)); - break; - case NVME_FEAT_FID_NOPSC: - printf("\tNon-Operational Power State Permissive Mode Enable (NOPPME): %s\n", - (result & 1) ? "True" : "False"); - break; - case NVME_FEAT_FID_RRL: - printf("\tRead Recovery Level (RRL): %u\n", result & 0xf); - break; - case NVME_FEAT_FID_PLM_CONFIG: - printf("\tPredictable Latency Window Enabled: %s\n", result & 0x1 ? "True":"False"); - if (buf) - nvme_show_plm_config((struct nvme_plm_config *)buf); - break; - case NVME_FEAT_FID_PLM_WINDOW: - printf("\tWindow Select: %s", nvme_plm_window(result)); - break; - case NVME_FEAT_FID_LBA_STS_INTERVAL: - nvme_show_lba_status_info(result); - break; - case NVME_FEAT_FID_HOST_BEHAVIOR: - if (buf) - printf("\tHost Behavior Support: %s\n", (buf[0] & 0x1) ? "True" : "False"); - break; - case NVME_FEAT_FID_SANITIZE: - printf("\tNo-Deallocate Response Mode (NODRM) : %u\n", result & 0x1); - break; - case NVME_FEAT_FID_ENDURANCE_EVT_CFG: - printf("\tEndurance Group Identifier (ENDGID): %u\n", result & 0xffff); - printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff); - break; - case NVME_FEAT_FID_IOCS_PROFILE: - printf("\tI/O Command Set Profile: %s\n", result & 0x1 ? "True":"False"); - break; - case NVME_FEAT_FID_SPINUP_CONTROL: - printf("\tSpinup control feature Enabled: %s\n", (result & 1) ? "True" : "False"); - break; - case NVME_FEAT_FID_ENH_CTRL_METADATA: - case NVME_FEAT_FID_CTRL_METADATA: - case NVME_FEAT_FID_NS_METADATA: - if (buf) - nvme_show_host_metadata(fid, (struct nvme_host_metadata *)buf); - break; - case NVME_FEAT_FID_SW_PROGRESS: - printf("\tPre-boot Software Load Count (PBSLC): %u\n", result & 0x000000ff); - break; - case NVME_FEAT_FID_HOST_ID: - if (buf) { - ull = buf[7]; ull <<= 8; ull |= buf[6]; ull <<= 8; ull |= buf[5]; ull <<= 8; - ull |= buf[4]; ull <<= 8; ull |= buf[3]; ull <<= 8; ull |= buf[2]; ull <<= 8; - ull |= buf[1]; ull <<= 8; ull |= buf[0]; - printf("\tHost Identifier (HOSTID): %" PRIu64 "\n", ull); - } - break; - case NVME_FEAT_FID_RESV_MASK: - printf("\tMask Reservation Preempted Notification (RESPRE): %s\n", - ((result & 0x00000008) >> 3) ? "True":"False"); - printf("\tMask Reservation Released Notification (RESREL): %s\n", - ((result & 0x00000004) >> 2) ? "True":"False"); - printf("\tMask Registration Preempted Notification (REGPRE): %s\n", - ((result & 0x00000002) >> 1) ? "True":"False"); - break; - case NVME_FEAT_FID_RESV_PERSIST: - printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True":"False"); - break; - case NVME_FEAT_FID_WRITE_PROTECT: - printf("\tNamespace Write Protect: %s\n", nvme_show_ns_wp_cfg(result)); - break; - default: - break; - } + nvme_print(show_feature_fields, NORMAL, fid, result, buf); } void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len, - enum nvme_print_flags flags) + enum nvme_print_flags flags) { - int idx; - - if (flags & BINARY) - return d_raw((unsigned char *)list, len); - - printf("Number of LBA Status Descriptors(NLSD): %" PRIu32 "\n", - le32_to_cpu(list->nlsd)); - printf("Completion Condition(CMPC): %u\n", list->cmpc); - - switch (list->cmpc) { - case 1: - printf("\tCompleted due to transferring the amount of data"\ - " specified in the MNDW field\n"); - break; - case 2: - printf("\tCompleted due to having performed the action\n"\ - "\tspecified in the Action Type field over the\n"\ - "\tnumber of logical blocks specified in the\n"\ - "\tRange Length field\n"); - break; - } - - 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); - } + nvme_print(lba_status, flags, list, len); } -static void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len) +void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len) { struct stat st; @@ -7181,7 +999,7 @@ static void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len) snprintf(path, len, "%s", nvme_ns_get_name(n)); } -static void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len) +void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len) { int head_instance; int instance; @@ -7193,7 +1011,7 @@ static void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len) if (stat(path, &st) == 0) return; - snprintf(path, len, "/dev/spkd/ng%dn%d", instance, head_instance); + snprintf(path, len, "/dev/spdk/ng%dn%d", instance, head_instance); if (stat(path, &st) == 0) return; /* @@ -7205,340 +1023,68 @@ static void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len) void nvme_show_list_item(nvme_ns_t n) { - char usage[128] = { 0 }, format[128] = { 0 }; - char devname[128] = { 0 }; char genname[128] = { 0 }; - - long long lba = nvme_ns_get_lba_size(n); - double nsze = nvme_ns_get_lba_count(n) * lba; - double nuse = nvme_ns_get_lba_util(n) * lba; - - const char *s_suffix = suffix_si_get(&nsze); - const char *u_suffix = suffix_si_get(&nuse); - const char *l_suffix = suffix_binary_get(&lba); - - snprintf(usage, sizeof(usage), "%6.2f %2sB / %6.2f %2sB", nuse, - u_suffix, nsze, s_suffix); - snprintf(format, sizeof(format), "%3.0f %2sB + %2d B", (double)lba, - l_suffix, nvme_ns_get_meta_size(n)); - - nvme_dev_full_path(n, devname, sizeof(devname)); - nvme_generic_full_path(n, genname, sizeof(genname)); - - printf("%-21s %-21s %-20s %-40s %-9d %-26s %-16s %-8s\n", - devname, genname, nvme_ns_get_serial(n), - nvme_ns_get_model(n), nvme_ns_get_nsid(n), usage, format, - nvme_ns_get_firmware(n)); + nvme_print(list_item, NORMAL, n); } -static void nvme_show_simple_list(nvme_root_t r) +void nvme_show_list_items(nvme_root_t r, enum nvme_print_flags flags) { - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; - nvme_ns_t n; - - printf("%-21s %-21s %-20s %-40s %-9s %-26s %-16s %-8s\n", - "Node", "Generic", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev"); - printf("%-.21s %-.21s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", - dash, dash, dash, dash, dash, dash, dash, dash); - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ns(s, n) - nvme_show_list_item(n); - - nvme_subsystem_for_each_ctrl(s, c) - nvme_ctrl_for_each_ns(c, n) - nvme_show_list_item(n); - } - } + nvme_print(list_items, flags, r); } -static void nvme_show_ns_details(nvme_ns_t n) +void nvme_show_topology(nvme_root_t r, + enum nvme_cli_topo_ranking ranking, + enum nvme_print_flags flags) { - char usage[128] = { 0 }, format[128] = { 0 }; - char devname[128] = { 0 }, genname[128] = { 0 }; + if (ranking == NVME_CLI_TOPO_NAMESPACE) + nvme_print(topology_namespace, flags, r); + else + nvme_print(topology_ctrl, flags, r); +} - long long lba = nvme_ns_get_lba_size(n); - double nsze = nvme_ns_get_lba_count(n) * lba; - double nuse = nvme_ns_get_lba_util(n) * lba; +void nvme_show_message(bool error, const char *msg, ...) +{ + struct print_ops *ops = nvme_print_ops(NORMAL); + va_list ap; - const char *s_suffix = suffix_si_get(&nsze); - const char *u_suffix = suffix_si_get(&nuse); - const char *l_suffix = suffix_binary_get(&lba); + va_start(ap, msg); - sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix); - sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix, - nvme_ns_get_meta_size(n)); + if (nvme_is_output_format_json()) + ops = nvme_print_ops(JSON); - nvme_dev_full_path(n, devname, sizeof(devname)); - nvme_generic_full_path(n, genname, sizeof(genname)); + if (ops && ops->show_message) + ops->show_message(error, msg, ap); - printf("%-12s %-12s %-8x %-26s %-16s ", devname, - genname, nvme_ns_get_nsid(n), usage, format); + va_end(ap); } -static void nvme_show_detailed_list(nvme_root_t r) +void nvme_show_perror(const char *msg) { - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; - nvme_path_t p; - nvme_ns_t n; - - printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers"); - printf("%-.16s %-.96s %-.16s\n", dash, dash, dash); - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - bool first = true; - printf("%-16s %-96s ", nvme_subsystem_get_name(s), - nvme_subsystem_get_nqn(s)); - - nvme_subsystem_for_each_ctrl(s, c) { - printf("%s%s", first ? "": ", ", - nvme_ctrl_get_name(c)); - first = false; - } - printf("\n"); - } - } - printf("\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); - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ctrl(s, c) { - bool first = true; - - printf("%-8s %-20s %-40s %-8s %-6s %-14s %-12s ", - nvme_ctrl_get_name(c), - nvme_ctrl_get_serial(c), - nvme_ctrl_get_model(c), - nvme_ctrl_get_firmware(c), - nvme_ctrl_get_transport(c), - nvme_ctrl_get_address(c), - nvme_subsystem_get_name(s)); - - nvme_ctrl_for_each_ns(c, n) { - printf("%s%s", first ? "": ", ", - nvme_ns_get_name(n)); - first = false; - } - - nvme_ctrl_for_each_path(c, p) { - n = nvme_path_get_ns(p); - if (!n) - continue; - printf("%s%s", first ? "": ", ", - nvme_ns_get_name(n)); - first = false; - } - printf("\n"); - } - } - } - printf("\n"); - - printf("%-12s %-12s %-8s %-26s %-16s %-16s\n", "Device", "Generic", - "NSID", "Usage", "Format", "Controllers"); - printf("%-.12s %-.12s %-.8s %-.26s %-.16s %-.16s\n", dash, dash, dash, - dash, dash, dash); - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ctrl(s, c) { - nvme_ctrl_for_each_ns(c, n) { - nvme_show_ns_details(n); - printf("%s\n", nvme_ctrl_get_name(c)); - } - } - - nvme_subsystem_for_each_ns(s, n) { - bool first = true; - - nvme_show_ns_details(n); - nvme_subsystem_for_each_ctrl(s, c) { - printf("%s%s", first ? "" : ", ", - nvme_ctrl_get_name(c)); - first = false; - } - printf("\n"); - } - } - } -} + struct print_ops *ops = nvme_print_ops(NORMAL); -static void json_detail_list(nvme_root_t r) -{ - struct json_object *jroot = json_create_object(); - struct json_object *jdev = json_create_array(); - - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; - nvme_path_t p; - nvme_ns_t n; - - nvme_for_each_host(r, h) { - struct json_object *hss = json_create_object(); - struct json_object *jsslist = json_create_array(); - - json_object_add_value_string(hss, "HostNQN", nvme_host_get_hostnqn(h)); - json_object_add_value_string(hss, "HostID", nvme_host_get_hostid(h)); - - nvme_for_each_subsystem(h , s) { - struct json_object *jss = json_create_object(); - struct json_object *jctrls = json_create_array(); - struct json_object *jnss = json_create_array(); - - json_object_add_value_string(jss, "Subsystem", nvme_subsystem_get_name(s)); - json_object_add_value_string(jss, "SubsystemNQN", nvme_subsystem_get_nqn(s)); - - nvme_subsystem_for_each_ctrl(s, c) { - struct json_object *jctrl = json_create_object(); - struct json_object *jnss = json_create_array(); - struct json_object *jpaths = json_create_array(); - - json_object_add_value_string(jctrl, "Controller", nvme_ctrl_get_name(c)); - json_object_add_value_string(jctrl, "SerialNumber", nvme_ctrl_get_serial(c)); - json_object_add_value_string(jctrl, "ModelNumber", nvme_ctrl_get_model(c)); - json_object_add_value_string(jctrl, "Firmware", nvme_ctrl_get_firmware(c)); - json_object_add_value_string(jctrl, "Transport", nvme_ctrl_get_transport(c)); - json_object_add_value_string(jctrl, "Address", nvme_ctrl_get_address(c)); - - nvme_ctrl_for_each_ns(c, n) { - struct json_object *jns = json_create_object(); - long long lba = nvme_ns_get_lba_size(n); - double nsze = nvme_ns_get_lba_count(n) * lba; - double nuse = nvme_ns_get_lba_util(n) * lba; - - json_object_add_value_string(jns, "NameSpace", nvme_ns_get_name(n)); - json_object_add_value_int(jns, "NSID", nvme_ns_get_nsid(n)); - json_object_add_value_int(jns, "UsedBytes", nuse); - json_object_add_value_int(jns, "MaximumLBA", nvme_ns_get_lba_count(n)); - json_object_add_value_int(jns, "PhysicalSize", nsze); - json_object_add_value_int(jns, "SectorSize", lba); - - json_array_add_value_object(jnss, jns); - } - json_object_add_value_object(jctrl, "Namespaces", jnss); - - nvme_ctrl_for_each_path(c, p) { - struct json_object *jpath = json_create_object(); - - json_object_add_value_string(jpath, "Path", nvme_path_get_name(p)); - json_object_add_value_string(jpath, "ANAState", nvme_path_get_ana_state(p)); - - json_array_add_value_object(jpaths, jpath); - } - json_object_add_value_object(jctrl, "Paths", jpaths); - - json_array_add_value_object(jctrls, jctrl); - } - json_object_add_value_object(jss, "Controllers", jctrls); - - nvme_subsystem_for_each_ns(s, n) { - struct json_object *jns = json_create_object(); - - long long lba = nvme_ns_get_lba_size(n); - double nsze = nvme_ns_get_lba_count(n) * lba; - double nuse = nvme_ns_get_lba_util(n) * lba; - - json_object_add_value_string(jns, "NameSpace", nvme_ns_get_name(n)); - json_object_add_value_int(jns, "NSID", nvme_ns_get_nsid(n)); - json_object_add_value_int(jns, "UsedBytes", nuse); - json_object_add_value_int(jns, "MaximumLBA", nvme_ns_get_lba_count(n)); - json_object_add_value_int(jns, "PhysicalSize", nsze); - json_object_add_value_int(jns, "SectorSize", lba); - - json_array_add_value_object(jnss, jns); - } - json_object_add_value_object(jss, "Namespaces", jnss); - - json_array_add_value_object(jsslist, jss); - } + if (nvme_is_output_format_json()) + ops = nvme_print_ops(JSON); - json_object_add_value_object(hss, "Subsystems", jsslist); - json_array_add_value_object(jdev, hss); - } - json_object_add_value_array(jroot, "Devices", jdev); - json_print_object(jroot, NULL); - printf("\n"); - json_free_object(jroot); + if (ops && ops->show_perror) + ops->show_perror(msg); } -static struct json_object *json_list_item(nvme_ns_t n) +void nvme_show_discovery_log(struct nvmf_discovery_log *log, uint64_t numrec, + enum nvme_print_flags flags) { - struct json_object *jdevice = json_create_object(); - char devname[128] = { 0 }; - - long long lba = nvme_ns_get_lba_size(n); - double nsze = nvme_ns_get_lba_count(n) * lba; - double nuse = nvme_ns_get_lba_util(n) * lba; - - nvme_dev_full_path(n, devname, sizeof(devname)); - - json_object_add_value_int(jdevice, "NameSpace", nvme_ns_get_nsid(n)); - json_object_add_value_string(jdevice, "DevicePath", devname); - json_object_add_value_string(jdevice, "Firmware", nvme_ns_get_firmware(n)); - json_object_add_value_string(jdevice, "ModelNumber", nvme_ns_get_model(n)); - json_object_add_value_string(jdevice, "SerialNumber", nvme_ns_get_serial(n)); - json_object_add_value_int(jdevice, "UsedBytes", nuse); - json_object_add_value_int(jdevice, "MaximumLBA", nvme_ns_get_lba_count(n)); - json_object_add_value_int(jdevice, "PhysicalSize", nsze); - json_object_add_value_int(jdevice, "SectorSize", lba); - - return jdevice; + nvme_print(discovery_log, flags, log, numrec); } -static void json_simple_list(nvme_root_t r) +void nvme_show_connect_msg(nvme_ctrl_t c, enum nvme_print_flags flags) { - struct json_object *jroot = json_create_object(); - struct json_object *jdevices = json_create_array(); - - nvme_host_t h; - nvme_subsystem_t s; - nvme_ctrl_t c; - nvme_ns_t n; - - nvme_for_each_host(r, h) { - nvme_for_each_subsystem(h, s) { - nvme_subsystem_for_each_ns(s, n) - json_array_add_value_object(jdevices, - json_list_item(n)); - - nvme_subsystem_for_each_ctrl(s, c) - nvme_ctrl_for_each_ns(c, n) - json_array_add_value_object(jdevices, - json_list_item(n)); - } - } - json_object_add_value_array(jroot, "Devices", jdevices); - json_print_object(jroot, NULL); - printf("\n"); - json_free_object(jroot); + nvme_print(connect_msg, flags, c); } -static void json_print_list_items(nvme_root_t r, - enum nvme_print_flags flags) +void nvme_show_init(void) { - if (flags & VERBOSE) - json_detail_list(r); - else - json_simple_list(r); + nvme_print_output_format(show_init); } -void nvme_show_list_items(nvme_root_t r, enum nvme_print_flags flags) +void nvme_show_finish(void) { - if (flags & JSON) - json_print_list_items(r, flags); - else if (flags & VERBOSE) - nvme_show_detailed_list(r); - else - nvme_show_simple_list(r); + nvme_print_output_format(show_finish); } diff --git a/nvme-print.h b/nvme-print.h index a318862d79..5ded3b6bec 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -8,22 +8,143 @@ #include typedef struct nvme_effects_log_node { + struct nvme_cmd_effects_log effects; /* needs to be first member because of alignment requirement. */ enum nvme_csi csi; - struct nvme_cmd_effects_log effects; struct list_node node; } nvme_effects_log_node_t; +#define nvme_show_error(msg, ...) nvme_show_message(true, msg, ##__VA_ARGS__) +#define nvme_show_result(msg, ...) nvme_show_message(false, msg, ##__VA_ARGS__) + void d(unsigned char *buf, int len, int width, int group); void d_raw(unsigned char *buf, unsigned len); -uint64_t int48_to_long(__u8 *data); -void nvme_show_status(__u16 status); +struct print_ops { + /* libnvme types.h print functions */ + void (*ana_log)(struct nvme_ana_log *ana_log, const char *devname, size_t len); + void (*boot_part_log)(void *bp_log, const char *devname, __u32 size); + void (*phy_rx_eom_log)(struct nvme_phy_rx_eom_log *log, __u16 controller); + void (*ctrl_list)(struct nvme_ctrl_list *ctrl_list); + void (*ctrl_registers)(void *bar, bool fabrics); + void (*directive)(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, void *buf, __u32 len); + void (*discovery_log)(struct nvmf_discovery_log *log, int numrec); + void (*effects_log_list)(struct list_head *list); + void (*endurance_group_event_agg_log)(struct nvme_aggregate_predictable_lat_event *endurance_log, __u64 log_entries, __u32 size, const char *devname); + void (*endurance_group_list)(struct nvme_id_endurance_group_list *endgrp_list); + void (*endurance_log)(struct nvme_endurance_group_log *endurance_group, __u16 group_id, const char *devname); + void (*error_log)(struct nvme_error_log_page *err_log, int entries, const char *devname); + void (*fdp_config_log)(struct nvme_fdp_config_log *log, size_t len); + void (*fdp_event_log)(struct nvme_fdp_events_log *log); + void (*fdp_ruh_status)(struct nvme_fdp_ruh_status *status, size_t len); + void (*fdp_stats_log)(struct nvme_fdp_stats_log *log); + void (*fdp_usage_log)(struct nvme_fdp_ruhu_log *log, size_t len); + void (*fid_supported_effects_log)(struct nvme_fid_supported_effects_log *fid_log, const char *devname); + void (*fw_log)(struct nvme_firmware_slot *fw_log, const char *devname); + void (*id_ctrl)(struct nvme_id_ctrl *ctrl, void (*vs)(__u8 *vs, struct json_object *root)); + void (*id_ctrl_nvm)(struct nvme_id_ctrl_nvm *ctrl_nvm); + void (*id_domain_list)(struct nvme_id_domain_list *id_dom); + void (*id_independent_id_ns)(struct nvme_id_independent_id_ns *ns, unsigned int nsid); + void (*id_iocs)(struct nvme_id_iocs *ioscs); + void (*id_ns)(struct nvme_id_ns *ns, unsigned int nsid, unsigned int lba_index, bool cap_only); + void (*id_ns_descs)(void *data, unsigned int nsid); + void (*id_ns_granularity_list)(const struct nvme_id_ns_granularity_list *list); + void (*id_nvmset_list)(struct nvme_id_nvmset_list *nvmset, unsigned int nvmeset_id); + void (*id_uuid_list)(const struct nvme_id_uuid_list *uuid_list); + void (*lba_status)(struct nvme_lba_status *list, unsigned long len); + void (*lba_status_log)(void *lba_status, __u32 size, const char *devname); + void (*media_unit_stat_log)(struct nvme_media_unit_stat_log *mus); + void (*mi_cmd_support_effects_log)(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, const char *devname); + void (*ns_list)(struct nvme_ns_list *ns_list); + void (*ns_list_log)(struct nvme_ns_list *log, const char *devname); + void (*nvm_id_ns)(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, struct nvme_id_ns *ns, unsigned int lba_index, bool cap_only); + void (*persistent_event_log)(void *pevent_log_info, __u8 action, __u32 size, const char *devname); + void (*predictable_latency_event_agg_log)(struct nvme_aggregate_predictable_lat_event *pea_log, __u64 log_entries, __u32 size, const char *devname); + void (*predictable_latency_per_nvmset)(struct nvme_nvmset_predictable_lat_log *plpns_log, __u16 nvmset_id, const char *devname); + void (*primary_ctrl_cap)(const struct nvme_primary_ctrl_cap *caps); + void (*resv_notification_log)(struct nvme_resv_notification_log *resv, const char *devname); + void (*resv_report)(struct nvme_resv_status *status, int bytes, bool eds); + void (*sanitize_log_page)(struct nvme_sanitize_log_page *sanitize_log, const char *devname); + void (*secondary_ctrl_list)(const struct nvme_secondary_ctrl_list *sc_list, __u32 count); + void (*select_result)(enum nvme_features_id fid, __u32 result); + void (*self_test_log)(struct nvme_self_test_log *self_test, __u8 dst_entries, __u32 size, const char *devname); + void (*single_property)(int offset, uint64_t value64); + void (*smart_log)(struct nvme_smart_log *smart, unsigned int nsid, const char *devname); + void (*supported_cap_config_list_log)(struct nvme_supported_cap_config_list_log *cap_log); + void (*supported_log_pages)(struct nvme_supported_log_pages *support_log, const char *devname); + void (*zns_start_zone_list)(__u64 nr_zones, struct json_object **zone_list); + void (*zns_changed_zone_log)(struct nvme_zns_changed_zone_log *log); + void (*zns_finish_zone_list)(__u64 nr_zones, struct json_object *zone_list); + void (*zns_id_ctrl)(struct nvme_zns_id_ctrl *ctrl); + void (*zns_id_ns)(struct nvme_zns_id_ns *ns, struct nvme_id_ns *id_ns); + void (*zns_report_zones)(void *report, __u32 descs, __u8 ext_size, __u32 report_size, struct json_object *zone_list); + void (*show_feature)(enum nvme_features_id fid, int sel, unsigned int result); + void (*show_feature_fields)(enum nvme_features_id fid, unsigned int result, unsigned char *buf); + void (*id_ctrl_rpmbs)(__le32 ctrl_rpmbs); + void (*lba_range)(struct nvme_lba_range_type *lbrt, int nr_ranges); + void (*lba_status_info)(__u32 result); + void (*d)(unsigned char *buf, int len, int width, int group); + void (*show_init)(void); + void (*show_finish)(void); + + /* libnvme tree print functions */ + void (*list_item)(nvme_ns_t n); + void (*list_items)(nvme_root_t t); + void (*print_nvme_subsystem_list)(nvme_root_t r, bool show_ana); + void (*topology_ctrl)(nvme_root_t r); + void (*topology_namespace)(nvme_root_t r); + + /* status and error messages */ + void (*connect_msg)(nvme_ctrl_t c); + void (*show_message)(bool error, const char *msg, va_list ap); + void (*show_perror)(const char *msg); + void (*show_status)(int status); + void (*show_error_status)(int status, const char *msg, va_list ap); + + enum nvme_print_flags flags; +}; + +struct nvme_bar_cap { + __u16 mqes; + __u8 cqr:1; + __u8 ams:2; + __u8 rsvd19:5; + __u8 to; + __u16 dstrd:4; + __u16 nssrs:1; + __u16 css:8; + __u16 bps:1; + __u8 cps:2; + __u8 mpsmin:4; + __u8 mpsmax:4; + __u8 pmrs:1; + __u8 cmbs:1; + __u8 nsss:1; + __u8 crwms:1; + __u8 crims:1; + __u8 rsvd61:3; +}; + +#ifdef CONFIG_JSONC + +struct print_ops *nvme_get_json_print_ops(enum nvme_print_flags flags); + +#else /* !CONFIG_JSONC */ + +static inline struct print_ops *nvme_get_json_print_ops(enum nvme_print_flags flags) { return NULL; } + +#endif /* !CONFIG_JSONC */ + +struct print_ops *nvme_get_stdout_print_ops(enum nvme_print_flags flags); +struct print_ops *nvme_get_binary_print_ops(enum nvme_print_flags flags); + +void nvme_show_status(int status); void nvme_show_lba_status_info(__u32 result); void nvme_show_relatives(const char *name); -void nvme_show_id_iocs(struct nvme_id_iocs *iocs); -void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, +void nvme_show_id_iocs(struct nvme_id_iocs *iocs, enum nvme_print_flags flags); +void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, void (*vendor_show)(__u8 *vs, struct json_object *root)); +void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs, enum nvme_print_flags flags); void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, unsigned int lba_index, bool cap_only, enum nvme_print_flags flags); void nvme_show_cmd_set_independent_id_ns( @@ -31,7 +152,8 @@ void nvme_show_cmd_set_independent_id_ns( enum nvme_print_flags flags); void nvme_show_resv_report(struct nvme_resv_status *status, int bytes, bool eds, enum nvme_print_flags flags); -void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges); +void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges, + enum nvme_print_flags flags); void nvme_show_supported_log(struct nvme_supported_log_pages *support, const char *devname, enum nvme_print_flags flags); void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries, @@ -39,12 +161,13 @@ void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries, void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname, enum nvme_print_flags flags); void nvme_show_ana_log(struct nvme_ana_log *ana_log, const char *devname, - enum nvme_print_flags flags, size_t len); + size_t len, enum nvme_print_flags flags); void nvme_show_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries, __u32 size, const char *devname, enum nvme_print_flags flags); void nvme_show_fw_log(struct nvme_firmware_slot *fw_log, const char *devname, enum nvme_print_flags flags); -void nvme_print_effects_log_pages(struct list_head *list, int flags); +void nvme_print_effects_log_pages(struct list_head *list, + enum nvme_print_flags flags); void nvme_show_changed_ns_list_log(struct nvme_ns_list *log, const char *devname, enum nvme_print_flags flags); void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log, @@ -61,9 +184,6 @@ void nvme_show_predictable_latency_event_agg_log( void nvme_show_persistent_event_log(void *pevent_log_info, __u8 action, __u32 size, const char *devname, enum nvme_print_flags flags); -void json_endurance_group_event_agg_log( - struct nvme_aggregate_predictable_lat_event *endurance_log, - __u64 log_entries); void nvme_show_endurance_group_event_agg_log( struct nvme_aggregate_predictable_lat_event *endurance_log, __u64 log_entries, __u32 size, const char *devname, @@ -74,6 +194,8 @@ void nvme_show_resv_notif_log(struct nvme_resv_notification_log *resv, const char *devname, enum nvme_print_flags flags); void nvme_show_boot_part_log(void *bp_log, const char *devname, __u32 size, enum nvme_print_flags flags); +void nvme_show_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, + __u16 controller, enum nvme_print_flags flags); void nvme_show_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log, const char *devname, enum nvme_print_flags flags); void nvme_show_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, @@ -83,7 +205,7 @@ void nvme_show_media_unit_stat_log(struct nvme_media_unit_stat_log *mus, void nvme_show_supported_cap_config_log(struct nvme_supported_cap_config_list_log *caplog, enum nvme_print_flags flags); void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags); -void nvme_show_single_property(int offset, uint64_t prop, int human); +void nvme_show_single_property(int offset, uint64_t prop, enum nvme_print_flags flags); void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags); void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len, enum nvme_print_flags flags); @@ -108,32 +230,85 @@ void nvme_show_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_ enum nvme_print_flags flags); void nvme_show_list_ns(struct nvme_ns_list *ns_list, enum nvme_print_flags flags); +void nvme_show_topology(nvme_root_t t, + enum nvme_cli_topo_ranking ranking, + enum nvme_print_flags flags); +void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result); void nvme_feature_show_fields(enum nvme_features_id fid, unsigned int result, unsigned char *buf); void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, void *buf, __u32 len, enum nvme_print_flags flags); -void nvme_show_select_result(__u32 result); +void nvme_show_select_result(enum nvme_features_id fid, __u32 result); -void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode); +void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, + enum nvme_print_flags flags); void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm, enum nvme_print_flags flags); void nvme_show_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, struct nvme_id_ns *ns, unsigned int lba_index, bool cap_only, enum nvme_print_flags flags); void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns, - struct nvme_id_ns *id_ns, unsigned long flags); -void nvme_show_zns_changed( struct nvme_zns_changed_zone_log *log, - unsigned long flags); + struct nvme_id_ns *id_ns, enum nvme_print_flags flags); +void nvme_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list, + enum nvme_print_flags flags); +void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log, + enum nvme_print_flags flags); +void nvme_zns_finish_zone_list(__u64 nr_zones, struct json_object *zone_list, + enum nvme_print_flags flags); void nvme_show_zns_report_zones(void *report, __u32 descs, - __u8 ext_size, __u32 report_size, unsigned long flags, - struct json_object *zone_list); + __u8 ext_size, __u32 report_size, + struct json_object *zone_list, + enum nvme_print_flags flags); void json_nvme_finish_zone_list(__u64 nr_zones, struct json_object *zone_list); void nvme_show_list_item(nvme_ns_t n); +void nvme_show_fdp_configs(struct nvme_fdp_config_log *configs, size_t len, + enum nvme_print_flags flags); +void nvme_show_fdp_stats(struct nvme_fdp_stats_log *log, + enum nvme_print_flags flags); +void nvme_show_fdp_events(struct nvme_fdp_events_log *log, + enum nvme_print_flags flags); +void nvme_show_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len, + enum nvme_print_flags flags); +void nvme_show_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len, + enum nvme_print_flags flags); + +void nvme_show_discovery_log(struct nvmf_discovery_log *log, uint64_t numrec, + enum nvme_print_flags flags); +void nvme_show_connect_msg(nvme_ctrl_t c, enum nvme_print_flags flags); + +const char *nvme_ana_state_to_string(enum nvme_ana_state state); const char *nvme_cmd_to_string(int admin, __u8 opcode); -const char *nvme_select_to_string(int sel); +const char *nvme_fdp_event_to_string(enum nvme_fdp_event_type event); +const char *nvme_feature_lba_type_to_string(__u8 type); +const char *nvme_feature_temp_sel_to_string(__u8 sel); +const char *nvme_feature_temp_type_to_string(__u8 type); const char *nvme_feature_to_string(enum nvme_features_id feature); +const char *nvme_feature_wl_hints_to_string(__u8 wh); +const char *nvme_host_metadata_type_to_string(enum nvme_features_id fid, __u8 type); +const char *nvme_log_to_string(__u8 lid); +const char *nvme_nss_hw_error_to_string(__u16 error_code); +const char *nvme_pel_event_to_string(int type); +const char *nvme_register_pmr_hsts_to_string(__u8 hsts); +const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu); +const char *nvme_register_szu_to_string(__u8 szu); const char *nvme_register_to_string(int reg); +const char *nvme_resv_notif_to_string(__u8 type); +const char *nvme_select_to_string(int sel); +const char *nvme_sstat_status_to_string(__u16 status); +const char *nvme_trtype_to_string(__u8 trtype); +const char *nvme_zone_state_to_string(__u8 state); +const char *nvme_zone_type_to_string(__u8 cond); +const char *nvme_plm_window_to_string(__u32 plm); +const char *nvme_ns_wp_cfg_to_string(enum nvme_ns_write_protect_cfg state); +const char *nvme_pel_rci_rcpit_to_string(enum nvme_pel_rci_rcpit rcpit); -#endif +void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len); +void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len); +void nvme_show_message(bool error, const char *msg, ...); +void nvme_show_perror(const char *msg); +void nvme_show_error_status(int status, const char *msg, ...); +void nvme_show_init(void); +void nvme_show_finish(void); +#endif /* NVME_PRINT_H */ diff --git a/nvme-rpmb.c b/nvme-rpmb.c index 40ddb5b2e3..345e6ea53f 100644 --- a/nvme-rpmb.c +++ b/nvme-rpmb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2020 Micron Techology Inc. All rights reserved. + * Copyright (C) 2020 Micron Technology Inc. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,6 +32,7 @@ #include "common.h" #include "nvme.h" #include "libnvme.h" +#include "nvme-print.h" #define CREATE_CMD @@ -48,7 +49,6 @@ #define HMAC_SHA256_HASH_SIZE 32 #define MD5_HASH_HASH_SIZE 16 -extern int nvme_show_id_ctrl_rpmbs(unsigned int); /* * Utility function to create hash value of given data (with given key) using * given hash algorithm; this function uses kernel crypto services @@ -68,7 +68,7 @@ unsigned char *create_hash(const char *algo, .salg_name = { 0 } }; - /* copy algorith name */ + /* copy algorithm name */ if (strlen(algo) > sizeof(provider_sa.salg_name)) { fprintf(stderr, "%s: algorithm name overflow", __func__); return hash; @@ -608,7 +608,7 @@ static int rpmb_program_auth_key(int fd, unsigned char target, goto out; } - /* re-use response buffer */ + /* reuse response buffer */ memset(rsp, 0, rsp_size); err = recv_rpmb_rsp(fd, req->target, rsp_size, rsp); if (err != 0) { @@ -903,7 +903,7 @@ int rpmb_cmd_option(int argc, char **argv, struct command *cmd, struct plugin *p /* parse and validate options; default print rpmb support info */ if (cfg.cmd == 0 || strcmp(cfg.cmd, "info") == 0) { - nvme_show_id_ctrl_rpmbs(regs.rpmbs); + nvme_show_id_ctrl_rpmbs(regs.rpmbs, 0); goto out; } @@ -1005,7 +1005,7 @@ int rpmb_cmd_option(int argc, char **argv, struct command *cmd, struct plugin *p cfg.blocks, (regs.access_size + 1)); if (err > 0 && msg_buf != NULL) { - printf("Writting %d bytes to file %s\n", + printf("Writing %d bytes to file %s\n", err * 512, cfg.msgfile); write_file(msg_buf, err * 512, NULL, cfg.msgfile, NULL); diff --git a/nvme-wrap.c b/nvme-wrap.c index 7b2c4f2cf4..5df562a458 100644 --- a/nvme-wrap.c +++ b/nvme-wrap.c @@ -40,7 +40,6 @@ int __rc; \ if (d->type == NVME_DEV_DIRECT) { \ args->fd = d->direct.fd; \ - args->timeout = NVME_DEFAULT_IOCTL_TIMEOUT; \ __rc = nvme_ ## op(args); \ } else if (d->type == NVME_DEV_MI) \ __rc = nvme_mi_admin_ ## op (d->mi.ctrl, args); \ @@ -77,6 +76,12 @@ int nvme_cli_identify_ns(struct nvme_dev *dev, __u32 nsid, return do_admin_op(identify_ns, dev, nsid, ns); } +int nvme_cli_identify_ns_descs(struct nvme_dev *dev, __u32 nsid, + struct nvme_ns_id_desc *descs) +{ + return do_admin_op(identify_ns_descs, dev, nsid, descs); +} + int nvme_cli_identify_allocated_ns(struct nvme_dev *dev, __u32 nsid, struct nvme_id_ns *ns) { @@ -95,6 +100,20 @@ int nvme_cli_identify_allocated_ns_list(struct nvme_dev *dev, __u32 nsid, return do_admin_op(identify_allocated_ns_list, dev, nsid, list); } +int nvme_cli_identify_primary_ctrl(struct nvme_dev *dev, __u32 nsid, + struct nvme_primary_ctrl_cap *cap) +{ + return do_admin_op(identify_primary_ctrl, dev, nsid, cap); +} + +int nvme_cli_identify_secondary_ctrl_list(struct nvme_dev *dev, + __u16 ctrl_id, + struct nvme_secondary_ctrl_list *sc_list) +{ + return do_admin_op(identify_secondary_ctrl_list, dev, ctrl_id, + sc_list); +} + int nvme_cli_get_features(struct nvme_dev *dev, struct nvme_get_features_args *args) { @@ -138,6 +157,12 @@ int nvme_cli_get_log(struct nvme_dev *dev, struct nvme_get_log_args *args) return do_admin_args_op(get_log, dev, args); } +int nvme_cli_get_log_page(struct nvme_dev *dev, __u32 xfer_len, + struct nvme_get_log_args *args) +{ + return do_admin_op(get_log_page, dev, xfer_len, args); +} + int nvme_cli_get_nsid_log(struct nvme_dev *dev, bool rae, enum nvme_cmd_get_log_lid lid, __u32 nsid, __u32 len, void *log) @@ -277,6 +302,12 @@ int nvme_cli_get_log_boot_partition(struct nvme_dev *dev, bool rae, __u8 lsp, return do_admin_op(get_log_boot_partition, dev, rae, lsp, len, part); } +int nvme_cli_get_log_phy_rx_eom(struct nvme_dev *dev, __u8 lsp, __u16 controller, + __u32 len, struct nvme_phy_rx_eom_log *part) +{ + return do_admin_op(get_log_phy_rx_eom, dev, lsp, controller, len, part); +} + int nvme_cli_get_log_discovery(struct nvme_dev *dev, bool rae, __u32 offset, __u32 len, void *log) { @@ -323,18 +354,77 @@ int nvme_cli_get_log_persistent_event(struct nvme_dev *dev, pevent_log); } +int nvme_cli_fw_download(struct nvme_dev *dev, + struct nvme_fw_download_args *args) +{ + return do_admin_args_op(fw_download, dev, args); +} + +int nvme_cli_fw_commit(struct nvme_dev *dev, + struct nvme_fw_commit_args *args) +{ + return do_admin_args_op(fw_commit, dev, args); +} + +int nvme_cli_admin_passthru(struct nvme_dev *dev, __u8 opcode, __u8 flags, + __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, + __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, + __u32 cdw14, __u32 cdw15, __u32 data_len, + void *data, __u32 metadata_len, void *metadata, + __u32 timeout_ms, __u32 *result) +{ + return do_admin_op(admin_passthru, dev, opcode, flags, rsvd, nsid, + cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15, + data_len, data, metadata_len, metadata, timeout_ms, + result); +} + /* The MI & direct interfaces don't have an exactly-matching API for * ns_mgmt_create, as we don't support a timeout for MI. */ -int nvme_cli_ns_mgmt_create(struct nvme_dev *dev, struct nvme_id_ns *ns, +int nvme_cli_ns_mgmt_create(struct nvme_dev *dev, + struct nvme_ns_mgmt_host_sw_specified *data, __u32 *nsid, __u32 timeout, __u8 csi) { if (dev->type == NVME_DEV_DIRECT) - return nvme_ns_mgmt_create(dev_fd(dev), ns, nsid, timeout, csi); + return nvme_ns_mgmt_create(dev_fd(dev), NULL, nsid, timeout, + csi, data); if (dev->type == NVME_DEV_MI) - return nvme_mi_admin_ns_mgmt_create(dev->mi.ctrl, ns, - csi, nsid); + return nvme_mi_admin_ns_mgmt_create(dev->mi.ctrl, NULL, + csi, nsid, data); return -ENODEV; } +int nvme_cli_get_feature_length2(int fid, __u32 cdw11, enum nvme_data_tfr dir, + __u32 *len) +{ + int err; + + err = nvme_get_feature_length2(fid, cdw11, dir, len); + if (err != -EEXIST) + return err; + return nvme_get_feature_length(fid, cdw11, len); +} + +int nvme_cli_security_send(struct nvme_dev *dev, + struct nvme_security_send_args* args) +{ + return do_admin_args_op(security_send, dev, args); +} + +int nvme_cli_security_receive(struct nvme_dev *dev, + struct nvme_security_receive_args* args) +{ + /* Cannot use do_admin_args_op here because the API have different suffix*/ + if (dev->type == NVME_DEV_DIRECT) { + args->fd = dev->direct.fd; + args->timeout = NVME_DEFAULT_IOCTL_TIMEOUT; + return nvme_security_receive(args); + } + + if (dev->type == NVME_DEV_MI) + return nvme_mi_admin_security_recv(dev->mi.ctrl, args); + + return -ENODEV; +} diff --git a/nvme-wrap.h b/nvme-wrap.h index dc7e04473b..c18115d224 100644 --- a/nvme-wrap.h +++ b/nvme-wrap.h @@ -18,15 +18,22 @@ int nvme_cli_identify_nsid_ctrl_list(struct nvme_dev *dev, __u32 nsid, struct nvme_ctrl_list *list); int nvme_cli_identify_ns(struct nvme_dev *dev, __u32 nsid, struct nvme_id_ns *ns); +int nvme_cli_identify_ns_descs(struct nvme_dev *dev, __u32 nsid, + struct nvme_ns_id_desc *descs); int nvme_cli_identify_allocated_ns(struct nvme_dev *dev, __u32 nsid, struct nvme_id_ns *ns); int nvme_cli_identify_active_ns_list(struct nvme_dev *dev, __u32 nsid, struct nvme_ns_list *list); int nvme_cli_identify_allocated_ns_list(struct nvme_dev *dev, __u32 nsid, struct nvme_ns_list *list); - +int nvme_cli_identify_primary_ctrl(struct nvme_dev *dev, __u32 nsid, + struct nvme_primary_ctrl_cap *cap); +int nvme_cli_identify_secondary_ctrl_list(struct nvme_dev *dev, + __u16 ctrl_id, + struct nvme_secondary_ctrl_list *sc_list); int nvme_cli_ns_mgmt_delete(struct nvme_dev *dev, __u32 nsid); -int nvme_cli_ns_mgmt_create(struct nvme_dev *dev, struct nvme_id_ns *ns, +int nvme_cli_ns_mgmt_create(struct nvme_dev *dev, + struct nvme_ns_mgmt_host_sw_specified *data, __u32 *nsid, __u32 timeout, __u8 csi); int nvme_cli_ns_attach(struct nvme_dev *dev, struct nvme_ns_attach_args *args); @@ -45,6 +52,9 @@ int nvme_cli_get_features(struct nvme_dev *dev, int nvme_cli_get_log(struct nvme_dev *dev, struct nvme_get_log_args *args); +int nvme_cli_get_log_page(struct nvme_dev *dev, + __u32 xfer_len, + struct nvme_get_log_args *args); int nvme_cli_get_nsid_log(struct nvme_dev *dev, bool rae, enum nvme_cmd_get_log_lid lid, @@ -95,6 +105,8 @@ int nvme_cli_get_log_mi_cmd_supported_effects(struct nvme_dev *dev, bool rae, int nvme_cli_get_log_boot_partition(struct nvme_dev *dev, bool rae, __u8 lsp, __u32 len, struct nvme_boot_partition *part); +int nvme_cli_get_log_phy_rx_eom(struct nvme_dev *dev, __u8 lsp, __u16 controller, + __u32 len, struct nvme_phy_rx_eom_log *part); int nvme_cli_get_log_discovery(struct nvme_dev *dev, bool rae, __u32 offset, __u32 len, void *log); int nvme_cli_get_log_media_unit_stat(struct nvme_dev *dev, __u16 domid, @@ -112,4 +124,27 @@ int nvme_cli_get_log_zns_changed_zones(struct nvme_dev *dev, __u32 nsid, int nvme_cli_get_log_persistent_event(struct nvme_dev *dev, enum nvme_pevent_log_action action, __u32 size, void *pevent_log); + +int nvme_cli_fw_download(struct nvme_dev *dev, + struct nvme_fw_download_args *args); + +int nvme_cli_fw_commit(struct nvme_dev *dev, + struct nvme_fw_commit_args *args); + +int nvme_cli_admin_passthru(struct nvme_dev *dev, __u8 opcode, __u8 flags, + __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3, + __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13, + __u32 cdw14, __u32 cdw15, __u32 data_len, + void *data, __u32 metadata_len, void *metadata, + __u32 timeout_ms, __u32 *result); + +int nvme_cli_get_feature_length2(int fid, __u32 cdw11, enum nvme_data_tfr dir, + __u32 *len); + +int nvme_cli_security_send(struct nvme_dev *dev, + struct nvme_security_send_args* args); + +int nvme_cli_security_receive(struct nvme_dev *dev, + struct nvme_security_receive_args* args); + #endif /* _NVME_WRAP_H */ diff --git a/nvme.c b/nvme.c index 61d13a2ce2..3f0f2ff454 100644 --- a/nvme.c +++ b/nvme.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * nvme.c -- NVM-Express command line utility. + * NVM-Express command line utility. * * Copyright (c) 2014-2015, Intel Corporation. * @@ -27,6 +27,7 @@ #include "config.h" #include "nvme/tree.h" #include "nvme/types.h" +#include "util/cleanup.h" #include #include #include @@ -39,11 +40,7 @@ #include #include #include -#include - -#ifdef CONFIG_LIBHUGETLBFS -#include -#endif +#include #include @@ -55,31 +52,70 @@ #include #endif +#include + #include "common.h" #include "nvme.h" -#include "libnvme.h" #include "nvme-print.h" #include "plugin.h" #include "util/base64.h" +#include "util/crc32.h" #include "nvme-wrap.h" - #include "util/argconfig.h" +#include "util/suffix.h" +#include "util/logging.h" #include "fabrics.h" - #define CREATE_CMD #include "nvme-builtin.h" +#include "malloc.h" struct feat_cfg { enum nvme_features_id feature_id; __u32 namespace_id; enum nvme_get_features_sel sel; __u32 cdw11; + __u32 cdw12; __u8 uuid_index; __u32 data_len; bool raw_binary; bool human_readable; }; +struct passthru_config { + __u8 opcode; + __u8 flags; + __u16 rsvd; + __u32 namespace_id; + __u32 data_len; + __u32 metadata_len; + __u32 timeout; + __u32 cdw2; + __u32 cdw3; + __u32 cdw10; + __u32 cdw11; + __u32 cdw12; + __u32 cdw13; + __u32 cdw14; + __u32 cdw15; + char *input_file; + char *metadata; + bool raw_binary; + bool show_command; + bool dry_run; + bool read; + bool write; + __u8 prefill; + bool latency; +}; + +#define NVME_ARGS(n, ...) \ + struct argconfig_commandline_options n[] = { \ + OPT_INCR("verbose", 'v', &verbose_level, verbose), \ + OPT_FMT("output-format", 'o', &output_format_val, output_format), \ + ##__VA_ARGS__, \ + OPT_END() \ + } + static const char nvme_version_string[] = NVME_VERSION; static struct plugin builtin = { @@ -94,68 +130,68 @@ static struct program nvme = { .name = "nvme", .version = nvme_version_string, .usage = " [] []", - .desc = "The '' may be either an NVMe character "\ - "device (ex: /dev/nvme0), an nvme block device "\ - "(ex: /dev/nvme0n1), or a mctp address in the form "\ + .desc = "The '' may be either an NVMe character " + "device (ex: /dev/nvme0), an nvme block device " + "(ex: /dev/nvme0n1), or a mctp address in the form " "mctp:,[:ctrl-id]", .extensions = &builtin, }; const char *output_format = "Output format: normal|json|binary"; -static const char *output_format_no_binary = "Output format: normal|json"; +static const char *app_tag = "app tag for end-to-end PI"; +static const char *app_tag_mask = "app tag mask for end-to-end PI"; +static const char *block_count = "number of blocks (zeroes based) on device to access"; +static const char *crkey = "current reservation key"; +static const char *csi = "command set identifier"; +static const char *buf_len = "buffer len (if) data is sent or received"; +static const char *domainid = "Domain Identifier"; +static const char *doper = "directive operation"; +static const char *dry = "show command instead of sending"; +static const char *dspec_w_dtype = "directive specification associated with directive type"; +static const char *dtype = "directive type"; +static const char *force_unit_access = "force device to commit data before command completes"; +static const char *human_readable_directive = "show directive in readable format"; +static const char *human_readable_identify = "show identify in readable format"; +static const char *human_readable_info = "show info in readable format"; +static const char *human_readable_log = "show log in readable format"; +static const char *iekey = "ignore existing res. key"; +static const char *latency = "output latency statistics"; +static const char *lba_format_index = "The index into the LBA Format list\n" + "identifying the LBA Format capabilities that are to be returned"; +static const char *limited_retry = "limit media access attempts"; +static const char *lsp = "log specific field"; +static const char *mos = "management operation specific"; +static const char *mo = "management operation"; +static const char *namespace_desired = "desired namespace"; +static const char *namespace_id_desired = "identifier of desired namespace"; +static const char *namespace_id_optional = "optional namespace attached to controller"; +static const char *nssf = "NVMe Security Specific Field"; +static const char *prinfo = "PI and check field"; +static const char *rae = "Retain an Asynchronous Event"; +static const char *raw_directive = "show directive in binary format"; +static const char *raw_dump = "dump output in binary format"; +static const char *raw_identify = "show identify in binary format"; +static const char *raw_log = "show log in binary format"; +static const char *raw_output = "output in binary format"; +static const char *ref_tag = "reference tag for end-to-end PI"; +static const char *raw_use = "use binary output"; +static const char *rtype = "reservation type"; +static const char *secp = "security protocol (cf. SPC-4)"; +static const char *spsp = "security-protocol-specific (cf. SPC-4)"; +static const char *start_block = "64-bit LBA of first block to access"; +static const char *storage_tag = "storage tag for end-to-end PI"; +static const char *timeout = "timeout value, in milliseconds"; +static const char *uuid_index = "UUID index"; +static const char *uuid_index_specify = "specify uuid index"; +static const char *verbose = "Increase output verbosity"; +static const char dash[51] = {[0 ... 49] = '=', '\0'}; +static const char space[51] = {[0 ... 49] = ' ', '\0'}; + +static char *output_format_val = "normal"; +int verbose_level; static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev); -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; -} - -#define HUGE_MIN 0x80000 - -#ifdef CONFIG_LIBHUGETLBFS -void nvme_free(void *p, bool huge) -{ - if (huge) { - if (p) - free_hugepage_region(p); - } - else - free(p); -} - -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 -void nvme_free(void *p, bool huge) -{ - free(p); -} - -void *nvme_alloc(size_t len, bool *huge) -{ - return __nvme_alloc(len, huge); -} -#endif - const char *nvme_strerror(int errnum) { if (errnum >= ENVME_CONNECT_RESOLVE) @@ -163,30 +199,6 @@ const char *nvme_strerror(int errnum) return strerror(errnum); } -int map_log_level(int verbose, bool quiet) -{ - int log_level; - - switch (verbose) { - case 0: - log_level = LOG_WARNING; - break; - case 1: - log_level = LOG_NOTICE; - break; - case 2: - log_level = LOG_INFO; - break; - default: - log_level = LOG_DEBUG; - break; - } - if (quiet) - log_level = LOG_ERR; - - return log_level; -} - static ssize_t getrandom_bytes(void *buf, size_t buflen) { #if HAVE_SYS_RANDOM @@ -230,19 +242,18 @@ static int open_dev_direct(struct nvme_dev **devp, char *devstr, int flags) dev->name = basename(devstr); err = open(devstr, flags); if (err < 0) { - perror(devstr); + nvme_show_perror(devstr); goto err_free; } dev->direct.fd = err; err = fstat(dev_fd(dev), &dev->direct.stat); if (err < 0) { - perror(devstr); + nvme_show_perror(devstr); goto err_close; } if (!is_chardev(dev) && !is_blkdev(dev)) { - fprintf(stderr, "%s is not a block or character device\n", - devstr); + nvme_show_error("%s is not a block or character device", devstr); err = -ENODEV; goto err_close; } @@ -284,7 +295,7 @@ static int open_dev_mi_mctp(struct nvme_dev **devp, char *devstr) rc = parse_mi_dev(devstr, &net, &eid, &ctrl_id); if (rc) { - fprintf(stderr, "invalid device specifier '%s'\n", devstr); + nvme_show_error("invalid device specifier '%s'", devstr); return rc; } @@ -324,7 +335,7 @@ static int check_arg_dev(int argc, char **argv) { if (optind >= argc) { errno = EINVAL; - perror(argv[0]); + nvme_show_perror(argv[0]); return -EINVAL; } return 0; @@ -346,12 +357,12 @@ static int get_dev(struct nvme_dev **dev, int argc, char **argv, int flags) else ret = open_dev_direct(dev, devname, flags); - return ret; + return ret != 0 ? -errno : 0; } int parse_and_open(struct nvme_dev **dev, int argc, char **argv, const char *desc, - const struct argconfig_commandline_options *opts) + struct argconfig_commandline_options *opts) { int ret; @@ -362,6 +373,8 @@ int parse_and_open(struct nvme_dev **dev, int argc, char **argv, ret = get_dev(dev, argc, argv, O_RDONLY); if (ret < 0) argconfig_print_help(desc, opts); + else + log_level = map_log_level(verbose_level, false); return ret; } @@ -377,17 +390,35 @@ int open_exclusive(struct nvme_dev **dev, int argc, char **argv, return get_dev(dev, argc, argv, flags); } -enum nvme_print_flags validate_output_format(const char *format) +int validate_output_format(const char *format, enum nvme_print_flags *flags) { + enum nvme_print_flags f; + if (!format) return -EINVAL; + if (!strcmp(format, "normal")) - return NORMAL; - if (!strcmp(format, "json")) - return JSON; - if (!strcmp(format, "binary")) - return BINARY; - return -EINVAL; + f = NORMAL; + else if (!strcmp(format, "json")) + f = JSON; + else if (!strcmp(format, "binary")) + f = BINARY; + else + return -EINVAL; + + *flags = f; + + return 0; +} + +bool nvme_is_output_format_json(void) +{ + enum nvme_print_flags flags; + + if (validate_output_format(output_format_val, &flags)) + return false; + + return flags == JSON; } void dev_close(struct nvme_dev *dev) @@ -406,140 +437,324 @@ void dev_close(struct nvme_dev *dev) 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 *desc = "Retrieve SMART log for the given device " + "(or optionally a namespace) in either decoded format " + "(default) or binary."; + + _cleanup_free_ struct nvme_smart_log *smart_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; const char *namespace = "(optional) desired namespace"; - const char *raw = "output in binary format"; - const char *human_readable = "show info in readable format"; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; struct config { __u32 namespace_id; - char *output_format; bool raw_binary; bool human_readable; }; struct config cfg = { .namespace_id = NVME_NSID_ALL, - .output_format = "normal", .raw_binary = false, .human_readable = false, }; - - 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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_output), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - 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_cli_get_log_smart(dev, cfg.namespace_id, true, - &smart_log); + smart_log = nvme_alloc(sizeof(*smart_log)); + if (!smart_log) + return -ENOMEM; + + err = nvme_cli_get_log_smart(dev, cfg.namespace_id, false, + smart_log); if (!err) - nvme_show_smart_log(&smart_log, cfg.namespace_id, + nvme_show_smart_log(smart_log, cfg.namespace_id, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "smart log: %s\n", nvme_strerror(errno)); -close_fd: - dev_close(dev); -ret: + nvme_show_error("smart log: %s", nvme_strerror(errno)); + return err; } static int get_ana_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve ANA log for the given device in " \ - "decoded format (default), json or binary."; + const char *desc = "Retrieve ANA log for the given device in " + "decoded format (default), json or binary."; const char *groups = "Return ANA groups only."; - void *ana_log; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + _cleanup_free_ void *ana_log = NULL; size_t ana_log_len; - struct nvme_id_ctrl ctrl; enum nvme_print_flags flags; enum nvme_log_ana_lsp lsp; - struct nvme_dev *dev; int err = -1; struct config { bool groups; - char *output_format; }; struct config cfg = { .groups = false, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_FLAG("groups", 'g', &cfg.groups, groups), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_FLAG("groups", 'g', &cfg.groups, groups)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_fd; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = nvme_cli_identify_ctrl(dev, &ctrl); + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); if (err) { - fprintf(stderr, "ERROR : nvme_identify_ctrl() failed: %s\n", + nvme_show_error("ERROR : nvme_identify_ctrl() failed: %s", nvme_strerror(errno)); - goto close_fd; + return err; } ana_log_len = sizeof(struct nvme_ana_log) + - le32_to_cpu(ctrl.nanagrpid) * sizeof(struct nvme_ana_group_desc); - if (!(ctrl.anacap & (1 << 6))) - ana_log_len += le32_to_cpu(ctrl.mnan) * sizeof(__le32); + 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) { - err = -ENOMEM; - goto close_fd; - } + ana_log = nvme_alloc(ana_log_len); + if (!ana_log) + return -ENOMEM; lsp = cfg.groups ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY : NVME_LOG_ANA_LSP_RGO_NAMESPACES; err = nvme_cli_get_log_ana(dev, lsp, true, 0, ana_log_len, ana_log); - if (!err) { - nvme_show_ana_log(ana_log, dev->name, flags, ana_log_len); - } else if (err > 0) + if (!err) + nvme_show_ana_log(ana_log, dev->name, ana_log_len, flags); + else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "ana-log: %s", nvme_strerror(errno)); - free(ana_log); -close_fd: - dev_close(dev); -ret: + nvme_show_error("ana-log: %s", nvme_strerror(errno)); + + return err; +} + +static int parse_telemetry_da(struct nvme_dev *dev, + enum nvme_telemetry_da da, + struct nvme_telemetry_log *telem, + size_t *size) + +{ + _cleanup_free_ struct nvme_id_ctrl *id_ctrl = NULL; + size_t dalb = 0; + + id_ctrl = nvme_alloc(sizeof(*id_ctrl)); + if (!id_ctrl) + return -ENOMEM; + + switch (da) { + case NVME_TELEMETRY_DA_1: + dalb = le16_to_cpu(telem->dalb1); + break; + case NVME_TELEMETRY_DA_2: + dalb = le16_to_cpu(telem->dalb2); + break; + case NVME_TELEMETRY_DA_3: + /* dalb3 >= dalb2 >= dalb1 */ + dalb = le16_to_cpu(telem->dalb3); + break; + case NVME_TELEMETRY_DA_4: + if (nvme_cli_identify_ctrl(dev, id_ctrl)) { + perror("identify-ctrl"); + return -errno; + } + + if (id_ctrl->lpa & 0x40) { + dalb = le32_to_cpu(telem->dalb4); + } else { + nvme_show_error( + "Data area 4 unsupported, bit 6 of Log Page Attributes not set"); + return -EINVAL; + } + break; + default: + nvme_show_error("Invalid data area parameter - %d", da); + return -EINVAL; + } + + if (dalb == 0) { + nvme_show_error("ERROR: No telemetry data block"); + return -ENOENT; + } + *size = (dalb + 1) * NVME_LOG_TELEM_BLOCK_SIZE; + return 0; +} + +static int get_log_telemetry_ctrl(struct nvme_dev *dev, bool rae, size_t size, + struct nvme_telemetry_log **buf) +{ + struct nvme_telemetry_log *log; + int err; + + log = nvme_alloc(size); + if (!log) + return -errno; + + err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0, size, log); + if (err) { + free(log); + return -errno; + } + + *buf = log; + return 0; +} + +static int get_log_telemetry_host(struct nvme_dev *dev, size_t size, + struct nvme_telemetry_log **buf) +{ + struct nvme_telemetry_log *log; + int err; + + log = nvme_alloc(size); + if (!log) + return -errno; + + err = nvme_cli_get_log_telemetry_host(dev, 0, size, log); + if (err) { + free(log); + return -errno; + } + + *buf = log; + return 0; +} + +static int __create_telemetry_log_host(struct nvme_dev *dev, + enum nvme_telemetry_da da, + size_t *size, + struct nvme_telemetry_log **buf) +{ + _cleanup_free_ struct nvme_telemetry_log *log = NULL; + int err; + + log = nvme_alloc(sizeof(*log)); + if (!log) + return -ENOMEM; + + err = nvme_cli_get_log_create_telemetry_host(dev, log); + if (err) + return -errno; + + err = parse_telemetry_da(dev, da, log, size); + if (err) + return err; + + return get_log_telemetry_host(dev, *size, buf); +} + +static int __get_telemetry_log_ctrl(struct nvme_dev *dev, + bool rae, + enum nvme_telemetry_da da, + size_t *size, + struct nvme_telemetry_log **buf) +{ + struct nvme_telemetry_log *log; + int err; + + log = nvme_alloc(NVME_LOG_TELEM_BLOCK_SIZE); + if (!log) + return -errno; + + /* + * set rae = true so it won't clear the current telemetry log in + * controller + */ + err = nvme_cli_get_log_telemetry_ctrl(dev, true, 0, + NVME_LOG_TELEM_BLOCK_SIZE, + log); + if (err) + goto free; + + if (!log->ctrlavail) { + if (!rae) { + err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0, + NVME_LOG_TELEM_BLOCK_SIZE, + log); + goto free; + } + + *size = NVME_LOG_TELEM_BLOCK_SIZE; + *buf = log; + + printf("Warning: Telemetry Controller-Initiated Data Not Available.\n"); + return 0; + } + + err = parse_telemetry_da(dev, da, log, size); + if (err) + goto free; + + return get_log_telemetry_ctrl(dev, rae, *size, buf); + +free: + free(log); return err; } +static int __get_telemetry_log_host(struct nvme_dev *dev, + enum nvme_telemetry_da da, + size_t *size, + struct nvme_telemetry_log **buf) +{ + _cleanup_free_ struct nvme_telemetry_log *log = NULL; + int err; + + log = nvme_alloc(sizeof(*log)); + if (!log) + return -errno; + + err = nvme_cli_get_log_telemetry_host(dev, 0, + NVME_LOG_TELEM_BLOCK_SIZE, + log); + if (err) + return err; + + err = parse_telemetry_da(dev, da, log, size); + if (err) + return err; + + return get_log_telemetry_host(dev, *size, buf); +} + static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { @@ -548,70 +763,75 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, const char *hgen = "Have the host tell the controller to generate the report"; const char *cgen = "Gather report generated by the controller."; const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4."; - struct nvme_telemetry_log *log; - int err = 0, output; + + _cleanup_free_ struct nvme_telemetry_log *log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_file_ int output = -1; + int err = 0; size_t total_size; __u8 *data_ptr = NULL; int data_written = 0, data_remaining = 0; - struct nvme_dev *dev; struct config { char *file_name; __u32 host_gen; bool ctrl_init; int data_area; + bool rae; }; struct config cfg = { .file_name = NULL, .host_gen = 1, .ctrl_init = false, .data_area = 3, + .rae = true, }; - 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() - }; + NVME_ARGS(opts, + OPT_FILE("output-file", 'O', &cfg.file_name, fname), + OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen), + OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen), + OPT_UINT("data-area", 'd', &cfg.data_area, dgen), + OPT_FLAG("rae", 'r', &cfg.rae, rae)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.file_name) { - fprintf(stderr, "Please provide an output file!\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("Please provide an output file!"); + return -EINVAL; } cfg.host_gen = !!cfg.host_gen; output = open(cfg.file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) { - fprintf(stderr, "Failed to open output file %s: %s!\n", + nvme_show_error("Failed to open output file %s: %s!", cfg.file_name, strerror(errno)); - err = output; - goto close_dev; + return output; } + log = nvme_alloc(sizeof(*log)); + if (!log) + return -ENOMEM; + if (cfg.ctrl_init) - err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log, - cfg.data_area, &total_size); + err = __get_telemetry_log_ctrl(dev, cfg.rae, cfg.data_area, + &total_size, &log); else if (cfg.host_gen) - err = nvme_get_new_host_telemetry(dev_fd(dev), &log, - cfg.data_area, &total_size); + err = __create_telemetry_log_host(dev, cfg.data_area, + &total_size, &log); else - err = nvme_get_host_telemetry(dev_fd(dev), &log, - cfg.data_area, &total_size); + err = __get_telemetry_log_host(dev, cfg.data_area, + &total_size, &log); if (err < 0) { - fprintf(stderr, "get-telemetry-log: %s\n", - nvme_strerror(errno)); + nvme_show_error("get-telemetry-log: %s", nvme_strerror(errno)); + return err; } else if (err > 0) { nvme_show_status(err); fprintf(stderr, "Failed to acquire telemetry log %d!\n", err); - goto close_output; + return err; } data_written = 0; @@ -635,65 +855,58 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, } if (fsync(output) < 0) { - fprintf(stderr, "ERROR : %s: : fsync : %s\n", __func__, strerror(errno)); + nvme_show_error("ERROR : %s: : fsync : %s", __func__, strerror(errno)); return -1; } - free(log); - -close_output: - close(output); -close_dev: - dev_close(dev); -ret: return err; } 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"; + + _cleanup_free_ struct nvme_endurance_group_log *endurance_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; 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_SHRT("group-id", 'g', &cfg.group_id, group_id), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("group-id", 'g', &cfg.group_id, group_id)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + endurance_log = nvme_alloc(sizeof(*endurance_log)); + if (!endurance_log) + return -ENOMEM; err = nvme_cli_get_log_endurance_group(dev, cfg.group_id, - &endurance_log); + endurance_log); if (!err) - nvme_show_endurance_log(&endurance_log, cfg.group_id, + nvme_show_endurance_log(endurance_log, cfg.group_id, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "endurance log: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("endurance log: %s", nvme_strerror(errno)); + return err; } @@ -703,7 +916,7 @@ static int collect_effects_log(struct nvme_dev *dev, enum nvme_csi csi, nvme_effects_log_node_t *node; int err; - node = malloc(sizeof(nvme_effects_log_node_t)); + node = nvme_alloc(sizeof(*node)); if (!node) return -ENOMEM; @@ -721,12 +934,10 @@ static int collect_effects_log(struct nvme_dev *dev, enum nvme_csi csi, 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"; - const char *csi = ""; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; struct list_head log_pages; nvme_effects_log_node_t *node; - struct nvme_dev *dev; void *bar = NULL; @@ -734,67 +945,71 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl enum nvme_print_flags flags; struct config { - char *output_format; bool human_readable; bool raw_binary; int csi; }; struct config cfg = { - .output_format = "normal", .human_readable = false, .raw_binary = false, .csi = -1, }; - 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_INT("csi", 'c', &cfg.csi, csi), - OPT_END() - }; + NVME_ARGS(opts, + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_log), + OPT_INT("csi", 'c', &cfg.csi, csi)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (cfg.human_readable) flags |= VERBOSE; list_head_init(&log_pages); if (cfg.csi < 0) { - nvme_root_t nvme_root; - uint64_t cap; - int nvme_command_set_supported; - int other_command_sets_supported; - nvme_root = nvme_scan(NULL); - bar = mmap_registers(nvme_root, dev); - nvme_free_tree(nvme_root); - - if (!bar) { - goto close_dev; - } - cap = mmio_read64(bar + NVME_REG_CAP); - munmap(bar, getpagesize()); + nvme_root_t r; + __u64 cap; + + r = nvme_scan(NULL); + bar = mmap_registers(r, dev); + nvme_free_tree(r); - nvme_command_set_supported = NVME_CAP_CSS(cap) & NVME_CAP_CSS_NVM; - other_command_sets_supported = NVME_CAP_CSS(cap) & NVME_CAP_CSS_CSI; + if (bar) { + cap = mmio_read64(bar + NVME_REG_CAP); + munmap(bar, getpagesize()); + } else { + struct nvme_get_property_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .offset = NVME_REG_CAP, + .value = &cap, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + err = nvme_get_property(&args); + if (err) + goto cleanup_list; + } - if (nvme_command_set_supported) + if (NVME_CAP_CSS(cap) & NVME_CAP_CSS_NVM) err = collect_effects_log(dev, NVME_CSI_NVM, &log_pages, flags); - if (!err && other_command_sets_supported) + if (!err && (NVME_CAP_CSS(cap) & NVME_CAP_CSS_CSI)) err = collect_effects_log(dev, NVME_CSI_ZNS, &log_pages, flags); - } else { err = collect_effects_log(dev, cfg.csi, &log_pages, flags); } @@ -804,15 +1019,12 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl else if (err > 0) nvme_show_status(err); else - perror("effects log page"); + nvme_show_perror("effects log page"); -close_dev: - while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node))) { +cleanup_list: + while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node))) free(node); - } - dev_close(dev); -ret: return err; } @@ -820,118 +1032,101 @@ static int get_supported_log_pages(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve supported logs and print the table."; - const char *verbose = "Increase output verbosity"; - struct nvme_supported_log_pages supports; + + _cleanup_free_ struct nvme_supported_log_pages *supports = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; - struct config { - char *output_format; - bool verbose; - }; - - struct config cfg = { - .output_format = "normal", - .verbose = false - }; - - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), - OPT_END() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - if (cfg.verbose) + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; - err = nvme_cli_get_log_supported_log_pages(dev, false, &supports); + supports = nvme_alloc(sizeof(*supports)); + if (!supports) + return -ENOMEM; + + err = nvme_cli_get_log_supported_log_pages(dev, false, supports); if (!err) - nvme_show_supported_log(&supports, dev->name, flags); + nvme_show_supported_log(supports, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "supported log pages: %s", - nvme_strerror(errno)); + nvme_show_error("supported log pages: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int get_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve specified number of "\ - "error log entries from a given device "\ + 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; + + _cleanup_free_ struct nvme_error_log_page *err_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; struct nvme_id_ctrl ctrl; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; struct config { __u32 log_entries; - char *output_format; bool raw_binary; }; struct config cfg = { .log_entries = 64, - .output_format = "normal", .raw_binary = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; if (!cfg.log_entries) { - fprintf(stderr, "non-zero log-entries is required param\n"); - err = -1; - goto close_dev; + nvme_show_error("non-zero log-entries is required param"); + return -1; } err = nvme_cli_identify_ctrl(dev, &ctrl); if (err < 0) { - perror("identify controller"); - goto close_dev; + nvme_show_perror("identify controller"); + return err; } else if (err) { - fprintf(stderr, "could not identify controller\n"); - err = -1; - goto close_dev; + nvme_show_error("could not identify controller"); + return err; } 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) { - err = -1; - goto close_dev; - } + err_log = nvme_alloc(cfg.log_entries * sizeof(struct nvme_error_log_page)); + if (!err_log) + return -ENOMEM; err = nvme_cli_get_log_error(dev, cfg.log_entries, false, err_log); if (!err) @@ -940,343 +1135,323 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug else if (err > 0) nvme_show_status(err); else - perror("error log"); - free(err_log); -close_dev: - dev_close(dev); -ret: + nvme_show_perror("error log"); + return err; } static int get_fw_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve the firmware log for the "\ + 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_slot fw_log; + + _cleanup_free_ struct nvme_firmware_slot *fw_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { - char *output_format; bool raw_binary; }; struct config cfg = { - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; - err = nvme_cli_get_log_fw_slot(dev, false, &fw_log); + fw_log = nvme_alloc(sizeof(*fw_log)); + if (!fw_log) + return -ENOMEM; + + err = nvme_cli_get_log_fw_slot(dev, false, fw_log); if (!err) - nvme_show_fw_log(&fw_log, dev->name, flags); + nvme_show_fw_log(fw_log, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "fw log: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("fw log: %s", nvme_strerror(errno)); + return err; } static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Changed Namespaces log for the given device "\ - "in either decoded format "\ - "(default) or binary."; - const char *raw = "output in binary format"; - struct nvme_ns_list changed_ns_list_log; + const char *desc = "Retrieve Changed Namespaces log for the given device " + "in either decoded format (default) or binary."; + + _cleanup_free_ struct nvme_ns_list *changed_ns_list_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { - char *output_format; bool raw_binary; }; struct config cfg = { - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_output)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + changed_ns_list_log = nvme_alloc(sizeof(*changed_ns_list_log)); + if (!changed_ns_list_log) + return -ENOMEM; + err = nvme_cli_get_log_changed_ns_list(dev, true, - &changed_ns_list_log); + changed_ns_list_log); if (!err) - nvme_show_changed_ns_list_log(&changed_ns_list_log, + nvme_show_changed_ns_list_log(changed_ns_list_log, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "changed ns list log: %s\n", - nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("changed ns list log: %s", nvme_strerror(errno)); + return err; } static int get_pred_lat_per_nvmset_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Predictable latency per nvm set log "\ - "page and prints it for the given device in either decoded " \ - "format(default),json or binary."; + const char *desc = "Retrieve Predictable latency per nvm set log " + "page and prints it for the given device in either decoded " + "format(default),json or binary."; const char *nvmset_id = "NVM Set Identifier"; - const char *raw = "use binary output"; - struct nvme_nvmset_predictable_lat_log plpns_log; + + _cleanup_free_ struct nvme_nvmset_predictable_lat_log *plpns_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u16 nvmset_id; - char *output_format; bool raw_binary; }; struct config cfg = { .nvmset_id = 1, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_SHRT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + plpns_log = nvme_alloc(sizeof(*plpns_log)); + if (!plpns_log) + return -ENOMEM; + err = nvme_cli_get_log_predictable_lat_nvmset(dev, cfg.nvmset_id, - &plpns_log); + plpns_log); if (!err) - nvme_show_predictable_latency_per_nvmset(&plpns_log, - cfg.nvmset_id, dev->name, flags); + nvme_show_predictable_latency_per_nvmset(plpns_log, cfg.nvmset_id, dev->name, + flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "predictable latency per nvm set: %s\n", - nvme_strerror(errno)); + nvme_show_error("predictable latency per nvm set: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int get_pred_lat_event_agg_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Predictable Latency Event" \ - "Aggregate Log page and prints it, for the given" \ - "device in either decoded format(default)," \ - "json or binary."; - const char *log_entries = "Number of pending NVM Set" \ - "log Entries list"; - const char *rae = "Retain an Asynchronous Event"; - const char *raw = "use binary output"; + const char *desc = "Retrieve Predictable Latency Event " + "Aggregate Log page and prints it, for the given " + "device in either decoded format(default), json or binary."; + const char *log_entries = "Number of pending NVM Set log Entries list"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + _cleanup_free_ void *pea_log = NULL; enum nvme_print_flags flags; - struct nvme_id_ctrl ctrl; - struct nvme_dev *dev; __u32 log_size; - void *pea_log; int err; struct config { __u64 log_entries; bool rae; - char *output_format; bool raw_binary; }; struct config cfg = { .log_entries = 2044, .rae = false, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries), - OPT_FLAG("rae", 'r', &cfg.rae, rae), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries), + OPT_FLAG("rae", 'r', &cfg.rae, rae), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; if (!cfg.log_entries) { - fprintf(stderr, "non-zero log-entries is required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("non-zero log-entries is required param"); + return -EINVAL; } - err = nvme_cli_identify_ctrl(dev, &ctrl); + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); if (err < 0) { - fprintf(stderr, "identify controller: %s\n", - nvme_strerror(errno)); - goto close_dev; + nvme_show_error("identify controller: %s", nvme_strerror(errno)); + return err; } else if (err) { nvme_show_status(err); - goto close_dev; + return err; } - cfg.log_entries = min(cfg.log_entries, le32_to_cpu(ctrl.nsetidmax)); + cfg.log_entries = min(cfg.log_entries, le32_to_cpu(ctrl->nsetidmax)); log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16); - pea_log = calloc(log_size, 1); - if (!pea_log) { - err = -ENOMEM; - goto close_dev; - } + + pea_log = nvme_alloc(log_size); + if (!pea_log) + return -ENOMEM; err = nvme_cli_get_log_predictable_lat_event(dev, cfg.rae, 0, log_size, pea_log); if (!err) - nvme_show_predictable_latency_event_agg_log(pea_log, cfg.log_entries, - log_size, dev->name, flags); + nvme_show_predictable_latency_event_agg_log(pea_log, cfg.log_entries, log_size, + dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "predictable latency event aggregate log page: %s", - nvme_strerror(errno)); - free(pea_log); + nvme_show_error("predictable latency event aggregate log page: %s", + nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int get_persistent_event_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Persistent Event log info for"\ - " the given device in either decoded format(default),"\ - " json or binary."; - const char *action = "action the controller shall take during"\ - " processing this persistent log page command."; + const char *desc = "Retrieve Persistent Event log info for " + "the given device in either decoded format(default), json or binary."; + const char *action = "action the controller shall take during " + "processing this persistent log page command."; const char *log_len = "number of bytes to retrieve"; - const char *raw = "use binary output"; - struct nvme_persistent_event_log *pevent, *pevent_collected; + + _cleanup_free_ struct nvme_persistent_event_log *pevent_collected = NULL; + _cleanup_free_ struct nvme_persistent_event_log *pevent = NULL; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; void *pevent_log_info; - struct nvme_dev *dev; - bool huge; int err; struct config { __u8 action; __u32 log_len; - char *output_format; bool raw_binary; }; struct config cfg = { .action = 0xff, .log_len = 0, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_BYTE("action", 'a', &cfg.action, action), - OPT_UINT("log_len", 'l', &cfg.log_len, log_len), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("action", 'a', &cfg.action, action), + OPT_UINT("log_len", 'l', &cfg.log_len, log_len), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; - pevent = calloc(sizeof(*pevent), 1); - if (!pevent) { - err = -ENOMEM; - goto close_dev; - } + pevent = nvme_alloc(sizeof(*pevent)); + if (!pevent) + return -ENOMEM; err = nvme_cli_get_log_persistent_event(dev, cfg.action, sizeof(*pevent), pevent); if (err < 0) { - fprintf(stderr, "persistent event log: %s\n", - nvme_strerror(errno)); - goto free_pevent; + nvme_show_error("persistent event log: %s", nvme_strerror(errno)); + return err; } else if (err) { nvme_show_status(err); - goto free_pevent; + return err; } if (cfg.action == NVME_PEVENT_LOG_RELEASE_CTX) { printf("Releasing Persistent Event Log Context\n"); - goto free_pevent; + return 0; } if (!cfg.log_len && cfg.action != NVME_PEVENT_LOG_EST_CTX_AND_READ) { cfg.log_len = le64_to_cpu(pevent->tll); } else if (!cfg.log_len && cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) { printf("Establishing Persistent Event Log Context\n"); - goto free_pevent; + return 0; } /* @@ -1289,11 +1464,10 @@ static int get_persistent_event_log(int argc, char **argv, if (cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) cfg.action = NVME_PEVENT_LOG_READ; - pevent_log_info = nvme_alloc(cfg.log_len, &huge); - if (!pevent_log_info) { - err = -ENOMEM; - goto free_pevent; - } + pevent_log_info = nvme_alloc_huge(cfg.log_len, &mh); + if (!pevent_log_info) + return -ENOMEM; + err = nvme_cli_get_log_persistent_event(dev, cfg.action, cfg.log_len, pevent_log_info); if (!err) { @@ -1301,199 +1475,169 @@ static int get_persistent_event_log(int argc, char **argv, sizeof(*pevent), pevent); if (err < 0) { - fprintf(stderr, "persistent event log: %s\n", - nvme_strerror(errno)); - goto free; + nvme_show_error("persistent event log: %s", nvme_strerror(errno)); + return err; } else if (err) { nvme_show_status(err); - goto free; + return err; } pevent_collected = pevent_log_info; if (pevent_collected->gen_number != pevent->gen_number) { - printf("Collected Persistent Event Log may be invalid, "\ - "Re-read the log is required\n"); - goto free; + printf("Collected Persistent Event Log may be invalid,\n" + "Re-read the log is required\n"); + return -EINVAL; } nvme_show_persistent_event_log(pevent_log_info, cfg.action, cfg.log_len, dev->name, flags); - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); - else - fprintf(stderr, "persistent event log: %s\n", - nvme_strerror(errno)); + } else { + nvme_show_error("persistent event log: %s", nvme_strerror(errno)); + } -free: - nvme_free(pevent_log_info, huge); -free_pevent: - free(pevent); -close_dev: - dev_close(dev); -ret: return err; } static int get_endurance_event_agg_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Retrieve Predictable Latency " \ - "Event Aggregate page and prints it, for the given " \ - "device in either decoded format(default), " \ - "json or binary."; - const char *log_entries = "Number of pending Endurance Group " \ - "Event log Entries list"; - const char *rae = "Retain an Asynchronous Event"; - const char *raw = "use binary output"; - void *endurance_log; - struct nvme_id_ctrl ctrl; + const char *desc = "Retrieve Retrieve Predictable Latency " + "Event Aggregate page and prints it, for the given " + "device in either decoded format(default), json or binary."; + const char *log_entries = "Number of pending Endurance Group Event log Entries list"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + _cleanup_free_ void *endurance_log = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; __u32 log_size; int err; struct config { __u64 log_entries; bool rae; - char *output_format; bool raw_binary; }; struct config cfg = { .log_entries = 2044, .rae = false, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries), - OPT_FLAG("rae", 'r', &cfg.rae, rae), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries), + OPT_FLAG("rae", 'r', &cfg.rae, rae), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; if (!cfg.log_entries) { - fprintf(stderr, "non-zero log-entries is required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("non-zero log-entries is required param"); + return -EINVAL; } - err = nvme_cli_identify_ctrl(dev, &ctrl); + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); if (err < 0) { - fprintf(stderr, "identify controller: %s\n", - nvme_strerror(errno)); - goto close_dev; + nvme_show_error("identify controller: %s", nvme_strerror(errno)); + return err; } else if (err) { - fprintf(stderr, "could not identify controller\n"); - err = -ENODEV; - goto close_dev; + nvme_show_error("could not identify controller"); + return -ENODEV; } - cfg.log_entries = min(cfg.log_entries, le16_to_cpu(ctrl.endgidmax)); + cfg.log_entries = min(cfg.log_entries, le16_to_cpu(ctrl->endgidmax)); log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16); - endurance_log = calloc(log_size, 1); - if (!endurance_log) { - err = -ENOMEM; - goto close_dev; - } + + endurance_log = nvme_alloc(log_size); + if (!endurance_log) + return -ENOMEM; err = nvme_cli_get_log_endurance_grp_evt(dev, cfg.rae, 0, log_size, endurance_log); if (!err) - nvme_show_endurance_group_event_agg_log(endurance_log, cfg.log_entries, - log_size, dev->name, flags); + nvme_show_endurance_group_event_agg_log(endurance_log, cfg.log_entries, log_size, + dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "endurance group event aggregate log page: %s\n", - nvme_strerror(errno)); - free(endurance_log); + nvme_show_error("endurance group event aggregate log page: %s", + nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int get_lba_status_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Get LBA Status Info Log " \ - "and prints it, for the given device in either " \ - "decoded format(default),json or binary."; - const char *rae = "Retain an Asynchronous Event"; - void *lab_status; + const char *desc = "Retrieve Get LBA Status Info Log and prints it, " + "for the given device in either decoded format(default),json or binary."; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *lba_status = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; __u32 lslplen; int err; struct config { bool rae; - char *output_format; }; struct config cfg = { .rae = false, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_FLAG("rae", 'r', &cfg.rae, rae), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_FLAG("rae", 'r', &cfg.rae, rae)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } err = nvme_cli_get_log_lba_status(dev, true, 0, sizeof(__u32), &lslplen); if (err < 0) { - fprintf(stderr, "lba status log page: %s\n", - nvme_strerror(errno)); - goto close_dev; + nvme_show_error("lba status log page: %s", nvme_strerror(errno)); + return err; } else if (err) { nvme_show_status(err); - goto close_dev; + return err; } - lab_status = calloc(lslplen, 1); - if (!lab_status) { - err = -ENOMEM; - goto close_dev; - } + lba_status = nvme_alloc(lslplen); + if (!lba_status) + return -ENOMEM; - err = nvme_cli_get_log_lba_status(dev, cfg.rae, 0, lslplen, - lab_status); + err = nvme_cli_get_log_lba_status(dev, cfg.rae, 0, lslplen, lba_status); if (!err) - nvme_show_lba_status_log(lab_status, lslplen, dev->name, flags); + nvme_show_lba_status_log(lba_status, lslplen, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "lba status log page: %s\n", - nvme_strerror(errno)); - free(lab_status); + nvme_show_error("lba status log page: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } @@ -1501,293 +1645,525 @@ static int get_resv_notif_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Reservation Notification " \ - "log page and prints it, for the given " \ - "device in either decoded format(default), " \ - "json or binary."; - struct nvme_resv_notification_log resv; + const char *desc = "Retrieve Reservation Notification " + "log page and prints it, for the given " + "device in either decoded format(default), json or binary."; + + _cleanup_free_ struct nvme_resv_notification_log *resv = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; 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() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + resv = nvme_alloc(sizeof(*resv)); + if (!resv) + return -ENOMEM; - err = nvme_cli_get_log_reservation(dev, false, &resv); + err = nvme_cli_get_log_reservation(dev, false, resv); if (!err) - nvme_show_resv_notif_log(&resv, dev->name, flags); + nvme_show_resv_notif_log(resv, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "resv notifi log: %s\n", - nvme_strerror(errno)); + nvme_show_error("resv notifi log: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int get_boot_part_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Boot Partition " \ - "log page and prints it, for the given " \ - "device in either decoded format(default), " \ - "json or binary."; - const char *lsp = "log specific field"; + const char *desc = "Retrieve Boot Partition " + "log page and prints it, for the given " + "device in either decoded format(default), json or binary."; const char *fname = "boot partition data output file name"; - struct nvme_boot_partition boot; - __u8 *bp_log; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_boot_partition *boot = NULL; + _cleanup_free_ __u8 *bp_log = NULL; enum nvme_print_flags flags; - int err = -1, output = 0; - struct nvme_dev *dev; + int err = -1; + _cleanup_file_ int output = -1; __u32 bpsz = 0; struct config { __u8 lsp; char *file_name; - char *output_format; }; struct config cfg = { .lsp = 0, - .output_format = "normal", .file_name = NULL, }; - OPT_ARGS(opts) = { - OPT_BYTE("lsp", 's', &cfg.lsp, lsp), - OPT_FILE("output-file", 'f', &cfg.file_name, fname), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("lsp", 's', &cfg.lsp, lsp), + OPT_FILE("output-file", 'f', &cfg.file_name, fname)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } if (!cfg.file_name) { - fprintf(stderr, "Please provide an output file!\n"); - err = -1; - goto close_dev; + nvme_show_error("Please provide an output file!"); + return -1; } - if (cfg.lsp > 128) { - fprintf(stderr, "invalid lsp param: %u\n", cfg.lsp); - err = -1; - goto close_dev; + if (cfg.lsp > 127) { + nvme_show_error("invalid lsp param: %u", cfg.lsp); + return -1; } output = open(cfg.file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) { - fprintf(stderr, "Failed to open output file %s: %s!\n", + nvme_show_error("Failed to open output file %s: %s!", cfg.file_name, strerror(errno)); - err = output; - goto close_dev; + return output; } + boot = nvme_alloc(sizeof(*boot)); + if (!boot) + return -ENOMEM; + err = nvme_cli_get_log_boot_partition(dev, false, cfg.lsp, - sizeof(boot), &boot); + sizeof(*boot), boot); if (err < 0) { - fprintf(stderr, "boot partition log: %s\n", - nvme_strerror(errno)); - goto close_output; + nvme_show_error("boot partition log: %s", nvme_strerror(errno)); + return err; } else if (err) { nvme_show_status(err); - goto close_output; + return err; } - bpsz = (boot.bpinfo & 0x7fff) * 128 * 1024; - bp_log = calloc(sizeof(boot) + bpsz, 1); - if (!bp_log) { - err = -1; - goto close_output; - } + bpsz = (boot->bpinfo & 0x7fff) * 128 * 1024; + bp_log = nvme_alloc(sizeof(*boot) + bpsz); + if (!bp_log) + return -ENOMEM; err = nvme_cli_get_log_boot_partition(dev, false, cfg.lsp, - sizeof(boot) + bpsz, + sizeof(*boot) + bpsz, (struct nvme_boot_partition *)bp_log); if (!err) - nvme_show_boot_part_log(&bp_log, dev->name, flags, - sizeof(boot) + bpsz); + nvme_show_boot_part_log(&bp_log, dev->name, sizeof(*boot) + bpsz, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "boot partition log: %s\n", - nvme_strerror(errno)); + nvme_show_error("boot partition log: %s", nvme_strerror(errno)); - err = write(output, (void *) bp_log + sizeof(boot), bpsz); - if (err != bpsz) { + err = write(output, (void *) bp_log + sizeof(*boot), bpsz); + if (err != bpsz) fprintf(stderr, "Failed to flush all data to file!\n"); - } else { + else printf("Data flushed into file %s\n", cfg.file_name); - } err = 0; - free(bp_log); - -close_output: - close(output); -close_dev: - dev_close(dev); -ret: return err; } -static int get_media_unit_stat_log(int argc, char **argv, struct command *cmd, - struct plugin *plugin) +static int get_phy_rx_eom_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - const char *desc = "Retrieve the configuration and wear of media units and print it"; - const char *domainid = "Domain Identifier"; - const char *raw = "use binary output"; - struct nvme_media_unit_stat_log mus; + const char *desc = "Retrieve Physical Interface Receiver Eye Opening " + "Measurement log for the given device in decoded format " + "(default), json or binary."; + const char *controller = "Target Controller ID."; + _cleanup_free_ struct nvme_phy_rx_eom_log *phy_rx_eom_log = NULL; + size_t phy_rx_eom_log_len; enum nvme_print_flags flags; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err = -1; + __u8 lsp_tmp; struct config { - __u16 domainid; - char *output_format; - bool raw_binary; + __u8 lsp; + __u16 controller; }; struct config cfg = { - .domainid = 0, - .output_format = "normal", - .raw_binary = false, + .lsp = 0, + .controller = NVME_LOG_LSI_NONE, }; - OPT_ARGS(opts) = { - OPT_UINT("domain-id", 'd', &cfg.domainid, domainid), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("lsp", 's', &cfg.lsp, lsp), + OPT_SHRT("controller", 'c', &cfg.controller, controller)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - if (cfg.raw_binary) - flags = BINARY; + if (cfg.lsp > 127) { + nvme_show_error("invalid lsp param: %u", cfg.lsp); + return -1; + } else if ((cfg.lsp & 3) == 3) { + nvme_show_error("invalid measurement quality: %u", cfg.lsp & 3); + return -1; + } else if ((cfg.lsp & 12) == 12) { + nvme_show_error("invalid action: %u", cfg.lsp & 12); + return -1; + } + + /* Fetching header to calculate total log length */ + phy_rx_eom_log_len = sizeof(struct nvme_phy_rx_eom_log); + phy_rx_eom_log = nvme_alloc(phy_rx_eom_log_len); + if (!phy_rx_eom_log) + return -ENOMEM; + + /* Just read measurement, take given action when fetching full log */ + lsp_tmp = cfg.lsp & 0xf3; + + err = nvme_cli_get_log_phy_rx_eom(dev, lsp_tmp, cfg.controller, phy_rx_eom_log_len, + phy_rx_eom_log); + if (err) { + if (err > 0) + nvme_show_status(err); + else + nvme_show_error("phy-rx-eom-log: %s", nvme_strerror(errno)); + + return err; + } + + if (phy_rx_eom_log->eomip == NVME_PHY_RX_EOM_COMPLETED) + phy_rx_eom_log_len = le16_to_cpu(phy_rx_eom_log->hsize) + + le32_to_cpu(phy_rx_eom_log->dsize) * + le16_to_cpu(phy_rx_eom_log->nd); + else + phy_rx_eom_log_len = le16_to_cpu(phy_rx_eom_log->hsize); + + phy_rx_eom_log = nvme_realloc(phy_rx_eom_log, phy_rx_eom_log_len); + if (!phy_rx_eom_log) + return -ENOMEM; - err = nvme_cli_get_log_media_unit_stat(dev, cfg.domainid, &mus); + err = nvme_cli_get_log_phy_rx_eom(dev, cfg.lsp, cfg.controller, phy_rx_eom_log_len, + phy_rx_eom_log); if (!err) - nvme_show_media_unit_stat_log(&mus, flags); + nvme_show_phy_rx_eom_log(phy_rx_eom_log, cfg.controller, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "media unit status log: %s\n", - nvme_strerror(errno)); + nvme_show_error("phy-rx-eom-log: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } -static int get_supp_cap_config_log(int argc, char **argv, struct command *cmd, +static int get_media_unit_stat_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve the list of Supported Capacity Configuration Descriptors"; - const char *domainid = "Domain Identifier"; - const char *raw = "use binary output"; - struct nvme_supported_cap_config_list_log cap_log; + const char *desc = "Retrieve the configuration and wear of media units and print it"; + + _cleanup_free_ struct nvme_media_unit_stat_log *mus = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; struct config { __u16 domainid; - char *output_format; bool raw_binary; }; struct config cfg = { .domainid = 0, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_UINT("domain-id", 'd', &cfg.domainid, domainid), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("domain-id", 'd', &cfg.domainid, domainid), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; - - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + return err; - if (cfg.raw_binary) + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + if (cfg.raw_binary) flags = BINARY; + mus = nvme_alloc(sizeof(*mus)); + if (!mus) + return -ENOMEM; + + err = nvme_cli_get_log_media_unit_stat(dev, cfg.domainid, mus); + if (!err) + nvme_show_media_unit_stat_log(mus, flags); + else if (err > 0) + nvme_show_status(err); + else + nvme_show_error("media unit status log: %s", nvme_strerror(errno)); + + return err; +} + +static int get_supp_cap_config_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Retrieve the list of Supported Capacity Configuration Descriptors"; + + _cleanup_free_ struct nvme_supported_cap_config_list_log *cap_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + enum nvme_print_flags flags; + int err = -1; + + struct config { + __u16 domainid; + bool raw_binary; + }; + + struct config cfg = { + .domainid = 0, + .raw_binary = false, + }; + + NVME_ARGS(opts, + OPT_UINT("domain-id", 'd', &cfg.domainid, domainid), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + if (cfg.raw_binary) + flags = BINARY; + + cap_log = nvme_alloc(sizeof(*cap_log)); + if (!cap_log) + return -ENOMEM; + err = nvme_cli_get_log_support_cap_config_list(dev, cfg.domainid, - &cap_log); + cap_log); if (!err) - nvme_show_supported_cap_config_log(&cap_log, flags); + nvme_show_supported_cap_config_log(cap_log, flags); else if (err > 0) nvme_show_status(err); else - perror("supported capacity configuration list log"); + nvme_show_perror("supported capacity configuration list log"); + + return err; +} + +static int io_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "I/O Management Send"; + const char *data = "optional file for data (default stdin)"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *buf = NULL; + int err = -1; + int dfd = STDIN_FILENO; + + struct config { + __u16 mos; + __u8 mo; + __u32 namespace_id; + char *file; + __u32 data_len; + }; + + struct config cfg = { + .mos = 0, + }; + + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SHRT("mos", 's', &cfg.mos, mos), + OPT_BYTE("mo", 'm', &cfg.mo, mo), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + nvme_show_perror("get-namespace-id"); + return err; + } + } + + if (cfg.data_len) { + buf = nvme_alloc(cfg.data_len); + if (!buf) + return -ENOMEM; + } + + if (cfg.file) { + dfd = open(cfg.file, O_RDONLY); + if (dfd < 0) { + nvme_show_perror(cfg.file); + return -errno; + } + } + + err = read(dfd, buf, cfg.data_len); + if (err < 0) { + nvme_show_perror("read"); + goto close_fd; + } + + struct nvme_io_mgmt_send_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .nsid = cfg.namespace_id, + .mos = cfg.mos, + .mo = cfg.mo, + .data_len = cfg.data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + err = nvme_io_mgmt_send(&args); + if (!err) + printf("io-mgmt-send: Success, mos:%u mo:%u nsid:%d\n", + cfg.mos, cfg.mo, cfg.namespace_id); + else if (err > 0) + nvme_show_status(err); + else + nvme_show_perror("io-mgmt-send"); + +close_fd: + if (cfg.file) + close(dfd); + return err; +} + +static int io_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "I/O Management Receive"; + const char *data = "optional file for data (default stdout)"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *buf = NULL; + int err = -1; + _cleanup_file_ int dfd = -1; + + struct config { + __u16 mos; + __u8 mo; + __u32 namespace_id; + char *file; + __u32 data_len; + }; + + struct config cfg = { + .mos = 0, + }; + + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SHRT("mos", 's', &cfg.mos, mos), + OPT_BYTE("mo", 'm', &cfg.mo, mo), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + nvme_show_perror("get-namespace-id"); + return err; + } + } + + if (cfg.data_len) { + buf = nvme_alloc(cfg.data_len); + if (!buf) + return -ENOMEM; + } + + struct nvme_io_mgmt_recv_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .nsid = cfg.namespace_id, + .mos = cfg.mos, + .mo = cfg.mo, + .data_len = cfg.data_len, + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + }; + + err = nvme_io_mgmt_recv(&args); + if (!err) { + printf("io-mgmt-recv: Success, mos:%u mo:%u nsid:%d\n", + cfg.mos, cfg.mo, cfg.namespace_id); + + if (cfg.file) { + dfd = open(cfg.file, O_WRONLY | O_CREAT, 0644); + if (dfd < 0) { + nvme_show_perror(cfg.file); + return -errno; + } + + err = write(dfd, buf, cfg.data_len); + if (err < 0) { + nvme_show_perror("write"); + return -errno; + } + } else { + d((unsigned char *)buf, cfg.data_len, 16, 1); + } + } else if (err > 0) { + nvme_show_status(err); + } else { + nvme_show_perror("io-mgmt-recv"); + } -close_dev: - dev_close(dev); -ret: return err; } static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve desired number of bytes "\ - "from a given log on a specified device in either "\ + 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 *lsi = "log specific identifier specifies an identifier that is required for a particular log page"; - const char *rae = "retain an asynchronous event"; const char *raw = "output in raw format"; - const char *uuid_index = "UUID index"; - const char *csi = "command set identifier"; const char *offset_type = "offset type"; - struct nvme_dev *dev; - unsigned char *log; + const char *xfer_len = "read chunk size (default 4k)"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ unsigned char *log = NULL; int err; struct config { @@ -1803,6 +2179,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl bool raw_binary; __u8 csi; bool ot; + __u32 xfer_len; }; struct config cfg = { @@ -1818,58 +2195,57 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl .raw_binary = false, .csi = NVME_CSI_NVM, .ot = false, - }; - - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_BYTE("log-id", 'i', &cfg.log_id, log_id), - OPT_UINT("log-len", 'l', &cfg.log_len, log_len), - OPT_UINT("aen", 'a', &cfg.aen, aen), - OPT_SUFFIX("lpo", 'o', &cfg.lpo, lpo), - OPT_BYTE("lsp", 's', &cfg.lsp, lsp), - OPT_SHRT("lsi", 'S', &cfg.lsi, lsi), - OPT_FLAG("rae", 'r', &cfg.rae, rae), - OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_BYTE("csi", 'y', &cfg.csi, csi), - OPT_FLAG("ot", 'O', &cfg.ot, offset_type), - OPT_END() - }; + .xfer_len = 4096, + }; + + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_BYTE("log-id", 'i', &cfg.log_id, log_id), + OPT_UINT("log-len", 'l', &cfg.log_len, log_len), + OPT_UINT("aen", 'a', &cfg.aen, aen), + OPT_SUFFIX("lpo", 'L', &cfg.lpo, lpo), + OPT_BYTE("lsp", 's', &cfg.lsp, lsp), + OPT_SHRT("lsi", 'S', &cfg.lsi, lsi), + OPT_FLAG("rae", 'r', &cfg.rae, rae), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_BYTE("csi", 'y', &cfg.csi, csi), + OPT_FLAG("ot", 'O', &cfg.ot, offset_type), + OPT_UINT("xfer-len", 'x', &cfg.xfer_len, xfer_len)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.aen) { cfg.log_len = 4096; cfg.log_id = (cfg.aen >> 16) & 0xff; } - if (!cfg.log_len) { - perror("non-zero log-len is required param\n"); - err = -EINVAL; - goto close_dev; + if (!cfg.log_len || cfg.log_len & 0x3) { + nvme_show_error("non-zero or non-dw alignment log-len is required param"); + return -EINVAL; } - if (cfg.lsp > 128) { - perror("invalid lsp param\n"); - err = -EINVAL; - goto close_dev; + if (cfg.lsp > 127) { + nvme_show_error("invalid lsp param"); + return -EINVAL; } - if (cfg.uuid_index > 128) { - perror("invalid uuid index param\n"); - err = -EINVAL; - goto close_dev; + if (cfg.uuid_index > 127) { + nvme_show_error("invalid uuid index param"); + return -EINVAL; } - log = malloc(cfg.log_len); - if (!log) { - perror("could not alloc buffer for log\n"); - err = -ENOMEM; - goto close_dev; + if (cfg.xfer_len == 0 || cfg.xfer_len % 4096) { + nvme_show_error("xfer-len argument invalid. It needs to be multiple of 4k"); + return -EINVAL; } + log = nvme_alloc(cfg.log_len); + if (!log) + return -ENOMEM; + struct nvme_get_log_args args = { .args_size = sizeof(args), .lid = cfg.log_id, @@ -1885,83 +2261,78 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl .log = log, .result = NULL, }; - err = nvme_cli_get_log(dev, &args); + err = nvme_cli_get_log_page(dev, cfg.xfer_len, &args); if (!err) { if (!cfg.raw_binary) { - printf("Device:%s log-id:%d namespace-id:%#x\n", - dev->name, cfg.log_id, - cfg.namespace_id); + printf("Device:%s log-id:%d namespace-id:%#x\n", dev->name, cfg.log_id, + cfg.namespace_id); d(log, cfg.log_len, 16, 1); - } else + } else { d_raw((unsigned char *)log, cfg.log_len); - } else if (err > 0) + } + } else if (err > 0) { nvme_show_status(err); - else - fprintf(stderr, "log page: %s\n", nvme_strerror(errno)); - free(log); + } else { + nvme_show_error("log page: %s", nvme_strerror(errno)); + } -close_dev: - dev_close(dev); -ret: return err; } static int sanitize_log(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Retrieve sanitize log and show it."; - const char *rae = "Retain an Asynchronous Event"; - const char *raw = "show log in binary format"; - const char *human_readable = "show log in readable format"; - struct nvme_sanitize_log_page sanitize_log; + + _cleanup_free_ struct nvme_sanitize_log_page *sanitize_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { bool rae; - char *output_format; bool human_readable; bool raw_binary; }; struct config cfg = { .rae = false, - .output_format = "normal", .human_readable = false, .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_FLAG("rae", 'r', &cfg.rae, rae), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_FLAG("rae", 'r', &cfg.rae, rae), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_log)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (cfg.human_readable) flags |= VERBOSE; - err = nvme_cli_get_log_sanitize(dev, cfg.rae, &sanitize_log); + sanitize_log = nvme_alloc(sizeof(*sanitize_log)); + if (!sanitize_log) + return -ENOMEM; + + err = nvme_cli_get_log_sanitize(dev, cfg.rae, sanitize_log); if (!err) - nvme_show_sanitize_log(&sanitize_log, dev->name, flags); + nvme_show_sanitize_log(sanitize_log, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "sanitize status log: %s\n", - nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("sanitize status log: %s", nvme_strerror(errno)); + return err; } @@ -1969,51 +2340,48 @@ static int get_fid_support_effects_log(int argc, char **argv, struct command *cm struct plugin *plugin) { const char *desc = "Retrieve FID Support and Effects log and show it."; - const char *human_readable = "show log in readable format"; - struct nvme_fid_supported_effects_log fid_support_log; + + _cleanup_free_ struct nvme_fid_supported_effects_log *fid_support_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; struct config { - char *output_format; bool human_readable; }; struct config cfg = { - .output_format = "normal", .human_readable = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.human_readable) flags |= VERBOSE; - err = nvme_cli_get_log_fid_supported_effects(dev, false, - &fid_support_log); + fid_support_log = nvme_alloc(sizeof(*fid_support_log)); + if (!fid_support_log) + return -ENOMEM; + + err = nvme_cli_get_log_fid_supported_effects(dev, false, fid_support_log); if (!err) - nvme_show_fid_support_effects_log(&fid_support_log, - dev->name, flags); + nvme_show_fid_support_effects_log(fid_support_log, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "fid support effects log: %s\n", - nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("fid support effects log: %s", nvme_strerror(errno)); + return err; } @@ -2021,98 +2389,90 @@ static int get_mi_cmd_support_effects_log(int argc, char **argv, struct command struct plugin *plugin) { const char *desc = "Retrieve NVMe-MI Command Support and Effects log and show it."; - const char *human_readable = "show log in readable format"; - struct nvme_mi_cmd_supported_effects_log mi_cmd_support_log; + + _cleanup_free_ struct nvme_mi_cmd_supported_effects_log *mi_cmd_support_log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; struct config { - char *output_format; bool human_readable; }; struct config cfg = { - .output_format = "normal", .human_readable = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.human_readable) flags |= VERBOSE; - err = nvme_cli_get_log_mi_cmd_supported_effects(dev, false, - &mi_cmd_support_log); + mi_cmd_support_log = nvme_alloc(sizeof(*mi_cmd_support_log)); + if (!mi_cmd_support_log) + return -ENOMEM; + + err = nvme_cli_get_log_mi_cmd_supported_effects(dev, false, mi_cmd_support_log); if (!err) - nvme_show_mi_cmd_support_effects_log(&mi_cmd_support_log, - dev->name, flags); + nvme_show_mi_cmd_support_effects_log(mi_cmd_support_log, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "mi command support effects log: %s\n", - nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("mi command support effects log: %s", nvme_strerror(errno)); + return err; } static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Show controller list information for the subsystem the "\ + 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"; - struct nvme_ctrl_list *cntlist; + + _cleanup_free_ struct nvme_ctrl_list *cntlist = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u16 cntid; __u32 namespace_id; - char *output_format; }; struct config cfg = { .cntid = 0, .namespace_id = NVME_NSID_NONE, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_SHRT("cntid", 'c', &cfg.cntid, controller), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("cntid", 'c', &cfg.cntid, controller), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_optional)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; - - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + return err; - if (posix_memalign((void *)&cntlist, getpagesize(), 0x1000)) { - fprintf(stderr, "can not allocate controller list payload\n"); - err = -ENOMEM; - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; } + cntlist = nvme_alloc(sizeof(*cntlist)); + if (!cntlist) + return -ENOMEM; + if (cfg.namespace_id == NVME_NSID_NONE) err = nvme_cli_identify_ctrl_list(dev, cfg.cntid, cntlist); else @@ -2123,72 +2483,64 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin * else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "id controller list: %s\n", - nvme_strerror(errno)); + nvme_show_error("id controller list: %s", nvme_strerror(errno)); - free(cntlist); -close_dev: - dev_close(dev); -ret: return err; } static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "For the specified controller handle, show the "\ + const char *desc = "For the specified controller handle, show the " "namespace list in the associated NVMe subsystem, optionally starting with a given nsid."; const char *namespace_id = "first nsid returned list should start from"; const char *csi = "I/O command set identifier"; const char *all = "show all namespaces in the subsystem, whether attached or inactive"; - struct nvme_ns_list ns_list; + + _cleanup_free_ struct nvme_ns_list *ns_list = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u32 namespace_id; int csi; bool all; - char *output_format; }; struct config cfg = { .namespace_id = 1, .csi = -1, .all = false, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_INT("csi", 'y', &cfg.csi, csi), - OPT_FLAG("all", 'a', &cfg.all, all), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_INT("csi", 'y', &cfg.csi, csi), + OPT_FLAG("all", 'a', &cfg.all, all)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; - if (flags != JSON && flags != NORMAL) { - err = -EINVAL; - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0 || (flags != JSON && flags != NORMAL)) { + nvme_show_error("Invalid output format"); + return -EINVAL; } if (!cfg.namespace_id) { - err = -EINVAL; - fprintf(stderr, "invalid nsid parameter\n"); - goto close_dev; + nvme_show_error("invalid nsid parameter"); + return -EINVAL; } + ns_list = nvme_alloc(sizeof(*ns_list)); + if (!ns_list) + return -ENOMEM; + struct nvme_identify_args args = { .args_size = sizeof(args), .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .data = &ns_list, + .data = ns_list, .nsid = cfg.namespace_id - 1. }; if (cfg.csi < 0) { @@ -2201,155 +2553,129 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl } err = nvme_cli_identify(dev, &args); - if (!err) - nvme_show_list_ns(&ns_list, flags); + nvme_show_list_ns(ns_list, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "id namespace list: %s", - nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("id namespace list: %s", nvme_strerror(errno)); + return err; } static int id_ns_lba_format(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Namespace command to the given "\ - "device, returns capability field properties of the specified "\ + const char *desc = "Send an Identify Namespace command to the given " + "device, returns capability field properties of the specified " "LBA Format index in various formats."; - const char *lba_format_index = "The index into the LBA Format list "\ - "identifying the LBA Format capabilities that are to be returned"; - const char *uuid_index = "UUID index"; - const char *verbose = "Increase output verbosity"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; enum nvme_print_flags flags; - struct nvme_id_ns ns; - struct nvme_dev *dev; int err = -1; struct config { __u16 lba_format_index; __u8 uuid_index; - bool verbose; - char *output_format; }; struct config cfg = { .lba_format_index = 0, .uuid_index = NVME_UUID_NONE, - .verbose = false, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_UINT("lba-format-index", 'i', &cfg.lba_format_index, lba_format_index), - OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("lba-format-index", 'i', &cfg.lba_format_index, lba_format_index), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - if (cfg.verbose) + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + err = nvme_identify_ns_csi_user_data_format(dev_fd(dev), - cfg.lba_format_index, - cfg.uuid_index, NVME_CSI_NVM, &ns); + cfg.lba_format_index, + cfg.uuid_index, NVME_CSI_NVM, ns); if (!err) - nvme_show_id_ns(&ns, 0, cfg.lba_format_index, true, flags); + nvme_show_id_ns(ns, 0, cfg.lba_format_index, true, flags); else if (err > 0) nvme_show_status(err); else - perror("identify namespace for specific LBA format"); -close_dev: - dev_close(dev); -ret: - return nvme_status_to_errno(err, false); + nvme_show_perror("identify namespace for specific LBA format"); + + return err; } static int id_endurance_grp_list(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Show endurance group list information for the given endurance "\ - "group id"; + const char *desc = "Show endurance group list information for the given endurance group id"; const char *endurance_grp_id = "Endurance Group ID"; - struct nvme_id_endurance_group_list *endgrp_list; + + _cleanup_free_ struct nvme_id_endurance_group_list *endgrp_list = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err = -1; struct config { __u16 endgrp_id; - char *output_format; }; struct config cfg = { .endgrp_id = 0, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_SHRT("endgrp-id", 'i', &cfg.endgrp_id, endurance_grp_id), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("endgrp-id", 'i', &cfg.endgrp_id, endurance_grp_id)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; - if (flags != JSON && flags != NORMAL) { - err = -EINVAL; - fprintf(stderr, "invalid output format\n"); - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0 || (flags != JSON && flags != NORMAL)) { + nvme_show_error("invalid output format"); + return -EINVAL; } - if (posix_memalign((void *)&endgrp_list, getpagesize(), 0x1000)) { - err = -1; - goto close_dev; - } + endgrp_list = nvme_alloc(sizeof(*endgrp_list)); + if (!endgrp_list) + return -ENOMEM; - err = nvme_identify_endurance_group_list(dev_fd(dev), cfg.endgrp_id, - endgrp_list); + err = nvme_identify_endurance_group_list(dev_fd(dev), cfg.endgrp_id, endgrp_list); if (!err) nvme_show_endurance_group_list(endgrp_list, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "Id endurance group list: %s", - nvme_strerror(errno)); + nvme_show_error("Id endurance group list: %s", nvme_strerror(errno)); - free(endgrp_list); -close_dev: - dev_close(dev); -ret: return err; } static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Delete the given namespace by "\ - "sending a namespace management command to "\ - "the provided device. All controllers should be detached from "\ - "the namespace prior to namespace deletion. A namespace ID "\ - "becomes inactive when that namespace is detached or, if "\ + 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"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -2362,46 +2688,39 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin * .timeout = 120000, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("timeout", 't', &cfg.timeout, timeout), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("timeout", 't', &cfg.timeout, timeout)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", - nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } err = nvme_cli_ns_mgmt_delete(dev, cfg.namespace_id); if (!err) - printf("%s: Success, deleted nsid:%d\n", cmd->name, - cfg.namespace_id); + printf("%s: Success, deleted nsid:%d\n", cmd->name, cfg.namespace_id); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "delete namespace: %s\n", nvme_strerror(errno)); + nvme_show_error("delete namespace: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, struct command *cmd) { - struct nvme_ctrl_list cntlist; + _cleanup_free_ struct nvme_ctrl_list *cntlist = NULL; + _cleanup_free_ __u16 *ctrlist = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err, num, i, list[2048]; - struct nvme_dev *dev; - __u16 ctrlist[2048]; const char *namespace_id = "namespace to attach"; const char *cont = "optional comma-sep controller id list"; @@ -2416,104 +2735,216 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s .cntlist = "", }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_LIST("controllers", 'c', &cfg.cntlist, cont), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_LIST("controllers", 'c', &cfg.cntlist, cont)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { - fprintf(stderr, "%s: namespace-id parameter required\n", - cmd->name); - err = -EINVAL; - goto close_dev; + nvme_show_error("%s: namespace-id parameter required", cmd->name); + return -EINVAL; } num = argconfig_parse_comma_sep_array(cfg.cntlist, list, 2047); - if (!num) { + 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_dev; + nvme_show_error("%s: controller id list is malformed", cmd->name); + return -EINVAL; } + cntlist = nvme_alloc(sizeof(*cntlist)); + if (!cntlist) + return -ENOMEM; + + ctrlist = nvme_alloc(sizeof(*ctrlist) * 2048); + if (!ctrlist) + return -ENOMEM; + for (i = 0; i < num; i++) ctrlist[i] = (__u16)list[i]; - nvme_init_ctrl_list(&cntlist, num, ctrlist); + nvme_init_ctrl_list(cntlist, num, ctrlist); if (attach) err = nvme_cli_ns_attach_ctrls(dev, cfg.namespace_id, - &cntlist); + cntlist); else err = nvme_cli_ns_detach_ctrls(dev, cfg.namespace_id, - &cntlist); + cntlist); 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"); + nvme_show_perror(attach ? "attach namespace" : "detach namespace"); -close_dev: - dev_close(dev); -ret: return err; } static int attach_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Attach the given namespace to the "\ - "given controller or comma-sep list of controllers. ID of the "\ - "given namespace becomes active upon attachment to a "\ - "controller. A namespace must be attached to a controller "\ + 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 "\ + const char *desc = "Detach the given namespace from the " + "given controller; de-activates the given namespace's ID. A " + "namespace must be attached to a controller before IO " "commands may be directed to that namespace."; + return nvme_attach_ns(argc, argv, 0, desc, cmd); } +static int parse_lba_num_si(struct nvme_dev *dev, const char *opt, + const char *val, __u8 flbas, __u64 *num, __u32 align) +{ + _cleanup_free_ struct nvme_ns_list *ns_list = NULL; + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + __u32 nsid = 1; + unsigned int remainder; + char *endptr; + int err = -EINVAL; + int i; + int lbas; + + struct nvme_identify_args args = { + .args_size = sizeof(args), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST, + .nsid = nsid - 1. + }; + + if (!val) + return 0; + + if (*num) { + nvme_show_error( + "Invalid specification of both %s and its SI argument, please specify only one", + opt); + return err; + } + + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); + if (err) { + if (err < 0) + nvme_show_error("identify controller: %s", nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + + ns_list = nvme_alloc(sizeof(*ns_list)); + if (!ns_list) + return -ENOMEM; + args.data = ns_list; + + if ((ctrl->oacs & 0x8) >> 3) + nsid = NVME_NSID_ALL; + else { + err = nvme_cli_identify(dev, &args); + if (err) { + if (err < 0) + nvme_show_error("identify namespace list: %s", + nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + nsid = le32_to_cpu(ns_list->ns[0]); + } + + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, nsid, ns); + if (err) { + if (err < 0) + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + else + nvme_show_status(err); + return err; + } + + i = flbas & NVME_NS_FLBAS_LOWER_MASK; + lbas = (1 << ns->lbaf[i].ds) + ns->lbaf[i].ms; + + if (suffix_si_parse(val, &endptr, (uint64_t *)num)) { + nvme_show_error("Expected long suffixed integer argument for '%s-si' but got '%s'!", + opt, val); + return -errno; + } + + if (endptr[0]) { + remainder = *num % align; + if (remainder) + *num += align - remainder; + } + + if (endptr[0] != '\0') + *num /= lbas; + + return 0; +} + static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send a namespace management command "\ - "to the specified device to create a namespace with the given "\ - "parameters. The next available namespace ID is used for the "\ - "create operation. Note that create-ns does not attach the "\ + const char *desc = "Send a namespace management command " + "to the specified device to create a namespace with the given " + "parameters. The next available namespace ID is used for the " + "create operation. Note that create-ns does not attach the " "namespace to a controller, the attach-ns command is needed."; const char *nsze = "size of ns (NSZE)"; const char *ncap = "capacity of ns (NCAP)"; - const char *flbas = "Formatted LBA size (FLBAS), if entering this "\ - "value ignore \'block-size\' field"; + const char *flbas = + "Formatted LBA size (FLBAS), if entering this value ignore \'block-size\' field"; const char *dps = "data protection settings (DPS)"; const char *nmic = "multipath and sharing capabilities (NMIC)"; const char *anagrpid = "ANA Group Identifier (ANAGRPID)"; const char *nvmsetid = "NVM Set Identifier (NVMSETID)"; + const char *endgid = "Endurance Group Identifier (ENDGID)"; const char *csi = "command set identifier (CSI)"; const char *lbstm = "logical block storage tag mask (LBSTM)"; - const char *timeout = "timeout value, in milliseconds"; - const char *bs = "target block size, specify only if \'FLBAS\' "\ - "value not entered"; - - struct nvme_id_ns ns; - struct nvme_dev *dev; + const char *nphndls = "Number of Placement Handles (NPHNDLS)"; + const char *bs = "target block size, specify only if \'FLBAS\' value not entered"; + const char *nsze_si = "size of ns (NSZE) in standard SI units"; + const char *ncap_si = "capacity of ns (NCAP) in standard SI units"; + const char *azr = "Allocate ZRWA Resources (AZR) for Zoned Namespace Command Set"; + const char *rar = "Requested Active Resources (RAR) for Zoned Namespace Command Set"; + const char *ror = "Requested Open Resources (ROR) for Zoned Namespace Command Set"; + const char *rnumzrwa = + "Requested Number of ZRWA Resources (RNUMZRWA) for Zoned Namespace Command Set"; + const char *phndls = "Comma separated list of Placement Handle Associated RUH"; + + _cleanup_free_ struct nvme_ns_mgmt_host_sw_specified *data = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err = 0, i; __u32 nsid; + uint16_t num_phandle; + uint16_t phndl[128] = { 0, }; + _cleanup_free_ struct nvme_id_ctrl *id = NULL; + _cleanup_free_ struct nvme_id_ns_granularity_list *gr_list = NULL; + __u32 align_nsze = 1 << 20; /* Default 1 MiB */ + __u32 align_ncap = align_nsze; struct config { __u64 nsze; @@ -2523,10 +2954,19 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * __u8 nmic; __u32 anagrpid; __u16 nvmsetid; + __u16 endgid; __u64 bs; __u32 timeout; __u8 csi; __u64 lbstm; + __u16 nphndls; + char *nsze_si; + char *ncap_si; + bool azr; + __u32 rar; + __u32 ror; + __u32 rnumzrwa; + char *phndls; }; struct config cfg = { @@ -2537,58 +2977,77 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * .nmic = 0, .anagrpid = 0, .nvmsetid = 0, + .endgid = 0, .bs = 0x00, .timeout = 120000, .csi = 0, .lbstm = 0, - }; - - 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_BYTE("csi", 'y', &cfg.csi, csi), - OPT_SUFFIX("lbstm", 'l', &cfg.lbstm, lbstm), - OPT_END() - }; + .nphndls = 0, + .nsze_si = NULL, + .ncap_si = NULL, + .azr = false, + .rar = 0, + .ror = 0, + .rnumzrwa = 0, + .phndls = "", + }; + + NVME_ARGS(opts, + OPT_SUFFIX("nsze", 's', &cfg.nsze, nsze), + OPT_SUFFIX("ncap", 'c', &cfg.ncap, ncap), + OPT_BYTE("flbas", 'f', &cfg.flbas, flbas), + OPT_BYTE("dps", 'd', &cfg.dps, dps), + OPT_BYTE("nmic", 'm', &cfg.nmic, nmic), + OPT_UINT("anagrp-id", 'a', &cfg.anagrpid, anagrpid), + OPT_UINT("nvmset-id", 'i', &cfg.nvmsetid, nvmsetid), + OPT_UINT("endg-id", 'e', &cfg.endgid, endgid), + OPT_SUFFIX("block-size", 'b', &cfg.bs, bs), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), + OPT_BYTE("csi", 'y', &cfg.csi, csi), + OPT_SUFFIX("lbstm", 'l', &cfg.lbstm, lbstm), + OPT_SHRT("nphndls", 'n', &cfg.nphndls, nphndls), + OPT_STR("nsze-si", 'S', &cfg.nsze_si, nsze_si), + OPT_STR("ncap-si", 'C', &cfg.ncap_si, ncap_si), + OPT_FLAG("azr", 'z', &cfg.azr, azr), + OPT_UINT("rar", 'r', &cfg.rar, rar), + OPT_UINT("ror", 'O', &cfg.ror, ror), + OPT_UINT("rnumzrwa", 'u', &cfg.rnumzrwa, rnumzrwa), + OPT_LIST("phndls", 'p', &cfg.phndls, phndls)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; 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_dev; + nvme_show_error( + "Invalid specification of both FLBAS and Block Size, please specify only one"); + return -EINVAL; } if (cfg.bs) { if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) { - 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_dev; + nvme_show_error( + "Invalid value for block size (%"PRIu64"). Block size must be a power of two", + (uint64_t)cfg.bs); + return -EINVAL; } - err = nvme_cli_identify_ns(dev, NVME_NSID_ALL, &ns); + + + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, NVME_NSID_ALL, ns); if (err) { - if (err < 0) - fprintf(stderr, "identify-namespace: %s", - nvme_strerror(errno)); - else { + if (err < 0) { + nvme_show_error("identify-namespace: %s", nvme_strerror(errno)); + } else { fprintf(stderr, "identify failed\n"); nvme_show_status(err); } - goto close_dev; + return err; } - for (i = 0; i <= ns.nlbaf; ++i) { - if ((1 << ns.lbaf[i].ds) == cfg.bs && ns.lbaf[i].ms == 0) { + for (i = 0; i <= ns->nlbaf; ++i) { + if ((1 << ns->lbaf[i].ds) == cfg.bs && ns->lbaf[i].ms == 0) { cfg.flbas = i; break; } @@ -2596,38 +3055,107 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * } if (cfg.flbas == 0xff) { - fprintf(stderr, - "FLBAS corresponding to block size %"PRIu64" not found\n", + 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"); + fprintf(stderr, "Please correct block size, or specify FLBAS directly\n"); - err = -EINVAL; - goto close_dev; + return -EINVAL; } - struct nvme_id_ns ns2 = { - .nsze = cpu_to_le64(cfg.nsze), - .ncap = cpu_to_le64(cfg.ncap), - .flbas = cfg.flbas, - .dps = cfg.dps, - .nmic = cfg.nmic, - .anagrpid = cpu_to_le32(cfg.anagrpid), - .nvmsetid = cpu_to_le16(cfg.nvmsetid), - .lbstm = cpu_to_le64(cfg.lbstm), - }; + id = nvme_alloc(sizeof(*id)); + if (!id) + return -ENOMEM; + + err = nvme_identify_ctrl(dev_fd(dev), id); + if (err) { + if (err < 0) { + nvme_show_error("identify-controller: %s", nvme_strerror(errno)); + } else { + fprintf(stderr, "identify controller failed\n"); + nvme_show_status(err); + } + return err; + } + + if (id->ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) { + gr_list = nvme_alloc(sizeof(*gr_list)); + if (!gr_list) + return -ENOMEM; + + if (!nvme_identify_ns_granularity(dev_fd(dev), gr_list)) { + struct nvme_id_ns_granularity_desc *desc; + int index = cfg.flbas; + + /* FIXME: add a proper bitmask to libnvme */ + if (!(gr_list->attributes & 1)) { + /* Only the first descriptor is valid */ + index = 0; + } else if (index > gr_list->num_descriptors) { + /* + * The descriptor will contain only zeroes + * so we don't need to read it. + */ + goto parse_lba; + } + desc = &gr_list->entry[index]; + + if (desc->nszegran && desc->nszegran < align_nsze) + align_nsze = desc->nszegran; + if (desc->ncapgran && desc->ncapgran < align_ncap) + align_ncap = desc->ncapgran; + } + } + +parse_lba: + err = parse_lba_num_si(dev, "nsze", cfg.nsze_si, cfg.flbas, &cfg.nsze, align_nsze); + if (err) + return err; + + err = parse_lba_num_si(dev, "ncap", cfg.ncap_si, cfg.flbas, &cfg.ncap, align_ncap); + if (err) + return err; + + if (cfg.csi != NVME_CSI_ZNS && (cfg.azr || cfg.rar || cfg.ror || cfg.rnumzrwa)) { + nvme_show_error("Invalid ZNS argument is given (CSI:%#x)", cfg.csi); + return -EINVAL; + } + + data = nvme_alloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->nsze = cpu_to_le64(cfg.nsze); + data->ncap = cpu_to_le64(cfg.ncap); + data->flbas = cfg.flbas; + data->dps = cfg.dps; + data->nmic = cfg.nmic; + data->anagrpid = cpu_to_le32(cfg.anagrpid); + data->nvmsetid = cpu_to_le16(cfg.nvmsetid); + data->endgid = cpu_to_le16(cfg.endgid); + data->lbstm = cpu_to_le64(cfg.lbstm); + data->zns.znsco = cfg.azr; + data->zns.rar = cpu_to_le32(cfg.rar); + data->zns.ror = cpu_to_le32(cfg.ror); + data->zns.rnumzrwa = cpu_to_le32(cfg.rnumzrwa); + data->nphndls = cpu_to_le16(cfg.nphndls); + + num_phandle = argconfig_parse_comma_sep_array_short(cfg.phndls, phndl, ARRAY_SIZE(phndl)); + if (cfg.nphndls != num_phandle) { + nvme_show_error("Invalid Placement handle list"); + return -EINVAL; + } - err = nvme_cli_ns_mgmt_create(dev, &ns2, &nsid, cfg.timeout, cfg.csi); + for (i = 0; i < num_phandle; i++) + data->phndl[i] = cpu_to_le16(phndl[i]); + + err = nvme_cli_ns_mgmt_create(dev, data, &nsid, cfg.timeout, cfg.csi); if (!err) printf("%s: Success, created nsid:%d\n", cmd->name, nsid); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "create namespace: %s\n", nvme_strerror(errno)); + nvme_show_error("create namespace: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } @@ -2672,27 +3200,12 @@ static int list_subsys(int argc, char **argv, struct command *cmd, nvme_root_t r = NULL; enum nvme_print_flags flags; const char *desc = "Retrieve information for subsystems"; - const char *verbose = "Increase output verbosity"; nvme_scan_filter_t filter = NULL; char *devname; int err; int nsid = NVME_NSID_ALL; - 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_INCR("verbose", 'v', &cfg.verbose, verbose), - OPT_END() - }; + NVME_ARGS(opts); err = argconfig_parse(argc, argv, desc, opts); if (err < 0) @@ -2702,24 +3215,22 @@ static int list_subsys(int argc, char **argv, struct command *cmd, if (optind < argc) devname = basename(argv[optind++]); - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto ret; - if (flags != JSON && flags != NORMAL) { - err = -EINVAL; - goto ret; + err = validate_output_format(output_format_val, &flags); + if (err < 0 || (flags != JSON && flags != NORMAL)) { + nvme_show_error("Invalid output format"); + return -EINVAL; } - if (cfg.verbose) + + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; - r = nvme_create_root(stderr, map_log_level(cfg.verbose, false)); + + r = nvme_create_root(stderr, log_level); if (!r) { if (devname) - fprintf(stderr, - "Failed to scan nvme subsystem for %s\n", - devname); + nvme_show_error("Failed to scan nvme subsystem for %s", devname); else - fprintf(stderr, "Failed to scan nvme subsystem\n"); + nvme_show_error("Failed to scan nvme subsystem"); err = -errno; goto ret; } @@ -2728,7 +3239,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd, int subsys_num; if (sscanf(devname, "nvme%dn%d", &subsys_num, &nsid) != 2) { - fprintf(stderr, "Invalid device name %s\n", devname); + nvme_show_error("Invalid device name %s", devname); err = -EINVAL; goto ret; } @@ -2737,8 +3248,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd, err = nvme_scan_topology(r, filter, (void *)devname); if (err) { - fprintf(stderr, "Failed to scan topology: %s\n", - nvme_strerror(errno)); + nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno)); goto ret; } @@ -2753,51 +3263,33 @@ static int list_subsys(int argc, char **argv, struct command *cmd, 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"; enum nvme_print_flags flags; nvme_root_t r; int err = 0; - struct config { - char *output_format; - bool verbose; - }; - - struct config cfg = { - .output_format = "normal", - .verbose = false, - }; - - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), - OPT_END() - }; + NVME_ARGS(opts); 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"); + err = validate_output_format(output_format_val, &flags); + if (err < 0 || (flags != JSON && flags != NORMAL)) { + nvme_show_error("Invalid output format"); return -EINVAL; } - if (cfg.verbose) + + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; - r = nvme_create_root(stderr, map_log_level(cfg.verbose, false)); + r = nvme_create_root(stderr, log_level); if (!r) { - fprintf(stderr, "Failed to create topology root: %s\n", - nvme_strerror(errno)); + nvme_show_error("Failed to create topology root: %s", nvme_strerror(errno)); return -errno; } err = nvme_scan_topology(r, NULL, NULL); if (err < 0) { - fprintf(stderr, "Failed to scan topology: %s\n", - nvme_strerror(errno)); + nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno)); nvme_free_tree(r); return err; } @@ -2811,65 +3303,66 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi 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 "\ + 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"; + + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_id_ctrl ctrl; - struct nvme_dev *dev; int err; struct config { bool vendor_specific; - char *output_format; bool raw_binary; bool human_readable; }; struct config cfg = { .vendor_specific = false, - .output_format = "normal", .raw_binary = false, .human_readable = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_FLAG("vendor-specific", 'V', &cfg.vendor_specific, vendor_specific), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (cfg.vendor_specific) flags |= VS; + if (cfg.human_readable) flags |= VERBOSE; - err = nvme_cli_identify_ctrl(dev, &ctrl); + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); if (!err) - nvme_show_id_ctrl(&ctrl, flags, vs); + nvme_show_id_ctrl(ctrl, flags, vs); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify controller: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("identify controller: %s", nvme_strerror(errno)); + return err; } @@ -2881,278 +3374,259 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl static int nvm_id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Controller NVM Command Set "\ - "command to the given device and report information about "\ + const char *desc = "Send an Identify Controller NVM Command Set " + "command to the given device and report information about " "the specified controller in various formats."; + + _cleanup_free_ struct nvme_id_ctrl_nvm *ctrl_nvm = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_id_ctrl_nvm ctrl_nvm; - struct nvme_dev *dev; int err = -1; - struct config { - char *output_format; - }; - - struct config cfg = { - .output_format = "normal", - }; - - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + ctrl_nvm = nvme_alloc(sizeof(*ctrl_nvm)); + if (!ctrl_nvm) + return -ENOMEM; - err = nvme_nvm_identify_ctrl(dev_fd(dev), &ctrl_nvm); + err = nvme_nvm_identify_ctrl(dev_fd(dev), ctrl_nvm); if (!err) - nvme_show_id_ctrl_nvm(&ctrl_nvm, flags); + nvme_show_id_ctrl_nvm(ctrl_nvm, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "nvm identify controller: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("nvm identify controller: %s", nvme_strerror(errno)); + return err; } static int nvm_id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Namespace NVM Command Set "\ - "command to the given device and report information about "\ + const char *desc = "Send an Identify Namespace NVM Command Set " + "command to the given device and report information about " "the specified namespace in various formats."; - const char *namespace_id = "identifier of desired namespace"; - const char *uuid_index = "UUID index"; - const char *verbose = "Increase output verbosity"; + + _cleanup_free_ struct nvme_nvm_id_ns *id_ns = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_nvm_id_ns id_ns; - struct nvme_id_ns ns; - struct nvme_dev *dev; int err = -1; struct config { __u32 namespace_id; __u8 uuid_index; - char *output_format; - bool verbose; }; struct config cfg = { .namespace_id = 0, .uuid_index = NVME_UUID_NONE, - .output_format = "normal", - .verbose = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - if (cfg.verbose) + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - perror("get-namespace-id"); - goto close_dev; + nvme_show_perror("get-namespace-id"); + return err; } } - err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns); if (err) { nvme_show_status(err); - goto close_dev; + return err; } + id_ns = nvme_alloc(sizeof(*id_ns)); + if (!id_ns) + return -ENOMEM; + err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, - cfg.uuid_index, - NVME_CSI_NVM, &id_ns); + cfg.uuid_index, + NVME_CSI_NVM, id_ns); if (!err) - nvme_show_nvm_id_ns(&id_ns, cfg.namespace_id, &ns, 0, false, flags); + nvme_show_nvm_id_ns(id_ns, cfg.namespace_id, ns, 0, false, flags); else if (err > 0) nvme_show_status(err); else - perror("nvm identify namespace"); -close_dev: - dev_close(dev); -ret: - return nvme_status_to_errno(err, false); + nvme_show_perror("nvm identify namespace"); + + return err; } static int nvm_id_ns_lba_format(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Send an NVM Command Set specific Identify Namespace " "command to the given device, returns capability field properties of " - "the specified LBA Format index in the specified namespace in various " - "formats."; - const char *lba_format_index = "The index into the LBA Format list "\ - "identifying the LBA Format capabilities that are to be returned"; - const char *uuid_index = "UUID index"; - const char *verbose = "Increase output verbosity"; + "the specified LBA Format index in the specified namespace in various formats."; + + _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_id_ns ns; - struct nvme_nvm_id_ns nvm_ns; - struct nvme_dev *dev; int err = -1; struct config { __u16 lba_format_index; __u8 uuid_index; - bool verbose; - char *output_format; }; struct config cfg = { .lba_format_index = 0, .uuid_index = NVME_UUID_NONE, - .verbose = false, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_UINT("lba-format-index", 'i', &cfg.lba_format_index, lba_format_index), - OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("lba-format-index", 'i', &cfg.lba_format_index, lba_format_index), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - if (cfg.verbose) + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; - err = nvme_cli_identify_ns(dev, NVME_NSID_ALL, &ns); + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, NVME_NSID_ALL, ns); if (err) { - ns.nlbaf = NVME_FEAT_LBA_RANGE_MAX - 1; - ns.nulbaf = 0; + ns->nlbaf = NVME_FEAT_LBA_RANGE_MAX - 1; + ns->nulbaf = 0; } - err = nvme_identify_iocs_ns_csi_user_data_format(dev_fd(dev), - cfg.lba_format_index, - cfg.uuid_index, NVME_CSI_NVM, &nvm_ns); + + nvm_ns = nvme_alloc(sizeof(*nvm_ns)); + if (!nvm_ns) + return -ENOMEM; + + err = nvme_identify_iocs_ns_csi_user_data_format(dev_fd(dev), cfg.lba_format_index, + cfg.uuid_index, NVME_CSI_NVM, nvm_ns); if (!err) - nvme_show_nvm_id_ns(&nvm_ns, 0, &ns, cfg.lba_format_index, true, - flags); + nvme_show_nvm_id_ns(nvm_ns, 0, ns, cfg.lba_format_index, true, flags); else if (err > 0) nvme_show_status(err); else - perror("NVM identify namespace for specific LBA format"); -close_dev: - dev_close(dev); -ret: - return nvme_status_to_errno(err, false); + nvme_show_perror("NVM identify namespace for specific LBA format"); + + return err; } static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send Namespace Identification Descriptors command to the "\ - "given device, returns the namespace identification descriptors "\ - "of the specific namespace in either human-readable or binary format."; + const char *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"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *nsdescs = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; - void *nsdescs; int err; struct config { __u32 namespace_id; - char *output_format; bool raw_binary; }; struct config cfg = { .namespace_id = 0, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (argconfig_parse_seen(opts, "verbose")) + flags |= VERBOSE; + if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } - if (posix_memalign(&nsdescs, getpagesize(), 0x1000)) { - err = -ENOMEM; - goto close_dev; - } + nsdescs = nvme_alloc(sizeof(*nsdescs)); + if (!nsdescs) + return -ENOMEM; - err = nvme_identify_ns_descs(dev_fd(dev), cfg.namespace_id, nsdescs); + err = nvme_cli_identify_ns_descs(dev, cfg.namespace_id, nsdescs); if (!err) nvme_show_id_ns_descs(nsdescs, cfg.namespace_id, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); - free(nsdescs); -close_dev: - dev_close(dev); -ret: + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + return err; } static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Namespace command to the "\ - "given device, returns properties of the specified namespace "\ - "in either human-readable or binary format. Can also return "\ + const char *desc = "Send an Identify Namespace command to the " + "given device, returns properties of the specified namespace " + "in either human-readable or binary format. Can also return " "binary vendor-specific namespace attributes."; const char *force = "Return this namespace, even if not attached (1.2 devices only)"; const char *vendor_specific = "dump binary vendor fields"; - 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"; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; enum nvme_print_flags flags; - struct nvme_id_ns ns; - struct nvme_dev *dev; int err; struct config { @@ -3160,7 +3634,6 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug bool force; bool vendor_specific; bool raw_binary; - char *output_format; bool human_readable; }; @@ -3169,300 +3642,285 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug .force = false, .vendor_specific = false, .raw_binary = false, - .output_format = "normal", .human_readable = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FLAG("force", 0, &cfg.force, force), - OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_FLAG("force", 0, &cfg.force, force), + OPT_FLAG("vendor-specific", 'V', &cfg.vendor_specific, vendor_specific), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (cfg.vendor_specific) flags |= VS; + if (cfg.human_readable) flags |= VERBOSE; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + if (cfg.force) - err = nvme_cli_identify_allocated_ns(dev, - cfg.namespace_id, &ns); + err = nvme_cli_identify_allocated_ns(dev, cfg.namespace_id, ns); else - err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); + err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns); if (!err) - nvme_show_id_ns(&ns, cfg.namespace_id, 0, false, flags); + nvme_show_id_ns(ns, cfg.namespace_id, 0, false, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + return err; } -static int cmd_set_independent_id_ns(int argc, char **argv, - struct command *cmd, struct plugin *plugin) +static int cmd_set_independent_id_ns(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - const char *desc = "Send an I/O Command Set Independent Identify "\ - "Namespace command to the given device, returns properties of the "\ + const char *desc = "Send an I/O Command Set Independent Identify " + "Namespace command to the given device, returns properties of the " "specified namespace in human-readable or binary or json format."; - 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"; + _cleanup_free_ struct nvme_id_independent_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_id_independent_id_ns ns; - struct nvme_dev *dev; int err = -1; struct config { __u32 namespace_id; bool raw_binary; - char *output_format; bool human_readable; }; struct config cfg = { .namespace_id = 0, .raw_binary = false, - .output_format = "normal", .human_readable = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - 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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (cfg.human_readable) flags |= VERBOSE; if (!cfg.namespace_id) { - err = cfg.namespace_id = nvme_get_nsid(dev_fd(dev), - &cfg.namespace_id); + err = cfg.namespace_id = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - perror("get-namespace-id"); - goto close_dev; + nvme_show_perror("get-namespace-id"); + return err; } } - err = nvme_identify_independent_identify_ns(dev_fd(dev), - cfg.namespace_id, &ns); + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_identify_independent_identify_ns(dev_fd(dev), cfg.namespace_id, ns); if (!err) - nvme_show_cmd_set_independent_id_ns(&ns, cfg.namespace_id, flags); + nvme_show_cmd_set_independent_id_ns(ns, cfg.namespace_id, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "I/O command set independent identify namespace: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("I/O command set independent identify namespace: %s", + nvme_strerror(errno)); + return err; } static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Namespace Granularity List command to the "\ - "given device, returns namespace granularity list "\ + 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; + _cleanup_free_ struct nvme_id_ns_granularity_list *granularity_list = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; 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() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; - - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + return err; - if (posix_memalign((void *)&granularity_list, getpagesize(), NVME_IDENTIFY_DATA_SIZE)) { - fprintf(stderr, "can not allocate granularity list payload\n"); - err = -ENOMEM; - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; } + granularity_list = nvme_alloc(NVME_IDENTIFY_DATA_SIZE); + if (!granularity_list) + return -ENOMEM; + err = nvme_identify_ns_granularity(dev_fd(dev), granularity_list); if (!err) nvme_show_id_ns_granularity_list(granularity_list, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify namespace granularity: %s\n", nvme_strerror(errno)); - free(granularity_list); -close_dev: - dev_close(dev); -ret: + nvme_show_error("identify namespace granularity: %s", nvme_strerror(errno)); + return err; } static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify NVM Set List command to the "\ - "given device, returns entries for NVM Set identifiers greater "\ - "than or equal to the value specified CDW11.NVMSETID "\ + 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_list nvmset; + _cleanup_free_ struct nvme_id_nvmset_list *nvmset = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u16 nvmset_id; - char *output_format; }; struct config cfg = { .nvmset_id = 0, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_SHRT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + nvmset = nvme_alloc(sizeof(*nvmset)); + if (!nvmset) + return -ENOMEM; - err = nvme_identify_nvmset_list(dev_fd(dev), cfg.nvmset_id, &nvmset); + err = nvme_identify_nvmset_list(dev_fd(dev), cfg.nvmset_id, nvmset); if (!err) - nvme_show_id_nvmset(&nvmset, cfg.nvmset_id, flags); + nvme_show_id_nvmset(nvmset, cfg.nvmset_id, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify nvm set list: %s\n", nvme_strerror(errno)); + nvme_show_error("identify nvm set list: %s", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: return err; } static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify UUID List command to the "\ - "given device, returns list of supported Vendor Specific UUIDs "\ + 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; + _cleanup_free_ struct nvme_id_uuid_list *uuid_list = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { - char *output_format; bool raw_binary; bool human_readable; }; struct config cfg = { - .output_format = "normal", .raw_binary = false, .human_readable = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; + if (cfg.human_readable) flags |= VERBOSE; - err = nvme_identify_uuid(dev_fd(dev), &uuid_list); + uuid_list = nvme_alloc(sizeof(*uuid_list)); + if (!uuid_list) + return -ENOMEM; + + err = nvme_identify_uuid(dev_fd(dev), uuid_list); if (!err) - nvme_show_id_uuid_list(&uuid_list, flags); + nvme_show_id_uuid_list(uuid_list, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify UUID list: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: - return err;; + nvme_show_error("identify UUID list: %s", nvme_strerror(errno)); + + return err; } static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Command Set Data command to the "\ - "given device, returns properties of the specified controller "\ + const char *desc = "Send an Identify Command Set Data command to " + "the given device, returns properties of the specified controller " "in either human-readable or binary format."; const char *controller_id = "identifier of desired controller"; - struct nvme_id_iocs iocs; - struct nvme_dev *dev; + + _cleanup_free_ struct nvme_id_iocs *iocs = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -3473,127 +3931,125 @@ static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *pl .cntid = 0xffff, }; - OPT_ARGS(opts) = { - OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + iocs = nvme_alloc(sizeof(*iocs)); + if (!iocs) + return -ENOMEM; - err = nvme_identify_iocs(dev_fd(dev), cfg.cntid, &iocs); + err = nvme_identify_iocs(dev_fd(dev), cfg.cntid, iocs); if (!err) { printf("NVMe Identify I/O Command Set:\n"); - nvme_show_id_iocs(&iocs); - } else if (err > 0) + nvme_show_id_iocs(iocs, 0); + } else if (err > 0) { nvme_show_status(err); - else - fprintf(stderr, "NVMe Identify I/O Command Set: %s\n", nvme_strerror(errno)); + } else { + nvme_show_error("NVMe Identify I/O Command Set: %s", nvme_strerror(errno)); + } - dev_close(dev); -ret: return err; } -static int id_domain(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an Identify Domain List command to the "\ - "given device, returns properties of the specified domain "\ +static int id_domain(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Send an Identify Domain List command to the " + "given device, returns properties of the specified domain " "in either normal|json|binary format."; const char *domain_id = "identifier of desired domain"; - struct nvme_id_domain_list id_domain; + + _cleanup_free_ struct nvme_id_domain_list *id_domain = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u16 dom_id; - char *output_format; }; struct config cfg = { .dom_id = 0xffff, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_SHRT("dom-id", 'd', &cfg.dom_id, domain_id), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_SHRT("dom-id", 'd', &cfg.dom_id, domain_id)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + id_domain = nvme_alloc(sizeof(*id_domain)); + if (!id_domain) + return -ENOMEM; - err = nvme_identify_domain_list(dev_fd(dev), cfg.dom_id, &id_domain); + err = nvme_identify_domain_list(dev_fd(dev), cfg.dom_id, id_domain); if (!err) { printf("NVMe Identify command for Domain List is successful:\n"); printf("NVMe Identify Domain List:\n"); - nvme_show_id_domain_list(&id_domain, flags); - } else if (err > 0) + nvme_show_id_domain_list(id_domain, flags); + } else if (err > 0) { nvme_show_status(err); - else - fprintf(stderr, "NVMe Identify Domain List: %s\n", nvme_strerror(errno)); + } else { + nvme_show_error("NVMe Identify Domain List: %s", nvme_strerror(errno)); + } -close_dev: - dev_close(dev); -ret: return err; } static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Get namespace ID of a the block device."; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; unsigned int nsid; - int err = 0; + int err; - OPT_ARGS(opts) = { - OPT_END() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; err = nvme_get_nsid(dev_fd(dev), &nsid); if (err < 0) { - fprintf(stderr, "get namespace ID: %s\n", nvme_strerror(errno)); - err = errno; - goto close_fd; + nvme_show_error("get namespace ID: %s", nvme_strerror(errno)); + return -errno; } - err = 0; + printf("%s: namespace-id:%d\n", dev->name, nsid); -close_fd: - dev_close(dev); -ret: - return err; + return 0; } static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "The Virtualization Management command is supported by primary controllers "\ - "that support the Virtualization Enhancements capability. This command is used for:\n"\ - " 1. Modifying Flexible Resource allocation for the primary controller\n"\ - " 2. Assigning Flexible Resources for secondary controllers\n"\ + 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"\ + 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"\ + 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)"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; __u32 result; int err; @@ -3611,17 +4067,15 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi .nr = 0, }; - OPT_ARGS(opts) = { - OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid), - OPT_BYTE("rt", 'r', &cfg.rt, rt), - OPT_BYTE("act", 'a', &cfg.act, act), - OPT_SHRT("nr", 'n', &cfg.nr, nr), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid), + OPT_BYTE("rt", 'r', &cfg.rt, rt), + OPT_BYTE("act", 'a', &cfg.act, act), + OPT_SHRT("nr", 'n', &cfg.nr, nr)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; struct nvme_virtual_mgmt_args args = { .args_size = sizeof(args), @@ -3634,178 +4088,296 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi .result = &result, }; err = nvme_virtual_mgmt(&args); - if (!err) { - printf("success, Number of Controller Resources Modified "\ - "(NRM):%#x\n", result); - } else if (err > 0) { + if (!err) + printf("success, Number of Controller Resources Modified (NRM):%#x\n", result); + else if (err > 0) nvme_show_status(err); - } else - fprintf(stderr, "virt-mgmt: %s\n", nvme_strerror(errno)); + else + nvme_show_error("virt-mgmt: %s", nvme_strerror(errno)); - dev_close(dev); -ret: return err; } static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *cntlid = "Controller ID"; - const char *desc = "Send an Identify Primary Controller Capabilities "\ - "command to the given device and report the information in a "\ + const char *desc = "Send an Identify Primary Controller Capabilities " + "command to the given device and report the information in a " "decoded format (default), json or binary."; - const char *human_readable = "show info in readable format"; - struct nvme_primary_ctrl_cap caps; + + _cleanup_free_ struct nvme_primary_ctrl_cap *caps = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u16 cntlid; - char *output_format; bool human_readable; }; struct config cfg = { .cntlid = 0, - .output_format = "normal", .human_readable = false, }; - OPT_ARGS(opts) = { - OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.human_readable) flags |= VERBOSE; - err = nvme_identify_primary_ctrl(dev_fd(dev), cfg.cntlid, &caps); + caps = nvme_alloc(sizeof(*caps)); + if (!caps) + return -ENOMEM; + + err = nvme_cli_identify_primary_ctrl(dev, cfg.cntlid, caps); if (!err) - nvme_show_primary_ctrl_cap(&caps, flags); + nvme_show_primary_ctrl_cap(caps, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "identify primary controller capabilities: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("identify primary controller capabilities: %s", + nvme_strerror(errno)); + return err; } static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Show secondary controller list associated with the primary controller "\ - "of the given device."; + const char *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_ctrl_list *sc_list; + _cleanup_free_ struct nvme_secondary_ctrl_list *sc_list = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u16 cntid; - __u32 namespace_id; __u32 num_entries; - char *output_format; }; struct config cfg = { .cntid = 0, - .namespace_id = 0, .num_entries = ARRAY_SIZE(sc_list->sc_entry), - .output_format = "normal", }; - 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() - }; + NVME_ARGS(opts, + OPT_SHRT("cntid", 'c', &cfg.cntid, controller), + OPT_UINT("num-entries", 'e', &cfg.num_entries, num_entries)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_err; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } if (!cfg.num_entries) { - fprintf(stderr, "non-zero num-entries is required param\n"); - err = -EINVAL; - goto close_err; + nvme_show_error("non-zero num-entries is required param"); + return -EINVAL; } - if (posix_memalign((void *)&sc_list, getpagesize(), sizeof(*sc_list))) { - fprintf(stderr, "can not allocate controller list payload\n"); - err = -ENOMEM; - goto close_err; - } + sc_list = nvme_alloc(sizeof(*sc_list)); + if (!sc_list) + return -ENOMEM; - err = nvme_identify_secondary_ctrl_list(dev_fd(dev), cfg.namespace_id, - cfg.cntid, sc_list); + err = nvme_cli_identify_secondary_ctrl_list(dev, cfg.cntid, sc_list); if (!err) nvme_show_list_secondary_ctrl(sc_list, cfg.num_entries, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "id secondary controller list: %s\n", nvme_strerror(errno)); - - free(sc_list); + nvme_show_error("id secondary controller list: %s", nvme_strerror(errno)); -close_err: - dev_close(dev); -ret: return err; } +static void intr_self_test(int signum) +{ + printf("\nInterrupted device self-test operation by %s\n", strsignal(signum)); + + errno = EINTR; +} + +static int sleep_self_test(unsigned int seconds) +{ + errno = 0; + + sleep(seconds); + + if (errno) + return -errno; + + return 0; +} + +static int wait_self_test(struct nvme_dev *dev) +{ + static const char spin[] = {'-', '\\', '|', '/' }; + _cleanup_free_ struct nvme_self_test_log *log = NULL; + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + int err, i = 0, p = 0, cnt = 0; + int wthr; + + signal(SIGINT, intr_self_test); + + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + log = nvme_alloc(sizeof(*log)); + if (!log) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); + if (err) { + nvme_show_error("identify-ctrl: %s", nvme_strerror(errno)); + return err; + } + + wthr = le16_to_cpu(ctrl->edstt) * 60 / 100 + 60; + + printf("Waiting for self test completion...\n"); + while (true) { + printf("\r[%.*s%c%.*s] %3d%%", p / 2, dash, spin[i % 4], 49 - p / 2, space, p); + fflush(stdout); + err = sleep_self_test(1); + if (err) + return err; + + err = nvme_cli_get_log_device_self_test(dev, log); + if (err) { + printf("\n"); + if (err < 0) + perror("self test log\n"); + else + nvme_show_status(err); + return err; + } + + if (++cnt > wthr) { + nvme_show_error("no progress for %d seconds, stop waiting", wthr); + return -EIO; + } + + if (log->completion == 0 && p > 0) { + printf("\r[%.*s] %3d%%\n", 50, dash, 100); + break; + } + + if (log->completion < p) { + printf("\n"); + nvme_show_error("progress broken"); + return -EIO; + } else if (log->completion != p) { + p = log->completion; + cnt = 0; + } + + i++; + } + + return 0; +} + +static void abort_self_test(struct nvme_dev_self_test_args *args) +{ + int err; + + args->stc = NVME_DST_STC_ABORT; + + err = nvme_dev_self_test(args); + if (!err) + printf("Aborting device self-test operation\n"); + else if (err > 0) + nvme_show_status(err); + else + nvme_show_error("Device self-test: %s", nvme_strerror(errno)); +} + static int device_self_test(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Implementing the device self-test feature"\ - " which provides the necessary log to determine the state of the device"; - const char *namespace_id = "Indicate the namespace in which the device self-test"\ - " has to be carried out"; - const char * self_test_code = "This field specifies the action taken by the device self-test command : "\ - "\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"; - struct nvme_dev *dev; + const char *desc = "Implementing the device self-test feature " + "which provides the necessary log to determine the state of the device"; + const char *namespace_id = + "Indicate the namespace in which the device self-test has to be carried out"; + const char *self_test_code = + "This field specifies the action taken by the device self-test command :\n" + "0h Show current state of device self-test operation\n" + "1h Start a short device self-test operation\n" + "2h Start a extended device self-test operation\n" + "eh Start a vendor specific device self-test operation\n" + "fh Abort the device self-test operation"; + const char *wait = "Wait for the test to finish"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { __u32 namespace_id; __u8 stc; + bool wait; }; struct config cfg = { .namespace_id = NVME_NSID_ALL, - .stc = 0, + .stc = NVME_ST_CODE_RESERVED, + .wait = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_BYTE("self-test-code", 's', &cfg.stc, self_test_code), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_BYTE("self-test-code", 's', &cfg.stc, self_test_code), + OPT_FLAG("wait", 'w', &cfg.wait, wait)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + if (cfg.stc == NVME_ST_CODE_RESERVED) { + _cleanup_free_ struct nvme_self_test_log *log = NULL; + + log = nvme_alloc(sizeof(*log)); + if (!log) + return -ENOMEM; + + err = nvme_cli_get_log_device_self_test(dev, log); + if (err) { + printf("\n"); + if (err < 0) + perror("self test log\n"); + else + nvme_show_status(err); + } + + if (log->completion == 0) { + printf("no self test running\n"); + } else { + if (cfg.wait) + err = wait_self_test(dev); + else + printf("progress %d%%\n", log->completion); + } + + goto check_abort; + } struct nvme_dev_self_test_args args = { .args_size = sizeof(args), @@ -3817,76 +4389,76 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p }; err = nvme_dev_self_test(&args); if (!err) { - if (cfg.stc == 0xf) + if (cfg.stc == NVME_ST_CODE_ABORT) printf("Aborting device self-test operation\n"); - else if (cfg.stc == 0x2) + else if (cfg.stc == NVME_ST_CODE_EXTENDED) printf("Extended Device self-test started\n"); - else if (cfg.stc == 0x1) + else if (cfg.stc == NVME_ST_CODE_SHORT) printf("Short Device self-test started\n"); + + if (cfg.wait && cfg.stc != NVME_ST_CODE_ABORT) + err = wait_self_test(dev); } else if (err > 0) { nvme_show_status(err); - } else - fprintf(stderr, "Device self-test: %s\n", nvme_strerror(errno)); + } else { + nvme_show_error("Device self-test: %s", nvme_strerror(errno)); + } + +check_abort: + if (err == -EINTR) + abort_self_test(&args); - dev_close(dev); -ret: return err; } static int self_test_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve the self-test log for the given device and given test "\ - "(or optionally a namespace) in either decoded format "\ - "(default) or binary."; - const char *dst_entries = "Indicate how many DST log entries to be retrieved, "\ - "by default all the 20 entries will be retrieved"; - const char *verbose = "Increase output verbosity"; + const char *desc = "Retrieve the self-test log for the given device and given test " + "(or optionally a namespace) in either decoded format (default) or binary."; + const char *dst_entries = "Indicate how many DST log entries to be retrieved, " + "by default all the 20 entries will be retrieved"; - struct nvme_self_test_log log; + _cleanup_free_ struct nvme_self_test_log *log = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err; struct config { __u8 dst_entries; - char *output_format; - bool verbose; }; struct config cfg = { .dst_entries = NVME_LOG_ST_MAX_RESULTS, - .output_format = "normal", - .verbose = false, }; - OPT_ARGS(opts) = { - OPT_BYTE("dst-entries", 'e', &cfg.dst_entries, dst_entries), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("dst-entries", 'e', &cfg.dst_entries, dst_entries)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; - if (cfg.verbose) + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + if (argconfig_parse_seen(opts, "verbose")) flags |= VERBOSE; - err = nvme_cli_get_log_device_self_test(dev, &log); + log = nvme_alloc(sizeof(*log)); + if (!log) + return -ENOMEM; + + err = nvme_cli_get_log_device_self_test(dev, log); if (!err) - nvme_show_self_test_log(&log, cfg.dst_entries, 0, - dev->name, flags); + nvme_show_self_test_log(log, cfg.dst_entries, 0, dev->name, flags); else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "self test log: %s\n", nvme_strerror(errno)); -close_dev: - dev_close(dev); -ret: + nvme_show_error("self test log: %s", nvme_strerror(errno)); + return err; } @@ -3901,14 +4473,18 @@ static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg, if (cfg->feature_id == NVME_FEAT_FID_HOST_ID && (cfg->cdw11 & 0x1)) cfg->data_len = 16; + if (cfg->feature_id == NVME_FEAT_FID_FDP_EVENTS) { + cfg->data_len = 0xff * sizeof(__u16); + cfg->cdw11 |= 0xff << 16; + } + if (cfg->sel == 3) cfg->data_len = 0; if (cfg->data_len) { - if (posix_memalign(buf, getpagesize(), cfg->data_len)) { + *buf = nvme_alloc(cfg->data_len - 1); + if (!*buf) return -1; - } - memset(*buf, 0, cfg->data_len); } struct nvme_get_features_args args = { @@ -3926,18 +4502,23 @@ static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg, return nvme_cli_get_features(dev, &args); } +static int filter_out_flags(int status) +{ + return status & (NVME_GET(NVME_SCT_MASK, SCT) | + NVME_GET(NVME_SC_MASK, SC)); +} + static void get_feature_id_print(struct feat_cfg cfg, int err, __u32 result, void *buf) { + int status = filter_out_flags(err); + enum nvme_status_type type = NVME_STATUS_TYPE_NVME; + if (!err) { if (!cfg.raw_binary || !buf) { - printf("get-feature:%#0*x (%s), %s value:%#0*x\n", - cfg.feature_id ? 4 : 2, cfg.feature_id, - nvme_feature_to_string(cfg.feature_id), - nvme_select_to_string(cfg.sel), result ? 10 : 8, - result); + nvme_feature_show(cfg.feature_id, cfg.sel, result); if (cfg.sel == 3) - nvme_show_select_result(result); + nvme_show_select_result(cfg.feature_id, result); else if (cfg.human_readable) nvme_feature_show_fields(cfg.feature_id, result, buf); @@ -3947,10 +4528,11 @@ static void get_feature_id_print(struct feat_cfg cfg, int err, __u32 result, d_raw(buf, cfg.data_len); } } else if (err > 0) { - if (err != NVME_SC_INVALID_FIELD) + if (!nvme_status_equals(status, type, NVME_SC_INVALID_FIELD) && + !nvme_status_equals(status, type, NVME_SC_INVALID_NS)) nvme_show_status(err); } else { - fprintf(stderr, "get-feature: %s\n", nvme_strerror(errno)); + nvme_show_error("get-feature: %s", nvme_strerror(errno)); } } @@ -3994,6 +4576,8 @@ static int get_feature_ids(struct nvme_dev *dev, struct feat_cfg cfg) int feat_max = 0x100; int feat_num = 0; bool changed = false; + int status = 0; + enum nvme_status_type type = NVME_STATUS_TYPE_NVME; if (cfg.sel == 8) changed = true; @@ -4004,11 +4588,18 @@ static int get_feature_ids(struct nvme_dev *dev, struct feat_cfg cfg) for (i = cfg.feature_id; i < feat_max; i++, feat_num++) { cfg.feature_id = i; err = get_feature_id_changed(dev, cfg, changed); - if (err && err != NVME_SC_INVALID_FIELD) + if (!err) + continue; + status = filter_out_flags(err); + if (nvme_status_equals(status, type, NVME_SC_INVALID_FIELD)) + continue; + if (!nvme_status_equals(status, type, NVME_SC_INVALID_NS)) break; + nvme_show_error_status(err, "get-feature:%#0*x (%s)", cfg.feature_id ? 4 : 2, + cfg.feature_id, nvme_feature_to_string(cfg.feature_id)); } - if (err == NVME_SC_INVALID_FIELD && feat_num == 1) + if (feat_num == 1 && nvme_status_equals(status, type, NVME_SC_INVALID_FIELD)) nvme_show_status(err); return err; @@ -4017,24 +4608,22 @@ static int get_feature_ids(struct nvme_dev *dev, struct feat_cfg cfg) static int get_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Read operating parameters of the "\ - "specified controller. Operating parameters are grouped "\ - "and identified by Feature Identifiers; each Feature "\ - "Identifier contains one or more attributes that may affect "\ - "behavior of the feature. Each Feature has three possible "\ - "settings: default, saveable, and current. If a Feature is "\ - "saveable, it may be modified by set-feature. Default values "\ - "are vendor-specific and not changeable. Use set-feature to "\ + const char *desc = "Read operating parameters of the " + "specified controller. Operating parameters are grouped " + "and identified by Feature Identifiers; each Feature " + "Identifier contains one or more attributes that may affect " + "behavior of the feature. Each Feature has three possible " + "settings: default, saveable, and current. If a Feature is " + "saveable, it may be modified by set-feature. Default values " + "are vendor-specific and not changeable. Use set-feature to " "change saveable Features."; const char *raw = "show feature in binary format"; const char *feature_id = "feature identifier"; - const char *namespace_id = "identifier of desired namespace"; const char *sel = "[0-3,8]: current/default/saved/supported/changed"; - 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 *cdw11 = "feature specific dword 11"; const char *human_readable = "show feature in readable format"; - const char *uuid_index = "specify uuid index"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct feat_cfg cfg = { @@ -4048,197 +4637,322 @@ static int get_feature(int argc, char **argv, struct command *cmd, .human_readable = false, }; - OPT_ARGS(opts) = { - OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_BYTE("sel", 's', &cfg.sel, sel), - OPT_UINT("data-len", 'l', &cfg.data_len, data_len), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11), - OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), - OPT_END() + NVME_ARGS(opts, + OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_BYTE("sel", 's', &cfg.sel, sel), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index_specify), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (!argconfig_parse_seen(opts, "namespace-id")) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + if (errno != ENOTTY) { + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; + } + cfg.namespace_id = NVME_NSID_ALL; + } + } + + if (cfg.sel > 8) { + nvme_show_error("invalid 'select' param:%d", cfg.sel); + return -EINVAL; + } + + if (cfg.uuid_index > 127) { + nvme_show_error("invalid uuid index param: %u", cfg.uuid_index); + return -1; + } + + nvme_show_init(); + + err = get_feature_ids(dev, cfg); + + nvme_show_finish(); + + return err; +} + +/* + * Transfers one chunk of firmware to the device, and decodes & reports any + * errors. Returns -1 on (fatal) error; signifying that the transfer should + * be aborted. + */ +static int fw_download_single(struct nvme_dev *dev, void *fw_buf, + unsigned int fw_len, uint32_t offset, + uint32_t len, bool progress, bool ignore_ovr) +{ + const unsigned int max_retries = 3; + bool retryable, ovr; + int err, try; + + if (progress) { + printf("Firmware download: transferring 0x%08x/0x%08x bytes: %03d%%\r", + offset, fw_len, (int)(100 * offset / fw_len)); + } + + struct nvme_fw_download_args args = { + .args_size = sizeof(args), + .offset = offset, + .data_len = len, + .data = fw_buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, }; - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - goto ret; + for (try = 0; try < max_retries; try++) { + if (try > 0) { + fprintf(stderr, "retrying offset %x (%u/%u)\n", + offset, try, max_retries); + } - if (!cfg.namespace_id) { - err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); - if (err < 0) { - if (errno != ENOTTY) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; - } - cfg.namespace_id = NVME_NSID_ALL; + err = nvme_cli_fw_download(dev, &args); + if (!err) + return 0; + + /* + * don't retry if the NVMe-type error indicates Do Not Resend. + */ + retryable = !((err > 0) && + (nvme_status_get_type(err) == NVME_STATUS_TYPE_NVME) && + (nvme_status_get_value(err) & NVME_SC_DNR)); + + /* + * detect overwrite errors, which are handled differently + * depending on ignore_ovr + */ + ovr = (err > 0) && + (nvme_status_get_type(err) == NVME_STATUS_TYPE_NVME) && + (NVME_GET(err, SCT) == NVME_SCT_CMD_SPECIFIC) && + (NVME_GET(err, SC) == NVME_SC_OVERLAPPING_RANGE); + + if (ovr && ignore_ovr) + return 0; + + /* + * if we're printing progress, we'll need a newline to separate + * error output from the progress data (which doesn't have a + * \n), and flush before we write to stderr. + */ + if (progress) { + printf("\n"); + fflush(stdout); } - } - if (cfg.sel > 8) { - fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel); - err = -EINVAL; - goto close_dev; - } + fprintf(stderr, "fw-download: error on offset 0x%08x/0x%08x\n", + offset, fw_len); - if (cfg.uuid_index > 128) { - fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index); - err = -1; - goto close_dev; - } + if (err < 0) { + fprintf(stderr, "fw-download: %s\n", nvme_strerror(errno)); + } else { + nvme_show_status(err); + if (ovr) { + /* + * non-ignored ovr error: print a little extra info + * about recovering + */ + fprintf(stderr, + "Use --ignore-ovr to ignore overwrite errors\n"); - err = get_feature_ids(dev, cfg); + /* + * We'll just be attempting more overwrites if + * we retry. DNR will likely be set, but force + * an exit anyway. + */ + retryable = false; + } + } -close_dev: - dev_close(dev); + if (!retryable) + break; + } -ret: - return err; + return -1; } static int fw_download(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Copy all or part of a firmware image to "\ - "a controller for future update. Optionally, specify how "\ - "many KiB of the firmware to transfer at once. The offset will "\ - "start at 0 and automatically adjust based on xfer size "\ - "unless fw is split across multiple files. May be submitted "\ - "while outstanding commands exist on the Admin and IO "\ - "Submission Queues. Activate downloaded firmware with "\ + 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"; - unsigned int fw_size; - struct nvme_dev *dev; - void *fw_buf, *buf; - int err, fw_fd = -1; + const char *progress = "display firmware transfer progress"; + const char *ignore_ovr = "ignore overwrite errors"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + _cleanup_file_ int fw_fd = -1; + unsigned int fw_size, pos; + int err; struct stat sb; - bool huge; + void *fw_buf; + struct nvme_id_ctrl ctrl; struct config { char *fw; __u32 xfer; __u32 offset; + bool progress; + bool ignore_ovr; }; struct config cfg = { - .fw = "", - .xfer = 4096, - .offset = 0, + .fw = "", + .xfer = 4096, + .offset = 0, + .progress = false, + .ignore_ovr = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_FILE("fw", 'f', &cfg.fw, fw), + OPT_UINT("xfer", 'x', &cfg.xfer, xfer), + OPT_UINT("offset", 'O', &cfg.offset, offset), + OPT_FLAG("progress", 'p', &cfg.progress, progress), + OPT_FLAG("ignore-ovr", 'i', &cfg.ignore_ovr, ignore_ovr)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; 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_dev; + nvme_show_error("Failed to open firmware file %s: %s", cfg.fw, strerror(errno)); + return -EINVAL; } err = fstat(fw_fd, &sb); if (err < 0) { - perror("fstat"); - goto close_fw_fd; + nvme_show_perror("fstat"); + return err; } fw_size = sb.st_size; if ((fw_size & 0x3) || (fw_size == 0)) { - fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size); - err = -EINVAL; - goto close_fw_fd; + nvme_show_error("Invalid size:%d for f/w image", fw_size); + return -EINVAL; } - if (cfg.xfer == 0 || cfg.xfer % 4096) + if (cfg.xfer == 0) { + err = nvme_cli_identify_ctrl(dev, &ctrl); + if (err) { + nvme_show_error("identify-ctrl: %s", nvme_strerror(errno)); + return err; + } + if (ctrl.fwug == 0 || ctrl.fwug == 0xff) + cfg.xfer = 4096; + else + cfg.xfer = ctrl.fwug * 4096; + } else if (cfg.xfer % 4096) cfg.xfer = 4096; - if (cfg.xfer < HUGE_MIN) - fw_buf = __nvme_alloc(fw_size, &huge); - else - fw_buf = nvme_alloc(fw_size, &huge); - - if (!fw_buf) { - err = -ENOMEM; - goto close_fw_fd; - } + fw_buf = nvme_alloc_huge(fw_size, &mh); + if (!fw_buf) + return -ENOMEM; - buf = fw_buf; 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; + nvme_show_error("read :%s :%s", cfg.fw, strerror(errno)); + return err; } - while (fw_size > 0) { - cfg.xfer = min(cfg.xfer, fw_size); + for (pos = 0; pos < fw_size; pos += cfg.xfer) { + cfg.xfer = min(cfg.xfer, fw_size - pos); - struct nvme_fw_download_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .offset = cfg.offset, - .data_len = cfg.xfer, - .data = fw_buf, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - err = nvme_fw_download(&args); - if (err < 0) { - fprintf(stderr, "fw-download: %s\n", nvme_strerror(errno)); - break; - } else if (err != 0) { - nvme_show_status(err); + err = fw_download_single(dev, fw_buf + pos, fw_size, + cfg.offset + pos, cfg.xfer, + cfg.progress, cfg.ignore_ovr); + if (err) break; - } - fw_buf += cfg.xfer; - fw_size -= cfg.xfer; - cfg.offset += cfg.xfer; } - if (!err) + + if (!err) { + /* end the progress output */ + if (cfg.progress) + printf("\n"); printf("Firmware download success\n"); + } -free: - nvme_free(buf, huge); -close_fw_fd: - close(fw_fd); -close_dev: - dev_close(dev); -ret: return err; } static char *nvme_fw_status_reset_type(__u16 status) { switch (status & 0x7ff) { - case NVME_SC_FW_NEEDS_CONV_RESET: return "conventional"; - case NVME_SC_FW_NEEDS_SUBSYS_RESET: return "subsystem"; - case NVME_SC_FW_NEEDS_RESET: return "any controller"; - default: return "unknown"; + case NVME_SC_FW_NEEDS_CONV_RESET: + return "conventional"; + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + return "subsystem"; + case NVME_SC_FW_NEEDS_RESET: + return "any controller"; + default: + return "unknown"; } } +static bool fw_commit_support_mud(struct nvme_dev *dev) +{ + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + int err; + + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return false; + + err = nvme_cli_identify_ctrl(dev, ctrl); + + if (err) + nvme_show_error("identify-ctrl: %s", nvme_strerror(errno)); + else if (ctrl->frmw >> 5 & 0x1) + return true; + + return false; +} + +static void fw_commit_print_mud(struct nvme_dev *dev, __u32 result) +{ + if (!fw_commit_support_mud(dev)) + return; + + printf("Multiple Update Detected (MUD) Value: %u\n", result); + + if (result & 0x1) + printf("Detected an overlapping firmware/boot partition image update command\n" + "sequence due to processing a command from a Management Endpoint"); + + if (result >> 1 & 0x1) + printf("Detected an overlapping firmware/boot partition image update command\n" + "sequence due to processing a command from an Admin SQ on a controller"); +} + static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Verify downloaded firmware image and "\ - "commit to specific firmware slot. Device is not automatically "\ - "reset following firmware activation. A reset may be issued "\ - "with an 'echo 1 > /sys/class/nvme/nvmeX/reset_controller'. "\ + 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)"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; __u32 result; int err; @@ -4254,168 +4968,150 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin * .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() - }; + NVME_ARGS(opts, + OPT_BYTE("slot", 's', &cfg.slot, slot), + OPT_BYTE("action", 'a', &cfg.action, action), + OPT_BYTE("bpid", 'b', &cfg.bpid, bpid)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.slot > 7) { - fprintf(stderr, "invalid slot:%d\n", cfg.slot); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid slot:%d", cfg.slot); + return -EINVAL; } if (cfg.action > 7 || cfg.action == 4 || cfg.action == 5) { - fprintf(stderr, "invalid action:%d\n", cfg.action); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid action:%d", cfg.action); + return -EINVAL; } if (cfg.bpid > 1) { - fprintf(stderr, "invalid boot partition id:%d\n", cfg.bpid); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid boot partition id:%d", cfg.bpid); + return -EINVAL; } struct nvme_fw_commit_args args = { .args_size = sizeof(args), - .fd = dev_fd(dev), .slot = cfg.slot, .action = cfg.action, .bpid = cfg.bpid, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = &result, }; - err = nvme_fw_commit(&args); - if (err < 0) - fprintf(stderr, "fw-commit: %s\n", nvme_strerror(errno)); - else if (err != 0) - switch (err & 0x7ff) { - case NVME_SC_FW_NEEDS_CONV_RESET: - case NVME_SC_FW_NEEDS_SUBSYS_RESET: - case NVME_SC_FW_NEEDS_RESET: - printf("Success activating firmware action:%d slot:%d", - cfg.action, cfg.slot); - if (cfg.action == 6 || cfg.action == 7) - printf(" bpid:%d", cfg.bpid); - printf(", but firmware requires %s reset\n", nvme_fw_status_reset_type(err)); - break; - default: + err = nvme_cli_fw_commit(dev, &args); + + if (err < 0) { + nvme_show_error("fw-commit: %s", nvme_strerror(errno)); + } else if (err != 0) { + __u32 val = nvme_status_get_value(err); + int type = nvme_status_get_type(err); + + if (type == NVME_STATUS_TYPE_NVME) { + switch (val & 0x7ff) { + case NVME_SC_FW_NEEDS_CONV_RESET: + case NVME_SC_FW_NEEDS_SUBSYS_RESET: + case NVME_SC_FW_NEEDS_RESET: + printf("Success activating firmware action:%d slot:%d", + cfg.action, cfg.slot); + if (cfg.action == 6 || cfg.action == 7) + printf(" bpid:%d", cfg.bpid); + printf(", but firmware requires %s reset\n", + nvme_fw_status_reset_type(val)); + break; + default: + nvme_show_status(err); + break; + } + } else { nvme_show_status(err); - break; } - else { + } else { printf("Success committing firmware action:%d slot:%d", cfg.action, cfg.slot); if (cfg.action == 6 || cfg.action == 7) printf(" bpid:%d", cfg.bpid); printf("\n"); + fw_commit_print_mud(dev, result); } - if (err >= 0) { - printf("Multiple Update Detected (MUD) Value: %u\n", result); - if (result & 0x1) - printf("Detected an overlapping firmware/boot partition image update command "\ - "sequence due to processing a command from a Management Endpoint"); - if ((result >> 1) & 0x1) - printf("Detected an overlapping firmware/boot partition image update command "\ - "sequence due to processing a command from an Admin SQ on a controller"); - } - -close_dev: - dev_close(dev); -ret: return err; } static int subsystem_reset(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Resets the NVMe subsystem\n"; - struct nvme_dev *dev; + const char *desc = "Resets the NVMe subsystem"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; - OPT_ARGS(opts) = { - OPT_END() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; err = nvme_subsystem_reset(dev_fd(dev)); if (err < 0) { if (errno == ENOTTY) - fprintf(stderr, - "Subsystem-reset: NVM Subsystem Reset not supported.\n"); + nvme_show_error("Subsystem-reset: NVM Subsystem Reset not supported."); else - fprintf(stderr, "Subsystem-reset: %s\n", nvme_strerror(errno)); + nvme_show_error("Subsystem-reset: %s", nvme_strerror(errno)); } - dev_close(dev); -ret: return err; } static int reset(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Resets the NVMe controller\n"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; - OPT_ARGS(opts) = { - OPT_END() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; err = nvme_ctrl_reset(dev_fd(dev)); if (err < 0) - fprintf(stderr, "Reset: %s\n", nvme_strerror(errno)); + nvme_show_error("Reset: %s", nvme_strerror(errno)); - dev_close(dev); -ret: return err; } static int ns_rescan(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Rescans the NVMe namespaces\n"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; - OPT_ARGS(opts) = { - OPT_END() - }; + NVME_ARGS(opts); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; err = nvme_ns_rescan(dev_fd(dev)); if (err < 0) - fprintf(stderr, "Namespace Rescan"); + nvme_show_error("Namespace Rescan"); - dev_close(dev); -ret: return err; } -static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int sanitize_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Send a sanitize command."; const char *no_dealloc_desc = "No deallocate after sanitize."; const char *oipbp_desc = "Overwrite invert pattern between passes."; const char *owpass_desc = "Overwrite pass count."; const char *ause_desc = "Allow unrestricted sanitize exit."; - const char *sanact_desc = "Sanitize action."; + const char *sanact_desc = "Sanitize action: 1 = Exit failure mode, 2 = Start block erase, 3 = Start overwrite, 4 = Start crypto erase"; const char *ovrpat_desc = "Overwrite pattern."; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -4436,19 +5132,25 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p .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() + OPT_VALS(sanact) = { + VAL_BYTE("exit-failure", NVME_SANITIZE_SANACT_EXIT_FAILURE), + VAL_BYTE("start-block-erase", NVME_SANITIZE_SANACT_START_BLOCK_ERASE), + VAL_BYTE("start-overwrite", NVME_SANITIZE_SANACT_START_OVERWRITE), + VAL_BYTE("start-crypto-erase", NVME_SANITIZE_SANACT_START_CRYPTO_ERASE), + VAL_END() }; + NVME_ARGS(opts, + OPT_FLAG("no-dealloc", 'd', &cfg.no_dealloc, no_dealloc_desc), + OPT_FLAG("oipbp", 'i', &cfg.oipbp, oipbp_desc), + OPT_BYTE("owpass", 'n', &cfg.owpass, owpass_desc), + OPT_FLAG("ause", 'u', &cfg.ause, ause_desc), + OPT_BYTE("sanact", 'a', &cfg.sanact, sanact_desc, sanact), + OPT_UINT("ovrpat", 'p', &cfg.ovrpat, ovrpat_desc)); + err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; switch (cfg.sanact) { case NVME_SANITIZE_SANACT_EXIT_FAILURE: @@ -4457,30 +5159,26 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p case NVME_SANITIZE_SANACT_START_CRYPTO_ERASE: break; default: - fprintf(stderr, "Invalid Sanitize Action\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("Invalid Sanitize Action"); + return -EINVAL; } if (cfg.sanact == NVME_SANITIZE_SANACT_EXIT_FAILURE) { - if (cfg.ause || cfg.no_dealloc) { - fprintf(stderr, "SANACT is Exit Failure Mode\n"); - err = -EINVAL; - goto close_dev; - } + if (cfg.ause || cfg.no_dealloc) { + nvme_show_error("SANACT is Exit Failure Mode"); + return -EINVAL; + } } if (cfg.sanact == NVME_SANITIZE_SANACT_START_OVERWRITE) { - if (cfg.owpass > 16) { - fprintf(stderr, "OWPASS out of range [0-16]\n"); - err = -EINVAL; - goto close_dev; + if (cfg.owpass > 15) { + nvme_show_error("OWPASS out of range [0-15]"); + return -EINVAL; } } else { if (cfg.owpass || cfg.oipbp || cfg.ovrpat) { - fprintf(stderr, "SANACT is not Overwrite\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("SANACT is not Overwrite"); + return -EINVAL; } } @@ -4496,13 +5194,10 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p }; err = nvme_cli_sanitize_nvm(dev, &args); if (err < 0) - fprintf(stderr, "sanitize: %s\n", nvme_strerror(errno)); + nvme_show_error("sanitize: %s", nvme_strerror(errno)); else if (err > 0) nvme_show_status(err); -close_dev: - dev_close(dev); -ret: return err; } @@ -4510,14 +5205,14 @@ static int nvme_get_properties(int fd, void **pbar) { int offset, err, size = getpagesize(); __u64 value; + void *bar = malloc(size); - *pbar = malloc(size); - if (!*pbar) { - fprintf(stderr, "malloc: %s\n", strerror(errno)); + if (!bar) { + nvme_show_error("malloc: %s", strerror(errno)); return -1; } - memset(*pbar, 0xff, size); + memset(bar, 0xff, size); for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ;) { struct nvme_get_property_args args = { .args_size = sizeof(args), @@ -4526,23 +5221,29 @@ static int nvme_get_properties(int fd, void **pbar) .value = &value, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, }; + err = nvme_get_property(&args); - if (err > 0 && (err & 0xff) == NVME_SC_INVALID_FIELD) { + if (nvme_status_equals(err, NVME_STATUS_TYPE_NVME, NVME_SC_INVALID_FIELD)) { err = 0; value = -1; } else if (err) { - free(*pbar); + nvme_show_error("get-property: %s", nvme_strerror(errno)); break; } if (nvme_is_64bit_reg(offset)) { - *(uint64_t *)(*pbar + offset) = value; + *(uint64_t *)(bar + offset) = value; offset += 8; } else { - *(uint32_t *)(*pbar + offset) = value; + *(uint32_t *)(bar + offset) = value; offset += 4; } } + if (err) + free(bar); + else + *pbar = bar; + return err; } @@ -4563,25 +5264,28 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) } else { n = nvme_scan_namespace(dev->name); if (!n) { - fprintf(stderr, "Unable to find %s\n", dev->name); + nvme_show_error("Unable to find %s", dev->name); return NULL; } snprintf(path, sizeof(path), "%s/device/device/resource0", - nvme_ns_get_sysfs_dir(n)); + nvme_ns_get_sysfs_dir(n)); nvme_free_ns(n); } fd = open(path, O_RDONLY); if (fd < 0) { - fprintf(stderr, "%s did not find a pci resource, open failed %s\n", - dev->name, strerror(errno)); + if (log_level >= LOG_DEBUG) + nvme_show_error("%s did not find a pci resource, open failed %s", + dev->name, strerror(errno)); return NULL; } membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); if (membase == MAP_FAILED) { - fprintf(stderr, "%s failed to map. ", dev->name); - fprintf(stderr, "Did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n"); + if (log_level >= LOG_DEBUG) { + fprintf(stderr, "%s failed to map. ", dev->name); + fprintf(stderr, "Did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n"); + } membase = NULL; } @@ -4591,76 +5295,70 @@ static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev) 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"; + const char *desc = "Reads and shows the defined NVMe controller registers\n" + "in binary or human-readable format"; + const char *human_readable = + "show info in readable format in case of output_format == normal"; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; - bool fabrics = true; + bool fabrics = false; nvme_root_t r; void *bar; int err; struct config { - char *output_format; bool human_readable; }; struct config cfg = { - .output_format = "normal", .human_readable = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; r = nvme_scan(NULL); - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + goto free_tree; + } + if (cfg.human_readable) flags |= VERBOSE; - err = nvme_get_properties(dev_fd(dev), &bar); - if (err) { - bar = mmap_registers(r, dev); - fabrics = false; - if (bar) - err = 0; + bar = mmap_registers(r, dev); + if (!bar) { + err = nvme_get_properties(dev_fd(dev), &bar); + if (err) + goto free_tree; + fabrics = true; } - if (!bar) - goto close_dev; nvme_show_ctrl_registers(bar, fabrics, flags); if (fabrics) free(bar); else munmap(bar, getpagesize()); -close_dev: - dev_close(dev); +free_tree: nvme_free_tree(r); -ret: return err; } static int get_property(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Reads and shows the defined NVMe controller property "\ - "for NVMe over Fabric. Property offset must be one of:\n" - "CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20"; + const char *desc = "Reads and shows the defined NVMe controller property\n" + "for NVMe over Fabric. Property offset must be one of:\n" + "CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20, NSSD=0x64, CRTO=0x68"; const char *offset = "offset of the requested property"; const char *human_readable = "show property in readable format"; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; __u64 value; int err; @@ -4674,20 +5372,17 @@ static int get_property(int argc, char **argv, struct command *cmd, struct plugi .human_readable = false, }; - OPT_ARGS(opts) = { - OPT_UINT("offset", 'o', &cfg.offset, offset), - OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("offset", 'O', &cfg.offset, offset), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.offset == -1) { - fprintf(stderr, "offset required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("offset required param"); + return -EINVAL; } struct nvme_get_property_args args = { @@ -4698,27 +5393,24 @@ static int get_property(int argc, char **argv, struct command *cmd, struct plugi .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, }; err = nvme_get_property(&args); - if (err < 0) { - fprintf(stderr, "get-property: %s\n", nvme_strerror(errno)); - } else if (!err) { + if (err < 0) + nvme_show_error("get-property: %s", nvme_strerror(errno)); + else if (!err) nvme_show_single_property(cfg.offset, value, cfg.human_readable); - } else if (err > 0) { + else if (err > 0) nvme_show_status(err); - } -close_dev: - dev_close(dev); -ret: return err; } static int set_property(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Writes and shows the defined NVMe controller property "\ - "for NVMe over Fabric"; + const char *desc = + "Writes and shows the defined NVMe controller property for NVMe over Fabric"; const char *offset = "the offset of the property"; const char *value = "the value of the property to be set"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -4731,25 +5423,21 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi .value = -1, }; - OPT_ARGS(opts) = { - OPT_UINT("offset", 'o', &cfg.offset, offset), - OPT_UINT("value", 'v', &cfg.value, value), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("offset", 'O', &cfg.offset, offset), + OPT_UINT("value", 'V', &cfg.value, value)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.offset == -1) { - fprintf(stderr, "offset required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("offset required param"); + return -EINVAL; } if (cfg.value == -1) { - fprintf(stderr, "value required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("value required param"); + return -EINVAL; } struct nvme_set_property_args args = { @@ -4761,40 +5449,35 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi .result = NULL, }; err = nvme_set_property(&args); - if (err < 0) { - fprintf(stderr, "set-property: %s\n", nvme_strerror(errno)); - } else if (!err) { + if (err < 0) + nvme_show_error("set-property: %s", nvme_strerror(errno)); + else if (!err) printf("set-property: %02x (%s), value: %#08x\n", cfg.offset, - nvme_register_to_string(cfg.offset), cfg.value); - } else if (err > 0) { + nvme_register_to_string(cfg.offset), cfg.value); + else if (err > 0) nvme_show_status(err); - } -close_dev: - dev_close(dev); -ret: return err; } -static int format(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int format_cmd(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. "\ + const char *desc = "Re-format a specified namespace on the\n" + "given device. Can erase all data in namespace (user\n" + "data erase) or delete data encryption key if specified.\n" "Can also be used to change LBAF to change the namespaces reported physical block format."; - const char *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; - struct nvme_dev *dev; + + _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; __u8 prev_lbaf = 0; int block_size; int err, i; @@ -4825,63 +5508,60 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu .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", 0, &cfg.force, force), - OPT_SUFFIX("block-size", 'b', &cfg.bs, bs), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), + OPT_BYTE("lbaf", 'l', &cfg.lbaf, lbaf), + OPT_BYTE("ses", 's', &cfg.ses, ses), + OPT_BYTE("pi", 'i', &cfg.pi, pi), + OPT_BYTE("pil", 'p', &cfg.pil, pil), + OPT_BYTE("ms", 'm', &cfg.ms, ms), + OPT_FLAG("reset", 'r', &cfg.reset, reset), + OPT_FLAG("force", 0, &cfg.force, force), + OPT_SUFFIX("block-size", 'b', &cfg.bs, bs)); err = argconfig_parse(argc, argv, desc, opts); if (err) - goto ret; + return err; err = open_exclusive(&dev, argc, argv, cfg.force); if (err) { if (errno == EBUSY) { - fprintf(stderr, "Failed to open %s.\n", - basename(argv[optind])); - fprintf(stderr, - "Namespace is currently busy.\n"); + fprintf(stderr, "Failed to open %s.\n", basename(argv[optind])); + fprintf(stderr, "Namespace is currently busy.\n"); if (!cfg.force) - fprintf(stderr, - "Use the force [--force] option to ignore that.\n"); + fprintf(stderr, "Use the force [--force] option to ignore that.\n"); } else { argconfig_print_help(desc, opts); } - goto ret; + return err; } - 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_dev; + if (cfg.lbaf != 0xff && cfg.bs != 0) { + nvme_show_error( + "Invalid specification of both LBAF and Block Size, please specify only one"); + return -EINVAL; } if (cfg.bs) { if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) { - fprintf(stderr, - "Invalid value for block size (%"PRIu64"), must be a power of two\n", - (uint64_t) cfg.bs); - err = -EINVAL; - goto close_dev; + nvme_show_error( + "Invalid value for block size (%"PRIu64"), must be a power of two", + (uint64_t) cfg.bs); + return -EINVAL; } } - err = nvme_cli_identify_ctrl(dev, &ctrl); + ctrl = nvme_alloc(sizeof(*ctrl)); + if (!ctrl) + return -ENOMEM; + + err = nvme_cli_identify_ctrl(dev, ctrl); if (err) { - fprintf(stderr, "identify-ctrl: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("identify-ctrl: %s", nvme_strerror(errno)); + return -errno; } - if ((ctrl.fna & 1) == 1) { + 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 @@ -4891,81 +5571,78 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu } else if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return -errno; } } 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_dev; + nvme_show_error( + "Invalid namespace ID, specify a namespace to format or use\n" + "'-n 0xffffffff' to format all namespaces on this controller."); + return -EINVAL; } if (cfg.namespace_id != NVME_NSID_ALL) { - err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns); if (err) { - if (err < 0) - fprintf(stderr, "identify-namespace: %s\n", nvme_strerror(errno)); - else { + if (err < 0) { + nvme_show_error("identify-namespace: %s", nvme_strerror(errno)); + } else { fprintf(stderr, "identify failed\n"); nvme_show_status(err); } - goto close_dev; + return err; } - nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &prev_lbaf); + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &prev_lbaf); if (cfg.bs) { - for (i = 0; i < ns.nlbaf; ++i) { - if ((1ULL << ns.lbaf[i].ds) == cfg.bs && - ns.lbaf[i].ms == 0) { + for (i = 0; i <= ns->nlbaf; ++i) { + if ((1ULL << ns->lbaf[i].ds) == cfg.bs && ns->lbaf[i].ms == 0) { cfg.lbaf = i; break; } } if (cfg.lbaf == 0xff) { fprintf(stderr, - "LBAF corresponding to given block size %"PRIu64" not found\n", - (uint64_t)cfg.bs); + "LBAF corresponding to given block size %"PRIu64" not found\n", + (uint64_t)cfg.bs); fprintf(stderr, "Please correct block size, or specify LBAF directly\n"); - err = -EINVAL; - goto close_dev; + return -EINVAL; } - } else if (cfg.lbaf == 0xff) + } else if (cfg.lbaf == 0xff) { cfg.lbaf = prev_lbaf; + } } else { - if (cfg.lbaf == 0xff) cfg.lbaf = 0; + 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_dev; + nvme_show_error("invalid secure erase settings:%d", cfg.ses); + return -EINVAL; } if (cfg.lbaf > 63) { - fprintf(stderr, "invalid lbaf:%d\n", cfg.lbaf); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid lbaf:%d", cfg.lbaf); + return -EINVAL; } if (cfg.pi > 7) { - fprintf(stderr, "invalid pi:%d\n", cfg.pi); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid pi:%d", cfg.pi); + return -EINVAL; } if (cfg.pil > 1) { - fprintf(stderr, "invalid pil:%d\n", cfg.pil); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid pil:%d", cfg.pil); + return -EINVAL; } if (cfg.ms > 1) { - fprintf(stderr, "invalid ms:%d\n", cfg.ms); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid ms:%d", cfg.ms); + return -EINVAL; } if (!cfg.force) { @@ -4973,11 +5650,12 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu dev->name, cfg.namespace_id, cfg.namespace_id == NVME_NSID_ALL ? "(ALL namespaces)" : ""); nvme_show_relatives(dev->name); - fprintf(stderr, "WARNING: Format may irrevocably delete this device's data.\n" + fprintf(stderr, + "WARNING: Format may irrevocably delete this device's data.\n" "You have 10 seconds to press Ctrl-C to cancel this operation.\n\n" "Use the force [--force] option to suppress this warning.\n"); sleep(10); - fprintf(stderr, "Sending format operation ... \n"); + fprintf(stderr, "Sending format operation ...\n"); } struct nvme_format_nvm_args args = { @@ -4993,21 +5671,20 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu .result = NULL, }; err = nvme_cli_format_nvm(dev, &args); - if (err < 0) - fprintf(stderr, "format: %s\n", nvme_strerror(errno)); - else if (err != 0) + if (err < 0) { + nvme_show_error("format: %s", nvme_strerror(errno)); + } else if (err != 0) { nvme_show_status(err); - else { + } else { printf("Success formatting namespace:%x\n", cfg.namespace_id); - if (dev->type == NVME_DEV_DIRECT && cfg.lbaf != prev_lbaf){ + if (dev->type == NVME_DEV_DIRECT && cfg.lbaf != prev_lbaf) { if (is_chardev(dev)) { if (ioctl(dev_fd(dev), NVME_IOCTL_RESCAN) < 0) { - fprintf(stderr, "failed to rescan namespaces\n"); - err = -errno; - goto close_dev; + nvme_show_error("failed to rescan namespaces"); + return -errno; } - } else { - block_size = 1 << ns.lbaf[cfg.lbaf].ds; + } else if (cfg.namespace_id != NVME_NSID_ALL) { + block_size = 1 << ns->lbaf[cfg.lbaf].ds; /* * If block size has been changed by the format @@ -5017,16 +5694,14 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu * update by itself without re-opening fd. */ if (ioctl(dev_fd(dev), BLKBSZSET, &block_size) < 0) { - fprintf(stderr, "failed to set block size to %d\n", + nvme_show_error("failed to set block size to %d", block_size); - err = -errno; - goto close_dev; + return -errno; } if (ioctl(dev_fd(dev), BLKRRPART) < 0) { - fprintf(stderr, "failed to re-read partition table\n"); - err = -errno; - goto close_dev; + nvme_show_error("failed to re-read partition table"); + return -errno; } } } @@ -5034,9 +5709,6 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu nvme_ctrl_reset(dev_fd(dev)); } -close_dev: - dev_close(dev); -ret: return err; } @@ -5045,28 +5717,26 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu 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 "\ + 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"; - const char *uuid_index = "specify uuid index"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *buf = NULL; + _cleanup_file_ int ffd = STDIN_FILENO; int err; __u32 result; - void *buf = NULL; - int ffd = STDIN_FILENO; struct config { __u32 namespace_id; @@ -5089,57 +5759,50 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin .save = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_SUFFIX("value", 'v', &cfg.value, value), - OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12), - OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), - OPT_UINT("data-len", 'l', &cfg.data_len, data_len), - OPT_FILE("data", 'd', &cfg.file, data), - OPT_FLAG("save", 's', &cfg.save, save), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), + OPT_SUFFIX("value", 'V', &cfg.value, value), + OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index_specify), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_FLAG("save", 's', &cfg.save, save)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - if (!cfg.namespace_id) { + if (!argconfig_parse_seen(opts, "namespace-id")) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { if (errno != ENOTTY) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return -errno; } - cfg.namespace_id = NVME_NSID_ALL; } } if (!cfg.feature_id) { - fprintf(stderr, "feature-id required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("feature-id required param"); + return -EINVAL; } - if (cfg.uuid_index > 128) { - fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index); - err = -1; - goto close_dev; + if (cfg.uuid_index > 127) { + nvme_show_error("invalid uuid index param: %u", cfg.uuid_index); + return -1; } if (!cfg.data_len) - nvme_get_feature_length(cfg.feature_id, cfg.value, - &cfg.data_len); + nvme_cli_get_feature_length2(cfg.feature_id, cfg.value, + NVME_DATA_TFR_HOST_TO_CTRL, + &cfg.data_len); if (cfg.data_len) { - if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { - fprintf(stderr, "can not allocate feature payload\n"); - err = -ENOMEM; - goto close_dev; - } - memset(buf, 0, cfg.data_len); + buf = nvme_alloc(cfg.data_len); + if (!buf) + return -ENOMEM; } if (buf) { @@ -5149,25 +5812,23 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin * should use the buffer method if the value exceeds this * length. */ - if (NVME_FEAT_FID_TIMESTAMP == cfg.feature_id && cfg.value) { + if (cfg.feature_id == NVME_FEAT_FID_TIMESTAMP && cfg.value) { memcpy(buf, &cfg.value, NVME_FEAT_TIMESTAMP_DATA_SIZE); } else { - if (strlen(cfg.file)) { + if (strlen(cfg.file)) ffd = open(cfg.file, O_RDONLY); - if (ffd <= 0) { - fprintf(stderr, "Failed to open file %s: %s\n", + + if (ffd < 0) { + nvme_show_error("Failed to open file %s: %s", cfg.file, strerror(errno)); - err = -EINVAL; - goto free; - } + return -EINVAL; } - err = read(ffd, (void *)buf, cfg.data_len); + err = read(ffd, 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; + nvme_show_error("failed to read data buffer from input file: %s", + strerror(errno)); + return -errno; } } } @@ -5189,55 +5850,43 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin }; err = nvme_set_features(&args); if (err < 0) { - fprintf(stderr, "set-feature: %s\n", nvme_strerror(errno)); + nvme_show_error("set-feature: %s", nvme_strerror(errno)); } else if (!err) { printf("set-feature:%#0*x (%s), value:%#0*"PRIx64", cdw12:%#0*x, save:%#x\n", cfg.feature_id ? 4 : 2, cfg.feature_id, nvme_feature_to_string(cfg.feature_id), cfg.value ? 10 : 8, (uint64_t)cfg.value, cfg.cdw12 ? 10 : 8, cfg.cdw12, cfg.save); - if (cfg.feature_id == NVME_FEAT_FID_LBA_STS_INTERVAL) { + if (cfg.feature_id == NVME_FEAT_FID_LBA_STS_INTERVAL) nvme_show_lba_status_info(result); - } if (buf) { if (cfg.feature_id == NVME_FEAT_FID_LBA_RANGE) - nvme_show_lba_range((struct nvme_lba_range_type *)buf, - result); + nvme_show_lba_range((struct nvme_lba_range_type *)buf, result, 0); else d(buf, cfg.data_len, 16, 1); } - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } -close_ffd: - if (ffd != STDIN_FILENO) - close(ffd); -free: - free(buf); -close_dev: - dev_close(dev); -ret: return err; } static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) { struct stat sb; - const char *desc = "Transfer security protocol data to "\ - "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 *desc = "Transfer security protocol data to\n" + "a controller. Security Receives for the same protocol should be\n" + "performed after Security Sends. The security protocol field\n" + "associates Security Sends (security-send) and Security Receives (security-recv)."; const char *file = "transfer payload"; - const char *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, sec_fd = STDIN_FILENO; - struct nvme_dev *dev; - void *sec_buf; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *sec_buf = NULL; + _cleanup_file_ int sec_fd = -1; unsigned int sec_size; + int err; struct config { __u32 namespace_id; @@ -5257,27 +5906,25 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p .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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_FILE("file", 'f', &cfg.file, file), + OPT_BYTE("nssf", 'N', &cfg.nssf, nssf), + OPT_BYTE("secp", 'p', &cfg.secp, secp), + OPT_SHRT("spsp", 's', &cfg.spsp, spsp), + OPT_UINT("tl", 't', &cfg.tl, tl)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.tl == 0) { - fprintf(stderr, "--tl unspecified or zero\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("--tl unspecified or zero"); + return -EINVAL; } if ((cfg.tl & 3) != 0) - fprintf(stderr, "WARNING: --tl not dword aligned; unaligned bytes may be truncated\n"); + nvme_show_error( + "WARNING: --tl not dword aligned; unaligned bytes may be truncated"); if (strlen(cfg.file) == 0) { sec_fd = STDIN_FILENO; @@ -5285,40 +5932,32 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p } else { sec_fd = open(cfg.file, O_RDONLY); if (sec_fd < 0) { - fprintf(stderr, "Failed to open %s: %s\n", - cfg.file, strerror(errno)); - err = -EINVAL; - goto close_dev; + nvme_show_error("Failed to open %s: %s", cfg.file, strerror(errno)); + return -EINVAL; } err = fstat(sec_fd, &sb); if (err < 0) { - perror("fstat"); - goto close_sec_fd; + nvme_show_perror("fstat"); + return err; } sec_size = cfg.tl > sb.st_size ? cfg.tl : sb.st_size; } - if (posix_memalign(&sec_buf, getpagesize(), cfg.tl)) { - fprintf(stderr, "No memory for security size:%d\n", cfg.tl); - err = -ENOMEM; - goto close_sec_fd; - } - - memset(sec_buf, 0, cfg.tl); // ensure zero fill if buf_size > sec_size + sec_buf = nvme_alloc(cfg.tl); + if (!sec_buf) + return -ENOMEM; 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; + nvme_show_error("Failed to read data from security file %s with %s", cfg.file, + strerror(errno)); + return -errno; } struct nvme_security_send_args args = { .args_size = sizeof(args), - .fd = dev_fd(dev), .nsid = cfg.namespace_id, .nssf = cfg.nssf, .spsp0 = cfg.spsp & 0xff, @@ -5330,43 +5969,31 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; - err = nvme_security_send(&args); + + err = nvme_cli_security_send(dev, &args); + if (err < 0) - fprintf(stderr, "security-send: %s\n", nvme_strerror(errno)); + nvme_show_error("security-send: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Security Send Command Success\n"); -free: - free(sec_buf); -close_sec_fd: - close(sec_fd); -close_dev: - dev_close(dev); -ret: return err; } static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Set directive parameters of the "\ - "specified directive type."; - const char *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 *desc = "Set directive parameters of the specified directive type."; const char *endir = "directive enable"; const char *ttype = "target directive type to be enabled/disabled"; - const char *human_readable = "show directive in readable format"; const char *input = "write/send file (default stdin)"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *buf = NULL; __u32 result; __u32 dw12 = 0; - void *buf = NULL; - int ffd = STDIN_FILENO; + _cleanup_file_ int ffd = STDIN_FILENO; int err; struct config { @@ -5395,39 +6022,35 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p .file = "", }; - 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_FILE("input-file", 'i', &cfg.file, input), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype), + OPT_BYTE("target-dir", 'T', &cfg.ttype, ttype), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype), + OPT_BYTE("dir-oper", 'O', &cfg.doper, doper), + OPT_SHRT("endir", 'e', &cfg.endir, endir), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_directive), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_directive), + OPT_FILE("input-file", 'i', &cfg.file, input)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; switch (cfg.dtype) { case NVME_DIRECTIVE_DTYPE_IDENTIFY: switch (cfg.doper) { case NVME_DIRECTIVE_SEND_IDENTIFY_DOPER_ENDIR: if (!cfg.ttype) { - fprintf(stderr, "target-dir required param\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("target-dir required param\n"); + return -EINVAL; } dw12 = cfg.ttype << 8 | cfg.endir; break; default: - fprintf(stderr, "invalid directive operations for Identify Directives\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid directive operations for Identify Directives"); + return -EINVAL; } break; case NVME_DIRECTIVE_DTYPE_STREAMS: @@ -5436,42 +6059,35 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p case NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE: break; default: - fprintf(stderr, "invalid directive operations for Streams Directives\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid directive operations for Streams Directives"); + return -EINVAL; } break; default: - fprintf(stderr, "invalid directive type\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid directive type"); + return -EINVAL; } - if (cfg.data_len) { - if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { - err = -ENOMEM; - goto close_dev; - } - memset(buf, 0, cfg.data_len); + buf = nvme_alloc(cfg.data_len); + if (!buf) + return -ENOMEM; } if (buf) { if (strlen(cfg.file)) { ffd = open(cfg.file, O_RDONLY); if (ffd <= 0) { - fprintf(stderr, "Failed to open file %s: %s\n", + nvme_show_error("Failed to open file %s: %s", cfg.file, strerror(errno)); - err = -EINVAL; - goto free; + return -EINVAL; } } 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; + nvme_show_error("failed to read data buffer from input file %s", + strerror(errno)); + return -errno; } } @@ -5490,92 +6106,92 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p }; err = nvme_directive_send(&args); if (err < 0) { - fprintf(stderr, "dir-send: %s\n", nvme_strerror(errno)); - goto close_ffd; + nvme_show_error("dir-send: %s", nvme_strerror(errno)); + return err; } if (!err) { - printf("dir-send: type %#x, operation %#x, spec_val %#x, nsid %#x, result %#x \n", - cfg.dtype, cfg.doper, cfg.dspec, cfg.namespace_id, result); + 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) + } else if (err > 0) { nvme_show_status(err); + } -close_ffd: - close(ffd); -free: - free(buf); -close_dev: - dev_close(dev); -ret: return err; } static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "The Write Uncorrectable command is used to set a "\ - "range of logical blocks to invalid."; - 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 nvme_dev *dev; + const char *desc = + "The Write Uncorrectable command is used to set a range of logical blocks to invalid."; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { __u32 namespace_id; __u64 start_block; __u16 block_count; + __u8 dtype; + __u16 dspec; }; struct config cfg = { .namespace_id = 0, .start_block = 0, .block_count = 0, + .dtype = 0, + .dspec = 0, }; - 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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), + OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), + OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } + if (cfg.dtype > 0xf) { + nvme_show_error("Invalid directive type, %x", cfg.dtype); + return -EINVAL; + } + struct nvme_io_args args = { .args_size = sizeof(args), .fd = dev_fd(dev), .nsid = cfg.namespace_id, .slba = cfg.start_block, .nlb = cfg.block_count, + .control = cfg.dtype << 4, + .dspec = cfg.dspec, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; err = nvme_write_uncorrectable(&args); if (err < 0) - fprintf(stderr, "write uncorrectable: %s\n", nvme_strerror(errno)); + nvme_show_error("write uncorrectable: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Write Uncorrectable Success\n"); -close_dev: - dev_close(dev); -ret: return err; } @@ -5584,7 +6200,7 @@ static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif) int result = 0; if (sts < 64 && storage_tag >= (1LL << sts)) { - fprintf(stderr, "Storage tag larger than storage tag size\n"); + nvme_show_error("Storage tag larger than storage tag size"); return 1; } @@ -5598,49 +6214,43 @@ static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif) result = 1; break; case 2: - if (sts > 0 && ref_tag >= (1LL << (64 - sts))) + if (sts > 0 && ref_tag >= (1LL << (48 - sts))) result = 1; break; default: - fprintf(stderr, "Invalid PIF\n"); + nvme_show_error("Invalid PIF"); result = 1; + break; } if (result) - fprintf(stderr, "Reference tag larger than allowed by PIF\n"); - + nvme_show_error("Reference tag larger than allowed by PIF"); + return result; } static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - __u16 control = 0; + _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; __u8 lba_index, sts = 0, pif = 0; - struct nvme_id_ns ns; - struct nvme_dev *dev; - struct nvme_nvm_id_ns nvm_ns; + __u16 control = 0; int err; - const char *desc = "The Write Zeroes command is used to set a "\ - "range of logical blocks to zero."; - const char *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_unit_access = "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 *storage_tag = "storage tag for end-to-end PI"; - const char *deac = "Set DEAC bit, requesting controller to deallocate specified logical blocks"; - const char *storage_tag_check = "This bit specifies the Storage Tag field shall be checked as "\ - "part of end-to-end data protection processing"; + const char *desc = + "The Write Zeroes command is used to set a range of logical blocks to zero."; + const char *deac = + "Set DEAC bit, requesting controller to deallocate specified logical blocks"; + const char *storage_tag_check = + "This bit specifies the Storage Tag field shall be checked as\n" + "part of end-to-end data protection processing"; struct config { __u32 namespace_id; __u64 start_block; __u16 block_count; + __u8 dtype; bool deac; bool limited_retry; bool force_unit_access; @@ -5650,46 +6260,52 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi __u16 app_tag; __u64 storage_tag; bool storage_tag_check; + __u16 dspec; }; struct config cfg = { .namespace_id = 0, .start_block = 0, .block_count = 0, - .deac = false, + .dtype = 0, + .deac = false, .limited_retry = false, .force_unit_access = false, - .prinfo = 0, - .ref_tag = 0, + .prinfo = 0, + .ref_tag = 0, .app_tag_mask = 0, - .app_tag = 0, + .app_tag = 0, .storage_tag = 0, .storage_tag_check = false, - }; - - 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_unit_access), - OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), - OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), - OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), - OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), - OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), - OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), - OPT_END() - }; + .dspec = 0, + }; + + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), + OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), + OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype), + OPT_FLAG("deac", 'd', &cfg.deac, deac), + OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), + OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), + OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), + OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), + OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), + OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), + OPT_SHRT("dir-spec", 'D', &cfg.dspec, dspec_w_dtype)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + if (cfg.prinfo > 0xf) + return -EINVAL; - if (cfg.prinfo > 0xf) { - err = -EINVAL; - goto close_dev; + if (cfg.dtype > 0xf) { + nvme_show_error("Invalid directive type, %x", cfg.dtype); + return -EINVAL; } control |= (cfg.prinfo << 10); @@ -5701,39 +6317,45 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi control |= NVME_IO_DEAC; if (cfg.storage_tag_check) control |= NVME_IO_STC; + control |= (cfg.dtype << 4); if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } - err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); - if (err) { + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns); + if (err < 0) { + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + return err; + } else if (err) { nvme_show_status(err); - goto close_dev; - } else if (err < 0) { - fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); - goto close_dev; + return err; } - err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0, - NVME_CSI_NVM, &nvm_ns); + nvm_ns = nvme_alloc(sizeof(*nvm_ns)); + if (!nvm_ns) + return -ENOMEM; + + err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0, NVME_CSI_NVM, nvm_ns); if (!err) { - nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); - sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; - pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); + sts = nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; + pif = (nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; } - if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { - err = -EINVAL; - goto close_dev; - } + if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) + return -EINVAL; struct nvme_io_args args = { .args_size = sizeof(args), - .fd = dev_fd(dev), + .fd = dev_fd(dev), .nsid = cfg.namespace_id, .slba = cfg.start_block, .nlb = cfg.block_count, @@ -5744,30 +6366,27 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi .sts = sts, .pif = pif, .storage_tag = cfg.storage_tag, + .dspec = cfg.dspec, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; err = nvme_write_zeros(&args); if (err < 0) - fprintf(stderr, "write-zeroes: %s\n", nvme_strerror(errno)); + nvme_show_error("write-zeroes: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Write Zeroes Success\n"); -close_dev: - dev_close(dev); -ret: return err; } static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "The Dataset Management command is used by the host to "\ - "indicate attributes for ranges of logical blocks. This includes attributes "\ - "for discarding unused blocks, data read and write frequency, access size, and other "\ + const char *desc = "The Dataset Management command is used by the host to\n" + "indicate attributes for ranges of logical blocks. This includes attributes\n" + "for discarding unused blocks, data read and write frequency, access size, and other\n" "information that may be used to optimize performance and reliability."; - const char *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"; @@ -5776,12 +6395,12 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin const char *idr = "Attribute Integral Dataset for Read"; const char *cdw11 = "All the command DWORD 11 attributes. Use instead of specifying individual attributes"; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_dsm_range *dsm = NULL; uint16_t nr, nc, nb, ns; __u32 ctx_attrs[256] = {0,}; __u32 nlbs[256] = {0,}; __u64 slbas[256] = {0,}; - struct nvme_dsm_range dsm[256]; - struct nvme_dev *dev; int err; struct config { @@ -5806,42 +6425,43 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin .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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_LIST("ctx-attrs", 'a', &cfg.ctx_attrs, context_attrs), + OPT_LIST("blocks", 'b', &cfg.blocks, blocks), + OPT_LIST("slbs", 's', &cfg.slbas, starting_blocks), + OPT_FLAG("ad", 'd', &cfg.ad, ad), + OPT_FLAG("idw", 'w', &cfg.idw, idw), + OPT_FLAG("idr", 'r', &cfg.idr, idr), + OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - nc = argconfig_parse_comma_sep_array(cfg.ctx_attrs, (int *)ctx_attrs, ARRAY_SIZE(ctx_attrs)); - nb = argconfig_parse_comma_sep_array(cfg.blocks, (int *)nlbs, ARRAY_SIZE(nlbs)); - ns = argconfig_parse_comma_sep_array_long(cfg.slbas, (unsigned long long *)slbas, ARRAY_SIZE(slbas)); + nc = argconfig_parse_comma_sep_array_u32(cfg.ctx_attrs, ctx_attrs, ARRAY_SIZE(ctx_attrs)); + nb = argconfig_parse_comma_sep_array_u32(cfg.blocks, nlbs, ARRAY_SIZE(nlbs)); + ns = argconfig_parse_comma_sep_array_u64(cfg.slbas, slbas, ARRAY_SIZE(slbas)); nr = max(nc, max(nb, ns)); if (!nr || nr > 256) { - fprintf(stderr, "No range definition provided\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("No range definition provided"); + return -EINVAL; } if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } if (!cfg.cdw11) cfg.cdw11 = (cfg.ad << 2) | (cfg.idw << 1) | (cfg.idr << 0); + dsm = nvme_alloc(sizeof(*dsm) * 256); + if (!dsm) + return -ENOMEM; + nvme_init_dsm_range(dsm, ctx_attrs, nlbs, slbas, nr); struct nvme_dsm_args args = { .args_size = sizeof(args), @@ -5850,34 +6470,30 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin .attrs = cfg.cdw11, .nr_ranges = nr, .dsm = dsm, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; err = nvme_dsm(&args); if (err < 0) - fprintf(stderr, "data-set management: %s\n", nvme_strerror(errno)); + nvme_show_error("data-set management: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVMe DSM: success\n"); -close_dev: - dev_close(dev); -ret: return err; } -static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int copy_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "The Copy command is used by the host to copy data " - "from one or more source logical block ranges to a " - "single consecutive destination logical block " - "range."; - - const char *d_nsid = "identifier of desired namespace"; + const char *desc = "The Copy command is used by the host to copy data\n" + "from one or more source logical block ranges to a\n" + "single consecutive destination logical block range."; const char *d_sdlba = "64-bit addr of first destination logical block"; const char *d_slbas = "64-bit addr of first block per range (comma-separated list)"; const char *d_nlbs = "number of blocks per range (comma-separated list, zeroes-based values)"; + const char *d_snsids = "source namespace identifier per range (comma-separated list)"; + const char *d_sopts = "source options per range (comma-separated list)"; const char *d_lr = "limited retry"; const char *d_fua = "force unit access"; const char *d_prinfor = "protection information and check field (read part)"; @@ -5892,30 +6508,36 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi const char *d_dspec = "directive specific (write part)"; const char *d_format = "source range entry format"; - uint16_t nr, nb, ns, nrts, natms, nats; - __u16 nlbs[128] = { 0 }; - unsigned long long slbas[128] = {0,}; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + __u16 nr, nb, ns, nrts, natms, nats, nids; + __u16 nlbs[256] = { 0 }; + __u64 slbas[256] = { 0 }; + __u32 snsids[256] = { 0 }; + __u16 sopts[256] = { 0 }; int err; union { - __u32 f0[128]; - __u64 f1[101]; + __u32 short_pi[256]; + __u64 long_pi[256]; } eilbrts; - __u32 elbatms[128] = { 0 }; - __u32 elbats[128] = { 0 }; + __u32 elbatms[256] = { 0 }; + __u32 elbats[256] = { 0 }; union { - struct nvme_copy_range f0[128]; - struct nvme_copy_range_f1 f1[101]; - } copy; + struct nvme_copy_range f0[256]; + struct nvme_copy_range_f1 f1[256]; + struct nvme_copy_range_f2 f2[256]; + struct nvme_copy_range_f3 f3[256]; + } *copy; struct config { __u32 namespace_id; __u64 sdlba; char *slbas; char *nlbs; + char *snsids; + char *sopts; bool lr; bool fua; __u8 prinfow; @@ -5936,6 +6558,8 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi .sdlba = 0, .slbas = "", .nlbs = "", + .snsids = "", + .sopts = "", .lr = false, .fua = false, .prinfow = 0, @@ -5951,74 +6575,93 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi .format = 0, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, d_nsid), - OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba), - OPT_LIST("slbs", 's', &cfg.slbas, d_slbas), - OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs), - OPT_FLAG("limited-retry", 'l', &cfg.lr, d_lr), - OPT_FLAG("force-unit-access", 'f', &cfg.fua, d_fua), - OPT_BYTE("prinfow", 'p', &cfg.prinfow, d_prinfow), - OPT_BYTE("prinfor", 'P', &cfg.prinfor, d_prinfor), - OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, d_ilbrt), - OPT_LIST("expected-ref-tags", 'R', &cfg.eilbrts, d_eilbrts), - OPT_SHRT("app-tag", 'a', &cfg.lbat, d_lbat), - OPT_LIST("expected-app-tags", 'A', &cfg.elbats, d_elbats), - OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, d_lbatm), - OPT_LIST("expected-app-tag-masks", 'M', &cfg.elbatms, d_elbatms), - OPT_BYTE("dir-type", 'T', &cfg.dtype, d_dtype), - OPT_SHRT("dir-spec", 'S', &cfg.dspec, d_dspec), - OPT_BYTE("format", 'F', &cfg.format, d_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba), + OPT_LIST("slbs", 's', &cfg.slbas, d_slbas), + OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs), + OPT_LIST("snsids", 'N', &cfg.snsids, d_snsids), + OPT_LIST("sopts", 'O', &cfg.sopts, d_sopts), + OPT_FLAG("limited-retry", 'l', &cfg.lr, d_lr), + OPT_FLAG("force-unit-access", 'f', &cfg.fua, d_fua), + OPT_BYTE("prinfow", 'p', &cfg.prinfow, d_prinfow), + OPT_BYTE("prinfor", 'P', &cfg.prinfor, d_prinfor), + OPT_SUFFIX("ref-tag", 'r', &cfg.ilbrt, d_ilbrt), + OPT_LIST("expected-ref-tags", 'R', &cfg.eilbrts, d_eilbrts), + OPT_SHRT("app-tag", 'a', &cfg.lbat, d_lbat), + OPT_LIST("expected-app-tags", 'A', &cfg.elbats, d_elbats), + OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, d_lbatm), + OPT_LIST("expected-app-tag-masks", 'M', &cfg.elbatms, d_elbatms), + OPT_BYTE("dir-type", 'T', &cfg.dtype, d_dtype), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, d_dspec), + OPT_BYTE("format", 'F', &cfg.format, d_format)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - nb = argconfig_parse_comma_sep_array_short(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs)); - ns = argconfig_parse_comma_sep_array_long(cfg.slbas, slbas, ARRAY_SIZE(slbas)); - - if (cfg.format == 0) - nrts = argconfig_parse_comma_sep_array(cfg.eilbrts, (int *)eilbrts.f0, ARRAY_SIZE(eilbrts.f0)); - else if (cfg.format == 1) - nrts = argconfig_parse_comma_sep_array_long(cfg.eilbrts, (__u64 *)eilbrts.f1, ARRAY_SIZE(eilbrts.f1)); - else { - fprintf(stderr, "invalid format\n"); - err = -EINVAL; - goto close_dev; + nb = argconfig_parse_comma_sep_array_u16(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs)); + ns = argconfig_parse_comma_sep_array_u64(cfg.slbas, slbas, ARRAY_SIZE(slbas)); + nids = argconfig_parse_comma_sep_array_u32(cfg.snsids, snsids, ARRAY_SIZE(snsids)); + argconfig_parse_comma_sep_array_u16(cfg.sopts, sopts, ARRAY_SIZE(sopts)); + + if (cfg.format == 0 || cfg.format == 2) { + nrts = argconfig_parse_comma_sep_array_u32(cfg.eilbrts, eilbrts.short_pi, + ARRAY_SIZE(eilbrts.short_pi)); + } else if (cfg.format == 1 || cfg.format == 3) { + nrts = argconfig_parse_comma_sep_array_u64(cfg.eilbrts, eilbrts.long_pi, + ARRAY_SIZE(eilbrts.long_pi)); + } else { + nvme_show_error("invalid format"); + return -EINVAL; } - natms = argconfig_parse_comma_sep_array(cfg.elbatms, (int *)elbatms, ARRAY_SIZE(elbatms)); - nats = argconfig_parse_comma_sep_array(cfg.elbats, (int *)elbats, ARRAY_SIZE(elbats)); + natms = argconfig_parse_comma_sep_array_u32(cfg.elbatms, elbatms, ARRAY_SIZE(elbatms)); + nats = argconfig_parse_comma_sep_array_u32(cfg.elbats, elbats, ARRAY_SIZE(elbats)); nr = max(nb, max(ns, max(nrts, max(natms, nats)))); - if (!nr || nr > 128 || (cfg.format == 1 && nr > 101)) { - fprintf(stderr, "invalid range\n"); - err = -EINVAL; - goto close_dev; + if (cfg.format == 2 || cfg.format == 3) { + if (nr != nids) { + nvme_show_error("formats 2 and 3 require source namespace ids for each source range"); + return -EINVAL; + } + } else if (nids) { + nvme_show_error("formats 0 and 1 do not support cross-namespace copy"); + return -EINVAL; + } + if (!nr || nr > 256) { + nvme_show_error("invalid range"); + return -EINVAL; } if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } + copy = nvme_alloc(sizeof(*copy)); + if (!copy) + return -ENOMEM; + if (cfg.format == 0) - nvme_init_copy_range(copy.f0, nlbs, (__u64 *)slbas, - eilbrts.f0, elbatms, elbats, nr); + nvme_init_copy_range(copy->f0, nlbs, slbas, eilbrts.short_pi, elbatms, elbats, nr); else if (cfg.format == 1) - nvme_init_copy_range_f1(copy.f1, nlbs, (__u64 *)slbas, - eilbrts.f1, elbatms, elbats, nr); + nvme_init_copy_range_f1(copy->f1, nlbs, slbas, eilbrts.long_pi, elbatms, elbats, nr); + else if (cfg.format == 2) + nvme_init_copy_range_f2(copy->f2, snsids, nlbs, slbas, sopts, eilbrts.short_pi, elbatms, + elbats, nr); + else if (cfg.format == 3) + nvme_init_copy_range_f3(copy->f3, snsids, nlbs, slbas, sopts, eilbrts.long_pi, elbatms, + elbats, nr); struct nvme_copy_args args = { .args_size = sizeof(args), .fd = dev_fd(dev), .nsid = cfg.namespace_id, - .copy = copy.f0, + .copy = copy->f0, .sdlba = cfg.sdlba, .nr = nr, .prinfor = cfg.prinfor, @@ -6036,27 +6679,24 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi }; err = nvme_copy(&args); if (err < 0) - fprintf(stderr, "NVMe Copy: %s\n", nvme_strerror(errno)); + nvme_show_error("NVMe Copy: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVMe Copy: success\n"); -close_dev: - dev_close(dev); -ret: return err; } -static int flush(int argc, char **argv, struct command *cmd, struct plugin *plugin) +static int flush_cmd(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 "\ + const char *desc = "Commit data and metadata associated with\n" + "given namespaces to nonvolatile media. Applies to all commands\n" + "finished before the flush was submitted. Additional data may also be\n" + "flushed by the controller, from any namespace, depending on controller and\n" "associated namespace status."; - const char *namespace_id = "identifier of desired namespace"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -6067,51 +6707,43 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug .namespace_id = 0, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } err = nvme_flush(dev_fd(dev), cfg.namespace_id); if (err < 0) - fprintf(stderr, "flush: %s\n", nvme_strerror(errno)); + nvme_show_error("flush: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVMe Flush: success\n"); -close_dev: - dev_close(dev); -ret: + return err; } static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Obtain a reservation on a given "\ - "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 *desc = "Obtain a reservation on a given\n" + "namespace. Only one reservation is allowed at a time on a\n" + "given namespace, though multiple controllers may register\n" + "with that namespace. Namespace reservation will abort with\n" + "status Reservation Conflict if the given namespace is already reserved."; const char *prkey = "pre-empt reservation key"; - const char *rtype = "reservation type"; const char *racqa = "reservation acquire action"; - const char *iekey = "ignore existing res. key"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -6132,31 +6764,28 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi .iekey = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), - OPT_SUFFIX("prkey", 'p', &cfg.prkey, prkey), - OPT_BYTE("rtype", 't', &cfg.rtype, rtype), - OPT_BYTE("racqa", 'a', &cfg.racqa, racqa), - OPT_FLAG("iekey", 'i', &cfg.iekey, iekey), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), + OPT_SUFFIX("prkey", 'p', &cfg.prkey, prkey), + OPT_BYTE("rtype", 't', &cfg.rtype, rtype), + OPT_BYTE("racqa", 'a', &cfg.racqa, racqa), + OPT_FLAG("iekey", 'i', &cfg.iekey, iekey)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } if (cfg.racqa > 7) { - fprintf(stderr, "invalid racqa:%d\n", cfg.racqa); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid racqa:%d", cfg.racqa); + return -EINVAL; } struct nvme_resv_acquire_args args = { @@ -6173,30 +6802,25 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi }; err = nvme_resv_acquire(&args); if (err < 0) - fprintf(stderr, "reservation acquire: %s\n", nvme_strerror(errno)); + nvme_show_error("reservation acquire: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Reservation Acquire success\n"); -close_dev: - dev_close(dev); -ret: return err; } 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. "\ + const char *desc = "Register, de-register, or\n" + "replace a controller's reservation on a given namespace.\n" "Only one reservation at a time is allowed on any namespace."; - const char *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"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -6216,37 +6840,33 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug .cptpl = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), - OPT_SUFFIX("nrkey", 'k', &cfg.nrkey, nrkey), - OPT_BYTE("rrega", 'r', &cfg.rrega, rrega), - OPT_BYTE("cptpl", 'p', &cfg.cptpl, cptpl), - OPT_FLAG("iekey", 'i', &cfg.iekey, iekey), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), + OPT_SUFFIX("nrkey", 'k', &cfg.nrkey, nrkey), + OPT_BYTE("rrega", 'r', &cfg.rrega, rrega), + OPT_BYTE("cptpl", 'p', &cfg.cptpl, cptpl), + OPT_FLAG("iekey", 'i', &cfg.iekey, iekey)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } if (cfg.cptpl > 3) { - fprintf(stderr, "invalid cptpl:%d\n", cfg.cptpl); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid cptpl:%d", cfg.cptpl); + return -EINVAL; } if (cfg.rrega > 7) { - fprintf(stderr, "invalid rrega:%d\n", cfg.rrega); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid rrega:%d", cfg.rrega); + return -EINVAL; } struct nvme_resv_register_args args = { @@ -6263,34 +6883,28 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug }; err = nvme_resv_register(&args); if (err < 0) - fprintf(stderr, "reservation register: %s\n", nvme_strerror(errno)); + nvme_show_error("reservation register: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Reservation success\n"); -close_dev: - dev_close(dev); -ret: return err; } 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 "\ + const char *desc = "Releases reservation held on a\n" + "namespace by the given controller. If rtype != current reservation\n" + "type, release will fails. If the given controller holds no\n" + "reservation on the namespace or is not the namespace's current\n" + "reservation holder, the release command completes with no\n" + "effect. If the reservation type is not Write Exclusive or\n" + "Exclusive Access, all registrants on the namespace except\n" "the issuing controller are notified."; - const char *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"; - struct nvme_dev *dev; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; struct config { @@ -6309,30 +6923,27 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi .iekey = 0, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), - OPT_BYTE("rtype", 't', &cfg.rtype, rtype), - OPT_BYTE("rrela", 'a', &cfg.rrela, rrela), - OPT_FLAG("iekey", 'i', &cfg.iekey, iekey), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), + OPT_BYTE("rtype", 't', &cfg.rtype, rtype), + OPT_BYTE("rrela", 'a', &cfg.rrela, rrela), + OPT_FLAG("iekey", 'i', &cfg.iekey, iekey)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } if (cfg.rrela > 7) { - fprintf(stderr, "invalid rrela:%d\n", cfg.rrela); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid rrela:%d", cfg.rrela); + return -EINVAL; } struct nvme_resv_release_args args = { @@ -6348,40 +6959,33 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi }; err = nvme_resv_release(&args); if (err < 0) - fprintf(stderr, "reservation release: %s\n", nvme_strerror(errno)); + nvme_show_error("reservation release: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Reservation Release success\n"); -close_dev: - dev_close(dev); -ret: return err; } 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 *desc = "Returns Reservation Status data\n" + "structure describing any existing reservations on and the\n" + "status of a given namespace. Namespace Reservation Status\n" + "depends on the number of controllers registered for that namespace."; const char *numd = "number of dwords to transfer"; const char *eds = "request extended data structure"; - const char *raw = "dump output in binary format"; - struct nvme_resv_status *status; + _cleanup_free_ struct nvme_resv_status *status = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; enum nvme_print_flags flags; - struct nvme_dev *dev; int err, size; struct config { __u32 namespace_id; __u32 numd; __u8 eds; - char *output_format; bool raw_binary; }; @@ -6389,34 +6993,33 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin .namespace_id = 0, .numd = 0, .eds = false, - .output_format = "normal", .raw_binary = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("numd", 'd', &cfg.numd, numd), - OPT_FLAG("eds", 'e', &cfg.eds, eds), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("numd", 'd', &cfg.numd, numd), + OPT_FLAG("eds", 'e', &cfg.eds, eds), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; if (cfg.raw_binary) flags = BINARY; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } @@ -6427,12 +7030,9 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin 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_dev; - } - memset(status, 0, size); + status = nvme_alloc(size); + if (!status) + return -ENOMEM; struct nvme_resv_report_args args = { .args_size = sizeof(args), @@ -6450,11 +7050,8 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "reservation report: %s\n", nvme_strerror(errno)); - free(status); -close_dev: - dev_close(dev); -ret: + nvme_show_error("reservation report: %s", nvme_strerror(errno)); + return err; } @@ -6466,47 +7063,37 @@ unsigned long long elapsed_utime(struct timeval start_time, return err; } -static int submit_io(int opcode, char *command, const char *desc, - int argc, char **argv) +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; + void *buffer; + _cleanup_free_ void *mbuffer = NULL; int err = 0; - int dfd, mfd; - 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; + _cleanup_file_ int dfd = -1, mfd = -1; + int flags; + int mode = 0644; + __u16 control = 0, nblocks = 0; __u32 dsmgmt = 0; - int logical_block_size = 0; + unsigned int logical_block_size = 0; unsigned long long buffer_size = 0, mbuffer_size = 0; - bool huge; - struct nvme_id_ns ns; - struct nvme_nvm_id_ns nvm_ns; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; __u8 lba_index, ms = 0, sts = 0, pif = 0; - struct nvme_dev *dev; - const char *namespace_id = "Identifier of desired namespace"; - const char *start_block = "64-bit addr of first block to access"; - const char *block_count = "number of blocks (zeroes based) on device to access"; + const char *start_block_addr = "64-bit addr of first block to access"; const char *data_size = "size of data in bytes"; const char *metadata_size = "size of metadata in bytes"; - const char *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_unit_access = "force device to commit data before command completes"; + const char *limited_retry_num = "limit num. media access attempts"; 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 *dtype_for_write = "directive type (for write-only)"; const char *dspec = "directive specific (for write-only)"; const char *dsm = "dataset management attributes (lower 8 bits)"; - const char *storage_tag_check = "This bit specifies the Storage Tag field shall be " \ + const char *storage_tag_check = "This bit specifies the Storage Tag field shall be\n" "checked as part of end-to-end data protection processing"; - const char *storage_tag = "storage tag for end-to-end PI"; const char *force = "The \"I know what I'm doing\" flag, do not enforce exclusive access for write"; struct config { @@ -6559,70 +7146,63 @@ static int submit_io(int opcode, char *command, const char *desc, .force = false, }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), - OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), - OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size), - OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size), - OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), - OPT_FILE("data", 'd', &cfg.data, data), - OPT_FILE("metadata", 'M', &cfg.metadata, metadata), - OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), - OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), - OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), - OPT_SUFFIX("storage-tag", 'g', &cfg.storage_tag, storage_tag), - OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), - OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), - OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), - OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype), - OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), - OPT_BYTE("dsm", 'D', &cfg.dsmgmt, dsm), - OPT_FLAG("show-command", 'v', &cfg.show, show), - OPT_FLAG("dry-run", 'w', &cfg.dry_run, dry), - OPT_FLAG("latency", 't', &cfg.latency, latency), - OPT_FLAG("force", 0, &cfg.force, force), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block_addr), + OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), + OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size), + OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_FILE("data", 'd', &cfg.data, data), + OPT_FILE("metadata", 'M', &cfg.metadata, metadata), + OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), + OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), + OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), + OPT_SUFFIX("storage-tag", 'g', &cfg.storage_tag, storage_tag), + OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry_num), + OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access), + OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), + OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype_for_write), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), + OPT_BYTE("dsm", 'D', &cfg.dsmgmt, dsm), + OPT_FLAG("show-command", 'V', &cfg.show, show), + OPT_FLAG("dry-run", 'w', &cfg.dry_run, dry), + OPT_FLAG("latency", 't', &cfg.latency, latency), + OPT_FLAG("force", 0, &cfg.force, force)); if (opcode != nvme_cmd_write) { err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; } else { err = argconfig_parse(argc, argv, desc, opts); if (err) - goto ret; + return err; err = open_exclusive(&dev, argc, argv, cfg.force); if (err) { if (errno == EBUSY) { - fprintf(stderr, "Failed to open %s.\n", - basename(argv[optind])); - fprintf(stderr, - "Namespace is currently busy.\n"); + fprintf(stderr, "Failed to open %s.\n", basename(argv[optind])); + fprintf(stderr, "Namespace is currently busy.\n"); if (!cfg.force) fprintf(stderr, - "Use the force [--force] option to ignore that.\n"); + "Use the force [--force] option to ignore that.\n"); } else { argconfig_print_help(desc, opts); } - goto ret; + return err; } } if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } - dfd = mfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO; - if (cfg.prinfo > 0xf) { - err = -EINVAL; - goto close_dev; - } + if (cfg.prinfo > 0xf) + return err; dsmgmt = cfg.dsmgmt; control |= (cfg.prinfo << 10); @@ -6634,104 +7214,122 @@ static int submit_io(int opcode, char *command, const char *desc, control |= NVME_IO_STC; if (cfg.dtype) { if (cfg.dtype > 0xf) { - fprintf(stderr, "Invalid directive type, %x\n", - cfg.dtype); - err = -EINVAL; - goto close_dev; + nvme_show_error("Invalid directive type, %x", cfg.dtype); + return -EINVAL; } control |= cfg.dtype << 4; dsmgmt |= ((__u32)cfg.dspec) << 16; } + if (opcode & 1) { + dfd = mfd = STDIN_FILENO; + flags = O_RDONLY; + } else { + dfd = mfd = STDOUT_FILENO; + flags = O_WRONLY | O_CREAT; + } + if (strlen(cfg.data)) { dfd = open(cfg.data, flags, mode); if (dfd < 0) { - perror(cfg.data); - err = -EINVAL; - goto close_dev; + nvme_show_perror(cfg.data); + return -EINVAL; } } if (strlen(cfg.metadata)) { mfd = open(cfg.metadata, flags, mode); if (mfd < 0) { - perror(cfg.metadata); - err = -EINVAL; - goto close_dfd; + nvme_show_perror(cfg.metadata); + return -EINVAL; } } - if (!cfg.data_size) { - fprintf(stderr, "data size not provided\n"); - err = -EINVAL; - goto close_mfd; + if (!cfg.data_size) { + nvme_show_error("data size not provided"); + return -EINVAL; + } + + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns); + if (err > 0) { + nvme_show_status(err); + return err; + } else if (err < 0) { + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + return err; } - if (nvme_get_logical_block_size(dev_fd(dev), cfg.namespace_id, - &logical_block_size) < 0) - goto close_mfd; + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); + logical_block_size = 1 << ns->lbaf[lba_index].ds; + ms = ns->lbaf[lba_index].ms; + if (NVME_FLBAS_META_EXT(ns->flbas)) { + /* + * No meta data is transferred for PRACT=1 and MD=8: + * 5.2.2.1 Protection Information and Write Commands + * 5.2.2.2 Protection Information and Read Commands + */ + if (!((cfg.prinfo & 0x8) != 0 && ms == 8)) + logical_block_size += ms; + } buffer_size = ((long long)cfg.block_count + 1) * logical_block_size; - if (cfg.data_size < buffer_size) { - fprintf(stderr, "Rounding data size to fit block count (%lld bytes)\n", - buffer_size); - } else { + if (cfg.data_size < buffer_size) + nvme_show_error("Rounding data size to fit block count (%lld bytes)", buffer_size); + else buffer_size = cfg.data_size; - } - buffer = nvme_alloc(buffer_size, &huge); - if (!buffer) { - err = -ENOMEM; - goto close_mfd; + if (argconfig_parse_seen(opts, "block-count")) { + /* Use the value provided */ + nblocks = cfg.block_count; + } else { + /* Get the required block count. Note this is a zeroes based value. */ + nblocks = ((buffer_size + (logical_block_size - 1)) / logical_block_size) - 1; + + /* Update the data size based on the required block count */ + buffer_size = ((unsigned long long)nblocks + 1) * logical_block_size; } - if (cfg.metadata_size) { - err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); - if (err > 0) { - nvme_show_status(err); - goto free_buffer; - } else if (err < 0) { - fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); - goto free_buffer; - } + buffer = nvme_alloc_huge(buffer_size, &mh); + if (!buffer) + return -ENOMEM; - nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); - ms = ns.lbaf[lba_index].ms; + nvm_ns = nvme_alloc(sizeof(*nvm_ns)); + if (!nvm_ns) + return -ENOMEM; - err = nvme_identify_ns_csi(dev_fd(dev), 1, 0, NVME_CSI_NVM, - &nvm_ns); + if (cfg.metadata_size) { + err = nvme_identify_ns_csi(dev_fd(dev), 1, 0, NVME_CSI_NVM, nvm_ns); if (!err) { - sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; - pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + sts = nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; + pif = (nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; } mbuffer_size = ((unsigned long long)cfg.block_count + 1) * ms; - if (ms && cfg.metadata_size < mbuffer_size) { - fprintf(stderr, "Rounding metadata size to fit block count (%lld bytes)\n", + if (ms && cfg.metadata_size < mbuffer_size) + nvme_show_error("Rounding metadata size to fit block count (%lld bytes)", mbuffer_size); - } else { + else mbuffer_size = cfg.metadata_size; - } + mbuffer = malloc(mbuffer_size); - if (!mbuffer) { - err = -ENOMEM; - goto free_buffer; - } + if (!mbuffer) + return -ENOMEM; memset(mbuffer, 0, mbuffer_size); } - if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { - err = -EINVAL; - goto free_buffer; - } + if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) + return -EINVAL; - if ((opcode & 1)) { + 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; + nvme_show_error("failed to read data buffer from input file %s", strerror(errno)); + return err; } } @@ -6739,9 +7337,8 @@ static int submit_io(int opcode, char *command, const char *desc, err = read(mfd, (void *)mbuffer, mbuffer_size); if (err < 0) { err = -errno; - fprintf(stderr, "failed to read meta-data buffer from" - " input file %s\n", strerror(errno)); - goto free_mbuffer; + nvme_show_error("failed to read meta-data buffer from input file %s", strerror(errno)); + return err; } } @@ -6750,7 +7347,7 @@ static int submit_io(int opcode, char *command, const char *desc, printf("nsid : %02x\n", cfg.namespace_id); printf("flags : %02x\n", 0); printf("control : %04x\n", control); - printf("nblocks : %04x\n", cfg.block_count); + printf("nblocks : %04x\n", nblocks); printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer); printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer); printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block); @@ -6764,14 +7361,14 @@ static int submit_io(int opcode, char *command, const char *desc, printf("sts : %02x\n", sts); } if (cfg.dry_run) - goto free_mbuffer; + return 0; struct nvme_io_args args = { .args_size = sizeof(args), .fd = dev_fd(dev), .nsid = cfg.namespace_id, .slba = cfg.start_block, - .nlb = cfg.block_count, + .nlb = nblocks, .control = control, .dsm = cfg.dsmgmt, .sts = sts, @@ -6783,7 +7380,7 @@ static int submit_io(int opcode, char *command, const char *desc, .storage_tag = cfg.storage_tag, .data_len = buffer_size, .data = buffer, - .metadata_len = cfg.metadata_size, + .metadata_len = mbuffer_size, .metadata = mbuffer, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, @@ -6792,61 +7389,52 @@ static int submit_io(int opcode, char *command, const char *desc, err = nvme_io(&args, opcode); gettimeofday(&end_time, NULL); if (cfg.latency) - printf(" latency: %s: %llu us\n", - command, elapsed_utime(start_time, end_time)); - if (err < 0) - fprintf(stderr, "submit-io: %s\n", nvme_strerror(errno)); - else if (err) + printf(" latency: %s: %llu us\n", command, elapsed_utime(start_time, end_time)); + if (err < 0) { + nvme_show_error("submit-io: %s", nvme_strerror(errno)); + } else if (err) { nvme_show_status(err); - else { - if (!(opcode & 1) && write(dfd, (void *)buffer, cfg.data_size) < 0) { - fprintf(stderr, "write: %s: failed to write buffer to output file\n", - strerror(errno)); + } else { + if (!(opcode & 1) && write(dfd, (void *)buffer, buffer_size) < 0) { + nvme_show_error("write: %s: failed to write buffer to output file", + strerror(errno)); err = -EINVAL; } else if (!(opcode & 1) && cfg.metadata_size && - write(mfd, (void *)mbuffer, mbuffer_size) < 0) { - fprintf(stderr, "write: %s: failed to write meta-data buffer to output file\n", - strerror(errno)); + write(mfd, (void *)mbuffer, mbuffer_size) < 0) { + nvme_show_error( + "write: %s: failed to write meta-data buffer to output file", + strerror(errno)); err = -EINVAL; - } else + } else { fprintf(stderr, "%s: Success\n", command); + } } -free_mbuffer: - free(mbuffer); -free_buffer: - nvme_free(buffer, huge); -close_mfd: - if (strlen(cfg.metadata)) - close(mfd); -close_dfd: - close(dfd); -close_dev: - dev_close(dev); -ret: return err; } 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 "\ + const char *desc = "Compare specified logical blocks on\n" + "device with specified data buffer; return failure if buffer\n" "and block(s) are dissimilar"; + return submit_io(nvme_cmd_compare, "compare", desc, argc, argv); } static int read_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Copy specified logical blocks on the given "\ + const char *desc = "Copy specified logical blocks on the given\n" "device to specified data buffer (default buffer is stdout)."; + return submit_io(nvme_cmd_read, "read", desc, argc, argv); } static int write_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Copy from provided data buffer (default "\ - "buffer is stdin) to specified logical blocks on the given "\ - "device."; + const char *desc = "Copy from provided data buffer (default\n" + "buffer is stdin) to specified logical blocks on the given device."; + return submit_io(nvme_cmd_write, "write", desc, argc, argv); } @@ -6854,24 +7442,16 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin { __u16 control = 0; __u8 lba_index, sts = 0, pif = 0; - struct nvme_id_ns ns; - struct nvme_nvm_id_ns nvm_ns; - struct nvme_dev *dev; + _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL; + _cleanup_free_ struct nvme_id_ns *ns = NULL; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err; const char *desc = "Verify specified logical blocks on the given device."; - const char *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_unit_access = "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"; - const char *storage_tag = "storage tag for end-to-end PI"; - const char *storage_tag_check = "This bit specifies the Storage Tag field shall "\ - "be checked as part of Verify operation"; + const char *force_unit_access_verify = + "force device to commit cached data before performing the verify operation"; + const char *storage_tag_check = + "This bit specifies the Storage Tag field shall be checked as part of Verify operation"; struct config { __u32 namespace_id; @@ -6901,29 +7481,25 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin .storage_tag_check = false, }; - 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_unit_access), - OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), - OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), - OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), - OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), - OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), - OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), + OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), + OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), + OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access_verify), + OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), + OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag), + OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), + OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), + OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), + OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - if (cfg.prinfo > 0xf) { - err = EINVAL; - goto close_dev; - } + if (cfg.prinfo > 0xf) + return -EINVAL; control |= (cfg.prinfo << 10); if (cfg.limited_retry) @@ -6936,32 +7512,38 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { - fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); - goto close_dev; + nvme_show_error("get-namespace-id: %s", nvme_strerror(errno)); + return err; } } - err = nvme_cli_identify_ns(dev, cfg.namespace_id, &ns); - if (err) { + ns = nvme_alloc(sizeof(*ns)); + if (!ns) + return -ENOMEM; + + err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns); + if (err < 0) { + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + return err; + } else if (err) { nvme_show_status(err); - goto close_dev; - } else if (err < 0) { - fprintf(stderr, "identify namespace: %s\n", nvme_strerror(errno)); - goto close_dev; + return err; } + nvm_ns = nvme_alloc(sizeof(*nvm_ns)); + if (!nvm_ns) + return -ENOMEM; + err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0, - NVME_CSI_NVM, &nvm_ns); + NVME_CSI_NVM, nvm_ns); if (!err) { - nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index); - sts = nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; - pif = (nvm_ns.elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); + sts = nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK; + pif = (nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7; } - if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) { - err = -EINVAL; - goto close_dev; - } + if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif)) + return -EINVAL; struct nvme_io_args args = { .args_size = sizeof(args), @@ -6981,35 +7563,28 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin }; err = nvme_verify(&args); if (err < 0) - fprintf(stderr, "verify: %s\n", nvme_strerror(errno)); + nvme_show_error("verify: %s", nvme_strerror(errno)); else if (err != 0) nvme_show_status(err); else printf("NVME Verify Success\n"); -close_dev: - dev_close(dev); -ret: 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 "\ + const char *desc = "Obtain results of one or more\n" + "previously submitted security-sends. Results, and association\n" + "between Security Send and Receive, depend on the security\n" + "protocol field as they are defined by the security protocol\n" + "used. A Security Receive must follow a Security Send made with\n" "the same security protocol."; const char *size = "size of buffer (prints to stdout on success)"; - const char *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"; - struct nvme_dev *dev; - void *sec_buf = NULL; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *sec_buf = NULL; int err; struct config { @@ -7032,33 +7607,27 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p .raw_binary = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_UINT("size", 'x', &cfg.size, size), + OPT_BYTE("nssf", 'N', &cfg.nssf, nssf), + OPT_BYTE("secp", 'p', &cfg.secp, secp), + OPT_SHRT("spsp", 's', &cfg.spsp, spsp), + OPT_UINT("al", 't', &cfg.al, al), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; 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_dev; - } + sec_buf = nvme_alloc(sizeof(*sec_buf)); + if (!sec_buf) + return -ENOMEM; } struct nvme_security_receive_args args = { .args_size = sizeof(args), - .fd = dev_fd(dev), .nsid = cfg.namespace_id, .nssf = cfg.nssf, .spsp0 = cfg.spsp & 0xff, @@ -7070,24 +7639,20 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; - err = nvme_security_receive(&args); - if (err < 0) - fprintf(stderr, "security receive: %s\n", nvme_strerror(errno)); - else if (err != 0) + + err = nvme_cli_security_receive(dev, &args); + if (err < 0) { + nvme_show_error("security receive: %s", nvme_strerror(errno)); + } else if (err != 0) { nvme_show_status(err); - else { + } else { printf("NVME Security Receive Command Success\n"); - if (!cfg.raw_binary) { + if (!cfg.raw_binary) d(sec_buf, cfg.size, 16, 1); - } else if (cfg.size) + else if (cfg.size) d_raw((unsigned char *)sec_buf, cfg.size); } - free(sec_buf); - -close_dev: - dev_close(dev); -ret: return err; } @@ -7095,22 +7660,19 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Information about potentially unrecoverable LBAs."; - const char *namespace_id = "Desired Namespace"; - const char *slba = "Starting LBA(SLBA) in 64-bit address of the first"\ - " logical block addressed by this command"; - const char *mndw = "Maximum Number of Dwords(MNDW) specifies maximum"\ - " number of dwords to return"; - const char *atype = "Action Type(ATYPE) specifies the mechanism"\ - " the controller uses in determining the LBA"\ - " Status Descriptors to return."; - const char *rl = "Range Length(RL) specifies the length of the range"\ - " of contiguous LBAs beginning at SLBA"; - const char *timeout = "timeout value, in milliseconds"; - + const char *slba = + "Starting LBA(SLBA) in 64-bit address of the first logical block addressed by this command"; + const char *mndw = + "Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return"; + const char *atype = "Action Type(ATYPE) specifies the mechanism\n" + "the controller uses in determining the LBA Status Descriptors to return."; + const char *rl = + "Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA"; + + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *buf = NULL; enum nvme_print_flags flags; unsigned long buf_len; - struct nvme_dev *dev; - void *buf; int err; struct config { @@ -7120,7 +7682,6 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, __u8 atype; __u16 rl; __u32 timeout; - char *output_format; }; struct config cfg = { @@ -7130,40 +7691,35 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, .atype = 0, .rl = 0, .timeout = 0, - .output_format = "normal", }; - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_SUFFIX("start-lba", 's', &cfg.slba, slba), - OPT_UINT("max-dw", 'm', &cfg.mndw, mndw), - OPT_BYTE("action", 'a', &cfg.atype, atype), - OPT_SHRT("range-len", 'l', &cfg.rl, rl), - OPT_UINT("timeout", 't', &cfg.timeout, timeout), - OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_END() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_SUFFIX("start-lba", 's', &cfg.slba, slba), + OPT_UINT("max-dw", 'm', &cfg.mndw, mndw), + OPT_BYTE("action", 'a', &cfg.atype, atype), + OPT_SHRT("range-len", 'l', &cfg.rl, rl), + OPT_UINT("timeout", 't', &cfg.timeout, timeout)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto err; + return err; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_dev; + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } if (!cfg.atype) { - fprintf(stderr, "action type (--action) has to be given\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("action type (--action) has to be given"); + return -EINVAL; } buf_len = (cfg.mndw + 1) * 4; - buf = calloc(1, buf_len); - if (!buf) { - err = -ENOMEM; - goto close_dev; - } + buf = nvme_alloc(buf_len); + if (!buf) + return -ENOMEM; struct nvme_get_lba_status_args args = { .args_size = sizeof(args), @@ -7183,28 +7739,25 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, else if (err > 0) nvme_show_status(err); else - fprintf(stderr, "get lba status: %s\n", nvme_strerror(errno)); - free(buf); -close_dev: - dev_close(dev); -err: + nvme_show_error("get lba status: %s", nvme_strerror(errno)); + return err; } static int capacity_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Host software uses the Capacity Management command to "\ - "configure Endurance Groups and NVM Sets in an NVM subsystem by either " \ - "selecting one of a set of supported configurations or by specifying the "\ + const char *desc = "Host software uses the Capacity Management command to\n" + "configure Endurance Groups and NVM Sets in an NVM subsystem by either\n" + "selecting one of a set of supported configurations or by specifying the\n" "capacity of the Endurance Group or NVM Set to be created"; const char *operation = "Operation to be performed by the controller"; const char *element_id = "Value specific to the value of the Operation field."; - const char *cap_lower = "Least significant 32 bits of the capacity in bytes of the "\ - "Endurance Group or NVM Set to be created"; - const char *cap_upper = "Most significant 32 bits of the capacity in bytes of the "\ - "Endurance Group or NVM Set to be created"; + const char *cap_lower = + "Least significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created"; + const char *cap_upper = + "Most significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created"; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err = -1; __u32 result; @@ -7222,22 +7775,19 @@ static int capacity_mgmt(int argc, char **argv, struct command *cmd, struct plug .dw12 = 0, }; - OPT_ARGS(opts) = { - OPT_BYTE("operation", 'o', &cfg.operation, operation), - OPT_SHRT("element-id", 'i', &cfg.element_id, element_id), - OPT_UINT("cap-lower", 'l', &cfg.dw11, cap_lower), - OPT_UINT("cap-upper", 'u', &cfg.dw12, cap_upper), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("operation", 'O', &cfg.operation, operation), + OPT_SHRT("element-id", 'i', &cfg.element_id, element_id), + OPT_UINT("cap-lower", 'l', &cfg.dw11, cap_lower), + OPT_UINT("cap-upper", 'u', &cfg.dw12, cap_upper)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.operation > 0xf) { - fprintf(stderr, "invalid operation field: %u\n", cfg.operation); - err = -1; - goto close_dev; + nvme_show_error("invalid operation field: %u", cfg.operation); + return -1; } struct nvme_capacity_mgmt_args args = { @@ -7253,40 +7803,29 @@ static int capacity_mgmt(int argc, char **argv, struct command *cmd, struct plug err = nvme_capacity_mgmt(&args); if (!err) { printf("Capacity Management Command is Success\n"); - if (cfg.operation == 1) { + if (cfg.operation == 1) printf("Created Element Identifier for Endurance Group is: %u\n", result); - } else if (cfg.operation == 3) { + else if (cfg.operation == 3) printf("Created Element Identifier for NVM Set is: %u\n", result); - } - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); - else if (err < 0) - fprintf(stderr, "capacity management: %s\n", nvme_strerror(errno)); + } else if (err < 0) { + nvme_show_error("capacity management: %s", nvme_strerror(errno)); + } -close_dev: - dev_close(dev); -ret: return err; } static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Read directive parameters of the "\ - "specified directive type."; - const char *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 *desc = "Read directive parameters of the specified directive type."; const char *nsr = "namespace stream requested"; - const char *human_readable = "show directive in readable format"; enum nvme_print_flags flags = NORMAL; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_free_ void *buf = NULL; __u32 result; __u32 dw12 = 0; - void *buf = NULL; int err; struct config { @@ -7311,21 +7850,19 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin .human_readable = false, }; - 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() - }; + NVME_ARGS(opts, + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired), + OPT_UINT("data-len", 'l', &cfg.data_len, buf_len), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_directive), + OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype), + OPT_BYTE("dir-oper", 'O', &cfg.doper, doper), + OPT_SHRT("req-resource", 'r', &cfg.nsr, nsr), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_directive)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; if (cfg.human_readable) flags |= VERBOSE; @@ -7340,9 +7877,8 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin cfg.data_len = 4096; break; default: - fprintf(stderr, "invalid directive operations for Identify Directives\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid directive operations for Identify Directives"); + return -EINVAL; } break; case NVME_DIRECTIVE_DTYPE_STREAMS: @@ -7359,23 +7895,19 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin dw12 = cfg.nsr; break; default: - fprintf(stderr, "invalid directive operations for Streams Directives\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid directive operations for Streams Directives"); + return -EINVAL; } break; default: - fprintf(stderr, "invalid directive type\n"); - err = -EINVAL; - goto close_dev; + nvme_show_error("invalid directive type"); + return -EINVAL; } if (cfg.data_len) { - if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { - err = -ENOMEM; - goto close_dev; - } - memset(buf, 0, cfg.data_len); + buf = nvme_alloc(cfg.data_len); + if (!buf) + return -ENOMEM; } struct nvme_directive_recv_args args = { @@ -7393,18 +7925,13 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin }; err = nvme_directive_recv(&args); if (!err) - nvme_directive_show(cfg.dtype, cfg.doper, cfg.dspec, - cfg.namespace_id, result, buf, cfg.data_len, - flags); + 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) - fprintf(stderr, "dir-receive: %s\n", nvme_strerror(errno)); + nvme_show_error("dir-receive: %s", nvme_strerror(errno)); - free(buf); -close_dev: - dev_close(dev); -ret: return err; } @@ -7417,26 +7944,26 @@ static int rpmb_cmd(int argc, char **argv, struct command *cmd, struct plugin *p static int lockdown_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "The Lockdown command is used to control the "\ - "Command and Feature Lockdown capability which configures the "\ - "prohibition or allowance of execution of the specified command "\ + const char *desc = "The Lockdown command is used to control the\n" + "Command and Feature Lockdown capability which configures the\n" + "prohibition or allowance of execution of the specified command\n" "or Set Features command targeting a specific Feature Identifier."; - const char *ofi_desc = "Opcode or Feature Identifier(OFI) "\ - "specifies the command opcode or Set Features Feature Identifier "\ + const char *ofi_desc = "Opcode or Feature Identifier (OFI)\n" + "specifies the command opcode or Set Features Feature Identifier\n" "identified by the Scope field."; - const char *ifc_desc = "[0-3] Interface (INF) field identifies the "\ - "interfaces affected by this command."; - const char *prhbt_desc = "[0-1]Prohibit(PRHBT) bit specifies whether "\ - "to prohibit or allow the command opcode or Set Features Feature "\ + const char *ifc_desc = + "[0-3] Interface (INF) field identifies the interfaces affected by this command."; + const char *prhbt_desc = "[0-1]Prohibit(PRHBT) bit specifies whether\n" + "to prohibit or allow the command opcode or Set Features Feature\n" "Identifier specified by this command."; - const char *scp_desc = "[0-15]Scope(SCP) field specifies the contents "\ - "of the Opcode or Feature Identifier field."; - const char *uuid_desc = "UUID Index - If this field is set to a non-zero "\ - "value, then the value of this field is the index of a UUID in the UUID "\ - "List that is used by the command.If this field is cleared to 0h,"\ + const char *scp_desc = + "[0-15]Scope(SCP) field specifies the contents of the Opcode or Feature Identifier field."; + const char *uuid_desc = "UUID Index - If this field is set to a non-zero\n" + "value, then the value of this field is the index of a UUID in the UUID\n" + "List that is used by the command.If this field is cleared to 0h,\n" "then no UUID index is specified"; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; int err = -1; struct config { @@ -7455,39 +7982,33 @@ static int lockdown_cmd(int argc, char **argv, struct command *cmd, struct plugi .uuid = 0, }; - OPT_ARGS(opts) = { - OPT_BYTE("ofi", 'o', &cfg.ofi, ofi_desc), - OPT_BYTE("ifc", 'f', &cfg.ifc, ifc_desc), - OPT_BYTE("prhbt", 'p', &cfg.prhbt, prhbt_desc), - OPT_BYTE("scp", 's', &cfg.scp, scp_desc), - OPT_BYTE("uuid", 'U', &cfg.uuid, uuid_desc), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("ofi", 'O', &cfg.ofi, ofi_desc), + OPT_BYTE("ifc", 'f', &cfg.ifc, ifc_desc), + OPT_BYTE("prhbt", 'p', &cfg.prhbt, prhbt_desc), + OPT_BYTE("scp", 's', &cfg.scp, scp_desc), + OPT_BYTE("uuid", 'U', &cfg.uuid, uuid_desc)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; /* check for input argument limit */ if (cfg.ifc > 3) { - fprintf(stderr, "invalid interface settings:%d\n", cfg.ifc); - err = -1; - goto close_dev; + nvme_show_error("invalid interface settings:%d", cfg.ifc); + return -1; } if (cfg.prhbt > 1) { - fprintf(stderr, "invalid prohibit settings:%d\n", cfg.prhbt); - err = -1; - goto close_dev; + nvme_show_error("invalid prohibit settings:%d", cfg.prhbt); + return -1; } if (cfg.scp > 15) { - fprintf(stderr, "invalid scope settings:%d\n", cfg.scp); - err = -1; - goto close_dev; + nvme_show_error("invalid scope settings:%d", cfg.scp); + return -1; } if (cfg.uuid > 127) { - fprintf(stderr, "invalid UUID index settings:%d\n", cfg.uuid); - err = -1; - goto close_dev; + nvme_show_error("invalid UUID index settings:%d", cfg.uuid); + return -1; } struct nvme_lockdown_args args = { @@ -7503,29 +8024,49 @@ static int lockdown_cmd(int argc, char **argv, struct command *cmd, struct plugi }; err = nvme_lockdown(&args); if (err < 0) - fprintf(stderr, "lockdown: %s\n", nvme_strerror(errno)); + nvme_show_error("lockdown: %s", nvme_strerror(errno)); else if (err > 0) nvme_show_status(err); else printf("Lockdown Command is Successful\n"); -close_dev: - dev_close(dev); -ret: return err; } +static void passthru_print_read_output(struct passthru_config cfg, void *data, int dfd, void *mdata, + int mfd, int err) +{ + if (strlen(cfg.input_file)) { + if (write(dfd, (void *)data, cfg.data_len) < 0) + perror("failed to write data buffer"); + } else if (data) { + if (cfg.raw_binary) + d_raw((unsigned char *)data, cfg.data_len); + else if (!err) + d((unsigned char *)data, cfg.data_len, 16, 1); + } + if (cfg.metadata_len && cfg.metadata) { + if (strlen(cfg.metadata)) { + if (write(mfd, (void *)mdata, cfg.metadata_len) < 0) + perror("failed to write metadata buffer"); + } else { + if (cfg.raw_binary) + d_raw((unsigned char *)mdata, cfg.metadata_len); + else if (!err) + d((unsigned char *)mdata, cfg.metadata_len, 16, 1); + } + } +} + static int passthru(int argc, char **argv, bool admin, const char *desc, struct command *cmd) { const char *opcode = "opcode (required)"; const char *cflags = "command flags"; const char *rsvd = "value for reserved field"; - const char *namespace_id = "desired namespace"; const char *data_len = "data I/O length (bytes)"; const char *metadata_len = "metadata seg. length (bytes)"; const char *metadata = "metadata input or output file"; - const char *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"; @@ -7535,52 +8076,24 @@ static int passthru(int argc, char **argv, bool admin, const char *cdw14 = "command dword 14 value"; const char *cdw15 = "command dword 15 value"; const char *input = "data input or output file"; - 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"; - const char *latency = "output latency statistics"; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + _cleanup_file_ int dfd = -1, mfd = -1; int flags; - int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH; - void *data = NULL, *mdata = NULL; - int err = 0, dfd, mfd; - struct nvme_dev *dev; + int mode = 0644; + void *data = NULL; + _cleanup_free_ void *mdata = NULL; + int err = 0; __u32 result; - bool huge = false; const char *cmd_name = NULL; struct timeval start_time, end_time; - 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; - char *metadata; - bool raw_binary; - bool show_command; - bool dry_run; - bool read; - bool write; - __u8 prefill; - bool latency; - }; - - struct config cfg = { + struct passthru_config cfg = { .opcode = 0, .flags = 0, .prefill = 0, @@ -7607,50 +8120,44 @@ static int passthru(int argc, char **argv, bool admin, .latency = false, }; - OPT_ARGS(opts) = { - OPT_BYTE("opcode", 'o', &cfg.opcode, opcode), - OPT_BYTE("flags", 'f', &cfg.flags, cflags), - OPT_BYTE("prefill", 'p', &cfg.prefill, prefill), - OPT_SHRT("rsvd", 'R', &cfg.rsvd, rsvd), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_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_FILE("metadata", 'M', &cfg.metadata, metadata), - 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_FLAG("latency", 'T', &cfg.latency, latency), - OPT_END() - }; + NVME_ARGS(opts, + OPT_BYTE("opcode", 'O', &cfg.opcode, opcode), + OPT_BYTE("flags", 'f', &cfg.flags, cflags), + OPT_BYTE("prefill", 'p', &cfg.prefill, prefill), + OPT_SHRT("rsvd", 'R', &cfg.rsvd, rsvd), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_UINT("data-len", 'l', &cfg.data_len, data_len), + OPT_UINT("metadata-len", 'm', &cfg.metadata_len, metadata_len), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), + OPT_UINT("cdw2", '2', &cfg.cdw2, cdw2), + OPT_UINT("cdw3", '3', &cfg.cdw3, cdw3), + OPT_UINT("cdw10", '4', &cfg.cdw10, cdw10), + OPT_UINT("cdw11", '5', &cfg.cdw11, cdw11), + OPT_UINT("cdw12", '6', &cfg.cdw12, cdw12), + OPT_UINT("cdw13", '7', &cfg.cdw13, cdw13), + OPT_UINT("cdw14", '8', &cfg.cdw14, cdw14), + OPT_UINT("cdw15", '9', &cfg.cdw15, cdw15), + OPT_FILE("input-file", 'i', &cfg.input_file, input), + OPT_FILE("metadata", 'M', &cfg.metadata, metadata), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump), + OPT_FLAG("show-command", 's', &cfg.show_command, show), + OPT_FLAG("dry-run", 'd', &cfg.dry_run, dry), + OPT_FLAG("read", 'r', &cfg.read, re), + OPT_FLAG("write", 'w', &cfg.write, wr), + OPT_FLAG("latency", 'T', &cfg.latency, latency)); err = parse_and_open(&dev, argc, argv, desc, opts); if (err) - goto ret; + return err; - if (cfg.opcode & 0x01) + if (cfg.opcode & 0x01) { cfg.write = true; - - if (cfg.opcode & 0x02) - cfg.read = true; - - if (cfg.write) { flags = O_RDONLY; dfd = mfd = STDIN_FILENO; } - if (cfg.read) { + if (cfg.opcode & 0x02) { + cfg.read = true; flags = O_WRONLY | O_CREAT; dfd = mfd = STDOUT_FILENO; } @@ -7658,56 +8165,49 @@ static int passthru(int argc, char **argv, bool admin, if (strlen(cfg.input_file)) { dfd = open(cfg.input_file, flags, mode); if (dfd < 0) { - perror(cfg.input_file); - err = -EINVAL; - goto close_dev; + nvme_show_perror(cfg.input_file); + return -EINVAL; } } if (cfg.metadata && strlen(cfg.metadata)) { mfd = open(cfg.metadata, flags, mode); if (mfd < 0) { - perror(cfg.metadata); - err = -EINVAL; - goto close_dfd; + nvme_show_perror(cfg.metadata); + return -EINVAL; } } if (cfg.metadata_len) { mdata = malloc(cfg.metadata_len); - if (!mdata) { - err = -ENOMEM; - goto close_mfd; - } + if (!mdata) + return -ENOMEM; if (cfg.write) { if (read(mfd, mdata, cfg.metadata_len) < 0) { err = -errno; - perror("failed to read metadata write buffer"); - goto free_metadata; + nvme_show_perror("failed to read metadata write buffer"); + return err; } - } else + } else { memset(mdata, cfg.prefill, cfg.metadata_len); + } } if (cfg.data_len) { - data = nvme_alloc(cfg.data_len, &huge); - if (!data) { - err = -ENOMEM; - goto free_metadata; - } + data = nvme_alloc_huge(cfg.data_len, &mh); + if (!data) + return -ENOMEM; memset(data, cfg.prefill, cfg.data_len); if (!cfg.read && !cfg.write) { - fprintf(stderr, "data direction not given\n"); - err = -EINVAL; - goto free_data; + nvme_show_error("data direction not given"); + return -EINVAL; } else if (cfg.write) { if (read(dfd, data, cfg.data_len) < 0) { err = -errno; - fprintf(stderr, "failed to read write buffer " - "%s\n", strerror(errno)); - goto free_data; + nvme_show_error("failed to read write buffer %s", strerror(errno)); + return err; } } } @@ -7732,20 +8232,20 @@ static int passthru(int argc, char **argv, bool admin, printf("timeout_ms : %08x\n", cfg.timeout); } if (cfg.dry_run) - goto free_data; + return 0; gettimeofday(&start_time, NULL); if (admin) - err = nvme_admin_passthru(dev_fd(dev), cfg.opcode, cfg.flags, - cfg.rsvd, - cfg.namespace_id, cfg.cdw2, - cfg.cdw3, cfg.cdw10, - cfg.cdw11, cfg.cdw12, cfg.cdw13, - cfg.cdw14, - cfg.cdw15, cfg.data_len, data, - cfg.metadata_len, - mdata, cfg.timeout, &result); + err = nvme_cli_admin_passthru(dev, cfg.opcode, cfg.flags, + cfg.rsvd, + cfg.namespace_id, cfg.cdw2, + cfg.cdw3, cfg.cdw10, + cfg.cdw11, cfg.cdw12, cfg.cdw13, + cfg.cdw14, + cfg.cdw15, cfg.data_len, data, + cfg.metadata_len, + mdata, cfg.timeout, &result); else err = nvme_io_passthru(dev_fd(dev), cfg.opcode, cfg.flags, cfg.rsvd, @@ -7760,59 +8260,37 @@ static int passthru(int argc, char **argv, bool admin, gettimeofday(&end_time, NULL); cmd_name = nvme_cmd_to_string(admin, cfg.opcode); if (cfg.latency) - printf("%s Command %s latency: %llu us\n", - admin ? "Admin": "IO", - strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific", - elapsed_utime(start_time, end_time)); + printf("%s Command %s latency: %llu us\n", admin ? "Admin" : "IO", + strcmp(cmd_name, "Unknown") ? cmd_name : "Vendor Specific", + elapsed_utime(start_time, end_time)); - if (err < 0) - fprintf(stderr, "passthru: %s\n", nvme_strerror(errno)); - else if (err) + if (err < 0) { + nvme_show_error("%s: %s", __func__, nvme_strerror(errno)); + } else if (err) { nvme_show_status(err); - else { - fprintf(stderr, "%s Command %s is Success and result: 0x%08x\n", - admin ? "Admin": "IO", - strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific", - result); - if (cfg.read && strlen(cfg.input_file)) { - if (write(dfd, (void *)data, cfg.data_len) < 0) - perror("failed to write data buffer"); - if (cfg.metadata_len && cfg.metadata) - if (write(mfd, (void *)mdata, cfg.metadata_len) < 0) - perror("failed to write metadata buffer"); - } else if (!cfg.raw_binary) { - 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); + } else { + fprintf(stderr, "%s Command %s is Success and result: 0x%08x\n", admin ? "Admin" : "IO", + strcmp(cmd_name, "Unknown") ? cmd_name : "Vendor Specific", result); + if (cfg.read) + passthru_print_read_output(cfg, data, dfd, mdata, mfd, err); } -free_metadata: - free(mdata); -free_data: - nvme_free(data, huge); -close_dfd: - if (strlen(cfg.input_file)) - close(dfd); -close_mfd: - if (strlen(cfg.metadata)) - close(mfd); -close_dev: - dev_close(dev); -ret: + return err; } static int io_passthru(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send a user-defined IO command to the specified "\ - "device via IOCTL passthrough, return results."; + const char *desc = + "Send a user-defined IO command to the specified device via IOCTL passthrough, return results."; + return passthru(argc, argv, false, desc, cmd); } static int admin_passthru(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send a user-defined Admin command to the specified "\ - "device via IOCTL passthrough, return results."; + const char *desc = + "Send a user-defined Admin command to the specified device via IOCTL passthrough, return results."; + return passthru(argc, argv, true, desc, cmd); } @@ -7822,8 +8300,8 @@ static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struc hostnqn = nvmf_hostnqn_generate(); if (!hostnqn) { - fprintf(stderr, "\"%s\" not supported. Install lib uuid and rebuild.\n", - command->name); + nvme_show_error("\"%s\" not supported. Install lib uuid and rebuild.", + command->name); return -ENOTSUP; } printf("%s\n", hostnqn); @@ -7840,8 +8318,8 @@ static int show_hostnqn_cmd(int argc, char **argv, struct command *command, stru hostnqn = nvmf_hostnqn_generate(); if (!hostnqn) { - fprintf(stderr, "hostnqn is not available -- use nvme gen-hostnqn\n"); - return ENOENT; + nvme_show_error("hostnqn is not available -- use nvme gen-hostnqn"); + return -ENOENT; } fprintf(stdout, "%s\n", hostnqn); @@ -7853,14 +8331,13 @@ static int show_hostnqn_cmd(int argc, char **argv, struct command *command, stru static int gen_dhchap_key(int argc, char **argv, struct command *command, struct plugin *plugin) { - const char *desc = "Generate a DH-HMAC-CHAP host key usable "\ - "for NVMe In-Band Authentication."; - const char *secret = "Optional secret (in hexadecimal characters) "\ - "to be used to initialize the host key."; - const char *key_len = "Length of the resulting key "\ - "(32, 48, or 64 bytes)."; - const char *hmac = "HMAC function to use for key transformation "\ - "(0 = none, 1 = SHA-256, 2 = SHA-384, 3 = SHA-512)."; + const char *desc = + "Generate a DH-HMAC-CHAP host key usable for NVMe In-Band Authentication."; + const char *secret = + "Optional secret (in hexadecimal characters) to be used to initialize the host key."; + const char *key_len = "Length of the resulting key (32, 48, or 64 bytes)."; + const char *hmac = + "HMAC function to use for key transformation (0 = none, 1 = SHA-256, 2 = SHA-384, 3 = SHA-512)."; const char *nqn = "Host NQN to use for key transformation."; unsigned char *raw_secret; @@ -7883,59 +8360,55 @@ static int gen_dhchap_key(int argc, char **argv, struct command *command, struct .hmac = 0, }; - OPT_ARGS(opts) = { - OPT_STR("secret", 's', &cfg.secret, secret), - OPT_UINT("key-length", 'l', &cfg.key_len, key_len), - OPT_STR("nqn", 'n', &cfg.nqn, nqn), - OPT_UINT("hmac", 'm', &cfg.hmac, hmac), - OPT_END() - }; + NVME_ARGS(opts, + OPT_STR("secret", 's', &cfg.secret, secret), + OPT_UINT("key-length", 'l', &cfg.key_len, key_len), + OPT_STR("nqn", 'n', &cfg.nqn, nqn), + OPT_UINT("hmac", 'm', &cfg.hmac, hmac)); err = argconfig_parse(argc, argv, desc, opts); if (err) return err; if (cfg.hmac > 3) { - fprintf(stderr, "Invalid HMAC identifier %u\n", cfg.hmac); + nvme_show_error("Invalid HMAC identifier %u", cfg.hmac); return -EINVAL; } if (cfg.hmac > 0) { switch (cfg.hmac) { case 1: - if (!cfg.key_len) + if (!cfg.key_len) { cfg.key_len = 32; - else if (cfg.key_len != 32) { - fprintf(stderr, "Invalid key length %d for SHA(256)\n", - cfg.key_len); + } else if (cfg.key_len != 32) { + nvme_show_error("Invalid key length %d for SHA(256)", cfg.key_len); return -EINVAL; } break; case 2: - if (!cfg.key_len) + if (!cfg.key_len) { cfg.key_len = 48; - else if (cfg.key_len != 48) { - fprintf(stderr, "Invalid key length %d for SHA(384)\n", - cfg.key_len); + } else if (cfg.key_len != 48) { + nvme_show_error("Invalid key length %d for SHA(384)", cfg.key_len); return -EINVAL; } break; case 3: - if (!cfg.key_len) + if (!cfg.key_len) { cfg.key_len = 64; - else if (cfg.key_len != 64) { - fprintf(stderr, "Invalid key length %d for SHA(512)\n", - cfg.key_len); + } else if (cfg.key_len != 64) { + nvme_show_error("Invalid key length %d for SHA(512)", cfg.key_len); return -EINVAL; } break; default: break; } - } else if (!cfg.key_len) + } else if (!cfg.key_len) { cfg.key_len = 32; + } if (cfg.key_len != 32 && cfg.key_len != 48 && cfg.key_len != 64) { - fprintf(stderr, "Invalid key length %u\n", cfg.key_len); + nvme_show_error("Invalid key length %u", cfg.key_len); return -EINVAL; } raw_secret = malloc(cfg.key_len); @@ -7948,17 +8421,15 @@ static int gen_dhchap_key(int argc, char **argv, struct command *command, struct int secret_len = 0, i; unsigned int c; - for (i = 0; i < strlen(cfg.secret); i+=2) { + for (i = 0; i < strlen(cfg.secret); i += 2) { if (sscanf(&cfg.secret[i], "%02x", &c) != 1) { - fprintf(stderr, "Invalid secret '%s'\n", - cfg.secret); + nvme_show_error("Invalid secret '%s'", cfg.secret); return -EINVAL; } raw_secret[secret_len++] = (unsigned char)c; } if (secret_len != cfg.key_len) { - fprintf(stderr, "Invalid key length (%d bytes)\n", - secret_len); + nvme_show_error("Invalid key length (%d bytes)", secret_len); return -EINVAL; } } @@ -7966,13 +8437,12 @@ static int gen_dhchap_key(int argc, char **argv, struct command *command, struct if (!cfg.nqn) { cfg.nqn = nvmf_hostnqn_from_file(); if (!cfg.nqn) { - fprintf(stderr, "Could not read host NQN\n"); + nvme_show_error("Could not read host NQN"); return -ENOENT; } } - if (nvme_gen_dhchap_key(cfg.nqn, cfg.hmac, cfg.key_len, - raw_secret, key) < 0) + if (nvme_gen_dhchap_key(cfg.nqn, cfg.hmac, cfg.key_len, raw_secret, key) < 0) return -errno; crc = crc32(crc, key, cfg.key_len); @@ -7990,10 +8460,9 @@ static int gen_dhchap_key(int argc, char **argv, struct command *command, struct static int check_dhchap_key(int argc, char **argv, struct command *command, struct plugin *plugin) { - const char *desc = "Check a DH-HMAC-CHAP host key for usability "\ - "for NVMe In-Band Authentication."; - const char *key = "DH-HMAC-CHAP key (in hexadecimal characters) "\ - "to be validated."; + const char *desc = + "Check a DH-HMAC-CHAP host key for usability for NVMe In-Band Authentication."; + const char *key = "DH-HMAC-CHAP key (in hexadecimal characters) to be validated."; unsigned char decoded_key[128]; unsigned int decoded_len; @@ -8008,22 +8477,20 @@ static int check_dhchap_key(int argc, char **argv, struct command *command, stru .key = NULL, }; - OPT_ARGS(opts) = { - OPT_STR("key", 'k', &cfg.key, key), - OPT_END() - }; + NVME_ARGS(opts, + OPT_STR("key", 'k', &cfg.key, key)); err = argconfig_parse(argc, argv, desc, opts); if (err) return err; if (!cfg.key) { - fprintf(stderr, "Key not specified\n"); + nvme_show_error("Key not specified"); return -EINVAL; } if (sscanf(cfg.key, "DHHC-1:%02x:*s", &hmac) != 1) { - fprintf(stderr, "Invalid key header '%s'\n", cfg.key); + nvme_show_error("Invalid key header '%s'", cfg.key); return -EINVAL; } switch (hmac) { @@ -8031,99 +8498,132 @@ static int check_dhchap_key(int argc, char **argv, struct command *command, stru break; case 1: if (strlen(cfg.key) != 59) { - fprintf(stderr, "Invalid key length for SHA(256)\n"); + nvme_show_error("Invalid key length for SHA(256)"); return -EINVAL; } break; case 2: if (strlen(cfg.key) != 83) { - fprintf(stderr, "Invalid key length for SHA(384)\n"); + nvme_show_error("Invalid key length for SHA(384)"); return -EINVAL; } break; case 3: if (strlen(cfg.key) != 103) { - fprintf(stderr, "Invalid key length for SHA(512)\n"); + nvme_show_error("Invalid key length for SHA(512)"); return -EINVAL; } break; default: - fprintf(stderr, "Invalid HMAC identifier %d\n", hmac); + nvme_show_error("Invalid HMAC identifier %d", hmac); return -EINVAL; - break; } - err = base64_decode(cfg.key + 10, strlen(cfg.key) - 11, - decoded_key); + err = base64_decode(cfg.key + 10, strlen(cfg.key) - 11, decoded_key); if (err < 0) { - fprintf(stderr, "Base64 decoding failed, error %d\n", - err); + nvme_show_error("Base64 decoding failed, error %d", err); return err; } decoded_len = err; if (decoded_len < 32) { - fprintf(stderr, "Base64 decoding failed (%s, size %u)\n", - cfg.key + 10, decoded_len); + nvme_show_error("Base64 decoding failed (%s, size %u)", cfg.key + 10, decoded_len); return -EINVAL; } decoded_len -= 4; if (decoded_len != 32 && decoded_len != 48 && decoded_len != 64) { - fprintf(stderr, "Invalid key length %d\n", decoded_len); + nvme_show_error("Invalid key length %d", decoded_len); return -EINVAL; } crc = crc32(crc, decoded_key, decoded_len); key_crc = ((u_int32_t)decoded_key[decoded_len]) | - ((u_int32_t)decoded_key[decoded_len + 1] << 8) | - ((u_int32_t)decoded_key[decoded_len + 2] << 16) | - ((u_int32_t)decoded_key[decoded_len + 3] << 24); + ((u_int32_t)decoded_key[decoded_len + 1] << 8) | + ((u_int32_t)decoded_key[decoded_len + 2] << 16) | + ((u_int32_t)decoded_key[decoded_len + 3] << 24); if (key_crc != crc) { - fprintf(stderr, "CRC mismatch (key %08x, crc %08x)\n", - key_crc, crc); + nvme_show_error("CRC mismatch (key %08x, crc %08x)", key_crc, crc); return -EINVAL; } - printf("Key is valid (HMAC %d, length %d, CRC %08x)\n", - hmac, decoded_len, crc); + printf("Key is valid (HMAC %d, length %d, CRC %08x)\n", hmac, decoded_len, crc); return 0; } static int gen_tls_key(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Generate a TLS key in NVMe PSK Interchange format."; - const char *secret = "Optional secret (in hexadecimal characters) "\ - "to be used for the TLS key."; - const char *hmac = "HMAC function to use for the retained key "\ - "(1 = SHA-256, 2 = SHA-384)."; + const char *secret = + "Optional secret (in hexadecimal characters) to be used for the TLS key."; + const char *hmac = "HMAC function to use for the retained key (1 = SHA-256, 2 = SHA-384)."; + const char *identity = "TLS identity version to use (0 = NVMe TCP 1.0c, 1 = NVMe TCP 2.0"; + const char *hostnqn = "Host NQN for the retained key."; + const char *subsysnqn = "Subsystem NQN for the retained key."; + const char *keyring = "Keyring for the retained key."; + const char *keytype = "Key type of the retained key."; + const char *insert = "Insert only, do not print the retained key."; unsigned char *raw_secret; char encoded_key[128]; int key_len = 32; unsigned long crc = crc32(0L, NULL, 0); - int err = 0; + int err; + long tls_key; struct config { + char *keyring; + char *keytype; + char *hostnqn; + char *subsysnqn; char *secret; unsigned int hmac; + unsigned int identity; + bool insert; }; struct config cfg = { + .keyring = ".nvme", + .keytype = "psk", + .hostnqn = NULL, + .subsysnqn = NULL, .secret = NULL, .hmac = 1, + .identity = 0, + .insert = false, }; - OPT_ARGS(opts) = { - OPT_STR("secret", 's', &cfg.secret, secret), - OPT_UINT("hmac", 'm', &cfg.hmac, hmac), - OPT_END() - }; + NVME_ARGS(opts, + OPT_STR("keyring", 'k', &cfg.keyring, keyring), + OPT_STR("keytype", 't', &cfg.keytype, keytype), + OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn), + OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn), + OPT_STR("secret", 's', &cfg.secret, secret), + OPT_UINT("hmac", 'm', &cfg.hmac, hmac), + OPT_UINT("identity", 'I', &cfg.identity, identity), + OPT_FLAG("insert", 'i', &cfg.insert, insert)); err = argconfig_parse(argc, argv, desc, opts); if (err) return err; - if (cfg.hmac < 1 || cfg.hmac > 3) { - fprintf(stderr, "Invalid HMAC identifier %u\n", cfg.hmac); + if (cfg.hmac < 1 || cfg.hmac > 2) { + nvme_show_error("Invalid HMAC identifier %u", cfg.hmac); return -EINVAL; } - + if (cfg.identity > 1) { + nvme_show_error("Invalid TLS identity version %u", + cfg.identity); + return -EINVAL; + } + if (cfg.insert) { + if (!cfg.subsysnqn) { + nvme_show_error("No subsystem NQN specified"); + return -EINVAL; + } + if (!cfg.hostnqn) { + cfg.hostnqn = nvmf_hostnqn_from_file(); + if (!cfg.hostnqn) { + nvme_show_error("Failed to read host NQN"); + return -EINVAL; + } + } + } if (cfg.hmac == 2) key_len = 48; @@ -8137,26 +8637,36 @@ static int gen_tls_key(int argc, char **argv, struct command *command, struct pl int secret_len = 0, i; unsigned int c; - for (i = 0; i < strlen(cfg.secret); i+=2) { + for (i = 0; i < strlen(cfg.secret); i += 2) { if (sscanf(&cfg.secret[i], "%02x", &c) != 1) { - fprintf(stderr, "Invalid secret '%s'\n", - cfg.secret); + nvme_show_error("Invalid secret '%s'", cfg.secret); return -EINVAL; } - if (i >= key_len) { - fprintf(stderr, - "Skipping excess secret bytes\n"); + if (i >= key_len * 2) { + fprintf(stderr, "Skipping excess secret bytes\n"); break; } raw_secret[secret_len++] = (unsigned char)c; } if (secret_len != key_len) { - fprintf(stderr, "Invalid key length (%d bytes)\n", - secret_len); + nvme_show_error("Invalid key length (%d bytes)", secret_len); return -EINVAL; } } + if (cfg.insert) { + tls_key = nvme_insert_tls_key_versioned(cfg.keyring, + cfg.keytype, cfg.hostnqn, + cfg.subsysnqn, cfg.identity, + cfg.hmac, raw_secret, key_len); + if (tls_key < 0) { + nvme_show_error("Failed to insert key, error %d", errno); + return -errno; + } + + printf("Inserted TLS key %08x\n", (unsigned int)tls_key); + return 0; + } crc = crc32(crc, raw_secret, key_len); raw_secret[key_len++] = crc & 0xff; raw_secret[key_len++] = (crc >> 8) & 0xff; @@ -8173,72 +8683,106 @@ static int gen_tls_key(int argc, char **argv, struct command *command, struct pl static int check_tls_key(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Check a TLS key for NVMe PSK Interchange format.\n"; - const char *key = "TLS key (in PSK Interchange format) "\ - "to be validated."; + const char *keydata = "TLS key (in PSK Interchange format) to be validated."; + const char *identity = "TLS identity version to use (0 = NVMe TCP 1.0c, 1 = NVMe TCP 2.0)"; + const char *hostnqn = "Host NQN for the retained key."; + const char *subsysnqn = "Subsystem NQN for the retained key."; + const char *keyring = "Keyring for the retained key."; + const char *keytype = "Key type of the retained key."; + const char *insert = "Insert retained key into the keyring."; unsigned char decoded_key[128]; unsigned int decoded_len; u_int32_t crc = crc32(0L, NULL, 0); u_int32_t key_crc; int err = 0, hmac; + long tls_key; struct config { - char *key; + char *keyring; + char *keytype; + char *hostnqn; + char *subsysnqn; + char *keydata; + unsigned int identity; + bool insert; }; struct config cfg = { - .key = NULL, - }; - - OPT_ARGS(opts) = { - OPT_STR("key", 'k', &cfg.key, key), - OPT_END() - }; + .keyring = ".nvme", + .keytype = "psk", + .hostnqn = NULL, + .subsysnqn = NULL, + .keydata = NULL, + .identity = 0, + .insert = false, + }; + + NVME_ARGS(opts, + OPT_STR("keyring", 'k', &cfg.keyring, keyring), + OPT_STR("keytype", 't', &cfg.keytype, keytype), + OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn), + OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn), + OPT_STR("keydata", 'd', &cfg.keydata, keydata), + OPT_UINT("identity", 'I', &cfg.identity, identity), + OPT_FLAG("insert", 'i', &cfg.insert, insert)); err = argconfig_parse(argc, argv, desc, opts); if (err) return err; - if (!cfg.key) { - fprintf(stderr, "Key not specified\n"); + if (!cfg.keydata) { + nvme_show_error("No key data"); + return -EINVAL; + } + if (cfg.identity > 1) { + nvme_show_error("Invalid TLS identity version %u", + cfg.identity); return -EINVAL; } - if (sscanf(cfg.key, "NVMeTLSkey-1:%02x:*s", &hmac) != 1) { - fprintf(stderr, "Invalid key header '%s'\n", cfg.key); + if (sscanf(cfg.keydata, "NVMeTLSkey-1:%02x:*s", &hmac) != 1) { + nvme_show_error("Invalid key '%s'", cfg.keydata); return -EINVAL; } switch (hmac) { case 1: - if (strlen(cfg.key) != 65) { - fprintf(stderr, "Invalid key length %lu for SHA(256)\n", - strlen(cfg.key)); + if (strlen(cfg.keydata) != 65) { + nvme_show_error("Invalid key length %zu for SHA(256)", strlen(cfg.keydata)); return -EINVAL; } break; case 2: - if (strlen(cfg.key) != 89) { - fprintf(stderr, "Invalid key length %lu for SHA(384)\n", - strlen(cfg.key)); + if (strlen(cfg.keydata) != 89) { + nvme_show_error("Invalid key length %zu for SHA(384)", strlen(cfg.keydata)); return -EINVAL; } break; default: - fprintf(stderr, "Invalid HMAC identifier %d\n", hmac); + nvme_show_error("Invalid HMAC identifier %d", hmac); return -EINVAL; - break; } - err = base64_decode(cfg.key + 16, strlen(cfg.key) - 17, - decoded_key); + if (cfg.subsysnqn) { + if (cfg.insert && !cfg.hostnqn) { + cfg.hostnqn = nvmf_hostnqn_from_file(); + if (!cfg.hostnqn) { + nvme_show_error("Failed to read host NQN"); + return -EINVAL; + } + } + } else if (cfg.insert || cfg.identity == 1) { + nvme_show_error("Need to specify a subsystem NQN"); + return -EINVAL; + } + err = base64_decode(cfg.keydata + 16, strlen(cfg.keydata) - 17, decoded_key); if (err < 0) { - fprintf(stderr, "Base64 decoding failed (%s, error %d)\n", - cfg.key + 16, err); + nvme_show_error("Base64 decoding failed (%s, error %d)", cfg.keydata + 16, err); return err; } decoded_len = err; decoded_len -= 4; if (decoded_len != 32 && decoded_len != 48) { - fprintf(stderr, "Invalid key length %d\n", decoded_len); + nvme_show_error("Invalid key length %d", decoded_len); return -EINVAL; } crc = crc32(crc, decoded_key, decoded_len); @@ -8247,36 +8791,122 @@ static int check_tls_key(int argc, char **argv, struct command *command, struct ((u_int32_t)decoded_key[decoded_len + 2] << 16) | ((u_int32_t)decoded_key[decoded_len + 3] << 24); if (key_crc != crc) { - fprintf(stderr, "CRC mismatch (key %08x, crc %08x)\n", - key_crc, crc); + nvme_show_error("CRC mismatch (key %08x, crc %08x)", key_crc, crc); return -EINVAL; } - printf("Key is valid (HMAC %d, length %d, CRC %08x)\n", - hmac, decoded_len, crc); + if (cfg.insert) { + tls_key = nvme_insert_tls_key_versioned(cfg.keyring, + cfg.keytype, cfg.hostnqn, + cfg.subsysnqn, cfg.identity, + hmac, decoded_key, decoded_len); + if (tls_key < 0) { + nvme_show_error("Failed to insert key, error %d", errno); + return -errno; + } + printf("Inserted TLS key %08x\n", (unsigned int)tls_key); + } else { + char *tls_id; + + tls_id = nvme_generate_tls_key_identity(cfg.hostnqn, + cfg.subsysnqn, cfg.identity, + hmac, decoded_key, decoded_len); + if (!tls_id) { + nvme_show_error("Failed to generate identity, error %d", + errno); + return -errno; + } + printf("%s\n", tls_id); + free(tls_id); + } return 0; } +static int show_topology_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) +{ + const char *desc = "Show the topology\n"; + const char *ranking = "Ranking order: namespace|ctrl"; + enum nvme_print_flags flags; + nvme_root_t r; + enum nvme_cli_topo_ranking rank; + int err; + + struct config { + char *ranking; + }; + + struct config cfg = { + .ranking = "namespace", + }; + + NVME_ARGS(opts, + OPT_FMT("ranking", 'r', &cfg.ranking, ranking)); + + err = argconfig_parse(argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(output_format_val, &flags); + if (err < 0) { + nvme_show_error("Invalid output format"); + return err; + } + + if (argconfig_parse_seen(opts, "verbose")) + flags |= VERBOSE; + + if (!strcmp(cfg.ranking, "namespace")) { + rank = NVME_CLI_TOPO_NAMESPACE; + } else if (!strcmp(cfg.ranking, "ctrl")) { + rank = NVME_CLI_TOPO_CTRL; + } else { + nvme_show_error("Invalid ranking argument: %s", cfg.ranking); + return -EINVAL; + } + + r = nvme_create_root(stderr, log_level); + if (!r) { + nvme_show_error("Failed to create topology root: %s", nvme_strerror(errno)); + return -errno; + } + + err = nvme_scan_topology(r, NULL, NULL); + if (err < 0) { + nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno)); + nvme_free_tree(r); + return err; + } + + nvme_show_topology(r, rank, flags); + nvme_free_tree(r); + + return err; +} + static int discover_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Send Get Log Page request to Discovery Controller."; + return nvmf_discover(desc, argc, argv, false); } static int connect_all_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Discover NVMeoF subsystems and connect to them"; + return nvmf_discover(desc, argc, argv, true); } static int connect_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Connect to NVMeoF subsystem"; + return nvmf_connect(desc, argc, argv); } static int disconnect_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Disconnect from NVMeoF subsystem"; + return nvmf_disconnect(desc, argc, argv); } @@ -8284,21 +8914,148 @@ int disconnect_all_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Disconnect from all connected NVMeoF subsystems"; + return nvmf_disconnect_all(desc, argc, argv); } static int config_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Configuration of NVMeoF subsystems"; + return nvmf_config(desc, argc, argv); } static int dim_cmd(int argc, char **argv, struct command *command, struct plugin *plugin) { - const char *desc = "Send Discovery Information Management command to a Discovery Controller (DC)"; + const char *desc = + "Send Discovery Information Management command to a Discovery Controller (DC)"; + return nvmf_dim(desc, argc, argv); } +static int nvme_mi(int argc, char **argv, __u8 admin_opcode, const char *desc) +{ + const char *opcode = "opcode (required)"; + const char *data_len = "data I/O length (bytes)"; + const char *nmimt = "nvme-mi message type"; + const char *nmd0 = "nvme management dword 0 value"; + const char *nmd1 = "nvme management dword 1 value"; + const char *input = "data input or output file"; + + int mode = 0644; + void *data = NULL; + int err = 0; + bool send; + _cleanup_file_ int fd = -1; + int flags; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + __u32 result; + + struct config { + __u8 opcode; + __u32 namespace_id; + __u32 data_len; + __u32 nmimt; + __u32 nmd0; + __u32 nmd1; + char *input_file; + }; + + struct config cfg = { + .opcode = 0, + .namespace_id = 0, + .data_len = 0, + .nmimt = 0, + .nmd0 = 0, + .nmd1 = 0, + .input_file = "", + }; + + NVME_ARGS(opts, + OPT_BYTE("opcode", 'O', &cfg.opcode, opcode), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired), + OPT_UINT("data-len", 'l', &cfg.data_len, data_len), + OPT_UINT("nmimt", 'm', &cfg.nmimt, nmimt), + OPT_UINT("nmd0", '0', &cfg.nmd0, nmd0), + OPT_UINT("nmd1", '1', &cfg.nmd1, nmd1), + OPT_FILE("input-file", 'i', &cfg.input_file, input)); + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (admin_opcode == nvme_admin_nvme_mi_send) { + flags = O_RDONLY; + fd = STDIN_FILENO; + send = true; + } else { + flags = O_WRONLY | O_CREAT; + fd = STDOUT_FILENO; + send = false; + } + + if (strlen(cfg.input_file)) { + fd = open(cfg.input_file, flags, mode); + if (fd < 0) { + nvme_show_perror(cfg.input_file); + return -EINVAL; + } + } + + if (cfg.data_len) { + data = nvme_alloc_huge(cfg.data_len, &mh); + if (!data) + return -ENOMEM; + + if (send) { + if (read(fd, data, cfg.data_len) < 0) { + err = -errno; + nvme_show_error("failed to read write buffer %s", strerror(errno)); + return err; + } + } + } + + err = nvme_cli_admin_passthru(dev, admin_opcode, 0, 0, cfg.namespace_id, 0, 0, + cfg.nmimt << 11 | 4, cfg.opcode, cfg.nmd0, cfg.nmd1, 0, 0, + cfg.data_len, data, 0, NULL, 0, &result); + if (err < 0) { + nvme_show_error("nmi_recv: %s", nvme_strerror(errno)); + } else if (err) { + nvme_show_status(err); + } else { + printf( + "%s Command is Success and result: 0x%08x (status: 0x%02x, response: 0x%06x)\n", + nvme_cmd_to_string(true, admin_opcode), result, result & 0xff, result >> 8); + if (result & 0xff) + printf("status: %s\n", nvme_mi_status_to_string(result & 0xff)); + if (!send && strlen(cfg.input_file)) { + if (write(fd, (void *)data, cfg.data_len) < 0) + perror("failed to write data buffer"); + } else if (data && !send && !err) { + d((unsigned char *)data, cfg.data_len, 16, 1); + } + } + + return err; +} + +static int nmi_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = + "Send a NVMe-MI Receive command to the specified device, return results."; + + return nvme_mi(argc, argv, nvme_admin_nvme_mi_recv, desc); +} + +static int nmi_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Send a NVMe-MI Send command to the specified device, return results."; + + return nvme_mi(argc, argv, nvme_admin_nvme_mi_send, desc); +} + void register_extension(struct plugin *plugin) { plugin->parent = &nvme; diff --git a/nvme.h b/nvme.h index 8ecc2918d9..d0aca2aee9 100644 --- a/nvme.h +++ b/nvme.h @@ -28,7 +28,9 @@ #include "plugin.h" #include "util/json.h" +#include "util/mem.h" #include "util/argconfig.h" +#include "util/cleanup.h" enum nvme_print_flags { NORMAL = 0, @@ -38,6 +40,11 @@ enum nvme_print_flags { BINARY = 1 << 3, /* binary dump raw bytes */ }; +enum nvme_cli_topo_ranking { + NVME_CLI_TOPO_NAMESPACE, + NVME_CLI_TOPO_CTRL, +}; + #define SYS_NVME "/sys/class/nvme" enum nvme_dev_type { @@ -91,30 +98,26 @@ void register_extension(struct plugin *plugin); * parse_and_open - parses arguments and opens the NVMe device, populating @dev */ int parse_and_open(struct nvme_dev **dev, int argc, char **argv, const char *desc, - const struct argconfig_commandline_options *clo); + struct argconfig_commandline_options *clo); void dev_close(struct nvme_dev *dev); +static inline DEFINE_CLEANUP_FUNC( + cleanup_nvme_dev, struct nvme_dev *, dev_close) +#define _cleanup_nvme_dev_ __cleanup__(cleanup_nvme_dev) + extern const char *output_format; -enum nvme_print_flags validate_output_format(const char *format); +int validate_output_format(const char *format, enum nvme_print_flags *flags); +bool nvme_is_output_format_json(void); int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, void (*vs)(uint8_t *vs, struct json_object *root)); -extern int current_index; -void *nvme_alloc(size_t len, bool *huge); -void nvme_free(void *p, bool huge); const char *nvme_strerror(int errnum); unsigned long long elapsed_utime(struct timeval start_time, struct timeval end_time); -static inline void nvme_strip_spaces(char *s, int l) -{ - while (l && (s[l] == '\0' || s[l] == ' ')) - s[l--] = '\0'; -} - /* nvme-print.c */ const char *nvme_select_to_string(int sel); @@ -122,5 +125,4 @@ void d(unsigned char *buf, int len, int width, int group); void d_raw(unsigned char *buf, unsigned len); uint64_t int48_to_long(uint8_t *data); -int map_log_level(int verbose, bool quiet); #endif /* _NVME_H */ diff --git a/nvme.spec.in b/nvme.spec.in index fe4675a7bb..43fc9303f3 100644 --- a/nvme.spec.in +++ b/nvme.spec.in @@ -30,11 +30,13 @@ touch %{buildroot}@SYSCONFDIR@/nvme/hostid @SYSCONFDIR@/nvme/hostid @SYSCONFDIR@/nvme/discovery.conf %ghost @SYSCONFDIR@/nvme/config.json +@UDEVRULESDIR@/65-persistent-net-nbft.rules @UDEVRULESDIR@/70-nvmf-autoconnect.rules -@UDEVRULESDIR@/71-nvmf-iopolicy-netapp.rules +@UDEVRULESDIR@/71-nvmf-netapp.rules @DRACUTRILESDIR@/70-nvmf-autoconnect.conf @SYSTEMDDIR@/nvmf-connect@.service @SYSTEMDDIR@/nvmefc-boot-connections.service +@SYSTEMDDIR@/nvmf-connect-nbft.service @SYSTEMDDIR@/nvmf-connect.target @SYSTEMDDIR@/nvmf-autoconnect.service diff --git a/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in b/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in index 33ab8c1f61..7036625c77 100644 --- a/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in +++ b/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in @@ -1,6 +1,9 @@ [Unit] Description=Auto-connect to subsystems on FC-NVME devices found during boot ConditionPathExists=/sys/class/fc/fc_udev_device/nvme_discovery +DefaultDependencies=no +After=systemd-udevd.service +Before=local-fs-pre.target [Service] Type=oneshot diff --git a/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in b/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in index d83d9a1ad0..92960cde61 100644 --- a/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in +++ b/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in @@ -1,13 +1,15 @@ [Unit] Description=Connect NVMe-oF subsystems automatically during boot -ConditionPathExists=@SYSCONFDIR@/nvme/discovery.conf +ConditionPathExists=|@SYSCONFDIR@/nvme/config.json +ConditionPathExists=|@SYSCONFDIR@/nvme/discovery.conf +Wants=modprobe@nvme_fabrics.service +After=modprobe@nvme_fabrics.service After=network-online.target Before=remote-fs-pre.target [Service] Type=oneshot -ExecStartPre=/sbin/modprobe nvme-fabrics -ExecStart=@SBINDIR@/nvme connect-all +ExecStart=@SBINDIR@/nvme connect-all --context=autoconnect [Install] WantedBy=default.target diff --git a/nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in b/nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in new file mode 100644 index 0000000000..820e6ced2c --- /dev/null +++ b/nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in @@ -0,0 +1,14 @@ +# This unit is meant to be started by network management software +# after a network interface defined in the NBFT gets set up +[Unit] +Description=Connect NBFT-defined NVMe-oF subsystems automatically +ConditionPathExists=|/sys/firmware/acpi/tables/NBFT +ConditionPathExists=|/sys/firmware/acpi/tables/NBFT1 +Wants=modprobe@nvme_fabrics.service +After=modprobe@nvme_fabrics.service +After=network-online.target +Before=remote-fs-pre.target + +[Service] +Type=oneshot +ExecStart=@SBINDIR@/nvme connect-all --nbft diff --git a/nvmf-autoconnect/systemd/nvmf-connect@.service.in b/nvmf-autoconnect/systemd/nvmf-connect@.service.in index 90f774c55a..5ba70863e6 100644 --- a/nvmf-autoconnect/systemd/nvmf-connect@.service.in +++ b/nvmf-autoconnect/systemd/nvmf-connect@.service.in @@ -4,11 +4,13 @@ [Unit] Description=NVMf auto-connect scan upon nvme discovery controller Events -After=syslog.target +DefaultDependencies=no +After=systemd-udevd.service +Before=local-fs-pre.target PartOf=nvmf-connect.target Requires=nvmf-connect.target [Service] Type=simple Environment="CONNECT_ARGS=%i" -ExecStart=/bin/sh -c "@SBINDIR@/nvme connect-all --quiet `/bin/echo -e '${CONNECT_ARGS}'`" +ExecStart=/bin/sh -c "@SBINDIR@/nvme connect-all --context=autoconnect --quiet `/bin/echo -e '${CONNECT_ARGS}'`" diff --git a/nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in b/nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in new file mode 100644 index 0000000000..344942bca0 --- /dev/null +++ b/nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in @@ -0,0 +1,2 @@ +# Avoid renaming nbft$X interfaces +SUBSYSTEM=="net", ACTION!="remove", ENV{INTERFACE}=="nbft*", NAME:="%E{INTERFACE}" diff --git a/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in b/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in index 434cc080ff..9235a5c696 100644 --- a/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in +++ b/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in @@ -4,16 +4,29 @@ # controller and connect to elements in the discovery log. # # +ACTION!="change", GOTO="autoconnect_end" + +# For backwards compatibility. Make sure HOST_IFACE is not an empty string. +ENV{NVME_HOST_IFACE}=="", ENV{NVME_HOST_IFACE}="none" # Events from persistent discovery controllers or nvme-fc transport events # NVME_AEN: # type 0x2 (NOTICE) info 0xf0 (DISCOVERY_LOG_CHANGE) log-page-id 0x70 (DISCOVERY_LOG_PAGE) -ACTION=="change", SUBSYSTEM=="nvme", ENV{NVME_AEN}=="0x70f002",\ +ACTION=="change", SUBSYSTEM=="nvme", ENV{NVME_AEN}=="0x70f002", \ ENV{NVME_TRTYPE}=="*", ENV{NVME_TRADDR}=="*", \ - ENV{NVME_TRSVCID}=="*", ENV{NVME_HOST_TRADDR}=="*", \ - RUN+="@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" + ENV{NVME_TRSVCID}=="*", ENV{NVME_HOST_TRADDR}=="*", ENV{NVME_HOST_IFACE}=="*", \ + RUN+="@SYSTEMCTL@ --no-block restart nvmf-connect@--device=$kernel\t--transport=$env{NVME_TRTYPE}\t--traddr=$env{NVME_TRADDR}\t--trsvcid=$env{NVME_TRSVCID}\t--host-traddr=$env{NVME_HOST_TRADDR}\t--host-iface=$env{NVME_HOST_IFACE}.service" # nvme-fc transport generated events (old-style for compatibility) ACTION=="change", SUBSYSTEM=="fc", ENV{FC_EVENT}=="nvmediscovery", \ ENV{NVMEFC_HOST_TRADDR}=="*", ENV{NVMEFC_TRADDR}=="*", \ - RUN+="@SYSTEMCTL@ --no-block start nvmf-connect@--device=none\t--transport=fc\t--traddr=$env{NVMEFC_TRADDR}\t--trsvcid=none\t--host-traddr=$env{NVMEFC_HOST_TRADDR}.service" + RUN+="@SYSTEMCTL@ --no-block restart nvmf-connect@--device=none\t--transport=fc\t--traddr=$env{NVMEFC_TRADDR}\t--trsvcid=none\t--host-traddr=$env{NVMEFC_HOST_TRADDR}.service" + +# A discovery controller just (re)connected, re-read the discovery log change to +# check if there were any changes since it was last connected. +ACTION=="change", SUBSYSTEM=="nvme", ENV{NVME_EVENT}=="rediscover", ATTR{cntrltype}=="discovery", \ + ENV{NVME_TRTYPE}=="*", ENV{NVME_TRADDR}=="*", \ + ENV{NVME_TRSVCID}=="*", ENV{NVME_HOST_TRADDR}=="*", ENV{NVME_HOST_IFACE}=="*", \ + RUN+="@SYSTEMCTL@ --no-block restart nvmf-connect@--device=$kernel\t--transport=$env{NVME_TRTYPE}\t--traddr=$env{NVME_TRADDR}\t--trsvcid=$env{NVME_TRSVCID}\t--host-traddr=$env{NVME_HOST_TRADDR}\t--host-iface=$env{NVME_HOST_IFACE}.service" + +LABEL="autoconnect_end" diff --git a/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in b/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in deleted file mode 100644 index aefd9d49e8..0000000000 --- a/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in +++ /dev/null @@ -1,3 +0,0 @@ -# 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/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in b/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in new file mode 100644 index 0000000000..99b6a8ba0b --- /dev/null +++ b/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in @@ -0,0 +1,6 @@ +# Enable round-robin for NetApp ONTAP and NetApp E-Series +ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="NetApp ONTAP Controller", ATTR{iopolicy}="round-robin" +ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="NetApp E-Series", ATTR{iopolicy}="round-robin" + +# Set ctrl_loss_tmo to -1 for NetApp ONTAP NVMe/TCP +ACTION!="remove", SUBSYSTEM=="nvme", KERNEL=="nvme*", ATTR{transport}=="tcp", ATTR{model}=="NetApp ONTAP Controller", ATTR{ctrl_loss_tmo}="-1" diff --git a/plugin.c b/plugin.c index c05bb72d2a..a5cb4f995a 100644 --- a/plugin.c +++ b/plugin.c @@ -9,7 +9,7 @@ #include -static int version(struct plugin *plugin) +static int version_cmd(struct plugin *plugin) { struct program *prog = plugin->parent; @@ -55,7 +55,7 @@ static int help(int argc, char **argv, struct plugin *plugin) return 0; } -void usage(struct plugin *plugin) +static void usage_cmd(struct plugin *plugin) { struct program *prog = plugin->parent; @@ -69,30 +69,35 @@ void general_help(struct plugin *plugin) { struct program *prog = plugin->parent; struct plugin *extension; - unsigned i = 0; - unsigned padding = 15; - unsigned curr_length = 0; + unsigned int i = 0; + unsigned int padding = 15; + unsigned int curr_length = 0; + printf("%s-%s\n", prog->name, prog->version); - usage(plugin); + usage_cmd(plugin); printf("\n"); - print_word_wrapped(prog->desc, 0, 0); + print_word_wrapped(prog->desc, 0, 0, stdout); printf("\n"); if (plugin->desc) { printf("\n"); - print_word_wrapped(plugin->desc, 0, 0); + print_word_wrapped(plugin->desc, 0, 0, stdout); printf("\n"); } printf("\nThe following are all implemented sub-commands:\n"); - /* iterate through all commands to get maximum length */ - /* Still need to handle the case of ultra long strings, help messages, etc */ - for (; plugin->commands[i]; i++) - if (padding < (curr_length = 2 + strlen(plugin->commands[i]->name))) + /* + * iterate through all commands to get maximum length + * Still need to handle the case of ultra long strings, help messages, etc + */ + for (; plugin->commands[i]; i++) { + curr_length = 2 + strlen(plugin->commands[i]->name); + if (padding < curr_length) padding = curr_length; + } i = 0; for (; plugin->commands[i]; i++) @@ -110,8 +115,10 @@ void general_help(struct plugin *plugin) printf("See '%s help ' 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 */ + /* + * 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; @@ -156,7 +163,7 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) if (!strcmp(str, "help")) return help(argc, argv, plugin); if (!strcmp(str, "version")) - return version(plugin); + return version_cmd(plugin); while (*cmd) { if (!strcmp(str, (*cmd)->name) || @@ -183,7 +190,7 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) if (plugin->name) { printf("ERROR: Invalid sub-command '%s' for plugin %s\n", str, plugin->name); return -ENOTTY; - } + } extension = plugin->next; while (extension) { @@ -192,8 +199,10 @@ int handle_plugin(int argc, char **argv, struct plugin *plugin) extension = extension->next; } - /* If the command is executed with the extension name and - * command together ("plugin-command"), run the plug in */ + /* + * 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))) { diff --git a/plugin.h b/plugin.h index 6f61a2102d..03bd95a7bd 100644 --- a/plugin.h +++ b/plugin.h @@ -31,7 +31,6 @@ struct command { char *alias; }; -void usage(struct plugin *plugin); void general_help(struct plugin *plugin); int handle_plugin(int argc, char **argv, struct plugin *plugin); diff --git a/plugins/amzn/amzn-nvme.c b/plugins/amzn/amzn-nvme.c index e04aa535f8..d359cc3497 100644 --- a/plugins/amzn/amzn-nvme.c +++ b/plugins/amzn/amzn-nvme.c @@ -28,15 +28,15 @@ static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id, static void amzn_id_ctrl(__u8 *vs, struct json_object *root) { - struct nvme_vu_id_ctrl_field* id = (struct nvme_vu_id_ctrl_field *)vs; + struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs; char bdev[32] = { 0 }; int len = 0; + while (len < 31) { - if (id->bdev[++len] == ' ') { + if (id->bdev[++len] == ' ') break; - } } snprintf(bdev, len+1, "%s", id->bdev); diff --git a/plugins/dera/dera-nvme.c b/plugins/dera/dera-nvme.c index 9408e506d7..ca4b53d698 100644 --- a/plugins/dera/dera-nvme.c +++ b/plugins/dera/dera-nvme.c @@ -104,13 +104,12 @@ static int nvme_dera_get_device_status(int fd, enum dera_device_status *result) .addr = (__u64)(uintptr_t)NULL, .data_len = 0, .cdw10 = 0, - .cdw12 = 0x104, + .cdw12 = 0x104, }; err = nvme_submit_admin_passthru(fd, &cmd, NULL); - if (!err && result) { + if (!err && result) *result = cmd.result; - } return err; } @@ -130,13 +129,12 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin err = parse_and_open(&dev, argc, argv, desc, opts); if (err) return err; - + err = nvme_get_log_simple(dev_fd(dev), 0xc0, sizeof(log), &log); - if (err) { + if (err) goto exit; - } - const char* dev_status[] = { + static const char *dev_status[] = { "Normal", "Quick Rebuilding", "Full Rebuilding", @@ -148,25 +146,22 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin "Firmware Committing", "Over Temperature" }; - const char *volt_status[] = { + static const char *volt_status[] = { "Normal", "Initial Low", "Runtime Low", }; err = nvme_dera_get_device_status(dev_fd(dev), &state); - if (!err){ - if (state > 0 && state < 4){ + if (!err) { + if (state > 0 && state < 4) printf("device_status : %s %d%% completed\n", dev_status[state], log.rebuild_percent); - } - else{ + else printf("device_status : %s\n", dev_status[state]); - } - } - else { + } 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); @@ -188,12 +183,10 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin printf("fw_loader_version : %.*s\n", 8, log.fw_loader_version); printf("uefi_driver_version : %.*s\n", 8, log.uefi_driver_version); - if (log.pcie_volt_status < sizeof(volt_status) / sizeof(const char *)){ + if (log.pcie_volt_status < sizeof(volt_status) / sizeof(const char *)) printf("pcie_volt_status : %s\n", volt_status[log.pcie_volt_status]); - } - else{ + 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]); diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c new file mode 100644 index 0000000000..2a221f8657 --- /dev/null +++ b/plugins/fdp/fdp.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "nvme-print.h" + +#define CREATE_CMD +#include "fdp.h" + +static int fdp_configs(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Configurations"; + const char *egid = "Endurance group identifier"; + const char *human_readable = "show log in readable format"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_config_log hdr; + void *log = NULL; + int err; + + struct config { + __u16 egid; + char *output_format; + bool human_readable; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + if (cfg.human_readable) + flags |= VERBOSE; + + if (!cfg.egid) { + fprintf(stderr, "endurance group identifier required\n"); + err = -EINVAL; + goto out; + } + + err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0, + sizeof(hdr), &hdr); + if (err) { + nvme_show_status(errno); + goto out; + } + + log = malloc(hdr.size); + if (!log) { + err = -ENOMEM; + goto out; + } + + err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0, + hdr.size, log); + if (err) { + nvme_show_status(errno); + goto out; + } + + nvme_show_fdp_configs(log, hdr.size, flags); + +out: + dev_close(dev); + free(log); + + return err; +} + +static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Reclaim Unit Handle Usage"; + const char *egid = "Endurance group identifier"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_ruhu_log hdr; + size_t len; + void *log = NULL; + int err; + + struct config { + __u16 egid; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid, + 0, sizeof(hdr), &hdr); + if (err) { + nvme_show_status(err); + goto out; + } + + len = sizeof(hdr) + le16_to_cpu(hdr.nruh) * sizeof(struct nvme_fdp_ruhu_desc); + log = malloc(len); + if (!log) { + err = -ENOMEM; + goto out; + } + + err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid, + 0, len, log); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_usage(log, len, flags); + +out: + dev_close(dev); + free(log); + + return err; +} + +static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Statistics"; + const char *egid = "Endurance group identifier"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_stats_log stats; + int err; + + struct config { + __u16 egid; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + memset(&stats, 0x0, sizeof(stats)); + + err = nvme_get_log_fdp_stats(dev->direct.fd, cfg.egid, 0, sizeof(stats), &stats); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_stats(&stats, flags); + +out: + dev_close(dev); + + return err; +} + +static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Get Flexible Data Placement Events"; + const char *egid = "Endurance group identifier"; + const char *host_events = "Get host events"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_events_log events; + int err; + + struct config { + __u16 egid; + bool host_events; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .egid = 0, + .host_events = false, + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("endgrp-id", 'e', &cfg.egid, egid), + OPT_FLAG("host-events", 'E', &cfg.host_events, host_events), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + memset(&events, 0x0, sizeof(events)); + + err = nvme_get_log_fdp_events(dev->direct.fd, cfg.egid, + cfg.host_events, 0, sizeof(events), &events); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_events(&events, flags); + +out: + dev_close(dev); + + return err; +} + +static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Reclaim Unit Handle Status"; + const char *namespace_id = "Namespace identifier"; + const char *raw = "use binary output"; + + enum nvme_print_flags flags; + struct nvme_dev *dev; + struct nvme_fdp_ruh_status hdr; + size_t len; + void *buf = NULL; + int err = -1; + + struct config { + __u32 namespace_id; + char *output_format; + bool raw_binary; + }; + + struct config cfg = { + .output_format = "normal", + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(cfg.output_format, &flags); + if (flags < 0) + goto out; + + if (cfg.raw_binary) + flags = BINARY; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto out; + } + } + + err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev), + cfg.namespace_id, sizeof(hdr), &hdr); + if (err) { + nvme_show_status(err); + goto out; + } + + len = sizeof(struct nvme_fdp_ruh_status) + + le16_to_cpu(hdr.nruhsd) * sizeof(struct nvme_fdp_ruh_status_desc); + buf = malloc(len); + if (!buf) { + err = -ENOMEM; + goto out; + } + + err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev), + cfg.namespace_id, len, buf); + if (err) { + nvme_show_status(err); + goto out; + } + + nvme_show_fdp_ruh_status(buf, len, flags); + +out: + free(buf); + dev_close(dev); + + return err; +} + +static int fdp_update(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Reclaim Unit Handle Update"; + const char *namespace_id = "Namespace identifier"; + const char *_pids = "Comma-separated list of placement identifiers to update"; + + struct nvme_dev *dev; + unsigned short pids[256]; + __u16 buf[256]; + int npids; + int err = -1; + + struct config { + __u32 namespace_id; + char *pids; + }; + + struct config cfg = { + .pids = "", + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_LIST("pids", 'p', &cfg.pids, _pids), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + npids = argconfig_parse_comma_sep_array_short(cfg.pids, pids, ARRAY_SIZE(pids)); + if (npids < 0) { + perror("could not parse pids"); + err = -EINVAL; + goto out; + } else if (npids == 0) { + fprintf(stderr, "no placement identifiers set\n"); + err = -EINVAL; + goto out; + } + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto out; + } + } + + for (unsigned int i = 0; i < npids; i++) + buf[i] = cpu_to_le16(pids[i]); + + err = nvme_fdp_reclaim_unit_handle_update(dev_fd(dev), cfg.namespace_id, npids, buf); + if (err) { + nvme_show_status(err); + goto out; + } + + printf("update: Success\n"); + +out: + dev_close(dev); + + return err; +} + +static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Enable or disable FDP events"; + const char *namespace_id = "Namespace identifier"; + const char *enable = "Enable/disable event"; + const char *event_types = "Comma-separated list of event types"; + const char *ph = "Placement Handle"; + const char *save = "specifies that the controller shall save the attribute"; + + struct nvme_dev *dev; + int err = -1; + unsigned short evts[255]; + int nev; + __u8 buf[255]; + + struct config { + __u32 namespace_id; + __u16 ph; + char *event_types; + bool enable; + bool save; + }; + + struct config cfg = { + .enable = false, + .save = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_SHRT("placement-handle", 'p', &cfg.ph, ph), + OPT_FLAG("enable", 'e', &cfg.enable, enable), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_LIST("event-types", 't', &cfg.event_types, event_types), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + nev = argconfig_parse_comma_sep_array_short(cfg.event_types, evts, ARRAY_SIZE(evts)); + if (nev < 0) { + perror("could not parse event types"); + err = -EINVAL; + goto out; + } else if (nev == 0) { + fprintf(stderr, "no event types set\n"); + err = -EINVAL; + goto out; + } else if (nev > 255) { + fprintf(stderr, "too many event types (max 255)\n"); + err = -EINVAL; + goto out; + } + + if (!cfg.namespace_id) { + err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); + if (err < 0) { + if (errno != ENOTTY) { + fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno)); + goto out; + } + + cfg.namespace_id = NVME_NSID_ALL; + } + } + + for (unsigned int i = 0; i < nev; i++) + buf[i] = (__u8)evts[i]; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = NVME_FEAT_FID_FDP_EVENTS, + .save = cfg.save, + .nsid = cfg.namespace_id, + .cdw11 = (nev << 16) | cfg.ph, + .cdw12 = cfg.enable ? 0x1 : 0x0, + .data_len = sizeof(buf), + .data = buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + + err = nvme_set_features(&args); + if (err) { + nvme_show_status(err); + goto out; + } + + printf("set-events: Success\n"); + +out: + dev_close(dev); + + return err; +} diff --git a/plugins/fdp/fdp.h b/plugins/fdp/fdp.h new file mode 100644 index 0000000000..f162b32116 --- /dev/null +++ b/plugins/fdp/fdp.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/fdp/fdp + +#if !defined(FDP_NVME) || defined(CMD_HEADER_MULTI_READ) +#define FDP_NVME + +#include "cmd.h" + +PLUGIN(NAME("fdp", "Manage Flexible Data Placement enabled devices", NVME_VERSION), + COMMAND_LIST( + ENTRY("configs", "List configurations", fdp_configs) + ENTRY("usage", "Show reclaim unit handle usage", fdp_usage) + ENTRY("stats", "Show statistics", fdp_stats) + ENTRY("events", "List events affecting reclaim units and media usage", fdp_events) + ENTRY("status", "Show reclaim unit handle status", fdp_status) + ENTRY("update", "Update a reclaim unit handle", fdp_update) + ENTRY("set-events", "Enabled or disable events", fdp_set_events) + ) +); + +#endif + +#include "define_cmd.h" diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c index 572086ce8c..0272dead34 100644 --- a/plugins/huawei/huawei-nvme.c +++ b/plugins/huawei/huawei-nvme.c @@ -47,9 +47,9 @@ struct huawei_list_item { char node[1024]; struct nvme_id_ctrl ctrl; - unsigned nsid; + unsigned int nsid; struct nvme_id_ns ns; - unsigned block; + unsigned int block; char ns_name[NS_NAME_LEN]; char array_name[ARRAY_NAME_LEN]; bool huawei_device; @@ -98,23 +98,19 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha 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 { + } 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) + if (len < 0) return -EINVAL; - } - else { + } else { memcpy(item->array_name, item->ctrl.vs, ARRAY_NAME_LEN); item->array_name[ARRAY_NAME_LEN - 1] = '\0'; } @@ -123,9 +119,8 @@ static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const cha 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); - 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') { @@ -137,7 +132,7 @@ static void format(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz) } static void huawei_json_print_list_items(struct huawei_list_item *list_items, - unsigned len) + unsigned int len) { struct json_object *root; struct json_object *devices; @@ -210,8 +205,9 @@ static void huawei_print_list_item(struct huawei_list_item *list_item, struct huawei_list_element_len element_len) { __u8 lba_index; + nvme_id_ns_flbas_to_lbaf_inuse(list_item->ns.flbas, &lba_index); - unsigned long long int lba = 1ULL << list_item->ns.lbaf[lba_index].ds; + unsigned long long lba = 1ULL << list_item->ns.lbaf[lba_index].ds; double nsze = le64_to_cpu(list_item->ns.nsze) * lba; double nuse = le64_to_cpu(list_item->ns.nuse) * lba; @@ -223,8 +219,7 @@ static void huawei_print_list_item(struct huawei_list_item *list_item, char *nguid = nguid_buf; int i; - sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, - nsze, s_suffix); + 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++) @@ -247,37 +242,37 @@ static unsigned int choose_len(unsigned int old_len, unsigned int cur_len, unsig 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) +static unsigned int huawei_get_ns_len(struct huawei_list_item *list_items, unsigned int len, + unsigned int default_len) { int i; unsigned int min_len = default_len; for (i = 0 ; i < len ; i++) - min_len = choose_len(min_len , strlen(list_items->ns_name), default_len); + 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) +static int huawei_get_array_len(struct huawei_list_item *list_items, unsigned int len, + unsigned int default_len) { int i; int min_len = default_len; for (i = 0 ; i < len ; i++) - min_len = choose_len(min_len , strlen(list_items->array_name), default_len); + 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) +static void huawei_print_list_items(struct huawei_list_item *list_items, unsigned int len) { - unsigned i; + unsigned int i; struct huawei_list_element_len element_len; element_len.node = 16; @@ -301,7 +296,7 @@ static int huawei_list(int argc, char **argv, struct command *command, struct huawei_list_item *list_items; unsigned int i, n, ret; unsigned int huawei_num = 0; - int fmt; + enum nvme_print_flags fmt; const char *desc = "Retrieve basic information for the given huawei device"; struct config { char *output_format; @@ -320,9 +315,9 @@ static int huawei_list(int argc, char **argv, struct command *command, if (ret) return ret; - fmt = validate_output_format(cfg.output_format); - if (fmt != JSON && fmt != NORMAL) - return -EINVAL; + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0 || (fmt != JSON && fmt != NORMAL)) + return ret; n = scandir("/dev", &devices, nvme_namespace_filter, alphasort); if (n <= 0) @@ -350,13 +345,12 @@ static int huawei_list(int argc, char **argv, struct command *command, close(fd); goto out_free_list_items; } - if (list_items[huawei_num].huawei_device == true) { + if (list_items[huawei_num].huawei_device == true) huawei_num++; - } close(fd); } - if (huawei_num > 0){ + if (huawei_num > 0) { if (fmt == JSON) huawei_json_print_list_items(list_items, huawei_num); else diff --git a/plugins/innogrit/innogrit-nvme.c b/plugins/innogrit/innogrit-nvme.c index fb79cf63f7..cd47efa01a 100644 --- a/plugins/innogrit/innogrit-nvme.c +++ b/plugins/innogrit/innogrit-nvme.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "common.h" #include "nvme.h" @@ -70,11 +71,15 @@ static int innogrit_smart_log_additional(int argc, char **argv, printf("DW17 weight_ec : %u\n", pvsc_smart->weight_ec); printf("DW18 slc_cap_mb : %u\n", pvsc_smart->slc_cap_mb); printf("DW19-20 nand_page_write_cnt : %llu\n", pvsc_smart->nand_page_write_cnt); - - iindex = 21; - for (i = 0; i < (sizeof(pvsc_smart->reserved2)/4); i++) { - if (pvsc_smart->reserved2[i] != 0) - printf("DW%-37d : %u\n", iindex, pvsc_smart->reserved2[i]); + printf("DW21 program_error_cnt : %u\n", pvsc_smart->program_error_cnt); + printf("DW22 erase_error_cnt : %u\n", pvsc_smart->erase_error_cnt); + printf("DW23[0] flash_type : %u\n", pvsc_smart->flash_type); + printf("DW24 hs_crc_err_cnt : %u\n", pvsc_smart->hs_crc_err_cnt); + printf("DW25 ddr_ecc_err_cnt : %u\n", pvsc_smart->ddr_ecc_err_cnt); + iindex = 26; + for (i = 0; i < (sizeof(pvsc_smart->reserved3)/4); i++) { + if (pvsc_smart->reserved3[i] != 0) + printf("DW%-37d : %u\n", iindex, pvsc_smart->reserved3[i]); iindex++; } @@ -141,11 +146,13 @@ static int nvme_vucmd(int fd, unsigned char opcode, unsigned int cdw12, memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; + cmd.cdw2 = IGVSC_SIG; + cmd.cdw10 = data_len / 4; cmd.cdw12 = cdw12; cmd.cdw13 = cdw13; cmd.cdw14 = cdw14; cmd.cdw15 = cdw15; - cmd.nsid = 0; + cmd.nsid = 0xffffffff; cmd.addr = (__u64)(__u64)(uintptr_t)data; cmd.data_len = data_len; return nvme_submit_admin_passthru(fd, &cmd, NULL); @@ -157,7 +164,7 @@ static int innogrit_vsc_geteventlog(int argc, char **argv, { time_t timep; struct tm *logtime; - int icount, ioffset16k, iblock; + int icount, ioffset16k, iblock, ivsctype; char currentdir[128], filename[512]; unsigned char data[4096], data16k[SIZE_16K], zerob[32]; unsigned int *pcheckdata; @@ -190,6 +197,15 @@ static int innogrit_vsc_geteventlog(int argc, char **argv, if (getcwd(currentdir, 128) == NULL) return -1; + ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x03, 0x00, 0x00, (char *)data, 4096); + if (ret == -1) + return ret; + + if (data[0] == 0x5A) + ivsctype = 1; + else + ivsctype = 0; + time(&timep); logtime = localtime(&timep); sprintf(filename, "%s/eventlog_%02d%02d-%02d%02d%02d.elog", currentdir, logtime->tm_mon+1, @@ -213,10 +229,14 @@ static int innogrit_vsc_geteventlog(int argc, char **argv, icount++; memset(data, 0, 4096); - ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET_EVENT_LOG, 0, 0, - (SRB_SIGNATURE >> 32), - (SRB_SIGNATURE & 0xFFFFFFFF), - (char *)data, 4096); + if (ivsctype == 1) + ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x60, 0x00, 0x00, 0x00, (char *)data, + 4096); + else + ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET_EVENT_LOG, 0, 0, + (SRB_SIGNATURE >> 32), + (SRB_SIGNATURE & 0xFFFFFFFF), + (char *)data, 4096); if (ret == -1) return ret; @@ -297,7 +317,7 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command, time_t timep; struct tm *logtime; char currentdir[128], filename[512], fname[128]; - unsigned int itotal, icur; + unsigned int itotal, icur, ivsctype; unsigned char data[4096]; struct cdumpinfo cdumpinfo; unsigned char busevsc = false; @@ -321,29 +341,44 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command, time(&timep); logtime = localtime(&timep); + ivsctype = 0; ipackindex = 0; memset(data, 0, 4096); - if (nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, - (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF), - (char *)data, 4096) == 0) { - memcpy(&cdumpinfo, &data[3072], sizeof(cdumpinfo)); - if (cdumpinfo.sig == 0x5a5b5c5d) { - busevsc = true; - ipackcount = cdumpinfo.ipackcount; - if (ipackcount == 0) { - itotal = 0; - } else { - itotal = cdumpinfo.cdumppack[ipackindex].ilenth; - memset(fwvera, 0, sizeof(fwvera)); - memcpy(fwvera, cdumpinfo.cdumppack[ipackindex].fwver, 8); - sprintf(fname, "cdump_%02d%02d-%02d%02d%02d_%d_%s.cdp", logtime->tm_mon+1, - logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec, - ipackindex, fwvera); - sprintf(filename, "%s/%s", currentdir, fname); - } + + ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x03, 0x00, 0x00, (char *)data, 4096); + if (ret == -1) + return ret; + + if (data[0] == 0x5A) { + ivsctype = 1; + ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00, (char *)data, 4096); + } else { + ivsctype = 0; + ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, + (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF), + (char *)data, 4096); + } + if (ret == -1) + return ret; + + memcpy(&cdumpinfo, &data[3072], sizeof(cdumpinfo)); + if (cdumpinfo.sig == 0x5a5b5c5d) { + busevsc = true; + ipackcount = cdumpinfo.ipackcount; + if (ipackcount == 0) { + itotal = 0; + } else { + itotal = cdumpinfo.cdumppack[ipackindex].ilenth; + memset(fwvera, 0, sizeof(fwvera)); + memcpy(fwvera, cdumpinfo.cdumppack[ipackindex].fwver, 8); + sprintf(fname, "cdump_%02d%02d-%02d%02d%02d_%d_%s.cdp", logtime->tm_mon+1, + logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec, + ipackindex, fwvera); + sprintf(filename, "%s/%s", currentdir, fname); } } + if (busevsc == false) { memset(data, 0, 4096); ret = nvme_get_nsid_log(dev_fd(dev), true, 0x07, @@ -370,16 +405,19 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command, setfilecontent(filename, data, strlen((char *)data)); for (icur = 0; icur < itotal; icur += 4096) { memset(data, 0, 4096); - if (busevsc) - ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, - VSC_FN_GET_CDUMP, 0x00, - (SRB_SIGNATURE >> 32), - (SRB_SIGNATURE & 0xFFFFFFFF), - (char *)data, 4096); - else + if (busevsc) { + if (ivsctype == 1) + ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00, + (char *)data, 4096); + else + ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, + (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF), + (char *)data, 4096); + } else { ret = nvme_get_nsid_log(dev_fd(dev), true, 0x07, NVME_NSID_ALL, 4096, data); + } if (ret != 0) return ret; @@ -394,17 +432,20 @@ static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command, ipackindex++; if (ipackindex != ipackcount) { memset(data, 0, 4096); - if (busevsc) - ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, - VSC_FN_GET_CDUMP, 0x00, - (SRB_SIGNATURE >> 32), - (SRB_SIGNATURE & 0xFFFFFFFF), - (char *)data, 4096); - else + if (busevsc) { + if (ivsctype == 1) + ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00, + (char *)data, 4096); + else + ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00, + (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF), + (char *)data, 4096); + } else { ret = nvme_get_nsid_log(dev_fd(dev), true, 0x07, NVME_NSID_ALL, 4096, data); + } if (ret != 0) return ret; diff --git a/plugins/innogrit/typedef.h b/plugins/innogrit/typedef.h index d4ea269b85..f2a59b4f3a 100644 --- a/plugins/innogrit/typedef.h +++ b/plugins/innogrit/typedef.h @@ -7,6 +7,7 @@ #define NVME_VSC_GET 0xE6 #define VSC_FN_GET_CDUMP 0x08 #define EVLOG_SIG 0x65766C67 +#define IGVSC_SIG 0x69677673 #define SRB_SIGNATURE 0x544952474F4E4E49ULL #define XCLEAN_LINE "\033[K" @@ -56,7 +57,13 @@ struct vsc_smart_log { unsigned int weight_ec; unsigned int slc_cap_mb; unsigned long long nand_page_write_cnt; - unsigned int reserved2[49]; + unsigned int program_error_cnt; + unsigned int erase_error_cnt; + u_char flash_type; + u_char reserved2[3]; + unsigned int hs_crc_err_cnt; + unsigned int ddr_ecc_err_cnt; + unsigned int reserved3[44]; }; #pragma pack(pop) diff --git a/plugins/inspur/inspur-nvme.c b/plugins/inspur/inspur-nvme.c new file mode 100644 index 0000000000..cda3507533 --- /dev/null +++ b/plugins/inspur/inspur-nvme.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "nvme-print.h" +#include "util/suffix.h" + +#define CREATE_CMD +#include "inspur-nvme.h" +#include "inspur-utils.h" + +void show_r1_vendor_log(r1_cli_vendor_log_t *vendorlog) +{ + int i = 0; + + if (vendorlog->device_state == 0) + printf("device_state : [healthy]\n"); + else + printf("device_state : [warning]\n"); + + printf("commit id : %s\n", vendorlog->commit_id); + printf("mcu data id(mcu) : 0x%x\n", le32_to_cpu(vendorlog->mcu_data_id)); + printf("power_info(mcu) : %u mW\n", le32_to_cpu(vendorlog->power_info)); + printf("voltage_info(mcu) : %u mV\n", le32_to_cpu(vendorlog->voltage_info)); + printf("current_info(mcu) : %u mA\n", le32_to_cpu(vendorlog->current_info)); + printf("history max_power(mcu) : %u mW\n", le32_to_cpu(vendorlog->max_power)); + printf("disk_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->disk_max_temper) - 273); + printf("disk_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->disk_overtemper_cout)); + printf("ctrl_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->ctrl_max_temper) - 273); + printf("ctrl_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->ctrl_overtemper_cout)); + printf("nand_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->nand_max_temper) - 273); + printf("nand_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->nand_overtemper_cout)); + + for (i = 0; i < 4; i++) + printf("temperature[%d](mcu) : %d C\n", i, le32_to_cpu(vendorlog->current_temp[i]) - 273); + + printf("CAP Time from 32v to 27v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time1)); + printf("CAP Time from 27v to 10v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time2)); + printf("cap_health_state(mcu) : %u\n", le32_to_cpu(vendorlog->cap_health_state)); + printf("warning bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning[1]), + le32_to_cpu(vendorlog->detail_warning[0])); + printf("-->high_format_fail : %x\n", vendorlog->detail_warning_bit.high_format_fail); + printf("-->low_format_fail : %x\n", vendorlog->detail_warning_bit.low_format_fail); + printf("-->current sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail1); + printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail2); + printf("-->board temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail3); + printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail4); + printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_bit.capacitance_test_fail); + printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_bit.readOnly_after_rebuild); + printf("-->firmware_loss : %x\n", vendorlog->detail_warning_bit.firmware_loss); + printf("-->cap_self_test : %x\n", vendorlog->detail_warning_bit.cap_unsupply); + printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_bit.spare_space_warning); + printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_bit.lifetime_warning); + printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_bit.temp_high_warning); + printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_bit.temp_low_warning); + printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_bit.mcu_disable); + printf("warning history bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning_his[1]), + le32_to_cpu(vendorlog->detail_warning_his[0])); + printf("-->high_format_fail : %x\n", vendorlog->detail_warning_his_bit.high_format_fail); + printf("-->low_format_fail : %x\n", vendorlog->detail_warning_his_bit.low_format_fail); + printf("-->current sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail1); + printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail2); + printf("-->board temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail3); + printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail4); + printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_his_bit.capacitance_test_fail); + printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_his_bit.readOnly_after_rebuild); + printf("-->firmware_loss : %x\n", vendorlog->detail_warning_his_bit.firmware_loss); + printf("-->cap_self_test : %x\n", vendorlog->detail_warning_his_bit.cap_unsupply); + printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_his_bit.spare_space_warning); + printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_his_bit.lifetime_warning); + printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_his_bit.temp_high_warning); + printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_his_bit.temp_low_warning); + printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_his_bit.mcu_disable); + + for (i = 0; i < 4; i++) + printf("[%d]nand_bytes_written : %" PRIu64 " GB\n", i, le64_to_cpu(vendorlog->nand_bytes_written[i])); + + for (i = 0; i < 4; i++) { + printf("[%d]io_apptag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_apptag_err)); + printf("[%d]io_guard_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_guard_err)); + printf("[%d]io_reftag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_reftag_err)); + printf("[%d]io_read_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_read_fail_cout)); + printf("[%d]io_write_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_write_fail_cout)); + printf("[%d]io_dma_disable_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_disable_err)); + printf("[%d]io_dma_fatal_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_fatal_err)); + printf("[%d]io_dma_linkdown_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_linkdown_err)); + printf("[%d]io_dma_timeout_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_timeout_err)); + printf("[%d]lba_err[0] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[0])); + printf("[%d]lba_err[1] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[1])); + printf("[%d]lba_err[2] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[2])); + printf("[%d]lba_err[3] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[3])); + printf("[%d]lba_err[4] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[4])); + printf("[%d]lba_err[5] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[5])); + } + + printf("temp_throttle_per : %u\n", le32_to_cpu(vendorlog->temp_throttle_per)); + printf("port0_flreset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_fundamental_reset_cnt)); + printf("port0_hot_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_hot_reset_cnt)); + printf("port0_func_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_func_reset_cnt)); + printf("port0_linkdown_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_linkdown_cnt)); + printf("port0_ctrl_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_ctrl_reset_cnt)); + printf("ces_RcvErr_cnt : %u\n", le32_to_cpu(vendorlog->ces_RcvErr_cnt)); + printf("ces_BadTlp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadTlp_cnt)); + printf("ces_BadDllp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadDllp_cnt)); + printf("ces_Rplyover_cnt : %u\n", le32_to_cpu(vendorlog->ces_Rplyover_cnt)); + printf("ces_RplyTo_cnt : %u\n", le32_to_cpu(vendorlog->ces_RplyTo_cnt)); + printf("ces_Hlo_cnt : %u\n", le32_to_cpu(vendorlog->ces_Hlo_cnt)); + printf("scan doorbell err cnt : %u\n", le32_to_cpu(vendorlog->scan_db_err_cnt)); + printf("doorbell interrupt err cnt : %u\n", le32_to_cpu(vendorlog->db_int_err_cnt)); + + printf("------------ncm-----------------------\n"); + for (i = 0; i < 4; i++) { + printf("------------part%d-----------------------\n", i); + printf("[%d]nand_rd_unc_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_unc_cnt)); + printf("[%d]nand_rd_srr_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_srr_cnt)); + printf("[%d]nand_rd_sdecode_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_soft_decode_cnt)); + printf("[%d]nand_rd_rb_fail_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_rebuild_fail_cnt)); + printf("[%d]nand_prg_fail_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_fail_cnt)); + printf("[%d]nand_eras_fail_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_fail_cnt)); + printf("[%d]nand_rd_count : %" PRIu64 "\n", i, + le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_cnt)); + printf("[%d]nand_prg_count : %" PRIu64 "\n", i, + le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_cnt)); + printf("[%d]nand_eras_count : %" PRIu64 "\n", i, + le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_cnt)); + printf("[%d]BE_scan_unc_count : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].BE_scan_unc_cnt)); + printf("[%d]rebuild_req_cnt : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].rebuild_req_cnt)); + printf("[%d]retry_req_cnt : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_req_cnt)); + printf("[%d]retry_success_cnt : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_success_cnt)); + printf("[%d]prg_badblk_num : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].prg_badblk_num)); + printf("[%d]eras_badblk_num : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].eras_badblk_num)); + printf("[%d]read_badblk_num : %u\n", i, + le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].unc_badblk_num)); + } + + printf("[%d]temp_ctrl_limit_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_limit_cnt)); + printf("[%d]temp_ctrl_stop_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_stop_cnt)); + printf("------------wlm-----------------------\n"); + for (i = 0; i < 4; i++) { + printf("------------part%d-----------------------\n", i); + printf("[%d]fbb_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].fbb_count)); + printf("[%d]ebb_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].ebb_count)); + printf("[%d]lbb_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].lbb_count)); + printf("[%d]gc_read_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_read_count)); + printf("[%d]gc_write_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_count)); + printf("[%d]gc_write_fail_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_fail_count)); + printf("[%d]force_gc_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].force_gc_count)); + printf("[%d]avg_pe_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].avg_pe_count)); + printf("[%d]max_pe_count : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].max_pe_count)); + printf("[%d]free_blk_num1 : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num1)); + printf("[%d]free_blk_num2 : %u\n", i, + le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num2)); + } + + printf("------------lkm-----------------------\n"); + printf("[%d]e2e_check_err_count1 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt1)); + printf("[%d]e2e_check_err_count2 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt2)); + printf("[%d]e2e_check_err_count3 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt3)); + printf("[%d]e2e_check_err_count4 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt4)); +} + +void show_r1_media_err_log(r1_cli_vendor_log_t *vendorlog) +{ + int i, j; + + for (i = 0; i < 4; i++) { + printf("DM%d read err lba:\n", i); + for (j = 0; j < 10; j++) + printf("[%d]lba : %" PRIu64 "\n", j, le64_to_cpu(vendorlog->media_err[i].lba_err[j])); + } +} + +static int nvme_get_vendor_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + __u8 local_mem[BYTE_OF_4K]; + char *desc = "Get the Inspur vendor log"; + struct nvme_dev *dev; + int err; + + OPT_ARGS(opts) = { OPT_END() }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + memset(local_mem, 0, BYTE_OF_4K); + err = nvme_get_log_simple(dev_fd(dev), + (enum nvme_cmd_get_log_lid)VENDOR_SMART_LOG_PAGE, + sizeof(r1_cli_vendor_log_t), local_mem); + if (!err) { + show_r1_vendor_log((r1_cli_vendor_log_t *)local_mem); + show_r1_media_err_log((r1_cli_vendor_log_t *)local_mem); + } else { + nvme_show_status(err); + } + + dev_close(dev); + return err; +} diff --git a/plugins/inspur/inspur-nvme.h b/plugins/inspur/inspur-nvme.h new file mode 100644 index 0000000000..14a5e7609e --- /dev/null +++ b/plugins/inspur/inspur-nvme.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/inspur/inspur-nvme + +#if !defined(INSPUR_NVME) || defined(CMD_HEADER_MULTI_READ) +#define INSPUR_NVME + +#include "cmd.h" + +PLUGIN(NAME("inspur", "Inspur vendor specific extensions", NVME_VERSION), + COMMAND_LIST( + ENTRY("nvme-vendor-log", "Retrieve Inspur Vendor Log, show it", nvme_get_vendor_log) + ) +); + +#endif + +#include "define_cmd.h" diff --git a/plugins/inspur/inspur-utils.h b/plugins/inspur/inspur-utils.h new file mode 100644 index 0000000000..d411bf0f29 --- /dev/null +++ b/plugins/inspur/inspur-utils.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __INSPUR_UTILS_H__ +#define __INSPUR_UTILS_H__ + +#define BYTE_OF_64K 65536UL +#define BYTE_OF_32K 32768UL +#define BYTE_OF_16K 16384UL +#define BYTE_OF_4K 4096UL +#define BYTE_OF_512 512UL +#define BYTE_OF_256 256UL +#define BYTE_OF_128 128UL + +/* Inspur specific LOG_PAGE_ID */ +typedef enum { + VENDOR_SMART_LOG_PAGE = 0xc0, +} vendor_sepc_log_page_id_e; + +#pragma pack(push, 1) +typedef struct r1_am_cap_transtime { + __u32 cap_trans_time1 : 16; + __u32 cap_trans_time2 : 16; +} r1_cap_transtime_t; + +typedef struct vendor_warning_bit { + __u32 high_format_fail : 1; + __u32 low_format_fail : 1; + __u32 rebuild_fail1 : 1; + __u32 rebuild_fail2 : 1; + __u32 rebuild_fail3 : 1; + __u32 rebuild_fail4 : 1; + __u32 rebuild_fail5 : 1; + __u32 rebuild_fail6 : 1; + __u32 self_test_fail1 : 1; + __u32 self_test_fail2 : 1; + __u32 self_test_fail3 : 1; + __u32 self_test_fail4 : 1; + __u32 internal_err1 : 1; + __u32 internal_err2 : 1; + __u32 internal_err3 : 1; + __u32 internal_err4 : 1; + __u32 internal_err5 : 1; + __u32 internal_err6 : 1; + __u32 internal_err7 : 1; + __u32 internal_err8 : 1; + __u32 internal_err9 : 1; + __u32 internal_err10 : 1; + __u32 internal_err11 : 1; + __u32 internal_err12 : 1; + __u32 internal_err13 : 1; + __u32 internal_err14 : 1; + __u32 internal_err15 : 1; + __u32 internal_err16 : 1; + __u32 capacitance_test_fail : 1; + __u32 IO_read_fail : 1; + __u32 IO_write_fail : 1; + __u32 readOnly_after_rebuild : 1; + __u32 firmware_loss : 1; + __u32 cap_unsupply : 1; + __u32 spare_space_warning : 1; + __u32 lifetime_warning : 1; + __u32 temp_high_warning : 1; + __u32 temp_low_warning : 1; + __u32 mcu_disable : 1; + __u32 rsv : 25; +} vendor_warning_str; + +typedef struct r1_vendor_log_ncm_cout { + __u32 nand_rd_unc_cnt; + __u32 nand_rd_srr_cnt; + __u32 nand_rd_soft_decode_cnt; + __u32 nand_rd_rebuild_fail_cnt; + __u32 nand_prg_fail_cnt; + __u32 nand_eras_fail_cnt; + __u64 nand_rd_cnt; + __u64 nand_prg_cnt; + __u64 nand_eras_cnt; + __u32 BE_scan_unc_cnt; + __u32 rebuild_req_cnt; + __u16 retry_req_cnt; + __u16 retry_success_cnt; + __u32 prg_badblk_num; + __u32 eras_badblk_num; + __u32 unc_badblk_num; +} r1_vendor_log_nandctl_count_t; + +typedef struct r1_wearlvl_vendor_log_count { + __u32 fbb_count; + __u32 ebb_count; + __u32 lbb_count; + __u32 gc_read_count; + __u32 gc_write_count; + __u32 gc_write_fail_count; + __u32 force_gc_count; + __u32 avg_pe_count; + __u32 max_pe_count; + __u32 free_blk_num1; + __u32 free_blk_num2; +} r1_wearlvl_vendor_log_count_t; + +typedef struct vendor_media_err { + __u64 lba_err[10]; +} vendor_media_err_t; + +typedef struct r1_vendor_log_io_err { + __u32 io_guard_err; + __u32 io_apptag_err; + __u32 io_reftag_err; + __u32 io_dma_linkdown_err; + __u32 io_dma_disable_err; + __u32 io_dma_timeout_err; + __u32 io_dma_fatal_err; + __u32 io_write_fail_cout; + __u32 io_read_fail_cout; + __u32 lba_err[6]; +} r1_vendor_log_io_err_t; + +typedef struct r1_vendor_log_s { + __u32 max_power; + __u32 disk_max_temper; + __u32 disk_overtemper_cout; + __u32 ctrl_max_temper; + __u32 ctrl_overtemper_cout; + r1_cap_transtime_t cap_transtime; + __u32 cap_health_state; + __u32 device_state; + r1_vendor_log_io_err_t io_err[4]; + union { + vendor_warning_str detail_warning_bit; + __u32 detail_warning[2]; + }; + union { + vendor_warning_str detail_warning_his_bit; + __u32 detail_warning_his[2]; + }; + __u32 ddr_bit_err_cout; + __u32 temp_throttle_per; + __u64 port0_fundamental_reset_cnt; + __u64 port0_hot_reset_cnt; + __u64 port0_func_reset_cnt; + __u64 port0_linkdown_cnt; + __u64 port0_ctrl_reset_cnt; + __u64 nand_bytes_written[4]; + __u32 power_info; + __u32 voltage_info; + __u32 current_info; + __u32 current_temp[4]; + __u32 nand_max_temper; + __u32 nand_overtemper_cout; + __u32 mcu_data_id; + __u8 commit_id[16]; + __u32 ces_RcvErr_cnt; + __u32 ces_BadTlp_cnt; + __u32 ces_BadDllp_cnt; + __u32 ces_Rplyover_cnt; + __u32 ces_RplyTo_cnt; + __u32 ces_Hlo_cnt; + __u32 scan_db_err_cnt; + __u32 db_int_err_cnt; + __u8 rsvFE[56]; + r1_vendor_log_nandctl_count_t vendor_log_nandctl_cnt[4]; + __u32 temp_ctrl_limit_cnt; + __u32 temp_ctrl_stop_cnt; + __u8 rsvncm[216]; + r1_wearlvl_vendor_log_count_t wearlvl_vendor_log_count[4]; + __u8 rsvwlm[512 - sizeof(r1_wearlvl_vendor_log_count_t) * 4 % 512]; + __u32 e2e_check_err_cnt1; + __u32 e2e_check_err_cnt2; + __u32 e2e_check_err_cnt3; + __u32 e2e_check_err_cnt4; + vendor_media_err_t media_err[4]; + __u8 rsvlkm[176]; +} r1_cli_vendor_log_t; +#pragma pack(pop) + +#endif // __INSPUR_UTILS_H__ diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c index f660b84409..378ecc0348 100644 --- a/plugins/intel/intel-nvme.c +++ b/plugins/intel/intel-nvme.c @@ -16,25 +16,25 @@ #define CREATE_CMD #include "intel-nvme.h" -struct __attribute__((packed)) nvme_additional_smart_log_item { +struct __packed nvme_additional_smart_log_item { __u8 key; __u8 _kp[2]; __u8 norm; __u8 _np; - union __attribute__((packed)) { + union __packed { __u8 raw[6]; - struct __attribute__((packed)) wear_level { + struct __packed wear_level { __le16 min; __le16 max; __le16 avg; } wear_level; - struct __attribute__((packed)) thermal_throttle { + struct __packed thermal_throttle { __u8 pct; __u32 count; } thermal_throttle; - } ; + }; __u8 _rp; -} ; +}; struct nvme_additional_smart_log { struct nvme_additional_smart_log_item program_fail_cnt; @@ -79,7 +79,7 @@ static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id, 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_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); @@ -92,7 +92,7 @@ static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id, 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; + struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs; char health[21] = { 0 }; char bl[9] = { 0 }; @@ -100,15 +100,10 @@ static void intel_id_ctrl(__u8 *vs, struct json_object *root) char mic_bl[5] = { 0 }; char mic_fw[5] = { 0 }; - - if (id->health[0]==0) - { - snprintf(health, 21, "%s", "healthy"); - } + if (id->health[0] == 0) + snprintf(health, 21, "%s", "healthy"); else - { - snprintf(health, 21, "%s", id->health); - } + 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], @@ -203,57 +198,57 @@ static void show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart, 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_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_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_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_int(entry_stats, "raw", int48_to_long(smart->host_bytes_written.raw)); json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->host_ctx_wear_used.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_ctx_wear_used.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_ctx_wear_used.raw)); json_object_add_value_object(dev_stats, "host_ctx_wear_used", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->perf_stat_indicator.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->perf_stat_indicator.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->perf_stat_indicator.raw)); json_object_add_value_object(dev_stats, "perf_stat_indicator", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->re_alloc_sectr_cnt.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->re_alloc_sectr_cnt.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->re_alloc_sectr_cnt.raw)); json_object_add_value_object(dev_stats, "re_alloc_sectr_cnt", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->soft_ecc_err_rate.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->soft_ecc_err_rate.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->soft_ecc_err_rate.raw)); json_object_add_value_object(dev_stats, "soft_ecc_err_rate", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->unexp_power_loss.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->unexp_power_loss.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->unexp_power_loss.raw)); json_object_add_value_object(dev_stats, "unexp_power_loss", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->media_bytes_read.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->media_bytes_read.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->media_bytes_read.raw)); json_object_add_value_object(dev_stats, "media_bytes_read", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "normalized", smart->avail_fw_downgrades.norm); - json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->avail_fw_downgrades.raw)); + json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->avail_fw_downgrades.raw)); json_object_add_value_object(dev_stats, "avail_fw_downgrades", entry_stats); json_object_add_value_object(root, "Device stats", dev_stats); @@ -337,11 +332,11 @@ static void show_intel_smart_log(struct nvme_additional_smart_log *smart, 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 *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"; + const char *json = "Dump output in json format"; struct nvme_additional_smart_log smart_log; struct nvme_dev *dev; @@ -379,9 +374,9 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, dev->name); else d_raw((unsigned char *)&smart_log, sizeof(smart_log)); - } - else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); return err; } @@ -490,7 +485,7 @@ struct intel_lat_stats { __u32 data[1216]; }; -struct __attribute__((__packed__)) optane_lat_stats { +struct __packed optane_lat_stats { __u16 maj; __u16 min; __u64 data[9]; @@ -645,7 +640,7 @@ static void show_optane_lat_stats_bucket(struct optane_lat_stats *stats, set_unit_string(buffer, upper_us, fu, end_type); printf("%-*s", COL_WIDTH, buffer); - printf("%-*lu\n", COL_WIDTH, (long unsigned int)stats->data[i]); + printf("%-*lu\n", COL_WIDTH, (unsigned long)stats->data[i]); } @@ -888,6 +883,7 @@ static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) } struct json_object *subroot = json_create_object(); + json_object_add_value_object(root, "Average latency since last reset", subroot); json_object_add_value_uint(subroot, "value in us", stats->data[8]); @@ -900,12 +896,13 @@ static void json_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) { int i; + if (write) { for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++) show_optane_lat_stats_bucket(stats, v1000_bucket.write[i], NOINF, - v1000_bucket.write[i + 1] -1, + v1000_bucket.write[i + 1] - 1, NOINF, i); show_optane_lat_stats_bucket(stats, v1000_bucket.write[i], @@ -916,7 +913,7 @@ static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) show_optane_lat_stats_bucket(stats, v1000_bucket.read[i], NOINF, - v1000_bucket.read[i + 1] -1, + v1000_bucket.read[i + 1] - 1, NOINF, i); show_optane_lat_stats_bucket(stats, v1000_bucket.read[i], @@ -924,7 +921,7 @@ static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write) POSINF, i); } - printf("Average latency since last reset: %lu us\n", (long unsigned int)stats->data[8]); + printf("Average latency since last reset: %lu us\n", (unsigned long)stats->data[8]); } @@ -1035,7 +1032,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct const char *desc = "Get Intel Latency Statistics log and show it."; const char *raw = "Dump output in binary format"; - const char *json= "Dump output in json format"; + const char *json = "Dump output in json format"; const char *write = "Get write statistics (read default)"; struct config { @@ -1068,7 +1065,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct media_version[1] = (data[3] << 8) | data[2]; if (err) - goto close_fd; + goto close_dev; if (media_version[0] == 1000) { __u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0}; @@ -1089,9 +1086,9 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct }; err = nvme_get_features(&args); if (err) { - fprintf(stderr, "Quering thresholds failed. "); + fprintf(stderr, "Querying thresholds failed. "); nvme_show_status(err); - goto close_fd; + goto close_dev; } /* Update bucket thresholds to be printed */ @@ -1127,7 +1124,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct sizeof(stats)); } -close_fd: +close_dev: dev_close(dev); return err; } @@ -1159,11 +1156,11 @@ struct intel_event_header { }; struct intel_vu_log { - struct intel_vu_version ver; - __u32 header; - __u32 size; - __u32 numcores; - __u8 reserved[4080]; + struct intel_vu_version ver; + __u32 header; + __u32 size; + __u32 numcores; + __u8 reserved[4080]; }; struct intel_vu_nlog { @@ -1197,7 +1194,7 @@ struct intel_cd_log { __u32 reserved2 : 16; } fields; __u32 entireDword; - } u; + } u; }; static void print_intel_nlog(struct intel_vu_nlog *intel_nlog) @@ -1272,7 +1269,7 @@ static int write_header(__u8 *buf, int fd, size_t amnt) return 0; } -static int read_header(struct nvme_passthru_cmd *cmd,__u8 *buf, int ioctl_fd, +static int read_header(struct nvme_passthru_cmd *cmd, __u8 *buf, int ioctl_fd, __u32 dw12, int nsid) { memset(cmd, 0, sizeof(*cmd)); @@ -1476,7 +1473,7 @@ static int get_internal_log(int argc, char **argv, struct command *command, if (err) goto out; - } else if(cfg.log == 0) { + } else if (cfg.log == 0) { /* If the user selected to read the entire nlog */ if (count > 1) cdlog.u.fields.selectNlog = i; @@ -1558,7 +1555,7 @@ static int enable_lat_stats_tracking(int argc, char **argv, .disable = false, }; - const struct argconfig_commandline_options command_line_options[] = { + struct argconfig_commandline_options command_line_options[] = { {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument, enable_desc}, {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument, disable_desc}, {NULL} @@ -1640,7 +1637,7 @@ static int enable_lat_stats_tracking(int argc, char **argv, break; default: printf("%d not supported.\n", option); - return EINVAL; + return -EINVAL; } dev_close(dev); return err; @@ -1697,6 +1694,7 @@ static int set_lat_stats_thresholds(int argc, char **argv, if (media_version[0] == 1000) { int thresholds[OPTANE_V1000_BUCKET_LEN] = {0}; + num = argconfig_parse_comma_sep_array(cfg.bucket_thresholds, thresholds, sizeof(thresholds)); diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c index 6fdd67597f..b215125dd6 100644 --- a/plugins/memblaze/memblaze-nvme.c +++ b/plugins/memblaze/memblaze-nvme.c @@ -3,10 +3,12 @@ #include #include #include +#include #include #include #include "nvme.h" +#include "common.h" #include "libnvme.h" #include "plugin.h" #include "linux/types.h" @@ -17,22 +19,22 @@ #include "memblaze-utils.h" enum { - // feature id - MB_FEAT_POWER_MGMT = 0x02, - MB_FEAT_HIGH_LATENCY = 0xE1, - // log id - GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM = 0xC1, - GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM = 0xC2, - GLP_ID_VU_GET_HIGH_LATENCY_LOG = 0xC3, - MB_FEAT_CLEAR_ERRORLOG = 0xF7, + /* feature id */ + MB_FEAT_POWER_MGMT = 0x02, + MB_FEAT_HIGH_LATENCY = 0xE1, + /* log id */ + GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM = 0xC1, + GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM = 0xC2, + GLP_ID_VU_GET_HIGH_LATENCY_LOG = 0xC3, + MB_FEAT_CLEAR_ERRORLOG = 0xF7, }; -#define LOG_PAGE_SIZE (0x1000) -#define DO_PRINT_FLAG (1) -#define NOT_PRINT_FLAG (0) -#define FID_C1_LOG_FILENAME "log_c1.csv" -#define FID_C2_LOG_FILENAME "log_c2.csv" -#define FID_C3_LOG_FILENAME "log_c3.csv" +#define LOG_PAGE_SIZE (0x1000) +#define DO_PRINT_FLAG (1) +#define NOT_PRINT_FLAG (0) +#define FID_C1_LOG_FILENAME "log_c1.csv" +#define FID_C2_LOG_FILENAME "log_c2.csv" +#define FID_C3_LOG_FILENAME "log_c3.csv" /* * Return -1 if @fw1 < @fw2 @@ -41,420 +43,370 @@ enum { */ 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; + 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 + * 1: new intel format + * 0: old memblaze format * *******************************************************/ -#define MEMBLAZE_FORMAT (0) -#define INTEL_FORMAT (1) +#define MEMBLAZE_FORMAT (0) +#define INTEL_FORMAT (1) -// 2.13 = papaya -#define IS_PAPAYA(str) (!strcmp(str, "2.13")) -// 2.83 = raisin -#define IS_RAISIN(str) (!strcmp(str, "2.83")) -// 2.94 = kumquat -#define IS_KUMQUAT(str) (!strcmp(str, "2.94")) -// 0.60 = loquat -#define IS_LOQUAT(str) (!strcmp(str, "0.60")) +/* 2.13 = papaya */ +#define IS_PAPAYA(str) (!strcmp(str, "2.13")) +/* 2.83 = raisin */ +#define IS_RAISIN(str) (!strcmp(str, "2.83")) +/* 2.94 = kumquat */ +#define IS_KUMQUAT(str) (!strcmp(str, "2.94")) +/* 0.60 = loquat */ +#define IS_LOQUAT(str) (!strcmp(str, "0.60")) -#define STR_VER_SIZE (5) +#define STR_VER_SIZE (5) int getlogpage_format_type(char *model_name) { - int logpage_format_type = INTEL_FORMAT; - const char *boundary_model_name1 = "P"; // MEMBLAZE P7936DT0640M00 - const char *boundary_model_name2 = "P5920"; // Use INTEL_FORMAT from Raisin P5920. - if (0 == strncmp(model_name, boundary_model_name1, strlen(boundary_model_name1))) - { - if (strncmp(model_name, boundary_model_name2, strlen(boundary_model_name2)) < 0) - { - logpage_format_type = MEMBLAZE_FORMAT; - } - } - return logpage_format_type; + int logpage_format_type = INTEL_FORMAT; + const char *boundary_model_name1 = "P"; /* MEMBLAZE P7936DT0640M00 */ + const char *boundary_model_name2 = "P5920"; /* Use INTEL_FORMAT from Raisin P5920. */ + + if (!strncmp(model_name, boundary_model_name1, strlen(boundary_model_name1))) { + if (strncmp(model_name, boundary_model_name2, strlen(boundary_model_name2)) < 0) + logpage_format_type = MEMBLAZE_FORMAT; + } + return logpage_format_type; } static __u32 item_id_2_u32(struct nvme_memblaze_smart_log_item *item) { - __le32 __id = 0; - memcpy(&__id, item->id, 3); - return le32_to_cpu(__id); + __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); + __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_count" -#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) +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); + 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) + unsigned int nsid, const char *devname) { - struct nvme_p4_smart_log *smart = (struct nvme_p4_smart_log *)s; - u8 *nm = malloc(NM_SIZE * sizeof(u8)); - u8 *raw = malloc(RAW_SIZE * sizeof(u8)); - - if (!nm) { - if (raw) - free(raw); - return; - } - if (!raw) { - free(nm); - return; - } - /* 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 */ - /* 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); + struct nvme_p4_smart_log *smart = (struct nvme_p4_smart_log *)s; + __u8 *nm = malloc(NM_SIZE * sizeof(__u8)); + __u8 *raw = malloc(RAW_SIZE * sizeof(__u8)); + + if (!nm) { + if (raw) + free(raw); + return; + } + if (!raw) { + free(nm); + return; + } + + printf("%s:%s %s:%x\n", "Additional Smart Log for NVME device", devname, "namespace-id", nsid); + printf("%-34s%-11s%s\n", "key", "normalized", "raw"); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PROGRAM_FAIL, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "program_fail_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_ERASE_FAIL, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "erase_fail_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_WEARLEVELING_COUNT, nm, raw); + printf("%-31s : %3d%% %s%u%s%u%s%u\n", "wear_leveling", *nm, + "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_E2E_DECTECTION_COUNT, nm, raw); + printf("%-31s: %3d%% %"PRIu64"\n", "end_to_end_error_detection_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PCIE_CRC_ERR_COUNT, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "crc_error_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR, nm, raw); + printf("%-32s: %3d%% %.3f%%\n", "timed_workload_media_wear", *nm, ((float)int48_to_long(raw))/1000); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ, nm, raw); + printf("%-32s: %3d%% %"PRIu64"%%\n", "timed_workload_host_reads", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_TIMER, nm, raw); + printf("%-32s: %3d%% %"PRIu64"%s\n", "timed_workload_timer", *nm, int48_to_long(raw), " min"); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_STATUS, nm, raw); + printf("%-32s: %3d%% %u%%%s%"PRIu64"\n", "thermal_throttle_status", *nm, + *raw, ", cnt: ", int48_to_long(raw+1)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "retry_buffer_overflow_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "pll_lock_loss_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_WRITE, nm, raw); + printf("%-32s: %3d%% %s%"PRIu64"\n", "nand_bytes_written", *nm, "sectors: ", int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_HOST_WRITE, nm, raw); + printf("%-32s: %3d%% %s%"PRIu64"\n", "host_bytes_written", *nm, "sectors: ", int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "system_area_life_left", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_READ, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "total_read", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BORN, nm, raw); + printf("%-32s: %3d%% %s%u%s%u%s%u\n", "tempt_since_born", *nm, + "max: ", *(__u16 *)raw, ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_POWER_CONSUMPTION, nm, raw); + printf("%-32s: %3d%% %s%u%s%u%s%u\n", "power_consumption", *nm, + "max: ", *(__u16 *)raw, ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BOOTUP, nm, raw); + printf("%-32s: %3d%% %s%u%s%u%s%u\n", "tempt_since_bootup", *nm, "max: ", *(__u16 *)raw, + ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_READ_FAIL, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "read_fail_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_TIME, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "thermal_throttle_time", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(smart, RAISIN_SI_VD_FLASH_MEDIA_ERROR, nm, raw); + printf("%-32s: %3d%% %"PRIu64"\n", "flash_media_error", *nm, int48_to_long(raw)); + + free(nm); + free(raw); } static void show_memblaze_smart_log_old(struct nvme_memblaze_smart_log *smart, - unsigned int nsid, const char *devname, const char *fw_ver) + unsigned int nsid, const char *devname, const char *fw_ver) { - char fw_ver_local[STR_VER_SIZE + 1]; - struct nvme_memblaze_smart_log_item *item; - - strncpy(fw_ver_local, fw_ver, STR_VER_SIZE); - *(fw_ver_local + STR_VER_SIZE) = '\0'; - - printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid); - - printf("Total write in GB since last factory reset : %"PRIu64"\n", - int48_to_long(smart->items[TOTAL_WRITE].rawval)); - printf("Total read in GB since last factory reset : %"PRIu64"\n", - int48_to_long(smart->items[TOTAL_READ].rawval)); - - printf("Thermal throttling status[1:HTP in progress] : %u\n", - smart->items[THERMAL_THROTTLE].thermal_throttle.on); - printf("Total thermal throttling minutes since power on : %u\n", - smart->items[THERMAL_THROTTLE].thermal_throttle.count); - - printf("Maximum temperature in 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)); - - if (!nm) { - if (raw) - free(raw); - return; + char fw_ver_local[STR_VER_SIZE + 1]; + struct nvme_memblaze_smart_log_item *item; + + strncpy(fw_ver_local, fw_ver, STR_VER_SIZE); + *(fw_ver_local + STR_VER_SIZE) = '\0'; + + printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid); + + printf("Total write in GB since last factory reset : %"PRIu64"\n", + int48_to_long(smart->items[TOTAL_WRITE].rawval)); + printf("Total read in GB since last factory reset : %"PRIu64"\n", + int48_to_long(smart->items[TOTAL_READ].rawval)); + + printf("Thermal throttling status[1:HTP in progress] : %u\n", + smart->items[THERMAL_THROTTLE].thermal_throttle.on); + printf("Total thermal throttling minutes since power on : %u\n", + smart->items[THERMAL_THROTTLE].thermal_throttle.count); + + printf("Maximum temperature in kelvins since last factory reset : %u\n", + le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.max)); + printf("Minimum temperature in kelvins since last factory reset : %u\n", + le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.min)); + if (compare_fw_version(fw_ver, "0.09.0300") != 0) { + printf("Maximum temperature in kelvins since power on : %u\n", + le16_to_cpu(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.max)); + printf("Minimum temperature in kelvins since power on : %u\n", + le16_to_cpu(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.min)); } - if (!raw) { - free(nm); - return; + printf("Current temperature in kelvins : %u\n", + le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.curr)); + + printf("Maximum power in watt since power on : %u\n", + le16_to_cpu(smart->items[POWER_CONSUMPTION].power.max)); + printf("Minimum power in watt since power on : %u\n", + le16_to_cpu(smart->items[POWER_CONSUMPTION].power.min)); + printf("Current power in watt : %u\n", + le16_to_cpu(smart->items[POWER_CONSUMPTION].power.curr)); + + item = &smart->items[POWER_LOSS_PROTECTION]; + if (item_id_2_u32(item) == 0xEC) + printf("Power loss protection normalized value : %u\n", + item->power_loss_protection.curr); + + item = &smart->items[WEARLEVELING_COUNT]; + if (item_id_2_u32(item) == 0xAD) { + printf("Percentage of wearleveling count left : %u\n", + le16_to_cpu(item->nmval)); + printf("Wearleveling count min erase cycle : %u\n", + le16_to_cpu(item->wearleveling_count.min)); + printf("Wearleveling count max erase cycle : %u\n", + le16_to_cpu(item->wearleveling_count.max)); + printf("Wearleveling count avg erase cycle : %u\n", + le16_to_cpu(item->wearleveling_count.avg)); + } + + item = &smart->items[HOST_WRITE]; + if (item_id_2_u32(item) == 0xF5) + printf("Total host write in GiB since device born : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + item = &smart->items[THERMAL_THROTTLE_CNT]; + if (item_id_2_u32(item) == 0xEB) + printf("Thermal throttling count since device born : %u\n", + item->thermal_throttle_cnt.cnt); + + item = &smart->items[CORRECT_PCIE_PORT0]; + if (item_id_2_u32(item) == 0xED) + printf("PCIE Correctable Error Count of Port0 : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + item = &smart->items[CORRECT_PCIE_PORT1]; + if (item_id_2_u32(item) == 0xEE) + printf("PCIE Correctable Error Count of Port1 : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + item = &smart->items[REBUILD_FAIL]; + if (item_id_2_u32(item) == 0xEF) + printf("End-to-End Error Detection Count : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + item = &smart->items[ERASE_FAIL]; + if (item_id_2_u32(item) == 0xF0) + printf("Erase Fail Count : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + item = &smart->items[PROGRAM_FAIL]; + if (item_id_2_u32(item) == 0xF1) + printf("Program Fail Count : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + item = &smart->items[READ_FAIL]; + if (item_id_2_u32(item) == 0xF2) + printf("Read Fail Count : %llu\n", + (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval))); + + if (IS_PAPAYA(fw_ver_local)) { + struct nvme_p4_smart_log *s = (struct nvme_p4_smart_log *)smart; + __u8 *nm = malloc(NM_SIZE * sizeof(__u8)); + __u8 *raw = malloc(RAW_SIZE * sizeof(__u8)); + + if (!nm) { + if (raw) + free(raw); + return; + } + if (!raw) { + free(nm); + return; + } + get_memblaze_new_smart_info(s, PROGRAM_FAIL, nm, raw); + printf("%-32s : %3d%% %"PRIu64"\n", + "program_fail_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(s, ERASE_FAIL, nm, raw); + printf("%-32s : %3d%% %"PRIu64"\n", + "erase_fail_count", *nm, int48_to_long(raw)); + + get_memblaze_new_smart_info(s, WEARLEVELING_COUNT, nm, raw); + printf("%-31s : %3d%% %s%u%s%u%s%u\n", + "wear_leveling", *nm, "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4)); + + get_memblaze_new_smart_info(s, TOTAL_WRITE, nm, raw); + printf("%-32s : %3d%% %"PRIu64"\n", + "nand_bytes_written", *nm, 32*int48_to_long(raw)); + + get_memblaze_new_smart_info(s, HOST_WRITE, nm, raw); + printf("%-32s : %3d%% %"PRIu64"\n", + "host_bytes_written", *nm, 32*int48_to_long(raw)); + + free(nm); + free(raw); } - /* 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_memblaze_smart_log *smart) { - struct nvme_id_ctrl ctrl; - char fw_ver[10]; - int err = 0; - - err = nvme_identify_ctrl(fd, &ctrl); - if (err) - return err; - - snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c", - ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3], - ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]); - - if (getlogpage_format_type(ctrl.mn)) // Intel Format & new format - { - show_memblaze_smart_log_new(smart, nsid, devname); - } - else // Memblaze Format & old format - { - show_memblaze_smart_log_old(smart, nsid, devname, fw_ver); - } + struct nvme_id_ctrl ctrl; + char fw_ver[10]; + int err = 0; + + err = nvme_identify_ctrl(fd, &ctrl); + if (err) + return err; + + snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c", + ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3], + ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]); + + if (getlogpage_format_type(ctrl.mn)) /* Intel Format & new format */ + show_memblaze_smart_log_new(smart, nsid, devname); + else /* Memblaze Format & old format */ + show_memblaze_smart_log_old(smart, nsid, devname, fw_ver); return err; } int parse_params(char *str, int number, ...) { - va_list argp; - int *param; - char *c; - int value; - - va_start(argp, number); - - while (number > 0) { - c = strtok(str, ","); - if ( c == NULL) { - printf("No enough parameters. abort...\n"); - va_end(argp); - return 1; - } - - if (isalnum((int)*c) == 0) { - printf("%s is not a valid number\n", c); - va_end(argp); - return 1; - } - value = atoi(c); - param = va_arg(argp, int *); - *param = value; - - if (str) { - str = strchr(str, ','); - if (str) { str++; } - } - number--; - } - va_end(argp); - - return 0; + va_list argp; + int *param; + char *c; + int value; + + va_start(argp, number); + + while (number > 0) { + c = strtok(str, ","); + if (!c) { + printf("No enough parameters. abort...\n"); + va_end(argp); + return 1; + } + + if (!isalnum((int)*c)) { + printf("%s is not a valid number\n", c); + va_end(argp); + return 1; + } + value = atoi(c); + param = va_arg(argp, int *); + *param = value; + + if (str) { + str = strchr(str, ','); + if (str) + str++; + } + number--; + } + va_end(argp); + + return 0; } static int mb_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { struct nvme_memblaze_smart_log smart_log; - char *desc = "Get Memblaze vendor specific additional smart log (optionally, "\ - "for the specified namespace), and show it."; + char *desc = + "Get Memblaze vendor specific additional smart log (optionally, for the specified namespace), and show it."; const char *namespace = "(optional) desired namespace"; const char *raw = "dump output in binary format"; struct nvme_dev *dev; @@ -470,7 +422,7 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_END() }; @@ -482,9 +434,8 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm sizeof(smart_log), &smart_log); if (!err) { if (!cfg.raw_binary) - err = show_memblaze_smart_log(dev_fd(dev), - cfg.namespace_id, - dev->name, &smart_log); + err = show_memblaze_smart_log(dev_fd(dev), cfg.namespace_id, dev->name, + &smart_log); else d_raw((unsigned char *)&smart_log, sizeof(smart_log)); } @@ -497,333 +448,326 @@ static int mb_get_additional_smart_log(int argc, char **argv, struct command *cm static char *mb_feature_to_string(int feature) { - switch (feature) { - case MB_FEAT_POWER_MGMT: return "Memblaze power management"; - case MB_FEAT_HIGH_LATENCY: return "Memblaze high latency log"; - case MB_FEAT_CLEAR_ERRORLOG: return "Memblaze clear error log"; - default: return "Unknown"; - } + switch (feature) { + case MB_FEAT_POWER_MGMT: + return "Memblaze power management"; + case MB_FEAT_HIGH_LATENCY: + return "Memblaze high latency log"; + case MB_FEAT_CLEAR_ERRORLOG: + return "Memblaze clear error log"; + default: + return "Unknown"; + } } static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)"; - __u32 result; - __u32 feature_id = MB_FEAT_POWER_MGMT; - struct nvme_dev *dev; - int err; - - OPT_ARGS(opts) = { - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = feature_id, - .nsid = 0, - .sel = 0, - .cdw11 = 0, - .uuidx = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_get_features(&args); - if (err < 0) { - perror("get-feature"); - } - if (!err) { - printf("get-feature:0x%02x (%s), %s value: %#08x\n", feature_id, - mb_feature_to_string(feature_id), - nvme_select_to_string(0), result); - } else if (err > 0) - nvme_show_status(err); - dev_close(dev); - return err; + const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)"; + __u32 result; + __u32 feature_id = MB_FEAT_POWER_MGMT; + struct nvme_dev *dev; + int err; + + OPT_ARGS(opts) = { + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = feature_id, + .nsid = 0, + .sel = 0, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_get_features(&args); + if (err < 0) + perror("get-feature"); + if (!err) + printf("get-feature:0x%02x (%s), %s value: %#08x\n", feature_id, + mb_feature_to_string(feature_id), nvme_select_to_string(0), result); + else if (err > 0) + nvme_show_status(err); + dev_close(dev); + return err; } static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Set Memblaze power management status\n (value 0 - 25w, 1 - 20w, 2 - 15w)"; - const char *value = "new value of feature (required)"; - const char *save = "specifies that the controller shall save the attribute"; - struct nvme_dev *dev; - __u32 result; - int err; - - struct config { - __u32 feature_id; - __u32 value; - bool save; - }; - - struct config cfg = { - .feature_id = MB_FEAT_POWER_MGMT, - .value = 0, - .save = 0, - }; - - OPT_ARGS(opts) = { - OPT_UINT("value", 'v', &cfg.value, value), - OPT_FLAG("save", 's', &cfg.save, save), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = cfg.feature_id, - .nsid = 0, - .cdw11 = cfg.value, - .cdw12 = 0, - .save = cfg.save, - .uuidx = 0, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_set_features(&args); - if (err < 0) { - perror("set-feature"); - } - if (!err) { - printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, - mb_feature_to_string(cfg.feature_id), cfg.value); - } else if (err > 0) - nvme_show_status(err); - - dev_close(dev); - return err; + const char *desc = "Set Memblaze power management status\n (value 0 - 25w, 1 - 20w, 2 - 15w)"; + const char *value = "new value of feature (required)"; + const char *save = "specifies that the controller shall save the attribute"; + struct nvme_dev *dev; + __u32 result; + int err; + + struct config { + __u32 feature_id; + __u32 value; + bool save; + }; + + struct config cfg = { + .feature_id = MB_FEAT_POWER_MGMT, + .value = 0, + .save = 0, + }; + + OPT_ARGS(opts) = { + OPT_UINT("value", 'v', &cfg.value, value), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = cfg.feature_id, + .nsid = 0, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = cfg.save, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (err < 0) + perror("set-feature"); + if (!err) + printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, + mb_feature_to_string(cfg.feature_id), cfg.value); + else if (err > 0) + nvme_show_status(err); + + dev_close(dev); + return err; } -#define P2MIN (1) -#define P2MAX (5000) -#define MB_FEAT_HIGH_LATENCY_VALUE_SHIFT (15) +#define P2MIN (1) +#define P2MAX (5000) +#define MB_FEAT_HIGH_LATENCY_VALUE_SHIFT (15) static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Set Memblaze high latency log\n"\ - " input parameter p1,p2\n"\ - " p1 value: 0 is disable, 1 is enable\n"\ - " p2 value: 1 .. 5000 ms"; - const char *param = "input parameters"; - int param1 = 0, param2 = 0; - struct nvme_dev *dev; - __u32 result; - int err; - - struct config { - __u32 feature_id; - char * param; - __u32 value; - }; - - struct config cfg = { - .feature_id = MB_FEAT_HIGH_LATENCY, - .param = "0,0", - .value = 0, - }; - - OPT_ARGS(opts) = { - OPT_LIST("param", 'p', &cfg.param, param), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - if (parse_params(cfg.param, 2, ¶m1, ¶m2)) { - printf("setfeature: invalid formats %s\n", cfg.param); - dev_close(dev); - return EINVAL; - } - if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) { - printf("setfeature: invalid high io latency threshold %d\n", param2); - dev_close(dev); - return EINVAL; - } - cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2; - - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = cfg.feature_id, - .nsid = 0, - .cdw11 = cfg.value, - .cdw12 = 0, - .save = false, - .uuidx = 0, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_set_features(&args); - if (err < 0) { - perror("set-feature"); - } - if (!err) { - printf("set-feature:0x%02X (%s), value:%#08x\n", cfg.feature_id, - mb_feature_to_string(cfg.feature_id), cfg.value); - } else if (err > 0) - nvme_show_status(err); - - dev_close(dev); - return err; + const char *desc = "Set Memblaze high latency log\n" + " input parameter p1,p2\n" + " p1 value: 0 is disable, 1 is enable\n" + " p2 value: 1 .. 5000 ms"; + const char *param = "input parameters"; + int param1 = 0, param2 = 0; + struct nvme_dev *dev; + __u32 result; + int err; + + struct config { + __u32 feature_id; + char *param; + __u32 value; + }; + + struct config cfg = { + .feature_id = MB_FEAT_HIGH_LATENCY, + .param = "0,0", + .value = 0, + }; + + OPT_ARGS(opts) = { + OPT_LIST("param", 'p', &cfg.param, param), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (parse_params(cfg.param, 2, ¶m1, ¶m2)) { + printf("setfeature: invalid formats %s\n", cfg.param); + dev_close(dev); + return -EINVAL; + } + if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) { + printf("setfeature: invalid high io latency threshold %d\n", param2); + dev_close(dev); + return -EINVAL; + } + cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = cfg.feature_id, + .nsid = 0, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = false, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (err < 0) + perror("set-feature"); + if (!err) + printf("set-feature:0x%02X (%s), value:%#08x\n", cfg.feature_id, + mb_feature_to_string(cfg.feature_id), cfg.value); + else if (err > 0) + nvme_show_status(err); + + dev_close(dev); + return err; } static int glp_high_latency_show_bar(FILE *fdi, int print) { - fPRINT_PARAM1("Memblaze High Latency Log\n"); - fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n"); - fPRINT_PARAM1("Timestamp Type QID CID NSID StartLBA NumLBA Latency\n"); - fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n"); - return 0; + fPRINT_PARAM1("Memblaze High Latency Log\n"); + fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n"); + fPRINT_PARAM1("Timestamp Type QID CID NSID StartLBA NumLBA Latency\n"); + fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n"); + return 0; } -/* High latency log page definiton +/* + * High latency log page definition * Total 32 bytes */ -typedef struct -{ - __u8 port; - __u8 revision; - __u16 rsvd; - __u8 opcode; - __u8 sqe; - __u16 cid; - __u32 nsid; - __u32 latency; - __u64 sLBA; - __u16 numLBA; - __u16 timestampH; - __u32 timestampL; -} log_page_high_latency_t; /* total 32 bytes */ +struct log_page_high_latency { + __u8 port; + __u8 revision; + __u16 rsvd; + __u8 opcode; + __u8 sqe; + __u16 cid; + __u32 nsid; + __u32 latency; + __u64 sLBA; + __u16 numLBA; + __u16 timestampH; + __u32 timestampL; +}; /* total 32 bytes */ static int find_deadbeef(char *buf) { - if (((*(buf + 0) & 0xff) == 0xef) && ((*(buf + 1) & 0xff) == 0xbe) && \ - ((*(buf + 2) & 0xff) == 0xad) && ((*(buf + 3) & 0xff) == 0xde)) - { - return 1; - } - return 0; + if (((*(buf + 0) & 0xff) == 0xef) && ((*(buf + 1) & 0xff) == 0xbe) && + ((*(buf + 2) & 0xff) == 0xad) && ((*(buf + 3) & 0xff) == 0xde)) + return 1; + return 0; } -#define TIME_STR_SIZE (44) +#define TIME_STR_SIZE (44) static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print) { - log_page_high_latency_t *logEntry; - char string[TIME_STR_SIZE]; - int i, entrySize; - __u64 timestamp; - time_t tt = 0; - struct tm *t = NULL; - int millisec = 0; - - if (find_deadbeef(buf)) return 0; - - entrySize = sizeof(log_page_high_latency_t); - for (i = 0; i < buflen; i += entrySize) - { - logEntry = (log_page_high_latency_t *)(buf + i); - - if (logEntry->latency == 0 && logEntry->revision == 0) - { - return 1; - } - - if (0 == logEntry->timestampH) // generate host time string - { - snprintf(string, sizeof(string), "%d", logEntry->timestampL); - } - else // sort - { - timestamp = logEntry->timestampH - 1; - timestamp = timestamp << 32; - timestamp += logEntry->timestampL; - tt = timestamp / 1000; - millisec = timestamp % 1000; - t = gmtime(&tt); - snprintf(string, sizeof(string), "%4d%02d%02d--%02d:%02d:%02d.%03d UTC", - 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, millisec); - } - - if (fdi) { - fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n", - string, logEntry->opcode, logEntry->sqe, - logEntry->cid, logEntry->nsid, - (__u32)(logEntry->sLBA >> 32), - (__u32)logEntry->sLBA, logEntry->numLBA, - logEntry->latency); + struct log_page_high_latency *logEntry; + char string[TIME_STR_SIZE]; + int i, entrySize; + __u64 timestamp; + time_t tt = 0; + struct tm *t = NULL; + int millisec = 0; + + if (find_deadbeef(buf)) + return 0; + + entrySize = sizeof(struct log_page_high_latency); + for (i = 0; i < buflen; i += entrySize) { + logEntry = (struct log_page_high_latency *)(buf + i); + + if (logEntry->latency == 0 && logEntry->revision == 0) + return 1; + + if (!logEntry->timestampH) { /* generate host time string */ + snprintf(string, sizeof(string), "%d", logEntry->timestampL); + } else { /* sort */ + timestamp = logEntry->timestampH; + timestamp = timestamp << 32; + timestamp += logEntry->timestampL; + tt = timestamp / 1000; + millisec = timestamp % 1000; + t = gmtime(&tt); + snprintf(string, sizeof(string), "%4d%02d%02d--%02d:%02d:%02d.%03d UTC", + 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, + t->tm_min, t->tm_sec, millisec); + } + + if (fdi) + fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n", + string, logEntry->opcode, logEntry->sqe, + logEntry->cid, logEntry->nsid, + (__u32)(logEntry->sLBA >> 32), + (__u32)logEntry->sLBA, logEntry->numLBA, + logEntry->latency); + if (print) + printf("%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n", + string, logEntry->opcode, logEntry->sqe, logEntry->cid, + logEntry->nsid, (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, + logEntry->numLBA, logEntry->latency); } - if (print) - { - printf("%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n", - string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid, - (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency); - } - } - return 1; + return 1; } static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Get Memblaze high latency log"; - char buf[LOG_PAGE_SIZE]; - struct nvme_dev *dev; - FILE *fdi = NULL; - int err; - - OPT_ARGS(opts) = { - OPT_END() - }; + const char *desc = "Get Memblaze high latency log"; + char buf[LOG_PAGE_SIZE]; + struct nvme_dev *dev; + FILE *fdi = NULL; + int err; - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; + OPT_ARGS(opts) = { + OPT_END() + }; - fdi = fopen(FID_C3_LOG_FILENAME, "w+"); + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; - glp_high_latency_show_bar(fdi, DO_PRINT_FLAG); - err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG, - sizeof(buf), &buf); + fdi = fopen(FID_C3_LOG_FILENAME, "w+"); - while (1) { - if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG)) break; - err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG, + glp_high_latency_show_bar(fdi, DO_PRINT_FLAG); + err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG, sizeof(buf), &buf); - if ( err) { - nvme_show_status(err); - break; - } - } - - if (NULL != fdi) fclose(fdi); - dev_close(dev); - return err; -} + while (1) { + if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG)) + break; + err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG, + sizeof(buf), &buf); + if (err) { + nvme_show_status(err); + break; + } + } + + if (fdi) + fclose(fdi); + dev_close(dev); + return err; +} static int memblaze_fw_commit(int fd, int select) { struct nvme_passthru_cmd cmd = { .opcode = nvme_admin_fw_commit, .cdw10 = 8, - .cdw12 = select, + .cdw12 = select, }; return nvme_submit_admin_passthru(fd, &cmd, NULL); @@ -832,9 +776,9 @@ static int memblaze_fw_commit(int fd, int select) static int mb_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = - "This performs a selective firmware download, which allows the user to " - "select which firmware binary to update for 9200 devices. This requires a power cycle once the " - "update completes. The options available are: \n\n" + "This performs a selective firmware download, which allows the user to\n" + "select which firmware binary to update for 9200 devices. This requires a power cycle once the\n" + "update completes. The options available are:\n\n" "OOB - This updates the OOB and main firmware\n" "EEP - This updates the eeprom and main firmware\n" "ALL - This updates the eeprom, OOB, and main firmware"; @@ -842,18 +786,18 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str const char *select = "FW Select (e.g., --select=OOB, EEP, ALL)"; int xfer = 4096; void *fw_buf; - int selectNo,fw_fd,fw_size,err,offset = 0; + int selectNo, fw_fd, fw_size, err, offset = 0; struct nvme_dev *dev; struct stat sb; int i; struct config { - char *fw; - char *select; + char *fw; + char *select; }; struct config cfg = { - .fw = "", + .fw = "", .select = "\0", }; @@ -873,15 +817,14 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str goto out; } - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) cfg.select[i] = toupper(cfg.select[i]); - } - if (strncmp(cfg.select,"OOB", 3) == 0) { + if (!strncmp(cfg.select, "OOB", 3)) { selectNo = 18; - } else if (strncmp(cfg.select,"EEP", 3) == 0) { + } else if (!strncmp(cfg.select, "EEP", 3)) { selectNo = 10; - } else if (strncmp(cfg.select,"ALL", 3) == 0) { + } else if (!strncmp(cfg.select, "ALL", 3)) { selectNo = 26; } else { fprintf(stderr, "Invalid select flag\n"); @@ -941,14 +884,14 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str nvme_show_status(err); goto out_free; } - fw_buf += xfer; + fw_buf += xfer; fw_size -= xfer; offset += xfer; } err = memblaze_fw_commit(dev_fd(dev), selectNo); - if(err == 0x10B || err == 0x20B) { + if (err == 0x10B || err == 0x20B) { err = 0; fprintf(stderr, "Update successful! Please power cycle for changes to take effect\n"); } @@ -963,216 +906,181 @@ static int mb_selective_download(int argc, char **argv, struct command *cmd, str } static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, char *unit0, - char *unit1, unsigned int *pHistogram, int print) + char *unit1, unsigned int *pHistogram, int print) { - int len; - char string[64], subString0[12], subString1[12]; - - snprintf(subString0, sizeof(subString0), "%d%s", start, unit0); - if (end != 0x7FFFFFFF) - snprintf(subString1, sizeof(subString1), "%d%s", end, unit1); - else - snprintf(subString1, sizeof(subString1), "%s", "+INF"); - len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n", + int len; + char string[64], subString0[12], subString1[12]; + + snprintf(subString0, sizeof(subString0), "%d%s", start, unit0); + if (end != 0x7FFFFFFF) + snprintf(subString1, sizeof(subString1), "%d%s", end, unit1); + else + snprintf(subString1, sizeof(subString1), "%s", "+INF"); + len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n", index, subString0, subString1, - pHistogram[index]); - fwrite(string, 1, len, fd); - if (print) - printf("%s", string); + pHistogram[index]); + fwrite(string, 1, len, fd); + if (print) + printf("%s", string); } int io_latency_histogram(char *file, char *buf, int print, int logid) { - FILE *fdi = fopen(file, "w+"); - int i, index; - char unit[2][3]; - unsigned int *revision = (unsigned int *)buf; - - if (logid == GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM) - { - fPRINT_PARAM1("Memblaze IO Read Command Latency Histogram\n"); - } - else if (logid == GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM) - { - fPRINT_PARAM1("Memblaze IO Write Command Latency Histogram\n"); - } - fPRINT_PARAM2("Major Revision : %d\n", revision[1]); - fPRINT_PARAM2("Minor Revision : %d\n", revision[0]); - buf += 8; - - if (revision[1] == 1 && revision[0] == 0) - { - fPRINT_PARAM1("--------------------------------------------------\n"); - fPRINT_PARAM1("Bucket Start End Value \n"); - fPRINT_PARAM1("--------------------------------------------------\n"); - index = 0; - strcpy(unit[0], "us"); - strcpy(unit[1], "us"); - for (i = 0; i < 32; i++, index++) - { - if (i == 31) - { - strcpy(unit[1], "ms"); - ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print); - } - else - { - ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf, - print); - } - } - - strcpy(unit[0], "ms"); - strcpy(unit[1], "ms"); - for (i = 1; i < 32; i++, index++) - { - ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print); - } - - for (i = 1; i < 32; i++, index++) - { - if (i == 31) - { - strcpy(unit[1], "s"); - ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print); - } - else - { - ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf, - print); - } - } - - strcpy(unit[0], "s"); - strcpy(unit[1], "s"); - for (i = 1; i < 4; i++, index++) - { - ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print); - } - - ioLatencyHistogramOutput(fdi, index, i, 0x7FFFFFFF, unit[0], unit[1], (unsigned int *)buf, print); - } - else - { - fPRINT_PARAM1("Unsupported io latency histogram revision\n"); - } - - if (fdi) - fclose(fdi); - return 1; + FILE *fdi = fopen(file, "w+"); + int i, index; + char unit[2][3]; + unsigned int *revision = (unsigned int *)buf; + + if (logid == GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM) + fPRINT_PARAM1("Memblaze IO Read Command Latency Histogram\n"); + else if (logid == GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM) + fPRINT_PARAM1("Memblaze IO Write Command Latency Histogram\n"); + fPRINT_PARAM2("Major Revision : %d\n", revision[1]); + fPRINT_PARAM2("Minor Revision : %d\n", revision[0]); + buf += 8; + + if (revision[1] == 1 && revision[0] == 0) { + fPRINT_PARAM1("--------------------------------------------------\n"); + fPRINT_PARAM1("Bucket Start End Value\n"); + fPRINT_PARAM1("--------------------------------------------------\n"); + index = 0; + strcpy(unit[0], "us"); + strcpy(unit[1], "us"); + for (i = 0; i < 32; i++, index++) { + if (i == 31) { + strcpy(unit[1], "ms"); + ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], + (unsigned int *)buf, print); + } else { + ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], + unit[1], (unsigned int *)buf, print); + } + } + + strcpy(unit[0], "ms"); + strcpy(unit[1], "ms"); + for (i = 1; i < 32; i++, index++) + ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print); + + for (i = 1; i < 32; i++, index++) { + if (i == 31) { + strcpy(unit[1], "s"); + ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], + (unsigned int *)buf, print); + } else { + ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], + unit[1], (unsigned int *)buf, print); + } + } + + strcpy(unit[0], "s"); + strcpy(unit[1], "s"); + for (i = 1; i < 4; i++, index++) + ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print); + + ioLatencyHistogramOutput(fdi, index, i, 0x7FFFFFFF, unit[0], unit[1], (unsigned int *)buf, print); + } else { + fPRINT_PARAM1("Unsupported io latency histogram revision\n"); + } + + if (fdi) + fclose(fdi); + return 1; } static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - char stats[LOG_PAGE_SIZE]; - char f1[] = FID_C1_LOG_FILENAME; - char f2[] = FID_C2_LOG_FILENAME; - struct nvme_dev *dev; - int err; - - const char *desc = "Get Latency Statistics log and show it."; - const char *write = "Get write statistics (read default)"; - - struct config { - bool write; - }; - struct config cfg = { - .write = 0, - }; - - OPT_ARGS(opts) = { - OPT_FLAG("write", 'w', &cfg.write, write), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc2 : 0xc1, - sizeof(stats), &stats); - if (!err) - io_latency_histogram(cfg.write ? f2 : f1, stats, DO_PRINT_FLAG, - cfg.write ? GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM : GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM); - else - nvme_show_status(err); - - dev_close(dev); - return err; + char stats[LOG_PAGE_SIZE]; + char f1[] = FID_C1_LOG_FILENAME; + char f2[] = FID_C2_LOG_FILENAME; + struct nvme_dev *dev; + int err; + + const char *desc = "Get Latency Statistics log and show it."; + const char *write = "Get write statistics (read default)"; + + struct config { + bool write; + }; + struct config cfg = { + .write = 0, + }; + + OPT_ARGS(opts) = { + OPT_FLAG("write", 'w', &cfg.write, write), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc2 : 0xc1, + sizeof(stats), &stats); + if (!err) + io_latency_histogram(cfg.write ? f2 : f1, stats, DO_PRINT_FLAG, + cfg.write ? GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM : + GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM); + else + nvme_show_status(err); + + dev_close(dev); + return err; } -#define OP 0xFC -#define FID 0x68 static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - char *desc = "Clear Memblaze devices error log."; - struct nvme_dev *dev; - int err; - - //const char *value = "new value of feature (required)"; - //const char *save = "specifies that the controller shall save the attribute"; - __u32 result; - - struct config { - __u32 feature_id; - __u32 value; - int save; - }; - - struct config cfg = { - .feature_id = 0xf7, - .value = 0x534d0001, - .save = 0, - }; - - OPT_ARGS(opts) = { - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = cfg.feature_id, - .nsid = 0, - .cdw11 = cfg.value, - .cdw12 = 0, - .save = cfg.save, - .uuidx = 0, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_set_features(&args); - if (err < 0) { - perror("set-feature"); - } - if (!err) { - printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value); - } else if (err > 0) - nvme_show_status(err); + char *desc = "Clear Memblaze devices error log."; + struct nvme_dev *dev; + int err; -/* - struct nvme_admin_cmd admin_cmd = { - .opcode = OP, - .cdw10 = FID, + __u32 result; + + struct config { + __u32 feature_id; + __u32 value; + int save; }; - err = nvme_submit_admin_passthru(fd, &admin_cmd); + struct config cfg = { + .feature_id = 0xf7, + .value = 0x534d0001, + .save = 0, + }; - if (!err) { - printf("OP(0x%2X) FID(0x%2X) Clear error log success.\n", OP, FID); - } else { - printf("NVMe Status:%s(%x)\n", nvme_status_to_string(err), err); + OPT_ARGS(opts) = { + OPT_END() }; -*/ - dev_close(dev); - return err; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = cfg.feature_id, + .nsid = 0, + .cdw11 = cfg.value, + .cdw12 = 0, + .save = cfg.save, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (err < 0) + perror("set-feature"); + if (!err) + printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value); + else if (err > 0) + nvme_show_status(err); + + dev_close(dev); + return err; } static int mb_set_lat_stats(int argc, char **argv, @@ -1204,7 +1112,7 @@ static int mb_set_lat_stats(int argc, char **argv, .disable = false, }; - const struct argconfig_commandline_options command_line_options[] = { + struct argconfig_commandline_options command_line_options[] = { {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument, enable_desc}, {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument, disable_desc}, {NULL} @@ -1271,7 +1179,7 @@ static int mb_set_lat_stats(int argc, char **argv, break; case True: case False: - err = nvme_set_features(&args_set); + err = nvme_set_features(&args_set); if (err > 0) { nvme_show_status(err); } else if (err < 0) { @@ -1290,3 +1198,645 @@ static int mb_set_lat_stats(int argc, char **argv, return err; } +// Global definitions + +static inline int K2C(int k) // KELVINS_2_CELSIUS +{ + return (k - 273); +}; + +// Global ID definitions + +enum { + // feature ids + FID_LATENCY_FEATURE = 0xd0, + + // log ids + LID_SMART_LOG_ADD = 0xca, + LID_LATENCY_STATISTICS = 0xd0, + LID_HIGH_LATENCY_LOG = 0xd1, + LID_PERFORMANCE_STATISTICS = 0xd2, +}; + +// smart-log-add + +struct smart_log_add_item { + uint32_t index; + char *attr; +}; + +struct __packed wear_level { + __le16 min; + __le16 max; + __le16 avg; +}; + +struct __packed smart_log_add_item_12 { + uint8_t id; + uint8_t rsvd[2]; + uint8_t norm; + uint8_t rsvd1; + union { + struct wear_level wear_level; // 0xad + struct temp_since_born { // 0xe7 + __le16 max; + __le16 min; + __le16 curr; + } temp_since_born; + struct power_consumption { // 0xe8 + __le16 max; + __le16 min; + __le16 curr; + } power_consumption; + struct temp_since_power_on { // 0xaf + __le16 max; + __le16 min; + __le16 curr; + } temp_since_power_on; + uint8_t raw[6]; + }; + uint8_t rsvd2; +}; + +struct __packed smart_log_add_item_10 { + uint8_t id; + uint8_t norm; + union { + struct wear_level wear_level; // 0xad + uint8_t raw[6]; + }; + uint8_t rsvd[2]; +}; + +struct smart_log_add { + union { + union { + struct smart_log_add_v0 { + struct smart_log_add_item_12 program_fail_count; + struct smart_log_add_item_12 erase_fail_count; + struct smart_log_add_item_12 wear_leveling_count; + struct smart_log_add_item_12 end_to_end_error_count; + struct smart_log_add_item_12 crc_error_count; + struct smart_log_add_item_12 timed_workload_media_wear; + struct smart_log_add_item_12 timed_workload_host_reads; + struct smart_log_add_item_12 timed_workload_timer; + struct smart_log_add_item_12 thermal_throttle_status; + struct smart_log_add_item_12 retry_buffer_overflow_counter; + struct smart_log_add_item_12 pll_lock_loss_count; + struct smart_log_add_item_12 nand_bytes_written; + struct smart_log_add_item_12 host_bytes_written; + struct smart_log_add_item_12 system_area_life_remaining; + struct smart_log_add_item_12 nand_bytes_read; + struct smart_log_add_item_12 temperature; + struct smart_log_add_item_12 power_consumption; + struct smart_log_add_item_12 power_on_temperature; + struct smart_log_add_item_12 power_loss_protection; + struct smart_log_add_item_12 read_fail_count; + struct smart_log_add_item_12 thermal_throttle_time; + struct smart_log_add_item_12 flash_error_media_count; + } v0; + + struct smart_log_add_item_12 v0_raw[22]; + }; + + union { + struct smart_log_add_v2 { + struct smart_log_add_item_12 program_fail_count; + struct smart_log_add_item_12 erase_fail_count; + struct smart_log_add_item_12 wear_leveling_count; + struct smart_log_add_item_12 end_to_end_error_count; + struct smart_log_add_item_12 crc_error_count; + struct smart_log_add_item_12 timed_workload_media_wear; + struct smart_log_add_item_12 timed_workload_host_reads; + struct smart_log_add_item_12 timed_workload_timer; + struct smart_log_add_item_12 thermal_throttle_status; + struct smart_log_add_item_12 lifetime_write_amplification; + struct smart_log_add_item_12 pll_lock_loss_count; + struct smart_log_add_item_12 nand_bytes_written; + struct smart_log_add_item_12 host_bytes_written; + struct smart_log_add_item_12 system_area_life_remaining; + struct smart_log_add_item_12 firmware_update_count; + struct smart_log_add_item_12 dram_cecc_count; + struct smart_log_add_item_12 dram_uecc_count; + struct smart_log_add_item_12 xor_pass_count; + struct smart_log_add_item_12 xor_fail_count; + struct smart_log_add_item_12 xor_invoked_count; + struct smart_log_add_item_12 inflight_read_io_cmd; + struct smart_log_add_item_12 flash_error_media_count; + struct smart_log_add_item_12 nand_bytes_read; + struct smart_log_add_item_12 temp_since_born; + struct smart_log_add_item_12 power_consumption; + struct smart_log_add_item_12 temp_since_bootup; + struct smart_log_add_item_12 thermal_throttle_time; + } v2; + + struct smart_log_add_item_12 v2_raw[27]; + }; + + union { + struct smart_log_add_v3 { + struct smart_log_add_item_10 program_fail_count; + struct smart_log_add_item_10 erase_fail_count; + struct smart_log_add_item_10 wear_leveling_count; + struct smart_log_add_item_10 ext_e2e_err_count; + struct smart_log_add_item_10 crc_err_count; + struct smart_log_add_item_10 nand_bytes_written; + struct smart_log_add_item_10 host_bytes_written; + struct smart_log_add_item_10 reallocated_sector_count; + struct smart_log_add_item_10 uncorrectable_sector_count; + struct smart_log_add_item_10 nand_uecc_detection; + struct smart_log_add_item_10 nand_xor_correction; + struct smart_log_add_item_10 gc_count; + struct smart_log_add_item_10 dram_uecc_detection_count; + struct smart_log_add_item_10 sram_uecc_detection_count; + struct smart_log_add_item_10 internal_raid_recovery_fail_count; + struct smart_log_add_item_10 inflight_cmds; + struct smart_log_add_item_10 internal_e2e_err_count; + struct smart_log_add_item_10 die_fail_count; + struct smart_log_add_item_10 wear_leveling_execution_count; + struct smart_log_add_item_10 read_disturb_count; + struct smart_log_add_item_10 data_retention_count; + struct smart_log_add_item_10 capacitor_health; + } v3; + + struct smart_log_add_item_10 v3_raw[24]; + }; + + uint8_t raw[512]; + }; +}; + +static void smart_log_add_v0_print(struct smart_log_add_item_12 *item, int item_count) +{ + static const struct smart_log_add_item items[0xff] = { + [0xab] = {0, "program_fail_count" }, + [0xac] = {1, "erase_fail_count" }, + [0xad] = {2, "wear_leveling_count" }, + [0xb8] = {3, "end_to_end_error_count" }, + [0xc7] = {4, "crc_error_count" }, + [0xe2] = {5, "timed_workload_media_wear" }, + [0xe3] = {6, "timed_workload_host_reads" }, + [0xe4] = {7, "timed_workload_timer" }, + [0xea] = {8, "thermal_throttle_status" }, + [0xf0] = {9, "retry_buffer_overflow_counter"}, + [0xf3] = {10, "pll_lock_loss_count" }, + [0xf4] = {11, "nand_bytes_written" }, + [0xf5] = {12, "host_bytes_written" }, + [0xf6] = {13, "system_area_life_remaining" }, + [0xfa] = {14, "nand_bytes_read" }, + [0xe7] = {15, "temperature" }, + [0xe8] = {16, "power_consumption" }, + [0xaf] = {17, "power_on_temperature" }, + [0xec] = {18, "power_loss_protection" }, + [0xf2] = {19, "read_fail_count" }, + [0xeb] = {20, "thermal_throttle_time" }, + [0xed] = {21, "flash_error_media_count" }, + }; + + for (int i = 0; i < item_count; i++, item++) { + if (item->id == 0) + continue; + + printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm); + switch (item->id) { + case 0xad: + printf("min: %d, max: %d, avg: %d\n", + le16_to_cpu(item->wear_level.min), + le16_to_cpu(item->wear_level.max), + le16_to_cpu(item->wear_level.avg)); + break; + case 0xe7: + printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n", + K2C(le16_to_cpu(item->temp_since_born.max)), + le16_to_cpu(item->temp_since_born.max), + K2C(le16_to_cpu(item->temp_since_born.min)), + le16_to_cpu(item->temp_since_born.min), + K2C(le16_to_cpu(item->temp_since_born.curr)), + le16_to_cpu(item->temp_since_born.curr)); + break; + case 0xe8: + printf("max: %d, min: %d, curr: %d\n", + le16_to_cpu(item->power_consumption.max), + le16_to_cpu(item->power_consumption.min), + le16_to_cpu(item->power_consumption.curr)); + break; + case 0xaf: + printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n", + K2C(le16_to_cpu(item->temp_since_power_on.max)), + le16_to_cpu(item->temp_since_power_on.max), + K2C(le16_to_cpu(item->temp_since_power_on.min)), + le16_to_cpu(item->temp_since_power_on.min), + K2C(le16_to_cpu(item->temp_since_power_on.curr)), + le16_to_cpu(item->temp_since_power_on.curr)); + break; + default: + printf("%" PRIu64 "\n", int48_to_long(item->raw)); + break; + } + } +} + +static void smart_log_add_v2_print(struct smart_log_add_item_12 *item, int item_count) +{ + static const struct smart_log_add_item items[0xff] = { + [0xab] = {0, "program_fail_count" }, + [0xac] = {1, "erase_fail_count" }, + [0xad] = {2, "wear_leveling_count" }, + [0xb8] = {3, "end_to_end_error_count" }, + [0xc7] = {4, "crc_error_count" }, + [0xe2] = {5, "timed_workload_media_wear" }, + [0xe3] = {6, "timed_workload_host_reads" }, + [0xe4] = {7, "timed_workload_timer" }, + [0xea] = {8, "thermal_throttle_status" }, + [0xf0] = {9, "lifetime_write_amplification"}, + [0xf3] = {10, "pll_lock_loss_count" }, + [0xf4] = {11, "nand_bytes_written" }, + [0xf5] = {12, "host_bytes_written" }, + [0xf6] = {13, "system_area_life_remaining" }, + [0xf9] = {14, "firmware_update_count" }, + [0xfa] = {15, "dram_cecc_count" }, + [0xfb] = {16, "dram_uecc_count" }, + [0xfc] = {17, "xor_pass_count" }, + [0xfd] = {18, "xor_fail_count" }, + [0xfe] = {19, "xor_invoked_count" }, + [0xe5] = {20, "inflight_read_io_cmd" }, + [0xe6] = {21, "flash_error_media_count" }, + [0xf8] = {22, "nand_bytes_read" }, + [0xe7] = {23, "temp_since_born" }, + [0xe8] = {24, "power_consumption" }, + [0xaf] = {25, "temp_since_bootup" }, + [0xeb] = {26, "thermal_throttle_time" }, + }; + + for (int i = 0; i < item_count; i++, item++) { + if (item->id == 0) + continue; + + printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm); + switch (item->id) { + case 0xad: + printf("min: %d, max: %d, avg: %d\n", + le16_to_cpu(item->wear_level.min), + le16_to_cpu(item->wear_level.max), + le16_to_cpu(item->wear_level.avg)); + break; + case 0xe7: + printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n", + K2C(le16_to_cpu(item->temp_since_born.max)), + le16_to_cpu(item->temp_since_born.max), + K2C(le16_to_cpu(item->temp_since_born.min)), + le16_to_cpu(item->temp_since_born.min), + K2C(le16_to_cpu(item->temp_since_born.curr)), + le16_to_cpu(item->temp_since_born.curr)); + break; + case 0xe8: + printf("max: %d, min: %d, curr: %d\n", + le16_to_cpu(item->power_consumption.max), + le16_to_cpu(item->power_consumption.min), + le16_to_cpu(item->power_consumption.curr)); + break; + case 0xaf: + printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n", + K2C(le16_to_cpu(item->temp_since_power_on.max)), + le16_to_cpu(item->temp_since_power_on.max), + K2C(le16_to_cpu(item->temp_since_power_on.min)), + le16_to_cpu(item->temp_since_power_on.min), + K2C(le16_to_cpu(item->temp_since_power_on.curr)), + le16_to_cpu(item->temp_since_power_on.curr)); + break; + default: + printf("%" PRIu64 "\n", int48_to_long(item->raw)); + break; + } + } +} + +static void smart_log_add_v3_print(struct smart_log_add_item_10 *item, int item_count) +{ + static const struct smart_log_add_item items[0xff] = { + [0xab] = {0, "program_fail_count" }, + [0xac] = {1, "erase_fail_count" }, + [0xad] = {2, "wear_leveling_count" }, + [0xb8] = {3, "ext_e2e_err_count" }, + [0xc7] = {4, "crc_err_count" }, + [0xf4] = {5, "nand_bytes_written" }, + [0xf5] = {6, "host_bytes_written" }, + [0xd0] = {7, "reallocated_sector_count" }, + [0xd1] = {8, "uncorrectable_sector_count" }, + [0xd2] = {9, "nand_uecc_detection" }, + [0xd3] = {10, "nand_xor_correction" }, + [0xd4] = {12, "gc_count" }, // 11 is reserved + [0xd5] = {13, "dram_uecc_detection_count" }, + [0xd6] = {14, "sram_uecc_detection_count" }, + [0xd7] = {15, "internal_raid_recovery_fail_count"}, + [0xd8] = {16, "inflight_cmds" }, + [0xd9] = {17, "internal_e2e_err_count" }, + [0xda] = {19, "die_fail_count" }, // 18 is reserved + [0xdb] = {20, "wear_leveling_execution_count" }, + [0xdc] = {21, "read_disturb_count" }, + [0xdd] = {22, "data_retention_count" }, + [0xde] = {23, "capacitor_health" }, + }; + + for (int i = 0; i < item_count; i++, item++) { + if (item->id == 0) + continue; + + printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm); + switch (item->id) { + case 0xad: + printf("min: %d, max: %d, avg: %d\n", + le16_to_cpu(item->wear_level.min), + le16_to_cpu(item->wear_level.max), + le16_to_cpu(item->wear_level.avg)); + break; + default: + printf("%" PRIu64 "\n", int48_to_long(item->raw)); + break; + } + } +} + +static void smart_log_add_print(struct smart_log_add *log, const char *devname) +{ + uint8_t version = log->raw[511]; + + printf("Version: %u\n", version); + printf("\n"); + printf("Additional Smart Log for NVMe device: %s\n", devname); + printf("\n"); + + printf("%-12s%-36s%-12s%s\n", "Id", "Key", "Normalized", "Raw"); + + switch (version) { + case 0: + return smart_log_add_v0_print(&log->v0_raw[0], + sizeof(struct smart_log_add_v0) / sizeof(struct smart_log_add_item_12)); + case 2: + return smart_log_add_v2_print(&log->v2_raw[0], + sizeof(struct smart_log_add_v2) / sizeof(struct smart_log_add_item_12)); + case 3: + return smart_log_add_v3_print(&log->v3_raw[0], + sizeof(struct smart_log_add_v3) / sizeof(struct smart_log_add_item_10)); + + case 1: + fprintf(stderr, "Version %d: N/A\n", version); + break; + default: + fprintf(stderr, "Version %d: Not supported yet\n", version); + break; + } +} + +static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + int err = 0; + + // Get the configuration + + struct config { + bool raw_binary; + }; + + struct config cfg = {0}; + + OPT_ARGS(opts) = { + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, "dump the whole log buffer in binary format"), + OPT_END()}; + + // Open device + + struct nvme_dev *dev = NULL; + + err = parse_and_open(&dev, argc, argv, cmd->help, opts); + if (err) + return err; + + // Get log + + struct smart_log_add log = {0}; + + err = nvme_get_log_simple(dev_fd(dev), LID_SMART_LOG_ADD, sizeof(struct smart_log_add), &log); + if (!err) { + if (!cfg.raw_binary) + smart_log_add_print(&log, dev->name); + else + d_raw((unsigned char *)&log, sizeof(struct smart_log_add)); + } else if (err > 0) { + nvme_show_status(err); + } else { + nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno)); + } + + // Close device + + dev_close(dev); + return err; +} + +// performance-monitor + +struct latency_stats_bucket { + char *start_threshold; + char *end_threshold; +}; + +struct __packed latency_stats { + union { + struct latency_stats_v2_0 { + uint32_t minor_version; + uint32_t major_version; + uint32_t bucket_read_data[32]; + uint32_t rsvd[32]; + uint32_t bucket_write_data[32]; + uint32_t rsvd1[32]; + uint32_t bucket_trim_data[32]; + uint32_t rsvd2[32]; + uint8_t rsvd3[248]; + } v2_0; + uint8_t raw[1024]; + }; +}; + +struct __packed high_latency_log { + union { + struct high_latency_log_v1 { + uint32_t version; + struct high_latency_log_entry { + uint64_t timestamp; // ms + uint32_t latency; + uint32_t qid; + uint32_t opcode : 8; + uint32_t fuse : 2; + uint32_t psdt : 2; + uint32_t cid : 16; + uint32_t rsvd : 4; + uint32_t nsid; + uint64_t slba; + uint32_t nlb : 16; + uint32_t dtype : 8; + uint32_t pinfo : 4; + uint32_t fua : 1; + uint32_t lr : 1; + uint32_t rsvd1 : 2; + uint8_t rsvd2[28]; + } entries[1024]; + } v1; + uint8_t raw[4 + 1024 * 64]; + }; +}; + +struct __packed performance_stats { + union { + struct performance_stats_v1 { + uint8_t version; + uint8_t rsvd[3]; + struct performance_stats_timestamp { + uint8_t timestamp[6]; + struct performance_stats_entry { + uint16_t read_iops; // K IOPS + uint16_t read_bandwidth; // MiB + uint32_t read_latency; // us + uint32_t read_latency_max; // us + uint16_t write_iops; // K IOPS + uint16_t write_bandwidth; // MiB + uint32_t write_latency; // us + uint32_t write_latency_max; // us + } entries[3600]; + } timestamps[24]; + } v1; + uint8_t raw[4 + 24 * (6 + 3600 * 24)]; + }; +}; + +static int mb_set_latency_feature(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err = 0; + + // Get the configuration + + struct config { + uint32_t perf_monitor; + uint32_t cmd_mask; + uint32_t read_threshold; + uint32_t write_threshold; + uint32_t de_allocate_trim_threshold; + }; + + struct config cfg = {0}; + + OPT_ARGS(opts) = { + OPT_UINT("sel-perf-log", 's', &cfg.perf_monitor, + "Select features to turn on, default: Disable\n" + " bit 0: latency statistics\n" + " bit 1: high latency log\n" + " bit 2: Performance stat"), + OPT_UINT("set-commands-mask", 'm', &cfg.cmd_mask, + "Set Enable, default: Disable\n" + " bit 0: Read commands\n" + " bit 1: high Write commands\n" + " bit 2: De-allocate/TRIM (this bit is not worked for Performance stat.)"), + OPT_UINT("set-read-threshold", 'r', &cfg.read_threshold, + "set read high latency log threshold, it's a 0-based value and unit is 10ms"), + OPT_UINT("set-write-threshold", 'w', &cfg.write_threshold, + "set write high latency log threshold, it's a 0-based value and unit is 10ms"), + OPT_UINT("set-trim-threshold", 't', &cfg.de_allocate_trim_threshold, + "set trim high latency log threshold, it's a 0-based value and unit is 10ms"), + OPT_END()}; + + // Open device + + struct nvme_dev *dev = NULL; + + err = parse_and_open(&dev, argc, argv, cmd->help, opts); + if (err) + return err; + + + // Set feature + + uint32_t result = 0; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = FID_LATENCY_FEATURE, + .nsid = 0, + .cdw11 = 0 | cfg.perf_monitor, + .cdw12 = 0 | cfg.cmd_mask, + .cdw13 = 0 | + (cfg.read_threshold & 0xff) | + ((cfg.write_threshold & 0xff) << 8) | + ((cfg.de_allocate_trim_threshold & 0xff) << 16), + .cdw15 = 0, + .save = 0, + .uuidx = 0, + .data = NULL, + .data_len = 0, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_set_features(&args); + if (!err) + printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result); + else if (err > 0) + nvme_show_status(err); + else + nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno)); + + // Close device + + dev_close(dev); + return err; +} + +static int mb_get_latency_feature(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err = 0; + + // Get the configuration + + OPT_ARGS(opts) = { + OPT_END()}; + + // Open device + + struct nvme_dev *dev = NULL; + + err = parse_and_open(&dev, argc, argv, cmd->help, opts); + if (err) + return err; + + // Get feature + + uint32_t result = 0; + + err = nvme_get_features_simple(dev_fd(dev), FID_LATENCY_FEATURE, 0, &result); + if (!err) { + printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result); + + printf("latency statistics enable status = %d\n", (result & (0x01 << 0)) >> 0); + printf("high latency enable status = %d\n", (result & (0x01 << 1)) >> 1); + printf("performance stat enable status = %d\n", (result & (0x01 << 2)) >> 2); + + printf("Monitor Read command = %d\n", (result & (0x01 << 4)) >> 4); + printf("Monitor Write command = %d\n", (result & (0x01 << 5)) >> 5); + printf("Monitor Trim command = %d\n", (result & (0x01 << 6)) >> 6); + + printf("Threshold for Read = %dms\n", (((result & (0xff << 8)) >> 8) + 1) * 10); + printf("Threshold for Write = %dms\n", (((result & (0xff << 16)) >> 16) + 1) * 10); + printf("Threshold for Trim = %dms\n", (((result & (0xff << 24)) >> 24) + 1) * 10); + } else if (err > 0) { + nvme_show_status(err); + } else { + nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno)); + } + + // Close device + + dev_close(dev); + return err; +} diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h index 87314c665c..e25267bdcd 100644 --- a/plugins/memblaze/memblaze-nvme.h +++ b/plugins/memblaze/memblaze-nvme.h @@ -6,12 +6,6 @@ #define MEMBLAZE_NVME #include "cmd.h" -#include "common.h" - -#include -#include -#include -#include PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION), COMMAND_LIST( @@ -24,10 +18,12 @@ PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION), ENTRY("lat-log", "Set Memblaze High Latency Log", mb_set_high_latency_log) ENTRY("lat-log-print", "Output Memblaze High Latency Log", mb_high_latency_log_print) ENTRY("clear-error-log", "Clear error log", memblaze_clear_error_log) + ENTRY("smart-log-add-x", "Retrieve Memblaze SMART Log, show it", mb_get_smart_log_add) + ENTRY("lat-set-feature-x", "Set Enable/Disable for Latency Monitor feature", mb_set_latency_feature) + ENTRY("lat-get-feature-x", "Get Enabled/Disabled of Latency Monitor feature", mb_get_latency_feature) ) ); #endif #include "define_cmd.h" - diff --git a/plugins/memblaze/memblaze-utils.h b/plugins/memblaze/memblaze-utils.h index 84263f3f02..8914f955b2 100644 --- a/plugins/memblaze/memblaze-utils.h +++ b/plugins/memblaze/memblaze-utils.h @@ -2,223 +2,216 @@ #ifndef __MEMBLAZE_UTILS_H__ #define __MEMBLAZE_UTILS_H__ -#define SMART_INFO_OLD_SIZE 512 -#define SMART_INFO_NEW_SIZE 4096 +#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; +#define ID_SIZE 3 +#define NM_SIZE 2 +#define RAW_SIZE 7 // Intel Format & new format /* Raisin Additional smart external ID */ -#define RAISIN_SI_VD_PROGRAM_FAIL_ID 0xAB -#define RAISIN_SI_VD_ERASE_FAIL_ID 0xAC -#define RAISIN_SI_VD_WEARLEVELING_COUNT_ID 0xAD -#define RAISIN_SI_VD_E2E_DECTECTION_COUNT_ID 0xB8 -#define RAISIN_SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7 -#define RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2 -#define RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3 -#define RAISIN_SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4 -#define RAISIN_SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA -#define RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0 -#define RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3 -#define RAISIN_SI_VD_TOTAL_WRITE_ID 0xF4 -#define RAISIN_SI_VD_HOST_WRITE_ID 0xF5 -#define RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6 -#define RAISIN_SI_VD_TOTAL_READ_ID 0xFA -#define RAISIN_SI_VD_TEMPT_SINCE_BORN_ID 0xE7 -#define RAISIN_SI_VD_POWER_CONSUMPTION_ID 0xE8 -#define RAISIN_SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF -#define RAISIN_SI_VD_POWER_LOSS_PROTECTION_ID 0xEC -#define RAISIN_SI_VD_READ_FAIL_ID 0xF2 -#define RAISIN_SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB -#define RAISIN_SI_VD_FLASH_MEDIA_ERROR_ID 0xED - -/* Raisin Addtional smart internal ID */ +#define RAISIN_SI_VD_PROGRAM_FAIL_ID 0xAB +#define RAISIN_SI_VD_ERASE_FAIL_ID 0xAC +#define RAISIN_SI_VD_WEARLEVELING_COUNT_ID 0xAD +#define RAISIN_SI_VD_E2E_DECTECTION_COUNT_ID 0xB8 +#define RAISIN_SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7 +#define RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2 +#define RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3 +#define RAISIN_SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4 +#define RAISIN_SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA +#define RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0 +#define RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3 +#define RAISIN_SI_VD_TOTAL_WRITE_ID 0xF4 +#define RAISIN_SI_VD_HOST_WRITE_ID 0xF5 +#define RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6 +#define RAISIN_SI_VD_TOTAL_READ_ID 0xFA +#define RAISIN_SI_VD_TEMPT_SINCE_BORN_ID 0xE7 +#define RAISIN_SI_VD_POWER_CONSUMPTION_ID 0xE8 +#define RAISIN_SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF +#define RAISIN_SI_VD_POWER_LOSS_PROTECTION_ID 0xEC +#define RAISIN_SI_VD_READ_FAIL_ID 0xF2 +#define RAISIN_SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB +#define RAISIN_SI_VD_FLASH_MEDIA_ERROR_ID 0xED + +/* Raisin Additional smart internal ID */ typedef enum { - /* smart attr following intel */ - RAISIN_SI_VD_PROGRAM_FAIL = 0, /* 0xAB */ - RAISIN_SI_VD_ERASE_FAIL = 1, /* 0xAC */ - RAISIN_SI_VD_WEARLEVELING_COUNT = 2,/* 0xAD */ - RAISIN_SI_VD_E2E_DECTECTION_COUNT = 3, /* 0xB8 */ - RAISIN_SI_VD_PCIE_CRC_ERR_COUNT = 4, /* 0xC7, 2 port data in one attribute */ - RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR = 5, /* 0xE2 , unknown definition*/ - RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ = 6, /* 0xE3 , unknown definition */ - RAISIN_SI_VD_TIMED_WORKLOAD_TIMER = 7, /* 0xE4 , unknown definition */ - RAISIN_SI_VD_THERMAL_THROTTLE_STATUS = 8, /* 0xEA */ - RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT = 9, /* 0xF0, unknown definition*/ - RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT = 10, /* 0xF3, unknown definition*/ - RAISIN_SI_VD_TOTAL_WRITE = 11, /* 0xF4, unit is 32MiB */ - RAISIN_SI_VD_HOST_WRITE = 12, /* 0xF5, unit is 32MiB */ - RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT = 13, /* 0xF6, unknown definition*/ - RAISIN_SI_VD_TOTAL_READ = 14, /* 0xFA, unit is 32MiB */ - - /* smart attr self defined */ - RAISIN_SI_VD_TEMPT_SINCE_BORN = 15, /* 0xE7 */ - RAISIN_SI_VD_POWER_CONSUMPTION = 16, /* 0xE8 */ - RAISIN_SI_VD_TEMPT_SINCE_BOOTUP = 17, /* 0xAF */ - RAISIN_SI_VD_POWER_LOSS_PROTECTION = 18, /* 0xEC */ - RAISIN_SI_VD_READ_FAIL = 19, /* 0xF2 */ - RAISIN_SI_VD_THERMAL_THROTTLE_TIME = 20, /* 0xEB */ - RAISIN_SI_VD_FLASH_MEDIA_ERROR = 21, /* 0xED */ - RAISIN_SI_VD_SMART_INFO_ITEMS_MAX, + /* 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, + /*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; + __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]; + 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]; + /* 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]; + struct nvme_p4_smart_log_item itemArr[NR_SMART_ITEMS]; + + /** + * change 512 to 4096. + * because micron's getlogpage request,the size of many commands have changed to 4k. + * request size > user malloc size,casuing parameters that are closed in memery are dirty. + */ + __u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS]; }; // base -#define DD do{ printf("=Memblaze= %s[%d]-%s():\n", __FILE__, __LINE__, __func__); }while(0) -#define DE(str) do{ printf("===ERROR!=== %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, \ - str); }while(0) +#define DD do{ printf("=Memblaze= %s[%d]-%s():\n", __FILE__, __LINE__, __func__); }while(0) +#define DE(str) do{ printf("===ERROR!=== %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, \ + str); }while(0) // integer -#define DI(i) do{ printf("=Memblaze= %s[%d]-%s():int=%d\n", __FILE__, __LINE__, __func__, \ - (int)i); } while(0) -#define DPI(prompt, i) do{ printf("=Memblaze= %s[%d]-%s():%s=%d\n", __FILE__, __LINE__, __func__, \ - prompt, i); }while(0) -#define DAI(prompt, i, arr, max) do{ printf("=Memblaze= %s[%d]-%s():%s", __FILE__, __LINE__, __func__, prompt); \ - for(i=0;i #include "linux/types.h" #include "nvme-print.h" +#include "util/cleanup.h" #define CREATE_CMD #include "micron-nvme.h" /* Supported Vendor specific feature ids */ -#define MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS 0xC3 -#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY 0xC1 -#define MICRON_FEATURE_TELEMETRY_CONTROL_OPTION 0xCF -#define MICRON_FEATURE_SMBUS_OPTION 0xD5 +#define MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS 0xC3 +#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY 0xC1 +#define MICRON_FEATURE_TELEMETRY_CONTROL_OPTION 0xCF +#define MICRON_FEATURE_SMBUS_OPTION 0xD5 /* Supported Vendor specific log page sizes */ #define C5_log_size (((452 + 16 * 1024) / 4) * 4096) @@ -33,8 +34,8 @@ #define D0_log_size 512 #define FB_log_size 512 #define E1_log_size 256 -#define MaxLogChunk 16 * 1024 -#define CommonChunkSize 16 * 4096 +#define MaxLogChunk (16 * 1024) +#define CommonChunkSize (16 * 4096) #define min(x, y) ((x) > (y) ? (y) : (x)) #define SensorCount 8 @@ -44,10 +45,19 @@ static const char *__version_major = "1"; static const char *__version_minor = "0"; static const char *__version_patch = "14"; -/* supported models of micron plugin; new models should be added at the end +/* + * supported models of micron plugin; new models should be added at the end * before UNKNOWN_MODEL. Make sure M5410 is first in the list ! */ -typedef enum { M5410 = 0, M51AX, M51BX, M51CX, M5407, M5411, UNKNOWN_MODEL } eDriveModel; +enum eDriveModel { + M5410 = 0, + M51AX, + M51BX, + M51CX, + M5407, + M5411, + UNKNOWN_MODEL +}; #define MICRON_VENDOR_ID 0x1344 @@ -58,396 +68,386 @@ static char *fdeviceid2 = "/sys/class/misc/nvme%d/device/device"; static unsigned short vendor_id; static unsigned short device_id; -typedef struct _LogPageHeader_t { - unsigned char numDwordsInLogPageHeaderLo; - unsigned char logPageHeaderFormatVersion; - unsigned char logPageId; - unsigned char numDwordsInLogPageHeaderHi; - unsigned int numValidDwordsInPayload; - unsigned int numDwordsInEntireLogPage; -} LogPageHeader_t; +struct LogPageHeader_t { + unsigned char numDwordsInLogPageHeaderLo; + unsigned char logPageHeaderFormatVersion; + unsigned char logPageId; + unsigned char numDwordsInLogPageHeaderHi; + unsigned int numValidDwordsInPayload; + unsigned int numDwordsInEntireLogPage; +}; static void WriteData(__u8 *data, __u32 len, const char *dir, const char *file, const char *msg) { - char tempFolder[8192] = { 0 }; - FILE *fpOutFile = NULL; - sprintf(tempFolder, "%s/%s", dir, file); - if ((fpOutFile = fopen(tempFolder, "ab+")) != NULL) { - if (fwrite(data, 1, len, fpOutFile) != len) { - printf("Failed to write %s data to %s\n", msg, tempFolder); - } - fclose(fpOutFile); - } else { - printf("Failed to open %s file to write %s\n", tempFolder, msg); - } + char tempFolder[8192] = { 0 }; + FILE *fpOutFile = NULL; + + sprintf(tempFolder, "%s/%s", dir, file); + fpOutFile = fopen(tempFolder, "ab+"); + if (fpOutFile) { + if (fwrite(data, 1, len, fpOutFile) != len) + printf("Failed to write %s data to %s\n", msg, tempFolder); + fclose(fpOutFile); + } else { + printf("Failed to open %s file to write %s\n", tempFolder, msg); + } } static int ReadSysFile(const char *file, unsigned short *id) { - int ret = 0; - char idstr[32] = { '\0' }; - int fd = open(file, O_RDONLY); - - if (fd < 0) { - perror(file); - return fd; - } - - ret = read(fd, idstr, sizeof(idstr)); - close(fd); - if (ret < 0) - perror("read"); - else - *id = strtol(idstr, NULL, 16); - - return ret; + int ret = 0; + char idstr[32] = { '\0' }; + int fd = open(file, O_RDONLY); + + if (fd < 0) { + perror(file); + return fd; + } + + ret = read(fd, idstr, sizeof(idstr)); + close(fd); + if (ret < 0) + perror("read"); + else + *id = strtol(idstr, NULL, 16); + + return ret; } -static eDriveModel GetDriveModel(int idx) +static enum eDriveModel GetDriveModel(int idx) { - eDriveModel eModel = UNKNOWN_MODEL; - char path[512]; - - sprintf(path, fvendorid1, idx); - if (ReadSysFile(path, &vendor_id) < 0) { - sprintf(path, fvendorid2, idx); - ReadSysFile(path, &vendor_id); - } - sprintf(path, fdeviceid1, idx); - if (ReadSysFile(path, &device_id) < 0) { - sprintf(path, fdeviceid2, idx); - ReadSysFile(path, &device_id); - } - if (vendor_id == MICRON_VENDOR_ID) { - switch (device_id) { - case 0x5196: - case 0x51A0: - case 0x51A1: - case 0x51A2: - eModel = M51AX; - break; - case 0x51B0: - case 0x51B1: - case 0x51B2: - eModel = M51BX; - break; - case 0x51C0: - case 0x51C1: - case 0x51C2: - case 0x51C3: - eModel = M51CX; - break; - case 0x5405: - case 0x5406: - case 0x5407: - eModel = M5407; - break; - case 0x5410: - eModel = M5410; - break; - case 0x5411: - eModel = M5411; - break; - default: - break; - } - } - return eModel; + enum eDriveModel eModel = UNKNOWN_MODEL; + char path[512]; + + sprintf(path, fvendorid1, idx); + if (ReadSysFile(path, &vendor_id) < 0) { + sprintf(path, fvendorid2, idx); + ReadSysFile(path, &vendor_id); + } + sprintf(path, fdeviceid1, idx); + if (ReadSysFile(path, &device_id) < 0) { + sprintf(path, fdeviceid2, idx); + ReadSysFile(path, &device_id); + } + if (vendor_id == MICRON_VENDOR_ID) { + switch (device_id) { + case 0x5196: + case 0x51A0: + case 0x51A1: + case 0x51A2: + eModel = M51AX; + break; + case 0x51B0: + case 0x51B1: + case 0x51B2: + eModel = M51BX; + break; + case 0x51C0: + case 0x51C1: + case 0x51C2: + case 0x51C3: + eModel = M51CX; + break; + case 0x5405: + case 0x5406: + case 0x5407: + eModel = M5407; + break; + case 0x5410: + eModel = M5410; + break; + case 0x5411: + eModel = M5411; + break; + default: + break; + } + } + return eModel; } static int ZipAndRemoveDir(char *strDirName, char *strFileName) { - int err = 0; - char strBuffer[PATH_MAX]; - int nRet; - bool is_tgz = false; - struct stat sb; - - if (strstr(strFileName, ".tar.gz") || strstr(strFileName, ".tgz")) { - sprintf(strBuffer, "tar -zcf \"%s\" \"%s\"", strFileName, - strDirName); - is_tgz = true; - } else { - sprintf(strBuffer, "zip -r \"%s\" \"%s\" >temp.txt 2>&1", strFileName, - strDirName); - } - - err = EINVAL; - nRet = system(strBuffer); - - /* check if log file is created, if not print error message */ - if (nRet < 0 || (stat(strFileName, &sb) == -1)) { - if (is_tgz) - sprintf(strBuffer, "check if tar and gzip commands are installed"); - else - sprintf(strBuffer, "check if zip command is installed"); - - fprintf(stderr, "Failed to create log data package, %s!\n", strBuffer); - } - - sprintf(strBuffer, "rm -f -R \"%s\" >temp.txt 2>&1", strDirName); - nRet = system(strBuffer); - if (nRet < 0) - printf("Failed to remove temporary files!\n"); - - err = system("rm -f temp.txt"); - return err; + int err = 0; + char strBuffer[PATH_MAX]; + int nRet; + bool is_tgz = false; + struct stat sb; + + if (strstr(strFileName, ".tar.gz") || strstr(strFileName, ".tgz")) { + sprintf(strBuffer, "tar -zcf \"%s\" \"%s\"", strFileName, strDirName); + is_tgz = true; + } else { + sprintf(strBuffer, "zip -r \"%s\" \"%s\" >temp.txt 2>&1", strFileName, + strDirName); + } + + err = EINVAL; + nRet = system(strBuffer); + + /* check if log file is created, if not print error message */ + if (nRet < 0 || (stat(strFileName, &sb) == -1)) { + if (is_tgz) + sprintf(strBuffer, "check if tar and gzip commands are installed"); + else + sprintf(strBuffer, "check if zip command is installed"); + + fprintf(stderr, "Failed to create log data package, %s!\n", strBuffer); + } + + sprintf(strBuffer, "rm -f -R \"%s\" >temp.txt 2>&1", strDirName); + nRet = system(strBuffer); + if (nRet < 0) + printf("Failed to remove temporary files!\n"); + + err = system("rm -f temp.txt"); + return err; } static int SetupDebugDataDirectories(char *strSN, char *strFilePath, - char *strMainDirName, char *strOSDirName, - char *strCtrlDirName) + char *strMainDirName, char *strOSDirName, + char *strCtrlDirName) { - int err = 0; - char strAppend[250]; - struct stat st; - char *fileLocation = NULL; - char *fileName; - int length = 0; - int nIndex = 0; - char *strTemp = NULL; - struct stat dirStat; - int j; - int k = 0; - int i = 0; - - if (strchr(strFilePath, '/') != NULL) { - fileName = strrchr(strFilePath, '\\'); - if (fileName == NULL) { - fileName = strrchr(strFilePath, '/'); - } - - if (fileName != NULL) { - if (!strcmp(fileName, "/")) { - goto exit_status; - } - - while (strFilePath[nIndex] != '\0') { - if ('\\' == strFilePath[nIndex] && '\\' == strFilePath[nIndex + 1]) { - goto exit_status; - } - nIndex++; - } - - length = (int)strlen(strFilePath) - (int)strlen(fileName); - - if (fileName == strFilePath) { - length = 1; - } - - if ((fileLocation = (char *)malloc(length + 1)) == NULL) { - goto exit_status; - } - strncpy(fileLocation, strFilePath, length); - fileLocation[length] = '\0'; - - while (fileLocation[k] != '\0') { - if (fileLocation[k] == '\\') { - fileLocation[k] = '/'; - } - k++; - } - - length = (int)strlen(fileLocation); - - if (':' == fileLocation[length - 1]) { - if ((strTemp = (char *)malloc(length + 2)) == NULL) { - free(fileLocation); - goto exit_status; - } - strcpy(strTemp, fileLocation); - strcat(strTemp, "/"); - free(fileLocation); - - length = (int)strlen(strTemp); - if ((fileLocation = (char *)malloc(length + 1)) == NULL) { - free(strTemp); - goto exit_status; - } - - memcpy(fileLocation, strTemp, length + 1); - free(strTemp); - } - - if (stat(fileLocation, &st) != 0) { - free(fileLocation); - goto exit_status; - } - free(fileLocation); - } else { - goto exit_status; - } - } - - nIndex = 0; - for (i = 0; i < (int)strlen(strSN); i++) { - if (strSN[i] != ' ' && strSN[i] != '\n' && strSN[i] != '\t' && strSN[i] != '\r') { - strMainDirName[nIndex++] = strSN[i]; - } - } - strMainDirName[nIndex] = '\0'; - - j = 1; - while (stat(strMainDirName, &dirStat) == 0) { - strMainDirName[nIndex] = '\0'; - sprintf(strAppend, "-%d", j); - strcat(strMainDirName, strAppend); - j++; - } - - if (mkdir(strMainDirName, 0777) < 0) { - err = -1; - goto exit_status; - } - - if (strOSDirName != NULL) { - sprintf(strOSDirName, "%s/%s", strMainDirName, "OS"); - if (mkdir(strOSDirName, 0777) < 0) { - rmdir(strMainDirName); - err = -1; - goto exit_status; - } - } - if (strCtrlDirName != NULL) { - sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller"); - if (mkdir(strCtrlDirName, 0777) < 0) { - if (strOSDirName != NULL) - rmdir(strOSDirName); - rmdir(strMainDirName); - err = -1; - } - } + int err = 0; + char strAppend[250]; + struct stat st; + char *fileLocation = NULL; + char *fileName; + int length = 0; + int nIndex = 0; + char *strTemp = NULL; + int j; + int k = 0; + int i = 0; + + if (strchr(strFilePath, '/')) { + fileName = strrchr(strFilePath, '\\'); + if (!fileName) + fileName = strrchr(strFilePath, '/'); + + if (fileName) { + if (!strcmp(fileName, "/")) + goto exit_status; + + while (strFilePath[nIndex] != '\0') { + if ('\\' == strFilePath[nIndex] && '\\' == strFilePath[nIndex + 1]) + goto exit_status; + nIndex++; + } + + length = (int)strlen(strFilePath) - (int)strlen(fileName); + + if (fileName == strFilePath) + length = 1; + + fileLocation = (char *)malloc(length + 1); + if (!fileLocation) + goto exit_status; + strncpy(fileLocation, strFilePath, length); + fileLocation[length] = '\0'; + + while (fileLocation[k] != '\0') { + if (fileLocation[k] == '\\') + fileLocation[k] = '/'; + k++; + } + + length = (int)strlen(fileLocation); + + if (':' == fileLocation[length - 1]) { + strTemp = (char *)malloc(length + 2); + if (!strTemp) { + free(fileLocation); + goto exit_status; + } + strcpy(strTemp, fileLocation); + strcat(strTemp, "/"); + free(fileLocation); + + length = (int)strlen(strTemp); + fileLocation = (char *)malloc(length + 1); + if (!fileLocation) { + free(strTemp); + goto exit_status; + } + + memcpy(fileLocation, strTemp, length + 1); + free(strTemp); + } + + if (stat(fileLocation, &st)) { + free(fileLocation); + goto exit_status; + } + free(fileLocation); + } else { + goto exit_status; + } + } + + nIndex = 0; + for (i = 0; i < (int)strlen(strSN); i++) { + if (strSN[i] != ' ' && strSN[i] != '\n' && strSN[i] != '\t' && strSN[i] != '\r') + strMainDirName[nIndex++] = strSN[i]; + } + strMainDirName[nIndex] = '\0'; + + j = 1; + while (mkdir(strMainDirName, 0777) < 0) { + if (errno != EEXIST) { + err = -1; + goto exit_status; + } + strMainDirName[nIndex] = '\0'; + sprintf(strAppend, "-%d", j); + strcat(strMainDirName, strAppend); + j++; + } + + if (strOSDirName) { + sprintf(strOSDirName, "%s/%s", strMainDirName, "OS"); + if (mkdir(strOSDirName, 0777) < 0) { + rmdir(strMainDirName); + err = -1; + goto exit_status; + } + } + if (strCtrlDirName) { + sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller"); + if (mkdir(strCtrlDirName, 0777) < 0) { + if (strOSDirName) + rmdir(strOSDirName); + rmdir(strMainDirName); + err = -1; + } + } exit_status: - return err; + return err; } static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize) { - int err = 0; - unsigned char pTmpBuf[CommonChunkSize] = { 0 }; - LogPageHeader_t *pLogHeader = NULL; - - if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) { - err = nvme_get_log_simple(nFD, ucLogID, - CommonChunkSize, pTmpBuf); - if (err == 0) { - pLogHeader = (LogPageHeader_t *) pTmpBuf; - LogPageHeader_t *pLogHeader1 = (LogPageHeader_t *) pLogHeader; - *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4; - if (pLogHeader1->logPageHeaderFormatVersion == 0) { - printf ("Unsupported log page format version %d of log page : 0x%X\n", - ucLogID, err); - *nLogSize = 0; - err = -1; - } - } else { - printf ("Getting size of log page : 0x%X failed with %d (ignored)!\n", - ucLogID, err); - *nLogSize = 0; - } - } - return err; + int err = 0; + unsigned char pTmpBuf[CommonChunkSize] = { 0 }; + struct LogPageHeader_t *pLogHeader = NULL; + + if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) { + err = nvme_get_log_simple(nFD, ucLogID, CommonChunkSize, pTmpBuf); + if (!err) { + pLogHeader = (struct LogPageHeader_t *) pTmpBuf; + struct LogPageHeader_t *pLogHeader1 = (struct LogPageHeader_t *) pLogHeader; + *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4; + if (!pLogHeader1->logPageHeaderFormatVersion) { + printf("Unsupported log page format version %d of log page : 0x%X\n", + ucLogID, err); + *nLogSize = 0; + err = -1; + } + } else { + printf("Getting size of log page : 0x%X failed with %d (ignored)!\n", + ucLogID, err); + *nLogSize = 0; + } + } + return err; } static int NVMEGetLogPage(int nFD, unsigned char ucLogID, unsigned char *pBuffer, int nBuffSize) { - int err = 0; - struct nvme_passthru_cmd cmd = { 0 }; - unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int); - unsigned int uiMaxChunk = uiNumDwords; - unsigned int uiNumChunks = 1; - unsigned int uiXferDwords = 0; - unsigned long long ullBytesRead = 0; - unsigned char *pTempPtr = pBuffer; - unsigned char ucOpCode = 0x02; - - if (ullBytesRead == 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_admin_passthru(nFD, &cmd, NULL); - ullBytesRead += uiXferDwords * 4; - pTempPtr = pBuffer + ullBytesRead; - } - - return err; + int err = 0; + struct nvme_passthru_cmd cmd = { 0 }; + unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int); + unsigned int uiMaxChunk = uiNumDwords; + unsigned int uiNumChunks = 1; + unsigned int uiXferDwords = 0; + unsigned long long ullBytesRead = 0; + unsigned char *pTempPtr = pBuffer; + unsigned char ucOpCode = 0x02; + + if (!ullBytesRead && (ucLogID == 0xE6 || ucLogID == 0xE7)) + uiMaxChunk = 4096; + else if (uiMaxChunk > 16 * 1024) + uiMaxChunk = 16 * 1024; + + uiNumChunks = uiNumDwords / uiMaxChunk; + if (uiNumDwords % uiMaxChunk > 0) + uiNumChunks += 1; + + for (unsigned int i = 0; i < uiNumChunks; i++) { + memset(&cmd, 0, sizeof(cmd)); + uiXferDwords = uiMaxChunk; + if (i == uiNumChunks - 1 && uiNumDwords % uiMaxChunk > 0) + uiXferDwords = uiNumDwords % uiMaxChunk; + + cmd.opcode = ucOpCode; + cmd.cdw10 |= ucLogID; + cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16; + + if (ucLogID == 0x7) + cmd.cdw10 |= 0x80; + if (!ullBytesRead && (ucLogID == 0xE6 || ucLogID == 0xE7)) + cmd.cdw11 = 1; + if (ullBytesRead > 0 && !(ucLogID == 0xE6 || ucLogID == 0xE7)) { + unsigned long long ullOffset = ullBytesRead; + + cmd.cdw12 = ullOffset & 0xFFFFFFFF; + cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF; + } + + cmd.addr = (__u64) (uintptr_t) pTempPtr; + cmd.nsid = 0xFFFFFFFF; + cmd.data_len = uiXferDwords * 4; + err = nvme_submit_admin_passthru(nFD, &cmd, NULL); + ullBytesRead += uiXferDwords * 4; + pTempPtr = pBuffer + ullBytesRead; + } + + return err; } static int NVMEResetLog(int nFD, unsigned char ucLogID, int nBufferSize, - long long llMaxSize) + long long llMaxSize) { - unsigned int *pBuffer = NULL; - int err = 0; + unsigned int *pBuffer = NULL; + int err = 0; - if ((pBuffer = (unsigned int *)calloc(1, nBufferSize)) == NULL) - return err; + pBuffer = (unsigned int *)calloc(1, nBufferSize); + if (!pBuffer) + return err; - while (err == 0 && llMaxSize > 0) { - err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize); - if (err) { - free(pBuffer); - return err; - } + while (!err && llMaxSize > 0) { + err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize); + if (err) { + free(pBuffer); + return err; + } - if (pBuffer[0] == 0xdeadbeef) - break; + if (pBuffer[0] == 0xdeadbeef) + break; - llMaxSize = llMaxSize - nBufferSize; - } + llMaxSize = llMaxSize - nBufferSize; + } - free(pBuffer); - return err; + free(pBuffer); + return err; } static int GetCommonLogPage(int nFD, unsigned char ucLogID, - unsigned char **pBuffer, int nBuffSize) + unsigned char **pBuffer, int nBuffSize) { - unsigned char *pTempPtr = NULL; - int err = 0; - pTempPtr = (unsigned char *)malloc(nBuffSize); - if (!pTempPtr) { - goto exit_status; - } - memset(pTempPtr, 0, nBuffSize); - err = nvme_get_log_simple(nFD, ucLogID, nBuffSize, pTempPtr); - *pBuffer = pTempPtr; + unsigned char *pTempPtr = NULL; + int err = 0; + + pTempPtr = (unsigned char *)malloc(nBuffSize); + if (!pTempPtr) + goto exit_status; + memset(pTempPtr, 0, nBuffSize); + err = nvme_get_log_simple(nFD, ucLogID, nBuffSize, pTempPtr); + *pBuffer = pTempPtr; exit_status: - return err; + return err; } /* @@ -455,1532 +455,1527 @@ static int GetCommonLogPage(int nFD, unsigned char ucLogID, */ static int micron_parse_options(struct nvme_dev **dev, int argc, char **argv, const char *desc, - const struct argconfig_commandline_options *opts, - eDriveModel *modelp) + struct argconfig_commandline_options *opts, + enum eDriveModel *modelp) { - int idx = 0; - int err = parse_and_open(dev, argc, argv, desc, opts); + int idx; + int err = parse_and_open(dev, argc, argv, desc, opts); - if (err) { - perror("open"); - return -1; - } + if (err) { + perror("open"); + return -1; + } - if (modelp) { - sscanf(argv[optind], "/dev/nvme%d", &idx); - *modelp = GetDriveModel(idx); - } + if (modelp) { + if (sscanf(argv[optind], "/dev/nvme%d", &idx) != 1) + idx = 0; + *modelp = GetDriveModel(idx); + } - return 0; + return 0; } static int micron_fw_commit(int fd, int select) { - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_fw_commit, - .cdw10 = 8, - .cdw12 = select, - }; - return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd); + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_fw_commit, + .cdw10 = 8, + .cdw12 = select, + }; + return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd); } static int micron_selective_download(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + 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 selectNo, fw_fd, fw_size, err, offset = 0; - struct nvme_dev *dev; - struct stat sb; - - struct config { - char *fw; - char *select; - }; - - struct config cfg = { - .fw = "", - .select = "\0", - }; - - OPT_ARGS(opts) = { - OPT_STRING("fw", 'f', "FILE", &cfg.fw, fw), - OPT_STRING("select", 's', "flag", &cfg.select, select), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - if (strlen(cfg.select) != 3) { - fprintf(stderr, "Invalid select flag\n"); - dev_close(dev); - return EINVAL; - } - - for (int i = 0; i < 3; i++) { - cfg.select[i] = toupper(cfg.select[i]); - } - - if (strncmp(cfg.select, "OOB", 3) == 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"); - dev_close(dev); - return EINVAL; - } - - fw_fd = open(cfg.fw, O_RDONLY); - if (fw_fd < 0) { - fprintf(stderr, "no firmware file provided\n"); - dev_close(dev); - return EINVAL; - } - - err = fstat(fw_fd, &sb); - if (err < 0) { - perror("fstat"); - err = errno; - goto out; - } - - fw_size = sb.st_size; - if (fw_size & 0x3) { - fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size); - err = EINVAL; - goto out; - } - - if (posix_memalign(&fw_buf, getpagesize(), fw_size)) { - fprintf(stderr, "No memory for f/w size:%d\n", fw_size); - err = ENOMEM; - goto out; - } - - if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size))) { - err = errno; - goto out_free; - } - - while (fw_size > 0) { - xfer = min(xfer, fw_size); - - struct nvme_fw_download_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .offset = offset, - .data_len = xfer, - .data = fw_buf, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, + const char *desc = + "This performs a selective firmware download, which allows the user to\n" + "select which firmware binary to update for 9200 devices. This requires\n" + "a power cycle once the update completes. The options available are:\n\n" + "OOB - This updates the OOB and main firmware\n" + "EEP - This updates the eeprom and main firmware\n" + "ALL - This updates the eeprom, OOB, and main firmware"; + const char *fw = "firmware file (required)"; + const char *select = "FW Select (e.g., --select=ALL)"; + int xfer = 4096; + void *fw_buf; + int selectNo, fw_fd, fw_size, err, offset = 0; + struct nvme_dev *dev; + struct stat sb; + + struct config { + char *fw; + char *select; }; - err = nvme_fw_download(&args); - if (err < 0) { - perror("fw-download"); - goto out_free; - } else if (err != 0) { - nvme_show_status(err); - goto out_free; - } - fw_buf += xfer; - fw_size -= xfer; - offset += xfer; - } - - err = micron_fw_commit(dev_fd(dev), selectNo); - - if (err == 0x10B || err == 0x20B) { - err = 0; - fprintf(stderr, - "Update successful! Power cycle for changes to take effect\n"); - } + + struct config cfg = { + .fw = "", + .select = "\0", + }; + + OPT_ARGS(opts) = { + OPT_STRING("fw", 'f', "FILE", &cfg.fw, fw), + OPT_STRING("select", 's', "flag", &cfg.select, select), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (strlen(cfg.select) != 3) { + fprintf(stderr, "Invalid select flag\n"); + dev_close(dev); + return -EINVAL; + } + + for (int i = 0; i < 3; i++) + cfg.select[i] = toupper(cfg.select[i]); + + if (!strncmp(cfg.select, "OOB", 3)) { + selectNo = 18; + } else if (!strncmp(cfg.select, "EEP", 3)) { + selectNo = 10; + } else if (!strncmp(cfg.select, "ALL", 3)) { + selectNo = 26; + } else { + fprintf(stderr, "Invalid select flag\n"); + dev_close(dev); + return -EINVAL; + } + + fw_fd = open(cfg.fw, O_RDONLY); + if (fw_fd < 0) { + fprintf(stderr, "no firmware file provided\n"); + dev_close(dev); + return -EINVAL; + } + + err = fstat(fw_fd, &sb); + if (err < 0) { + perror("fstat"); + err = errno; + goto out; + } + + fw_size = sb.st_size; + if (fw_size & 0x3) { + fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size); + err = EINVAL; + goto out; + } + + if (posix_memalign(&fw_buf, getpagesize(), fw_size)) { + fprintf(stderr, "No memory for f/w size:%d\n", fw_size); + err = ENOMEM; + goto out; + } + + if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size))) { + err = errno; + goto out_free; + } + + while (fw_size > 0) { + xfer = min(xfer, fw_size); + + struct nvme_fw_download_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .offset = offset, + .data_len = xfer, + .data = fw_buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + + err = nvme_fw_download(&args); + if (err < 0) { + perror("fw-download"); + goto out_free; + } else if (err) { + nvme_show_status(err); + goto out_free; + } + fw_buf += xfer; + fw_size -= xfer; + offset += xfer; + } + + err = micron_fw_commit(dev_fd(dev), selectNo); + + if (err == 0x10B || err == 0x20B) { + err = 0; + fprintf(stderr, + "Update successful! Power cycle for changes to take effect\n"); + } out_free: - free(fw_buf); + free(fw_buf); out: - close(fw_fd); - dev_close(dev); - return err; + close(fw_fd); + dev_close(dev); + return err; } static int micron_smbus_option(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - __u32 result = 0; - __u32 cdw11 = 0; - const char *desc = "Enable/Disable/Get status of SMBUS option on controller"; - const char *option = "enable or disable or status"; - const char *value = "1 - hottest component temperature, 0 - composite " - "temperature (default) for enable option, 0 (current), " - "1 (default), 2 (saved) for status options"; - const char *save = "1 - persistent, 0 - non-persistent (default)"; - int fid = MICRON_FEATURE_SMBUS_OPTION; - eDriveModel model = UNKNOWN_MODEL; - struct nvme_dev *dev; - int err = 0; - - struct { - char *option; - int value; - int save; - int status; - } opt = { - .option = "disable", - .value = 0, - .save = 0, - .status = 0, - }; - - OPT_ARGS(opts) = { - OPT_STRING("option", 'o', "option", &opt.option, option), - OPT_UINT("value", 'v', &opt.value, value), - OPT_UINT("save", 's', &opt.save, save), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return err; - - if (model != M5407 && model != M5411) { - printf ("This option is not supported for specified drive\n"); - dev_close(dev); - return err; - } - - if (!strcmp(opt.option, "enable")) { - cdw11 = opt.value << 1 | 1; - err = nvme_set_features_simple(dev_fd(dev), fid, 1, cdw11, opt.save, - &result); - if (err == 0) { - printf("successfully enabled SMBus on drive\n"); - } else { - printf("Failed to enabled SMBus on drive\n"); - } - } - else if (!strcmp(opt.option, "status")) { - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = fid, - .nsid = 1, - .sel = opt.value, - .cdw11 = 0, - .uuidx = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_get_features(&args); - if (err == 0) { - printf("SMBus status on the drive: %s (returns %s temperature) \n", - (result & 1) ? "enabled" : "disabled", - (result & 2) ? "hottest component" : "composite"); - } else { - printf("Failed to retrieve SMBus status on the drive\n"); - } - } - else if (!strcmp(opt.option, "disable")) { - cdw11 = opt.value << 1 | 0; - err = nvme_set_features_simple(dev_fd(dev), fid, 1, cdw11, opt.save, - &result); - if (err == 0) { - printf("Successfully disabled SMBus on drive\n"); - } else { - printf("Failed to disable SMBus on drive\n"); - } - } else { - printf("Invalid option %s, valid values are enable, disable or status\n", - opt.option); - dev_close(dev); - return -1; - } - - close(dev_fd(dev)); - return err; + __u32 result = 0; + __u32 cdw11 = 0; + const char *desc = "Enable/Disable/Get status of SMBUS option on controller"; + const char *option = "enable or disable or status"; + const char *value = + "1 - hottest component temperature, 0 - composite temperature (default) for enable option, 0 (current), 1 (default), 2 (saved) for status options"; + const char *save = "1 - persistent, 0 - non-persistent (default)"; + int fid = MICRON_FEATURE_SMBUS_OPTION; + enum eDriveModel model = UNKNOWN_MODEL; + struct nvme_dev *dev; + int err = 0; + + struct { + char *option; + int value; + int save; + int status; + } opt = { + .option = "disable", + .value = 0, + .save = 0, + .status = 0, + }; + + OPT_ARGS(opts) = { + OPT_STRING("option", 'o', "option", &opt.option, option), + OPT_UINT("value", 'v', &opt.value, value), + OPT_UINT("save", 's', &opt.save, save), + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return err; + + if (model != M5407 && model != M5411) { + printf("This option is not supported for specified drive\n"); + dev_close(dev); + return err; + } + + if (!strcmp(opt.option, "enable")) { + cdw11 = opt.value << 1 | 1; + err = nvme_set_features_simple(dev_fd(dev), fid, 1, cdw11, opt.save, + &result); + if (!err) + printf("successfully enabled SMBus on drive\n"); + else + printf("Failed to enabled SMBus on drive\n"); + } else if (!strcmp(opt.option, "status")) { + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = 1, + .sel = opt.value, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_get_features(&args); + if (!err) + printf("SMBus status on the drive: %s (returns %s temperature)\n", + (result & 1) ? "enabled" : "disabled", + (result & 2) ? "hottest component" : "composite"); + else + printf("Failed to retrieve SMBus status on the drive\n"); + } else if (!strcmp(opt.option, "disable")) { + cdw11 = opt.value << 1 | 0; + err = nvme_set_features_simple(dev_fd(dev), fid, 1, cdw11, opt.save, + &result); + if (!err) + printf("Successfully disabled SMBus on drive\n"); + else + printf("Failed to disable SMBus on drive\n"); + } else { + printf("Invalid option %s, valid values are enable, disable or status\n", + opt.option); + dev_close(dev); + return -1; + } + + close(dev_fd(dev)); + return err; } static int micron_temp_stats(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - struct nvme_smart_log smart_log; - unsigned int temperature = 0, i = 0, err = 0; - unsigned int tempSensors[SensorCount] = { 0 }; - const char *desc = "Retrieve Micron temperature info for the given device "; - const char *fmt = "output format normal|json"; - struct format { - char *fmt; - }; - struct format cfg = { - .fmt = "normal", - }; - bool is_json = false; - struct json_object *root; - struct json_object *logPages; - struct nvme_dev *dev; - - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) { - printf("\nDevice not found \n");; - return -1; - } - - if (strcmp(cfg.fmt, "json") == 0) - is_json = true; - - err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); - if (!err) { - temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]); - temperature = temperature ? temperature - 273 : 0; - for (i = 0; i < SensorCount && tempSensors[i] != 0; i++) { - tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]); - tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0; - } - if (is_json) { - struct json_object *stats = json_create_object(); - char tempstr[64] = { 0 }; - root = json_create_object(); - logPages = json_create_array(); - json_object_add_value_array(root, "Micron temperature information", logPages); - sprintf(tempstr, "%u C", temperature); - json_object_add_value_string(stats, "Current Composite Temperature", tempstr); - for (i = 0; i < SensorCount && tempSensors[i] != 0; i++) { - char sensor_str[256] = { 0 }; - char datastr[64] = { 0 }; - sprintf(sensor_str, "Temperature Sensor #%d", (i + 1)); - sprintf(datastr, "%u C", tempSensors[i]); - json_object_add_value_string(stats, sensor_str, datastr); - } - json_array_add_value_object(logPages, stats); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } else { - printf("Micron temperature information:\n"); - printf("%-10s : %u C\n", "Current Composite Temperature", temperature); - for (i = 0; i < SensorCount && tempSensors[i] != 0; i++) { - printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]); - } - } - } - dev_close(dev); - return err; + struct nvme_smart_log smart_log; + unsigned int temperature = 0, i = 0, err = 0; + unsigned int tempSensors[SensorCount] = { 0 }; + const char *desc = "Retrieve Micron temperature info for the given device "; + const char *fmt = "output format normal|json"; + struct format { + char *fmt; + }; + struct format cfg = { + .fmt = "normal", + }; + bool is_json = false; + struct json_object *root; + struct json_object *logPages; + struct nvme_dev *dev; + + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) { + printf("\nDevice not found\n"); + return -1; + } + + if (!strcmp(cfg.fmt, "json")) + is_json = true; + + err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); + if (!err) { + temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]); + temperature = temperature ? temperature - 273 : 0; + for (i = 0; i < SensorCount && tempSensors[i]; i++) { + tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]); + tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0; + } + if (is_json) { + struct json_object *stats = json_create_object(); + char tempstr[64] = { 0 }; + + root = json_create_object(); + logPages = json_create_array(); + json_object_add_value_array(root, "Micron temperature information", logPages); + sprintf(tempstr, "%u C", temperature); + json_object_add_value_string(stats, "Current Composite Temperature", tempstr); + for (i = 0; i < SensorCount && tempSensors[i]; i++) { + char sensor_str[256] = { 0 }; + char datastr[64] = { 0 }; + + sprintf(sensor_str, "Temperature Sensor #%d", (i + 1)); + sprintf(datastr, "%u C", tempSensors[i]); + json_object_add_value_string(stats, sensor_str, datastr); + } + json_array_add_value_object(logPages, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + printf("Micron temperature information:\n"); + printf("%-10s : %u C\n", "Current Composite Temperature", temperature); + for (i = 0; i < SensorCount && tempSensors[i]; i++) + printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]); + } + } + dev_close(dev); + return err; } static int micron_pcie_stats(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - int i, err = 0, bus = 0, domain = 0, device = 0, function = 0, ctrlIdx; - char strTempFile[1024], strTempFile2[1024], command[1024]; - struct nvme_dev *dev; - char *businfo = NULL; - char *devicename = NULL; - char tdevice[NAME_MAX] = { 0 }; - ssize_t sLinkSize = 0; - FILE *fp; - char correctable[8] = { 0 }; - char uncorrectable[8] = { 0 }; - struct nvme_passthru_cmd admin_cmd = { 0 }; - eDriveModel eModel = UNKNOWN_MODEL; - char *res; - bool is_json = true; - bool counters = false; - struct format { - char *fmt; - }; - const char *desc = "Retrieve PCIe event counters"; - const char *fmt = "output format json|normal"; - struct format cfg = { - .fmt = "json", - }; - struct pcie_error_counters { - __u16 receiver_error; - __u16 bad_tlp; - __u16 bad_dllp; - __u16 replay_num_rollover; - __u16 replay_timer_timeout; - __u16 advisory_non_fatal_error; - __u16 DLPES; - __u16 poisoned_tlp; - __u16 FCPC; - __u16 completion_timeout; - __u16 completion_abort; - __u16 unexpected_completion; - __u16 receiver_overflow; - __u16 malformed_tlp; - __u16 ecrc_error; - __u16 unsupported_request_error; - } pcie_error_counters = { 0 }; - - struct { - char *err; - int bit; - int val; - } pcie_correctable_errors[] = { - { "Unsupported Request Error Status (URES)", 20, + int i, err = 0, bus, domain, device, function, ctrlIdx; + char strTempFile[1024], strTempFile2[1024], command[1024]; + struct nvme_dev *dev; + char *businfo = NULL; + char *devicename = NULL; + char tdevice[NAME_MAX] = { 0 }; + ssize_t sLinkSize = 0; + FILE *fp; + char correctable[8] = { 0 }; + char uncorrectable[8] = { 0 }; + struct nvme_passthru_cmd admin_cmd = { 0 }; + enum eDriveModel eModel = UNKNOWN_MODEL; + char *res; + bool is_json = true; + bool counters = false; + struct format { + char *fmt; + }; + const char *desc = "Retrieve PCIe event counters"; + const char *fmt = "output format json|normal"; + struct format cfg = { + .fmt = "json", + }; + struct pcie_error_counters { + __u16 receiver_error; + __u16 bad_tlp; + __u16 bad_dllp; + __u16 replay_num_rollover; + __u16 replay_timer_timeout; + __u16 advisory_non_fatal_error; + __u16 DLPES; + __u16 poisoned_tlp; + __u16 FCPC; + __u16 completion_timeout; + __u16 completion_abort; + __u16 unexpected_completion; + __u16 receiver_overflow; + __u16 malformed_tlp; + __u16 ecrc_error; + __u16 unsupported_request_error; + } pcie_error_counters = { 0 }; + + struct { + char *err; + int bit; + int val; + } pcie_correctable_errors[] = { + { "Unsupported Request Error Status (URES)", 20, offsetof(struct pcie_error_counters, unsupported_request_error)}, - { "ECRC Error Status (ECRCES)", 19, + { "ECRC Error Status (ECRCES)", 19, offsetof(struct pcie_error_counters, ecrc_error)}, - { "Malformed TLP Status (MTS)", 18, + { "Malformed TLP Status (MTS)", 18, offsetof(struct pcie_error_counters, malformed_tlp)}, - { "Receiver Overflow Status (ROS)", 17, + { "Receiver Overflow Status (ROS)", 17, offsetof(struct pcie_error_counters, receiver_overflow)}, - { "Unexpected Completion Status (UCS)", 16, + { "Unexpected Completion Status (UCS)", 16, offsetof(struct pcie_error_counters, unexpected_completion)}, - { "Completer Abort Status (CAS)", 15, + { "Completer Abort Status (CAS)", 15, offsetof(struct pcie_error_counters, completion_abort)}, - { "Completion Timeout Status (CTS)", 14, + { "Completion Timeout Status (CTS)", 14, offsetof(struct pcie_error_counters, completion_timeout)}, - { "Flow Control Protocol Error Status (FCPES)", 13, + { "Flow Control Protocol Error Status (FCPES)", 13, offsetof(struct pcie_error_counters, FCPC)}, - { "Poisoned TLP Status (PTS)", 12, + { "Poisoned TLP Status (PTS)", 12, offsetof(struct pcie_error_counters, poisoned_tlp)}, - { "Data Link Protocol Error Status (DLPES)", 4, + { "Data Link Protocol Error Status (DLPES)", 4, offsetof(struct pcie_error_counters, DLPES)}, - }, - pcie_uncorrectable_errors[] = { - { "Advisory Non-Fatal Error Status (ANFES)", 13, + }, + pcie_uncorrectable_errors[] = { + { "Advisory Non-Fatal Error Status (ANFES)", 13, offsetof(struct pcie_error_counters, advisory_non_fatal_error)}, - { "Replay Timer Timeout Status (RTS)", 12, + { "Replay Timer Timeout Status (RTS)", 12, offsetof(struct pcie_error_counters, replay_timer_timeout)}, - { "REPLAY_NUM Rollover Status (RRS)", 8, + { "REPLAY_NUM Rollover Status (RRS)", 8, offsetof(struct pcie_error_counters, replay_num_rollover)}, - { "Bad DLLP Status (BDS)", 7, + { "Bad DLLP Status (BDS)", 7, offsetof(struct pcie_error_counters, bad_dllp)}, - { "Bad TLP Status (BTS)", 6, + { "Bad TLP Status (BTS)", 6, offsetof(struct pcie_error_counters, bad_tlp)}, - { "Receiver Error Status (RES)", 0, + { "Receiver Error Status (RES)", 0, offsetof(struct pcie_error_counters, receiver_error)}, - }; - - __u32 correctable_errors; - __u32 uncorrectable_errors; - - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) { - printf("\nDevice not found \n");; - return -1; - } - - /* pull log details based on the model name */ - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { - printf ("Unsupported drive model for vs-pcie-stats command\n"); - goto out; - } - - if (strcmp(cfg.fmt, "normal") == 0) - is_json = false; - - if (eModel == M5407) { - admin_cmd.opcode = 0xD6; - admin_cmd.addr = (__u64)(uintptr_t)&pcie_error_counters; - admin_cmd.data_len = sizeof(pcie_error_counters); - admin_cmd.cdw10 = 1; - err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); - if (!err) { - counters = true; - correctable_errors = 10; - uncorrectable_errors = 6; - goto print_stats; - } - } - - if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) { - devicename = strrchr(argv[optind], '/'); - } else if (strstr(argv[optind], "/dev/nvme")) { - devicename = strrchr(argv[optind], '/'); - sprintf(tdevice, "%s%s", devicename, "n1"); - devicename = tdevice; - } else { - printf("Invalid device specified!\n"); - goto out; - } - sprintf(strTempFile, "/sys/block/%s/device", devicename); - memset(strTempFile2, 0x0, 1024); - sLinkSize = readlink(strTempFile, strTempFile2, 1023); - if (sLinkSize < 0) { - err = -errno; - printf("Failed to read device\n"); - goto out; - } - if (strstr(strTempFile2, "../../nvme")) { - sprintf(strTempFile, "/sys/block/%s/device/device", devicename); - memset(strTempFile2, 0x0, 1024); - sLinkSize = readlink(strTempFile, strTempFile2, 1023); - if (sLinkSize < 0) { - err = -errno; - printf("Failed to read device\n"); - goto out; - } - } - businfo = strrchr(strTempFile2, '/'); - sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function); - sprintf(command, "setpci -s %x:%x.%x ECAP_AER+10.L", bus, device, - function); - fp = popen(command, "r"); - if (fp == NULL) { - printf("Failed to retrieve error count\n"); - goto out; - } - res = fgets(correctable, sizeof(correctable), fp); - if (res == NULL) { - printf("Failed to retrieve error count\n"); - pclose(fp); - goto out; - } - pclose(fp); - - sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x4.L", bus, device, - function); - fp = popen(command, "r"); - if (fp == NULL) { - printf("Failed to retrieve error count\n"); - goto out; - } - res = fgets(uncorrectable, sizeof(uncorrectable), fp); - if (res == NULL) { - printf("Failed to retrieve error count\n"); - pclose(fp); - goto out; - } - pclose(fp); - - correctable_errors = (__u32)strtol(correctable, NULL, 16); - uncorrectable_errors = (__u32)strtol(uncorrectable, NULL, 16); + }; + + __u32 correctable_errors; + __u32 uncorrectable_errors; + + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) { + printf("\nDevice not found\n"); + return -1; + } + + /* pull log details based on the model name */ + if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1) + ctrlIdx = 0; + eModel = GetDriveModel(ctrlIdx); + if (eModel == UNKNOWN_MODEL) { + printf("Unsupported drive model for vs-pcie-stats command\n"); + goto out; + } + + if (!strcmp(cfg.fmt, "normal")) + is_json = false; + + if (eModel == M5407) { + admin_cmd.opcode = 0xD6; + admin_cmd.addr = (__u64)(uintptr_t)&pcie_error_counters; + admin_cmd.data_len = sizeof(pcie_error_counters); + admin_cmd.cdw10 = 1; + err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); + if (!err) { + counters = true; + correctable_errors = 10; + uncorrectable_errors = 6; + goto print_stats; + } + } + + if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) { + devicename = strrchr(argv[optind], '/'); + } else if (strstr(argv[optind], "/dev/nvme")) { + devicename = strrchr(argv[optind], '/'); + sprintf(tdevice, "%s%s", devicename, "n1"); + devicename = tdevice; + } else { + printf("Invalid device specified!\n"); + goto out; + } + sprintf(strTempFile, "/sys/block/%s/device", devicename); + memset(strTempFile2, 0x0, 1024); + sLinkSize = readlink(strTempFile, strTempFile2, 1023); + if (sLinkSize < 0) { + err = -errno; + printf("Failed to read device\n"); + goto out; + } + if (strstr(strTempFile2, "../../nvme")) { + sprintf(strTempFile, "/sys/block/%s/device/device", devicename); + memset(strTempFile2, 0x0, 1024); + sLinkSize = readlink(strTempFile, strTempFile2, 1023); + if (sLinkSize < 0) { + err = -errno; + printf("Failed to read device\n"); + goto out; + } + } + businfo = strrchr(strTempFile2, '/'); + if (sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function) != 4) + domain = bus = device = function = 0; + sprintf(command, "setpci -s %x:%x.%x ECAP_AER+10.L", bus, device, + function); + fp = popen(command, "r"); + if (!fp) { + printf("Failed to retrieve error count\n"); + goto out; + } + res = fgets(correctable, sizeof(correctable), fp); + if (!res) { + printf("Failed to retrieve error count\n"); + pclose(fp); + goto out; + } + pclose(fp); + + sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x4.L", bus, device, + function); + fp = popen(command, "r"); + if (!fp) { + printf("Failed to retrieve error count\n"); + goto out; + } + res = fgets(uncorrectable, sizeof(uncorrectable), fp); + if (!res) { + printf("Failed to retrieve error count\n"); + pclose(fp); + goto out; + } + pclose(fp); + + correctable_errors = (__u32)strtol(correctable, NULL, 16); + uncorrectable_errors = (__u32)strtol(uncorrectable, NULL, 16); print_stats: - if (is_json) { - - struct json_object *root = json_create_object(); - struct json_object *pcieErrors = json_create_array(); - struct json_object *stats = json_create_object(); - __u8 *pcounter = (__u8 *)&pcie_error_counters; - - json_object_add_value_array(root, "PCIE Stats", pcieErrors); - for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) { - __u16 val = counters ? *(__u16 *)(pcounter + pcie_correctable_errors[i].val) : - (correctable_errors >> pcie_correctable_errors[i].bit) & 1; - json_object_add_value_int(stats, pcie_correctable_errors[i].err, val); - } - for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) { - __u16 val = counters ? *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val) : - (uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1; - json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err, val); - } - json_array_add_value_object(pcieErrors, stats); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } else if (counters == true) { - __u8 *pcounter = (__u8 *)&pcie_error_counters; - for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) { - printf("%-42s : %-1hu\n", pcie_correctable_errors[i].err, - *(__u16 *)(pcounter + pcie_correctable_errors[i].val)); - } - for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) { - printf("%-42s : %-1hu\n", pcie_uncorrectable_errors[i].err, - *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val)); - } - } else if (eModel == M5407 || eModel == M5410) { - for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) { - printf("%-42s : %-1d\n", pcie_correctable_errors[i].err, - ((correctable_errors >> pcie_correctable_errors[i].bit) & 1)); - } - for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) { - printf("%-42s : %-1d\n", pcie_uncorrectable_errors[i].err, - ((uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1)); - } - } else { - printf("PCIE Stats:\n"); - printf("Device correctable errors detected: %s\n", correctable); - printf("Device uncorrectable errors detected: %s\n", uncorrectable); - } + if (is_json) { + struct json_object *root = json_create_object(); + struct json_object *pcieErrors = json_create_array(); + struct json_object *stats = json_create_object(); + __u8 *pcounter = (__u8 *)&pcie_error_counters; + + json_object_add_value_array(root, "PCIE Stats", pcieErrors); + for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors); i++) { + __u16 val = counters ? *(__u16 *)(pcounter + pcie_correctable_errors[i].val) : + (correctable_errors >> pcie_correctable_errors[i].bit) & 1; + json_object_add_value_int(stats, pcie_correctable_errors[i].err, val); + } + for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors); i++) { + __u16 val = counters ? *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val) : + (uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1; + json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err, val); + } + json_array_add_value_object(pcieErrors, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else if (counters == true) { + __u8 *pcounter = (__u8 *)&pcie_error_counters; + + for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors); i++) + printf("%-42s : %-1hu\n", pcie_correctable_errors[i].err, + *(__u16 *)(pcounter + pcie_correctable_errors[i].val)); + for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors); i++) + printf("%-42s : %-1hu\n", pcie_uncorrectable_errors[i].err, + *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val)); + } else if (eModel == M5407 || eModel == M5410) { + for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors); i++) + printf("%-42s : %-1d\n", pcie_correctable_errors[i].err, + ((correctable_errors >> pcie_correctable_errors[i].bit) & 1)); + for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors); i++) + printf("%-42s : %-1d\n", pcie_uncorrectable_errors[i].err, + ((uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1)); + } else { + printf("PCIE Stats:\n"); + printf("Device correctable errors detected: %s\n", correctable); + printf("Device uncorrectable errors detected: %s\n", uncorrectable); + } out: - dev_close(dev); - return err; + dev_close(dev); + return err; } static int micron_clear_pcie_correctable_errors(int argc, char **argv, - struct command *cmd, - struct plugin *plugin) + struct command *cmd, + struct plugin *plugin) { - int err = -EINVAL, bus = 0, domain = 0, device = 0, function = 0; - char strTempFile[1024], strTempFile2[1024], command[1024]; - struct nvme_dev *dev; - char *businfo = NULL; - char *devicename = NULL; - char tdevice[PATH_MAX] = { 0 }; - ssize_t sLinkSize = 0; - eDriveModel model = UNKNOWN_MODEL; - struct nvme_passthru_cmd admin_cmd = { 0 }; - char correctable[8] = { 0 }; - FILE *fp; - char *res; - const char *desc = "Clear PCIe Device Correctable Errors"; - __u32 result = 0; - __u8 fid = MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS; - OPT_ARGS(opts) = { - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return err; - - /* For M51CX models, PCIe errors are cleared using 0xC3 feature */ - if (model == M51CX) { - err = nvme_set_features_simple(dev_fd(dev), fid, 0, (1 << 31), false, - &result); - if (err == 0 && (err = (int)result) == 0) { - printf("Device correctable errors are cleared!\n"); - goto out; - } - } else if (model == M5407) { - admin_cmd.opcode = 0xD6; - admin_cmd.addr = 0; - admin_cmd.cdw10 = 0; - err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); - if (err == 0) { - printf("Device correctable error counters are cleared!\n"); - goto out; - } else { - /* proceed to clear status bits using sysfs interface - printf("Error clearing PCIe correctable errors = 0x%x\n", err); */ - } - } - - if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) { - devicename = strrchr(argv[optind], '/'); - } else if (strstr(argv[optind], "/dev/nvme")) { - devicename = strrchr(argv[optind], '/'); - sprintf(tdevice, "%s%s", devicename, "n1"); - devicename = tdevice; - } else { - printf("Invalid device specified!\n"); - goto out; - } - err = snprintf(strTempFile, sizeof(strTempFile), - "/sys/block/%s/device", devicename); - if (err < 0) - goto out; - - memset(strTempFile2, 0x0, 1024); - sLinkSize = readlink(strTempFile, strTempFile2, 1023); - if (sLinkSize < 0) { - err = -errno; - printf("Failed to read device\n"); - goto out; - } - if (strstr(strTempFile2, "../../nvme")) { - err = snprintf(strTempFile, sizeof(strTempFile), - "/sys/block/%s/device/device", devicename); - if (err < 0) - goto out; - memset(strTempFile2, 0x0, 1024); - sLinkSize = readlink(strTempFile, strTempFile2, 1023); - if (sLinkSize < 0) { - err = -errno; - printf("Failed to read device\n"); - goto out; - } - } - businfo = strrchr(strTempFile2, '/'); - sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function); - sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L=0xffffffff", bus, - device, function); - err = -1; - fp = popen(command, "r"); - if (fp == NULL) { - printf("Failed to clear error count\n"); - goto out; - } - pclose(fp); - - sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L", bus, device, - function); - fp = popen(command, "r"); - if (fp == NULL) { - printf("Failed to retrieve error count\n"); - goto out; - } - res = fgets(correctable, sizeof(correctable), fp); - if (res == NULL) { - printf("Failed to retrieve error count\n"); - pclose(fp); - goto out; - } - pclose(fp); - printf("Device correctable errors cleared!\n"); - printf("Device correctable errors detected: %s\n", correctable); - err = 0; + int err = -EINVAL, bus, domain, device, function; + char strTempFile[1024], strTempFile2[1024], command[1024]; + struct nvme_dev *dev; + char *businfo = NULL; + char *devicename = NULL; + char tdevice[PATH_MAX] = { 0 }; + ssize_t sLinkSize = 0; + enum eDriveModel model = UNKNOWN_MODEL; + struct nvme_passthru_cmd admin_cmd = { 0 }; + char correctable[8] = { 0 }; + FILE *fp; + char *res; + const char *desc = "Clear PCIe Device Correctable Errors"; + __u32 result = 0; + __u8 fid = MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS; + + OPT_ARGS(opts) = { + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return err; + + /* For M51CX models, PCIe errors are cleared using 0xC3 feature */ + if (model == M51CX) { + err = nvme_set_features_simple(dev_fd(dev), fid, 0, (1 << 31), false, + &result); + if (!err) + err = (int)result; + if (!err) { + printf("Device correctable errors are cleared!\n"); + goto out; + } + } else if (model == M5407) { + admin_cmd.opcode = 0xD6; + admin_cmd.addr = 0; + admin_cmd.cdw10 = 0; + err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); + if (!err) { + printf("Device correctable error counters are cleared!\n"); + goto out; + } else { + /* proceed to clear status bits using sysfs interface */ + } + } + + if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) { + devicename = strrchr(argv[optind], '/'); + } else if (strstr(argv[optind], "/dev/nvme")) { + devicename = strrchr(argv[optind], '/'); + sprintf(tdevice, "%s%s", devicename, "n1"); + devicename = tdevice; + } else { + printf("Invalid device specified!\n"); + goto out; + } + err = snprintf(strTempFile, sizeof(strTempFile), + "/sys/block/%s/device", devicename); + if (err < 0) + goto out; + + memset(strTempFile2, 0x0, 1024); + sLinkSize = readlink(strTempFile, strTempFile2, 1023); + if (sLinkSize < 0) { + err = -errno; + printf("Failed to read device\n"); + goto out; + } + if (strstr(strTempFile2, "../../nvme")) { + err = snprintf(strTempFile, sizeof(strTempFile), + "/sys/block/%s/device/device", devicename); + if (err < 0) + goto out; + memset(strTempFile2, 0x0, 1024); + sLinkSize = readlink(strTempFile, strTempFile2, 1023); + if (sLinkSize < 0) { + err = -errno; + printf("Failed to read device\n"); + goto out; + } + } + businfo = strrchr(strTempFile2, '/'); + if (sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function) != 4) + domain = bus = device = function = 0; + sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L=0xffffffff", bus, + device, function); + err = -1; + fp = popen(command, "r"); + if (!fp) { + printf("Failed to clear error count\n"); + goto out; + } + pclose(fp); + + sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L", bus, device, + function); + fp = popen(command, "r"); + if (!fp) { + printf("Failed to retrieve error count\n"); + goto out; + } + res = fgets(correctable, sizeof(correctable), fp); + if (!res) { + printf("Failed to retrieve error count\n"); + pclose(fp); + goto out; + } + pclose(fp); + printf("Device correctable errors cleared!\n"); + printf("Device correctable errors detected: %s\n", correctable); + err = 0; out: - dev_close(dev); - return err; + dev_close(dev); + return err; } static struct logpage { - const char *field; - char datastr[128]; + const char *field; + char datastr[128]; } d0_log_page[] = { - { "NAND Writes (Bytes Written)", { 0 }}, - { "Program Failure Count", { 0 }}, - { "Erase Failures", { 0 }}, - { "Bad Block Count", { 0 }}, - { "NAND XOR/RAID Recovery Trigger Events", { 0 }}, - { "NSZE Change Supported", { 0 }}, - { "Number of NSZE Modifications", { 0 }} + { "NAND Writes (Bytes Written)", { 0 }}, + { "Program Failure Count", { 0 }}, + { "Erase Failures", { 0 }}, + { "Bad Block Count", { 0 }}, + { "NAND XOR/RAID Recovery Trigger Events", { 0 }}, + { "NSZE Change Supported", { 0 }}, + { "Number of NSZE Modifications", { 0 }} }; static void init_d0_log_page(__u8 *buf, __u8 nsze) { - unsigned int logD0[D0_log_size/sizeof(int)] = { 0 }; - __u64 count_lo, count_hi, count; + unsigned int logD0[D0_log_size/sizeof(int)] = { 0 }; + __u64 count_lo, count_hi, count; - memcpy(logD0, buf, sizeof(logD0)); + memcpy(logD0, buf, sizeof(logD0)); - count = ((__u64)logD0[45] << 32) | logD0[44]; - sprintf(d0_log_page[0].datastr, "0x%"PRIx64, le64_to_cpu(count)); + count = ((__u64)logD0[45] << 32) | logD0[44]; + sprintf(d0_log_page[0].datastr, "0x%"PRIx64, le64_to_cpu(count)); - count_hi = ((__u64)logD0[39] << 32) | logD0[38]; - count_lo = ((__u64)logD0[37] << 32) | logD0[36]; - if (count_hi != 0) - sprintf(d0_log_page[1].datastr, "0x%"PRIx64"%016"PRIx64, - le64_to_cpu(count_hi), le64_to_cpu(count_lo)); - else - sprintf(d0_log_page[1].datastr, "0x%"PRIx64, le64_to_cpu(count_lo)); + count_hi = ((__u64)logD0[39] << 32) | logD0[38]; + count_lo = ((__u64)logD0[37] << 32) | logD0[36]; + if (count_hi) + sprintf(d0_log_page[1].datastr, "0x%"PRIx64"%016"PRIx64, + le64_to_cpu(count_hi), le64_to_cpu(count_lo)); + else + sprintf(d0_log_page[1].datastr, "0x%"PRIx64, le64_to_cpu(count_lo)); - count = ((__u64)logD0[25] << 32) | logD0[24]; - sprintf(d0_log_page[2].datastr, "0x%"PRIx64, le64_to_cpu(count)); + count = ((__u64)logD0[25] << 32) | logD0[24]; + sprintf(d0_log_page[2].datastr, "0x%"PRIx64, le64_to_cpu(count)); - sprintf(d0_log_page[3].datastr, "0x%x", logD0[3]); + sprintf(d0_log_page[3].datastr, "0x%x", logD0[3]); - count_lo = ((__u64)logD0[37] << 32) | logD0[36]; - count = ((__u64)logD0[25] << 32) | logD0[24]; - count = (__u64)logD0[3] - (count_lo + count); - sprintf(d0_log_page[4].datastr, "0x%"PRIx64, le64_to_cpu(count)); + count_lo = ((__u64)logD0[37] << 32) | logD0[36]; + count = ((__u64)logD0[25] << 32) | logD0[24]; + count = (__u64)logD0[3] - (count_lo + count); + sprintf(d0_log_page[4].datastr, "0x%"PRIx64, le64_to_cpu(count)); - sprintf(d0_log_page[5].datastr, "0x%x", nsze); - sprintf(d0_log_page[6].datastr, "0x%x", logD0[1]); + sprintf(d0_log_page[5].datastr, "0x%x", nsze); + sprintf(d0_log_page[6].datastr, "0x%x", logD0[1]); } /* OCP and Vendor specific log data format */ struct micron_vs_logpage { - char *field; - int size; /* FB client spec version 1.0 sizes - M5410 models */ - int size2; /* FB client spec version 0.7 sizes - M5407 models */ + char *field; + int size; /* FB client spec version 1.0 sizes - M5410 models */ + int size2; /* FB client spec version 0.7 sizes - M5407 models */ } /* Smart Health Log information as per OCP spec M51CX models */ ocp_c0_log_page[] = { - { "Physical Media Units Written", 16}, - { "Physical Media Units Read", 16 }, - { "Raw Bad User NAND Block Count", 6}, - { "Normalized Bad User NAND Block Count", 2}, - { "Raw Bad System NAND Block Count", 6}, - { "Normalized Bad System NAND Block Count", 2}, - { "XOR Recovery Count", 8}, - { "Uncorrectable Read Error Count", 8}, - { "Soft ECC Error Count", 8}, - { "SSD End to End Detected Counts", 4}, - { "SSD End to End Corrected Errors", 4}, - { "System data % life-used", 1}, - { "Refresh Count", 7}, - { "Maximum User Data Erase Count", 4}, - { "Minimum User Data Erase Count", 4}, - { "Thermal Throttling Count", 1}, - { "Thermal Throttling Status", 1}, - { "Reserved", 6}, - { "PCIe Correctable Error count", 8}, - { "Incomplete Shutdowns", 4}, - { "Reserved", 4}, - { "% Free Blocks", 1}, - { "Reserved", 7}, - { "Capacitor Health", 2}, - { "Reserved", 6}, - { "Unaligned I/O", 8}, - { "Security Version Number", 8}, - { "NUSE", 8}, - { "PLP Start Count", 16}, - { "Endurance Estimate", 16}, - { "Reserved", 302}, - { "Log Page Version", 2}, - { "Log Page GUID", 16}, + { "Physical Media Units Written", 16}, + { "Physical Media Units Read", 16 }, + { "Raw Bad User NAND Block Count", 6}, + { "Normalized Bad User NAND Block Count", 2}, + { "Raw Bad System NAND Block Count", 6}, + { "Normalized Bad System NAND Block Count", 2}, + { "XOR Recovery Count", 8}, + { "Uncorrectable Read Error Count", 8}, + { "Soft ECC Error Count", 8}, + { "SSD End to End Detected Counts", 4}, + { "SSD End to End Corrected Errors", 4}, + { "System data % life-used", 1}, + { "Refresh Count", 7}, + { "Maximum User Data Erase Count", 4}, + { "Minimum User Data Erase Count", 4}, + { "Thermal Throttling Count", 1}, + { "Thermal Throttling Status", 1}, + { "Reserved", 6}, + { "PCIe Correctable Error count", 8}, + { "Incomplete Shutdowns", 4}, + { "Reserved", 4}, + { "% Free Blocks", 1}, + { "Reserved", 7}, + { "Capacitor Health", 2}, + { "Reserved", 6}, + { "Unaligned I/O", 8}, + { "Security Version Number", 8}, + { "NUSE", 8}, + { "PLP Start Count", 16}, + { "Endurance Estimate", 16}, + { "Reserved", 302}, + { "Log Page Version", 2}, + { "Log Page GUID", 16}, }, /* Extended SMART log information */ e1_log_page[] = { - { "Reserved", 12}, - { "Grown Bad Block Count", 4}, - { "Per Block Max Erase Count", 4}, - { "Power On Minutes", 4}, - { "Reserved", 24}, - { "Write Protect Reason", 4}, - { "Reserved", 12}, - { "Drive Capacity", 8}, - { "Reserved", 8}, - { "Total Erase Count", 8}, - { "Lifetime Use Rate", 8}, - { "Erase Fail Count", 8}, - { "Reserved", 8}, - { "Reported UC Errors", 8}, - { "Reserved", 24}, - { "Program Fail Count", 16}, - { "Total Bytes Read", 16}, - { "Total Bytes Written", 16}, - { "Reserved", 16}, - { "TU Size", 4}, - { "Total Block Stripe Count", 4}, - { "Free Block Stripe Count", 4}, - { "Block Stripe Size", 8}, - { "Reserved", 16}, - { "User Block Min Erase Count", 4}, - { "User Block Avg Erase Count", 4}, - { "User Block Max Erase Count", 4}, + { "Reserved", 12}, + { "Grown Bad Block Count", 4}, + { "Per Block Max Erase Count", 4}, + { "Power On Minutes", 4}, + { "Reserved", 24}, + { "Write Protect Reason", 4}, + { "Reserved", 12}, + { "Drive Capacity", 8}, + { "Reserved", 8}, + { "Total Erase Count", 8}, + { "Lifetime Use Rate", 8}, + { "Erase Fail Count", 8}, + { "Reserved", 8}, + { "Reported UC Errors", 8}, + { "Reserved", 24}, + { "Program Fail Count", 16}, + { "Total Bytes Read", 16}, + { "Total Bytes Written", 16}, + { "Reserved", 16}, + { "TU Size", 4}, + { "Total Block Stripe Count", 4}, + { "Free Block Stripe Count", 4}, + { "Block Stripe Size", 8}, + { "Reserved", 16}, + { "User Block Min Erase Count", 4}, + { "User Block Avg Erase Count", 4}, + { "User Block Max Erase Count", 4}, }, /* Vendor Specific Health Log information */ fb_log_page[] = { - { "Physical Media Units Written - TLC", 16, 16 }, - { "Physical Media Units Written - SLC", 16, 16 }, - { "Normalized Bad User NAND Block Count", 2, 2}, - { "Raw Bad User NAND Block Count", 6, 6}, - { "XOR Recovery Count", 8, 8}, - { "Uncorrectable Read Error Count", 8, 8}, - { "SSD End to End Corrected Errors", 8, 8}, - { "SSD End to End Detected Counts", 4, 8}, - { "SSD End to End Uncorrected Counts", 4, 8}, - { "System data % life-used", 1, 1}, - { "Reserved", 0, 3}, - { "Minimum User Data Erase Count - TLC", 8, 8}, - { "Maximum User Data Erase Count - TLC", 8, 8}, - { "Average User Data Erase Count - TLC", 0, 8}, - { "Minimum User Data Erase Count - SLC", 8, 8}, - { "Maximum User Data Erase Count - SLC", 8, 8}, - { "Average User Data Erase Count - SLC", 0, 8}, - { "Normalized Program Fail Count", 2, 2}, - { "Raw Program Fail Count", 6, 6}, - { "Normalized Erase Fail Count", 2, 2}, - { "Raw Erase Fail Count", 6, 6}, - { "Pcie Correctable Error Count", 8, 8}, - { "% Free Blocks (User)", 1, 1}, - { "Reserved", 0, 3}, - { "Security Version Number", 8, 8}, - { "% Free Blocks (System)", 1, 1}, - { "Reserved", 0, 3}, - { "Dataset Management (Deallocate) Commands", 16, 16}, - { "Incomplete TRIM Data", 8, 8}, - { "% Age of Completed TRIM", 1, 2}, - { "Background Back-Pressure Gauge", 1, 1}, - { "Reserved", 0, 3}, - { "Soft ECC Error Count", 8, 8}, - { "Refresh Count", 8, 8}, - { "Normalized Bad System NAND Block Count", 2, 2}, - { "Raw Bad System NAND Block Count", 6, 6}, - { "Endurance Estimate", 16, 16}, - { "Thermal Throttling Status", 1, 1}, - { "Thermal Throttling Count", 1, 1}, - { "Unaligned I/O", 8, 8}, - { "Physical Media Units Read", 16, 16}, - { "Reserved", 279, 0}, - { "Log Page Version", 2, 0}, - { "READ CMDs exceeding threshold", 0, 4}, - { "WRITE CMDs exceeding threshold", 0, 4}, - { "TRIMs CMDs exceeding threshold", 0, 4}, - { "Reserved", 0, 4}, - { "Reserved", 0, 210}, - { "Log Page Version", 0, 2}, - { "Log Page GUID", 0, 16}, + { "Physical Media Units Written - TLC", 16, 16 }, + { "Physical Media Units Written - SLC", 16, 16 }, + { "Normalized Bad User NAND Block Count", 2, 2}, + { "Raw Bad User NAND Block Count", 6, 6}, + { "XOR Recovery Count", 8, 8}, + { "Uncorrectable Read Error Count", 8, 8}, + { "SSD End to End Corrected Errors", 8, 8}, + { "SSD End to End Detected Counts", 4, 8}, + { "SSD End to End Uncorrected Counts", 4, 8}, + { "System data % life-used", 1, 1}, + { "Reserved", 0, 3}, + { "Minimum User Data Erase Count - TLC", 8, 8}, + { "Maximum User Data Erase Count - TLC", 8, 8}, + { "Average User Data Erase Count - TLC", 0, 8}, + { "Minimum User Data Erase Count - SLC", 8, 8}, + { "Maximum User Data Erase Count - SLC", 8, 8}, + { "Average User Data Erase Count - SLC", 0, 8}, + { "Normalized Program Fail Count", 2, 2}, + { "Raw Program Fail Count", 6, 6}, + { "Normalized Erase Fail Count", 2, 2}, + { "Raw Erase Fail Count", 6, 6}, + { "Pcie Correctable Error Count", 8, 8}, + { "% Free Blocks (User)", 1, 1}, + { "Reserved", 0, 3}, + { "Security Version Number", 8, 8}, + { "% Free Blocks (System)", 1, 1}, + { "Reserved", 0, 3}, + { "Dataset Management (Deallocate) Commands", 16, 16}, + { "Incomplete TRIM Data", 8, 8}, + { "% Age of Completed TRIM", 1, 2}, + { "Background Back-Pressure Gauge", 1, 1}, + { "Reserved", 0, 3}, + { "Soft ECC Error Count", 8, 8}, + { "Refresh Count", 8, 8}, + { "Normalized Bad System NAND Block Count", 2, 2}, + { "Raw Bad System NAND Block Count", 6, 6}, + { "Endurance Estimate", 16, 16}, + { "Thermal Throttling Status", 1, 1}, + { "Thermal Throttling Count", 1, 1}, + { "Unaligned I/O", 8, 8}, + { "Physical Media Units Read", 16, 16}, + { "Reserved", 279, 0}, + { "Log Page Version", 2, 0}, + { "READ CMDs exceeding threshold", 0, 4}, + { "WRITE CMDs exceeding threshold", 0, 4}, + { "TRIMs CMDs exceeding threshold", 0, 4}, + { "Reserved", 0, 4}, + { "Reserved", 0, 210}, + { "Log Page Version", 0, 2}, + { "Log Page GUID", 0, 16}, }; -/* Common function to print Micron VS log pages */ -static void print_micron_vs_logs( - __u8 *buf, /* raw log data */ - struct micron_vs_logpage *log_page, /* format of the data */ - int field_count, /* log field count */ - struct json_object *stats, /* json object to add fields */ - __u8 spec /* ocp spec index */ -) +/* + * Common function to print Micron VS log pages + * - buf: raw log data + * - log_page: format of the data + * - field_count: log field count + * - stats: json object to add fields + * - spec: ocp spec index + */ +static void print_micron_vs_logs(__u8 *buf, struct micron_vs_logpage *log_page, int field_count, + struct json_object *stats, __u8 spec) { - __u64 lval_lo, lval_hi; - __u32 ival; - __u16 sval; - __u8 cval, lval[8] = { 0 }; - int field; - int offset = 0; - - for (field = 0; field < field_count; field++) { - char datastr[1024] = { 0 }; - char *sfield = NULL; - int size = (spec == 0) ? log_page[field].size : log_page[field].size2; - if (size == 0) continue; - sfield = log_page[field].field; - if (size == 16) { - if (strstr(sfield, "GUID")) { - sprintf(datastr, "0x%"PRIx64"%"PRIx64"", - (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset + 8])), - (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset]))); - } else { - lval_lo = *((__u64 *)(&buf[offset])); - lval_hi = *((__u64 *)(&buf[offset + 8])); - if (lval_hi) - sprintf(datastr, "0x%"PRIx64"%016"PRIx64"", - le64_to_cpu(lval_hi), le64_to_cpu(lval_lo)); - else - sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } - } else if (size == 8) { - lval_lo = *((__u64 *)(&buf[offset])); - sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (size == 7) { - /* 7 bytes will be in little-endian format, with last byte as MSB */ - memcpy(&lval[0], &buf[offset], 7); - memcpy((void *)&lval_lo, lval, 8); - sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (size == 6) { - ival = *((__u32 *)(&buf[offset])); - sval = *((__u16 *)(&buf[offset + 4])); - lval_lo = (((__u64)sval << 32) | ival); - sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (size == 4) { - ival = *((__u32 *)(&buf[offset])); - sprintf(datastr, "0x%x", le32_to_cpu(ival)); - } else if (size == 2) { - sval = *((__u16 *)(&buf[offset])); - sprintf(datastr, "0x%04x", le16_to_cpu(sval)); - } else if (size == 1) { - cval = buf[offset]; - sprintf(datastr, "0x%02x", cval); - } else { - sprintf(datastr, "0"); - } - offset += size; - /* do not print reserved values */ - if (strstr(sfield, "Reserved")) - continue; - if (stats != NULL) { - json_object_add_value_string(stats, sfield, datastr); - } else { - printf("%-40s : %-4s\n", sfield, datastr); - } - } + __u64 lval_lo, lval_hi; + __u32 ival; + __u16 sval; + __u8 cval, lval[8] = { 0 }; + int field; + int offset = 0; + + for (field = 0; field < field_count; field++) { + char datastr[1024] = { 0 }; + char *sfield = NULL; + int size = !spec ? log_page[field].size : log_page[field].size2; + + if (!size) + continue; + sfield = log_page[field].field; + if (size == 16) { + if (strstr(sfield, "GUID")) { + sprintf(datastr, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset + 8])), + (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset]))); + } else { + lval_lo = *((__u64 *)(&buf[offset])); + lval_hi = *((__u64 *)(&buf[offset + 8])); + if (lval_hi) + sprintf(datastr, "0x%"PRIx64"%016"PRIx64"", + le64_to_cpu(lval_hi), le64_to_cpu(lval_lo)); + else + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } + } else if (size == 8) { + lval_lo = *((__u64 *)(&buf[offset])); + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } else if (size == 7) { + /* 7 bytes will be in little-endian format, with last byte as MSB */ + memcpy(&lval[0], &buf[offset], 7); + memcpy((void *)&lval_lo, lval, 8); + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } else if (size == 6) { + ival = *((__u32 *)(&buf[offset])); + sval = *((__u16 *)(&buf[offset + 4])); + lval_lo = (((__u64)sval << 32) | ival); + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } else if (size == 4) { + ival = *((__u32 *)(&buf[offset])); + sprintf(datastr, "0x%x", le32_to_cpu(ival)); + } else if (size == 2) { + sval = *((__u16 *)(&buf[offset])); + sprintf(datastr, "0x%04x", le16_to_cpu(sval)); + } else if (size == 1) { + cval = buf[offset]; + sprintf(datastr, "0x%02x", cval); + } else { + sprintf(datastr, "0"); + } + offset += size; + /* do not print reserved values */ + if (strstr(sfield, "Reserved")) + continue; + if (stats) + json_object_add_value_string(stats, sfield, datastr); + else + printf("%-40s : %-4s\n", sfield, datastr); + } } static void print_smart_cloud_health_log(__u8 *buf, bool is_json) { - struct json_object *root; - struct json_object *logPages; - struct json_object *stats = NULL; - int field_count = sizeof(ocp_c0_log_page)/sizeof(ocp_c0_log_page[0]); - - if (is_json) { - root = json_create_object(); - stats = json_create_object(); - logPages = json_create_array(); - json_object_add_value_array(root, "OCP SMART Cloud Health Log: 0xC0", - logPages); - } - - print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats, 0); - - if (is_json) { - json_array_add_value_object(logPages, stats); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } + struct json_object *root; + struct json_object *logPages; + struct json_object *stats = NULL; + int field_count = ARRAY_SIZE(ocp_c0_log_page); + + if (is_json) { + root = json_create_object(); + stats = json_create_object(); + logPages = json_create_array(); + json_object_add_value_array(root, "OCP SMART Cloud Health Log: 0xC0", + logPages); + } + + print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats, 0); + + if (is_json) { + json_array_add_value_object(logPages, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } } static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json, __u8 spec) { - struct json_object *root; - struct json_object *logPages; - struct json_object *stats = NULL; - int field_count = sizeof(fb_log_page)/sizeof(fb_log_page[0]); - - if (is_json) { - root = json_create_object(); - stats = json_create_object(); - logPages = json_create_array(); - json_object_add_value_array(root, "Extended Smart Log Page : 0xFB", - logPages); - } - - print_micron_vs_logs(buf, fb_log_page, field_count, stats, spec); - - /* print last three entries from D0 log page */ - if (buf2 != NULL) { - init_d0_log_page(buf2, nsze); - - if (is_json) { - for (int i = 0; i < 7; i++) { - json_object_add_value_string(stats, - d0_log_page[i].field, - d0_log_page[i].datastr); - } - } else { - for (int i = 0; i < 7; i++) { - printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); - } - } - } - - if (is_json) { - json_array_add_value_object(logPages, stats); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } + struct json_object *root; + struct json_object *logPages; + struct json_object *stats = NULL; + int field_count = ARRAY_SIZE(fb_log_page); + + if (is_json) { + root = json_create_object(); + stats = json_create_object(); + logPages = json_create_array(); + json_object_add_value_array(root, "Extended Smart Log Page : 0xFB", + logPages); + } + + print_micron_vs_logs(buf, fb_log_page, field_count, stats, spec); + + /* print last three entries from D0 log page */ + if (buf2) { + init_d0_log_page(buf2, nsze); + + if (is_json) { + for (int i = 0; i < 7; i++) + json_object_add_value_string(stats, + d0_log_page[i].field, + d0_log_page[i].datastr); + } else { + for (int i = 0; i < 7; i++) + printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); + } + } + + if (is_json) { + json_array_add_value_object(logPages, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } } static void print_nand_stats_d0(__u8 *buf, __u8 oacs, bool is_json) { - init_d0_log_page(buf, oacs); - - if (is_json) { - struct json_object *root = json_create_object(); - struct json_object *stats = json_create_object(); - struct json_object *logPages = json_create_array(); - - json_object_add_value_array(root, - "Extended Smart Log Page : 0xD0", - logPages); - - for (int i = 0; i < 7; i++) { - json_object_add_value_string(stats, - d0_log_page[i].field, - d0_log_page[i].datastr); - } - - json_array_add_value_object(logPages, stats); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } else { - for (int i = 0; i < 7; i++) { - printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); - } - } + init_d0_log_page(buf, oacs); + + if (is_json) { + struct json_object *root = json_create_object(); + struct json_object *stats = json_create_object(); + struct json_object *logPages = json_create_array(); + + json_object_add_value_array(root, + "Extended Smart Log Page : 0xD0", + logPages); + + for (int i = 0; i < 7; i++) + json_object_add_value_string(stats, + d0_log_page[i].field, + d0_log_page[i].datastr); + + json_array_add_value_object(logPages, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + for (int i = 0; i < 7; i++) + printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); + } } -static bool nsze_from_oacs = false; /* read nsze for now from idd[4059] */ +static bool nsze_from_oacs; /* read nsze for now from idd[4059] */ static int micron_nand_stats(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Micron NAND stats for the given device "; - unsigned int extSmartLog[D0_log_size/sizeof(int)] = { 0 }; - unsigned int logFB[FB_log_size/sizeof(int)] = { 0 }; - eDriveModel eModel = UNKNOWN_MODEL; - struct nvme_id_ctrl ctrl; - struct nvme_dev *dev; - int err, ctrlIdx; - __u8 nsze; - bool has_d0_log = true; - bool has_fb_log = false; - bool is_json = true; - struct format { - char *fmt; - }; - const char *fmt = "output format json|normal"; - struct format cfg = { - .fmt = "json", - }; - - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) { - printf("\nDevice not found \n");; - return -1; - } - - if (strcmp(cfg.fmt, "normal") == 0) - is_json = false; - - err = nvme_identify_ctrl(dev_fd(dev), &ctrl); - if (err) { - printf("Error %d retrieving controller identification data\n", err); - goto out; - } - - /* pull log details based on the model name */ - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - eModel = GetDriveModel(ctrlIdx); - if ((eModel == UNKNOWN_MODEL) || (eModel == M51CX)) { - printf ("Unsupported drive model for vs-nand-stats command\n"); - err = -1; - goto out; - } - - err = nvme_get_log_simple(dev_fd(dev), 0xD0, D0_log_size, extSmartLog); - has_d0_log = (0 == err); - - /* should check for firmware version if this log is supported or not */ - if (eModel == M5407 || eModel == M5410) { - err = nvme_get_log_simple(dev_fd(dev), 0xFB, FB_log_size, logFB); - has_fb_log = (0 == err); - } - - nsze = (ctrl.vs[987] == 0x12); - if (nsze == 0 && nsze_from_oacs) - nsze = ((ctrl.oacs >> 3) & 0x1); - err = 0; - if (has_fb_log) { - __u8 spec = (eModel == M5410) ? 0 : 1; /* FB spec version */ - print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json, spec); - } else if (has_d0_log) { - print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json); - } else { - printf("Unable to retrieve extended smart log for the drive\n"); - err = -ENOTTY; - } + const char *desc = "Retrieve Micron NAND stats for the given device "; + unsigned int extSmartLog[D0_log_size/sizeof(int)] = { 0 }; + unsigned int logFB[FB_log_size/sizeof(int)] = { 0 }; + enum eDriveModel eModel = UNKNOWN_MODEL; + struct nvme_id_ctrl ctrl; + struct nvme_dev *dev; + int err, ctrlIdx; + __u8 nsze; + bool has_d0_log = true; + bool has_fb_log = false; + bool is_json = true; + struct format { + char *fmt; + }; + const char *fmt = "output format json|normal"; + struct format cfg = { + .fmt = "json", + }; + + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) { + printf("\nDevice not found\n"); + return -1; + } + + if (!strcmp(cfg.fmt, "normal")) + is_json = false; + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) { + printf("Error %d retrieving controller identification data\n", err); + goto out; + } + + /* pull log details based on the model name */ + if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1) + ctrlIdx = 0; + eModel = GetDriveModel(ctrlIdx); + if ((eModel == UNKNOWN_MODEL) || (eModel == M51CX)) { + printf("Unsupported drive model for vs-nand-stats command\n"); + err = -1; + goto out; + } + + err = nvme_get_log_simple(dev_fd(dev), 0xD0, D0_log_size, extSmartLog); + has_d0_log = !err; + + /* should check for firmware version if this log is supported or not */ + if (eModel == M5407 || eModel == M5410) { + err = nvme_get_log_simple(dev_fd(dev), 0xFB, FB_log_size, logFB); + has_fb_log = !err; + } + + nsze = (ctrl.vs[987] == 0x12); + if (!nsze && nsze_from_oacs) + nsze = ((ctrl.oacs >> 3) & 0x1); + err = 0; + if (has_fb_log) { + __u8 spec = (eModel == M5410) ? 0 : 1; /* FB spec version */ + + print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json, spec); + } else if (has_d0_log) { + print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json); + } else { + printf("Unable to retrieve extended smart log for the drive\n"); + err = -ENOTTY; + } out: - dev_close(dev); - if (err > 0) - nvme_show_status(err); + dev_close(dev); + if (err > 0) + nvme_show_status(err); - return err; + return err; } static void print_ext_smart_logs_e1(__u8 *buf, bool is_json) { - struct json_object *root; - struct json_object *logPages; - struct json_object *stats = NULL; - int field_count = sizeof(e1_log_page)/sizeof(e1_log_page[0]); - - if (is_json) { - root = json_create_object(); - stats = json_create_object(); - logPages = json_create_array(); - json_object_add_value_array(root, "SMART Extended Log:0xE1", logPages); - } - else { - printf("SMART Extended Log:0xE1\n"); - } - - print_micron_vs_logs(buf, e1_log_page, field_count, stats, 0); - - if (is_json) { - json_array_add_value_object(logPages, stats); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } + struct json_object *root; + struct json_object *logPages; + struct json_object *stats = NULL; + int field_count = ARRAY_SIZE(e1_log_page); + + if (is_json) { + root = json_create_object(); + stats = json_create_object(); + logPages = json_create_array(); + json_object_add_value_array(root, "SMART Extended Log:0xE1", logPages); + } else { + printf("SMART Extended Log:0xE1\n"); + } + + print_micron_vs_logs(buf, e1_log_page, field_count, stats, 0); + + if (is_json) { + json_array_add_value_object(logPages, stats); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } } static int micron_smart_ext_log(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve extended SMART logs for the given device "; - unsigned int extSmartLog[E1_log_size/sizeof(int)] = { 0 }; - eDriveModel eModel = UNKNOWN_MODEL; - int err = 0, ctrlIdx = 0; - struct nvme_dev *dev; - bool is_json = true; - struct format { - char *fmt; - }; - const char *fmt = "output format json|normal"; - struct format cfg = { - .fmt = "json", - }; - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) { - printf("\nDevice not found \n");; - return -1; - } - if (strcmp(cfg.fmt, "normal") == 0) - is_json = false; - - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - if ((eModel = GetDriveModel(ctrlIdx)) != M51CX) { - printf ("Unsupported drive model for vs-smart-ext-log command\n"); - err = -1; - goto out; - } - err = nvme_get_log_simple(dev_fd(dev), 0xE1, E1_log_size, extSmartLog); - if (!err) { - print_ext_smart_logs_e1((__u8 *)extSmartLog, is_json); - } + const char *desc = "Retrieve extended SMART logs for the given device "; + unsigned int extSmartLog[E1_log_size/sizeof(int)] = { 0 }; + enum eDriveModel eModel = UNKNOWN_MODEL; + int err = 0, ctrlIdx; + struct nvme_dev *dev; + bool is_json = true; + struct format { + char *fmt; + }; + const char *fmt = "output format json|normal"; + struct format cfg = { + .fmt = "json", + }; + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) { + printf("\nDevice not found\n"); + return -1; + } + if (!strcmp(cfg.fmt, "normal")) + is_json = false; + + if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1) + ctrlIdx = 0; + eModel = GetDriveModel(ctrlIdx); + if (eModel != M51CX) { + printf("Unsupported drive model for vs-smart-ext-log command\n"); + err = -1; + goto out; + } + err = nvme_get_log_simple(dev_fd(dev), 0xE1, E1_log_size, extSmartLog); + if (!err) + print_ext_smart_logs_e1((__u8 *)extSmartLog, is_json); out: - dev_close(dev); - if (err > 0) - nvme_show_status(err); - return err; + dev_close(dev); + if (err > 0) + nvme_show_status(err); + return err; } static void GetDriveInfo(const char *strOSDirName, int nFD, - struct nvme_id_ctrl *ctrlp) + struct nvme_id_ctrl *ctrlp) { - FILE *fpOutFile = NULL; - char tempFile[256] = { 0 }; - char strBuffer[1024] = { 0 }; - char model[41] = { 0 }; - char serial[21] = { 0 }; - char fwrev[9] = { 0 }; - char *strPDir = strdup(strOSDirName); - char *strDest = dirname(strPDir); - - sprintf(tempFile, "%s/%s", strDest, "drive-info.txt"); - fpOutFile = fopen(tempFile, "w+"); - if (!fpOutFile) { - printf("Failed to create %s\n", tempFile); - free(strPDir); - return; - } - - strncpy(model, ctrlp->mn, 40); - strncpy(serial, ctrlp->sn, 20); - strncpy(fwrev, ctrlp->fr, 8); - - sprintf(strBuffer, - "********************\nDrive Info\n********************\n"); - - fprintf(fpOutFile, "%s", strBuffer); - sprintf(strBuffer, - "%-20s : /dev/nvme%d\n%-20s : %s\n%-20s : %-20s\n%-20s : %-20s\n", - "Device Name", nFD, - "Model No", (char *)model, - "Serial No", (char *)serial, "FW-Rev", (char *)fwrev); - - fprintf(fpOutFile, "%s", strBuffer); - - sprintf(strBuffer, - "\n********************\nPCI Info\n********************\n"); - - fprintf(fpOutFile, "%s", strBuffer); - - sprintf(strBuffer, - "%-22s : %04X\n%-22s : %04X\n", - "VendorId", vendor_id, "DeviceId", device_id); - fprintf(fpOutFile, "%s", strBuffer); - fclose(fpOutFile); - free(strPDir); + FILE *fpOutFile = NULL; + char tempFile[256] = { 0 }; + char strBuffer[1024] = { 0 }; + char model[41] = { 0 }; + char serial[21] = { 0 }; + char fwrev[9] = { 0 }; + char *strPDir = strdup(strOSDirName); + char *strDest = dirname(strPDir); + + sprintf(tempFile, "%s/%s", strDest, "drive-info.txt"); + fpOutFile = fopen(tempFile, "w+"); + if (!fpOutFile) { + printf("Failed to create %s\n", tempFile); + free(strPDir); + return; + } + + strncpy(model, ctrlp->mn, 40); + strncpy(serial, ctrlp->sn, 20); + strncpy(fwrev, ctrlp->fr, 8); + + sprintf(strBuffer, + "********************\nDrive Info\n********************\n"); + + fprintf(fpOutFile, "%s", strBuffer); + sprintf(strBuffer, + "%-20s : /dev/nvme%d\n%-20s : %s\n%-20s : %-20s\n%-20s : %-20s\n", + "Device Name", nFD, + "Model No", (char *)model, + "Serial No", (char *)serial, "FW-Rev", (char *)fwrev); + + fprintf(fpOutFile, "%s", strBuffer); + + sprintf(strBuffer, + "\n********************\nPCI Info\n********************\n"); + + fprintf(fpOutFile, "%s", strBuffer); + + sprintf(strBuffer, + "%-22s : %04X\n%-22s : %04X\n", + "VendorId", vendor_id, "DeviceId", device_id); + fprintf(fpOutFile, "%s", strBuffer); + fclose(fpOutFile); + free(strPDir); } static void GetTimestampInfo(const char *strOSDirName) { - __u8 outstr[1024]; - time_t t; - struct tm *tmp; - size_t num; - char *strPDir; - char *strDest; - - t = time(NULL); - tmp = localtime(&t); - if (tmp == NULL) - return; - - num = strftime((char *)outstr, sizeof(outstr), - "Timestamp (UTC): %a, %d %b %Y %T %z", tmp); - num += sprintf((char *)(outstr + num), "\nPackage Version: 1.4"); - if (num) { - strPDir = strdup(strOSDirName); - strDest = dirname(strPDir); - WriteData(outstr, num, strDest, "timestamp_info.txt", "timestamp"); - free(strPDir); - } + __u8 outstr[1024]; + time_t t; + struct tm *tmp; + size_t num; + char *strPDir; + char *strDest; + + t = time(NULL); + tmp = localtime(&t); + if (!tmp) + return; + + num = strftime((char *)outstr, sizeof(outstr), + "Timestamp (UTC): %a, %d %b %Y %T %z", tmp); + num += sprintf((char *)(outstr + num), "\nPackage Version: 1.4"); + if (num) { + strPDir = strdup(strOSDirName); + strDest = dirname(strPDir); + WriteData(outstr, num, strDest, "timestamp_info.txt", "timestamp"); + free(strPDir); + } } static void GetCtrlIDDInfo(const char *dir, struct nvme_id_ctrl *ctrlp) { - WriteData((__u8*)ctrlp, sizeof(*ctrlp), dir, - "nvme_controller_identify_data.bin", "id-ctrl"); + WriteData((__u8 *)ctrlp, sizeof(*ctrlp), dir, + "nvme_controller_identify_data.bin", "id-ctrl"); } static void GetSmartlogData(int fd, const char *dir) { - struct nvme_smart_log smart_log; - if (nvme_get_log_smart(fd, -1, false, &smart_log) == 0) { - WriteData((__u8*)&smart_log, sizeof(smart_log), dir, - "smart_data.bin", "smart log"); - } + struct nvme_smart_log smart_log; + + if (!nvme_get_log_smart(fd, -1, false, &smart_log)) + WriteData((__u8 *)&smart_log, sizeof(smart_log), dir, + "smart_data.bin", "smart log"); } static void GetErrorlogData(int fd, int entries, const char *dir) { - int logSize = entries * sizeof(struct nvme_error_log_page); - struct nvme_error_log_page *error_log = - (struct nvme_error_log_page *)calloc(1, logSize); + 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 (!error_log) + return; - if (nvme_get_log_error(fd, entries, false, error_log) == 0) { - WriteData((__u8*)error_log, logSize, dir, - "error_information_log.bin", "error log"); - } + if (!nvme_get_log_error(fd, entries, false, error_log)) + WriteData((__u8 *)error_log, logSize, dir, + "error_information_log.bin", "error log"); - free(error_log); + free(error_log); } static void GetGenericLogs(int fd, const char *dir) { - struct nvme_self_test_log self_test_log; - struct nvme_firmware_slot fw_log; - struct nvme_cmd_effects_log effects; - struct nvme_persistent_event_log pevent_log; - void *pevent_log_info = NULL; - __u32 log_len = 0; - int err = 0 ; - bool huge = false; - - /* get self test log */ - if (nvme_get_log_device_self_test(fd, &self_test_log) == 0) { - WriteData((__u8*)&self_test_log, sizeof(self_test_log), dir, - "drive_self_test.bin", "self test log"); - } - - /* get fw slot info log */ - if (nvme_get_log_fw_slot(fd, false, &fw_log) == 0) { - WriteData((__u8*)&fw_log, sizeof(fw_log), dir, - "firmware_slot_info_log.bin", "firmware log"); - } - - /* get effects log */ - if (nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &effects) == 0) { - WriteData((__u8*)&effects, sizeof(effects), dir, - "command_effects_log.bin", "effects log"); - } - - /* get persistent event log */ - (void)nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_RELEASE_CTX, - sizeof(pevent_log), &pevent_log); - memset(&pevent_log, 0, sizeof(pevent_log)); - err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ, - sizeof(pevent_log), &pevent_log); - if (err) { - fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n"); - return; - } - - log_len = le64_to_cpu(pevent_log.tll); - pevent_log_info = nvme_alloc(log_len, &huge); - if (!pevent_log_info) { - perror("could not alloc buffer for persistent event log page (ignored)!\n"); - return; - } - err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_READ, - log_len, pevent_log_info); - if (err == 0) { - WriteData((__u8*)pevent_log_info, log_len, dir, - "persistent_event_log.bin", "persistent event log"); - } - nvme_free(pevent_log_info, huge); - return; + struct nvme_self_test_log self_test_log; + struct nvme_firmware_slot fw_log; + struct nvme_cmd_effects_log effects; + struct nvme_persistent_event_log pevent_log; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + void *pevent_log_info = NULL; + __u32 log_len = 0; + int err = 0; + + /* get self test log */ + if (!nvme_get_log_device_self_test(fd, &self_test_log)) + WriteData((__u8 *)&self_test_log, sizeof(self_test_log), dir, + "drive_self_test.bin", "self test log"); + + /* get fw slot info log */ + if (!nvme_get_log_fw_slot(fd, false, &fw_log)) + WriteData((__u8 *)&fw_log, sizeof(fw_log), dir, + "firmware_slot_info_log.bin", "firmware log"); + + /* get effects log */ + if (!nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &effects)) + WriteData((__u8 *)&effects, sizeof(effects), dir, + "command_effects_log.bin", "effects log"); + + /* get persistent event log */ + (void)nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_RELEASE_CTX, + sizeof(pevent_log), &pevent_log); + memset(&pevent_log, 0, sizeof(pevent_log)); + err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ, + sizeof(pevent_log), &pevent_log); + if (err) { + fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n"); + return; + } + + log_len = le64_to_cpu(pevent_log.tll); + pevent_log_info = nvme_alloc_huge(log_len, &mh); + if (!pevent_log_info) { + perror("could not alloc buffer for persistent event log page (ignored)!\n"); + return; + } + + err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_READ, + log_len, pevent_log_info); + if (!err) + WriteData((__u8 *)pevent_log_info, log_len, dir, + "persistent_event_log.bin", "persistent event log"); } static void GetNSIDDInfo(int fd, const char *dir, int nsid) { - char file[PATH_MAX] = { 0 }; - struct nvme_id_ns ns; + char file[PATH_MAX] = { 0 }; + struct nvme_id_ns ns; - if (nvme_identify_ns(fd, nsid, &ns) == 0) { - sprintf(file, "identify_namespace_%d_data.bin", nsid); - WriteData((__u8*)&ns, sizeof(ns), dir, file, "id-ns"); - } + if (!nvme_identify_ns(fd, nsid, &ns)) { + sprintf(file, "identify_namespace_%d_data.bin", nsid); + WriteData((__u8 *)&ns, sizeof(ns), dir, file, "id-ns"); + } } static void GetOSConfig(const char *strOSDirName) { - FILE *fpOSConfig = NULL; - char strBuffer[1024]; - char strFileName[PATH_MAX]; - int i; - - struct { - char *strcmdHeader; - char *strCommand; - } cmdArray[] = { - { (char *)"SYSTEM INFORMATION", (char *)"uname -a >> %s" }, - { (char *)"LINUX KERNEL MODULE INFORMATION", (char *)"lsmod >> %s" }, - { (char *)"LINUX SYSTEM MEMORY INFORMATION", (char *)"cat /proc/meminfo >> %s" }, - { (char *)"SYSTEM INTERRUPT INFORMATION", (char *)"cat /proc/interrupts >> %s" }, - { (char *)"CPU INFORMATION", (char *)"cat /proc/cpuinfo >> %s" }, - { (char *)"IO MEMORY MAP INFORMATION", (char *)"cat /proc/iomem >> %s" }, - { (char *)"MAJOR NUMBER AND DEVICE GROUP", (char *)"cat /proc/devices >> %s" }, - { (char *)"KERNEL DMESG", (char *)"dmesg >> %s" }, - { (char *)"/VAR/LOG/MESSAGES", (char *)"cat /var/log/messages >> %s" } - }; - - sprintf(strFileName, "%s/%s", strOSDirName, "os_config.txt"); - - for (i = 0; i < 7; i++) { - fpOSConfig = fopen(strFileName, "a+"); - if (NULL != fpOSConfig) { - fprintf(fpOSConfig, - "\n\n\n\n%s\n-----------------------------------------------\n", - cmdArray[i].strcmdHeader); - fclose(fpOSConfig); - fpOSConfig = NULL; - } - snprintf(strBuffer, sizeof(strBuffer) - 1, - cmdArray[i].strCommand, strFileName); - if (system(strBuffer)) - fprintf(stderr, "Failed to send \"%s\"\n", strBuffer); - } + FILE *fpOSConfig = NULL; + char strBuffer[1024]; + char strFileName[PATH_MAX]; + int i; + + struct { + char *strcmdHeader; + char *strCommand; + } cmdArray[] = { + { (char *)"SYSTEM INFORMATION", (char *)"uname -a >> %s" }, + { (char *)"LINUX KERNEL MODULE INFORMATION", (char *)"lsmod >> %s" }, + { (char *)"LINUX SYSTEM MEMORY INFORMATION", (char *)"cat /proc/meminfo >> %s" }, + { (char *)"SYSTEM INTERRUPT INFORMATION", (char *)"cat /proc/interrupts >> %s" }, + { (char *)"CPU INFORMATION", (char *)"cat /proc/cpuinfo >> %s" }, + { (char *)"IO MEMORY MAP INFORMATION", (char *)"cat /proc/iomem >> %s" }, + { (char *)"MAJOR NUMBER AND DEVICE GROUP", (char *)"cat /proc/devices >> %s" }, + { (char *)"KERNEL DMESG", (char *)"dmesg >> %s" }, + { (char *)"/VAR/LOG/MESSAGES", (char *)"cat /var/log/messages >> %s" } + }; + + sprintf(strFileName, "%s/%s", strOSDirName, "os_config.txt"); + + for (i = 0; i < 7; i++) { + fpOSConfig = fopen(strFileName, "a+"); + if (fpOSConfig) { + fprintf(fpOSConfig, + "\n\n\n\n%s\n-----------------------------------------------\n", + cmdArray[i].strcmdHeader); + fclose(fpOSConfig); + fpOSConfig = NULL; + } + snprintf(strBuffer, sizeof(strBuffer) - 1, + cmdArray[i].strCommand, strFileName); + if (system(strBuffer)) + fprintf(stderr, "Failed to send \"%s\"\n", strBuffer); + } } static int micron_telemetry_log(int fd, __u8 type, __u8 **data, - int *logSize, int da) + int *logSize, int da) { - int err, bs = 512, offset = bs; - unsigned short data_area[4]; - unsigned char ctrl_init = (type == 0x8); - - __u8 *buffer = (unsigned char *)calloc(bs, 1); - if (buffer == NULL) - return -1; - if (ctrl_init) - err = nvme_get_log_telemetry_ctrl(fd, true, 0, bs, buffer); - else - err = nvme_get_log_telemetry_host(fd, 0, bs, buffer); - if (err != 0) { - fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type); - if (buffer != NULL) { - free(buffer); - } - return err; - } - - /* compute size of the log */ - data_area[1] = buffer[9] << 8 | buffer[8]; - data_area[2] = buffer[11] << 8 | buffer[10]; - data_area[3] = buffer[13] << 8 | buffer[12]; - data_area[0] = data_area[1] > data_area[2] ? data_area[1] : data_area[2]; - data_area[0] = data_area[3] > data_area[0] ? data_area[3] : data_area[0]; - - if (data_area[da] == 0) { - fprintf(stderr, "Requested telemetry data for 0x%X is empty\n", type); - if (buffer != NULL) { - free(buffer); - buffer = NULL; - } - return -1; - } - - *logSize = data_area[da] * bs; - offset = bs; - err = 0; - if ((buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize))) != NULL) { - while (err == 0 && offset != *logSize) { - if (ctrl_init) - err = nvme_get_log_telemetry_ctrl(fd, true, 0, *logSize, buffer + offset); - else - err = nvme_get_log_telemetry_host(fd, 0, *logSize, buffer + offset); - offset += bs; - } - } - - if (err == 0 && buffer != NULL) { - *data = buffer; - } else { - fprintf(stderr, "Failed to get telemetry data for 0x%x\n", type); - if (buffer != NULL) - free(buffer); - } - - return err; + int err, bs = 512, offset = bs; + unsigned short data_area[4]; + unsigned char ctrl_init = (type == 0x8); + + __u8 *buffer = (unsigned char *)calloc(bs, 1); + + if (!buffer) + return -1; + if (ctrl_init) + err = nvme_get_log_telemetry_ctrl(fd, true, 0, bs, buffer); + else + err = nvme_get_log_telemetry_host(fd, 0, bs, buffer); + if (err) { + fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type); + if (buffer) + free(buffer); + return err; + } + + /* compute size of the log */ + data_area[1] = buffer[9] << 8 | buffer[8]; + data_area[2] = buffer[11] << 8 | buffer[10]; + data_area[3] = buffer[13] << 8 | buffer[12]; + data_area[0] = data_area[1] > data_area[2] ? data_area[1] : data_area[2]; + data_area[0] = data_area[3] > data_area[0] ? data_area[3] : data_area[0]; + + if (!data_area[da]) { + fprintf(stderr, "Requested telemetry data for 0x%X is empty\n", type); + if (buffer) { + free(buffer); + buffer = NULL; + } + return -1; + } + + *logSize = data_area[da] * bs; + offset = bs; + err = 0; + buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize)); + if (buffer) { + while (!err && offset != *logSize) { + if (ctrl_init) + err = nvme_get_log_telemetry_ctrl(fd, true, 0, *logSize, buffer + offset); + else + err = nvme_get_log_telemetry_host(fd, 0, *logSize, buffer + offset); + offset += bs; + } + } + + if (!err && buffer) { + *data = buffer; + } else { + fprintf(stderr, "Failed to get telemetry data for 0x%x\n", type); + if (buffer) + free(buffer); + } + + return err; } static int GetTelemetryData(int fd, const char *dir) { - unsigned char *buffer = NULL; - int i, err, logSize = 0; - char msg[256] = {0}; - struct { - __u8 log; - char *file; - } tmap[] = { - {0x07, "nvmetelemetrylog.bin"}, - {0x08, "nvmetelemetrylog.bin"}, - }; - - for(i = 0; i < (int)(sizeof(tmap)/sizeof(tmap[0])); i++) { - err = micron_telemetry_log(fd, tmap[i].log, &buffer, &logSize, 0); - if (err == 0 && logSize > 0 && buffer != NULL) { - sprintf(msg, "telemetry log: 0x%X", tmap[i].log); - WriteData(buffer, logSize, dir, tmap[i].file, msg); - } - if (buffer) { - free(buffer); - buffer = NULL; - } - logSize = 0; - } - return err; + unsigned char *buffer = NULL; + int i, err, logSize = 0; + char msg[256] = { 0 }; + struct { + __u8 log; + char *file; + } tmap[] = { + {0x07, "nvmetelemetrylog.bin"}, + {0x08, "nvmetelemetrylog.bin"}, + }; + + for (i = 0; i < (int)(ARRAY_SIZE(tmap)); i++) { + err = micron_telemetry_log(fd, tmap[i].log, &buffer, &logSize, 0); + if (!err && logSize > 0 && buffer) { + sprintf(msg, "telemetry log: 0x%X", tmap[i].log); + WriteData(buffer, logSize, dir, tmap[i].file, msg); + } + if (buffer) { + free(buffer); + buffer = NULL; + } + logSize = 0; + } + return err; } static int GetFeatureSettings(int fd, const char *dir) { - unsigned char *bufp, buf[4096] = { 0 }; - int i, err, len, errcnt = 0; - __u32 attrVal = 0; - char msg[256] = { 0 }; - - struct features { - int id; - char *file; - } fmap[] = { - {0x01, "nvme_feature_setting_arbitration.bin"}, - {0x02, "nvme_feature_setting_pm.bin"}, - {0x03, "nvme_feature_setting_lba_range_namespace_1.bin"}, - {0x04, "nvme_feature_setting_temp_threshold.bin"}, - {0x05, "nvme_feature_setting_error_recovery.bin"}, - {0x06, "nvme_feature_setting_volatile_write_cache.bin"}, - {0x07, "nvme_feature_setting_num_queues.bin"}, - {0x08, "nvme_feature_setting_interrupt_coalescing.bin"}, - {0x09, "nvme_feature_setting_interrupt_vec_config.bin"}, - {0x0A, "nvme_feature_setting_write_atomicity.bin"}, - {0x0B, "nvme_feature_setting_async_event_config.bin"}, - {0x80, "nvme_feature_setting_sw_progress_marker.bin"}, - }; - - for (i = 0; i < (int)(sizeof(fmap)/sizeof(fmap[0])); i++) { - if (fmap[i].id == 0x03) { - len = 4096; - bufp = (unsigned char *)(&buf[0]); - } else { - len = 0; - bufp = NULL; - } + unsigned char *bufp, buf[4096] = { 0 }; + int i, err, len, errcnt = 0; + __u32 attrVal = 0; + char msg[256] = { 0 }; + + struct features { + int id; + char *file; + } fmap[] = { + {0x01, "nvme_feature_setting_arbitration.bin"}, + {0x02, "nvme_feature_setting_pm.bin"}, + {0x03, "nvme_feature_setting_lba_range_namespace_1.bin"}, + {0x04, "nvme_feature_setting_temp_threshold.bin"}, + {0x05, "nvme_feature_setting_error_recovery.bin"}, + {0x06, "nvme_feature_setting_volatile_write_cache.bin"}, + {0x07, "nvme_feature_setting_num_queues.bin"}, + {0x08, "nvme_feature_setting_interrupt_coalescing.bin"}, + {0x09, "nvme_feature_setting_interrupt_vec_config.bin"}, + {0x0A, "nvme_feature_setting_write_atomicity.bin"}, + {0x0B, "nvme_feature_setting_async_event_config.bin"}, + {0x80, "nvme_feature_setting_sw_progress_marker.bin"}, + }; + + for (i = 0; i < (int)(ARRAY_SIZE(fmap)); i++) { + if (fmap[i].id == 0x03) { + len = 4096; + bufp = (unsigned char *)(&buf[0]); + } else { + len = 0; + bufp = NULL; + } struct nvme_get_features_args args = { .args_size = sizeof(args), @@ -1995,901 +1990,882 @@ static int GetFeatureSettings(int fd, const char *dir) .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = &attrVal, }; - err = nvme_get_features(&args); - if (err == 0) { - sprintf(msg, "feature: 0x%X", fmap[i].id); - WriteData((__u8*)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg); - if (bufp != NULL) { - WriteData(bufp, len, dir, fmap[i].file, msg); - } - } else { - fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n", - fmap[i].id, err); - errcnt++; - } - } - return (int)(errcnt == sizeof(fmap)/sizeof(fmap[0])); + err = nvme_get_features(&args); + if (!err) { + sprintf(msg, "feature: 0x%X", fmap[i].id); + WriteData((__u8 *)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg); + if (bufp) + WriteData(bufp, len, dir, fmap[i].file, msg); + } else { + fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n", + fmap[i].id, err); + errcnt++; + } + } + return (int)(errcnt == ARRAY_SIZE(fmap)); } static int micron_drive_info(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - const char *desc = "Get drive HW information"; - struct nvme_id_ctrl ctrl = { 0 }; - struct nvme_passthru_cmd admin_cmd = { 0 }; - struct fb_drive_info { - unsigned char hw_ver_major; - unsigned char hw_ver_minor; - unsigned char ftl_unit_size; - unsigned char bs_ver_major; - unsigned char bs_ver_minor; - } dinfo = { 0 }; - eDriveModel model = UNKNOWN_MODEL; - bool is_json = false; - struct json_object *root, *driveInfo; - struct nvme_dev *dev; - struct format { - char *fmt; - }; - int err = 0; - - const char *fmt = "output format normal"; - struct format cfg = { - .fmt = "normal", - }; - - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return err; - - if (model == UNKNOWN_MODEL) { - fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd"); - dev_close(dev); - return -1; - } - - if (strcmp(cfg.fmt, "json") == 0) - is_json = true; - - if (model == M5407) { - admin_cmd.opcode = 0xD4, - admin_cmd.addr = (__u64) (uintptr_t) &dinfo; - admin_cmd.data_len = (__u32)sizeof(dinfo); - admin_cmd.cdw12 = 3; - err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); - if (err) { - fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err); - dev_close(dev); - return -1; - } - } else { - err = nvme_identify_ctrl(dev_fd(dev), &ctrl); - if (err) { - fprintf(stderr, "ERROR : identify_ctrl() failed with 0x%x\n", err); - dev_close(dev); - return -1; - } - dinfo.hw_ver_major = ctrl.vs[820]; - dinfo.hw_ver_minor = ctrl.vs[821]; - dinfo.ftl_unit_size = ctrl.vs[822]; - } - - if (is_json) { - struct json_object *pinfo = json_create_object(); - char tempstr[64] = { 0 }; - root = json_create_object(); - driveInfo = json_create_array(); - json_object_add_value_array(root, "Micron Drive HW Information", driveInfo); - sprintf(tempstr, "%hhu.%hhu", dinfo.hw_ver_major, dinfo.hw_ver_minor); - json_object_add_value_string(pinfo, "Drive Hardware Version", tempstr); - - if (dinfo.ftl_unit_size) { - sprintf(tempstr, "%hhu KB", dinfo.ftl_unit_size); - json_object_add_value_string(pinfo, "FTL_unit_size", tempstr); - } - - if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) { - sprintf(tempstr, "%hhu.%hhu", dinfo.bs_ver_major, dinfo.bs_ver_minor); - json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr); - } - - json_array_add_value_object(driveInfo, pinfo); - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); - } else { - printf("Drive Hardware Version: %hhu.%hhu\n", - dinfo.hw_ver_major, dinfo.hw_ver_minor); - - if (dinfo.ftl_unit_size) - printf("FTL_unit_size: %hhu KB\n", dinfo.ftl_unit_size); - - if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) { - printf("Boot Spec.Version: %hhu.%hhu\n", - dinfo.bs_ver_major, dinfo.bs_ver_minor); - } - } - - dev_close(dev); - return 0; + const char *desc = "Get drive HW information"; + struct nvme_id_ctrl ctrl = { 0 }; + struct nvme_passthru_cmd admin_cmd = { 0 }; + struct fb_drive_info { + unsigned char hw_ver_major; + unsigned char hw_ver_minor; + unsigned char ftl_unit_size; + unsigned char bs_ver_major; + unsigned char bs_ver_minor; + } dinfo = { 0 }; + enum eDriveModel model = UNKNOWN_MODEL; + bool is_json = false; + struct json_object *root, *driveInfo; + struct nvme_dev *dev; + struct format { + char *fmt; + }; + int err = 0; + + const char *fmt = "output format normal"; + struct format cfg = { + .fmt = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return err; + + if (model == UNKNOWN_MODEL) { + fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd"); + dev_close(dev); + return -1; + } + + if (!strcmp(cfg.fmt, "json")) + is_json = true; + + if (model == M5407) { + admin_cmd.opcode = 0xD4, + admin_cmd.addr = (__u64) (uintptr_t) &dinfo; + admin_cmd.data_len = (__u32)sizeof(dinfo); + admin_cmd.cdw12 = 3; + err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); + if (err) { + fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err); + dev_close(dev); + return -1; + } + } else { + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) { + fprintf(stderr, "ERROR : identify_ctrl() failed with 0x%x\n", err); + dev_close(dev); + return -1; + } + dinfo.hw_ver_major = ctrl.vs[820]; + dinfo.hw_ver_minor = ctrl.vs[821]; + dinfo.ftl_unit_size = ctrl.vs[822]; + } + + if (is_json) { + struct json_object *pinfo = json_create_object(); + char tempstr[64] = { 0 }; + + root = json_create_object(); + driveInfo = json_create_array(); + json_object_add_value_array(root, "Micron Drive HW Information", driveInfo); + sprintf(tempstr, "%u.%u", dinfo.hw_ver_major, dinfo.hw_ver_minor); + json_object_add_value_string(pinfo, "Drive Hardware Version", tempstr); + + if (dinfo.ftl_unit_size) { + sprintf(tempstr, "%u KB", dinfo.ftl_unit_size); + json_object_add_value_string(pinfo, "FTL_unit_size", tempstr); + } + + if (dinfo.bs_ver_major || dinfo.bs_ver_minor) { + sprintf(tempstr, "%u.%u", dinfo.bs_ver_major, dinfo.bs_ver_minor); + json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr); + } + + json_array_add_value_object(driveInfo, pinfo); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + printf("Drive Hardware Version: %u.%u\n", + dinfo.hw_ver_major, dinfo.hw_ver_minor); + + if (dinfo.ftl_unit_size) + printf("FTL_unit_size: %u KB\n", dinfo.ftl_unit_size); + + if (dinfo.bs_ver_major || dinfo.bs_ver_minor) + printf("Boot Spec.Version: %u.%u\n", + dinfo.bs_ver_major, dinfo.bs_ver_minor); + } + + dev_close(dev); + return 0; } static int micron_cloud_ssd_plugin_version(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - printf("nvme-cli Micron cloud SSD plugin version: %s.%s\n", - __version_major, __version_minor); - return 0; + printf("nvme-cli Micron cloud SSD plugin version: %s.%s\n", + __version_major, __version_minor); + return 0; } static int micron_plugin_version(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - printf("nvme-cli Micron plugin version: %s.%s.%s\n", - __version_major, __version_minor, __version_patch); - return 0; + printf("nvme-cli Micron plugin version: %s.%s.%s\n", + __version_major, __version_minor, __version_patch); + return 0; } /* Binary format of firmware activation history entry */ -struct __attribute__((__packed__)) fw_activation_history_entry { - __u8 version; - __u8 length; - __u16 rsvd1; - __le16 valid; - __le64 power_on_hour; - __le64 rsvd2; - __le64 power_cycle_count; - __u8 previous_fw[8]; - __u8 activated_fw[8]; - __u8 slot; - __u8 commit_action_type; - __le16 result; - __u8 rsvd3[14]; +struct __packed fw_activation_history_entry { + __u8 version; + __u8 length; + __u16 rsvd1; + __le16 valid; + __le64 power_on_hour; + __le64 rsvd2; + __le64 power_cycle_count; + __u8 previous_fw[8]; + __u8 activated_fw[8]; + __u8 slot; + __u8 commit_action_type; + __le16 result; + __u8 rsvd3[14]; }; - /* Binary format for firmware activation history table */ -struct __attribute__((__packed__)) micron_fw_activation_history_table { - __u8 log_page; - __u8 rsvd1[3]; - __le32 num_entries; - struct fw_activation_history_entry entries[20]; - __u8 rsvd2[2790]; - __u16 version; - __u8 GUID[16]; +struct __packed micron_fw_activation_history_table { + __u8 log_page; + __u8 rsvd1[3]; + __le32 num_entries; + struct fw_activation_history_entry entries[20]; + __u8 rsvd2[2790]; + __u16 version; + __u8 GUID[16]; }; -/* header to be printed field widths = 10 | 12 | 10 | 11 | 12 | 9 | 9 | 9 */ - -const char *fw_activation_history_table_header = "\ -__________________________________________________________________________________\n\ - | | | | | | | \n\ -Firmware | Power On | Power | Previous | New FW | Slot | Commit | Result \n\ -Activation| Hour | cycle | firmware | activated | number | Action | \n\ -Counter | | count | | | | Type | \n\ -__________|___________|_________|__________|___________|________|________|________\n"; - -static int display_fw_activate_entry ( - int entry_count, - struct fw_activation_history_entry *entry, - char *formatted_entry, - struct json_object *stats -) +static int display_fw_activate_entry(int entry_count, struct fw_activation_history_entry *entry, + char *formatted_entry, struct json_object *stats) { - time_t timestamp, hours; - char buffer[32]; - __u8 minutes, seconds; - char *ca[] = {"000b", "001b", "010b", "011b"}; - char *ptr = formatted_entry; - int index = 0, entry_size = 82; - - if ((entry->version != 1 && entry->version != 2) || entry->length != 64) { - /*fprintf(stderr, "unsupported entry ! version: %x with length: %d\n", - entry->version, entry->length); */ - return -EINVAL; - } - - sprintf(ptr, "%d", entry_count); - ptr += 10; - - timestamp = (le64_to_cpu(entry->power_on_hour) & 0x0000FFFFFFFFFFFFUL) / 1000; - hours = timestamp / 3600; - minutes = (timestamp % 3600) / 60; - seconds = (timestamp % 3600) % 60; - sprintf(ptr, "|%"PRIu64":%hhu:%hhu", (uint64_t)hours, minutes, seconds); - ptr += 12; - - sprintf(ptr, "| %"PRIu64, le64_to_cpu(entry->power_cycle_count)); - ptr += 10; - - /* firmware details */ - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, entry->previous_fw, sizeof(entry->previous_fw)); - sprintf(ptr, "| %s", buffer); - ptr += 11; - - memset(buffer, 0, sizeof(buffer)); - memcpy(buffer, entry->activated_fw, sizeof(entry->activated_fw)); - sprintf(ptr, "| %s", buffer); - ptr += 12; - - /* firmware slot and commit action*/ - sprintf(ptr, "| %d", entry->slot); - ptr += 9; - - if (entry->commit_action_type <= 3) - sprintf(ptr, "| %s", ca[entry->commit_action_type]); - else - sprintf(ptr, "| xxxb"); - ptr += 9; - - /* result */ - if (entry->result) { - sprintf(ptr, "| Fail #%d", entry->result); - } else { - sprintf(ptr, "| pass"); - } - - /* replace all null charecters with spaces */ - ptr = formatted_entry; - while (index < entry_size) { - if (ptr[index] == '\0') - ptr[index] = ' '; - index++; - } - return 0; + time_t timestamp, hours; + char buffer[32]; + __u8 minutes, seconds; + static const char * const ca[] = {"000b", "001b", "010b", "011b"}; + char *ptr = formatted_entry; + int index = 0, entry_size = 82; + + if ((entry->version != 1 && entry->version != 2) || entry->length != 64) + return -EINVAL; + + sprintf(ptr, "%d", entry_count); + ptr += 10; + + timestamp = (le64_to_cpu(entry->power_on_hour) & 0x0000FFFFFFFFFFFFUL) / 1000; + hours = timestamp / 3600; + minutes = (timestamp % 3600) / 60; + seconds = (timestamp % 3600) % 60; + sprintf(ptr, "|%"PRIu64":%u:%u", (uint64_t)hours, minutes, seconds); + ptr += 12; + + sprintf(ptr, "| %"PRIu64, le64_to_cpu(entry->power_cycle_count)); + ptr += 10; + + /* firmware details */ + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, entry->previous_fw, sizeof(entry->previous_fw)); + sprintf(ptr, "| %s", buffer); + ptr += 11; + + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, entry->activated_fw, sizeof(entry->activated_fw)); + sprintf(ptr, "| %s", buffer); + ptr += 12; + + /* firmware slot and commit action*/ + sprintf(ptr, "| %d", entry->slot); + ptr += 9; + + if (entry->commit_action_type <= 3) + sprintf(ptr, "| %s", ca[entry->commit_action_type]); + else + sprintf(ptr, "| xxxb"); + ptr += 9; + + /* result */ + if (entry->result) + sprintf(ptr, "| Fail #%d", entry->result); + else + sprintf(ptr, "| pass"); + + /* replace all null characters with spaces */ + ptr = formatted_entry; + while (index < entry_size) { + if (ptr[index] == '\0') + ptr[index] = ' '; + index++; + } + return 0; } +static void micron_fw_activation_history_header_print(void) +{ + /* header to be printed field widths = 10 | 12 | 10 | 11 | 12 | 9 | 9 | 9 */ + printf("__________________________________________________________________________________\n"); + printf(" | | | | | | |\n"); + printf("Firmware | Power On | Power | Previous | New FW | Slot | Commit | Result\n"); + printf("Activation| Hour | cycle | firmware | activated | number | Action |\n"); + printf("Counter | | count | | | | Type |\n"); + printf("__________|___________|_________|__________|___________|________|________|________\n"); +} static int micron_fw_activation_history(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - const char *desc = "Retrieve Firmware Activation history of the given drive"; - char formatted_output[100]; - int count = 0; - unsigned int logC2[C2_log_size/sizeof(int)] = { 0 }; - eDriveModel eModel = UNKNOWN_MODEL; - struct nvme_dev *dev; - struct format { - char *fmt; - }; - int err; - - const char *fmt = "output format normal"; - struct format cfg = { - .fmt = "normal", - }; - - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel); - if (err < 0) - return -1; - - if (strcmp(cfg.fmt, "normal") != 0) { - fprintf (stderr, "only normal format is supported currently\n"); - dev_close(dev); - return -1; - } - - /* check if product supports fw_history log */ - err = -EINVAL; - if (eModel != M51CX) { - fprintf(stderr, "Unsupported drive model for vs-fw-activate-history command\n"); - goto out; - } - - err = nvme_get_log_simple(dev_fd(dev), 0xC2, C2_log_size, logC2); - if (err) { - fprintf(stderr, "Failed to retrieve fw activation history log, error: %x\n", err); - goto out; - } - - /* check if we have atleast one entry to print */ - struct micron_fw_activation_history_table *table = - (struct micron_fw_activation_history_table *)logC2; - - /* check version and log page */ - if (table->log_page != 0xC2 || (table->version != 2 && table->version != 1)) - { - fprintf(stderr, "Unsupported fw activation history page: %x, version: %x\n", - table->log_page, table->version); - goto out; - } - - if (table->num_entries == 0) { - fprintf(stderr, "No entries were found in fw activation history log\n"); - goto out; - } - - printf("%s", fw_activation_history_table_header); - for(count = 0; count < table->num_entries; count++) { - memset(formatted_output, '\0', 100); - if (display_fw_activate_entry(count, - &table->entries[count], - formatted_output, NULL) == 0) - { - printf("%s\n", formatted_output); - } - } + const char *desc = "Retrieve Firmware Activation history of the given drive"; + char formatted_output[100]; + int count = 0; + unsigned int logC2[C2_log_size/sizeof(int)] = { 0 }; + enum eDriveModel eModel = UNKNOWN_MODEL; + struct nvme_dev *dev; + struct format { + char *fmt; + }; + int err; + + const char *fmt = "output format normal"; + struct format cfg = { + .fmt = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel); + if (err < 0) + return -1; + + if (strcmp(cfg.fmt, "normal")) { + fprintf(stderr, "only normal format is supported currently\n"); + dev_close(dev); + return -1; + } + + /* check if product supports fw_history log */ + err = -EINVAL; + if (eModel != M51CX) { + fprintf(stderr, "Unsupported drive model for vs-fw-activate-history command\n"); + goto out; + } + + err = nvme_get_log_simple(dev_fd(dev), 0xC2, C2_log_size, logC2); + if (err) { + fprintf(stderr, "Failed to retrieve fw activation history log, error: %x\n", err); + goto out; + } + + /* check if we have at least one entry to print */ + struct micron_fw_activation_history_table *table = + (struct micron_fw_activation_history_table *)logC2; + + /* check version and log page */ + if (table->log_page != 0xC2 || (table->version != 2 && table->version != 1)) { + fprintf(stderr, "Unsupported fw activation history page: %x, version: %x\n", + table->log_page, table->version); + goto out; + } + + if (!table->num_entries) { + fprintf(stderr, "No entries were found in fw activation history log\n"); + goto out; + } + + micron_fw_activation_history_header_print(); + for (count = 0; count < table->num_entries; count++) { + memset(formatted_output, '\0', 100); + if (!display_fw_activate_entry(count, &table->entries[count], formatted_output, + NULL)) + printf("%s\n", formatted_output); + } out: - dev_close(dev); - return err; + dev_close(dev); + return err; } #define MICRON_FID_LATENCY_MONITOR 0xD0 #define MICRON_LOG_LATENCY_MONITOR 0xD1 static int micron_latency_stats_track(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - int err = 0; - __u32 result = 0; - const char *desc = "Enable, Disable or Get cmd latency monitoring stats"; - const char *option = "enable or disable or status, default is status"; - const char *command = "commands to monitor for - all|read|write|trim," - " default is all i.e, enabled for all commands"; - const char *thrtime = "The threshold value to use for latency monitoring in" - " milliseconds, default is 800ms"; - - int fid = MICRON_FID_LATENCY_MONITOR; - eDriveModel model = UNKNOWN_MODEL; - uint32_t command_mask = 0x7; /* 1:read 2:write 4:trim 7:all */ - uint32_t timing_mask = 0x08080800; /* R[31-24]:W[23:16]:T[15:8]:0 */ - uint32_t enable = 2; - struct nvme_dev *dev; - struct { - char *option; - char *command; - uint32_t threshold; - } opt = { - .option = "status", - .command = "all", - .threshold = 0 - }; - - OPT_ARGS(opts) = { - OPT_STRING("option", 'o', "option", &opt.option, option), - OPT_STRING("command", 'c', "command", &opt.command, command), - OPT_UINT("threshold", 't', &opt.threshold, thrtime), - OPT_END() - }; - - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return -1; - - if (!strcmp(opt.option, "enable")) { - enable = 1; - } else if (!strcmp(opt.option, "disable")) { - enable = 0; - } else if (strcmp(opt.option, "status")) { - printf("Invalid control option %s specified\n", opt.option); - dev_close(dev); - return -1; - } - - struct nvme_get_features_args g_args = { - .args_size = sizeof(g_args), - .fd = dev_fd(dev), - .fid = fid, - .nsid = 0, - .sel = 0, + int err = 0; + __u32 result = 0; + const char *desc = "Enable, Disable or Get cmd latency monitoring stats"; + const char *option = "enable or disable or status, default is status"; + const char *command = + "commands to monitor for - all|read|write|trim, default is all i.e, enabled for all commands"; + const char *thrtime = + "The threshold value to use for latency monitoring in milliseconds, default is 800ms"; + + int fid = MICRON_FID_LATENCY_MONITOR; + enum eDriveModel model = UNKNOWN_MODEL; + uint32_t command_mask = 0x7; /* 1:read 2:write 4:trim 7:all */ + uint32_t timing_mask = 0x08080800; /* R[31-24]:W[23:16]:T[15:8]:0 */ + uint32_t enable = 2; + struct nvme_dev *dev; + struct { + char *option; + char *command; + uint32_t threshold; + } opt = { + .option = "status", + .command = "all", + .threshold = 0 + }; + + OPT_ARGS(opts) = { + OPT_STRING("option", 'o', "option", &opt.option, option), + OPT_STRING("command", 'c', "command", &opt.command, command), + OPT_UINT("threshold", 't', &opt.threshold, thrtime), + OPT_END() + }; + + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return -1; + + if (!strcmp(opt.option, "enable")) { + enable = 1; + } else if (!strcmp(opt.option, "disable")) { + enable = 0; + } else if (strcmp(opt.option, "status")) { + printf("Invalid control option %s specified\n", opt.option); + dev_close(dev); + return -1; + } + + struct nvme_get_features_args g_args = { + .args_size = sizeof(g_args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = 0, + .sel = 0, .cdw11 = 0, .uuidx = 0, .data_len = 0, .data = NULL, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = &result, - }; + }; - err = nvme_get_features(&g_args); - if (err != 0) { - printf("Failed to retrieve latency monitoring feature status\n"); - dev_close(dev); - return err; - } - - /* If it is to retrieve the status only */ - if (enable == 2) { - printf("Latency Tracking Statistics is currently %s", - (result & 0xFFFF0000) ? "enabled" : "disabled"); - if ((result & 7) == 7) { - printf(" for All commands\n"); - } else if ((result & 7) > 0) { - printf(" for"); - if (result & 1) { - printf(" Read"); - } - if (result & 2) { - printf(" Write"); - } - if (result & 4) { - printf(" Trim"); - } - printf(" commands\n"); - } else if (result == 0) { - printf("\n"); - } - dev_close(dev); - return err; - } - - /* read and validate threshold values if enable option is specified */ - if (enable == 1) { - if (opt.threshold > 2550) { - printf("The maximum threshold value cannot be more than 2550 ms\n"); - dev_close(dev); - return -1; - } - /* timing mask is in terms of 10ms units, so min allowed is 10ms */ - else if ((opt.threshold % 10) != 0) { - printf("The threshold value should be multiple of 10 ms\n"); - dev_close(dev); - return -1; - } - opt.threshold /= 10; - } - - /* read-in command(s) to be monitored */ - if (!strcmp(opt.command, "read")) { - command_mask = 0x1; - timing_mask = (opt.threshold << 24); - } else if (!strcmp(opt.command, "write")) { - command_mask = 0x2; - timing_mask = (opt.threshold << 16); - } else if (!strcmp(opt.command, "trim")) { - command_mask = 0x4; - timing_mask = (opt.threshold << 8); - } else if (strcmp(opt.command, "all")) { - printf("Invalid command %s specified for option %s\n", + err = nvme_get_features(&g_args); + if (err) { + printf("Failed to retrieve latency monitoring feature status\n"); + dev_close(dev); + return err; + } + + /* If it is to retrieve the status only */ + if (enable == 2) { + printf("Latency Tracking Statistics is currently %s", + (result & 0xFFFF0000) ? "enabled" : "disabled"); + if ((result & 7) == 7) { + printf(" for All commands\n"); + } else if ((result & 7) > 0) { + printf(" for"); + if (result & 1) + printf(" Read"); + if (result & 2) + printf(" Write"); + if (result & 4) + printf(" Trim"); + printf(" commands\n"); + } else if (!result) { + printf("\n"); + } + dev_close(dev); + return err; + } + + /* read and validate threshold values if enable option is specified */ + if (enable == 1) { + if (opt.threshold > 2550) { + printf("The maximum threshold value cannot be more than 2550 ms\n"); + dev_close(dev); + return -1; + } else if (opt.threshold % 10) { + /* timing mask is in terms of 10ms units, so min allowed is 10ms */ + printf("The threshold value should be multiple of 10 ms\n"); + dev_close(dev); + return -1; + } + opt.threshold /= 10; + } + + /* read-in command(s) to be monitored */ + if (!strcmp(opt.command, "read")) { + command_mask = 0x1; + timing_mask = (opt.threshold << 24); + } else if (!strcmp(opt.command, "write")) { + command_mask = 0x2; + timing_mask = (opt.threshold << 16); + } else if (!strcmp(opt.command, "trim")) { + command_mask = 0x4; + timing_mask = (opt.threshold << 8); + } else if (strcmp(opt.command, "all")) { + printf("Invalid command %s specified for option %s\n", opt.command, opt.option); - dev_close(dev); - return -1; - } - - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = MICRON_FID_LATENCY_MONITOR, - .nsid = 0, - .cdw11 = enable, - .cdw12 = command_mask, - .save = 1, - .uuidx = 0, - .cdw13 = timing_mask, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_set_features(&args); - if (err == 0) { - printf("Successfully %sd latency monitoring for %s commands with %dms threshold\n", - opt.option, opt.command, opt.threshold == 0 ? 800 : opt.threshold * 10); - } else { - printf("Failed to %s latency monitoring for %s commands with %dms threshold\n", - opt.option, opt.command, opt.threshold == 0 ? 800 : opt.threshold * 10); - } - - dev_close(dev); - return err; + dev_close(dev); + return -1; + } + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = MICRON_FID_LATENCY_MONITOR, + .nsid = 0, + .cdw11 = enable, + .cdw12 = command_mask, + .save = 1, + .uuidx = 0, + .cdw13 = timing_mask, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (!err) { + printf("Successfully %sd latency monitoring for %s commands with %dms threshold\n", + opt.option, opt.command, !opt.threshold ? 800 : opt.threshold * 10); + } else { + printf("Failed to %s latency monitoring for %s commands with %dms threshold\n", + opt.option, opt.command, !opt.threshold ? 800 : opt.threshold * 10); + } + + dev_close(dev); + return err; } static int micron_latency_stats_logs(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { #define LATENCY_LOG_ENTRIES 16 - struct latency_log_entry { - uint64_t timestamp; - uint32_t latency; - uint32_t cmdtag; + struct latency_log_entry { + uint64_t timestamp; + uint32_t latency; + uint32_t cmdtag; union { - struct { - uint32_t opcode:8; + struct { + uint32_t opcode:8; uint32_t fuse:2; uint32_t rsvd1:4; uint32_t psdt:2; uint32_t cid:16; - }; - uint32_t dw0; + }; + uint32_t dw0; }; uint32_t nsid; uint32_t slba_low; uint32_t slba_high; union { - struct { - uint32_t nlb:16; - uint32_t rsvd2:9; - uint32_t deac:1; - uint32_t prinfo:4; - uint32_t fua:1; - uint32_t lr:1; - }; - uint32_t dw12; + struct { + uint32_t nlb:16; + uint32_t rsvd2:9; + uint32_t deac:1; + uint32_t prinfo:4; + uint32_t fua:1; + uint32_t lr:1; + }; + uint32_t dw12; + }; + uint32_t dsm; + uint32_t rfu[6]; + } log[LATENCY_LOG_ENTRIES]; + enum eDriveModel model = UNKNOWN_MODEL; + struct nvme_dev *dev; + int err = -1; + const char *desc = "Display Latency tracking log information"; + + OPT_ARGS(opts) = { + OPT_END() }; - uint32_t dsm; - uint32_t rfu[6]; - } log[LATENCY_LOG_ENTRIES]; - eDriveModel model = UNKNOWN_MODEL; - struct nvme_dev *dev; - int err = -1; - const char *desc = "Display Latency tracking log information"; - OPT_ARGS(opts) = { - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err) - return err; - memset(&log, 0, sizeof(log)); - err = nvme_get_log_simple(dev_fd(dev), 0xD1, sizeof(log), &log); - if (err) { - if (err < 0) - printf("Unable to retrieve latency stats log the drive\n"); - dev_close(dev); - return err; - } - /* print header and each log entry */ - printf("Timestamp, Latency, CmdTag, Opcode, Fuse, Psdt,Cid, Nsid," - "Slba_L, Slba_H, Nlb, DEAC, PRINFO, FUA,LR\n"); - for (int i = 0; i < LATENCY_LOG_ENTRIES; i++) { - printf("%"PRIu64",%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n", - log[i].timestamp,log[i].latency, log[i].cmdtag, log[i].opcode, - log[i].fuse, log[i].psdt, log[i].cid, log[i].nsid, - log[i].slba_low, log[i].slba_high, log[i].nlb, - log[i].deac, log[i].prinfo, log[i].fua, log[i].lr); - } - printf("\n"); - dev_close(dev); - return err; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err) + return err; + memset(&log, 0, sizeof(log)); + err = nvme_get_log_simple(dev_fd(dev), 0xD1, sizeof(log), &log); + if (err) { + if (err < 0) + printf("Unable to retrieve latency stats log the drive\n"); + dev_close(dev); + return err; + } + /* print header and each log entry */ + printf("Timestamp, Latency, CmdTag, Opcode, Fuse, Psdt, Cid, Nsid, Slba_L, Slba_H, Nlb, "); + printf("DEAC, PRINFO, FUA, LR\n"); + for (int i = 0; i < LATENCY_LOG_ENTRIES; i++) + printf("%"PRIu64",%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n", + log[i].timestamp, log[i].latency, log[i].cmdtag, log[i].opcode, + log[i].fuse, log[i].psdt, log[i].cid, log[i].nsid, + log[i].slba_low, log[i].slba_high, log[i].nlb, + log[i].deac, log[i].prinfo, log[i].fua, log[i].lr); + printf("\n"); + dev_close(dev); + return err; } static int micron_latency_stats_info(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - const char *desc = "display command latency statistics"; - const char *command = "command to display stats - all|read|write|trim" - "default is all"; - int err = 0; - struct nvme_dev *dev; - eDriveModel model = UNKNOWN_MODEL; - #define LATENCY_BUCKET_COUNT 32 - #define LATENCY_BUCKET_RSVD 32 - struct micron_latency_stats { - uint64_t version; /* major << 32 | minior */ - uint64_t all_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; - uint64_t read_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; - uint64_t write_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; - uint64_t trim_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; - uint32_t reserved[255]; /* round up to 4K */ - } log; - - struct latency_thresholds { - uint32_t start; - uint32_t end; - char *unit; - } thresholds[LATENCY_BUCKET_COUNT] = { - {0, 50, "us"}, {50, 100, "us"}, {100, 150, "us"}, {150, 200, "us"}, - {200, 300, "us"}, {300, 400, "us"}, {400, 500, "us"}, {500, 600, "us"}, - {600, 700, "us"}, {700, 800, "us"}, {800, 900, "us"}, {900, 1000, "us"}, - {1, 5, "ms"}, {5, 10, "ms"}, {10, 20, "ms"}, {20, 50, "ms"}, {50, 100, "ms"}, - {100, 200, "ms"}, {200, 300, "ms"}, {300, 400, "ms"}, {400, 500, "ms"}, - {500, 600, "ms"}, {600, 700, "ms"}, {700, 800, "ms"}, {800, 900, "ms"}, - {900, 1000, "ms"}, {1, 2, "s"}, {2, 3, "s"}, {3, 4, "s"}, {4, 5, "s"}, - {5,8, "s"}, - {8, INT_MAX, "s"}, - }; - - struct { - char *command; - } opt = { - .command="all" - }; - - uint64_t *cmd_stats = &log.all_cmds[0]; - char *cmd_str = "All"; - - OPT_ARGS(opts) = { - OPT_STRING("command", 'c', "command", &opt.command, command), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return err; - if (!strcmp(opt.command, "read")) { - cmd_stats = &log.read_cmds[0]; + const char *desc = "display command latency statistics"; + const char *command = "command to display stats - all|read|write|trimdefault is all"; + int err = 0; + struct nvme_dev *dev; + enum eDriveModel model = UNKNOWN_MODEL; + #define LATENCY_BUCKET_COUNT 32 + #define LATENCY_BUCKET_RSVD 32 + struct micron_latency_stats { + uint64_t version; /* major << 32 | minior */ + uint64_t all_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; + uint64_t read_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; + uint64_t write_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; + uint64_t trim_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD]; + uint32_t reserved[255]; /* round up to 4K */ + } log; + + struct latency_thresholds { + uint32_t start; + uint32_t end; + char *unit; + } thresholds[LATENCY_BUCKET_COUNT] = { + {0, 50, "us"}, {50, 100, "us"}, {100, 150, "us"}, {150, 200, "us"}, + {200, 300, "us"}, {300, 400, "us"}, {400, 500, "us"}, {500, 600, "us"}, + {600, 700, "us"}, {700, 800, "us"}, {800, 900, "us"}, {900, 1000, "us"}, + {1, 5, "ms"}, {5, 10, "ms"}, {10, 20, "ms"}, {20, 50, "ms"}, {50, 100, "ms"}, + {100, 200, "ms"}, {200, 300, "ms"}, {300, 400, "ms"}, {400, 500, "ms"}, + {500, 600, "ms"}, {600, 700, "ms"}, {700, 800, "ms"}, {800, 900, "ms"}, + {900, 1000, "ms"}, {1, 2, "s"}, {2, 3, "s"}, {3, 4, "s"}, {4, 5, "s"}, + {5, 8, "s"}, + {8, INT_MAX, "s"}, + }; + + struct { + char *command; + } opt = { + .command = "all" + }; + + uint64_t *cmd_stats = &log.all_cmds[0]; + char *cmd_str = "All"; + + OPT_ARGS(opts) = { + OPT_STRING("command", 'c', "command", &opt.command, command), + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return err; + if (!strcmp(opt.command, "read")) { + cmd_stats = &log.read_cmds[0]; cmd_str = "Read"; - } else if (!strcmp(opt.command, "write")) { - cmd_stats = &log.write_cmds[0]; + } else if (!strcmp(opt.command, "write")) { + cmd_stats = &log.write_cmds[0]; cmd_str = "Write"; - } else if (!strcmp(opt.command, "trim")) { - cmd_stats = &log.trim_cmds[0]; + } else if (!strcmp(opt.command, "trim")) { + cmd_stats = &log.trim_cmds[0]; cmd_str = "Trim"; - } else if (strcmp(opt.command, "all")) { - printf("Invalid command option %s to display latency stats\n", opt.command); - dev_close(dev); + } else if (strcmp(opt.command, "all")) { + printf("Invalid command option %s to display latency stats\n", opt.command); + dev_close(dev); return -1; - } - - memset(&log, 0, sizeof(log)); - err = nvme_get_log_simple(dev_fd(dev), 0xD0, sizeof(log), &log); - if (err) { - if (err < 0) - printf("Unable to retrieve latency stats log the drive\n"); - dev_close(dev); - return err; - } - printf("Micron IO %s Command Latency Statistics\n" + } + + memset(&log, 0, sizeof(log)); + err = nvme_get_log_simple(dev_fd(dev), 0xD0, sizeof(log), &log); + if (err) { + if (err < 0) + printf("Unable to retrieve latency stats log the drive\n"); + dev_close(dev); + return err; + } + printf("Micron IO %s Command Latency Statistics\n" "Major Revision : %d\nMinor Revision : %d\n", cmd_str, (int)(log.version >> 32), (int)(log.version & 0xFFFFFFFF)); - printf("=============================================\n"); - printf("Bucket Start End Command Count\n"); - printf("=============================================\n"); - - for (int b = 0; b < LATENCY_BUCKET_COUNT; b++) { - int bucket = b + 1; - char start[32] = { 0 }; - char end[32] = { 0 }; - sprintf(start, "%u%s", thresholds[b].start, thresholds[b].unit); - if (thresholds[b].end == INT_MAX) - sprintf(end, "INF"); - else - sprintf(end, "%u%s", thresholds[b].end, thresholds[b].unit); - printf("%2d %8s %8s %8"PRIu64"\n", - bucket, start, end, cmd_stats[b]); - } - dev_close(dev); - return err; + printf("=============================================\n"); + printf("Bucket Start End Command Count\n"); + printf("=============================================\n"); + + for (int b = 0; b < LATENCY_BUCKET_COUNT; b++) { + int bucket = b + 1; + char start[32] = { 0 }; + char end[32] = { 0 }; + + sprintf(start, "%u%s", thresholds[b].start, thresholds[b].unit); + if (thresholds[b].end == INT_MAX) + sprintf(end, "INF"); + else + sprintf(end, "%u%s", thresholds[b].end, thresholds[b].unit); + printf("%2d %8s %8s %8"PRIu64"\n", bucket, start, end, cmd_stats[b]); + } + dev_close(dev); + return err; } static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - const char *desc = "Retrieve Smart or Extended Smart Health log for the given device "; - unsigned int logC0[C0_log_size/sizeof(int)] = { 0 }; - unsigned int logFB[FB_log_size/sizeof(int)] = { 0 }; - struct nvme_id_ctrl ctrl; - eDriveModel eModel = UNKNOWN_MODEL; - struct nvme_dev *dev; - bool is_json = true; - struct format { - char *fmt; - }; - const char *fmt = "output format normal|json"; - struct format cfg = { - .fmt = "json", - }; - int err = 0; - - OPT_ARGS(opts) = { - OPT_FMT("format", 'f', &cfg.fmt, fmt), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel); - if (err < 0) - return -1; - - if (strcmp(cfg.fmt, "normal") == 0) - is_json = false; - - /* For M5410 and M5407, this option prints 0xFB log page */ - if (eModel == M5410 || eModel == M5407) { - __u8 spec = (eModel == M5410) ? 0 : 1; - __u8 nsze; - - if ((err = nvme_identify_ctrl(dev_fd(dev), &ctrl)) == 0) - err = nvme_get_log_simple(dev_fd(dev), 0xFB, - FB_log_size, logFB); - if (err) { - if (err < 0) - printf("Unable to retrieve smart log 0xFB for the drive\n"); - goto out; - } - - nsze = (ctrl.vs[987] == 0x12); - if (nsze == 0 && nsze_from_oacs) - nsze = ((ctrl.oacs >> 3) & 0x1); - print_nand_stats_fb((__u8 *)logFB, NULL, nsze, is_json, spec); - goto out; - } - - /* check for models that support 0xC0 log */ - if (eModel != M51CX) { - printf ("Unsupported drive model for vs-smart-add-log commmand\n"); - err = -1; - goto out; - } - - err = nvme_get_log_simple(dev_fd(dev), 0xC0, C0_log_size, logC0); - if (err == 0) { - print_smart_cloud_health_log((__u8 *)logC0, is_json); - } else if (err < 0) { - printf("Unable to retrieve extended smart log 0xC0 for the drive\n"); - } + const char *desc = "Retrieve Smart or Extended Smart Health log for the given device "; + unsigned int logC0[C0_log_size/sizeof(int)] = { 0 }; + unsigned int logFB[FB_log_size/sizeof(int)] = { 0 }; + struct nvme_id_ctrl ctrl; + enum eDriveModel eModel = UNKNOWN_MODEL; + struct nvme_dev *dev; + bool is_json = true; + struct format { + char *fmt; + }; + const char *fmt = "output format normal|json"; + struct format cfg = { + .fmt = "json", + }; + int err = 0; + + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel); + if (err < 0) + return -1; + + if (!strcmp(cfg.fmt, "normal")) + is_json = false; + + /* For M5410 and M5407, this option prints 0xFB log page */ + if (eModel == M5410 || eModel == M5407) { + __u8 spec = (eModel == M5410) ? 0 : 1; + __u8 nsze; + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (!err) + err = nvme_get_log_simple(dev_fd(dev), 0xFB, FB_log_size, logFB); + if (err) { + if (err < 0) + printf("Unable to retrieve smart log 0xFB for the drive\n"); + goto out; + } + + nsze = (ctrl.vs[987] == 0x12); + if (!nsze && nsze_from_oacs) + nsze = ((ctrl.oacs >> 3) & 0x1); + print_nand_stats_fb((__u8 *)logFB, NULL, nsze, is_json, spec); + goto out; + } + + /* check for models that support 0xC0 log */ + if (eModel != M51CX) { + printf("Unsupported drive model for vs-smart-add-log command\n"); + err = -1; + goto out; + } + + err = nvme_get_log_simple(dev_fd(dev), 0xC0, C0_log_size, logC0); + if (!err) + print_smart_cloud_health_log((__u8 *)logC0, is_json); + else if (err < 0) + printf("Unable to retrieve extended smart log 0xC0 for the drive\n"); out: - dev_close(dev); - if (err > 0) - nvme_show_status(err); - return err; + dev_close(dev); + if (err > 0) + nvme_show_status(err); + return err; } static int micron_clr_fw_activation_history(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - const char *desc = "Clear FW activation history"; - __u32 result = 0; - __u8 fid = MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY; - eDriveModel model = UNKNOWN_MODEL; - struct nvme_dev *dev; - OPT_ARGS(opts) = { - OPT_END() - }; - int err = 0; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return err; - - if (model != M51CX) { - printf ("This option is not supported for specified drive\n"); - dev_close(dev); - return err; - } - - err = nvme_set_features_simple(dev_fd(dev), fid, 1 << 31, 0, 0, &result); - if (err == 0) err = (int)result; - else printf ("Failed to clear fw activation history, error = 0x%x\n", err); - - dev_close(dev); - return err; + const char *desc = "Clear FW activation history"; + __u32 result = 0; + __u8 fid = MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY; + enum eDriveModel model = UNKNOWN_MODEL; + struct nvme_dev *dev; + + OPT_ARGS(opts) = { + OPT_END() + }; + int err = 0; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return err; + + if (model != M51CX) { + printf("This option is not supported for specified drive\n"); + dev_close(dev); + return err; + } + + err = nvme_set_features_simple(dev_fd(dev), fid, 1 << 31, 0, 0, &result); + if (!err) + err = (int)result; + else + printf("Failed to clear fw activation history, error = 0x%x\n", err); + + dev_close(dev); + return err; } static int micron_telemetry_cntrl_option(int argc, char **argv, - struct command *cmd, struct plugin *plugin) + struct command *cmd, struct plugin *plugin) { - int err = 0; - __u32 result = 0; - const char *desc = "Enable or Disable Controller telemetry log generation"; - const char *option = "enable or disable or status"; - const char *select = "select/save values: enable/disable options" - "1 - save (persistent), 0 - non-persistent and for " - "status options: 0 - current, 1 - default, 2-saved"; - int fid = MICRON_FEATURE_TELEMETRY_CONTROL_OPTION; - eDriveModel model = UNKNOWN_MODEL; - struct nvme_id_ctrl ctrl = { 0 }; - struct nvme_dev *dev; - - struct { - char *option; - int select; - } opt = { - .option = "disable", - .select= 0, - }; - - OPT_ARGS(opts) = { - OPT_STRING("option", 'o', "option", &opt.option, option), - OPT_UINT("select", 's', &opt.select, select), - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return -1; - - err = nvme_identify_ctrl(dev_fd(dev), &ctrl); - if ((ctrl.lpa & 0x8) != 0x8) { - printf("drive doesn't support host/controller generated telemetry logs\n"); - dev_close(dev); - return err; - } - - if (!strcmp(opt.option, "enable")) { - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = fid, - .nsid = 1, - .cdw11 = 1, - .cdw12 = 0, - .save = (opt.select & 0x1), - .uuidx = 0, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_set_features(&args); - if (err == 0) { - printf("successfully set controller telemetry option\n"); - } else { - printf("Failed to set controller telemetry option\n"); - } - } else if (!strcmp(opt.option, "disable")) { - struct nvme_set_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = fid, - .nsid = 1, - .cdw11 = 0, - .cdw12 = 0, - .save = (opt.select & 0x1), - .uuidx = 0, - .cdw15 = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, - }; - err = nvme_set_features(&args); - if (err == 0) { - printf("successfully disabled controller telemetry option\n"); - } else { - printf("Failed to disable controller telemetry option\n"); - } - } else if (!strcmp(opt.option, "status")) { - struct nvme_get_features_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .fid = fid, - .nsid = 1, - .sel = opt.select & 0x3, - .cdw11 = 0, - .uuidx = 0, - .data_len = 0, - .data = NULL, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = &result, + int err = 0; + __u32 result = 0; + const char *desc = "Enable or Disable Controller telemetry log generation"; + const char *option = "enable or disable or status"; + const char *select = + "select/save values: enable/disable options1 - save (persistent), 0 - non-persistent and for status options: 0 - current, 1 - default, 2-saved"; + int fid = MICRON_FEATURE_TELEMETRY_CONTROL_OPTION; + enum eDriveModel model = UNKNOWN_MODEL; + struct nvme_id_ctrl ctrl = { 0 }; + struct nvme_dev *dev; + + struct { + char *option; + int select; + } opt = { + .option = "disable", + .select = 0, }; - err = nvme_get_features(&args); - if (err == 0) { - printf("Controller telemetry option : %s\n", - (result) ? "enabled" : "disabled"); - } else { - printf("Failed to retrieve controller telemetry option\n"); - } - } else { - printf("invalid option %s, valid values are enable,disable or status\n", opt.option); - dev_close(dev); - return -1; - } - - dev_close(dev); - return err; + + OPT_ARGS(opts) = { + OPT_STRING("option", 'o', "option", &opt.option, option), + OPT_UINT("select", 's', &opt.select, select), + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return -1; + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if ((ctrl.lpa & 0x8) != 0x8) { + printf("drive doesn't support host/controller generated telemetry logs\n"); + dev_close(dev); + return err; + } + + if (!strcmp(opt.option, "enable")) { + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = 1, + .cdw11 = 1, + .cdw12 = 0, + .save = (opt.select & 0x1), + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (!err) + printf("successfully set controller telemetry option\n"); + else + printf("Failed to set controller telemetry option\n"); + } else if (!strcmp(opt.option, "disable")) { + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = 1, + .cdw11 = 0, + .cdw12 = 0, + .save = (opt.select & 0x1), + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (!err) + printf("successfully disabled controller telemetry option\n"); + else + printf("Failed to disable controller telemetry option\n"); + } else if (!strcmp(opt.option, "status")) { + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = 1, + .sel = opt.select & 0x3, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_get_features(&args); + if (!err) + printf("Controller telemetry option : %s\n", + (result) ? "enabled" : "disabled"); + else + printf("Failed to retrieve controller telemetry option\n"); + } else { + printf("invalid option %s, valid values are enable,disable or status\n", + opt.option); + dev_close(dev); + return -1; + } + + dev_close(dev); + return err; } /* M51XX models log page header */ struct micron_common_log_header { - uint8_t id; - uint8_t version; - uint16_t pn; - uint32_t log_size; - uint32_t max_size; - uint32_t write_pointer; - uint32_t next_pointer; - uint32_t overwritten_bytes; - uint8_t flags; - uint8_t reserved[7]; + uint8_t id; + uint8_t version; + uint16_t pn; + uint32_t log_size; + uint32_t max_size; + uint32_t write_pointer; + uint32_t next_pointer; + uint32_t overwritten_bytes; + uint8_t flags; + uint8_t reserved[7]; }; /* helper function to retrieve logs with specific offset and max chunk size */ int nvme_get_log_lpo(int fd, __u8 log_id, __u32 lpo, __u32 chunk, - __u32 data_len, void *data) + __u32 data_len, void *data) { __u32 offset = lpo, xfer_len = data_len; void *ptr = data; @@ -2933,463 +2909,458 @@ int nvme_get_log_lpo(int fd, __u8 log_id, __u32 lpo, __u32 chunk, /* retrieves logs with common log format */ static int get_common_log(int fd, uint8_t id, uint8_t **buf, int *size) { - struct micron_common_log_header hdr = { 0 }; - int log_size = sizeof(hdr), first = 0, second = 0; - uint8_t *buffer = NULL; - int ret = -1; - int chunk = 0x4000; /* max chunk size to be used for these logs */ - - ret = nvme_get_log_simple(fd, id, sizeof(hdr), &hdr); - if (ret) { - fprintf(stderr, "pull hdr failed for %hhu with error: 0x%x\n", id, ret); - return ret; - } - - if (hdr.id != id || - hdr.log_size == 0 || - hdr.max_size == 0 || - hdr.write_pointer < sizeof(hdr)) - { - fprintf(stderr, "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, " - "max: %u, wp: %u, flags: %hhu, np: %u\n", id, - hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, - hdr.flags, hdr.next_pointer); - return 1; - } - - /* we may have just 32-bytes for some models; write to wfile if log hasn't - * yet reached its max size - */ - if (hdr.log_size == sizeof(hdr)) { - buffer = (uint8_t *)malloc(sizeof(hdr)); - if (buffer == NULL) { - fprintf(stderr, "malloc of %lu bytes failed for log: 0x%X\n", - sizeof(hdr), id); - return -ENOMEM; - } - memcpy(buffer,(uint8_t *)&hdr, sizeof(hdr)); - } else if (hdr.log_size < hdr.max_size) { - buffer = (uint8_t *)malloc(sizeof(hdr) + hdr.log_size); - if (buffer == NULL) { - fprintf(stderr, "malloc of %lu bytes failed for log: 0x%X\n", - hdr.log_size + sizeof(hdr), id); - return -ENOMEM; - } - memcpy(buffer, &hdr, sizeof(hdr)); - ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, hdr.log_size, - buffer + sizeof(hdr)); - if (ret == 0) { - log_size += hdr.log_size; - } - } else if (hdr.log_size >= hdr.max_size) { - /* reached maximum, to maintain, sequence we need to depend on write - * pointer to detect wrap-overs. FW doesn't yet implement the condition - * hdr.log_size > hdr.max_size; also ignore over-written log data; we - * also ignore collisions for now - */ - buffer = (uint8_t *)malloc(hdr.max_size + sizeof(hdr)); - if (buffer == NULL) { - fprintf(stderr, "malloc of %lu bytes failed for log: 0x%X\n", - hdr.max_size + sizeof(hdr), id); - return -ENOMEM; - } - memcpy(buffer, &hdr, sizeof(hdr)); - - first = hdr.max_size - hdr.write_pointer; - second = hdr.write_pointer - sizeof(hdr); - - if (first) { - ret = nvme_get_log_lpo(fd, id, hdr.write_pointer, chunk, first, - buffer + sizeof(hdr)); - if (ret) { - free(buffer); - fprintf(stderr, "failed to get log: 0x%X\n", id); - return ret; - } - log_size += first; - } - if (second) { - ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, second, - buffer + sizeof(hdr) + first); - if (ret) { - fprintf(stderr, "failed to get log: 0x%X\n", id); - free(buffer); + struct micron_common_log_header hdr = { 0 }; + int log_size = sizeof(hdr), first = 0, second = 0; + uint8_t *buffer = NULL; + int ret = -1; + int chunk = 0x4000; /* max chunk size to be used for these logs */ + + ret = nvme_get_log_simple(fd, id, sizeof(hdr), &hdr); + if (ret) { + fprintf(stderr, "pull hdr failed for %u with error: 0x%x\n", id, ret); return ret; - } - log_size += second; } - } - *buf = buffer; - *size = log_size; - return ret; + + if (hdr.id != id || !hdr.log_size || !hdr.max_size || + hdr.write_pointer < sizeof(hdr)) { + fprintf(stderr, + "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n", + id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr.flags, + hdr.next_pointer); + return 1; + } + + /* + * we may have just 32-bytes for some models; write to wfile if log hasn't + * yet reached its max size + */ + if (hdr.log_size == sizeof(hdr)) { + buffer = (uint8_t *)malloc(sizeof(hdr)); + if (!buffer) { + fprintf(stderr, "malloc of %zu bytes failed for log: 0x%X\n", + sizeof(hdr), id); + return -ENOMEM; + } + memcpy(buffer, (uint8_t *)&hdr, sizeof(hdr)); + } else if (hdr.log_size < hdr.max_size) { + buffer = (uint8_t *)malloc(sizeof(hdr) + hdr.log_size); + if (!buffer) { + fprintf(stderr, "malloc of %zu bytes failed for log: 0x%X\n", + hdr.log_size + sizeof(hdr), id); + return -ENOMEM; + } + memcpy(buffer, &hdr, sizeof(hdr)); + ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, hdr.log_size, + buffer + sizeof(hdr)); + if (!ret) + log_size += hdr.log_size; + } else if (hdr.log_size >= hdr.max_size) { + /* + * reached maximum, to maintain, sequence we need to depend on write + * pointer to detect wrap-overs. FW doesn't yet implement the condition + * hdr.log_size > hdr.max_size; also ignore over-written log data; we + * also ignore collisions for now + */ + buffer = (uint8_t *)malloc(hdr.max_size + sizeof(hdr)); + if (!buffer) { + fprintf(stderr, "malloc of %zu bytes failed for log: 0x%X\n", + hdr.max_size + sizeof(hdr), id); + return -ENOMEM; + } + memcpy(buffer, &hdr, sizeof(hdr)); + + first = hdr.max_size - hdr.write_pointer; + second = hdr.write_pointer - sizeof(hdr); + + if (first) { + ret = nvme_get_log_lpo(fd, id, hdr.write_pointer, chunk, first, + buffer + sizeof(hdr)); + if (ret) { + free(buffer); + fprintf(stderr, "failed to get log: 0x%X\n", id); + return ret; + } + log_size += first; + } + if (second) { + ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, second, + buffer + sizeof(hdr) + first); + if (ret) { + fprintf(stderr, "failed to get log: 0x%X\n", id); + free(buffer); + return ret; + } + log_size += second; + } + } + *buf = buffer; + *size = log_size; + return ret; } static int micron_internal_logs(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - int err = -EINVAL; - int ctrlIdx, telemetry_option = 0; - char strOSDirName[1024]; - char strCtrlDirName[1024]; - char strMainDirName[256]; - unsigned int *puiIDDBuf; - unsigned int uiMask; - struct nvme_id_ctrl ctrl; - char sn[20] = { 0 }; - char msg[256] = { 0 }; - int c_logs_index = 8; /* should be current size of aVendorLogs */ - struct nvme_dev *dev; - struct { - unsigned char ucLogPage; - const char *strFileName; - int nLogSize; - int nMaxSize; - } aVendorLogs[32] = { - { 0x03, "firmware_slot_info_log.bin", 512, 0 }, - { 0xC1, "nvmelog_C1.bin", 0, 0 }, - { 0xC2, "nvmelog_C2.bin", 0, 0 }, - { 0xC4, "nvmelog_C4.bin", 0, 0 }, - { 0xC5, "nvmelog_C5.bin", C5_log_size, 0 }, - { 0xD0, "nvmelog_D0.bin", D0_log_size, 0 }, - { 0xE6, "nvmelog_E6.bin", 0, 0 }, - { 0xE7, "nvmelog_E7.bin", 0, 0 } - }, - aM51XXLogs[] = { - { 0xFB, "nvmelog_FB.bin", 4096, 0 }, /* this should be collected first for M51AX */ - { 0xD0, "nvmelog_D0.bin", 512, 0 }, - { 0x03, "firmware_slot_info_log.bin", 512, 0}, - { 0xF7, "nvmelog_F7.bin", 4096, 512 * 1024 }, - { 0xF8, "nvmelog_F8.bin", 4096, 512 * 1024 }, - { 0xF9, "nvmelog_F9.bin", 4096, 200 * 1024 * 1024 }, - { 0xFC, "nvmelog_FC.bin", 4096, 200 * 1024 * 1024 }, - { 0xFD, "nvmelog_FD.bin", 4096, 80 * 1024 * 1024 } - }, - aM51AXLogs[] = { - { 0xCA, "nvmelog_CA.bin", 512, 0 }, - { 0xFA, "nvmelog_FA.bin", 4096, 15232 }, - { 0xF6, "nvmelog_F6.bin", 4096, 512 * 1024 }, - { 0xFE, "nvmelog_FE.bin", 4096, 512 * 1024 }, - { 0xFF, "nvmelog_FF.bin", 4096, 162 * 1024 }, - { 0x04, "changed_namespace_log.bin", 4096, 0 }, - { 0x05, "command_effects_log.bin", 4096, 0 }, - { 0x06, "drive_self_test.bin", 4096, 0 } - }, - aM51BXLogs[] = { - { 0xFA, "nvmelog_FA.bin", 4096, 16376 }, - { 0xFE, "nvmelog_FE.bin", 4096, 256 * 1024 }, - { 0xFF, "nvmelog_FF.bin", 4096, 64 * 1024 }, - { 0xCA, "nvmelog_CA.bin", 512, 1024 } - }, - aM51CXLogs[] = { - { 0xE1, "nvmelog_E1.bin", 0, 0 }, - { 0xE2, "nvmelog_E2.bin", 0, 0 }, - { 0xE3, "nvmelog_E3.bin", 0, 0 }, - { 0xE4, "nvmelog_E4.bin", 0, 0 }, - { 0xE5, "nvmelog_E5.bin", 0, 0 }, - { 0xE8, "nvmelog_E8.bin", 0, 0 }, - { 0xE9, "nvmelog_E9.bin", 0, 0 }, - { 0xEA, "nvmelog_EA.bin", 0, 0 }, - }; - - eDriveModel eModel; - - const char *desc = "This retrieves the micron debug log package"; - const char *package = "Log output data file name (required)"; - const char *type = "telemetry log type - host or controller"; - const char *data_area = "telemetry log data area 1, 2 or 3"; - unsigned char *dataBuffer = NULL; - int bSize = 0; - int maxSize = 0; - - struct config { - char *type; - char *package; - int data_area; - int log; - }; - - struct config cfg = { - .type = "", - .package = "", - .data_area = -1, - .log = 0x07, - }; - - OPT_ARGS(opts) = { - OPT_STRING("type", 't', "log type", &cfg.type, type), - OPT_STRING("package", 'p', "FILE", &cfg.package, package), - OPT_UINT("data_area", 'd', &cfg.data_area, data_area), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - /* if telemetry type is specified, check for data area */ - if (strlen(cfg.type) != 0) { - if (!strcmp(cfg.type, "controller")) { - cfg.log = 0x08; - } else if (strcmp(cfg.type, "host")) { - printf ("telemetry type (host or controller) should be specified i.e. -t=host\n"); - goto out; - } - - if (cfg.data_area <= 0 || cfg.data_area > 3) { - printf ("data area must be selected using -d option ie --d=1,2,3\n"); - goto out; - } - telemetry_option = 1; - } else if (cfg.data_area > 0) { - printf ("data area option is valid only for telemetry option (i.e --type=host|controller)\n"); - goto out; - } - - if (strlen(cfg.package) == 0) { - if (telemetry_option) - printf ("Log data file must be specified. ie -p=logfile.bin\n"); - else - printf ("Log data file must be specified. ie -p=logfile.zip or -p=logfile.tgz|logfile.tar.gz\n"); - goto out; - } - - /* pull log details based on the model name */ - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { - printf ("Unsupported drive model for vs-internal-log collection\n"); - goto out; - } - - err = nvme_identify_ctrl(dev_fd(dev), &ctrl); - if (err) - goto out; - - err = -EINVAL; - if (telemetry_option) { - if ((ctrl.lpa & 0x8) != 0x8) { - printf("telemetry option is not supported for specified drive\n"); - dev_close(dev); - goto out; - } - int logSize = 0; __u8 *buffer = NULL; const char *dir = "."; - err = micron_telemetry_log(dev_fd(dev), cfg.log, &buffer, &logSize, + int err = -EINVAL; + int ctrlIdx, telemetry_option = 0; + char strOSDirName[1024]; + char strCtrlDirName[1024]; + char strMainDirName[256]; + unsigned int *puiIDDBuf; + unsigned int uiMask; + struct nvme_id_ctrl ctrl; + char sn[20] = { 0 }; + char msg[256] = { 0 }; + int c_logs_index = 8; /* should be current size of aVendorLogs */ + struct nvme_dev *dev; + struct { + unsigned char ucLogPage; + const char *strFileName; + int nLogSize; + int nMaxSize; + } aVendorLogs[32] = { + { 0x03, "firmware_slot_info_log.bin", 512, 0 }, + { 0xC1, "nvmelog_C1.bin", 0, 0 }, + { 0xC2, "nvmelog_C2.bin", 0, 0 }, + { 0xC4, "nvmelog_C4.bin", 0, 0 }, + { 0xC5, "nvmelog_C5.bin", C5_log_size, 0 }, + { 0xD0, "nvmelog_D0.bin", D0_log_size, 0 }, + { 0xE6, "nvmelog_E6.bin", 0, 0 }, + { 0xE7, "nvmelog_E7.bin", 0, 0 } + }, + aM51XXLogs[] = { + { 0xFB, "nvmelog_FB.bin", 4096, 0 }, /* this should be collected first for M51AX */ + { 0xD0, "nvmelog_D0.bin", 512, 0 }, + { 0x03, "firmware_slot_info_log.bin", 512, 0}, + { 0xF7, "nvmelog_F7.bin", 4096, 512 * 1024 }, + { 0xF8, "nvmelog_F8.bin", 4096, 512 * 1024 }, + { 0xF9, "nvmelog_F9.bin", 4096, 200 * 1024 * 1024 }, + { 0xFC, "nvmelog_FC.bin", 4096, 200 * 1024 * 1024 }, + { 0xFD, "nvmelog_FD.bin", 4096, 80 * 1024 * 1024 } + }, + aM51AXLogs[] = { + { 0xCA, "nvmelog_CA.bin", 512, 0 }, + { 0xFA, "nvmelog_FA.bin", 4096, 15232 }, + { 0xF6, "nvmelog_F6.bin", 4096, 512 * 1024 }, + { 0xFE, "nvmelog_FE.bin", 4096, 512 * 1024 }, + { 0xFF, "nvmelog_FF.bin", 4096, 162 * 1024 }, + { 0x04, "changed_namespace_log.bin", 4096, 0 }, + { 0x05, "command_effects_log.bin", 4096, 0 }, + { 0x06, "drive_self_test.bin", 4096, 0 } + }, + aM51BXLogs[] = { + { 0xFA, "nvmelog_FA.bin", 4096, 16376 }, + { 0xFE, "nvmelog_FE.bin", 4096, 256 * 1024 }, + { 0xFF, "nvmelog_FF.bin", 4096, 64 * 1024 }, + { 0xCA, "nvmelog_CA.bin", 512, 1024 } + }, + aM51CXLogs[] = { + { 0xE1, "nvmelog_E1.bin", 0, 0 }, + { 0xE2, "nvmelog_E2.bin", 0, 0 }, + { 0xE3, "nvmelog_E3.bin", 0, 0 }, + { 0xE4, "nvmelog_E4.bin", 0, 0 }, + { 0xE5, "nvmelog_E5.bin", 0, 0 }, + { 0xE8, "nvmelog_E8.bin", 0, 0 }, + { 0xE9, "nvmelog_E9.bin", 0, 0 }, + { 0xEA, "nvmelog_EA.bin", 0, 0 }, + }; + + enum eDriveModel eModel; + + const char *desc = "This retrieves the micron debug log package"; + const char *package = "Log output data file name (required)"; + const char *type = "telemetry log type - host or controller"; + const char *data_area = "telemetry log data area 1, 2 or 3"; + unsigned char *dataBuffer = NULL; + int bSize = 0; + int maxSize = 0; + + struct config { + char *type; + char *package; + int data_area; + int log; + }; + + struct config cfg = { + .type = "", + .package = "", + .data_area = -1, + .log = 0x07, + }; + + OPT_ARGS(opts) = { + OPT_STRING("type", 't', "log type", &cfg.type, type), + OPT_STRING("package", 'p', "FILE", &cfg.package, package), + OPT_UINT("data_area", 'd', &cfg.data_area, data_area), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + /* if telemetry type is specified, check for data area */ + if (strlen(cfg.type)) { + if (!strcmp(cfg.type, "controller")) { + cfg.log = 0x08; + } else if (strcmp(cfg.type, "host")) { + printf("telemetry type (host or controller) should be specified i.e. -t=host\n"); + goto out; + } + + if (cfg.data_area <= 0 || cfg.data_area > 3) { + printf("data area must be selected using -d option ie --d=1,2,3\n"); + goto out; + } + telemetry_option = 1; + } else if (cfg.data_area > 0) { + printf("data area option is valid only for telemetry option (i.e --type=host|controller)\n"); + goto out; + } + + if (!strlen(cfg.package)) { + if (telemetry_option) + printf("Log data file must be specified. ie -p=logfile.bin\n"); + else + printf("Log data file must be specified. ie -p=logfile.zip or -p=logfile.tgz|logfile.tar.gz\n"); + goto out; + } + + /* pull log details based on the model name */ + if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1) + ctrlIdx = 0; + eModel = GetDriveModel(ctrlIdx); + if (eModel == UNKNOWN_MODEL) { + printf("Unsupported drive model for vs-internal-log collection\n"); + goto out; + } + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) + goto out; + + err = -EINVAL; + if (telemetry_option) { + if ((ctrl.lpa & 0x8) != 0x8) { + printf("telemetry option is not supported for specified drive\n"); + goto out; + } + int logSize = 0; __u8 *buffer = NULL; const char *dir = "."; + + err = micron_telemetry_log(dev_fd(dev), cfg.log, &buffer, &logSize, cfg.data_area); - if (err == 0 && logSize > 0 && buffer != NULL) { - sprintf(msg, "telemetry log: 0x%X", cfg.log); - WriteData(buffer, logSize, dir, cfg.package, msg); - free(buffer); - } - goto out; - } - - printf("Preparing log package. This will take a few seconds...\n"); - - /* trim spaces out of serial number string */ - int i, j = 0; - for (i = 0; i < sizeof(ctrl.sn); i++) { - if (isblank((int)ctrl.sn[i])) - continue; - sn[j++] = ctrl.sn[i]; - } - sn[j] = '\0'; - strcpy(ctrl.sn, sn); - - SetupDebugDataDirectories(ctrl.sn, cfg.package, strMainDirName, strOSDirName, strCtrlDirName); - - GetTimestampInfo(strOSDirName); - GetCtrlIDDInfo(strCtrlDirName, &ctrl); - GetOSConfig(strOSDirName); - GetDriveInfo(strOSDirName, ctrlIdx, &ctrl); - - for (int i = 1; i <= ctrl.nn; i++) - GetNSIDDInfo(dev_fd(dev), strCtrlDirName, i); - - GetSmartlogData(dev_fd(dev), strCtrlDirName); - GetErrorlogData(dev_fd(dev), ctrl.elpe, strCtrlDirName); - GetGenericLogs(dev_fd(dev), strCtrlDirName); - /* pull if telemetry log data is supported */ - if ((ctrl.lpa & 0x8) == 0x8) - GetTelemetryData(dev_fd(dev), strCtrlDirName); - - GetFeatureSettings(dev_fd(dev), strCtrlDirName); - - if (eModel != M5410 && eModel != M5407) { - memcpy(&aVendorLogs[c_logs_index], aM51XXLogs, sizeof(aM51XXLogs)); - c_logs_index += sizeof(aM51XXLogs)/sizeof(aM51XXLogs[0]); - if (eModel == M51AX) - memcpy((char *)&aVendorLogs[c_logs_index], aM51AXLogs, sizeof(aM51AXLogs)); - else if (eModel == M51BX) - memcpy((char *)&aVendorLogs[c_logs_index], aM51BXLogs, sizeof(aM51BXLogs)); - else if (eModel == M51CX) - memcpy((char *)&aVendorLogs[c_logs_index], aM51CXLogs, sizeof(aM51CXLogs)); - } - - for (int i = 0; i < (int)(sizeof(aVendorLogs) / sizeof(aVendorLogs[0])) && - aVendorLogs[i].ucLogPage != 0; i++) { - err = -1; - switch (aVendorLogs[i].ucLogPage) { - case 0xE1: - case 0xE5: - case 0xE9: - err = 1; - break; - - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE8: - case 0xEA: - err = get_common_log(dev_fd(dev), aVendorLogs[i].ucLogPage, + if (!err && logSize > 0 && buffer) { + sprintf(msg, "telemetry log: 0x%X", cfg.log); + WriteData(buffer, logSize, dir, cfg.package, msg); + free(buffer); + } + goto out; + } + + printf("Preparing log package. This will take a few seconds...\n"); + + /* trim spaces out of serial number string */ + int i, j = 0; + + for (i = 0; i < sizeof(ctrl.sn); i++) { + if (isblank((int)ctrl.sn[i])) + continue; + sn[j++] = ctrl.sn[i]; + } + sn[j] = '\0'; + strcpy(ctrl.sn, sn); + + SetupDebugDataDirectories(ctrl.sn, cfg.package, strMainDirName, strOSDirName, strCtrlDirName); + + GetTimestampInfo(strOSDirName); + GetCtrlIDDInfo(strCtrlDirName, &ctrl); + GetOSConfig(strOSDirName); + GetDriveInfo(strOSDirName, ctrlIdx, &ctrl); + + for (int i = 1; i <= ctrl.nn; i++) + GetNSIDDInfo(dev_fd(dev), strCtrlDirName, i); + + GetSmartlogData(dev_fd(dev), strCtrlDirName); + GetErrorlogData(dev_fd(dev), ctrl.elpe, strCtrlDirName); + GetGenericLogs(dev_fd(dev), strCtrlDirName); + /* pull if telemetry log data is supported */ + if ((ctrl.lpa & 0x8) == 0x8) + GetTelemetryData(dev_fd(dev), strCtrlDirName); + + GetFeatureSettings(dev_fd(dev), strCtrlDirName); + + if (eModel != M5410 && eModel != M5407) { + memcpy(&aVendorLogs[c_logs_index], aM51XXLogs, sizeof(aM51XXLogs)); + c_logs_index += ARRAY_SIZE(aM51XXLogs); + if (eModel == M51AX) + memcpy((char *)&aVendorLogs[c_logs_index], aM51AXLogs, sizeof(aM51AXLogs)); + else if (eModel == M51BX) + memcpy((char *)&aVendorLogs[c_logs_index], aM51BXLogs, sizeof(aM51BXLogs)); + else if (eModel == M51CX) + memcpy((char *)&aVendorLogs[c_logs_index], aM51CXLogs, sizeof(aM51CXLogs)); + } + + for (int i = 0; i < (int)(ARRAY_SIZE(aVendorLogs)) && aVendorLogs[i].ucLogPage; i++) { + err = -1; + switch (aVendorLogs[i].ucLogPage) { + case 0xE1: + case 0xE5: + case 0xE9: + err = 1; + break; + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE8: + case 0xEA: + err = get_common_log(dev_fd(dev), aVendorLogs[i].ucLogPage, &dataBuffer, &bSize); - break; - - case 0xC1: - case 0xC2: - case 0xC4: - err = GetLogPageSize(dev_fd(dev), aVendorLogs[i].ucLogPage, - &bSize); - if (err == 0 && bSize > 0) - err = GetCommonLogPage(dev_fd(dev), aVendorLogs[i].ucLogPage, - &dataBuffer, bSize); - break; - - case 0xE6: - case 0xE7: - puiIDDBuf = (unsigned int *)&ctrl; - uiMask = puiIDDBuf[1015]; - if (uiMask == 0 || (aVendorLogs[i].ucLogPage == 0xE6 && uiMask == 2) || - (aVendorLogs[i].ucLogPage == 0xE7 && uiMask == 1)) { - bSize = 0; - } else { - bSize = (int)puiIDDBuf[1023]; - if (bSize % (16 * 1024)) { - bSize += (16 * 1024) - (bSize % (16 * 1024)); - } - } - if (bSize != 0 && (dataBuffer = (unsigned char *)malloc(bSize)) != NULL) { - memset(dataBuffer, 0, bSize); - if (eModel == M5410 || eModel == M5407) - err = NVMEGetLogPage(dev_fd(dev), - aVendorLogs[i].ucLogPage, dataBuffer, - bSize); - else - err = nvme_get_log_simple(dev_fd(dev), - aVendorLogs[i].ucLogPage, - bSize, dataBuffer); - } - break; - - case 0xF7: - case 0xF9: - case 0xFC: - case 0xFD: - if (eModel == M51BX) { - (void)NVMEResetLog(dev_fd(dev), aVendorLogs[i].ucLogPage, - aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize); - } - /* fallthrough */ - default: - bSize = aVendorLogs[i].nLogSize; - dataBuffer = (unsigned char *)malloc(bSize); - if (dataBuffer == NULL) { - break; - } - memset(dataBuffer, 0, bSize); - err = nvme_get_log_simple(dev_fd(dev), aVendorLogs[i].ucLogPage, - bSize, dataBuffer); - maxSize = aVendorLogs[i].nMaxSize - bSize; - while (err == 0 && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) { - sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage); - WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg); - err = nvme_get_log_simple(dev_fd(dev), + break; + case 0xC1: + case 0xC2: + case 0xC4: + err = GetLogPageSize(dev_fd(dev), aVendorLogs[i].ucLogPage, + &bSize); + if (!err && bSize > 0) + err = GetCommonLogPage(dev_fd(dev), aVendorLogs[i].ucLogPage, + &dataBuffer, bSize); + break; + case 0xE6: + case 0xE7: + puiIDDBuf = (unsigned int *)&ctrl; + uiMask = puiIDDBuf[1015]; + if (!uiMask || (aVendorLogs[i].ucLogPage == 0xE6 && uiMask == 2) || + (aVendorLogs[i].ucLogPage == 0xE7 && uiMask == 1)) { + bSize = 0; + } else { + bSize = (int)puiIDDBuf[1023]; + if (bSize % (16 * 1024)) + bSize += (16 * 1024) - (bSize % (16 * 1024)); + } + dataBuffer = (unsigned char *)malloc(bSize); + if (bSize && dataBuffer) { + memset(dataBuffer, 0, bSize); + if (eModel == M5410 || eModel == M5407) + err = NVMEGetLogPage(dev_fd(dev), + aVendorLogs[i].ucLogPage, dataBuffer, + bSize); + else + err = nvme_get_log_simple(dev_fd(dev), + aVendorLogs[i].ucLogPage, + bSize, dataBuffer); + } + break; + case 0xF7: + case 0xF9: + case 0xFC: + case 0xFD: + if (eModel == M51BX) + (void)NVMEResetLog(dev_fd(dev), aVendorLogs[i].ucLogPage, + aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize); + fallthrough; + default: + bSize = aVendorLogs[i].nLogSize; + dataBuffer = (unsigned char *)malloc(bSize); + if (!dataBuffer) + break; + memset(dataBuffer, 0, bSize); + err = nvme_get_log_simple(dev_fd(dev), aVendorLogs[i].ucLogPage, + bSize, dataBuffer); + maxSize = aVendorLogs[i].nMaxSize - bSize; + while (!err && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) { + sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage); + WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg); + err = nvme_get_log_simple(dev_fd(dev), aVendorLogs[i].ucLogPage, bSize, dataBuffer); - if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef)) - break; - maxSize -= bSize; - } - break; - } - - if (err == 0 && dataBuffer != NULL && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) { - sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage); - WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg); - } - - if (dataBuffer != NULL) { - free(dataBuffer); - dataBuffer = NULL; - } - } - - err = ZipAndRemoveDir(strMainDirName, cfg.package); + if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef)) + break; + maxSize -= bSize; + } + break; + } + + if (!err && dataBuffer && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) { + sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage); + WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg); + } + + if (dataBuffer) { + free(dataBuffer); + dataBuffer = NULL; + } + } + + err = ZipAndRemoveDir(strMainDirName, cfg.package); out: - dev_close(dev); - return err; + dev_close(dev); + return err; } #define MIN_LOG_SIZE 512 static int micron_logpage_dir(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { - int err = -1; - const char *desc = "List the supported log pages"; - eDriveModel model = UNKNOWN_MODEL; - char logbuf[MIN_LOG_SIZE]; - struct nvme_dev *dev; - int i; - - OPT_ARGS(opts) = { - OPT_END() - }; - - err = micron_parse_options(&dev, argc, argv, desc, opts, &model); - if (err < 0) - return err; - - struct nvme_supported_logs { - uint8_t log_id; - uint8_t supported; - char *desc; - } log_list[] = { - {0x00, 0, "Support Log Pages"}, - {0x01, 0, "Error Information"}, - {0x02, 0, "SMART / Health Information"}, - {0x03, 0, "Firmware Slot Information"}, - {0x04, 0, "Changed Namespace List"}, - {0x05, 0, "Commands Supported and Effects"}, - {0x06, 0, "Device Self Test"}, - {0x07, 0, "Telemetry Host-Initiated"}, - {0x08, 0, "Telemetry Controller-Initiated"}, - {0x09, 0, "Endurance Group Information"}, - {0x0A, 0, "Predictable Latency Per NVM Set"}, - {0x0B, 0, "Predictable Latency Event Aggregate"}, - {0x0C, 0, "Asymmetric Namespace Access"}, - {0x0D, 0, "Persistent Event Log"}, - {0x0E, 0, "Predictable Latency Event Aggregate"}, - {0x0F, 0, "Endurance Group Event Aggregate"}, - {0x10, 0, "Media Unit Status"}, - {0x11, 0, "Supported Capacity Configuration List"}, - {0x12, 0, "Feature Identifiers Supported and Effects"}, - {0x13, 0, "NVMe-MI Commands Supported and Effects"}, - {0x14, 0, "Command and Feature lockdown"}, - {0x15, 0, "Boot Partition"}, - {0x16, 0, "Rotational Media Information"}, - {0x70, 0, "Discovery"}, - {0x80, 0, "Reservation Notification"}, - {0x81, 0, "Sanitize Status"}, - {0xC0, 0, "SMART Cloud Health Log"}, - {0xC2, 0, "Firmware Activation History"}, - {0xC3, 0, "Latency Monitor Log"}, - }; - - printf("Supported log page list\nLog ID : Description\n"); - for (i = 0; i < sizeof(log_list)/sizeof(log_list[0]); i++) { - err = nvme_get_log_simple(dev_fd(dev), log_list[i].log_id, - MIN_LOG_SIZE, &logbuf[0]); - if (err) continue; - printf("%02Xh : %s\n", log_list[i].log_id, log_list[i].desc); - } - - return err; + int err = -1; + const char *desc = "List the supported log pages"; + enum eDriveModel model = UNKNOWN_MODEL; + char logbuf[MIN_LOG_SIZE]; + struct nvme_dev *dev; + int i; + + OPT_ARGS(opts) = { + OPT_END() + }; + + err = micron_parse_options(&dev, argc, argv, desc, opts, &model); + if (err < 0) + return err; + + struct nvme_supported_logs { + uint8_t log_id; + uint8_t supported; + char *desc; + } log_list[] = { + {0x00, 0, "Support Log Pages"}, + {0x01, 0, "Error Information"}, + {0x02, 0, "SMART / Health Information"}, + {0x03, 0, "Firmware Slot Information"}, + {0x04, 0, "Changed Namespace List"}, + {0x05, 0, "Commands Supported and Effects"}, + {0x06, 0, "Device Self Test"}, + {0x07, 0, "Telemetry Host-Initiated"}, + {0x08, 0, "Telemetry Controller-Initiated"}, + {0x09, 0, "Endurance Group Information"}, + {0x0A, 0, "Predictable Latency Per NVM Set"}, + {0x0B, 0, "Predictable Latency Event Aggregate"}, + {0x0C, 0, "Asymmetric Namespace Access"}, + {0x0D, 0, "Persistent Event Log"}, + {0x0E, 0, "Predictable Latency Event Aggregate"}, + {0x0F, 0, "Endurance Group Event Aggregate"}, + {0x10, 0, "Media Unit Status"}, + {0x11, 0, "Supported Capacity Configuration List"}, + {0x12, 0, "Feature Identifiers Supported and Effects"}, + {0x13, 0, "NVMe-MI Commands Supported and Effects"}, + {0x14, 0, "Command and Feature lockdown"}, + {0x15, 0, "Boot Partition"}, + {0x16, 0, "Rotational Media Information"}, + {0x70, 0, "Discovery"}, + {0x80, 0, "Reservation Notification"}, + {0x81, 0, "Sanitize Status"}, + {0xC0, 0, "SMART Cloud Health Log"}, + {0xC2, 0, "Firmware Activation History"}, + {0xC3, 0, "Latency Monitor Log"}, + }; + + printf("Supported log page list\nLog ID : Description\n"); + for (i = 0; i < ARRAY_SIZE(log_list); i++) { + err = nvme_get_log_simple(dev_fd(dev), log_list[i].log_id, + MIN_LOG_SIZE, &logbuf[0]); + if (err) + continue; + printf("%02Xh : %s\n", log_list[i].log_id, log_list[i].desc); + } + + return err; } diff --git a/plugins/nbft/nbft-plugin.c b/plugins/nbft/nbft-plugin.c new file mode 100644 index 0000000000..2193ffb535 --- /dev/null +++ b/plugins/nbft/nbft-plugin.c @@ -0,0 +1,563 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "nvme-print.h" +#include "nvme.h" +#include "nbft.h" +#include "libnvme.h" +#include "fabrics.h" + +#define CREATE_CMD +#include "nbft-plugin.h" + +static const char dash[100] = {[0 ... 98] = '-', [99] = '\0'}; + +#define PCI_SEGMENT(sbdf) ((sbdf & 0xffff0000) >> 16) +#define PCI_BUS(sbdf) ((sbdf & 0x0000ff00) >> 8) +#define PCI_DEV(sbdf) ((sbdf & 0x000000f8) >> 3) +#define PCI_FUNC(sbdf) ((sbdf & 0x00000007) >> 0) + +static const char *pci_sbdf_to_string(__u16 pci_sbdf) +{ + static char pcidev[13]; + + snprintf(pcidev, sizeof(pcidev), "%x:%x:%x.%x", + PCI_SEGMENT(pci_sbdf), + PCI_BUS(pci_sbdf), + PCI_DEV(pci_sbdf), + PCI_FUNC(pci_sbdf)); + return pcidev; +} + +static char *mac_addr_to_string(unsigned char mac_addr[6]) +{ + static char mac_string[18]; + + snprintf(mac_string, sizeof(mac_string), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], + mac_addr[1], + mac_addr[2], + mac_addr[3], + mac_addr[4], + mac_addr[5]); + return mac_string; +} + +static json_object *hfi_to_json(struct nbft_info_hfi *hfi) +{ + struct json_object *hfi_json; + + hfi_json = json_create_object(); + if (!hfi_json) + return NULL; + + if (json_object_add_value_int(hfi_json, "index", hfi->index) + || json_object_add_value_string(hfi_json, "transport", hfi->transport)) + goto fail; + + if (strcmp(hfi->transport, "tcp") == 0) { + if (json_object_add_value_string(hfi_json, "pcidev", + pci_sbdf_to_string(hfi->tcp_info.pci_sbdf)) + || json_object_add_value_string(hfi_json, "mac_addr", + mac_addr_to_string(hfi->tcp_info.mac_addr)) + || json_object_add_value_int(hfi_json, "vlan", + hfi->tcp_info.vlan) + || json_object_add_value_int(hfi_json, "ip_origin", + hfi->tcp_info.ip_origin) + || json_object_add_value_string(hfi_json, "ipaddr", + hfi->tcp_info.ipaddr) + || json_object_add_value_int(hfi_json, "subnet_mask_prefix", + hfi->tcp_info.subnet_mask_prefix) + || json_object_add_value_string(hfi_json, "gateway_ipaddr", + hfi->tcp_info.gateway_ipaddr) + || json_object_add_value_int(hfi_json, "route_metric", + hfi->tcp_info.route_metric) + || json_object_add_value_string(hfi_json, "primary_dns_ipaddr", + hfi->tcp_info.primary_dns_ipaddr) + || json_object_add_value_string(hfi_json, "secondary_dns_ipaddr", + hfi->tcp_info.secondary_dns_ipaddr) + || json_object_add_value_string(hfi_json, "dhcp_server_ipaddr", + hfi->tcp_info.dhcp_server_ipaddr) + || (hfi->tcp_info.host_name + && json_object_add_value_string(hfi_json, "host_name", + hfi->tcp_info.host_name)) + || json_object_add_value_int(hfi_json, "this_hfi_is_default_route", + hfi->tcp_info.this_hfi_is_default_route) + || json_object_add_value_int(hfi_json, "dhcp_override", + hfi->tcp_info.dhcp_override)) + goto fail; + else + return hfi_json; + } +fail: + json_free_object(hfi_json); + return NULL; +} + +static json_object *ssns_to_json(struct nbft_info_subsystem_ns *ss) +{ + struct json_object *ss_json; + struct json_object *hfi_array_json; + char json_str[40]; + char *json_str_p; + int i; + + ss_json = json_create_object(); + if (!ss_json) + return NULL; + + hfi_array_json = json_create_array(); + if (!hfi_array_json) + goto fail; + + for (i = 0; i < ss->num_hfis; i++) + if (json_array_add_value_object(hfi_array_json, + json_object_new_int(ss->hfis[i]->index))) + goto fail; + + if (json_object_add_value_int(ss_json, "index", ss->index) + || json_object_add_value_int(ss_json, "num_hfis", ss->num_hfis) + || json_object_object_add(ss_json, "hfis", hfi_array_json) + || json_object_add_value_string(ss_json, "transport", ss->transport) + || json_object_add_value_string(ss_json, "traddr", ss->traddr) + || json_object_add_value_string(ss_json, "trsvcid", ss->trsvcid) + || json_object_add_value_int(ss_json, "subsys_port_id", ss->subsys_port_id) + || json_object_add_value_int(ss_json, "nsid", ss->nsid)) + goto fail; + + memset(json_str, 0, sizeof(json_str)); + json_str_p = json_str; + + switch (ss->nid_type) { + case NBFT_INFO_NID_TYPE_EUI64: + if (json_object_add_value_string(ss_json, "nid_type", "eui64")) + goto fail; + for (i = 0; i < 8; i++) + json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]); + break; + + case NBFT_INFO_NID_TYPE_NGUID: + if (json_object_add_value_string(ss_json, "nid_type", "nguid")) + goto fail; + for (i = 0; i < 16; i++) + json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]); + break; + + case NBFT_INFO_NID_TYPE_NS_UUID: + if (json_object_add_value_string(ss_json, "nid_type", "uuid")) + goto fail; + nvme_uuid_to_string(ss->nid, json_str); + break; + + default: + break; + } + if (json_object_add_value_string(ss_json, "nid", json_str)) + goto fail; + + if ((ss->subsys_nqn + && json_object_add_value_string(ss_json, "subsys_nqn", ss->subsys_nqn)) + || json_object_add_value_int(ss_json, "controller_id", ss->controller_id) + || json_object_add_value_int(ss_json, "asqsz", ss->asqsz) + || (ss->dhcp_root_path_string + && json_object_add_value_string(ss_json, "dhcp_root_path_string", + ss->dhcp_root_path_string)) + || json_object_add_value_int(ss_json, "pdu_header_digest_required", + ss->pdu_header_digest_required) + || json_object_add_value_int(ss_json, "data_digest_required", + ss->data_digest_required)) + goto fail; + + return ss_json; +fail: + json_free_object(ss_json); + return NULL; +} + +static json_object *discovery_to_json(struct nbft_info_discovery *disc) +{ + struct json_object *disc_json; + + disc_json = json_create_object(); + if (!disc_json) + return NULL; + + if (json_object_add_value_int(disc_json, "index", disc->index) + || (disc->security + && json_object_add_value_int(disc_json, "security", disc->security->index)) + || (disc->hfi + && json_object_add_value_int(disc_json, "hfi", disc->hfi->index)) + || (disc->uri + && json_object_add_value_string(disc_json, "uri", disc->uri)) + || (disc->nqn + && json_object_add_value_string(disc_json, "nqn", disc->nqn))) { + json_free_object(disc_json); + return NULL; + } else + return disc_json; +} + +static const char *primary_admin_host_flag_to_str(unsigned int primary) +{ + static const char * const str[] = { + [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED] = "not indicated", + [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED] = "unselected", + [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED] = "selected", + [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED] = "reserved", + }; + + if (primary > NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED) + return "INVALID"; + return str[primary]; +} + +static struct json_object *nbft_to_json(struct nbft_info *nbft, bool show_subsys, + bool show_hfi, bool show_discovery) +{ + struct json_object *nbft_json, *host_json; + + nbft_json = json_create_object(); + if (!nbft_json) + return NULL; + + if (json_object_add_value_string(nbft_json, "filename", nbft->filename)) + goto fail; + + host_json = json_create_object(); + if (!host_json) + goto fail; + if ((nbft->host.nqn + && json_object_add_value_string(host_json, "nqn", nbft->host.nqn)) + || (nbft->host.id + && json_object_add_value_string(host_json, "id", + util_uuid_to_string(nbft->host.id)))) + goto fail; + json_object_add_value_int(host_json, "host_id_configured", + nbft->host.host_id_configured); + json_object_add_value_int(host_json, "host_nqn_configured", + nbft->host.host_nqn_configured); + json_object_add_value_string(host_json, "primary_admin_host_flag", + primary_admin_host_flag_to_str(nbft->host.primary)); + if (json_object_object_add(nbft_json, "host", host_json)) { + json_free_object(host_json); + goto fail; + } + + if (show_subsys) { + struct json_object *subsys_array_json, *subsys_json; + struct nbft_info_subsystem_ns **ss; + + subsys_array_json = json_create_array(); + if (!subsys_array_json) + goto fail; + for (ss = nbft->subsystem_ns_list; ss && *ss; ss++) { + subsys_json = ssns_to_json(*ss); + if (!subsys_json) + goto fail; + if (json_object_array_add(subsys_array_json, subsys_json)) { + json_free_object(subsys_json); + goto fail; + } + } + if (json_object_object_add(nbft_json, "subsystem", subsys_array_json)) { + json_free_object(subsys_array_json); + goto fail; + } + } + if (show_hfi) { + struct json_object *hfi_array_json, *hfi_json; + struct nbft_info_hfi **hfi; + + hfi_array_json = json_create_array(); + if (!hfi_array_json) + goto fail; + for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) { + hfi_json = hfi_to_json(*hfi); + if (!hfi_json) + goto fail; + if (json_object_array_add(hfi_array_json, hfi_json)) { + json_free_object(hfi_json); + goto fail; + } + } + if (json_object_object_add(nbft_json, "hfi", hfi_array_json)) { + json_free_object(hfi_array_json); + goto fail; + } + } + if (show_discovery) { + struct json_object *discovery_array_json, *discovery_json; + struct nbft_info_discovery **disc; + + discovery_array_json = json_create_array(); + if (!discovery_array_json) + goto fail; + for (disc = nbft->discovery_list; disc && *disc; disc++) { + discovery_json = discovery_to_json(*disc); + if (!discovery_json) + goto fail; + if (json_object_array_add(discovery_array_json, discovery_json)) { + json_free_object(discovery_json); + goto fail; + } + } + if (json_object_object_add(nbft_json, "discovery", discovery_array_json)) { + json_free_object(discovery_array_json); + goto fail; + } + } + return nbft_json; +fail: + json_free_object(nbft_json); + return NULL; +} + +static int json_show_nbfts(struct list_head *nbft_list, bool show_subsys, + bool show_hfi, bool show_discovery) +{ + struct json_object *nbft_json_array, *nbft_json; + struct nbft_file_entry *entry; + + nbft_json_array = json_create_array(); + if (!nbft_json_array) + return -ENOMEM; + + list_for_each(nbft_list, entry, node) { + nbft_json = nbft_to_json(entry->nbft, show_subsys, show_hfi, show_discovery); + if (!nbft_json) + goto fail; + if (json_object_array_add(nbft_json_array, nbft_json)) { + json_free_object(nbft_json); + goto fail; + } + } + + json_print_object(nbft_json_array, NULL); + printf("\n"); + json_free_object(nbft_json_array); + return 0; +fail: + json_free_object(nbft_json_array); + return -ENOMEM; +} + +static void print_nbft_hfi_info(struct nbft_info *nbft) +{ + struct nbft_info_hfi **hfi; + unsigned int ip_width = 8, gw_width = 8, dns_width = 8; + + hfi = nbft->hfi_list; + if (!hfi || !*hfi) + return; + + for (; *hfi; hfi++) { + unsigned int len; + + len = strlen((*hfi)->tcp_info.ipaddr); + if (len > ip_width) + ip_width = len; + len = strlen((*hfi)->tcp_info.gateway_ipaddr); + if (len > gw_width) + gw_width = len; + len = strlen((*hfi)->tcp_info.primary_dns_ipaddr); + if (len > dns_width) + dns_width = len; + } + + printf("\nNBFT HFIs:\n\n"); + printf("%-3.3s|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4.4s|%-*.*s|%-*.*s\n", + "Idx", "Trsp", "PCI Addr", "MAC Addr", "DHCP", + ip_width, ip_width, "IP Addr", "Mask", + gw_width, gw_width, "Gateway", dns_width, dns_width, "DNS"); + printf("%-.3s+%-.4s+%-.10s+%-.17s+%-.4s+%-.*s+%-.4s+%-.*s+%-.*s\n", + dash, dash, dash, dash, dash, ip_width, dash, dash, + gw_width, dash, dns_width, dash); + for (hfi = nbft->hfi_list; *hfi; hfi++) + printf("%-3d|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4d|%-*.*s|%-*.*s\n", + (*hfi)->index, + (*hfi)->transport, + pci_sbdf_to_string((*hfi)->tcp_info.pci_sbdf), + mac_addr_to_string((*hfi)->tcp_info.mac_addr), + (*hfi)->tcp_info.dhcp_override ? "yes" : "no", + ip_width, ip_width, (*hfi)->tcp_info.ipaddr, + (*hfi)->tcp_info.subnet_mask_prefix, + gw_width, gw_width, (*hfi)->tcp_info.gateway_ipaddr, + dns_width, dns_width, (*hfi)->tcp_info.primary_dns_ipaddr); +} + +static void print_nbft_discovery_info(struct nbft_info *nbft) +{ + struct nbft_info_discovery **disc; + unsigned int nqn_width = 20, uri_width = 12; + + disc = nbft->discovery_list; + if (!disc || !*disc) + return; + + for (; *disc; disc++) { + size_t len; + + len = strlen((*disc)->uri); + if (len > uri_width) + uri_width = len; + len = strlen((*disc)->nqn); + if (len > nqn_width) + nqn_width = len; + } + + printf("\nNBFT Discovery Controllers:\n\n"); + printf("%-3.3s|%-*.*s|%-*.*s\n", "Idx", uri_width, uri_width, "URI", + nqn_width, nqn_width, "NQN"); + printf("%-.3s+%-.*s+%-.*s\n", dash, uri_width, dash, nqn_width, dash); + for (disc = nbft->discovery_list; *disc; disc++) + printf("%-3d|%-*.*s|%-*.*s\n", (*disc)->index, + uri_width, uri_width, (*disc)->uri, + nqn_width, nqn_width, (*disc)->nqn); +} + +#define HFIS_LEN 20 +static size_t print_hfis(const struct nbft_info_subsystem_ns *ss, char buf[HFIS_LEN]) +{ + char hfi_buf[HFIS_LEN]; + size_t len, ofs; + int i; + + len = snprintf(hfi_buf, sizeof(hfi_buf), "%d", ss->hfis[0]->index); + for (i = 1; i < ss->num_hfis; i++) { + ofs = len; + len += snprintf(hfi_buf + ofs, sizeof(hfi_buf) - ofs, ",%d", + ss->hfis[i]->index); + /* + * If the list doesn't fit in HFIS_LEN characters, + * truncate and end with "..." + */ + if (len >= sizeof(hfi_buf)) { + while (ofs < sizeof(hfi_buf) - 1) + hfi_buf[ofs++] = '.'; + hfi_buf[ofs] = '\0'; + len = sizeof(hfi_buf) - 1; + break; + } + } + if (buf) + memcpy(buf, hfi_buf, len + 1); + return len; +} + + +static void print_nbft_subsys_info(struct nbft_info *nbft) +{ + struct nbft_info_subsystem_ns **ss; + unsigned int nqn_width = 20, adr_width = 8, hfi_width = 4; + + ss = nbft->subsystem_ns_list; + if (!ss || !*ss) + return; + for (; *ss; ss++) { + size_t len; + + len = strlen((*ss)->subsys_nqn); + if (len > nqn_width) + nqn_width = len; + len = strlen((*ss)->traddr); + if (len > adr_width) + adr_width = len; + len = print_hfis(*ss, NULL); + if (len > hfi_width) + hfi_width = len; + } + + printf("\nNBFT Subsystems:\n\n"); + printf("%-3.3s|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n", + "Idx", nqn_width, nqn_width, "NQN", + "Trsp", adr_width, adr_width, "Address", "SvcId", hfi_width, hfi_width, "HFIs"); + printf("%-.3s+%-.*s+%-.4s+%-.*s+%-.5s+%-.*s\n", + dash, nqn_width, dash, dash, adr_width, dash, dash, hfi_width, dash); + for (ss = nbft->subsystem_ns_list; *ss; ss++) { + char hfi_buf[HFIS_LEN]; + + print_hfis(*ss, hfi_buf); + printf("%-3d|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n", + (*ss)->index, nqn_width, nqn_width, (*ss)->subsys_nqn, + (*ss)->transport, adr_width, adr_width, (*ss)->traddr, + (*ss)->trsvcid, hfi_width, hfi_width, hfi_buf); + } +} + +static void normal_show_nbft(struct nbft_info *nbft, bool show_subsys, + bool show_hfi, bool show_discovery) +{ + printf("%s:\n", nbft->filename); + if ((!nbft->hfi_list || !*nbft->hfi_list) && + (!nbft->security_list || !*nbft->security_list) && + (!nbft->discovery_list || !*nbft->discovery_list) && + (!nbft->subsystem_ns_list || !*nbft->subsystem_ns_list)) + printf("(empty)\n"); + else { + if (show_subsys) + print_nbft_subsys_info(nbft); + if (show_hfi) + print_nbft_hfi_info(nbft); + if (show_discovery) + print_nbft_discovery_info(nbft); + } +} + +static void normal_show_nbfts(struct list_head *nbft_list, bool show_subsys, + bool show_hfi, bool show_discovery) +{ + bool not_first = false; + struct nbft_file_entry *entry; + + list_for_each(nbft_list, entry, node) { + if (not_first) + printf("\n"); + normal_show_nbft(entry->nbft, show_subsys, show_hfi, show_discovery); + not_first = true; + } +} + +int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Display contents of the ACPI NBFT files."; + struct list_head nbft_list; + char *format = "normal"; + char *nbft_path = NBFT_SYSFS_PATH; + enum nvme_print_flags flags; + int ret; + bool show_subsys = false, show_hfi = false, show_discovery = false; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &format, "Output format: normal|json"), + OPT_FLAG("subsystem", 's', &show_subsys, "show NBFT subsystems"), + OPT_FLAG("hfi", 'H', &show_hfi, "show NBFT HFIs"), + OPT_FLAG("discovery", 'd', &show_discovery, "show NBFT discovery controllers"), + OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"), + OPT_END() + }; + + ret = argconfig_parse(argc, argv, desc, opts); + if (ret) + return ret; + + ret = validate_output_format(format, &flags); + if (ret < 0) + return ret; + + if (!(show_subsys || show_hfi || show_discovery)) + show_subsys = show_hfi = show_discovery = true; + + list_head_init(&nbft_list); + ret = read_nbft_files(&nbft_list, nbft_path); + if (!ret) { + if (flags == NORMAL) + normal_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery); + else if (flags == JSON) + ret = json_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery); + free_nbfts(&nbft_list); + } + return ret; +} diff --git a/plugins/nbft/nbft-plugin.h b/plugins/nbft/nbft-plugin.h new file mode 100644 index 0000000000..018349d961 --- /dev/null +++ b/plugins/nbft/nbft-plugin.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/nbft/nbft-plugin + +#if !defined(NBFT) || defined(CMD_HEADER_MULTI_READ) +#define NBFT + +#include "cmd.h" + +PLUGIN(NAME("nbft", "ACPI NBFT table extensions", NVME_VERSION), + COMMAND_LIST( + ENTRY("show", "Show contents of ACPI NBFT tables", show_nbft) + ) +); + +#endif + +#include "define_cmd.h" diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c index b6bd3f689c..99f0a20df4 100644 --- a/plugins/netapp/netapp-nvme.c +++ b/plugins/netapp/netapp-nvme.c @@ -1,18 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) 2018 NetApp, Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -*/ + * 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 #include @@ -22,7 +22,6 @@ #include #include #include -#include #include "common.h" #include "nvme.h" @@ -47,28 +46,30 @@ enum { enum { ONTAP_C2_LOG_SUPPORTED_LSP = 0x0, ONTAP_C2_LOG_NSINFO_LSP = 0x1, + ONTAP_C2_LOG_PLATFORM_LSP = 0x2, }; enum { - ONTAP_VSERVER_TLV = 0x11, - ONTAP_VOLUME_TLV = 0x12, - ONTAP_NS_TLV = 0x13, + ONTAP_VSERVER_NAME_TLV = 0x11, + ONTAP_VOLUME_NAME_TLV = 0x12, + ONTAP_NS_NAME_TLV = 0x13, + ONTAP_NS_PATH_TLV = 0x14, }; static const char *dev_path = "/dev/"; struct smdevice_info { - unsigned nsid; + unsigned int nsid; struct nvme_id_ctrl ctrl; struct nvme_id_ns ns; char dev[265]; }; struct ontapdevice_info { - unsigned nsid; + unsigned int nsid; struct nvme_id_ctrl ctrl; struct nvme_id_ns ns; - uuid_t uuid; + unsigned char uuid[NVME_UUID_LEN]; unsigned char log_data[ONTAP_C2_LOG_SIZE]; char dev[265]; }; @@ -108,6 +109,7 @@ static void netapp_get_ns_size(char *size, unsigned long long *lba, struct nvme_id_ns *ns) { __u8 lba_index; + nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index); *lba = 1ULL << ns->lbaf[lba_index].ds; double nsze = le64_to_cpu(ns->nsze) * (*lba); @@ -134,8 +136,10 @@ 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 *vserver_name, *volume_name, *namespace_name, *namespace_path; char vol_name[ONTAP_LABEL_LEN], ns_name[ONTAP_LABEL_LEN]; + char ns_path[ONTAP_LABEL_LEN]; + bool nspath_tlv_available = false; const char *ontap_vol = "/vol/"; int i, j; @@ -145,9 +149,9 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath, /* lsp not related to nsinfo */ return; - /* get the vserver tlv and name */ + /* get the vserver name tlv */ tlv = *(__u8 *)&log_data[32]; - if (tlv == ONTAP_VSERVER_TLV) { + if (tlv == ONTAP_VSERVER_NAME_TLV) { label_len = (*(__u16 *)&log_data[34]) * 4; vserver_name = (char *)&log_data[36]; ontap_labels_to_str(vsname, vserver_name, label_len); @@ -159,9 +163,9 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath, i = 36 + label_len; j = i + 2; - /* get the volume tlv and name */ + /* get the volume name tlv */ tlv = *(__u8 *)&log_data[i]; - if (tlv == ONTAP_VOLUME_TLV) { + if (tlv == ONTAP_VOLUME_NAME_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); @@ -173,9 +177,9 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath, i += 4 + label_len; j += 4 + label_len; - /* get the namespace tlv and name */ + /* get the namespace name tlv */ tlv = *(__u8 *)&log_data[i]; - if (tlv == ONTAP_NS_TLV) { + if (tlv == ONTAP_NS_NAME_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); @@ -185,8 +189,25 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath, return; } - snprintf(nspath, ONTAP_NS_PATHLEN, "%s%s%s%s", ontap_vol, + i += 4 + label_len; + j += 4 + label_len; + /* get the namespace path tlv if available */ + tlv = *(__u8 *)&log_data[i]; + if (tlv == ONTAP_NS_PATH_TLV) { + nspath_tlv_available = true; + label_len = (*(__u16 *)&log_data[j]) * 4; + namespace_path = (char *)&log_data[j + 2]; + ontap_labels_to_str(ns_path, namespace_path, label_len); + } + + if (nspath_tlv_available) { + /* set nspath from the corresponding ns_path string */ + snprintf(nspath, ONTAP_NS_PATHLEN, "%s", ns_path); + } else { + /* set nspath by concatenating ontap_vol with ns_name */ + snprintf(nspath, ONTAP_NS_PATHLEN, "%s%s%s%s", ontap_vol, vol_name, "/", ns_name); + } } static void netapp_smdevice_json(struct json_object *devices, char *devname, @@ -238,8 +259,8 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int 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 basestr[] = + "%s, Array Name %s, Volume Name %s, NSID %d, Volume ID %s, Controller %c, Access State %s, %s\n"; char columnstr[] = "%-16s %-30s %-30s %4d %32s %c %-12s %9s\n"; char *formatstr = basestr; /* default to "normal" output format */ __u8 lba_index; @@ -255,8 +276,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int "------------------------------", "----", "--------------------------------", "----", "------------", "---------"); - } - else if (format == NJSON) { + } else if (format == NJSON) { /* prepare for json output */ root = json_create_object(); json_devices = json_create_array(); @@ -264,7 +284,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int for (i = 0; i < count; i++) { nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas, &lba_index); - unsigned long long int lba = 1ULL << devices[i].ns.lbaf[lba_index].ds; + unsigned long long lba = 1ULL << devices[i].ns.lbaf[lba_index].ds; double nsze = le64_to_cpu(devices[i].ns.nsze) * lba; const char *s_suffix = suffix_si_get(&nsze); char size[128]; @@ -334,7 +354,7 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices, for (i = 0; i < count; i++) { netapp_get_ns_size(size, &lba, &devices[i].ns); - uuid_unparse_lower(devices[i].uuid, uuid_str); + nvme_uuid_to_string(devices[i].uuid, uuid_str); netapp_get_ontap_labels(vsname, nspath, devices[i].log_data); if (format == NJSON) { @@ -465,7 +485,7 @@ static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item, err = nvme_get_ontap_c2_log(fd, item->nsid, item->log_data, ONTAP_C2_LOG_SIZE); if (err) { fprintf(stderr, "Unable to get log page data for %s (%s)\n", - dev, err < 0 ? strerror(-err): + dev, err < 0 ? strerror(-err) : nvme_status_to_string(err, false)); return 0; } @@ -554,7 +574,7 @@ static int netapp_smdevices(int argc, char **argv, struct command *command, smdevices = calloc(num, sizeof(*smdevices)); if (!smdevices) { fprintf(stderr, "Unable to allocate memory for devices.\n"); - return ENOMEM; + return -ENOMEM; } for (i = 0; i < num; i++) { diff --git a/plugins/ocp/meson.build b/plugins/ocp/meson.build new file mode 100644 index 0000000000..64447ff66c --- /dev/null +++ b/plugins/ocp/meson.build @@ -0,0 +1,8 @@ +sources += [ + 'plugins/ocp/ocp-utils.c', + 'plugins/ocp/ocp-nvme.c', + 'plugins/ocp/ocp-clear-features.c', + 'plugins/ocp/ocp-smart-extended-log.c', + 'plugins/ocp/ocp-fw-activation-history.c', +] + diff --git a/plugins/ocp/ocp-clear-features.c b/plugins/ocp/ocp-clear-features.c new file mode 100644 index 0000000000..0f49584db9 --- /dev/null +++ b/plugins/ocp/ocp-clear-features.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Solidigm. + * + * Authors: haro.panosyan@solidigm.com + * leonardo.da.cunha@solidigm.com + */ + +#include +#include "ocp-utils.h" +#include "nvme-print.h" + +static const __u8 OCP_FID_CLEAR_FW_ACTIVATION_HISTORY = 0xC1; +static const __u8 OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS = 0xC3; + +static int ocp_clear_feature(int argc, char **argv, const char *desc, const __u8 fid) +{ + __u32 result = 0; + __u32 clear = 1 << 31; + struct nvme_dev *dev; + int uuid_index = 0; + bool uuid = true; + int err; + + OPT_ARGS(opts) = { + OPT_FLAG("no-uuid", 'n', NULL, + "Skip UUID index search (UUID index not required for OCP 1.0)"), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (opts[0].seen) + uuid = false; + + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &uuid_index); + if (err || !uuid_index) { + fprintf(stderr, "ERROR: No OCP UUID index found\n"); + goto close_dev; + } + } + + struct nvme_set_features_args args = { + .result = &result, + .data = NULL, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .nsid = 0, + .cdw11 = clear, + .cdw12 = 0, + .cdw13 = 0, + .cdw15 = 0, + .data_len = 0, + .save = 0, + .uuidx = uuid_index, + .fid = fid, + }; + + err = nvme_set_features(&args); + + if (err == 0) + printf("Success : %s\n", desc); + else if (err > 0) + nvme_show_status(err); + else + printf("Fail : %s\n", desc); +close_dev: + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); + dev_close(dev); + return err; +} + +int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "OCP Clear Firmware Update History"; + + return ocp_clear_feature(argc, argv, desc, OCP_FID_CLEAR_FW_ACTIVATION_HISTORY); +} + +int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "OCP Clear PCIe Correctable Error Counters"; + + return ocp_clear_feature(argc, argv, desc, + OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS); +} diff --git a/plugins/ocp/ocp-clear-features.h b/plugins/ocp/ocp-clear-features.h new file mode 100644 index 0000000000..99766dd888 --- /dev/null +++ b/plugins/ocp/ocp-clear-features.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022 Solidigm. + * + * Authors: haro.panosyan@solidigm.com + * leonardo.da.cunha@solidigm.com + */ + +int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin); + +int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd, + struct plugin *plugin); diff --git a/plugins/ocp/ocp-fw-activation-history.c b/plugins/ocp/ocp-fw-activation-history.c new file mode 100644 index 0000000000..9f1f7f5b7a --- /dev/null +++ b/plugins/ocp/ocp-fw-activation-history.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Solidigm. + * + * Author: karl.dedow@solidigm.com + */ + +#include "ocp-fw-activation-history.h" + +#include +#include + +#include "common.h" +#include "nvme-print.h" + +#include "ocp-utils.h" + +static const unsigned char ocp_fw_activation_history_guid[16] = { + 0x6D, 0x79, 0x9a, 0x76, + 0xb4, 0xda, 0xf6, 0xa3, + 0xe2, 0x4d, 0xb2, 0x8a, + 0xac, 0xf3, 0x1c, 0xd1 +}; + +struct __packed fw_activation_history_entry { + __u8 ver_num; + __u8 entry_length; + __u16 reserved1; + __u16 activation_count; + __u64 timestamp; + __u64 reserved2; + __u64 power_cycle_count; + char previous_fw[8]; + char new_fw[8]; + __u8 slot_number; + __u8 commit_action; + __u16 result; + __u8 reserved3[14]; +}; + +struct __packed fw_activation_history { + __u8 log_id; + __u8 reserved1[3]; + __u32 valid_entries; + struct fw_activation_history_entry entries[20]; + __u8 reserved2[2790]; + __u16 log_page_version; + __u64 log_page_guid[2]; +}; + +static void ocp_fw_activation_history_normal(const struct fw_activation_history *fw_history) +{ + printf("Firmware History Log:\n"); + + printf(" %-26s%d\n", "log identifier:", fw_history->log_id); + printf(" %-26s%d\n", "valid entries:", le32_to_cpu(fw_history->valid_entries)); + + printf(" entries:\n"); + + for (int index = 0; index < fw_history->valid_entries; index++) { + const struct fw_activation_history_entry *entry = &fw_history->entries[index]; + + printf(" entry[%d]:\n", le32_to_cpu(index)); + printf(" %-22s%d\n", "version number:", entry->ver_num); + printf(" %-22s%d\n", "entry length:", entry->entry_length); + printf(" %-22s%d\n", "activation count:", + le16_to_cpu(entry->activation_count)); + printf(" %-22s%"PRIu64"\n", "timestamp:", + (0x0000FFFFFFFFFFFF & le64_to_cpu(entry->timestamp))); + printf(" %-22s%"PRIu64"\n", "power cycle count:", + le64_to_cpu(entry->power_cycle_count)); + printf(" %-22s%.*s\n", "previous firmware:", (int)sizeof(entry->previous_fw), + entry->previous_fw); + printf(" %-22s%.*s\n", "new firmware:", (int)sizeof(entry->new_fw), + entry->new_fw); + printf(" %-22s%d\n", "slot number:", entry->slot_number); + printf(" %-22s%d\n", "commit action type:", entry->commit_action); + printf(" %-22s%d\n", "result:", le16_to_cpu(entry->result)); + } + + printf(" %-26s%d\n", "log page version:", + le16_to_cpu(fw_history->log_page_version)); + + printf(" %-26s0x%"PRIx64"%"PRIx64"\n", "log page guid:", + le64_to_cpu(fw_history->log_page_guid[1]), + le64_to_cpu(fw_history->log_page_guid[0])); + + printf("\n"); +} + +static void ocp_fw_activation_history_json(const struct fw_activation_history *fw_history) +{ + struct json_object *root = json_create_object(); + + json_object_add_value_uint(root, "log identifier", fw_history->log_id); + json_object_add_value_uint(root, "valid entries", le32_to_cpu(fw_history->valid_entries)); + + struct json_object *entries = json_create_array(); + + for (int index = 0; index < fw_history->valid_entries; index++) { + const struct fw_activation_history_entry *entry = &fw_history->entries[index]; + struct json_object *entry_obj = json_create_object(); + + json_object_add_value_uint(entry_obj, "version number", entry->ver_num); + json_object_add_value_uint(entry_obj, "entry length", entry->entry_length); + json_object_add_value_uint(entry_obj, "activation count", + le16_to_cpu(entry->activation_count)); + json_object_add_value_uint64(entry_obj, "timestamp", + (0x0000FFFFFFFFFFFF & le64_to_cpu(entry->timestamp))); + json_object_add_value_uint(entry_obj, "power cycle count", + le64_to_cpu(entry->power_cycle_count)); + + struct json_object *fw = json_object_new_string_len(entry->previous_fw, + sizeof(entry->previous_fw)); + + json_object_add_value_object(entry_obj, "previous firmware", fw); + + fw = json_object_new_string_len(entry->new_fw, sizeof(entry->new_fw)); + + json_object_add_value_object(entry_obj, "new firmware", fw); + json_object_add_value_uint(entry_obj, "slot number", entry->slot_number); + json_object_add_value_uint(entry_obj, "commit action type", entry->commit_action); + json_object_add_value_uint(entry_obj, "result", le16_to_cpu(entry->result)); + + json_array_add_value_object(entries, entry_obj); + } + + json_object_add_value_array(root, "entries", entries); + + json_object_add_value_uint(root, "log page version", + le16_to_cpu(fw_history->log_page_version)); + + char guid[2 * sizeof(fw_history->log_page_guid) + 3] = { 0 }; + + sprintf(guid, "0x%"PRIx64"%"PRIx64"", + le64_to_cpu(fw_history->log_page_guid[1]), + le64_to_cpu(fw_history->log_page_guid[0])); + json_object_add_value_string(root, "log page guid", guid); + + json_print_object(root, NULL); + json_free_object(root); + + printf("\n"); +} + +int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const __u8 log_id = 0xC2; + const char *description = "Retrieves the OCP firmware activation history log."; + + char *format = "normal"; + + OPT_ARGS(options) = { + OPT_FMT("output-format", 'o', &format, "output format : normal | json"), + OPT_END() + }; + + struct nvme_dev *dev = NULL; + int err = parse_and_open(&dev, argc, argv, description, options); + + if (err) + return err; + + int uuid_index = 0; + + /* + * Best effort attempt at uuid. Otherwise, assume no index (i.e. 0) + * Log GUID check will ensure correctness of returned data + */ + ocp_get_uuid_index(dev, &uuid_index); + + struct fw_activation_history fw_history = { 0 }; + + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = &fw_history, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = log_id, + .len = sizeof(fw_history), + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = 0, + .uuidx = uuid_index, + .rae = false, + .ot = false, + }; + + err = nvme_get_log(&args); + + if (err) + nvme_show_status(err); + + dev_close(dev); + + int guid_cmp_res = memcmp(fw_history.log_page_guid, ocp_fw_activation_history_guid, + sizeof(ocp_fw_activation_history_guid)); + + if (!err && guid_cmp_res) { + fprintf(stderr, + "Error: Unexpected data. Log page guid does not match with expected.\n"); + err = -EINVAL; + } + + if (!err) { + enum nvme_print_flags print_flag; + + err = validate_output_format(format, &print_flag); + if (err < 0) { + fprintf(stderr, "Error: Invalid output format.\n"); + return err; + } + + if (print_flag == JSON) + ocp_fw_activation_history_json(&fw_history); + else if (print_flag == NORMAL) + ocp_fw_activation_history_normal(&fw_history); + } + + return err; +} diff --git a/plugins/ocp/ocp-fw-activation-history.h b/plugins/ocp/ocp-fw-activation-history.h new file mode 100644 index 0000000000..a7f9058803 --- /dev/null +++ b/plugins/ocp/ocp-fw-activation-history.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022 Solidigm. + * + * Authors: karl.dedow@solidigm.com + */ + +#ifndef OCP_FIRMWARE_ACTIVATION_HISTORY_H +#define OCP_FIRMWARE_ACTIVATION_HISTORY_H + +struct command; +struct plugin; + +int ocp_fw_activation_history_log(int argc, char **argv, + struct command *cmd, struct plugin *plugin); + +#endif diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c index 0cb678c98e..53ae0f40c4 100644 --- a/plugins/ocp/ocp-nvme.c +++ b/plugins/ocp/ocp-nvme.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (c) 2022 Meta Platforms, Inc. +/* + * Copyright (c) 2023 Meta Platforms, Inc. * - * Authors: Arthur Shau , - * Wei Zhang , - * Venkat Ramesh + * Authors: Arthur Shau , + * Wei Zhang , + * Venkat Ramesh */ #include #include @@ -13,765 +14,2958 @@ #include #include #include +#include #include "common.h" #include "nvme.h" #include "libnvme.h" #include "plugin.h" #include "linux/types.h" +#include "util/types.h" #include "nvme-print.h" +#include "ocp-smart-extended-log.h" +#include "ocp-clear-features.h" +#include "ocp-fw-activation-history.h" + #define CREATE_CMD #include "ocp-nvme.h" +#include "ocp-utils.h" + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Latency Monitor Log + +#define C3_LATENCY_MON_LOG_BUF_LEN 0x200 +#define C3_LATENCY_MON_OPCODE 0xC3 +#define C3_LATENCY_MON_VERSION 0x0001 +#define C3_GUID_LENGTH 16 +#define NVME_FEAT_OCP_LATENCY_MONITOR 0xC5 + +#define C3_ACTIVE_BUCKET_TIMER_INCREMENT 5 +#define C3_ACTIVE_THRESHOLD_INCREMENT 5 +#define C3_MINIMUM_WINDOW_INCREMENT 100 +#define C3_BUCKET_NUM 4 + +static __u8 lat_mon_guid[C3_GUID_LENGTH] = { + 0x92, 0x7a, 0xc0, 0x8c, + 0xd0, 0x84, 0x6c, 0x9c, + 0x70, 0x43, 0xe6, 0xd4, + 0x58, 0x5e, 0xd4, 0x85 +}; + +#define READ 3 +#define WRITE 2 +#define TRIM 1 +#define RESERVED 0 + +struct __packed ssd_latency_monitor_log { + __u8 feature_status; /* 0x00 */ + __u8 rsvd1; /* 0x01 */ + __le16 active_bucket_timer; /* 0x02 */ + __le16 active_bucket_timer_threshold; /* 0x04 */ + __u8 active_threshold_a; /* 0x06 */ + __u8 active_threshold_b; /* 0x07 */ + __u8 active_threshold_c; /* 0x08 */ + __u8 active_threshold_d; /* 0x09 */ + __le16 active_latency_config; /* 0x0A */ + __u8 active_latency_min_window; /* 0x0C */ + __u8 rsvd2[0x13]; /* 0x0D */ + + __le32 active_bucket_counter[4][4]; /* 0x20 - 0x5F */ + __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */ + __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */ + __le16 active_latency_stamp_units; /* 0xD8 */ + __u8 rsvd3[0x16]; /* 0xDA */ + + __le32 static_bucket_counter[4][4]; /* 0x0F0 - 0x12F */ + __le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */ + __le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */ + __le16 static_latency_stamp_units; /* 0x1A8 */ + __u8 rsvd4[0x16]; /* 0x1AA */ + + __le16 debug_log_trigger_enable; /* 0x1C0 */ + __le16 debug_log_measured_latency; /* 0x1C2 */ + __le64 debug_log_latency_stamp; /* 0x1C4 */ + __le16 debug_log_ptr; /* 0x1CC */ + __le16 debug_log_counter_trigger; /* 0x1CE */ + __u8 debug_log_stamp_units; /* 0x1D0 */ + __u8 rsvd5[0x1D]; /* 0x1D1 */ + + __le16 log_page_version; /* 0x1EE */ + __u8 log_page_guid[0x10]; /* 0x1F0 */ +}; -/* C0 SCAO Log Page */ -#define C0_SMART_CLOUD_ATTR_LEN 0x200 -#define C0_SMART_CLOUD_ATTR_OPCODE 0xC0 -#define C0_GUID_LENGTH 16 -#define C0_ACTIVE_BUCKET_TIMER_INCREMENT 5 -#define C0_ACTIVE_THRESHOLD_INCREMENT 5 -#define C0_MINIMUM_WINDOW_INCREMENT 100 - -static __u8 scao_guid[C0_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, - 0xF2, 0xA4, 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF }; - -/* C3 Latency Monitor Log Page */ -#define C3_LATENCY_MON_LOG_BUF_LEN 0x200 -#define C3_LATENCY_MON_OPCODE 0xC3 -#define C3_LATENCY_MON_VERSION 0x0001 -#define C3_GUID_LENGTH 16 -static __u8 lat_mon_guid[C3_GUID_LENGTH] = { 0x92, 0x7a, 0xc0, 0x8c, 0xd0, 0x84, - 0x6c, 0x9c, 0x70, 0x43, 0xe6, 0xd4, 0x58, 0x5e, 0xd4, 0x85 }; - -#define READ 0 -#define WRITE 1 -#define TRIM 2 -#define RESERVED 3 - -typedef enum { - SCAO_PMUW = 0, /* Physical media units written */ - SCAO_PMUR = 16, /* Physical media units read */ - SCAO_BUNBR = 32, /* Bad user nand blocks raw */ - SCAO_BUNBN = 38, /* Bad user nand blocks normalized */ - SCAO_BSNBR = 40, /* Bad system nand blocks raw */ - SCAO_BSNBN = 46, /* Bad system nand blocks normalized */ - SCAO_XRC = 48, /* XOR recovery count */ - SCAO_UREC = 56, /* Uncorrectable read error count */ - SCAO_SEEC = 64, /* Soft ecc error count */ - SCAO_EECE = 72, /* End to end corrected errors */ - SCAO_EEDC = 76, /* End to end detected errors */ - SCAO_SDPU = 80, /* System data percent used */ - SCAO_RFSC = 81, /* Refresh counts */ - SCAO_MXUDEC = 88, /* Max User data erase counts */ - SCAO_MNUDEC = 92, /* Min User data erase counts */ - SCAO_NTTE = 96, /* Number of Thermal throttling events */ - SCAO_CTS = 97, /* Current throttling status */ - SCAO_EVF = 98, /* Errata Version Field */ - SCAO_PVF = 99, /* Point Version Field */ - SCAO_MIVF = 101, /* Minor Version Field */ - SCAO_MAVF = 103, /* Major Version Field */ - SCAO_PCEC = 104, /* PCIe correctable error count */ - SCAO_ICS = 112, /* Incomplete shutdowns */ - SCAO_PFB = 120, /* Percent free blocks */ - SCAO_CPH = 128, /* Capacitor health */ - SCAO_NEV = 130, /* NVMe Errata Version */ - SCAO_UIO = 136, /* Unaligned I/O */ - SCAO_SVN = 144, /* Security Version Number */ - SCAO_NUSE = 152, /* NUSE - Namespace utilization */ - SCAO_PSC = 160, /* PLP start count */ - SCAO_EEST = 176, /* Endurance estimate */ - SCAO_PLRC = 192, /* PCIe Link Retraining Count */ - SCAO_LPV = 494, /* Log page version */ - SCAO_LPG = 496, /* Log page GUID */ -} SMART_CLOUD_ATTRIBUTE_OFFSETS; - -struct __attribute__((__packed__)) ssd_latency_monitor_log { - __u8 feature_status; /* 0x00 */ - __u8 rsvd1; /* 0x01 */ - __le16 active_bucket_timer; /* 0x02 */ - __le16 active_bucket_timer_threshold; /* 0x04 */ - __u8 active_threshold_a; /* 0x06 */ - __u8 active_threshold_b; /* 0x07 */ - __u8 active_threshold_c; /* 0x08 */ - __u8 active_threshold_d; /* 0x09 */ - __le16 active_latency_config; /* 0x0A */ - __u8 active_latency_min_window; /* 0x0C */ - __u8 rsvd2[0x13]; /* 0x0D */ - - __le32 active_bucket_counter[4][4] ; /* 0x20 - 0x5F */ - __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */ - __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */ - __le16 active_latency_stamp_units; /* 0xD8 */ - __u8 rsvd3[0x16]; /* 0xDA */ - - __le32 static_bucket_counter[4][4] ; /* 0xF0 - 0x12F */ - __le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */ - __le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */ - __le16 static_latency_stamp_units; /* 0x1A8 */ - __u8 rsvd4[0x16]; /* 0x1AA */ - - __le16 debug_log_trigger_enable; /* 0x1C0 */ - __le16 debug_log_measured_latency; /* 0x1C2 */ - __le64 debug_log_latency_stamp; /* 0x1C4 */ - __le16 debug_log_ptr; /* 0x1CC */ - __le16 debug_log_counter_trigger; /* 0x1CE */ - __u8 debug_log_stamp_units; /* 0x1D0 */ - __u8 rsvd5[0x1D]; /* 0x1D1 */ - - __le16 log_page_version; /* 0x1EE */ - __u8 log_page_guid[0x10]; /* 0x1F0 */ +struct __packed feature_latency_monitor { + __u16 active_bucket_timer_threshold; + __u8 active_threshold_a; + __u8 active_threshold_b; + __u8 active_threshold_c; + __u8 active_threshold_d; + __u16 active_latency_config; + __u8 active_latency_minimum_window; + __u16 debug_log_trigger_enable; + __u8 discard_debug_log; + __u8 latency_monitor_feature_enable; + __u8 reserved[4083]; }; -static long double int128_to_double(__u8 *data) +static int ocp_print_C3_log_normal(struct nvme_dev *dev, + struct ssd_latency_monitor_log *log_data) { - int i; - long double result = 0; + char ts_buf[128]; + int i, j; + + printf("-Latency Monitor/C3 Log Page Data-\n"); + printf(" Controller : %s\n", dev->name); + printf(" Feature Status 0x%x\n", + log_data->feature_status); + printf(" Active Bucket Timer %d min\n", + C3_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer)); + printf(" Active Bucket Timer Threshold %d min\n", + C3_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer_threshold)); + printf(" Active Threshold A %d ms\n", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_a+1)); + printf(" Active Threshold B %d ms\n", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_b+1)); + printf(" Active Threshold C %d ms\n", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_c+1)); + printf(" Active Threshold D %d ms\n", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_d+1)); + printf(" Active Latency Configuration 0x%x \n", + le16_to_cpu(log_data->active_latency_config)); + printf(" Active Latency Minimum Window %d ms\n", + C3_MINIMUM_WINDOW_INCREMENT * + le16_to_cpu(log_data->active_latency_min_window)); + printf(" Active Latency Stamp Units %d\n", + le16_to_cpu(log_data->active_latency_stamp_units)); + printf(" Static Latency Stamp Units %d\n", + le16_to_cpu(log_data->static_latency_stamp_units)); + printf(" Debug Log Trigger Enable %d\n", + le16_to_cpu(log_data->debug_log_trigger_enable)); + printf(" Debug Log Measured Latency %d\n", + le16_to_cpu(log_data->debug_log_measured_latency)); + if (le64_to_cpu(log_data->debug_log_latency_stamp) == -1) { + printf(" Debug Log Latency Time Stamp N/A\n"); + } else { + convert_ts(le64_to_cpu(log_data->debug_log_latency_stamp), ts_buf); + printf(" Debug Log Latency Time Stamp %s\n", ts_buf); + } + printf(" Debug Log Pointer %d\n", + le16_to_cpu(log_data->debug_log_ptr)); + printf(" Debug Counter Trigger Source %d\n", + le16_to_cpu(log_data->debug_log_counter_trigger)); + printf(" Debug Log Stamp Units %d\n", + le16_to_cpu(log_data->debug_log_stamp_units)); + printf(" Log Page Version %d\n", + le16_to_cpu(log_data->log_page_version)); + + char guid[(C3_GUID_LENGTH * 2) + 1]; + char *ptr = &guid[0]; + + for (i = C3_GUID_LENGTH - 1; i >= 0; i--) + ptr += sprintf(ptr, "%02X", log_data->log_page_guid[i]); + + printf(" Log Page GUID %s\n", guid); + printf("\n"); + + printf(" Read Write Deallocate/Trim\n"); + for (i = 0; i < C3_BUCKET_NUM; i++) { + printf(" Active Bucket Counter: Bucket %d %27d %27d %27d\n", + i, + le32_to_cpu(log_data->active_bucket_counter[i][READ]), + le32_to_cpu(log_data->active_bucket_counter[i][WRITE]), + le32_to_cpu(log_data->active_bucket_counter[i][TRIM])); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + printf(" Active Latency Time Stamp: Bucket %d ", i); + for (j = 2; j >= 0; j--) { + if (le64_to_cpu(log_data->active_latency_timestamp[3-i][j]) == -1) { + printf(" N/A "); + } else { + convert_ts(le64_to_cpu(log_data->active_latency_timestamp[3-i][j]), ts_buf); + printf("%s ", ts_buf); + } + } + printf("\n"); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n", + i, + le16_to_cpu(log_data->active_measured_latency[3-i][READ-1]), + le16_to_cpu(log_data->active_measured_latency[3-i][WRITE-1]), + le16_to_cpu(log_data->active_measured_latency[3-i][TRIM-1])); + } + + printf("\n"); + for (i = 0; i < C3_BUCKET_NUM; i++) { + printf(" Static Bucket Counter: Bucket %d %27d %27d %27d\n", + i, + le32_to_cpu(log_data->static_bucket_counter[i][READ]), + le32_to_cpu(log_data->static_bucket_counter[i][WRITE]), + le32_to_cpu(log_data->static_bucket_counter[i][TRIM])); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + printf(" Static Latency Time Stamp: Bucket %d ", i); + for (j = 2; j >= 0; j--) { + if (le64_to_cpu(log_data->static_latency_timestamp[3-i][j]) == -1) { + printf(" N/A "); + } else { + convert_ts(le64_to_cpu(log_data->static_latency_timestamp[3-i][j]), ts_buf); + printf("%s ", ts_buf); + } + } + printf("\n"); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n", + i, + le16_to_cpu(log_data->static_measured_latency[3-i][READ-1]), + le16_to_cpu(log_data->static_measured_latency[3-i][WRITE-1]), + le16_to_cpu(log_data->static_measured_latency[3-i][TRIM-1])); + } + + return 0; +} - for (i = 0; i < 16; i++) { - result *= 256; - result += data[15 - i]; - } - return result; -} - -static int convert_ts(time_t time, char *ts_buf) -{ - struct tm gmTimeInfo; - time_t time_Human, time_ms; - char buf[80]; - - time_Human = time/1000; - time_ms = time % 1000; - - gmtime_r((const time_t *)&time_Human, &gmTimeInfo); - - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &gmTimeInfo); - sprintf(ts_buf, "%s.%03ld GMT", buf, time_ms); - - return 0; -} - -static void ocp_print_C0_log_normal(void *data) -{ - __u8 *log_data = (__u8*)data; - uint16_t smart_log_ver = 0; - - printf("SMART Cloud Attributes :- \n"); - - printf(" Physical media units written - %"PRIu64" %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); - printf(" Physical media units read - %"PRIu64" %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); - printf(" Bad user nand blocks - Raw %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); - printf(" Bad user nand blocks - Normalized %d\n", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); - printf(" Bad system nand blocks - Raw %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); - printf(" Bad system nand blocks - Normalized %d\n", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); - printf(" XOR recovery count %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); - printf(" Uncorrectable read error count %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); - printf(" Soft ecc error count %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); - printf(" End to end corrected errors %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); - printf(" End to end detected errors %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); - printf(" System data percent used %d\n", - (__u8)log_data[SCAO_SDPU]); - printf(" Refresh counts %"PRIu64"\n", - (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); - printf(" Max User data erase counts %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); - printf(" Min User data erase counts %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); - printf(" Number of Thermal throttling events %d\n", - (__u8)log_data[SCAO_NTTE]); - printf(" Current throttling status 0x%x\n", - (__u8)log_data[SCAO_CTS]); - printf(" PCIe correctable error count %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); - printf(" Incomplete shutdowns %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); - printf(" Percent free blocks %d\n", - (__u8)log_data[SCAO_PFB]); - printf(" Capacitor health %"PRIu16"\n", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); - printf(" Unaligned I/O %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); - printf(" Security Version Number %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); - printf(" NUSE - Namespace utilization %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - printf(" PLP start count %.0Lf\n", - int128_to_double(&log_data[SCAO_PSC])); - printf(" Endurance estimate %.0Lf\n", - int128_to_double(&log_data[SCAO_EEST])); - smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); - printf(" Log page version %"PRIu16"\n",smart_log_ver); - printf(" Log page GUID 0x"); - printf("%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); - if(smart_log_ver > 2) { - printf(" Errata Version Field %d\n", - (__u8)log_data[SCAO_EVF]); - printf(" Point Version Field %"PRIu16"\n", - (uint16_t)log_data[SCAO_PVF]); - printf(" Minor Version Field %"PRIu16"\n", - (uint16_t)log_data[SCAO_MIVF]); - printf(" Major Version Field %d\n", - (__u8)log_data[SCAO_MAVF]); - printf(" NVMe Errata Version %d\n", - (__u8)log_data[SCAO_NEV]); - printf(" PCIe Link Retraining Count %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); - } - printf("\n"); -} - -static void ocp_print_C0_log_json(void *data) -{ - __u8 *log_data = (__u8*)data; - struct json_object *root; - struct json_object *pmuw; - struct json_object *pmur; - uint16_t smart_log_ver = 0; - - root = json_create_object(); - pmuw = json_create_object(); - pmur = json_create_object(); - - json_object_add_value_uint64(pmuw, "hi", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW+8] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_uint64(pmuw, "lo", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_object(root, "Physical media units written", pmuw); - json_object_add_value_uint64(pmur, "hi", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR+8] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_uint64(pmur, "lo", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); - json_object_add_value_object(root, "Physical media units read", pmur); - json_object_add_value_uint64(root, "Bad user nand blocks - Raw", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); - json_object_add_value_uint(root, "Bad user nand blocks - Normalized", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); - json_object_add_value_uint64(root, "Bad system nand blocks - Raw", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); - json_object_add_value_uint(root, "Bad system nand blocks - Normalized", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); - json_object_add_value_uint64(root, "XOR recovery count", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); - json_object_add_value_uint64(root, "Uncorrectable read error count", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); - json_object_add_value_uint64(root, "Soft ecc error count", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); - json_object_add_value_uint(root, "End to end corrected errors", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); - json_object_add_value_uint(root, "End to end detected errors", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); - json_object_add_value_uint(root, "System data percent used", - (__u8)log_data[SCAO_SDPU]); - json_object_add_value_uint64(root, "Refresh counts", - (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); - json_object_add_value_uint(root, "Max User data erase counts", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); - json_object_add_value_uint(root, "Min User data erase counts", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); - json_object_add_value_uint(root, "Number of Thermal throttling events", - (__u8)log_data[SCAO_NTTE]); - json_object_add_value_uint(root, "Current throttling status", - (__u8)log_data[SCAO_CTS]); - json_object_add_value_uint64(root, "PCIe correctable error count", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); - json_object_add_value_uint(root, "Incomplete shutdowns", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); - json_object_add_value_uint(root, "Percent free blocks", - (__u8)log_data[SCAO_PFB]); - json_object_add_value_uint(root, "Capacitor health", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); - json_object_add_value_uint64(root, "Unaligned I/O", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); - json_object_add_value_uint64(root, "Security Version Number", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); - json_object_add_value_uint64(root, "NUSE - Namespace utilization", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - json_object_add_value_uint(root, "PLP start count", - int128_to_double(&log_data[SCAO_PSC])); - json_object_add_value_uint64(root, "Endurance estimate", - int128_to_double(&log_data[SCAO_EEST])); - smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); - json_object_add_value_uint(root, "Log page version", smart_log_ver); - char guid[40]; - memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); - json_object_add_value_string(root, "Log page GUID", guid); - if(smart_log_ver > 2){ - json_object_add_value_uint(root, "Errata Version Field", - (__u8)log_data[SCAO_EVF]); - json_object_add_value_uint(root, "Point Version Field", - (uint16_t)log_data[SCAO_PVF]); - json_object_add_value_uint(root, "Minor Version Field", - (uint16_t)log_data[SCAO_MIVF]); - json_object_add_value_uint(root, "Major Version Field", - (__u8)log_data[SCAO_MAVF]); - json_object_add_value_uint(root, "NVMe Errata Version", - (__u8)log_data[SCAO_NEV]); - json_object_add_value_uint(root, "PCIe Link Retraining Count", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); - } - json_print_object(root, NULL); - printf("\n"); - json_free_object(root); +static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data) +{ + struct json_object *root; + char ts_buf[128]; + char buf[128]; + int i, j; + char *operation[3] = {"Trim", "Write", "Read"}; + + root = json_create_object(); + + json_object_add_value_uint(root, "Feature Status", + log_data->feature_status); + json_object_add_value_uint(root, "Active Bucket Timer", + C3_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer)); + json_object_add_value_uint(root, "Active Bucket Timer Threshold", + C3_ACTIVE_BUCKET_TIMER_INCREMENT * + le16_to_cpu(log_data->active_bucket_timer_threshold)); + json_object_add_value_uint(root, "Active Threshold A", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_a + 1)); + json_object_add_value_uint(root, "Active Threshold B", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_b + 1)); + json_object_add_value_uint(root, "Active Threshold C", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_c + 1)); + json_object_add_value_uint(root, "Active Threshold D", + C3_ACTIVE_THRESHOLD_INCREMENT * + le16_to_cpu(log_data->active_threshold_d + 1)); + json_object_add_value_uint(root, "Active Latency Configuration", + le16_to_cpu(log_data->active_latency_config)); + json_object_add_value_uint(root, "Active Latency Minimum Window", + C3_MINIMUM_WINDOW_INCREMENT * + le16_to_cpu(log_data->active_latency_min_window)); + + for (i = 0; i < C3_BUCKET_NUM; i++) { + struct json_object *bucket; + + bucket = json_create_object(); + sprintf(buf, "Active Bucket Counter: Bucket %d", i); + for (j = 2; j >= 0; j--) { + json_object_add_value_uint(bucket, operation[j], + le32_to_cpu(log_data->active_bucket_counter[i][j+1])); + } + json_object_add_value_object(root, buf, bucket); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + struct json_object *bucket; + + bucket = json_create_object(); + sprintf(buf, "Active Latency Time Stamp: Bucket %d", i); + for (j = 2; j >= 0; j--) { + if (le64_to_cpu(log_data->active_latency_timestamp[3-i][j]) == -1) { + json_object_add_value_string(bucket, operation[j], "NA"); + } else { + convert_ts(le64_to_cpu(log_data->active_latency_timestamp[3-i][j]), ts_buf); + json_object_add_value_string(bucket, operation[j], ts_buf); + } + } + json_object_add_value_object(root, buf, bucket); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + struct json_object *bucket; + + bucket = json_create_object(); + sprintf(buf, "Active Measured Latency: Bucket %d", i); + for (j = 2; j >= 0; j--) { + json_object_add_value_uint(bucket, operation[j], + le16_to_cpu(log_data->active_measured_latency[3-i][j])); + } + json_object_add_value_object(root, buf, bucket); + } + + json_object_add_value_uint(root, "Active Latency Stamp Units", + le16_to_cpu(log_data->active_latency_stamp_units)); + + for (i = 0; i < C3_BUCKET_NUM; i++) { + struct json_object *bucket; + + bucket = json_create_object(); + sprintf(buf, "Static Bucket Counter: Bucket %d", i); + for (j = 2; j >= 0; j--) { + json_object_add_value_uint(bucket, operation[j], + le32_to_cpu(log_data->static_bucket_counter[i][j+1])); + } + json_object_add_value_object(root, buf, bucket); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + struct json_object *bucket; + + bucket = json_create_object(); + sprintf(buf, "Static Latency Time Stamp: Bucket %d", i); + for (j = 2; j >= 0; j--) { + if (le64_to_cpu(log_data->static_latency_timestamp[3-i][j]) == -1) { + json_object_add_value_string(bucket, operation[j], "NA"); + } else { + convert_ts(le64_to_cpu(log_data->static_latency_timestamp[3-i][j]), ts_buf); + json_object_add_value_string(bucket, operation[j], ts_buf); + } + } + json_object_add_value_object(root, buf, bucket); + } + + for (i = 0; i < C3_BUCKET_NUM; i++) { + struct json_object *bucket; + + bucket = json_create_object(); + sprintf(buf, "Static Measured Latency: Bucket %d", i); + for (j = 2; j >= 0; j--) { + json_object_add_value_uint(bucket, operation[j], + le16_to_cpu(log_data->static_measured_latency[3-i][j])); + } + json_object_add_value_object(root, buf, bucket); + } + + json_object_add_value_uint(root, "Static Latency Stamp Units", + le16_to_cpu(log_data->static_latency_stamp_units)); + json_object_add_value_uint(root, "Debug Log Trigger Enable", + le16_to_cpu(log_data->debug_log_trigger_enable)); + json_object_add_value_uint(root, "Debug Log Measured Latency", + le16_to_cpu(log_data->debug_log_measured_latency)); + if (le64_to_cpu(log_data->debug_log_latency_stamp) == -1) { + json_object_add_value_string(root, "Debug Log Latency Time Stamp", "NA"); + } else { + convert_ts(le64_to_cpu(log_data->debug_log_latency_stamp), ts_buf); + json_object_add_value_string(root, "Debug Log Latency Time Stamp", ts_buf); + } + json_object_add_value_uint(root, "Debug Log Pointer", + le16_to_cpu(log_data->debug_log_ptr)); + json_object_add_value_uint(root, "Debug Counter Trigger Source", + le16_to_cpu(log_data->debug_log_counter_trigger)); + json_object_add_value_uint(root, "Debug Log Stamp Units", + le16_to_cpu(log_data->debug_log_stamp_units)); + json_object_add_value_uint(root, "Log Page Version", + le16_to_cpu(log_data->log_page_version)); + + char guid[(C3_GUID_LENGTH * 2) + 1]; + char *ptr = &guid[0]; + + for (i = C3_GUID_LENGTH - 1; i >= 0; i--) + ptr += sprintf(ptr, "%02X", log_data->log_page_guid[i]); + + json_object_add_value_string(root, "Log Page GUID", guid); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); } -static int get_c0_log_page(int fd, char *format) +static int get_c3_log_page(struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; - __u8 *data; - int i; + struct ssd_latency_monitor_log *log_data; + enum nvme_print_flags fmt; + int ret; + __u8 *data; + int i; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + data = malloc(sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), C3_LATENCY_MON_OPCODE, + C3_LATENCY_MON_LOG_BUF_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); + + if (!ret) { + log_data = (struct ssd_latency_monitor_log *)data; + + /* check log page version */ + if (log_data->log_page_version != C3_LATENCY_MON_VERSION) { + fprintf(stderr, + "ERROR : OCP : invalid latency monitor version\n"); + ret = -1; + goto out; + } + + /* + * check log page guid + * Verify GUID matches + */ + for (i = 0; i < 16; i++) { + if (lat_mon_guid[i] != log_data->log_page_guid[i]) { + int j; + + fprintf(stderr, "ERROR : OCP : Unknown GUID in C3 Log Page data\n"); + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", lat_mon_guid[j]); + + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", log_data->log_page_guid[j]); + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + switch (fmt) { + case NORMAL: + ocp_print_C3_log_normal(dev, log_data); + break; + case JSON: + ocp_print_C3_log_json(log_data); + break; + default: + fprintf(stderr, "unhandled output format\n"); + + } + } else { + fprintf(stderr, + "ERROR : OCP : Unable to read C3 data from buffer\n"); + } - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : OCP : invalid output format\n"); - return fmt; - } +out: + free(data); + return ret; +} - if ((data = (__u8 *) malloc(sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN)) == NULL) { - fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); - return -1; - } - memset(data, 0, sizeof (__u8) * C0_SMART_CLOUD_ATTR_LEN); - - ret = nvme_get_log_simple(fd, C0_SMART_CLOUD_ATTR_OPCODE, - C0_SMART_CLOUD_ATTR_LEN, data); - - if (strcmp(format, "json")) - fprintf(stderr, "NVMe Status:%s(%x)\n", - nvme_status_to_string(ret, false), ret); - - if (ret == 0) { - - /* check log page guid */ - /* Verify GUID matches */ - for (i=0; i<16; i++) { - if (scao_guid[i] != data[SCAO_LPG + i]) { - fprintf(stderr, "ERROR : OCP : Unknown GUID in C0 Log Page data\n"); - int j; - fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); - for (j = 0; j<16; j++) { - fprintf(stderr, "%x", scao_guid[j]); - } - fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); - for (j = 0; j<16; j++) { - fprintf(stderr, "%x", data[SCAO_LPG + j]); - } - fprintf(stderr, "\n"); - - ret = -1; - goto out; - } - } - - /* print the data */ - switch (fmt) { - case NORMAL: - ocp_print_C0_log_normal(data); - break; - case JSON: - ocp_print_C0_log_json(data); - break; - } - } else { - fprintf(stderr, "ERROR : OCP : Unable to read C0 data from buffer\n"); - } +static int ocp_latency_monitor_log(int argc, char **argv, + struct command *command, + struct plugin *plugin) +{ + const char *desc = "Retrieve latency monitor log data."; + struct nvme_dev *dev; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, + "output Format: normal|json"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_c3_log_page(dev, cfg.output_format); + if (ret) + fprintf(stderr, + "ERROR : OCP : Failure reading the C3 Log Page, ret = %d\n", + ret); + + dev_close(dev); + return ret; +} + +int ocp_set_latency_monitor_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + int err = -1; + struct nvme_dev *dev; + __u32 result; + struct feature_latency_monitor buf = {0,}; + __u32 nsid = NVME_NSID_ALL; + struct stat nvme_stat; + struct nvme_id_ctrl ctrl; + + const char *desc = "Set Latency Monitor feature."; + const char *active_bucket_timer_threshold = "This is the value that loads the Active Bucket Timer Threshold."; + const char *active_threshold_a = "This is the value that loads into the Active Threshold A."; + const char *active_threshold_b = "This is the value that loads into the Active Threshold B."; + const char *active_threshold_c = "This is the value that loads into the Active Threshold C."; + const char *active_threshold_d = "This is the value that loads into the Active Threshold D."; + const char *active_latency_config = "This is the value that loads into the Active Latency Configuration."; + const char *active_latency_minimum_window = "This is the value that loads into the Active Latency Minimum Window."; + const char *debug_log_trigger_enable = "This is the value that loads into the Debug Log Trigger Enable."; + const char *discard_debug_log = "Discard Debug Log."; + const char *latency_monitor_feature_enable = "Latency Monitor Feature Enable."; + + struct config { + __u16 active_bucket_timer_threshold; + __u8 active_threshold_a; + __u8 active_threshold_b; + __u8 active_threshold_c; + __u8 active_threshold_d; + __u16 active_latency_config; + __u8 active_latency_minimum_window; + __u16 debug_log_trigger_enable; + __u8 discard_debug_log; + __u8 latency_monitor_feature_enable; + }; + + struct config cfg = { + .active_bucket_timer_threshold = 0x7E0, + .active_threshold_a = 0x5, + .active_threshold_b = 0x13, + .active_threshold_c = 0x1E, + .active_threshold_d = 0x2E, + .active_latency_config = 0xFFF, + .active_latency_minimum_window = 0xA, + .debug_log_trigger_enable = 0, + .discard_debug_log = 0, + .latency_monitor_feature_enable = 0x7, + }; + + OPT_ARGS(opts) = { + OPT_UINT("active_bucket_timer_threshold", 't', &cfg.active_bucket_timer_threshold, active_bucket_timer_threshold), + OPT_UINT("active_threshold_a", 'a', &cfg.active_threshold_a, active_threshold_a), + OPT_UINT("active_threshold_b", 'b', &cfg.active_threshold_b, active_threshold_b), + OPT_UINT("active_threshold_c", 'c', &cfg.active_threshold_c, active_threshold_c), + OPT_UINT("active_threshold_d", 'd', &cfg.active_threshold_d, active_threshold_d), + OPT_UINT("active_latency_config", 'f', &cfg.active_latency_config, active_latency_config), + OPT_UINT("active_latency_minimum_window", 'w', &cfg.active_latency_minimum_window, active_latency_minimum_window), + OPT_UINT("debug_log_trigger_enable", 'r', &cfg.debug_log_trigger_enable, debug_log_trigger_enable), + OPT_UINT("discard_debug_log", 'l', &cfg.discard_debug_log, discard_debug_log), + OPT_UINT("latency_monitor_feature_enable", 'e', &cfg.latency_monitor_feature_enable, latency_monitor_feature_enable), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = fstat(dev_fd(dev), &nvme_stat); + if (err < 0) + return err; + + if (S_ISBLK(nvme_stat.st_mode)) { + err = nvme_get_nsid(dev_fd(dev), &nsid); + if (err < 0) { + perror("invalid-namespace-id"); + return err; + } + } + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) + return err; + + memset(&buf, 0, sizeof(struct feature_latency_monitor)); + + buf.active_bucket_timer_threshold = cfg.active_bucket_timer_threshold; + buf.active_threshold_a = cfg.active_threshold_a; + buf.active_threshold_b = cfg.active_threshold_b; + buf.active_threshold_c = cfg.active_threshold_c; + buf.active_threshold_d = cfg.active_threshold_d; + buf.active_latency_config = cfg.active_latency_config; + buf.active_latency_minimum_window = cfg.active_latency_minimum_window; + buf.debug_log_trigger_enable = cfg.debug_log_trigger_enable; + buf.discard_debug_log = cfg.discard_debug_log; + buf.latency_monitor_feature_enable = cfg.latency_monitor_feature_enable; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = NVME_FEAT_OCP_LATENCY_MONITOR, + .nsid = 0, + .cdw12 = 0, + .save = 1, + .data_len = sizeof(struct feature_latency_monitor), + .data = (void *)&buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_set_features(&args); + if (err < 0) { + perror("set-feature"); + } else if (!err) { + printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n", NVME_FEAT_OCP_LATENCY_MONITOR); + printf("active bucket timer threshold: 0x%x\n", buf.active_bucket_timer_threshold); + printf("active threshold a: 0x%x\n", buf.active_threshold_a); + printf("active threshold b: 0x%x\n", buf.active_threshold_b); + printf("active threshold c: 0x%x\n", buf.active_threshold_c); + printf("active threshold d: 0x%x\n", buf.active_threshold_d); + printf("active latency config: 0x%x\n", buf.active_latency_config); + printf("active latency minimum window: 0x%x\n", buf.active_latency_minimum_window); + printf("debug log trigger enable: 0x%x\n", buf.debug_log_trigger_enable); + printf("discard debug log: 0x%x\n", buf.discard_debug_log); + printf("latency monitor feature enable: 0x%x\n", buf.latency_monitor_feature_enable); + } else if (err > 0) { + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err, false), err); + } + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// EOL/PLP Failure Mode + +static const char *eol_plp_failure_mode_to_string(__u8 mode) +{ + switch (mode) { + case 1: + return "Read only mode (ROM)"; + case 2: + return "Write through mode (WTM)"; + case 3: + return "Normal mode"; + default: + break; + } + + return "Reserved"; +} + +static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid, + const __u8 fid, __u8 sel) +{ + __u32 result; + int err; + + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = nsid, + .sel = sel, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_get_features(&args); + if (!err) { + nvme_show_result("End of Life Behavior (feature: %#0*x): %#0*x (%s: %s)", + fid ? 4 : 2, fid, result ? 10 : 8, result, + nvme_select_to_string(sel), + eol_plp_failure_mode_to_string(result)); + if (sel == NVME_GET_FEATURES_SEL_SUPPORTED) + nvme_show_select_result(fid, result); + } else { + nvme_show_error("Could not get feature: %#0*x.", fid ? 4 : 2, fid); + } + + return err; +} + +static int eol_plp_failure_mode_set(struct nvme_dev *dev, const __u32 nsid, + const __u8 fid, __u8 mode, bool save, + bool uuid) +{ + __u32 result; + int err; + int uuid_index = 0; + + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &uuid_index); + if (err || !uuid_index) { + nvme_show_error("ERROR: No OCP UUID index found"); + return err; + } + } + + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = nsid, + .cdw11 = mode << 30, + .cdw12 = 0, + .save = save, + .uuidx = uuid_index, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_set_features(&args); + if (err > 0) { + nvme_show_status(err); + } else if (err < 0) { + nvme_show_perror("Define EOL/PLP failure mode"); + fprintf(stderr, "Command failed while parsing.\n"); + } else { + nvme_show_result("Successfully set mode (feature: %#0*x): %#0*x (%s: %s).", + fid ? 4 : 2, fid, mode ? 10 : 8, mode, + save ? "Save" : "Not save", + eol_plp_failure_mode_to_string(mode)); + } + + return err; +} + +static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Define EOL or PLP circuitry failure mode.\n" + "No argument prints current mode."; + const char *mode = "[0-3]: default/rom/wtm/normal"; + const char *save = "Specifies that the controller shall save the attribute"; + const char *sel = "[0-3,8]: current/default/saved/supported/changed"; + const __u32 nsid = 0; + const __u8 fid = 0xc2; + struct nvme_dev *dev; + int err; + + struct config { + __u8 mode; + bool save; + __u8 sel; + }; + + struct config cfg = { + .mode = 0, + .save = false, + .sel = 0, + }; + + OPT_ARGS(opts) = { + OPT_BYTE("mode", 'm', &cfg.mode, mode), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_BYTE("sel", 'S', &cfg.sel, sel), + OPT_FLAG("no-uuid", 'n', NULL, + "Skip UUID index search (UUID index not required for OCP 1.0)"), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (argconfig_parse_seen(opts, "mode")) + err = eol_plp_failure_mode_set(dev, nsid, fid, cfg.mode, + cfg.save, + !argconfig_parse_seen(opts, "no-uuid")); + else + err = eol_plp_failure_mode_get(dev, nsid, fid, cfg.sel); + + dev_close(dev); + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Telemetry Log + +#define TELEMETRY_HEADER_SIZE 512 +#define TELEMETRY_BYTE_PER_BLOCK 512 +#define TELEMETRY_TRANSFER_SIZE 1024 +#define FILE_NAME_SIZE 2048 + +enum TELEMETRY_TYPE { + TELEMETRY_TYPE_NONE = 0, + TELEMETRY_TYPE_HOST = 7, + TELEMETRY_TYPE_CONTROLLER = 8, + TELEMETRY_TYPE_HOST_0 = 9, + TELEMETRY_TYPE_HOST_1 = 10, +}; + +struct telemetry_initiated_log { + __u8 LogIdentifier; + __u8 Reserved1[4]; + __u8 IEEE[3]; + __le16 DataArea1LastBlock; + __le16 DataArea2LastBlock; + __le16 DataArea3LastBlock; + __u8 Reserved2[368]; + __u8 DataAvailable; + __u8 DataGenerationNumber; + __u8 ReasonIdentifier[128]; +}; + +struct telemetry_data_area_1 { + __le16 major_version; + __le16 minor_version; + __u8 reserved1[4]; + __le64 timestamp; + __u8 log_page_guid[16]; + __u8 no_of_tps_supp; + __u8 tps; + __u8 reserved2[6]; + __le16 sls; + __u8 reserved3[8]; + __le16 fw_revision; + __u8 reserved4[32]; + __le16 da1_stat_start; + __le16 da1_stat_size; + __le16 da2_stat_start; + __le16 da2_stat_size; + __u8 reserved5[32]; + __u8 event_fifo_da[16]; + __le64 event_fifo_start[16]; + __le64 event_fifo_size[16]; + __u8 reserved6[80]; + __u8 smart_health_info[512]; + __u8 smart_health_info_extended[512]; +}; +static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn) +{ + int i; + /* Remove trailing spaces from the name */ + for (i = 0; i < sizeof(ctrl->sn); i++) { + if (ctrl->sn[i] == ' ') + break; + sn[i] = ctrl->sn[i]; + } +} + +static int get_telemetry_header(struct nvme_dev *dev, __u32 ns, __u8 tele_type, + __u32 data_len, void *data, __u8 nLSP, __u8 nRAE) +{ + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_get_log_page, + .nsid = ns, + .addr = (__u64)(uintptr_t) data, + .data_len = data_len, + }; + + __u32 numd = (data_len >> 2) - 1; + __u16 numdu = numd >> 16; + __u16 numdl = numd & 0xffff; + + cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16; + cmd.cdw11 = numdu; + cmd.cdw12 = 0; + cmd.cdw13 = 0; + cmd.cdw14 = 0; + + return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); +} + +static void print_telemetry_header(struct telemetry_initiated_log *logheader, + int tele_type) +{ + if (logheader) { + unsigned int i = 0, j = 0; + + if (tele_type == TELEMETRY_TYPE_HOST) + printf("============ Telemetry Host Header ============\n"); + else + printf("========= Telemetry Controller Header =========\n"); + + printf("Log Identifier : 0x%02X\n", logheader->LogIdentifier); + printf("IEEE : 0x%02X%02X%02X\n", + logheader->IEEE[0], logheader->IEEE[1], logheader->IEEE[2]); + printf("Data Area 1 Last Block : 0x%04X\n", + le16_to_cpu(logheader->DataArea1LastBlock)); + printf("Data Area 2 Last Block : 0x%04X\n", + le16_to_cpu(logheader->DataArea2LastBlock)); + printf("Data Area 3 Last Block : 0x%04X\n", + le16_to_cpu(logheader->DataArea3LastBlock)); + printf("Data Available : 0x%02X\n", logheader->DataAvailable); + printf("Data Generation Number : 0x%02X\n", logheader->DataGenerationNumber); + printf("Reason Identifier :\n"); + + for (i = 0; i < 8; i++) { + for (j = 0; j < 16; j++) + printf("%02X ", logheader->ReasonIdentifier[127 - ((i * 16) + j)]); + printf("\n"); + } + printf("===============================================\n\n"); + } +} +static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type, + __u32 data_len, void *data, __u8 nLSP, __u8 nRAE, + __u64 offset) +{ + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_get_log_page, + .nsid = ns, + .addr = (__u64)(uintptr_t) data, + .data_len = data_len, + }; + __u32 numd = (data_len >> 2) - 1; + __u16 numdu = numd >> 16; + __u16 numdl = numd & 0xffff; + cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16; + cmd.cdw11 = numdu; + cmd.cdw12 = offset; + cmd.cdw13 = 0; + cmd.cdw14 = 0; + return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); +} +static void print_telemetry_data_area_1(struct telemetry_data_area_1 *da1, + int tele_type) +{ + if (da1) { + unsigned int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) + printf("============ Telemetry Host Data area 1 ============\n"); + else + printf("========= Telemetry Controller Data area 1 =========\n"); + printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version)); + printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version)); + for (i = 0; i < 4; i++) + printf("reserved1 : 0x%x\n", da1->reserved1[i]); + printf("Timestamp : %"PRIu64"\n", le64_to_cpu(da1->timestamp)); + for (i = 15; i >= 0; i--) + printf("%x", da1->log_page_guid[i]); + printf("Number Telemetry Profiles Supported : 0x%x\n", da1->no_of_tps_supp); + printf("Telemetry Profile Selected (TPS) : 0x%x\n", da1->tps); + for (i = 0; i < 6; i++) + printf("reserved2 : 0x%x\n", da1->reserved2[i]); + printf("Telemetry String Log Size (SLS) : 0x%x\n", le16_to_cpu(da1->sls)); + for (i = 0; i < 8; i++) + printf("reserved3 : 0x%x\n", da1->reserved3[i]); + printf("Firmware Revision : 0x%x\n", le16_to_cpu(da1->fw_revision)); + for (i = 0; i < 32; i++) + printf("reserved4 : 0x%x\n", da1->reserved4[i]); + printf("Data Area 1 Statistic Start : 0x%x\n", le16_to_cpu(da1->da1_stat_start)); + printf("Data Area 1 Statistic Size : 0x%x\n", le16_to_cpu(da1->da1_stat_size)); + printf("Data Area 2 Statistic Start : 0x%x\n", le16_to_cpu(da1->da2_stat_start)); + printf("Data Area 2 Statistic Size : 0x%x\n", le16_to_cpu(da1->da2_stat_size)); + for (i = 0; i < 32; i++) + printf("reserved5 : 0x%x\n", da1->reserved5[i]); + for (i = 0; i < 17; i++){ + printf("Event FIFO %d Data Area : 0x%x\n", i, da1->event_fifo_da[i]); + printf("Event FIFO %d Start : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_start[i])); + printf("Event FIFO %d Size : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_size[i])); + } + for (i = 0; i < 80; i++) + printf("reserved6 : 0x%x\n", da1->reserved6[i]); + for (i = 0; i < 512; i++){ + printf("SMART / Health Information : 0x%x\n", da1->smart_health_info[i]); + printf("SMART / Health Information Extended : 0x%x\n", da1->smart_health_info_extended[i]); + } + printf("===============================================\n\n"); + } +} +static void print_telemetry_da1_stat(__u8 *da1_stat, int tele_type, __u16 buf_size) +{ + if (da1_stat) { + unsigned int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) + printf("============ Telemetry Host Data area 1 Statistics ============\n"); + else + printf("========= Telemetry Controller Data area 1 Statistics =========\n"); + while((i + 8) < buf_size) { + printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8)); + printf("Statistics info : 0x%x\n", da1_stat[i+2]); + printf("NS info : 0x%x\n", da1_stat[i+3]); + printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8)); + printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8)); + i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4); + } + printf("===============================================\n\n"); + } +} +static void print_telemetry_da1_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size) +{ + if (da1_fifo) { + unsigned int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) + printf("============ Telemetry Host Data area 1 FIFO ============\n"); + else + printf("========= Telemetry Controller Data area 1 FIFO =========\n"); + while((i + 4) < buf_size) { + printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]); + printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8)); + printf("Event Data Size : 0x%x\n", da1_fifo[3]); + i = 4 + ((da1_fifo[3]) * 4); + } + printf("===============================================\n\n"); + } +} +static void print_telemetry_da2_stat(__u8 *da1_stat, int tele_type, __u16 buf_size) +{ + if (da1_stat) { + unsigned int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) + printf("============ Telemetry Host Data area 1 Statistics ============\n"); + else + printf("========= Telemetry Controller Data area 1 Statistics =========\n"); + while((i + 8) < buf_size) { + printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8)); + printf("Statistics info : 0x%x\n", da1_stat[i+2]); + printf("NS info : 0x%x\n", da1_stat[i+3]); + printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8)); + printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8)); + i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4); + } + printf("===============================================\n\n"); + } +} +static void print_telemetry_da2_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size) +{ + if (da1_fifo) { + unsigned int i = 0; + if (tele_type == TELEMETRY_TYPE_HOST) + printf("============ Telemetry Host Data area 1 Statistics ============\n"); + else + printf("========= Telemetry Controller Data area 1 Statistics =========\n"); + while((i + 4) < buf_size) { + printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]); + printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8)); + printf("Event Data Size : 0x%x\n", da1_fifo[3]); + i = 4 + ((da1_fifo[3]) * 4); + } + printf("===============================================\n\n"); + } +} + +static int extract_dump_get_log(struct nvme_dev *dev, char *featurename, char *filename, char *sn, + int dumpsize, int transfersize, __u32 nsid, __u8 log_id, + __u8 lsp, __u64 offset, bool rae) +{ + int i = 0, err = 0; + + char *data = calloc(transfersize, sizeof(char)); + char filepath[FILE_NAME_SIZE] = {0,}; + int output = 0; + int total_loop_cnt = dumpsize / transfersize; + int last_xfer_size = dumpsize % transfersize; + + if (last_xfer_size) + total_loop_cnt++; + else + last_xfer_size = transfersize; + + if (filename == 0) + snprintf(filepath, FILE_NAME_SIZE, "%s_%s.bin", featurename, sn); + else + snprintf(filepath, FILE_NAME_SIZE, "%s%s_%s.bin", filename, featurename, sn); + + for (i = 0; i < total_loop_cnt; i++) { + memset(data, 0, transfersize); + + struct nvme_get_log_args args = { + .lpo = offset, + .result = NULL, + .log = (void *)data, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = log_id, + .len = transfersize, + .nsid = nsid, + .lsp = lsp, + .uuidx = 0, + .rae = rae, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .csi = NVME_CSI_NVM, + .ot = false, + }; + + err = nvme_get_log(&args); + if (err) { + if (i > 0) + goto close_output; + else + goto end; + } + + if (i != total_loop_cnt - 1) { + if (!i) { + output = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) { + err = -13; + goto end; + } + } + if (write(output, data, transfersize) < 0) { + err = -10; + goto close_output; + } + } else { + if (write(output, data, last_xfer_size) < 0) { + err = -10; + goto close_output; + } + } + offset += transfersize; + printf("%d%%\r", (i + 1) * 100 / total_loop_cnt); + } + printf("100%%\nThe log file was saved at \"%s\"\n", filepath); + +close_output: + close(output); + +end: + free(data); + return err; +} + +static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn, + enum TELEMETRY_TYPE tele_type, int data_area, bool header_print) +{ + __u32 err = 0, nsid = 0; + __u8 lsp = 0, rae = 0; + unsigned int i = 0; + char data[TELEMETRY_TRANSFER_SIZE] = { 0 }; + char data1[1536] = { 0 }; + char *featurename = 0; + struct telemetry_initiated_log *logheader = (struct telemetry_initiated_log *)data; + struct telemetry_data_area_1 *da1 = (struct telemetry_data_area_1 *)data1; + __u64 offset = 0, size = 0; + char dumpname[FILE_NAME_SIZE] = { 0 }; + + if (tele_type == TELEMETRY_TYPE_HOST_0) { + featurename = "Host(0)"; + lsp = 0; + rae = 0; + tele_type = TELEMETRY_TYPE_HOST; + } else if (tele_type == TELEMETRY_TYPE_HOST_1) { + featurename = "Host(1)"; + lsp = 1; + rae = 0; + tele_type = TELEMETRY_TYPE_HOST; + } else { + featurename = "Controller"; + lsp = 0; + rae = 1; + } + + err = get_telemetry_header(dev, nsid, tele_type, TELEMETRY_HEADER_SIZE, + (void *)data, lsp, rae); + if (err) + return err; + + if (header_print) + print_telemetry_header(logheader, tele_type); + err = get_telemetry_data(dev, nsid, tele_type, 1536, + (void *)data1, lsp, rae, 512); + if (err) + return err; + print_telemetry_data_area_1(da1, tele_type); + char *da1_stat = calloc((da1->da1_stat_size * 4), sizeof(char)); + err = get_telemetry_data(dev, nsid, tele_type, (da1->da1_stat_size) * 4, + (void *)da1_stat, lsp, rae, (da1->da1_stat_start) * 4); + if (err) + return err; + print_telemetry_da1_stat((void *)da1_stat, tele_type, (da1->da1_stat_size) * 4); + for (i = 0; i < 17 ; i++){ + if (da1->event_fifo_da[i] == 1){ + char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char)); + err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4, + (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4); + if (err) + return err; + print_telemetry_da1_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4); + } + } + char *da2_stat = calloc((da1->da2_stat_size * 4), sizeof(char)); + err = get_telemetry_data(dev, nsid, tele_type, (da1->da2_stat_size) * 4, + (void *)da2_stat, lsp, rae, (da1->da2_stat_start) * 4); + if (err) + return err; + print_telemetry_da2_stat((void *)da2_stat, tele_type, (da1->da2_stat_size) * 4); + for (i = 0; i < 17 ; i++){ + if (da1->event_fifo_da[i] == 2){ + char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char)); + err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4, + (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4); + if (err) + return err; + print_telemetry_da2_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4); + } + } + + switch (data_area) { + case 1: + offset = TELEMETRY_HEADER_SIZE; + size = le16_to_cpu(logheader->DataArea1LastBlock); + break; + case 2: + offset = TELEMETRY_HEADER_SIZE + + (le16_to_cpu(logheader->DataArea1LastBlock) * TELEMETRY_BYTE_PER_BLOCK); + size = le16_to_cpu(logheader->DataArea2LastBlock) + - le16_to_cpu(logheader->DataArea1LastBlock); + break; + case 3: + offset = TELEMETRY_HEADER_SIZE + + (le16_to_cpu(logheader->DataArea2LastBlock) * TELEMETRY_BYTE_PER_BLOCK); + size = le16_to_cpu(logheader->DataArea3LastBlock) + - le16_to_cpu(logheader->DataArea2LastBlock); + break; + default: + break; + } + + if (!size) { + printf("Telemetry %s Area %d is empty.\n", featurename, data_area); + return err; + } + + snprintf(dumpname, FILE_NAME_SIZE, + "Telemetry_%s_Area_%d", featurename, data_area); + err = extract_dump_get_log(dev, dumpname, filename, sn, size * TELEMETRY_BYTE_PER_BLOCK, + TELEMETRY_TRANSFER_SIZE, nsid, tele_type, + 0, offset, rae); + + return err; +} + +static int ocp_telemetry_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + struct nvme_dev *dev; + int err = 0; + const char *desc = "Retrieve and save telemetry log."; + const char *type = "Telemetry Type; 'host[Create bit]' or 'controller'"; + const char *area = "Telemetry Data Area; 1 or 3"; + const char *file = "Output file name with path;\n" + "e.g. '-o ./path/name'\n'-o ./path1/path2/';\n" + "If requested path does not exist, the directory will be newly created."; + + __u32 nsid = NVME_NSID_ALL; + struct stat nvme_stat; + char sn[21] = {0,}; + struct nvme_id_ctrl ctrl; + bool is_support_telemetry_controller; + + int tele_type = 0; + int tele_area = 0; + + struct config { + char *type; + int area; + char *file; + }; + + struct config cfg = { + .type = NULL, + .area = 0, + .file = NULL, + }; + + OPT_ARGS(opts) = { + OPT_STR("telemetry_type", 't', &cfg.type, type), + OPT_INT("telemetry_data_area", 'a', &cfg.area, area), + OPT_FILE("output-file", 'o', &cfg.file, file), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = fstat(dev_fd(dev), &nvme_stat); + if (err < 0) + return err; + + if (S_ISBLK(nvme_stat.st_mode)) { + err = nvme_get_nsid(dev_fd(dev), &nsid); + if (err < 0) + return err; + } + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) + return err; + + get_serial_number(&ctrl, sn); + + is_support_telemetry_controller = ((ctrl.lpa & 0x8) >> 3); + + if (!cfg.type && !cfg.area) { + tele_type = TELEMETRY_TYPE_NONE; + tele_area = 0; + } else if (cfg.type && cfg.area) { + if (!strcmp(cfg.type, "host0")) + tele_type = TELEMETRY_TYPE_HOST_0; + else if (!strcmp(cfg.type, "host1")) + tele_type = TELEMETRY_TYPE_HOST_1; + else if (!strcmp(cfg.type, "controller")) + tele_type = TELEMETRY_TYPE_CONTROLLER; + + tele_area = cfg.area; + + if ((tele_area != 1 && tele_area != 3) || + (tele_type == TELEMETRY_TYPE_CONTROLLER && tele_area != 3)) { + printf("\nUnsupported parameters entered.\n"); + printf("Possible combinations; {'host0',1}, {'host0',3}, {'host1',1}, {'host1',3}, {'controller',3}\n"); + return err; + } + } else { + printf("\nShould provide these all; 'telemetry_type' and 'telemetry_data_area'\n"); + return err; + } + + if (tele_type == TELEMETRY_TYPE_NONE) { + printf("\n-------------------------------------------------------------\n"); + /* Host 0 (lsp == 0) must be executed before Host 1 (lsp == 1). */ + printf("\nExtracting Telemetry Host 0 Dump (Data Area 1)...\n"); + + err = get_telemetry_dump(dev, cfg.file, sn, + TELEMETRY_TYPE_HOST_0, 1, true); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + + printf("\n-------------------------------------------------------------\n"); + + printf("\nExtracting Telemetry Host 0 Dump (Data Area 3)...\n"); + + err = get_telemetry_dump(dev, cfg.file, sn, + TELEMETRY_TYPE_HOST_0, 3, false); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + + printf("\n-------------------------------------------------------------\n"); + + printf("\nExtracting Telemetry Host 1 Dump (Data Area 1)...\n"); + + err = get_telemetry_dump(dev, cfg.file, sn, + TELEMETRY_TYPE_HOST_1, 1, true); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + + printf("\n-------------------------------------------------------------\n"); + + printf("\nExtracting Telemetry Host 1 Dump (Data Area 3)...\n"); + + err = get_telemetry_dump(dev, cfg.file, sn, + TELEMETRY_TYPE_HOST_1, 3, false); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + + printf("\n-------------------------------------------------------------\n"); + + printf("\nExtracting Telemetry Controller Dump (Data Area 3)...\n"); + + if (is_support_telemetry_controller == true) { + err = get_telemetry_dump(dev, cfg.file, sn, + TELEMETRY_TYPE_CONTROLLER, 3, true); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + } + + printf("\n-------------------------------------------------------------\n"); + } else if (tele_type == TELEMETRY_TYPE_CONTROLLER) { + printf("Extracting Telemetry Controller Dump (Data Area %d)...\n", tele_area); + + if (is_support_telemetry_controller == true) { + err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + } + } else { + printf("Extracting Telemetry Host(%d) Dump (Data Area %d)...\n", + (tele_type == TELEMETRY_TYPE_HOST_0) ? 0 : 1, tele_area); + + err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true); + if (err) + fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err); + } + + printf("telemetry-log done.\n"); + +return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Unsupported Requirement Log Page (LID : C5h) + +/* C5 Unsupported Requirement Log Page */ +#define C5_GUID_LENGTH 16 +#define C5_UNSUPPORTED_REQS_LEN 4096 +#define C5_UNSUPPORTED_REQS_OPCODE 0xC5 +#define C5_UNSUPPORTED_REQS_LOG_VERSION 0x1 +#define C5_NUM_UNSUPPORTED_REQ_ENTRIES 253 + +static __u8 unsupported_req_guid[C5_GUID_LENGTH] = { + 0x2F, 0x72, 0x9C, 0x0E, + 0x99, 0x23, 0x2C, 0xBB, + 0x63, 0x48, 0x32, 0xD0, + 0xB7, 0x98, 0xBB, 0xC7 +}; + +/* + * struct unsupported_requirement_log - unsupported requirement list + * @unsupported_count: Number of Unsupported Requirement IDs + * @rsvd1: Reserved + * @unsupported_req_list: Unsupported Requirements lists upto 253. + * @rsvd2: Reserved + * @log_page_version: indicates the version of the mapping this log page uses. + * Shall be set to 0001h + * @log_page_guid: Shall be set to C7BB98B7D0324863BB2C23990E9C722Fh. + */ +struct __packed unsupported_requirement_log { + __le16 unsupported_count; + __u8 rsvd1[14]; + __u8 unsupported_req_list[C5_NUM_UNSUPPORTED_REQ_ENTRIES][16]; + __u8 rsvd2[14]; + __le16 log_page_version; + __u8 log_page_guid[C5_GUID_LENGTH]; +}; + +/* Function declaration for unsupported requirement log page (LID:C5h) */ +static int ocp_unsupported_requirements_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin); + +static int ocp_print_C5_log_normal(struct nvme_dev *dev, + struct unsupported_requirement_log *log_data) +{ + int j; + + printf("Unsupported Requirement-C5 Log Page Data-\n"); + + printf(" Number Unsupported Req IDs : 0x%x\n", le16_to_cpu(log_data->unsupported_count)); + + for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) + printf(" Unsupported Requirement List %d : %s\n", j, log_data->unsupported_req_list[j]); + + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (j = C5_GUID_LENGTH - 1; j >= 0; j--) + printf("%x", log_data->log_page_guid[j]); + printf("\n"); + + return 0; +} + +static void ocp_print_C5_log_json(struct unsupported_requirement_log *log_data) +{ + int j; + struct json_object *root; + char unsup_req_list_str[40]; + char guid_buf[C5_GUID_LENGTH]; + char *guid = guid_buf; + + root = json_create_object(); + + json_object_add_value_int(root, "Number Unsupported Req IDs", le16_to_cpu(log_data->unsupported_count)); + + memset((void *)unsup_req_list_str, 0, 40); + for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) { + sprintf((char *)unsup_req_list_str, "Unsupported Requirement List %d", j); + json_object_add_value_string(root, unsup_req_list_str, (char *)log_data->unsupported_req_list[j]); + } + + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + + memset((void *)guid, 0, C5_GUID_LENGTH); + for (j = C5_GUID_LENGTH - 1; j >= 0; j--) + guid += sprintf(guid, "%02x", log_data->log_page_guid[j]); + json_object_add_value_string(root, "Log page GUID", guid_buf); + + json_print_object(root, NULL); + printf("\n"); + + json_free_object(root); +} + +static void ocp_print_c5_log_binary(struct unsupported_requirement_log *log_data) +{ + return d_raw((unsigned char *)log_data, sizeof(*log_data)); +} + +static int get_c5_log_page(struct nvme_dev *dev, char *format) +{ + enum nvme_print_flags fmt; + int ret; + __u8 *data; + int i; + struct unsupported_requirement_log *log_data; + int j; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + data = (__u8 *)malloc(sizeof(__u8) * C5_UNSUPPORTED_REQS_LEN); + if (!data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof(__u8) * C5_UNSUPPORTED_REQS_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), C5_UNSUPPORTED_REQS_OPCODE, + C5_UNSUPPORTED_REQS_LEN, data); + if (!ret) { + log_data = (struct unsupported_requirement_log *)data; + + /* check log page version */ + if (log_data->log_page_version != C5_UNSUPPORTED_REQS_LOG_VERSION) { + fprintf(stderr, "ERROR : OCP : invalid unsupported requirement version\n"); + ret = -1; + goto out; + } + + /* + * check log page guid + * Verify GUID matches + */ + for (i = 0; i < 16; i++) { + if (unsupported_req_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : OCP : Unknown GUID in C5 Log Page data\n"); + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", unsupported_req_guid[j]); + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", log_data->log_page_guid[j]); + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + switch (fmt) { + case NORMAL: + ocp_print_C5_log_normal(dev, log_data); + break; + case JSON: + ocp_print_C5_log_json(log_data); + break; + case BINARY: + ocp_print_c5_log_binary(log_data); + break; + default: + break; + } + } else { + fprintf(stderr, "ERROR : OCP : Unable to read C3 data from buffer\n"); + } out: - free(data); - return ret; + free(data); + return ret; } -static int ocp_smart_add_log(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + +static int ocp_unsupported_requirements_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - const char *desc = "Retrieve latency monitor log data."; + const char *desc = "Retrieve unsupported requirements log data."; struct nvme_dev *dev; - int ret = 0; - - struct config { - char *output_format; - }; - - struct config cfg = { - .output_format = "normal", - }; - - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"), - OPT_END() - }; - - ret = parse_and_open(&dev, argc, argv, desc, opts); - if (ret) - return ret; - - ret = get_c0_log_page(dev_fd(dev), cfg.output_format); - if (ret) - fprintf(stderr, "ERROR : OCP : Failure reading the C0 Log Page, ret = %d\n", - ret); - dev_close(dev); - return ret; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_c5_log_page(dev, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C5 Log Page, ret = %d\n", ret); + + dev_close(dev); + return ret; } -static int ocp_print_C3_log_normal(struct nvme_dev *dev, - struct ssd_latency_monitor_log *log_data) +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Error Recovery Log Page(0xC1) + +#define C1_ERROR_RECOVERY_LOG_BUF_LEN 0x200 +#define C1_ERROR_RECOVERY_OPCODE 0xC1 +#define C1_ERROR_RECOVERY_VERSION 0x0002 +#define C1_GUID_LENGTH 16 +static __u8 error_recovery_guid[C1_GUID_LENGTH] = { + 0x44, 0xd9, 0x31, 0x21, + 0xfe, 0x30, 0x34, 0xae, + 0xab, 0x4d, 0xfd, 0x3d, + 0xba, 0x83, 0x19, 0x5a +}; + +/** + * struct ocp_error_recovery_log_page - Error Recovery Log Page + * @panic_reset_wait_time: Panic Reset Wait Time + * @panic_reset_action: Panic Reset Action + * @device_recover_action_1: Device Recovery Action 1 + * @panic_id: Panic ID + * @device_capabilities: Device Capabilities + * @vendor_specific_recovery_opcode: Vendor Specific Recovery Opcode + * @reserved: Reserved + * @vendor_specific_command_cdw12: Vendor Specific Command CDW12 + * @vendor_specific_command_cdw13: Vendor Specific Command CDW13 + * @vendor_specific_command_timeout: Vendor Specific Command Timeout + * @device_recover_action_2: Device Recovery Action 2 + * @device_recover_action_2_timeout: Device Recovery Action 2 Timeout + * @reserved2: Reserved + * @log_page_version: Log Page Version + * @log_page_guid: Log Page GUID + */ +struct __packed ocp_error_recovery_log_page { + __le16 panic_reset_wait_time; /* 2 bytes - 0x00 - 0x01 */ + __u8 panic_reset_action; /* 1 byte - 0x02 */ + __u8 device_recover_action_1; /* 1 byte - 0x03 */ + __le64 panic_id; /* 8 bytes - 0x04 - 0x0B */ + __le32 device_capabilities; /* 4 bytes - 0x0C - 0x0F */ + __u8 vendor_specific_recovery_opcode; /* 1 byte - 0x10 */ + __u8 reserved[0x3]; /* 3 bytes - 0x11 - 0x13 */ + __le32 vendor_specific_command_cdw12; /* 4 bytes - 0x14 - 0x17 */ + __le32 vendor_specific_command_cdw13; /* 4 bytes - 0x18 - 0x1B */ + __u8 vendor_specific_command_timeout; /* 1 byte - 0x1C */ + __u8 device_recover_action_2; /* 1 byte - 0x1D */ + __u8 device_recover_action_2_timeout; /* 1 byte - 0x1E */ + __u8 reserved2[0x1cf]; /* 463 bytes - 0x1F - 0x1ED */ + __le16 log_page_version; /* 2 bytes - 0x1EE - 0x1EF */ + __u8 log_page_guid[0x10]; /* 16 bytes - 0x1F0 - 0x1FF */ +}; + +static void ocp_print_c1_log_normal(struct ocp_error_recovery_log_page *log_data); +static void ocp_print_c1_log_json(struct ocp_error_recovery_log_page *log_data); +static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data); +static int get_c1_log_page(struct nvme_dev *dev, char *format); +static int ocp_error_recovery_log(int argc, char **argv, struct command *cmd, struct plugin *plugin); + +static void ocp_print_c1_log_normal(struct ocp_error_recovery_log_page *log_data) { - printf("-Latency Monitor/C3 Log Page Data- \n"); - printf(" Controller : %s\n", dev->name); - int i, j; - int pos = 0; - char ts_buf[128]; - - printf(" Feature Status 0x%x \n", - log_data->feature_status); - printf(" Active Bucket Timer %d min \n", - C0_ACTIVE_BUCKET_TIMER_INCREMENT * - le16_to_cpu(log_data->active_bucket_timer)); - printf(" Active Bucket Timer Threshold %d min \n", - C0_ACTIVE_BUCKET_TIMER_INCREMENT * - le16_to_cpu(log_data->active_bucket_timer_threshold)); - printf(" Active Threshold A %d ms \n", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_a+1)); - printf(" Active Threshold B %d ms \n", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_b+1)); - printf(" Active Threshold C %d ms \n", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_c+1)); - printf(" Active Threshold D %d ms \n", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_d+1)); - printf(" Active Latency Minimum Window %d ms \n", - C0_MINIMUM_WINDOW_INCREMENT * - le16_to_cpu(log_data->active_latency_min_window)); - printf(" Active Latency Stamp Units %d \n", - le16_to_cpu(log_data->active_latency_stamp_units)); - printf(" Static Latency Stamp Units %d \n", - le16_to_cpu(log_data->static_latency_stamp_units)); - printf(" Debug Log Trigger Enable %d \n", - le16_to_cpu(log_data->debug_log_trigger_enable)); - - printf(" Read Write Deallocate/Trim \n"); - for (i = 0; i <= 3; i++) { - printf(" Active Latency Mode: Bucket %d %27d %27d %27d \n", - i, - log_data->active_latency_config & (1 << pos), - log_data->active_latency_config & (1 << pos), - log_data->active_latency_config & (1 << pos)); - } - printf("\n"); - for (i = 0; i <= 3; i++) { - printf(" Active Bucket Counter: Bucket %d %27d %27d %27d \n", - i, - le32_to_cpu(log_data->active_bucket_counter[i][READ]), - le32_to_cpu(log_data->active_bucket_counter[i][WRITE]), - le32_to_cpu(log_data->active_bucket_counter[i][TRIM])); - } + int i; + + printf(" Error Recovery/C1 Log Page Data\n"); + printf(" Panic Reset Wait Time : 0x%x\n", le16_to_cpu(log_data->panic_reset_wait_time)); + printf(" Panic Reset Action : 0x%x\n", log_data->panic_reset_action); + printf(" Device Recovery Action 1 : 0x%x\n", log_data->device_recover_action_1); + printf(" Panic ID : 0x%x\n", le32_to_cpu(log_data->panic_id)); + printf(" Device Capabilities : 0x%x\n", le32_to_cpu(log_data->device_capabilities)); + printf(" Vendor Specific Recovery Opcode : 0x%x\n", log_data->vendor_specific_recovery_opcode); + printf(" Vendor Specific Command CDW12 : 0x%x\n", le32_to_cpu(log_data->vendor_specific_command_cdw12)); + printf(" Vendor Specific Command CDW13 : 0x%x\n", le32_to_cpu(log_data->vendor_specific_command_cdw13)); + printf(" Vendor Specific Command Timeout : 0x%x\n", log_data->vendor_specific_command_timeout); + printf(" Device Recovery Action 2 : 0x%x\n", log_data->device_recover_action_2); + printf(" Device Recovery Action 2 Timeout : 0x%x\n", log_data->device_recover_action_2_timeout); + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (i = C1_GUID_LENGTH - 1; i >= 0; i--) + printf("%x", log_data->log_page_guid[i]); + printf("\n"); +} - for (i = 0; i <= 3; i++) { - printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms \n", - i, - le16_to_cpu(log_data->active_measured_latency[i][READ]), - le16_to_cpu(log_data->active_measured_latency[i][WRITE]), - le16_to_cpu(log_data->active_measured_latency[i][TRIM])); - } +static void ocp_print_c1_log_json(struct ocp_error_recovery_log_page *log_data) +{ + struct json_object *root; + + root = json_create_object(); + char guid[64]; + + json_object_add_value_int(root, "Panic Reset Wait Time", le16_to_cpu(log_data->panic_reset_wait_time)); + json_object_add_value_int(root, "Panic Reset Action", log_data->panic_reset_action); + json_object_add_value_int(root, "Device Recovery Action 1", log_data->device_recover_action_1); + json_object_add_value_int(root, "Panic ID", le32_to_cpu(log_data->panic_id)); + json_object_add_value_int(root, "Device Capabilities", le32_to_cpu(log_data->device_capabilities)); + json_object_add_value_int(root, "Vendor Specific Recovery Opcode", log_data->vendor_specific_recovery_opcode); + json_object_add_value_int(root, "Vendor Specific Command CDW12", le32_to_cpu(log_data->vendor_specific_command_cdw12)); + json_object_add_value_int(root, "Vendor Specific Command CDW13", le32_to_cpu(log_data->vendor_specific_command_cdw13)); + json_object_add_value_int(root, "Vendor Specific Command Timeout", log_data->vendor_specific_command_timeout); + json_object_add_value_int(root, "Device Recovery Action 2", log_data->device_recover_action_2); + json_object_add_value_int(root, "Device Recovery Action 2 Timeout", log_data->device_recover_action_2_timeout); + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + + memset((void *)guid, 0, 64); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); + json_object_add_value_string(root, "Log page GUID", guid); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} - for (i = 0; i <= 3; i++) { - printf(" Active Latency Time Stamp: Bucket %d ", i); - for (j = 0; j <= 2; j++) { - if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) - printf(" N/A "); - else { - convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf); - printf("%s ", ts_buf); - } - } - printf("\n"); - } +static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data) +{ + return d_raw((unsigned char *)log_data, sizeof(*log_data)); +} - for (i = 0; i <= 3; i++) { - printf(" Static Bucket Counter: Bucket %d %27d %27d %27d \n", - i, - le32_to_cpu(log_data->static_bucket_counter[i][READ]), - le32_to_cpu(log_data->static_bucket_counter[i][WRITE]), - le32_to_cpu(log_data->static_bucket_counter[i][TRIM])); - } +static int get_c1_log_page(struct nvme_dev *dev, char *format) +{ + struct ocp_error_recovery_log_page *log_data; + enum nvme_print_flags fmt; + int ret; + __u8 *data; + int i, j; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + data = (__u8 *)malloc(sizeof(__u8) * C1_ERROR_RECOVERY_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof(__u8) * C1_ERROR_RECOVERY_LOG_BUF_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), C1_ERROR_RECOVERY_OPCODE, C1_ERROR_RECOVERY_LOG_BUF_LEN, data); + + if (!ret) { + log_data = (struct ocp_error_recovery_log_page *)data; + + /* check log page version */ + if (log_data->log_page_version != C1_ERROR_RECOVERY_VERSION) { + fprintf(stderr, "ERROR : OCP : invalid error recovery log page version\n"); + ret = -1; + goto out; + } + + /* + * check log page guid + * Verify GUID matches + */ + for (i = 0; i < 16; i++) { + if (error_recovery_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : OCP : Unknown GUID in C1 Log Page data\n"); + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", error_recovery_guid[j]); + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", log_data->log_page_guid[j]); + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + switch (fmt) { + case NORMAL: + ocp_print_c1_log_normal(log_data); + break; + case JSON: + ocp_print_c1_log_json(log_data); + break; + case BINARY: + ocp_print_c1_log_binary(log_data); + break; + default: + break; + } + } else { + fprintf(stderr, "ERROR : OCP : Unable to read C1 data from buffer\n"); + } - for (i = 0; i <= 3; i++) { - printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms \n", - i, - le16_to_cpu(log_data->static_measured_latency[i][READ]), - le16_to_cpu(log_data->static_measured_latency[i][WRITE]), - le16_to_cpu(log_data->static_measured_latency[i][TRIM])); - } +out: + free(data); + return ret; +} - for (i = 0; i <= 3; i++) { - printf(" Static Latency Time Stamp: Bucket %d ", i); - for (j = 0; j <= 2; j++) { - if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) - printf(" N/A "); - else { - convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf); - printf("%s ", ts_buf); - } - } - printf("\n"); - } +static int ocp_error_recovery_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Retrieve C1h Error Recovery Log data."; + struct nvme_dev *dev; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json|binary"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_c1_log_page(dev, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C1h Log Page, ret = %d\n", ret); + dev_close(dev); + return ret; +} - return 0; +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Device Capabilities (Log Identifier C4h) Requirements + +#define C4_DEV_CAP_REQ_LEN 0x1000 +#define C4_DEV_CAP_REQ_OPCODE 0xC4 +#define C4_DEV_CAP_REQ_VERSION 0x0001 +#define C4_GUID_LENGTH 16 +static __u8 dev_cap_req_guid[C4_GUID_LENGTH] = { + 0x97, 0x42, 0x05, 0x0d, + 0xd1, 0xe1, 0xc9, 0x98, + 0x5d, 0x49, 0x58, 0x4b, + 0x91, 0x3c, 0x05, 0xb7 +}; + +/** + * struct ocp_device_capabilities_log_page - Device Capability Log page + * @pcie_exp_port: PCI Express Ports + * @oob_management_support: OOB Management Support + * @wz_cmd_support: Write Zeroes Command Support + * @sanitize_cmd_support: Sanitize Command Support + * @dsm_cmd_support: Dataset Management Command Support + * @wu_cmd_support: Write Uncorrectable Command Support + * @fused_operation_support: Fused Operation Support + * @min_valid_dssd_pwr_state: Minimum Valid DSSD Power State + * @dssd_pwr_state_desc: DSSD Power State Descriptors + * @vendor_specific_command_timeout: Vendor Specific Command Timeout + * @reserved: Reserved + * @log_page_version: Log Page Version + * @log_page_guid: Log Page GUID + */ +struct __packed ocp_device_capabilities_log_page { + __le16 pcie_exp_port; + __le16 oob_management_support; + __le16 wz_cmd_support; + __le16 sanitize_cmd_support; + __le16 dsm_cmd_support; + __le16 wu_cmd_support; + __le16 fused_operation_support; + __le16 min_valid_dssd_pwr_state; + __u8 dssd_pwr_state_desc[128]; + __u8 reserved[3934]; + __le16 log_page_version; + __u8 log_page_guid[16]; +}; + +static void ocp_print_c4_log_normal(struct ocp_device_capabilities_log_page *log_data); +static void ocp_print_c4_log_json(struct ocp_device_capabilities_log_page *log_data); +static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log_data); +static int get_c4_log_page(struct nvme_dev *dev, char *format); +static int ocp_device_capabilities_log(int argc, char **argv, struct command *cmd, struct plugin *plugin); + +static void ocp_print_c4_log_normal(struct ocp_device_capabilities_log_page *log_data) +{ + int i; + + printf(" Device Capability/C4 Log Page Data\n"); + printf(" PCI Express Ports : 0x%x\n", le16_to_cpu(log_data->pcie_exp_port)); + printf(" OOB Management Support : 0x%x\n", le16_to_cpu(log_data->oob_management_support)); + printf(" Write Zeroes Command Support : 0x%x\n", le16_to_cpu(log_data->wz_cmd_support)); + printf(" Sanitize Command Support : 0x%x\n", le16_to_cpu(log_data->sanitize_cmd_support)); + printf(" Dataset Management Command Support : 0x%x\n", le16_to_cpu(log_data->dsm_cmd_support)); + printf(" Write Uncorrectable Command Support : 0x%x\n", le16_to_cpu(log_data->wu_cmd_support)); + printf(" Fused Operation Support : 0x%x\n", le16_to_cpu(log_data->fused_operation_support)); + printf(" Minimum Valid DSSD Power State : 0x%x\n", le16_to_cpu(log_data->min_valid_dssd_pwr_state)); + printf(" DSSD Power State Descriptors : 0x"); + for (i = 0; i <= 127; i++) + printf("%x", log_data->dssd_pwr_state_desc[i]); + printf("\n"); + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); + printf(" Log page GUID : 0x"); + for (i = C4_GUID_LENGTH - 1; i >= 0; i--) + printf("%x", log_data->log_page_guid[i]); + printf("\n"); } -static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data) +static void ocp_print_c4_log_json(struct ocp_device_capabilities_log_page *log_data) { - int i, j; - int pos = 0; - char buf[128]; - char ts_buf[128]; - char *operation[3] = {"Read", "Write", "Trim"}; - struct json_object *root; - root = json_create_object(); - - json_object_add_value_uint(root, "Feature Status", - log_data->feature_status); - json_object_add_value_uint(root, "Active Bucket Timer", - C0_ACTIVE_BUCKET_TIMER_INCREMENT * - le16_to_cpu(log_data->active_bucket_timer)); - json_object_add_value_uint(root, "Active Bucket Timer Threshold", - C0_ACTIVE_BUCKET_TIMER_INCREMENT * - le16_to_cpu(log_data->active_bucket_timer_threshold)); - json_object_add_value_uint(root, "Active Threshold A", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_a+1)); - json_object_add_value_uint(root, "Active Threshold B", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_b+1)); - json_object_add_value_uint(root, "Active Threshold C", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_c+1)); - json_object_add_value_uint(root, "Active Threshold D", - C0_ACTIVE_THRESHOLD_INCREMENT * - le16_to_cpu(log_data->active_threshold_d+1)); - json_object_add_value_uint(root, "Active Lantency Minimum Window", - C0_MINIMUM_WINDOW_INCREMENT * - le16_to_cpu(log_data->active_latency_min_window)); - json_object_add_value_uint(root, "Active Latency Stamp Units", - le16_to_cpu(log_data->active_latency_stamp_units)); - json_object_add_value_uint(root, "Static Latency Stamp Units", - le16_to_cpu(log_data->static_latency_stamp_units)); - json_object_add_value_uint(root, "Debug Log Trigger Enable", - le16_to_cpu(log_data->debug_log_trigger_enable)); - - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Active Latency Mode: Bucket %d", i); - for (j = 0; j <= 2; j++) { - json_object_add_value_uint(bucket, operation[j], - log_data->active_latency_config & (1 << pos)); - } - json_object_add_value_object(root, buf, bucket); - } - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Active Bucket Counter: Bucket %d", i); - for (j = 0; j <= 2; j++) { - json_object_add_value_uint(bucket, operation[j], - le32_to_cpu(log_data->active_bucket_counter[i][j])); - } - json_object_add_value_object(root, buf, bucket); - } - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Active Measured Latency: Bucket %d", i); - for (j = 0; j <= 2; j++) { - json_object_add_value_uint(bucket, operation[j], - le16_to_cpu(log_data->active_measured_latency[i][j])); - } - json_object_add_value_object(root, buf, bucket); - } - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Active Latency Time Stamp: Bucket %d", i); - for (j = 0; j <= 2; j++) { - if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) - json_object_add_value_string(bucket, operation[j], "NA"); - else { - convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf); - json_object_add_value_string(bucket, operation[j], ts_buf); - } - } - json_object_add_value_object(root, buf, bucket); - } - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Static Bucket Counter: Bucket %d", i); - for (j = 0; j <= 2; j++) { - json_object_add_value_uint(bucket, operation[j], - le32_to_cpu(log_data->static_bucket_counter[i][j])); - } - json_object_add_value_object(root, buf, bucket); - } - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Static Measured Latency: Bucket %d", i); - for (j = 0; j <= 2; j++) { - json_object_add_value_uint(bucket, operation[j], - le16_to_cpu(log_data->static_measured_latency[i][j])); - } - json_object_add_value_object(root, buf, bucket); - } - for (i = 0; i <= 3; i++) { - struct json_object *bucket; - bucket = json_create_object(); - sprintf(buf, "Static Latency Time Stamp: Bucket %d", i); - for (j = 0; j <= 2; j++) { - if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) - json_object_add_value_string(bucket, operation[j], "NA"); - else { - convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf); - json_object_add_value_string(bucket, operation[j], ts_buf); - } - } - json_object_add_value_object(root, buf, bucket); - } + struct json_object *root = json_create_object(); + char guid[64]; + int i; + + json_object_add_value_int(root, "PCI Express Ports", le16_to_cpu(log_data->pcie_exp_port)); + json_object_add_value_int(root, "OOB Management Support", le16_to_cpu(log_data->oob_management_support)); + json_object_add_value_int(root, "Write Zeroes Command Support", le16_to_cpu(log_data->wz_cmd_support)); + json_object_add_value_int(root, "Sanitize Command Support", le16_to_cpu(log_data->sanitize_cmd_support)); + json_object_add_value_int(root, "Dataset Management Command Support", le16_to_cpu(log_data->dsm_cmd_support)); + json_object_add_value_int(root, "Write Uncorrectable Command Support", le16_to_cpu(log_data->wu_cmd_support)); + json_object_add_value_int(root, "Fused Operation Support", le16_to_cpu(log_data->fused_operation_support)); + json_object_add_value_int(root, "Minimum Valid DSSD Power State", le16_to_cpu(log_data->min_valid_dssd_pwr_state)); + for (i = 0; i <= 127; i++) + json_object_add_value_int(root, "DSSD Power State Descriptors", log_data->dssd_pwr_state_desc[i]); + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + + memset((void *)guid, 0, 64); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); + json_object_add_value_string(root, "Log page GUID", guid); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log_data) +{ + return d_raw((unsigned char *)log_data, sizeof(*log_data)); +} - json_print_object(root, NULL); - printf("\n"); +static int get_c4_log_page(struct nvme_dev *dev, char *format) +{ + struct ocp_device_capabilities_log_page *log_data; + enum nvme_print_flags fmt; + int ret; + __u8 *data; + int i, j; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + data = (__u8 *)malloc(sizeof(__u8) * C4_DEV_CAP_REQ_LEN); + if (!data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof(__u8) * C4_DEV_CAP_REQ_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), C4_DEV_CAP_REQ_OPCODE, C4_DEV_CAP_REQ_LEN, data); + + if (!ret) { + log_data = (struct ocp_device_capabilities_log_page *)data; + + /* check log page version */ + if (log_data->log_page_version != C4_DEV_CAP_REQ_VERSION) { + fprintf(stderr, "ERROR : OCP : invalid device capabilities log page version\n"); + ret = -1; + goto out; + } + + /* + * check log page guid + * Verify GUID matches + */ + for (i = 0; i < 16; i++) { + if (dev_cap_req_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR : OCP : Unknown GUID in C4 Log Page data\n"); + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", dev_cap_req_guid[j]); + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", log_data->log_page_guid[j]); + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + switch (fmt) { + case NORMAL: + ocp_print_c4_log_normal(log_data); + break; + case JSON: + ocp_print_c4_log_json(log_data); + break; + case BINARY: + ocp_print_c4_log_binary(log_data); + break; + default: + break; + } + } else { + fprintf(stderr, "ERROR : OCP : Unable to read C4 data from buffer\n"); + } - json_free_object(root); +out: + free(data); + return ret; } -static int get_c3_log_page(struct nvme_dev *dev, char *format) +static int ocp_device_capabilities_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Retrieve C4h Device Capabilities Log data."; + struct nvme_dev *dev; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json|binary"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_c4_log_page(dev, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C4h Log Page, ret = %d\n", ret); + dev_close(dev); + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// DSSD Power State (Feature Identifier C7h) Set Feature + +static int set_dssd_power_state(struct nvme_dev *dev, const __u32 nsid, + const __u8 fid, __u8 power_state, bool save, + bool uuid) +{ + __u32 result; + int err; + int uuid_index = 0; + + if (uuid) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &uuid_index); + if (err || !uuid_index) { + nvme_show_error("ERROR: No OCP UUID index found"); + return err; + } + } + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = nsid, + .cdw11 = power_state, + .cdw12 = 0, + .save = save, + .uuidx = uuid_index, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_set_features(&args); + if (err > 0) { + nvme_show_status(err); + } else if (err < 0) { + nvme_show_perror("Define DSSD Power State"); + fprintf(stderr, "Command failed while parsing.\n"); + } else { + printf("Successfully set DSSD Power State (feature: 0xC7) to below values\n"); + printf("DSSD Power State: 0x%x\n", power_state); + printf("Save bit Value: 0x%x\n", save); + } + + return err; +} + +static int set_dssd_power_state_feature(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Define DSSD Power State (Feature Identifier C7h) Set Feature."; + const char *power_state = "DSSD Power State to set in watts"; + const char *save = "Specifies that the controller shall save the attribute"; + const __u32 nsid = 0; + const __u8 fid = 0xC7; + struct nvme_dev *dev; + int err; + + struct config { + __u8 power_state; + bool save; + }; + + struct config cfg = { + .power_state = 0, + .save = false, + }; + + OPT_ARGS(opts) = { + OPT_BYTE("power-state", 'p', &cfg.power_state, power_state), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_FLAG("no-uuid", 'n', NULL, + "Skip UUID index search (UUID index not required for OCP 1.0)"), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (argconfig_parse_seen(opts, "power state")) + err = set_dssd_power_state(dev, nsid, fid, cfg.power_state, + cfg.save, + !argconfig_parse_seen(opts, "no-uuid")); + + dev_close(dev); + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// plp_health_check_interval + +static int set_plp_health_check_interval(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - int ret = 0; - int fmt = -1; - __u8 *data; - int i; - struct ssd_latency_monitor_log *log_data; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : OCP : invalid output format\n"); - return fmt; + const char *desc = "Define Issue Set Feature command (FID : 0xC6) PLP Health Check Interval"; + const char *plp_health_interval = "[31:16]:PLP Health Check Interval"; + const char *save = "Specifies that the controller shall save the attribute"; + const __u32 nsid = 0; + const __u8 fid = 0xc6; + struct nvme_dev *dev; + int err; + __u32 result; + int uuid_index = 0; + + struct config { + __le16 plp_health_interval; + bool save; + }; + + struct config cfg = { + .plp_health_interval = 0, + .save = false, + }; + + OPT_ARGS(opts) = { + OPT_BYTE("plp_health_interval", 'p', &cfg.plp_health_interval, plp_health_interval), + OPT_FLAG("save", 's', &cfg.save, save), + OPT_FLAG("no-uuid", 'n', NULL, + "Skip UUID index search (UUID index not required for OCP 1.0)"), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + + if (!argconfig_parse_seen(opts, "no-uuid")) { + /* OCP 2.0 requires UUID index support */ + err = ocp_get_uuid_index(dev, &uuid_index); + if (err || !uuid_index) { + printf("ERROR: No OCP UUID index found"); + return err; } + } + + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = nsid, + .cdw11 = cfg.plp_health_interval << 16, + .cdw12 = 0, + .save = cfg.save, + .uuidx = uuid_index, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_set_features(&args); + if (err > 0) { + nvme_show_status(err); + } else if (err < 0) { + nvme_show_perror("Define PLP Health Check Interval"); + fprintf(stderr, "Command failed while parsing.\n"); + } else { + printf("Successfully set the PLP Health Check Interval"); + printf("PLP Health Check Interval: 0x%x\n", cfg.plp_health_interval); + printf("Save bit Value: 0x%x\n", cfg.save); + } + return err; +} + +static int get_plp_health_check_interval(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + + const char *desc = "Define Issue Get Feature command (FID : 0xC6) PLP Health Check Interval"; + const char *sel = "[0-3,8]: current/default/saved/supported/changed"; + const __u32 nsid = 0; + const __u8 fid = 0xc6; + struct nvme_dev *dev; + __u32 result; + int err; + + struct config { + __u8 sel; + }; + + struct config cfg = { + .sel = 0, + }; + + OPT_ARGS(opts) = { + OPT_BYTE("sel", 'S', &cfg.sel, sel), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + + struct nvme_get_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = fid, + .nsid = nsid, + .sel = cfg.sel, + .cdw11 = 0, + .uuidx = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + err = nvme_get_features(&args); + if (!err) { + printf("get-feature:0xC6 %s value: %#08x\n", nvme_select_to_string(cfg.sel), result); + + if (cfg.sel == NVME_GET_FEATURES_SEL_SUPPORTED) + nvme_show_select_result(fid, result); + } else { + nvme_show_error("Could not get feature: 0xC6"); + } + + return err; +} - if ((data = (__u8 *) malloc(sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); - return -1; +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Telemetry String Log Format Log Page (LID : C9h) + +/* C9 Telemetry String Log Format Log Page */ +#define C9_GUID_LENGTH 16 +#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9 +#define C9_TELEMETRY_STR_LOG_LEN 432 +#define C9_TELEMETRY_STR_LOG_SIST_OFST 431 + +/** + * struct telemetry_str_log_format - Telemetry String Log Format + * @log_page_version: indicates the version of the mapping this log page uses + * Shall be set to 01h. + * @reserved1: Reserved. + * @log_page_guid: Shall be set to B13A83691A8F408B9EA495940057AA44h. + * @sls: Shall be set to the number of DWORDS in the String Log. + * @reserved2: reserved. + * @sits: shall be set to the number of DWORDS in the Statistics + * Identifier String Table + * @ests: Shall be set to the number of DWORDS from byte 0 of this + * log page to the start of the Event String Table + * @estsz: shall be set to the number of DWORDS in the Event String Table + * @vu_eve_sts: Shall be set to the number of DWORDS from byte 0 of this + * log page to the start of the VU Event String Table + * @vu_eve_st_sz: shall be set to the number of DWORDS in the VU Event String Table + * @ascts: the number of DWORDS from byte 0 of this log page until the ASCII Table Starts. + * @asctsz: the number of DWORDS in the ASCII Table + * @fifo1: FIFO 0 ASCII String + * @fifo2: FIFO 1 ASCII String + * @fifo3: FIFO 2 ASCII String + * @fifo4: FIFO 3 ASCII String + * @fif05: FIFO 4 ASCII String + * @fifo6: FIFO 5 ASCII String + * @fifo7: FIFO 6 ASCII String + * @fifo8: FIFO 7 ASCII String + * @fifo9: FIFO 8 ASCII String + * @fifo10: FIFO 9 ASCII String + * @fif011: FIFO 10 ASCII String + * @fif012: FIFO 11 ASCII String + * @fifo13: FIFO 12 ASCII String + * @fif014: FIFO 13 ASCII String + * @fif015: FIFO 14 ASCII String + * @fif016: FIFO 15 ASCII String + * @reserved3: reserved + */ +struct __attribute__((__packed__)) telemetry_str_log_format { + __u8 log_page_version; + __u8 reserved1[15]; + __u8 log_page_guid[C9_GUID_LENGTH]; + __le64 sls; + __u8 reserved2[24]; + __le64 sits; + __le64 sitsz; + __le64 ests; + __le64 estsz; + __le64 vu_eve_sts; + __le64 vu_eve_st_sz; + __le64 ascts; + __le64 asctsz; + __u8 fifo1[16]; + __u8 fifo2[16]; + __u8 fifo3[16]; + __u8 fifo4[16]; + __u8 fifo5[16]; + __u8 fifo6[16]; + __u8 fifo7[16]; + __u8 fifo8[16]; + __u8 fifo9[16]; + __u8 fifo10[16]; + __u8 fifo11[16]; + __u8 fifo12[16]; + __u8 fifo13[16]; + __u8 fifo14[16]; + __u8 fifo15[16]; + __u8 fifo16[16]; + __u8 reserved3[48]; +}; + +/* + * struct statistics_id_str_table_entry - Statistics Identifier String Table Entry + * @vs_si: Shall be set the Vendor Unique Statistic Identifier number. + * @reserved1: Reserved + * @ascii_id_len: Shall be set the number of ASCII Characters that are valid. + * @ascii_id_ofst: Shall be set to the offset from DWORD 0/Byte 0 of the Start + * of the ASCII Table to the first character of the string for + * this Statistic Identifier string.. + * @reserved2 reserved + */ +struct __attribute__((__packed__)) statistics_id_str_table_entry { + __le16 vs_si; + __u8 reserved1; + __u8 ascii_id_len; + __le64 ascii_id_ofst; + __le32 reserved2; +}; + +/* + * struct event_id_str_table_entry - Event Identifier String Table Entry + * @deb_eve_class: Shall be set the Debug Class. + * @ei: Shall be set to the Event Identifier + * @ascii_id_len: Shall be set the number of ASCII Characters that are valid. + * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the + * ASCII table to the ASCII data for this identifier + * @reserved2 reserved + */ +struct __attribute__((__packed__)) event_id_str_table_entry { + __u8 deb_eve_class; + __le16 ei; + __u8 ascii_id_len; + __le64 ascii_id_ofst; + __le32 reserved2; +}; + +/* + * struct vu_event_id_str_table_entry - VU Event Identifier String Table Entry + * @deb_eve_class: Shall be set the Debug Class. + * @vu_ei: Shall be set to the VU Event Identifier + * @ascii_id_len: Shall be set the number of ASCII Characters that are valid. + * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the + * ASCII table to the ASCII data for this identifier + * @reserved reserved + */ +struct __attribute__((__packed__)) vu_event_id_str_table_entry { + __u8 deb_eve_class; + __le16 vu_ei; + __u8 ascii_id_len; + __le64 ascii_id_ofst; + __le32 reserved; +}; + +/* Function declaration for Telemetry String Log Format (LID:C9h) */ +static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd, + struct plugin *plugin); + + +static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u8 *log_data_buf) +{ + //calculating the index value for array + __le64 stat_id_index = (log_data->sitsz * 4) / 16; + __le64 eve_id_index = (log_data->estsz * 4) / 16; + __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16; + __le64 ascii_table_index = (log_data->asctsz * 4); + //Calculating the offset for dynamic fields. + __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4); + __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4); + __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4); + __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4); + struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index]; + struct event_id_str_table_entry event_id_str_table_arr[eve_id_index]; + struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index]; + __u8 ascii_table_info_arr[ascii_table_index]; + int j; + + printf(" Log Page Version : 0x%x\n", log_data->log_page_version); + + printf(" Reserved : "); + for (j = 0; j < 15; j++) + printf("%d", log_data->reserved1[j]); + printf("\n"); + + printf(" Log page GUID : 0x"); + for (j = C9_GUID_LENGTH - 1; j >= 0; j--) + printf("%x", log_data->log_page_guid[j]); + printf("\n"); + + printf(" Telemetry String Log Size : 0x%lx\n", le64_to_cpu(log_data->sls)); + + printf(" Reserved : "); + for (j = 0; j < 24; j++) + printf("%d", log_data->reserved2[j]); + printf("\n"); + + printf(" Statistics Identifier String Table Start : 0x%lx\n", le64_to_cpu(log_data->sits)); + printf(" Statistics Identifier String Table Size : 0x%lx\n", le64_to_cpu(log_data->sitsz)); + printf(" Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->ests)); + printf(" Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->estsz)); + printf(" VU Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->vu_eve_sts)); + printf(" VU Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->vu_eve_st_sz)); + printf(" ASCII Table Start : 0x%lx\n", le64_to_cpu(log_data->ascts)); + printf(" ASCII Table Size : 0x%lx\n", le64_to_cpu(log_data->asctsz)); + + printf(" FIFO 1 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo1[j], log_data->fifo1[j]); + } + + printf(" FIFO 2 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo2[j], log_data->fifo2[j]); + } + + printf(" FIFO 3 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo3[j], log_data->fifo3[j]); + } + + printf(" FIFO 4 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + + printf(" %d %d %c \n", j, log_data->fifo4[j], log_data->fifo4[j]); + } + + printf(" FIFO 5 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo5[j], log_data->fifo5[j]); + } + + printf(" FIFO 6 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo6[j], log_data->fifo6[j]); + } + + printf(" FIFO 7 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo7[j], log_data->fifo7[j]); + } + + printf(" FIFO 8 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf("index value ascii_val"); + printf(" %d %d %c \n", j, log_data->fifo8[j], log_data->fifo8[j]); + } + + printf(" FIFO 9 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo9[j], log_data->fifo9[j]); + } + + printf(" FIFO 10 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo10[j], log_data->fifo10[j]); + } + + printf(" FIFO 11 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo11[j], log_data->fifo11[j]); + } + + printf(" FIFO 12 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo12[j], log_data->fifo12[j]); + } + + printf(" FIFO 13 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo13[j], log_data->fifo13[j]); + } + + printf(" FIFO 14 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo14[j], log_data->fifo14[j]); + } + + printf(" FIFO 15 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo15[j], log_data->fifo16[j]); + } + + printf(" FIFO 16 ASCII String\n"); + printf(" index value ascii_val\n"); + for (j = 0; j < 16; j++){ + printf(" %d %d %c \n", j, log_data->fifo16[j], log_data->fifo16[j]); + } + + printf(" Reserved : "); + for (j = 0; j < 48; j++) + printf("%d", log_data->reserved3[j]); + printf("\n"); + + memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4)); + memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4)); + memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4)); + memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4)); + + printf(" Statistics Identifier String Table\n"); + for (j = 0; j < stat_id_index; j++){ + printf(" Vendor Specific Statistic Identifier : 0x%x\n",le16_to_cpu(stat_id_str_table_arr[j].vs_si)); + printf(" Reserved : 0x%d",stat_id_str_table_arr[j].reserved1); + printf(" ASCII ID Length : 0x%x\n",stat_id_str_table_arr[j].ascii_id_len); + printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst)); + printf(" Reserved : 0x%d\n",stat_id_str_table_arr[j].reserved2); + } + + printf(" Event Identifier String Table Entry\n"); + for (j = 0; j < eve_id_index; j++){ + printf(" Debug Event Class : 0x%x\n",event_id_str_table_arr[j].deb_eve_class); + printf(" Event Identifier : 0x%x\n",le16_to_cpu(event_id_str_table_arr[j].ei)); + printf(" ASCII ID Length : 0x%x\n",event_id_str_table_arr[j].ascii_id_len); + printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst)); + printf(" Reserved : 0x%d\n",event_id_str_table_arr[j].reserved2); + + } + + printf(" VU Event Identifier String Table Entry\n"); + for (j = 0; j < vu_eve_index; j++){ + printf(" Debug Event Class : 0x%x\n",vu_event_id_str_table_arr[j].deb_eve_class); + printf(" VU Event Identifier : 0x%x\n",le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei)); + printf(" ASCII ID Length : 0x%x\n",vu_event_id_str_table_arr[j].ascii_id_len); + printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst)); + printf(" Reserved : 0x%d\n",vu_event_id_str_table_arr[j].reserved); + + } + + printf(" ASCII Table\n"); + printf(" Byte Data_Byte ASCII_Character\n"); + for (j = 0; j < ascii_table_index; j++){ + printf(" %lld 0x%x %c \n",ascii_table_ofst+j,ascii_table_info_arr[j],ascii_table_info_arr[j]); + } + return 0; +} + +static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 *log_data_buf) +{ + struct json_object *root = json_create_object(); + struct json_object *stat_table = json_create_object(); + struct json_object *eve_table = json_create_object(); + struct json_object *vu_eve_table = json_create_object(); + struct json_object *entry = json_create_object(); + char res_arr[48]; + char *res = res_arr; + char guid_buf[C9_GUID_LENGTH]; + char *guid = guid_buf; + char fifo_arr[16]; + char *fifo = fifo_arr; + //calculating the index value for array + __le64 stat_id_index = (log_data->sitsz * 4) / 16; + __le64 eve_id_index = (log_data->estsz * 4) / 16; + __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16; + __le64 ascii_table_index = (log_data->asctsz * 4); + //Calculating the offset for dynamic fields. + __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4); + __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4); + __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4); + __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4); + struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index]; + struct event_id_str_table_entry event_id_str_table_arr[eve_id_index]; + struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index]; + __u8 ascii_table_info_arr[ascii_table_index]; + char ascii_buf[ascii_table_index]; + char *ascii = ascii_buf; + int j; + + json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + + memset((__u8 *)res, 0, 15); + for (j = 0; j < 15; j++) + res += sprintf(res, "%d", log_data->reserved1[j]); + json_object_add_value_string(root, "Reserved", res_arr); + + memset((void *)guid, 0, C9_GUID_LENGTH); + for (j = C9_GUID_LENGTH - 1; j >= 0; j--) + guid += sprintf(guid, "%02x", log_data->log_page_guid[j]); + json_object_add_value_string(root, "Log page GUID", guid_buf); + + json_object_add_value_int(root, "Telemetry String Log Size", le64_to_cpu(log_data->sls)); + + memset((__u8 *)res, 0, 24); + for (j = 0; j < 24; j++) + res += sprintf(res, "%d", log_data->reserved2[j]); + json_object_add_value_string(root, "Reserved", res_arr); + + json_object_add_value_int(root, "Statistics Identifier String Table Start", le64_to_cpu(log_data->sits)); + json_object_add_value_int(root, "Event String Table Start", le64_to_cpu(log_data->ests)); + json_object_add_value_int(root, "Event String Table Size", le64_to_cpu(log_data->estsz)); + json_object_add_value_int(root, "VU Event String Table Start", le64_to_cpu(log_data->vu_eve_sts)); + json_object_add_value_int(root, "VU Event String Table Size", le64_to_cpu(log_data->vu_eve_st_sz)); + json_object_add_value_int(root, "ASCII Table Start", le64_to_cpu(log_data->ascts)); + json_object_add_value_int(root, "ASCII Table Size", le64_to_cpu(log_data->asctsz)); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo1[j]); + json_object_add_value_string(root, "FIFO 1 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo2[j]); + json_object_add_value_string(root, "FIFO 2 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo3[j]); + json_object_add_value_string(root, "FIFO 3 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo4[j]); + json_object_add_value_string(root, "FIFO 4 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo5[j]); + json_object_add_value_string(root, "FIFO 5 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo6[j]); + json_object_add_value_string(root, "FIFO 6 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo7[j]); + json_object_add_value_string(root, "FIFO 7 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo8[j]); + json_object_add_value_string(root, "FIFO 8 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo9[j]); + json_object_add_value_string(root, "FIFO 9 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo10[j]); + json_object_add_value_string(root, "FIFO 10 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo11[j]); + json_object_add_value_string(root, "FIFO 11 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo12[j]); + json_object_add_value_string(root, "FIFO 12 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo13[j]); + json_object_add_value_string(root, "FIFO 13 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo14[j]); + json_object_add_value_string(root, "FIFO 14 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo15[j]); + json_object_add_value_string(root, "FIFO 15 ASCII String", fifo_arr); + + memset((void *)fifo, 0, 16); + for (j = 0; j < 16; j++) + fifo += sprintf(fifo, "%c", log_data->fifo16[j]); + json_object_add_value_string(root, "FIFO 16 ASCII String", fifo_arr); + + memset((__u8 *)res, 0, 48); + for (j = 0; j < 48; j++) + res += sprintf(res, "%d", log_data->reserved3[j]); + json_object_add_value_string(root, "Reserved", res_arr); + + memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4)); + memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4)); + memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4)); + memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4)); + + for (j = 0; j < stat_id_index; j++){ + json_object_add_value_int(entry, "Vendor Specific Statistic Identifier", le16_to_cpu(stat_id_str_table_arr[j].vs_si)); + json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved1)); + json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len)); + json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst)); + json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved2)); + json_array_add_value_object(stat_table, entry); + } + json_object_add_value_array(root, "Statistics Identifier String Table", stat_table); + + for (j = 0; j < eve_id_index; j++){ + json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(event_id_str_table_arr[j].deb_eve_class)); + json_object_add_value_int(entry, "Event Identifier", le16_to_cpu(event_id_str_table_arr[j].ei)); + json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(event_id_str_table_arr[j].ascii_id_len)); + json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst)); + json_object_add_value_int(entry, "Reserved", le64_to_cpu(event_id_str_table_arr[j].reserved2)); + json_array_add_value_object(eve_table, entry); + } + json_object_add_value_array(root, "Event Identifier String Table Entry", eve_table); + + for (j = 0; j < vu_eve_index; j++){ + json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class)); + json_object_add_value_int(entry, "VU Event Identifier", le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei)); + json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len)); + json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst)); + json_object_add_value_int(entry, "Reserved", le64_to_cpu(vu_event_id_str_table_arr[j].reserved)); + json_array_add_value_object(vu_eve_table, entry); + } + json_object_add_value_array(root, "VU Event Identifier String Table Entry", vu_eve_table); + + memset((void *)ascii, 0, ascii_table_index); + for (j = 0; j < ascii_table_index; j++) + ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]); + json_object_add_value_string(root, "ASCII Table", ascii_buf); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + json_free_object(stat_table); + json_free_object(eve_table); + json_free_object(vu_eve_table); + + return 0; +} + +static void ocp_print_c9_log_binary(__u8 *log_data_buf,int total_log_page_size) +{ + return d_raw((unsigned char *)log_data_buf, total_log_page_size); +} + +static int get_c9_log_page(struct nvme_dev *dev, char *format) +{ + int ret = 0; + __u8 *header_data; + struct telemetry_str_log_format *log_data; + enum nvme_print_flags fmt; + __u8 *full_log_buf_data = NULL; + __le64 stat_id_str_table_ofst = 0; + __le64 event_str_table_ofst = 0; + __le64 vu_event_str_table_ofst = 0; + __le64 ascii_table_ofst = 0; + __le64 total_log_page_sz = 0; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN); + if (!header_data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN); + + ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE, + C9_TELEMETRY_STR_LOG_LEN, header_data); + + if (!ret) { + log_data = (struct telemetry_str_log_format *)header_data; + printf("Statistics Identifier String Table Size = %lld\n",log_data->sitsz); + printf("Event String Table Size = %lld\n",log_data->estsz); + printf("VU Event String Table Size = %lld\n",log_data->vu_eve_st_sz); + printf("ASCII Table Size = %lld\n",log_data->asctsz); + + //Calculating the offset for dynamic fields. + stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4); + event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4); + vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4); + ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4); + total_log_page_sz = stat_id_str_table_ofst + event_str_table_ofst + vu_event_str_table_ofst + ascii_table_ofst; + + printf("stat_id_str_table_ofst = %lld\n",stat_id_str_table_ofst); + printf("event_str_table_ofst = %lld\n",event_str_table_ofst); + printf("vu_event_str_table_ofst = %lld\n",vu_event_str_table_ofst); + printf("ascii_table_ofst = %lld\n",ascii_table_ofst); + printf("total_log_page_sz = %lld\n",total_log_page_sz); + + full_log_buf_data = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz); + if (!full_log_buf_data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; } - memset(data, 0, sizeof (__u8) * C3_LATENCY_MON_LOG_BUF_LEN); - - ret = nvme_get_log_simple(dev_fd(dev), C3_LATENCY_MON_OPCODE, - C3_LATENCY_MON_LOG_BUF_LEN, data); - - if (strcmp(format, "json")) - fprintf(stderr, - "NVMe Status:%s(%x)\n", - nvme_status_to_string(ret, false), - ret); - - if (ret == 0) { - log_data = (struct ssd_latency_monitor_log*)data; - - /* check log page version */ - if (log_data->log_page_version != C3_LATENCY_MON_VERSION) { - fprintf(stderr, - "ERROR : OCP : invalid latency monitor version\n"); - ret = -1; - goto out; - } - - /* check log page guid */ - /* Verify GUID matches */ - for (i=0; i<16; i++) { - if (lat_mon_guid[i] != log_data->log_page_guid[i]) { - fprintf(stderr,"ERROR : OCP : Unknown GUID in C3 Log Page data\n"); - int j; - fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); - for (j = 0; j<16; j++) { - fprintf(stderr, "%x", lat_mon_guid[j]); - } - fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); - for (j = 0; j<16; j++) { - fprintf(stderr, "%x", log_data->log_page_guid[j]); - } - fprintf(stderr, "\n"); - - ret = -1; - goto out; - } - } - - switch (fmt) { - case NORMAL: - ocp_print_C3_log_normal(dev, log_data); - break; - case JSON: - ocp_print_C3_log_json(log_data); - break; - } - } else { - fprintf(stderr, - "ERROR : OCP : Unable to read C3 data from buffer\n"); + memset(full_log_buf_data, 0, sizeof(__u8) * total_log_page_sz); + + ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE, + total_log_page_sz, full_log_buf_data); + + if (!ret) { + switch (fmt) { + case NORMAL: + ocp_print_C9_log_normal(log_data,full_log_buf_data); + break; + case JSON: + ocp_print_C9_log_json(log_data,full_log_buf_data); + break; + case BINARY: + ocp_print_c9_log_binary(full_log_buf_data,total_log_page_sz); + break; + default: + fprintf(stderr, "unhandled output format\n"); + break; + } + } else{ + fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); } + } else { + fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n"); + } -out: - free(data); - return ret; + free(header_data); + free(full_log_buf_data); + + return ret; } -static int ocp_latency_monitor_log(int argc, char **argv, struct command *command, - struct plugin *plugin) +static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd, + struct plugin *plugin) { - const char *desc = "Retrieve latency monitor log data."; - struct nvme_dev *dev; - int ret = 0; - - struct config { - char *output_format; - }; - - struct config cfg = { - .output_format = "normal", - }; - - OPT_ARGS(opts) = { - OPT_FMT("output-format", 'o', &cfg.output_format, - "output Format: normal|json"), - OPT_END() - }; - - ret = parse_and_open(&dev, argc, argv, desc, opts); - if (ret) - return ret; - - ret = get_c3_log_page(dev, cfg.output_format); - if (ret) - fprintf(stderr, - "ERROR : OCP : Failure reading the C3 Log Page, ret = %d\n", - ret); - dev_close(dev); + struct nvme_dev *dev; + int ret = 0; + const char *desc = "Retrieve telemetry string log format"; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) return ret; + + ret = get_c9_log_page(dev, cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret); + + dev_close(dev); + + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/// Misc + +static int clear_fw_update_history(int argc, char **argv, + struct command *cmd, struct plugin *plugin) +{ + return ocp_clear_fw_update_history(argc, argv, cmd, plugin); +} + +static int smart_add_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_smart_add_log(argc, argv, cmd, plugin); +} + +static int clear_pcie_correctable_error_counters(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_clear_pcie_correctable_errors(argc, argv, cmd, plugin); +} + +static int fw_activation_history_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_fw_activation_history_log(argc, argv, cmd, plugin); } diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h index 3e3f437aea..95539b068a 100644 --- a/plugins/ocp/ocp-nvme.h +++ b/plugins/ocp/ocp-nvme.h @@ -3,7 +3,7 @@ * * Authors: Arthur Shau , * Wei Zhang , - * Venkat Ramesh + * Venkat Ramesh */ #undef CMD_INC_FILE #define CMD_INC_FILE plugins/ocp/ocp-nvme @@ -14,10 +14,23 @@ #include "cmd.h" PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION), - COMMAND_LIST( - ENTRY("smart-add-log", "Retrieve extended SMART Information", ocp_smart_add_log) - ENTRY("latency-monitor-log", "Get Latency Monitor Log Page", ocp_latency_monitor_log) - ) + COMMAND_LIST( + ENTRY("smart-add-log", "Retrieve extended SMART Information", smart_add_log) + ENTRY("latency-monitor-log", "Get Latency Monitor Log Page", ocp_latency_monitor_log) + ENTRY("set-latency-monitor-feature", "Set Latency Monitor feature", ocp_set_latency_monitor_feature) + ENTRY("internal-log", "Retrieve and save internal device telemetry log", ocp_telemetry_log) + ENTRY("clear-fw-activate-history", "Clear firmware update history log", clear_fw_update_history) + ENTRY("eol-plp-failure-mode", "Define EOL or PLP circuitry failure mode.", eol_plp_failure_mode) + ENTRY("clear-pcie-correctable-errors", "Clear PCIe correctable error counters", clear_pcie_correctable_error_counters) + ENTRY("fw-activate-history", "Get firmware activation history log", fw_activation_history_log) + ENTRY("unsupported-reqs-log", "Get Unsupported Requirements Log Page", ocp_unsupported_requirements_log) + ENTRY("error-recovery-log", "Retrieve Error Recovery Log Page", ocp_error_recovery_log) + ENTRY("device-capability-log", "Get Device capabilities Requirements Log Page", ocp_device_capabilities_log) + ENTRY("set-dssd-power-state-feature", "Get Device capabilities Requirements Log Page", set_dssd_power_state_feature) + ENTRY("set-plp-health-check-interval", "Set PLP Health Check Interval", set_plp_health_check_interval) + ENTRY("get-plp-health-check-interval", "Get PLP Health Check Interval", get_plp_health_check_interval) + ENTRY("telemetry-string-log", "Retrieve Telemetry string Log Page", ocp_telemetry_str_log_format) + ) ); #endif diff --git a/plugins/ocp/ocp-smart-extended-log.c b/plugins/ocp/ocp-smart-extended-log.c new file mode 100644 index 0000000000..0d8ba81069 --- /dev/null +++ b/plugins/ocp/ocp-smart-extended-log.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2022 Meta Platforms, Inc. + * + * Authors: Arthur Shau , + * Wei Zhang , + * Venkat Ramesh + */ + +#include "ocp-smart-extended-log.h" + +#include +#include + +#include "common.h" +#include "nvme-print.h" + +/* C0 SCAO Log Page */ +#define C0_SMART_CLOUD_ATTR_LEN 0x200 +#define C0_SMART_CLOUD_ATTR_OPCODE 0xC0 +#define C0_GUID_LENGTH 16 + +static __u8 scao_guid[C0_GUID_LENGTH] = { + 0xC5, 0xAF, 0x10, 0x28, + 0xEA, 0xBF, 0xF2, 0xA4, + 0x9C, 0x4F, 0x6F, 0x7C, + 0xC9, 0x14, 0xD5, 0xAF +}; + +enum { + SCAO_PMUW = 0, /* Physical media units written */ + SCAO_PMUR = 16, /* Physical media units read */ + SCAO_BUNBR = 32, /* Bad user nand blocks raw */ + SCAO_BUNBN = 38, /* Bad user nand blocks normalized */ + SCAO_BSNBR = 40, /* Bad system nand blocks raw */ + SCAO_BSNBN = 46, /* Bad system nand blocks normalized */ + SCAO_XRC = 48, /* XOR recovery count */ + SCAO_UREC = 56, /* Uncorrectable read error count */ + SCAO_SEEC = 64, /* Soft ecc error count */ + SCAO_EEDC = 72, /* End to end detected errors */ + SCAO_EECE = 76, /* End to end corrected errors */ + SCAO_SDPU = 80, /* System data percent used */ + SCAO_RFSC = 81, /* Refresh counts */ + SCAO_MXUDEC = 88, /* Max User data erase counts */ + SCAO_MNUDEC = 92, /* Min User data erase counts */ + SCAO_NTTE = 96, /* Number of Thermal throttling events */ + SCAO_CTS = 97, /* Current throttling status */ + SCAO_EVF = 98, /* Errata Version Field */ + SCAO_PVF = 99, /* Point Version Field */ + SCAO_MIVF = 101, /* Minor Version Field */ + SCAO_MAVF = 103, /* Major Version Field */ + SCAO_PCEC = 104, /* PCIe correctable error count */ + SCAO_ICS = 112, /* Incomplete shutdowns */ + SCAO_PFB = 120, /* Percent free blocks */ + SCAO_CPH = 128, /* Capacitor health */ + SCAO_NEV = 130, /* NVMe Errata Version */ + SCAO_UIO = 136, /* Unaligned I/O */ + SCAO_SVN = 144, /* Security Version Number */ + SCAO_NUSE = 152, /* NUSE - Namespace utilization */ + SCAO_PSC = 160, /* PLP start count */ + SCAO_EEST = 176, /* Endurance estimate */ + SCAO_PLRC = 192, /* PCIe Link Retraining Count */ + SCAO_PSCC = 200, /* Power State Change Count */ + SCAO_LPV = 494, /* Log page version */ + SCAO_LPG = 496, /* Log page GUID */ +}; + +static void ocp_print_C0_log_normal(void *data) +{ + uint16_t smart_log_ver = 0; + __u8 *log_data = data; + + printf("SMART Cloud Attributes :-\n"); + + printf(" Physical media units written - %"PRIu64" %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); + printf(" Physical media units read - %"PRIu64" %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); + printf(" Bad user nand blocks - Raw %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); + printf(" Bad user nand blocks - Normalized %d\n", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); + printf(" Bad system nand blocks - Raw %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); + printf(" Bad system nand blocks - Normalized %d\n", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); + printf(" XOR recovery count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); + printf(" Uncorrectable read error count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); + printf(" Soft ecc error count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); + printf(" End to end detected errors %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); + printf(" End to end corrected errors %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); + printf(" System data percent used %d\n", + (__u8)log_data[SCAO_SDPU]); + printf(" Refresh counts %"PRIu64"\n", + (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF)); + printf(" Max User data erase counts %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); + printf(" Min User data erase counts %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); + printf(" Number of Thermal throttling events %d\n", + (__u8)log_data[SCAO_NTTE]); + printf(" Current throttling status 0x%x\n", + (__u8)log_data[SCAO_CTS]); + printf(" PCIe correctable error count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); + printf(" Incomplete shutdowns %"PRIu32"\n", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); + printf(" Percent free blocks %d\n", + (__u8)log_data[SCAO_PFB]); + printf(" Capacitor health %"PRIu16"\n", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); + printf(" Unaligned I/O %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); + printf(" Security Version Number %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); + printf(" NUSE - Namespace utilization %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); + printf(" PLP start count %s\n", + uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PSC]))); + printf(" Endurance estimate %s\n", + uint128_t_to_string(le128_to_cpu(&log_data[SCAO_EEST]))); + smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); + printf(" Log page version %"PRIu16"\n", smart_log_ver); + printf(" Log page GUID 0x"); + printf("%"PRIx64"%"PRIx64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); + if (smart_log_ver > 2) { + printf(" Errata Version Field %d\n", + (__u8)log_data[SCAO_EVF]); + printf(" Point Version Field %"PRIu16"\n", + le16_to_cpu(*(uint16_t *)&log_data[SCAO_PVF])); + printf(" Minor Version Field %"PRIu16"\n", + le16_to_cpu(*(uint16_t *)&log_data[SCAO_MIVF])); + printf(" Major Version Field %d\n", + (__u8)log_data[SCAO_MAVF]); + printf(" NVMe Errata Version %d\n", + (__u8)log_data[SCAO_NEV]); + printf(" PCIe Link Retraining Count %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); + printf(" Power State Change Count %"PRIu64"\n", + le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); + } + printf("\n"); +} + +static void ocp_print_C0_log_json(void *data) +{ + struct json_object *root; + struct json_object *pmuw; + struct json_object *pmur; + uint16_t smart_log_ver = 0; + __u8 *log_data = data; + char guid[40]; + + root = json_create_object(); + pmuw = json_create_object(); + pmur = json_create_object(); + + json_object_add_value_uint64(pmuw, "hi", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_uint64(pmuw, "lo", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_object(root, "Physical media units written", pmuw); + json_object_add_value_uint64(pmur, "hi", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_uint64(pmur, "lo", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF)); + json_object_add_value_object(root, "Physical media units read", pmur); + json_object_add_value_uint64(root, "Bad user nand blocks - Raw", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); + json_object_add_value_uint(root, "Bad user nand blocks - Normalized", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); + json_object_add_value_uint64(root, "Bad system nand blocks - Raw", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); + json_object_add_value_uint(root, "Bad system nand blocks - Normalized", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); + json_object_add_value_uint64(root, "XOR recovery count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); + json_object_add_value_uint64(root, "Uncorrectable read error count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); + json_object_add_value_uint64(root, "Soft ecc error count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); + json_object_add_value_uint(root, "End to end detected errors", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); + json_object_add_value_uint(root, "End to end corrected errors", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); + json_object_add_value_uint(root, "System data percent used", + (__u8)log_data[SCAO_SDPU]); + json_object_add_value_uint64(root, "Refresh counts", + (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF)); + json_object_add_value_uint(root, "Max User data erase counts", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); + json_object_add_value_uint(root, "Min User data erase counts", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); + json_object_add_value_uint(root, "Number of Thermal throttling events", + (__u8)log_data[SCAO_NTTE]); + json_object_add_value_uint(root, "Current throttling status", + (__u8)log_data[SCAO_CTS]); + json_object_add_value_uint64(root, "PCIe correctable error count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); + json_object_add_value_uint(root, "Incomplete shutdowns", + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); + json_object_add_value_uint(root, "Percent free blocks", + (__u8)log_data[SCAO_PFB]); + json_object_add_value_uint(root, "Capacitor health", + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); + json_object_add_value_uint64(root, "Unaligned I/O", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); + json_object_add_value_uint64(root, "Security Version Number", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); + json_object_add_value_uint64(root, "NUSE - Namespace utilization", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); + json_object_add_value_uint128(root, "PLP start count", + le128_to_cpu(&log_data[SCAO_PSC])); + json_object_add_value_uint128(root, "Endurance estimate", + le128_to_cpu(&log_data[SCAO_EEST])); + smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); + + json_object_add_value_uint(root, "Log page version", smart_log_ver); + + memset((void *)guid, 0, 40); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); + json_object_add_value_string(root, "Log page GUID", guid); + + if (smart_log_ver > 2) { + json_object_add_value_uint(root, "Errata Version Field", + (__u8)log_data[SCAO_EVF]); + json_object_add_value_uint(root, "Point Version Field", + le16_to_cpu(*(uint16_t *)&log_data[SCAO_PVF])); + json_object_add_value_uint(root, "Minor Version Field", + le16_to_cpu(*(uint16_t *)&log_data[SCAO_MIVF])); + json_object_add_value_uint(root, "Major Version Field", + (__u8)log_data[SCAO_MAVF]); + json_object_add_value_uint(root, "NVMe Errata Version", + (__u8)log_data[SCAO_NEV]); + json_object_add_value_uint(root, "PCIe Link Retraining Count", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); + json_object_add_value_uint(root, "Power State Change Count", + le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); + } + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static int get_c0_log_page(int fd, char *format) +{ + enum nvme_print_flags fmt; + __u8 *data; + int i; + int ret; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR : OCP : invalid output format\n"); + return ret; + } + + data = malloc(sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN); + if (!data) { + fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno)); + return -1; + } + memset(data, 0, sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN); + + ret = nvme_get_log_simple(fd, C0_SMART_CLOUD_ATTR_OPCODE, + C0_SMART_CLOUD_ATTR_LEN, data); + + if (strcmp(format, "json")) + fprintf(stderr, "NVMe Status:%s(%x)\n", + nvme_status_to_string(ret, false), ret); + + if (ret == 0) { + /* check log page guid */ + /* Verify GUID matches */ + for (i = 0; i < 16; i++) { + if (scao_guid[i] != data[SCAO_LPG + i]) { + int j; + + fprintf(stderr, "ERROR : OCP : Unknown GUID in C0 Log Page data\n"); + fprintf(stderr, "ERROR : OCP : Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", scao_guid[j]); + + fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", data[SCAO_LPG + j]); + fprintf(stderr, "\n"); + + ret = -1; + goto out; + } + } + + /* print the data */ + switch (fmt) { + case NORMAL: + ocp_print_C0_log_normal(data); + break; + case JSON: + ocp_print_C0_log_json(data); + break; + default: + break; + } + } else { + fprintf(stderr, "ERROR : OCP : Unable to read C0 data from buffer\n"); + } + +out: + free(data); + return ret; +} + +int ocp_smart_add_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Retrieve the extended SMART health data."; + struct nvme_dev *dev; + int ret = 0; + + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, "output Format: normal|json"), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + ret = get_c0_log_page(dev_fd(dev), cfg.output_format); + if (ret) + fprintf(stderr, "ERROR : OCP : Failure reading the C0 Log Page, ret = %d\n", + ret); + dev_close(dev); + return ret; +} diff --git a/plugins/ocp/ocp-smart-extended-log.h b/plugins/ocp/ocp-smart-extended-log.h new file mode 100644 index 0000000000..42c1f9856a --- /dev/null +++ b/plugins/ocp/ocp-smart-extended-log.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (c) 2022 Meta Platforms, Inc. + * + * Authors: Arthur Shau , + * Wei Zhang , + * Venkat Ramesh + */ + +#ifndef OCP_SMART_EXTENDED_LOG_H +#define OCP_SMART_EXTENDED_LOG_H + +struct command; +struct plugin; + +int ocp_smart_add_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin); + +#endif diff --git a/plugins/ocp/ocp-utils.c b/plugins/ocp/ocp-utils.c new file mode 100644 index 0000000000..1257b300fc --- /dev/null +++ b/plugins/ocp/ocp-utils.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include +#include "ocp-utils.h" +#include "nvme-print.h" + +const unsigned char ocp_uuid[NVME_UUID_LEN] = { + 0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94, 0xa2, 0x1d, + 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f }; + +int ocp_get_uuid_index(struct nvme_dev *dev, int *index) +{ + struct nvme_id_uuid_list uuid_list; + int err = nvme_identify_uuid(dev_fd(dev), &uuid_list); + + *index = 0; + if (err) + return err; + + for (int i = 0; i < NVME_ID_UUID_LIST_MAX; i++) { + if (memcmp(ocp_uuid, &uuid_list.entry[i].uuid, NVME_UUID_LEN) == 0) { + *index = i + 1; + break; + } + } + return err; +} diff --git a/plugins/ocp/ocp-utils.h b/plugins/ocp/ocp-utils.h new file mode 100644 index 0000000000..d02bea99a0 --- /dev/null +++ b/plugins/ocp/ocp-utils.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "nvme.h" + +/** + * ocp_get_uuid_index() - Get OCP UUID index + * @dev: nvme device + * @index: integer pointer to here to save the index + * @result: The command completion result from CQE dword0 + * + * Return: Zero if nvme device has UUID list log page, or result of get uuid list otherwise. + */ +int ocp_get_uuid_index(struct nvme_dev *dev, int *index); diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c index cd992a1d6a..f752d5d56a 100644 --- a/plugins/scaleflux/sfx-nvme.c +++ b/plugins/scaleflux/sfx-nvme.c @@ -3,20 +3,25 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include +#include +#include #include "common.h" #include "nvme.h" #include "libnvme.h" #include "plugin.h" #include "linux/types.h" +#include "nvme-wrap.h" #include "nvme-print.h" +#include "util/cleanup.h" #define CREATE_CMD #include "sfx-nvme.h" @@ -57,8 +62,7 @@ enum sfx_nvme_admin_opcode { nvme_admin_sfx_get_features = 0xd6, }; -struct sfx_freespace_ctx -{ +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 */ @@ -66,6 +70,10 @@ struct sfx_freespace_ctx __u64 hw_used; /* hw space used in 4K */ __u64 app_written; /* app data written in 4K */ __u64 out_of_space; + __u64 map_unit; + __u64 max_user_space; + __u64 extendible_user_cap_lba_count; + __u64 friendly_change_cap_support; }; struct nvme_capacity_info { @@ -75,72 +83,73 @@ struct nvme_capacity_info { __u64 free_space; }; -struct __attribute__((packed)) nvme_additional_smart_log_item { +struct __packed nvme_additional_smart_log_item { __u8 key; __u8 _kp[2]; __u8 norm; __u8 _np; - union __attribute__((packed)) { + union __packed { __u8 raw[6]; - struct __attribute__((packed)) wear_level { + struct __packed wear_level { __le16 min; __le16 max; __le16 avg; } wear_level; - struct __attribute__((packed)) thermal_throttle { + struct __packed thermal_throttle { __u8 pct; __u32 count; } thermal_throttle; - } ; + }; __u8 _rp; -} ; +}; struct nvme_additional_smart_log { - struct nvme_additional_smart_log_item program_fail_cnt; - struct nvme_additional_smart_log_item erase_fail_cnt; - struct nvme_additional_smart_log_item wear_leveling_cnt; - struct nvme_additional_smart_log_item e2e_err_cnt; - struct nvme_additional_smart_log_item crc_err_cnt; - struct nvme_additional_smart_log_item timed_workload_media_wear; - struct nvme_additional_smart_log_item timed_workload_host_reads; - struct nvme_additional_smart_log_item timed_workload_timer; - struct nvme_additional_smart_log_item thermal_throttle_status; - struct nvme_additional_smart_log_item retry_buffer_overflow_cnt; - struct nvme_additional_smart_log_item pll_lock_loss_cnt; - struct nvme_additional_smart_log_item nand_bytes_written; - struct nvme_additional_smart_log_item host_bytes_written; - struct nvme_additional_smart_log_item raid_recover_cnt; // errors which can be recovered by RAID - struct nvme_additional_smart_log_item prog_timeout_cnt; - struct nvme_additional_smart_log_item erase_timeout_cnt; - struct nvme_additional_smart_log_item read_timeout_cnt; - struct nvme_additional_smart_log_item read_ecc_cnt;//retry cnt - struct nvme_additional_smart_log_item non_media_crc_err_cnt; - struct nvme_additional_smart_log_item compression_path_err_cnt; - struct nvme_additional_smart_log_item out_of_space_flag; - struct nvme_additional_smart_log_item physical_usage_ratio; - struct nvme_additional_smart_log_item grown_bb; //grown bad block + struct nvme_additional_smart_log_item program_fail_cnt; + struct nvme_additional_smart_log_item erase_fail_cnt; + struct nvme_additional_smart_log_item wear_leveling_cnt; + struct nvme_additional_smart_log_item e2e_err_cnt; + struct nvme_additional_smart_log_item crc_err_cnt; + struct nvme_additional_smart_log_item timed_workload_media_wear; + struct nvme_additional_smart_log_item timed_workload_host_reads; + struct nvme_additional_smart_log_item timed_workload_timer; + struct nvme_additional_smart_log_item thermal_throttle_status; + struct nvme_additional_smart_log_item retry_buffer_overflow_cnt; + struct nvme_additional_smart_log_item pll_lock_loss_cnt; + struct nvme_additional_smart_log_item nand_bytes_written; + struct nvme_additional_smart_log_item host_bytes_written; + struct nvme_additional_smart_log_item raid_recover_cnt; /* errors which can be recovered by RAID */ + struct nvme_additional_smart_log_item prog_timeout_cnt; + struct nvme_additional_smart_log_item erase_timeout_cnt; + struct nvme_additional_smart_log_item read_timeout_cnt; + struct nvme_additional_smart_log_item read_ecc_cnt; /* retry cnt */ + struct nvme_additional_smart_log_item non_media_crc_err_cnt; + struct nvme_additional_smart_log_item compression_path_err_cnt; + struct nvme_additional_smart_log_item out_of_space_flag; + struct nvme_additional_smart_log_item physical_usage_ratio; + struct nvme_additional_smart_log_item grown_bb; /* grown bad block */ }; int nvme_query_cap(int fd, __u32 nsid, __u32 data_len, void *data) { - int rc = 0; - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_query_cap_info, - .nsid = nsid, - .addr = (__u64)(uintptr_t) data, - .data_len = data_len, - }; - - rc = ioctl(fd, SFX_GET_FREESPACE, data); - return rc == 0 ? 0 : nvme_submit_admin_passthru(fd, &cmd, NULL); + int rc = 0; + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_query_cap_info, + .nsid = nsid, + .addr = (__u64)(uintptr_t) data, + .data_len = data_len, + }; + + rc = ioctl(fd, SFX_GET_FREESPACE, data); + return rc ? nvme_submit_admin_passthru(fd, &cmd, NULL) : 0; } + int nvme_change_cap(int fd, __u32 nsid, __u64 capacity) { struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_change_cap, - .nsid = nsid, - .cdw10 = (capacity & 0xffffffff), - .cdw11 = (capacity >> 32), + .opcode = nvme_admin_change_cap, + .nsid = nsid, + .cdw10 = (capacity & 0xffffffff), + .cdw11 = (capacity >> 32), }; return nvme_submit_admin_passthru(fd, &cmd, NULL); @@ -149,10 +158,10 @@ int nvme_change_cap(int fd, __u32 nsid, __u64 capacity) int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value) { struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_sfx_set_features, - .nsid = nsid, - .cdw10 = fid, - .cdw11 = value, + .opcode = nvme_admin_sfx_set_features, + .nsid = nsid, + .cdw10 = fid, + .cdw11 = value, }; return nvme_submit_admin_passthru(fd, &cmd, NULL); @@ -161,16 +170,15 @@ int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value) int nvme_sfx_get_features(int fd, __u32 nsid, __u32 fid, __u32 *result) { int err = 0; - struct nvme_passthru_cmd cmd = { - .opcode = nvme_admin_sfx_get_features, - .nsid = nsid, - .cdw10 = fid, + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_sfx_get_features, + .nsid = nsid, + .cdw10 = fid, }; err = nvme_submit_admin_passthru(fd, &cmd, NULL); - if (!err && result) { + if (!err && result) *result = cmd.result; - } return err; } @@ -398,11 +406,11 @@ static void show_sfx_smart_log(struct nvme_additional_smart_log *smart, static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { struct nvme_additional_smart_log smart_log; - char *desc = "Get ScaleFlux vendor specific additional smart log (optionally, "\ - "for the specified namespace), and show it."; + 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"; + const char *json = "Dump output in json format"; struct nvme_dev *dev; struct config { __u32 namespace_id; @@ -438,14 +446,14 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, dev->name); else d_raw((unsigned char *)&smart_log, sizeof(smart_log)); - } - else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); return err; } -struct __attribute__((__packed__)) sfx_lat_stats_vanda { +struct __packed sfx_lat_stats_vanda { __u16 maj; __u16 min; __u32 bucket_1[32]; /* 0~1ms, step 32us */ @@ -456,7 +464,7 @@ struct __attribute__((__packed__)) sfx_lat_stats_vanda { __u32 bucket_6[1]; /* 4s+, specifically 4096ms+ */ }; -struct __attribute__((__packed__)) sfx_lat_stats_myrtle { +struct __packed sfx_lat_stats_myrtle { __u16 maj; __u16 min; __u32 bucket_1[64]; /* 0us~63us, step 1us */ @@ -482,7 +490,7 @@ struct __attribute__((__packed__)) sfx_lat_stats_myrtle { }; -struct __attribute__((__packed__)) sfx_lat_status_ver { +struct __packed sfx_lat_status_ver { __u16 maj; __u16 min; }; @@ -611,7 +619,8 @@ static void show_lat_stats_myrtle(struct sfx_lat_stats_myrtle *stats, int write) for (i = 0; i < 64; i++) printf("Bucket %2d: %u\n", i, stats->bucket_19[i]); - printf("\nAverage latency statistics %lld\n", stats->average); + printf("\nAverage latency statistics %" PRIu64 "\n", + (uint64_t)stats->average); } @@ -645,23 +654,22 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct sizeof(stats), (void *)&stats); if (!err) { if ((stats.ver.maj == VANDA_MAJOR_IDX) && (stats.ver.min == VANDA_MINOR_IDX)) { - if (!cfg.raw_binary) { + if (!cfg.raw_binary) show_lat_stats_vanda(&stats.vanda, cfg.write); - } else { + else d_raw((unsigned char *)&stats.vanda, sizeof(struct sfx_lat_stats_vanda)); - } } else if ((stats.ver.maj == MYRTLE_MAJOR_IDX) && (stats.ver.min == MYRTLE_MINOR_IDX)) { - if (!cfg.raw_binary) { + if (!cfg.raw_binary) show_lat_stats_myrtle(&stats.myrtle, cfg.write); - } else { + else d_raw((unsigned char *)&stats.myrtle, sizeof(struct sfx_lat_stats_myrtle)); - } } else { printf("ScaleFlux IO %s Command Latency Statistics Invalid Version Maj %d Min %d\n", - write ? "Write" : "Read", stats.ver.maj, stats.ver.min); + cfg.write ? "Write" : "Read", stats.ver.maj, stats.ver.min); } - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); return err; } @@ -696,7 +704,7 @@ 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 -EINVAL; } return sfx_nvme_get_log(fd, nsid, SFX_LOG_BBT, size, (void *)buf); @@ -730,7 +738,7 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size) remap_gbb_count = *((__u32 *)(bd_table + 4 * sizeof(__u32))); bb_elem = (__u64 *)(bd_table + 5 * sizeof(__u32)); - printf("Bad Block Table \n"); + 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); @@ -791,7 +799,7 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct err = get_bb_table(dev_fd(dev), 0xffffffff, data_buf, buf_size); if (err < 0) { perror("get-bad-block"); - } else if (err != 0) { + } else if (err) { nvme_show_status(err); } else { bd_table_show(data_buf, buf_size); @@ -815,6 +823,7 @@ static void show_cap_info(struct sfx_freespace_ctx *ctx) printf("used provisioned capacity:%5lluGB(0x%"PRIx64")\n", IDEMA_CAP2GB(ctx->phy_space) - IDEMA_CAP2GB(ctx->free_space), (uint64_t)(ctx->phy_space - ctx->free_space)); + printf("map_unit :0x%"PRIx64"K\n", (uint64_t)(ctx->map_unit * 4)); } static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -844,11 +853,10 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu } if (!err) { - if (!cfg.raw_binary) { + if (!cfg.raw_binary) show_cap_info(&ctx); - } else { + else d_raw((unsigned char *)&ctx, sizeof(ctx)); - } } dev_close(dev); return err; @@ -863,9 +871,8 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink) __u64 provisoned_cap_4k = 0; int extend = 0; - if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx)) { - return -1; - } + if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx)) + return -1; /* * capacity illegal check @@ -875,14 +882,13 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink) if (trg_in_4k < provisoned_cap_4k || trg_in_4k > ((__u64)provisoned_cap_4k * 4)) { fprintf(stderr, - "WARNING: Only support 1.0~4.0 x provisoned capacity!\n"); - if (trg_in_4k < provisoned_cap_4k) { + "WARNING: Only support 1.0~4.0 x provisioned capacity!\n"); + if (trg_in_4k < provisoned_cap_4k) fprintf(stderr, "WARNING: The target capacity is less than 1.0 x provisioned capacity!\n"); - } else { + else fprintf(stderr, "WARNING: The target capacity is larger than 4.0 x provisioned capacity!\n"); - } return -1; } if (trg_in_4k > ((__u64)provisoned_cap_4k*4)) { @@ -892,7 +898,7 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink) /* * check whether mem enough if extend - * */ + */ cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT); extend = (cur_in_4k <= trg_in_4k); if (extend) { @@ -903,10 +909,9 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink) mem_need = (trg_in_4k - cur_in_4k) * 8; if (s_info.freeram <= 10 || mem_need > s_info.freeram) { fprintf(stderr, - "WARNING: Free memory is not enough! " - "Please drop cache or extend more memory and retry\n" - "WARNING: Memory needed is %"PRIu64", free memory is %"PRIu64"\n", - (uint64_t)mem_need, (uint64_t)s_info.freeram); + "WARNING: Free memory is not enough! Please drop cache or extend more memory and retry\n" + "WARNING: Memory needed is %"PRIu64", free memory is %"PRIu64"\n", + (uint64_t)mem_need, (uint64_t)s_info.freeram); return -1; } } @@ -920,21 +925,22 @@ static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink) * * @param str, prompt string * - * @return 0, cancled; 1 confirmed + * @return 0, canceled; 1 confirmed */ static int sfx_confirm_change(const char *str) { unsigned char confirm; + fprintf(stderr, "WARNING: %s.\n" "Use the force [--force] option to suppress this warning.\n", str); fprintf(stderr, "Confirm Y/y, Others cancel:\n"); confirm = (unsigned char)fgetc(stdin); if (confirm != 'y' && confirm != 'Y') { - fprintf(stderr, "Cancled.\n"); + fprintf(stderr, "Canceled.\n"); return 0; } - fprintf(stderr, "Sending operation ... \n"); + fprintf(stderr, "Sending operation ...\n"); return 1; } @@ -992,11 +998,11 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin } err = nvme_change_cap(dev_fd(dev), 0xffffffff, cap_in_4k); - if (err < 0) + if (err < 0) { perror("sfx-change-cap"); - else if (err != 0) + } else if (err) { nvme_show_status(err); - else { + } else { printf("ScaleFlux change-capacity: success\n"); ioctl(dev_fd(dev), BLKRRPART); } @@ -1016,7 +1022,7 @@ static int sfx_verify_chr(int fd) if (!S_ISCHR(nvme_stat.st_mode)) { fprintf(stderr, "Error: requesting clean card on non-controller handle\n"); - return ENOTBLK; + return -ENOTBLK; } return 0; } @@ -1040,13 +1046,12 @@ static int sfx_clean_card(int fd) char *sfx_feature_to_string(int feature) { switch (feature) { - case SFX_FEAT_ATOMIC: - return "ATOMIC"; - case SFX_FEAT_UP_P_CAP: - return "UPDATE_PROVISION_CAPACITY"; - - default: - return "Unknown"; + case SFX_FEAT_ATOMIC: + return "ATOMIC"; + case SFX_FEAT_UP_P_CAP: + return "UPDATE_PROVISION_CAPACITY"; + default: + return "Unknown"; } } @@ -1092,7 +1097,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl if (!cfg.feature_id) { fprintf(stderr, "feature-id required param\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } if (cfg.feature_id == SFX_FEAT_CLR_CARD) { @@ -1106,7 +1111,7 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl } - if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value != 0) { + if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value) { if (cfg.namespace_id != 0xffffffff) { err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id, &ns); @@ -1124,14 +1129,14 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl if ((ns.flbas & 0xf) != 1) { printf("Please change-sector size to 4K, then retry\n"); dev_close(dev); - return EFAULT; + return -EFAULT; } } } else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) { if (cfg.value <= 0) { fprintf(stderr, "Invalid Param\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } /*Warning for change pacp by GB*/ @@ -1152,8 +1157,9 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl } else if (!err) { printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id, sfx_feature_to_string(cfg.feature_id), cfg.value); - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); return err; @@ -1191,7 +1197,7 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl if (!cfg.feature_id) { fprintf(stderr, "feature-id required param\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } err = nvme_sfx_get_features(dev_fd(dev), cfg.namespace_id, @@ -1203,10 +1209,479 @@ static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct pl } 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) + } else if (err > 0) { nvme_show_status(err); + } + + dev_close(dev); + return err; + +} + +static int nvme_parse_evtlog(void *pevent_log_info, __u32 log_len, char *output) +{ + __u32 offset = 0; + __u32 length = log_len; + __u16 fw_core; + __u64 fw_time; + __u8 code_level; + __u8 code_type; + char str_buffer[512]; + __u32 str_pos; + FILE *fd; + int err = 0; + + enum sfx_evtlog_level { + sfx_evtlog_level_warning, + sfx_evtlog_level_error, + }; + + const char *sfx_evtlog_warning[4] = { + "RESERVED", + "TOO_MANY_BB", + "LOW_SPACE", + "HIGH_TEMPERATURE" + }; + + const char *sfx_evtlog_error[14] = { + "RESERVED", + "HAS_ASSERT", + "HAS_PANIC_DUMP", + "INVALID_FORMAT_CAPACITY", + "MAT_FAILED", + "FREEZE_DUE_TO_RECOVERY_FAILED", + "RFS_BROKEN", + "MEDIA_ERR_ON_PAGE_IN", + "MEDIA_ERR_ON_MPAGE_HEADER", + "CAPACITOR_BROKEN", + "READONLY_DUE_TO_RECOVERY_FAILED", + "RD_ERR_IN_GSD_RECOVERY", + "RD_ERR_ON_PF_RECOVERY", + "MEDIA_ERR_ON_FULL_RECOVERY" + }; + + struct sfx_nvme_evtlog_info { + __u16 time_stamp[4]; + __u64 magic1; + __u8 reverse[10]; + char evt_name[32]; + __u64 magic2; + char fw_ver[24]; + char bl2_ver[32]; + __u16 code; + __u16 assert_id; + } __packed; + + struct sfx_nvme_evtlog_info *info = NULL; + + fd = fopen(output, "w+"); + if (!fd) { + fprintf(stderr, "Failed to open %s file to write\n", output); + err = ENOENT; + goto ret; + } + + while (length > 0) { + info = (struct sfx_nvme_evtlog_info *)(pevent_log_info + offset); + + if ((info->magic1 == 0x474F4C545645) && + (info->magic2 == 0x38B0B3ABA9BA)) { + + memset(str_buffer, 0, 512); + str_pos = 0; + + fw_core = info->time_stamp[3]; + snprintf(str_buffer + str_pos, 16, "[%d-", fw_core); + str_pos = strlen(str_buffer); + + fw_time = ((__u64)info->time_stamp[2] << 32) + ((__u64)info->time_stamp[1] << 16) + (__u64)info->time_stamp[0]; + convert_ts(fw_time, str_buffer + str_pos); + str_pos = strlen(str_buffer); + + strcpy(str_buffer + str_pos, "] event-log:\n"); + str_pos = strlen(str_buffer); + + snprintf(str_buffer + str_pos, 128, + " > fw_version: %s\n > bl2_version: %s\n", + info->fw_ver, info->bl2_ver); + str_pos = strlen(str_buffer); + + code_level = (info->code & 0x100) >> 8; + code_type = (info->code % 0x100); + if (code_level == sfx_evtlog_level_warning) { + snprintf(str_buffer + str_pos, 128, + " > error_str: [WARNING][%s]\n\n", + sfx_evtlog_warning[code_type]); + } else { + if (info->assert_id) + snprintf(str_buffer + str_pos, 128, + " > error_str: [ERROR][%s]\n > assert_id: %d\n\n", + sfx_evtlog_error[code_type], info->assert_id); + else + snprintf(str_buffer + str_pos, 128, + " > error_str: [ERROR][%s]\n\n", + sfx_evtlog_error[code_type]); + } + str_pos = strlen(str_buffer); + + if (fwrite(str_buffer, 1, str_pos, fd) != str_pos) { + fprintf(stderr, "Failed to write parse result to output file\n"); + goto close_fd; + } + } + + offset++; + length--; + + if (!(offset % (log_len / 100)) || (offset == log_len)) + util_spinner("Parse", (float) (offset) / (float) (log_len)); + } + + printf("\nParse-evtlog: Success\n"); + +close_fd: + fclose(fd); +ret: + return err; +} + +static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 storage_medium, + char *file, bool parse, char *output) +{ + struct nvme_persistent_event_log *pevent; + void *pevent_log_info; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; + __u8 lsp_base; + __u32 offset = 0; + __u32 length = 0; + __u32 log_len; + __u32 single_len; + int err = 0; + FILE *fd = NULL; + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = NVME_LOG_LID_PERSISTENT_EVENT, + .nsid = namespace_id, + .lpo = NVME_LOG_LPO_NONE, + .lsp = NVME_LOG_LSP_NONE, + .lsi = NVME_LOG_LSI_NONE, + .rae = false, + .uuidx = NVME_UUID_NONE, + .csi = NVME_CSI_NVM, + .ot = false, + .len = 0, + .log = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + + if (!storage_medium) { + lsp_base = 0; + single_len = 64 * 1024 - 4; + } else { + lsp_base = 4; + single_len = 32 * 1024; + } + + pevent = calloc(sizeof(*pevent), sizeof(__u8)); + if (!pevent) { + err = -ENOMEM; + goto ret; + } + + args.lsp = lsp_base + NVME_PEVENT_LOG_RELEASE_CTX; + args.log = pevent; + args.len = sizeof(*pevent); + + err = nvme_get_log(&args); + if (err) { + fprintf(stderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", args.lsp, err); + goto free_pevent; + } + + args.lsp = lsp_base + NVME_PEVENT_LOG_EST_CTX_AND_READ; + err = nvme_get_log(&args); + if (err) { + fprintf(stderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", args.lsp, err); + goto free_pevent; + } + + log_len = le64_to_cpu(pevent->tll); + if (log_len % 4) + log_len = (log_len / 4 + 1) * 4; + + pevent_log_info = nvme_alloc_huge(single_len, &mh); + if (!pevent_log_info) { + err = -ENOMEM; + goto free_pevent; + } + + fd = fopen(file, "wb+"); + if (!fd) { + fprintf(stderr, "Failed to open %s file to write\n", file); + err = ENOENT; + goto free_pevent; + } + + args.lsp = lsp_base + NVME_PEVENT_LOG_READ; + args.log = pevent_log_info; + length = log_len; + while (length > 0) { + args.lpo = offset; + if (length > single_len) { + args.len = single_len; + } else { + memset(args.log, 0, args.len); + args.len = length; + } + err = nvme_get_log(&args); + if (err) { + fprintf(stderr, "Unable to get evtlog offset=0x%x len 0x%x ret = 0x%x\n", offset, args.len, err); + goto close_fd; + } + + if (fwrite(args.log, 1, args.len, fd) != args.len) { + fprintf(stderr, "Failed to write evtlog to file\n"); + goto close_fd; + } + + offset += args.len; + length -= args.len; + util_spinner("Parse", (float) (offset) / (float) (log_len)); + } + + printf("\nDump-evtlog: Success\n"); + + if (parse) { + nvme_free_huge(&mh); + pevent_log_info = nvme_alloc_huge(log_len, &mh); + if (!pevent_log_info) { + fprintf(stderr, "Failed to alloc enough memory 0x%x to parse evtlog\n", log_len); + err = -ENOMEM; + goto close_fd; + } + + fclose(fd); + fd = fopen(file, "rb"); + if (!fd) { + fprintf(stderr, "Failed to open %s file to read\n", file); + err = ENOENT; + goto free_pevent; + } + if (fread(pevent_log_info, 1, log_len, fd) != log_len) { + fprintf(stderr, "Failed to read evtlog to buffer\n"); + goto close_fd; + } + + err = nvme_parse_evtlog(pevent_log_info, log_len, output); + } + +close_fd: + fclose(fd); +free_pevent: + free(pevent); +ret: + return err; +} + +static int sfx_dump_evtlog(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + char *desc = "dump evtlog into file and parse"; + const char *file = "evtlog file(required)"; + const char *namespace_id = "desired namespace"; + const char *storage_medium = "evtlog storage medium\n" + "0: nand(default) 1: nor"; + const char *parse = "parse error & warning evtlog from evtlog file"; + const char *output = "parse result output file"; + struct nvme_dev *dev; + int err = 0; + + struct config { + char *file; + __u32 namespace_id; + __u32 storage_medium; + bool parse; + char *output; + }; + struct config cfg = { + .file = NULL, + .namespace_id = 0xffffffff, + .storage_medium = 0, + .parse = false, + .output = NULL, + }; + + OPT_ARGS(opts) = { + OPT_FILE("file", 'f', &cfg.file, file), + OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id), + OPT_UINT("storage_medium", 's', &cfg.storage_medium, storage_medium), + OPT_FLAG("parse", 'p', &cfg.parse, parse), + OPT_FILE("output", 'o', &cfg.output, output), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + goto ret; + + if (!cfg.file) { + fprintf(stderr, "file required param\n"); + err = EINVAL; + goto close_dev; + } + + if (cfg.parse && !cfg.output) { + fprintf(stderr, "output file required if evtlog need be parsed\n"); + err = EINVAL; + goto close_dev; + } + err = nvme_dump_evtlog(dev, cfg.namespace_id, cfg.storage_medium, cfg.file, cfg.parse, cfg.output); + +close_dev: dev_close(dev); +ret: + return err; +} + +static int nvme_expand_cap(struct nvme_dev *dev, __u32 namespace_id, __u64 namespace_size, + __u64 namespace_cap, __u32 lbaf, __u32 units) +{ + struct dirent **devices; + char dev_name[32] = ""; + int i = 0; + int num = 0; + int err = 0; + + struct sfx_expand_cap_info { + __u64 namespace_size; + __u64 namespace_cap; + __u8 reserve[10]; + __u8 lbaf; + __u8 reserve1[5]; + } __packed; + + if (S_ISCHR(dev->direct.stat.st_mode)) + snprintf(dev_name, 32, "%sn%u", dev->name, namespace_id); + else + strcpy(dev_name, dev->name); + + num = scandir("/dev", &devices, nvme_namespace_filter, alphasort); + if (num <= 0) { + err = num; + goto ret; + } + + if (strcmp(dev_name, devices[num-1]->d_name)) { + fprintf(stderr, "Expand namespace not the last one\n"); + err = EINVAL; + goto free_devices; + } + + if (!units) { + namespace_size = IDEMA_CAP(namespace_size) / (1 << (lbaf * 3)); + namespace_cap = IDEMA_CAP(namespace_cap) / (1 << (lbaf * 3)); + } + + struct sfx_expand_cap_info info = { + .namespace_size = namespace_size, + .namespace_cap = namespace_cap, + .lbaf = lbaf, + }; + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_admin_ns_mgmt, + .nsid = namespace_id, + .addr = (__u64)(uintptr_t)&info, + .data_len = sizeof(info), + .cdw10 = 0x0e, + }; + + err = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); + if (err) { + fprintf(stderr, "Create ns failed\n"); + nvme_show_status(err); + goto free_devices; + } + +free_devices: + for (i = 0; i < num; i++) + free(devices[i]); + free(devices); +ret: return err; +} + +static int sfx_expand_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + char *desc = "expand capacity"; + const char *namespace_id = "desired namespace"; + const char *namespace_size = "namespace size(required)"; + const char *namespace_cap = "namespace capacity(required)"; + const char *lbaf = "LBA format to apply\n" + "0: 512(default) 1: 4096"; + const char *units = "namespace size/capacity units\n" + "0: GB(default) 1: LBA"; + struct nvme_dev *dev; + int err = 0; + + struct config { + __u32 namespace_id; + __u64 namespace_size; + __u64 namespace_cap; + __u32 lbaf; + __u32 units; + }; + struct config cfg = { + .namespace_id = 0xffffffff, + .lbaf = 0, + .units = 0, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id), + OPT_LONG("namespace_size", 's', &cfg.namespace_size, namespace_size), + OPT_LONG("namespace_cap", 'c', &cfg.namespace_cap, namespace_cap), + OPT_UINT("lbaf", 'l', &cfg.lbaf, lbaf), + OPT_UINT("units", 'u', &cfg.units, units), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + goto ret; + if (cfg.namespace_id == 0xffffffff) { + if (S_ISCHR(dev->direct.stat.st_mode)) { + fprintf(stderr, "namespace_id or blk device required\n"); + err = EINVAL; + goto ret; + } else { + cfg.namespace_id = atoi(&dev->name[strlen(dev->name) - 1]); + } + } + + if (!cfg.namespace_size) { + fprintf(stderr, "namespace_size required param\n"); + err = EINVAL; + goto close_dev; + } + + if (!cfg.namespace_cap) { + fprintf(stderr, "namespace_cap required param\n"); + err = EINVAL; + goto close_dev; + } + + err = nvme_expand_cap(dev, cfg.namespace_id, cfg.namespace_size, cfg.namespace_cap, cfg.lbaf, cfg.units); + if (err) + goto close_dev; + + printf("%s: Success, create nsid:%d\n", cmd->name, cfg.namespace_id); + +close_dev: + dev_close(dev); +ret: + return err; } diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h index 0b95d92d69..53e22179a4 100644 --- a/plugins/scaleflux/sfx-nvme.h +++ b/plugins/scaleflux/sfx-nvme.h @@ -16,6 +16,8 @@ PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions", NVME_VERSION), ENTRY("change-cap", "Dynamic change capacity", change_cap) ENTRY("set-feature", "Set a feature", sfx_set_feature) ENTRY("get-feature", "Get a feature", sfx_get_feature) + ENTRY("dump-evtlog", "dump evtlog into file and parse warning & error log", sfx_dump_evtlog) + ENTRY("expand-cap", "expand the last namespace capacity lossless", sfx_expand_cap) ) ); diff --git a/plugins/seagate/seagate-diag.h b/plugins/seagate/seagate-diag.h index 139901d310..39f0d39adc 100644 --- a/plugins/seagate/seagate-diag.h +++ b/plugins/seagate/seagate-diag.h @@ -18,6 +18,8 @@ * * \file seagate-diag.h * \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in. + * + * Author: Debabrata Bardhan */ @@ -25,19 +27,66 @@ #define SEAGATE_NVME_H #define SEAGATE_PLUGIN_VERSION_MAJOR 1 -#define SEAGATE_PLUGIN_VERSION_MINOR 1 +#define SEAGATE_PLUGIN_VERSION_MINOR 2 + +#define SEAGATE_OCP_PLUGIN_VERSION_MAJOR 1 +#define SEAGATE_OCP_PLUGIN_VERSION_MINOR 0 #define PERSIST_FILE_SIZE (2764800) #define ONE_MB (1048576) /* (1024 * 1024) */ #define PERSIST_CHUNK (65536) /* (1024 * 64) */ #define FOUR_KB (4096) +#define STX_NUM_LEGACY_DRV (123) + + +const char* stx_jag_pan_mn[STX_NUM_LEGACY_DRV] = {"ST1000KN0002", "ST1000KN0012", "ST2000KN0002", + "ST2000KN0012", "ST4000KN0002", "XP1600HE10002", + "XP1600HE10012", "XP1600HE30002", "XP1600HE30012", + "XP1920LE10002", "XP1920LE10012", "XP1920LE30002", + "XP1920LE30012", "XP3200HE10002", "XP3200HE10012", + "XP3840LE10002", "XP3840LE10012", "XP400HE30002", + "XP400HE30012", "XP400HE30022", "XP400HE30032", + "XP480LE30002", "XP480LE30012", "XP480LE30022", + "XP480LE30032", "XP800HE10002", "XP800HE10012", + "XP800HE30002", "XP800HE30012", "XP800HE30022", + "XP800HE30032", "XP960LE10002", "XP960LE10012", + "XP960LE30002", "XP960LE30012", "XP960LE30022", + "XP960LE30032", "XP256LE30011", "XP256LE30021", + "XP7680LE80002", "XP7680LE80003", "XP15360LE80003", + "XP30720LE80003", "XP7200-1A2048", "XP7200-1A4096", + "XP7201-2A2048", "XP7201-2A4096", "XP7200-1A8192", + "ST1000HM0021", "ST1000HM0031", "ST1000HM0061", + "ST1000HM0071", "ST1000HM0081", "ST1200HM0001", + "ST1600HM0031", "ST1800HM0001", "ST1800HM0011", + "ST2000HM0011", "ST2000HM0031", "ST400HM0061", + "ST400HM0071", "ST500HM0021", "ST500HM0031", + "ST500HM0061", "ST500HM0071", "ST500HM0081", + "ST800HM0061", "ST800HM0071", "ST1600HM0011", + "ST1600KN0001", "ST1600KN0011", "ST1920HM0001", + "ST1920KN0001", "ST1920KN0011", "ST400HM0021", + "ST400KN0001", "ST400KN0011", "ST480HM0001", + "ST480KN0001", "ST480KN0011", "ST800HM0021", + "ST800KN0001", "ST800KN0011", "ST960HM0001", + "ST960KN0001", "ST960KN0011", "XF1441-1AA251024", + "XF1441-1AA252048", "XF1441-1AA25512", "XF1441-1AB251024", + "XF1441-1AB252048", "XF1441-1AB25512", "XF1441-1BA251024", + "XF1441-1BA252048", "XF1441-1BA25512", "XF1441-1BB251024", + "XF1441-1BB252048", "XF1441-1BB25512", "ST400HM0031", + "ST400KN0021", "ST400KN0031", "ST480HM0011", + "ST480KN0021", "ST480KN0031", "ST800HM0031", + "ST800KN0021", "ST800KN0031", "ST960HM0011", + "ST960KN0021", "ST960KN0031", "XM1441-1AA111024", + "XM1441-1AA112048", "XM1441-1AA11512", "XM1441-1AA801024", + "XM1441-1AA80512", "XM1441-1AB111024", "XM1441-1AB112048", + "XM1441-1BA111024", "XM1441-1BA112048", "XM1441-1BA11512", + "XM1441-1BA801024", "XM1441-1BA80512", "XM1441-1BB112048"}; /*************************** *Supported Log-Pages from FW ***************************/ -typedef struct log_page_map_entry { +typedef struct __attribute__((__packed__)) log_page_map_entry { __u32 LogPageID; __u32 LogPageSignature; __u32 LogPageVersion; @@ -45,7 +94,7 @@ typedef struct log_page_map_entry { #define MAX_SUPPORTED_LOG_PAGE_ENTRIES ((4096 - sizeof(__u32)) / sizeof(log_page_map_entry)) -typedef struct log_page_map { +typedef struct __attribute__((__packed__)) log_page_map { __u32 NumLogPages; log_page_map_entry LogPageEntry[ MAX_SUPPORTED_LOG_PAGE_ENTRIES ]; } log_page_map; @@ -55,7 +104,6 @@ typedef struct log_page_map { /*************************** * Extended-SMART Information ***************************/ -#pragma pack(1) #define NUMBER_EXTENDED_SMART_ATTRIBUTES 42 typedef enum _EXTENDED_SMART_VERSION_ @@ -65,7 +113,7 @@ typedef enum _EXTENDED_SMART_VERSION_ EXTENDED_SMART_VERSION_VENDOR1, } EXTENDED_SMART_VERSION; -typedef struct _SmartVendorSpecific +typedef struct __attribute__((__packed__)) _SmartVendorSpecific { __u8 AttributeNumber; __u16 SmartStatus; @@ -75,22 +123,22 @@ typedef struct _SmartVendorSpecific __u8 RawHigh[3]; } SmartVendorSpecific; -typedef struct _EXTENDED_SMART_INFO_T +typedef struct __attribute__((__packed__)) _EXTENDED_SMART_INFO_T { __u16 Version; SmartVendorSpecific vendorData[NUMBER_EXTENDED_SMART_ATTRIBUTES]; __u8 vendor_specific_reserved[6]; } EXTENDED_SMART_INFO_T; -typedef struct vendor_smart_attribute_data +typedef struct __attribute__((__packed__)) vendor_smart_attribute_data { - __u8 AttributeNumber; /* 00 */ - __u8 Rsvd[3]; /* 01 -03 */ - __u32 LSDword; /* 04-07 */ - __u32 MSDword; /* 08 - 11 */ + __u8 AttributeNumber; + __u8 Rsvd[3]; + __u32 LSDword; + __u32 MSDword; } vendor_smart_attribute_data; -struct nvme_temetry_log_hdr +struct __attribute__((__packed__)) nvme_temetry_log_hdr { __u8 log_id; __u8 rsvd1[4]; @@ -104,38 +152,75 @@ struct nvme_temetry_log_hdr __u8 reason_identifier[128]; }; -typedef struct _U128 +typedef struct __attribute__((__packed__)) _U128 { __u64 LS__u64; __u64 MS__u64; } U128; -typedef struct _vendor_log_page_CF_Attr +typedef struct __attribute__((__packed__)) _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 + __u16 SuperCapCurrentTemperature; + __u16 SuperCapMaximumTemperature; + __u8 SuperCapStatus; + __u8 Reserved5to7[3]; + U128 DataUnitsReadToDramNamespace; + U128 DataUnitsWrittenToDramNamespace; + __u64 DramCorrectableErrorCount; + __u64 DramUncorrectableErrorCount; +} vendor_log_page_CF_Attr; + +typedef struct __attribute__((__packed__)) _vendor_log_page_CF { vendor_log_page_CF_Attr AttrCF; __u8 Vendor_Specific_Reserved[ 456 ]; /* 56-511 */ -}vendor_log_page_CF; +} vendor_log_page_CF; + +typedef struct __attribute__((__packed__)) _STX_EXT_SMART_LOG_PAGE_C0 +{ + U128 phyMediaUnitsWrt; + U128 phyMediaUnitsRd; + __u64 badUsrNandBlocks; + __u64 badSysNandBlocks; + __u64 xorRecoveryCnt; + __u64 ucRdEc; + __u64 softEccEc; + __u64 etoeCrrCnt; + __u64 sysDataUsed : 8; + __u64 refreshCount : 56; + __u64 usrDataEraseCnt; + __u16 thermalThrottling; + __u8 dssdSpecVerErrata; + __u16 dssdSpecVerPoint; + __u16 dssdSpecVerMinor; + __u8 dssdSpecVerMajor; + __u64 pcieCorrEc; + __u32 incompleteShutdowns; + __u32 rsvd_116_119; + __u8 freeBlocks; + __u8 rsvd_121_127[7]; + __u16 capHealth; + __u8 nvmeErrataVer; + __u8 rsvd_131_135[5]; + __u64 unalignedIO; + __u64 secVerNum; + __u64 totalNUSE; + U128 plpStartCnt; + U128 enduranceEstimate; + __u64 pcieLinkRetCnt; + __u64 powStateChangeCnt; + __u8 rsvd_208_493[286]; + __u16 logPageVer; + U128 logPageGUID; +} STX_EXT_SMART_LOG_PAGE_C0; -#pragma pack() /* EOF Extended-SMART Information*/ /************************** * PCIE ERROR INFORMATION **************************/ -typedef struct pcie_error_log_page +typedef struct __attribute__((__packed__)) pcie_error_log_page { __u32 Version; __u32 BadDllpErrCnt; @@ -159,53 +244,86 @@ typedef struct pcie_error_log_page } pcie_error_log_page; /*EOF PCIE ERROR INFORMATION */ +/************************************** +* FW Activation History Log INFORMATION +***************************************/ + +typedef struct __attribute__((__packed__)) _stx_fw_activ_his_ele +{ + __u8 entryVerNum; + __u8 entryLen; + __u16 rev02_03; + __u16 fwActivCnt; + __u64 timeStamp; + __u64 rev14_21; + __u64 powCycleCnt; + __u8 previousFW[8]; + __u8 newFW[8]; + __u8 slotNum; + __u8 commitActionType; + __u16 result; + __u8 rev50_63[14]; +} stx_fw_activ_his_ele; + +typedef struct __attribute__((__packed__)) _stx_fw_activ_history_log_page +{ + __u8 logID; + __u8 rev01_03[3]; + __u32 numValidFwActHisEnt; + stx_fw_activ_his_ele fwActHisEnt[20]; + __u8 rev1288_4077[2790]; + __u16 logPageVer; + __u8 logPageGUID[16]; +} stx_fw_activ_history_log_page; + +/* FW Activation History Log INFORMATION */ + + typedef enum { - VS_ATTR_SOFT_READ_ERROR_RATE, /* 0 OFFSET : 02 -13 bytes */ - VS_ATTR_REALLOCATED_SECTOR_COUNT, /* 1 OFFSET : 14 -25 bytes */ - VS_ATTR_POWER_ON_HOURS, /* 2 OFFSET : 26 -37 bytes */ + VS_ATTR_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_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, - + VS_ATTR_LIFETIME_ENTERING_PS4_COUNT, /* 7 OFFSET : 86 -97 bytes */ + VS_ATTR_LIFETIME_ENTERING_PS3_COUNT, /* 8 OFFSET : 98 -109 bytes */ + VS_ATTR_RETIRED_BLOCK_COUNT, /* 9 OFFSET : 110 -121 bytes */ + VS_ATTR_PROGRAM_FAILURE_COUNT, /* 10 OFFSET : 122 -133 bytes */ + VS_ATTR_ERASE_FAIL_COUNT, /* 11 OFFSET : 134 -145 bytes */ + VS_ATTR_AVG_ERASE_COUNT, /* 12 OFFSET : 146 -157 bytes */ + VS_ATTR_UNEXPECTED_POWER_LOSS_COUNT, /* 13 OFFSET : 158 -169 bytes */ + VS_ATTR_WEAR_RANGE_DELTA, /* 14 OFFSET : 170 -181 bytes */ + VS_ATTR_SATA_INTERFACE_DOWNSHIFT_COUNT, /* 15 OFFSET : 182 -193 bytes */ + VS_ATTR_END_TO_END_CRC_ERROR_COUNT, /* 16 OFFSET : 194 -205 bytes */ + VS_ATTR_MAX_LIFE_TEMPERATURE, /* 17 OFFSET : 206 -217 bytes */ + VS_ATTR_UNCORRECTABLE_RAISE_ERRORS, /* 18 OFFSET : 218 -229 bytes */ + VS_ATTR_DRIVE_LIFE_PROTECTION_STATUS, /* 19 OFFSET : 230 -241 bytes */ + VS_ATTR_REMAINING_SSD_LIFE, /* 20 OFFSET : 242 -253 bytes */ + VS_ATTR_LIFETIME_WRITES_TO_FLASH, /* 21 OFFSET : 254 -265 bytes */ + VS_ATTR_LIFETIME_WRITES_FROM_HOST, /* 22 OFFSET : 266 -277 bytes */ + VS_ATTR_LIFETIME_READS_TO_HOST, /* 23 OFFSET : 278 -289 bytes */ + VS_ATTR_FREE_SPACE, /* 24 OFFSET : 290 -301 bytes */ + VS_ATTR_TRIM_COUNT_LSB, /* 25 OFFSET : 302 -313 bytes */ + VS_ATTR_TRIM_COUNT_MSB, /* 26 OFFSET : 314 -325 bytes */ + VS_ATTR_OP_PERCENTAGE, /* 27 OFFSET : 326 -337 bytes */ + VS_ATTR_RAISE_ECC_CORRECTABLE_ERROR_COUNT, /* 28 OFFSET : 338 -349 bytes */ + VS_ATTR_UNCORRECTABLE_ECC_ERRORS , /* 29 OFFSET : 350 -361 bytes */ + VS_ATTR_LIFETIME_WRITES0_TO_FLASH, /* 30 OFFSET : 362-372 bytes */ + VS_ATTR_LIFETIME_WRITES1_TO_FLASH, /* 31 OFFSET : 374-385 bytes */ + VS_ATTR_LIFETIME_WRITES0_FROM_HOST, /* 32 OFFSET : 386-397 bytes */ + VS_ATTR_LIFETIME_WRITES1_FROM_HOST, /* 33 OFFSET : 398-409 bytes */ + VS_ATTR_LIFETIME_READ0_FROM_HOST, /* 34 OFFSET : 410-421 bytes */ + VS_ATTR_LIFETIME_READ1_FROM_HOST, /* 35 OFFSET : 422-433 bytes */ + VS_ATTR_PCIE_PHY_CRC_ERROR, /* 36 OFFSET : 434-445 bytes */ + VS_ATTR_BAD_BLOCK_COUNT_SYSTEM, /* 37 OFFSET : 446-457 bytes */ + VS_ATTR_BAD_BLOCK_COUNT_USER, /* 38 OFFSET : 458-469 bytes */ + VS_ATTR_THERMAL_THROTTLING_STATUS, /* 39 OFFSET : 470-481 bytes */ + VS_ATTR_POWER_CONSUMPTION, /* 40 OFFSET : 482-493 bytes */ + VS_ATTR_MAX_SOC_LIFE_TEMPERATURE, /* 41 OFFSET : 494-505 bytes */ + VS_MAX_ATTR_NUMBER } extended_smart_attributes; /*Smart attribute IDs */ diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c index 51f4589932..887e5bc05b 100644 --- a/plugins/seagate/seagate-nvme.c +++ b/plugins/seagate/seagate-nvme.c @@ -18,6 +18,8 @@ * * \file seagate-nvme.c * \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in. + * + * Author: Debabrata Bardhan */ @@ -25,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +38,7 @@ #include "plugin.h" #include "linux/types.h" #include "nvme-print.h" +#include #define CREATE_CMD @@ -43,89 +47,77 @@ /*************************************** -*Command for "log-pages-supp" -***************************************/ + * Command for "log-pages-supp" + ***************************************/ static char *log_pages_supp_print(__u32 pageID) { - switch(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 int stx_is_jag_pan(char *devMN) +{ + int match_found = 1; /* found = 0, not_found = 1 */ + + for (int i = 0; i < STX_NUM_LEGACY_DRV; i++) { + match_found = strncmp(devMN, stx_jag_pan_mn[i], strlen(stx_jag_pan_mn[i])); + if (!match_found) + break; + } + + return match_found; +} + static void json_log_pages_supp(log_page_map *logPageMap) { @@ -139,6 +131,7 @@ static void json_log_pages_supp(log_page_map *logPageMap) 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", @@ -147,12 +140,11 @@ static void json_log_pages_supp(log_page_map *logPageMap) json_array_add_value_object(logPages, lbaf); } json_print_object(root, NULL); - printf("\n"); json_free_object(root); } static int log_pages_supp(int argc, char **argv, struct command *cmd, - struct plugin *plugin) + struct plugin *plugin) { int err = 0; __u32 i = 0; @@ -181,23 +173,23 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd, err = nvme_get_log_simple(dev_fd(dev), 0xc5, sizeof(logPageMap), &logPageMap); if (!err) { - if (strcmp(cfg.output_format,"json")) { - printf ("Seagate Supported Log-pages count :%d\n", + 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"); + printf("%-15s %-30s\n", "LogPage-Id", "LogPage-Name"); - for(fmt=0; fmt<45; fmt++) - printf ("-"); + for (fmt = 0; fmt < 45; fmt++) + printf("-"); printf("\n"); } else json_log_pages_supp(&logPageMap); - for (i = 0; ivendorData[index].AttributeNumber != 0) { + + if (ExtdSMARTInfo->vendorData[index].AttributeNumber) { json_object_add_value_string(lbaf, "attribute_name", print_ext_smart_id(ExtdSMARTInfo->vendorData[index].AttributeNumber)); - json_object_add_value_int(lbaf, "attribute_id",ExtdSMARTInfo->vendorData[index].AttributeNumber); + json_object_add_value_int(lbaf, "attribute_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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_TRIM_COUNT_MSB) msbTrimCnt = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]); } } @@ -599,78 +535,58 @@ static void json_print_smart_log(struct json_object *root, 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("%-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"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(currentTemp)); 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(" 0x%016"PRIx64"\n", le64_to_cpu(maxTemp)); printf("%-40s", "Super-cap status"); - printf(" 0x%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.SuperCapStatus)); - printf("\n"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.SuperCapStatus)); printf("%-40s", "Data units read to DRAM namespace"); - printf(" 0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64), - le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64)); - printf("\n"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64), + le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64)); printf("%-40s", "Data units written to DRAM namespace"); - printf(" 0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64), - le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64)); - printf("\n"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64), + le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64)); printf("%-40s", "DRAM correctable error count"); - printf(" 0x%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DramCorrectableErrorCount)); - printf("\n"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DramCorrectableErrorCount)); printf("%-40s", "DRAM uncorrectable error count"); - printf(" 0x%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DramUncorrectableErrorCount)); - printf("\n"); - + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DramUncorrectableErrorCount)); } -static void json_print_smart_log_CF(struct json_object *root, - vendor_log_page_CF *pLogPageCF) +static void json_print_smart_log_CF(struct json_object *root, vendor_log_page_CF *pLogPageCF) { - /*struct json_object *root;*/ struct json_object *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); @@ -705,25 +621,285 @@ static void json_print_smart_log_CF(struct json_object *root, json_object_add_value_string(lbaf, "attribute_name", "DRAM uncorrectable error count"); json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.DramUncorrectableErrorCount); json_array_add_value_object(logPages, lbaf); +} + + +static void print_stx_smart_log_C0(STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0) +{ + printf("\n\nSeagate SMART Health Attributes :\n"); + printf("%-39s %-19s\n", "Description", "Health Attributes"); + + printf("%-40s", "Physical Media Units Written"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64), + le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.LS__u64)); + + printf("%-40s", "Physical Media Units Read"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsRd.MS__u64), + le64_to_cpu(pLogPageC0->phyMediaUnitsRd.LS__u64)); + + printf("%-40s", "Bad User NAND Blocks"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->badUsrNandBlocks)); + + printf("%-40s", "Bad System NAND Blocks"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->badSysNandBlocks)); + + printf("%-40s", "XOR Recovery Count"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->xorRecoveryCnt)); + + printf("%-40s", "Uncorrectable Read Error Count"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->ucRdEc)); + + printf("%-40s", "Soft ECC Error Count"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->softEccEc)); + + printf("%-40s", "End to End Correction Counts"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->etoeCrrCnt)); + + printf("%-40s", "System Data Used in Parcent"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->sysDataUsed)); + + printf("%-40s", "Refresh Counts"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->refreshCount)); + + printf("%-40s", "User Data Erase Counts"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->usrDataEraseCnt)); + + printf("%-40s", "Thermal Throttling Status and Count"); + printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->thermalThrottling)); + + printf("%-40s", "DSSD Specification Version"); + printf(" %d.%d.%d.%d\n", pLogPageC0->dssdSpecVerMajor, + le16_to_cpu(pLogPageC0->dssdSpecVerMinor), + le16_to_cpu(pLogPageC0->dssdSpecVerPoint), + pLogPageC0->dssdSpecVerErrata); + + printf("%-40s", "PCIe Correctable Error Count"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->pcieCorrEc)); + + printf("%-40s", "Incomplete Shutdowns"); + printf(" 0x%08x\n", le32_to_cpu(pLogPageC0->incompleteShutdowns)); + + printf("%-40s", "Free Blocks in Percent"); + printf(" %d\n", pLogPageC0->freeBlocks); + + printf("%-40s", "Capacitor Health"); + printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->capHealth)); + + printf("%-40s", "NVMe Errata Version"); + printf(" %c\n", pLogPageC0->nvmeErrataVer); + + printf("%-40s", "Unaligned IO"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->unalignedIO)); + + printf("%-40s", "Security Version Number"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->secVerNum)); + + printf("%-40s", "Total Namespace Utilization"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->totalNUSE)); - /* - json_print_object(root, NULL); - printf("\n"); - */ + printf("%-40s", "PLP Start Count"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->plpStartCnt.MS__u64), + le64_to_cpu(pLogPageC0->plpStartCnt.LS__u64)); + + printf("%-40s", "Endurance Estimate"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->enduranceEstimate.MS__u64), + le64_to_cpu(pLogPageC0->enduranceEstimate.LS__u64)); + + printf("%-40s", "PCIe Link Retraining Count"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->pcieLinkRetCnt)); + + printf("%-40s", "Power State Change Count"); + printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->powStateChangeCnt)); + + printf("%-40s", "Log Page Version"); + printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->logPageVer)); + + printf("%-40s", "Log Page GUID"); + printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->logPageGUID.MS__u64), + le64_to_cpu(pLogPageC0->logPageGUID.LS__u64)); +} + +static void json_print_stx_smart_log_C0(struct json_object *root, STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0) +{ + struct json_object *logPages; + char buf[40]; + + logPages = json_create_array(); + json_object_add_value_array(root, "Seagate SMART Health Attributes", logPages); + + struct json_object *lbaf = json_create_object(); + + json_object_add_value_string(lbaf, "attribute_name", "Physical Media Units Written"); + memset(buf, 0, sizeof(buf)); + sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64), + le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.LS__u64)); + json_object_add_value_string(lbaf, "attribute_value", buf); + json_array_add_value_object(logPages, lbaf); + + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Physical Media Units Read"); + memset(buf, 0, sizeof(buf)); + sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->phyMediaUnitsRd.MS__u64), + le64_to_cpu(pLogPageC0->phyMediaUnitsRd.LS__u64)); + json_object_add_value_string(lbaf, "attribute_value", buf); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Bad User NAND Blocks"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->badUsrNandBlocks)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Bad System NAND Blocks"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->badSysNandBlocks)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "XOR Recovery Count"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->xorRecoveryCnt)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Uncorrectable Read Error Count"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->ucRdEc)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Soft ECC Error Count"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->softEccEc)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "End to End Correction Counts"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->etoeCrrCnt)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "System Data Used in Parcent"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->sysDataUsed)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Refresh Counts"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->refreshCount)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "User Data Erase Counts"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->usrDataEraseCnt)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Thermal Throttling Status and Count"); + json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->thermalThrottling)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "DSSD Specification Version"); + memset(buf, 0, sizeof(buf)); + sprintf(buf, "%d.%d.%d.%d", pLogPageC0->dssdSpecVerMajor, + le16_to_cpu(pLogPageC0->dssdSpecVerMinor), + le16_to_cpu(pLogPageC0->dssdSpecVerPoint), + pLogPageC0->dssdSpecVerErrata); + json_object_add_value_string(lbaf, "attribute_value", buf); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "PCIe Correctable Error Count"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->pcieCorrEc)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Incomplete Shutdowns"); + json_object_add_value_int(lbaf, "attribute_value", le32_to_cpu(pLogPageC0->incompleteShutdowns)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Free Blocks in Percent"); + json_object_add_value_int(lbaf, "attribute_value", pLogPageC0->freeBlocks); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Capacitor Health"); + json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->capHealth)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "NVMe Errata Version"); + json_object_add_value_int(lbaf, "attribute_value", pLogPageC0->nvmeErrataVer); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Unaligned IO"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->unalignedIO)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Security Version Number"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->secVerNum)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Total Namespace Utilization"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->totalNUSE)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "PLP Start Count"); + memset(buf, 0, sizeof(buf)); + sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->plpStartCnt.MS__u64), + le64_to_cpu(pLogPageC0->plpStartCnt.LS__u64)); + json_object_add_value_string(lbaf, "attribute_value", buf); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Endurance Estimate"); + memset(buf, 0, sizeof(buf)); + sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->enduranceEstimate.MS__u64), + le64_to_cpu(pLogPageC0->enduranceEstimate.LS__u64)); + json_object_add_value_string(lbaf, "attribute_value", buf); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "PCIe Link Retraining Count"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->pcieLinkRetCnt)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Power State Change Count"); + json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->powStateChangeCnt)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Log Page Version"); + json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->logPageVer)); + json_array_add_value_object(logPages, lbaf); + + lbaf = json_create_object(); + json_object_add_value_string(lbaf, "attribute_name", "Log Page GUID"); + memset(buf, 0, sizeof(buf)); + sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->logPageGUID.MS__u64), + le64_to_cpu(pLogPageC0->logPageGUID.LS__u64)); + json_object_add_value_string(lbaf, "attribute_value", buf); + json_array_add_value_object(logPages, lbaf); } static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { + struct nvme_id_ctrl ctrl; + char modelNo[40]; + STX_EXT_SMART_LOG_PAGE_C0 ehExtSmart; EXTENDED_SMART_INFO_T ExtdSMARTInfo; vendor_log_page_CF logPageCF; struct json_object *root = json_create_object(); struct json_object *lbafs = json_create_array(); struct json_object *lbafs_ExtSmart, *lbafs_DramSmart; - const char *desc = "Retrieve Seagate Extended SMART information for the given device "; + const char *desc = "Retrieve the Firmware Activation History for Seagate NVMe drives"; const char *output_format = "output in binary format"; struct nvme_dev *dev; - int err, index=0; + int err, index = 0; struct config { char *output_format; }; @@ -739,22 +915,99 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - printf ("\nDevice not found \n"); + printf("\nDevice not found\n"); return -1; } - if (strcmp(cfg.output_format,"json")) + if (strcmp(cfg.output_format, "json")) printf("Seagate Extended SMART Information :\n"); + + /** + * Here we should identify if the drive is a Panthor or Jaguar. + * Here we need to extract the model no from ctrl-id abd use it + * to determine drive family. + */ + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (!err) { + memcpy(modelNo, ctrl.mn, sizeof(modelNo)); + } else { + nvme_show_status(err); + return err; + } + + if (!stx_is_jag_pan(modelNo)) { + err = nvme_get_log_simple(dev_fd(dev), 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); + if (!err) { + if (strcmp(cfg.output_format, "json")) { + printf("%-39s %-15s %-19s\n", "Description", "Ext-Smart-Id", "Ext-Smart-Value"); + for (index = 0; index < 80; index++) + printf("-"); + printf("\n"); + for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) + print_smart_log(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index], index == (NUMBER_EXTENDED_SMART_ATTRIBUTES - 1)); + + } else { + lbafs_ExtSmart = json_create_object(); + json_print_smart_log(lbafs_ExtSmart, &ExtdSMARTInfo); + + json_object_add_value_array(root, "SMART-Attributes", lbafs); + json_array_add_value_object(lbafs, lbafs_ExtSmart); + } + + /** + * Next get Log Page 0xCF + */ + + err = nvme_get_log_simple(dev_fd(dev), 0xCF, sizeof(logPageCF), &logPageCF); + if (!err) { + if (strcmp(cfg.output_format, "json")) { + print_smart_log_CF(&logPageCF); + } else { + lbafs_DramSmart = json_create_object(); + json_print_smart_log_CF(lbafs_DramSmart, &logPageCF); + json_array_add_value_object(lbafs, lbafs_DramSmart); + json_print_object(root, NULL); + } + } else if (!strcmp(cfg.output_format, "json")) { + json_print_object(root, NULL); + json_free_object(root); + } + } else if (err > 0) { + nvme_show_status(err); + } + } else { + err = nvme_get_log_simple(dev_fd(dev), 0xC0, sizeof(ehExtSmart), &ehExtSmart); + + if (!err) { + if (strcmp(cfg.output_format, "json")) { + print_stx_smart_log_C0(&ehExtSmart); + } else { + lbafs_ExtSmart = json_create_object(); + json_print_stx_smart_log_C0(lbafs_ExtSmart, &ehExtSmart); + + json_object_add_value_array(root, "SMART-Attributes", lbafs); + json_array_add_value_object(lbafs, lbafs_ExtSmart); + + json_print_object(root, NULL); + json_free_object(root); + } + } + + if (err > 0) + nvme_show_status(err); + } + err = nvme_get_log_simple(dev_fd(dev), 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); if (!err) { - if (strcmp(cfg.output_format,"json")) { - printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value"); - for(index=0; index<80; index++) + 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++) + for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) print_smart_log(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index], index == (NUMBER_EXTENDED_SMART_ATTRIBUTES - 1)); } else { @@ -772,9 +1025,7 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi err = nvme_get_log_simple(dev_fd(dev), 0xCF, sizeof(logPageCF), &logPageCF); if (!err) { - if(strcmp(cfg.output_format,"json")) { - /*printf("Seagate DRAM Supercap SMART Attributes :\n");*/ - + if (strcmp(cfg.output_format, "json")) { print_smart_log_CF(&logPageCF); } else { lbafs_DramSmart = json_create_object(); @@ -782,12 +1033,15 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi json_array_add_value_object(lbafs, lbafs_DramSmart); json_print_object(root, NULL); } - } else if (!strcmp(cfg.output_format, "json")) + } else if (!strcmp(cfg.output_format, "json")) { json_print_object(root, NULL); - } else if (err > 0) + } + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); + return err; } @@ -797,25 +1051,23 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi * 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) + __u32 MaxSocTemp, __u32 cf_err, __u32 scCurrentTemp, __u32 scMaxTem) { - struct json_object *root; - root = json_create_object(); + struct json_object *root = json_create_object(); json_object_add_value_int(root, "Current temperature", temperature); json_object_add_value_int(root, "Current PCB temperature", PcbTemp); json_object_add_value_int(root, "Current SOC temperature", SocTemp); json_object_add_value_int(root, "Highest temperature", maxTemperature); json_object_add_value_int(root, "Max SOC temperature", MaxSocTemp); - if(!cf_err) { + 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; @@ -844,11 +1096,11 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - printf ("\nDevice not found \n");; + printf("\nDevice not found\n"); return -1; } - if(strcmp(cfg.output_format,"json")) + if (strcmp(cfg.output_format, "json")) printf("Seagate Temperature Stats Information :\n"); /*STEP-1 : Get Current Temperature from SMART */ err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); @@ -859,7 +1111,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin 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")) { + 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); @@ -870,29 +1122,30 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin err = nvme_get_log_simple(dev_fd(dev), 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo); if (!err) { - for(index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) { + 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")) + 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")) + if (strcmp(cfg.output_format, "json")) printf("%-20s : %d C\n", "Max SOC Temperature", (unsigned int)MaxSocTemp); } } + } else { + if (err > 0) + nvme_show_status(err); } - else if (err > 0) - nvme_show_status(err); cf_err = nvme_get_log_simple(dev_fd(dev), 0xCF, - sizeof(ExtdSMARTInfo), &logPageCF); + sizeof(ExtdSMARTInfo), &logPageCF); - if(!cf_err) { + if (!cf_err) { scCurrentTemp = logPageCF.AttrCF.SuperCapCurrentTemperature; scCurrentTemp = scCurrentTemp ? scCurrentTemp - 273 : 0; printf("%-20s : %d C\n", "Super-cap Current Temperature", scCurrentTemp); @@ -902,7 +1155,7 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin printf("%-20s : %d C\n", "Super-cap Max Temperature", scMaxTemp); } - if(!strcmp(cfg.output_format,"json")) + if (!strcmp(cfg.output_format, "json")) json_temp_stats(temperature, PcbTemp, SocTemp, maxTemperature, MaxSocTemp, cf_err, scCurrentTemp, scMaxTemp); dev_close(dev); @@ -915,19 +1168,16 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin ***************************************/ 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; + __u32 correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt + + pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt + + pcieErrorLog.ReplayNumRolloverErrCnt; + __u32 uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt + + pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt + + pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt + + pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt + + pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt + + pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt + + pcieErrorLog.MemRdTlpPoisonedErrCnt; printf("%-45s : %u\n", "PCIe Correctable Error Count", correctPcieEc); printf("%-45s : %u\n", "PCIe Un-Correctable Error Count", uncorrectPcieEc); @@ -955,21 +1205,17 @@ static void print_vs_pcie_error_log(pcie_error_log_page pcieErrorLog) 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; + struct json_object *root = json_create_object(); + __u32 correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt + + pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt + + pcieErrorLog.ReplayNumRolloverErrCnt; + __u32 uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt + + pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt + + pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt + + pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt + + pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt + + pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt + + pcieErrorLog.MemRdTlpPoisonedErrCnt; json_object_add_value_int(root, "PCIe Correctable Error Count", correctPcieEc); json_object_add_value_int(root, "PCIe Un-Correctable Error Count", uncorrectPcieEc); @@ -992,7 +1238,6 @@ static void json_vs_pcie_error_log(pcie_error_log_page pcieErrorLog) 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) @@ -1018,34 +1263,249 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - printf ("\nDevice not found \n");; + printf("\nDevice not found\n"); return -1; } - if(strcmp(cfg.output_format,"json")) + if (strcmp(cfg.output_format, "json")) printf("Seagate PCIe error counters Information :\n"); err = nvme_get_log_simple(dev_fd(dev), 0xCB, sizeof(pcieErrorLog), &pcieErrorLog); if (!err) { - if(strcmp(cfg.output_format,"json")) { + if (strcmp(cfg.output_format, "json")) print_vs_pcie_error_log(pcieErrorLog); - } else + else json_vs_pcie_error_log(pcieErrorLog); - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); return err; } /* EOF PCIE error-log information */ + +/*************************************** + * FW Activation History log + ***************************************/ +static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis) +{ + __u32 i; + char prev_fw[9] = {0}; + char new_fw[9] = {0}; + char buf[80]; + + if (fwActivHis.numValidFwActHisEnt > 0) { + printf("\n\nSeagate FW Activation History :\n"); + printf("%-9s %-21s %-7s %-13s %-9s %-5s %-15s %-9s\n", "Counter ", " Timestamp ", " PCC ", "Previous FW ", "New FW ", "Slot", "Commit Action", "Result"); + + for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) { + + printf(" %-4d ", fwActivHis.fwActHisEnt[i].fwActivCnt); + + time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000; + struct tm ts = *localtime(&t); + + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts); + printf(" %-20s ", buf); + printf("%-5" PRId64 " ", + (uint64_t)fwActivHis.fwActHisEnt[i].powCycleCnt); + + memset(prev_fw, 0, sizeof(prev_fw)); + memcpy(prev_fw, fwActivHis.fwActHisEnt[i].previousFW, sizeof(fwActivHis.fwActHisEnt[i].previousFW)); + printf("%-8s ", prev_fw); + + memset(new_fw, 0, sizeof(new_fw)); + memcpy(new_fw, fwActivHis.fwActHisEnt[i].newFW, sizeof(fwActivHis.fwActHisEnt[i].newFW)); + printf("%-8s ", new_fw); + + printf(" %-2d ", fwActivHis.fwActHisEnt[i].slotNum); + printf(" 0x%02x ", fwActivHis.fwActHisEnt[i].commitActionType); + printf(" 0x%02x\n", fwActivHis.fwActHisEnt[i].result); + } + } else { + printf("%s\n", "Do not have valid FW Activation History"); + } +} + +static void json_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis) +{ + struct json_object *root = json_create_object(); + __u32 i; + + char buf[80]; + + struct json_object *historyLogPage = json_create_array(); + + json_object_add_value_array(root, "Seagate FW Activation History", historyLogPage); + + if (fwActivHis.numValidFwActHisEnt > 0) { + for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) { + struct json_object *lbaf = json_create_object(); + char prev_fw[8] = { 0 }; + char new_fw[8] = { 0 }; + + json_object_add_value_int(lbaf, "Counter", fwActivHis.fwActHisEnt[i].fwActivCnt); + + time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000; + struct tm ts = *localtime(&t); + + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts); + printf(" %-20s ", buf); + json_object_add_value_string(lbaf, "Timestamp", buf); + + json_object_add_value_int(lbaf, "PCC", fwActivHis.fwActHisEnt[i].powCycleCnt); + sprintf(prev_fw, "%s", fwActivHis.fwActHisEnt[i].previousFW); + json_object_add_value_string(lbaf, "Previous_FW", prev_fw); + + sprintf(new_fw, "%s", fwActivHis.fwActHisEnt[i].newFW); + json_object_add_value_string(lbaf, "New_FW", new_fw); + + json_object_add_value_int(lbaf, "Slot", fwActivHis.fwActHisEnt[i].slotNum); + json_object_add_value_int(lbaf, "Commit_Action", fwActivHis.fwActHisEnt[i].commitActionType); + json_object_add_value_int(lbaf, "Result", fwActivHis.fwActHisEnt[i].result); + + json_array_add_value_object(historyLogPage, lbaf); + } + } else { + printf("%s\n", "Do not have valid FW Activation History"); + } + + json_print_object(root, NULL); + json_free_object(root); +} + +static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + stx_fw_activ_history_log_page fwActivHis; + struct nvme_dev *dev; + + const char *desc = "Retrieve FW Activate History for Seagate device "; + const char *output_format = "output in binary format"; + int err; + struct config { + char *output_format; + }; + + struct config cfg = { + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err < 0) { + printf("\nDevice not found\n"); + return -1; + } + + if (strcmp(cfg.output_format, "json")) + printf("Seagate FW Activation History Information :\n"); + + err = nvme_get_log_simple(dev_fd(dev), 0xC2, sizeof(fwActivHis), &fwActivHis); + if (!err) { + if (strcmp(cfg.output_format, "json")) + print_stx_vs_fw_activate_history(fwActivHis); + else + json_stx_vs_fw_activate_history(fwActivHis); + + } else if (err > 0) { + nvme_show_status(err); + } + + dev_close(dev); + return err; +} +/* EOF FW Activation History log information */ + + +static int clear_fw_activate_history(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Clear FW Activation History for the given Seagate device "; + const char *save = "specifies that the controller shall save the attribute"; + int err; + struct nvme_dev *dev; + struct nvme_id_ctrl ctrl; + char modelNo[40]; + __u32 result; + + struct config { + bool save; + }; + + struct config cfg = { + .save = 0, + }; + + OPT_ARGS(opts) = { + OPT_FLAG("save", 's', &cfg.save, save), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err < 0) { + printf("\nDevice not found\n"); + return -1; + } + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (!err) { + memcpy(modelNo, ctrl.mn, sizeof(modelNo)); + } else { + nvme_show_status(err); + return err; + } + + if (!stx_is_jag_pan(modelNo)) { + printf("\nDevice does not support Clear FW Activation History\n"); + } else { + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = 0xC1, + .nsid = 0, + .cdw11 = 0x80000000, + .cdw12 = 0, + .save = 0, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (err) + fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n", + __func__); + } + + if (err < 0) { + perror("set-feature"); + return errno; + } + + dev_close(dev); + return err; +} + + static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Clear Seagate PCIe Correctable counters for the given device "; const char *save = "specifies that the controller shall save the attribute"; + + struct nvme_id_ctrl ctrl; + char modelNo[40]; + struct nvme_dev *dev; + __u32 result; int err; @@ -1064,29 +1524,60 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - printf ("\nDevice not found \n");; + printf("\nDevice not found\n"); return -1; } - err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, - &result); + + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (!err) { + memcpy(modelNo, ctrl.mn, sizeof(modelNo)); + } else { + nvme_show_status(err); + return err; + } + + if (!stx_is_jag_pan(modelNo)) { + err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result); + } else { + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = 0xC3, + .nsid = 0, + .cdw11 = 0x80000000, + .cdw12 = 0, + .save = 0, + .uuidx = 0, + .cdw15 = 0, + .data_len = 0, + .data = NULL, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + err = nvme_set_features(&args); + if (err) + fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n", __func__); + } + + err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result); if (err < 0) { perror("set-feature"); + return errno; } dev_close(dev); return err; - } static int get_host_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Capture the Telemetry Host-Initiated Data in either " \ - "hex-dump (default) or binary format"; + const char *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. " \ + const char *log_specific = "1 - controller shall capture Data representing the internal\n" + "state of the controller at the time the command is processed.\n" "0 - controller shall not update the Telemetry Host Initiated Data."; const char *raw = "output in raw format"; struct nvme_temetry_log_hdr tele_log; @@ -1129,27 +1620,28 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug if (!cfg.raw_binary) { printf("Device:%s log-id:%d namespace-id:%#x\n", - dev->name, cfg.log_id, - cfg.namespace_id); + dev->name, cfg.log_id, + cfg.namespace_id); printf("Data Block 1 Last Block:%d Data Block 2 Last Block:%d Data Block 3 Last Block:%d\n", - tele_log.tele_data_area1, tele_log.tele_data_area2, tele_log.tele_data_area3); + 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) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror("log page"); + } blkCnt = 0; - while(blkCnt < maxBlk) { + while (blkCnt < maxBlk) { unsigned long long bytesToGet; blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt); - if(blksToGet == 0) { + if (!blksToGet) { dev_close(dev); return err; } @@ -1160,27 +1652,27 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug if (!log) { fprintf(stderr, "could not alloc buffer for log\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } memset(log, 0, bytesToGet); struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .lid = cfg.log_id, - .nsid = cfg.namespace_id, - .lpo = offset, - .lsp = 0, - .lsi = 0, - .rae = true, - .uuidx = 0, - .csi = NVME_CSI_NVM, - .ot = false, - .len = bytesToGet, - .log = (void *)log, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = cfg.log_id, + .nsid = cfg.namespace_id, + .lpo = offset, + .lsp = 0, + .lsi = 0, + .rae = true, + .uuidx = 0, + .csi = NVME_CSI_NVM, + .ot = false, + .len = bytesToGet, + .log = (void *)log, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, }; err = nvme_get_log(&args); if (!err) { @@ -1192,10 +1684,11 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug d((unsigned char *)log, bytesToGet, 16, 1); } else seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd); - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror("log page"); + } blkCnt += blksToGet; @@ -1208,8 +1701,8 @@ static int get_host_tele(int argc, char **argv, struct command *cmd, struct plug 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 *desc = + "Capture the Telemetry Controller-Initiated Data in either hex-dump (default) or binary format"; const char *namespace_id = "desired namespace"; const char *raw = "output in raw format"; struct nvme_dev *dev; @@ -1250,26 +1743,27 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug if (!cfg.raw_binary) { printf("Device:%s namespace-id:%#x\n", - dev->name, cfg.namespace_id); + dev->name, cfg.namespace_id); printf("Data Block 1 Last Block:%d Data Block 2 Last Block:%d Data Block 3 Last Block:%d\n", - tele_log.tele_data_area1, tele_log.tele_data_area2, tele_log.tele_data_area3); + 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) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror("log page"); + } blkCnt = 0; - while(blkCnt < maxBlk) { + while (blkCnt < maxBlk) { unsigned long long bytesToGet; blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt); - if(blksToGet == 0) + if (!blksToGet) return err; bytesToGet = (unsigned long long)blksToGet * 512; @@ -1277,27 +1771,27 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug if (!log) { fprintf(stderr, "could not alloc buffer for log\n"); - return EINVAL; + return -EINVAL; } memset(log, 0, bytesToGet); struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .lid = log_id, - .nsid = cfg.namespace_id, - .lpo = offset, - .lsp = 0, - .lsi = 0, - .rae = true, - .uuidx = 0, - .csi = NVME_CSI_NVM, - .ot = false, - .len = bytesToGet, - .log = (void *)log, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = log_id, + .nsid = cfg.namespace_id, + .lpo = offset, + .lsp = 0, + .lsi = 0, + .rae = true, + .uuidx = 0, + .csi = NVME_CSI_NVM, + .ot = false, + .len = bytesToGet, + .log = (void *)log, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, }; err = nvme_get_log(&args); if (!err) { @@ -1309,10 +1803,11 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug d((unsigned char *)log, bytesToGet, 16, 1); } else seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd); - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror("log page"); + } blkCnt += blksToGet; @@ -1325,29 +1820,21 @@ static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plug 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__); + printf("%s: Write Failed\n", __func__); } static int vs_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Capture the Telemetry Controller-Initiated Data in " \ - "binary format"; + const char *desc = "Capture the Telemetry Controller-Initiated Data in binary format"; const char *namespace_id = "desired namespace"; const char *file = "dump file"; struct nvme_dev *dev; int err, dump_fd; int flags = O_WRONLY | O_CREAT; - int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH; + int mode = 0664; struct nvme_temetry_log_hdr tele_log; __le64 offset = 0; __u16 log_id; @@ -1375,12 +1862,12 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl return err; dump_fd = STDOUT_FILENO; - if(strlen(cfg.file)) { + if (strlen(cfg.file)) { dump_fd = open(cfg.file, flags, mode); if (dump_fd < 0) { perror(cfg.file); dev_close(dev); - return EINVAL; + return -EINVAL; } } @@ -1391,26 +1878,22 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl 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) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror("log page"); + } blkCnt = 0; - while(blkCnt < maxBlk) { + while (blkCnt < maxBlk) { unsigned long long bytesToGet; blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt); - if(blksToGet == 0) { + if (!blksToGet) goto out; - } bytesToGet = (unsigned long long)blksToGet * 512; log = malloc(bytesToGet); @@ -1424,21 +1907,21 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl memset(log, 0, bytesToGet); struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .lid = log_id, - .nsid = cfg.namespace_id, - .lpo = offset, - .lsp = 0, - .lsi = 0, - .rae = true, - .uuidx = 0, - .csi = NVME_CSI_NVM, - .ot = false, - .len = bytesToGet, - .log = (void *)log, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = log_id, + .nsid = cfg.namespace_id, + .lpo = offset, + .lsp = 0, + .lsi = 0, + .rae = true, + .uuidx = 0, + .csi = NVME_CSI_NVM, + .ot = false, + .len = bytesToGet, + .log = (void *)log, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, }; err = nvme_get_log(&args); if (!err) { @@ -1446,17 +1929,18 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd); - } else if (err > 0) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror("log page"); + } blkCnt += blksToGet; free(log); } out: - if(strlen(cfg.file)) + if (strlen(cfg.file)) close(dump_fd); dev_close(dev); @@ -1464,12 +1948,21 @@ static int vs_internal_log(int argc, char **argv, struct command *cmd, struct pl } /*SEAGATE-PLUGIN Version */ -static int seagate_plugin_version(int argc, char **argv, struct command *cmd, - struct plugin *plugin) +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); + printf("Seagate-Plugin version : %d.%d\n", + SEAGATE_PLUGIN_VERSION_MAJOR, + SEAGATE_PLUGIN_VERSION_MINOR); return 0; } /*EOF SEAGATE-PLUGIN Version */ + +/*OCP SEAGATE-PLUGIN Version */ +static int stx_ocp_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + printf("Seagate-OCP-Plugin version : %d.%d\n", + SEAGATE_OCP_PLUGIN_VERSION_MAJOR, + SEAGATE_OCP_PLUGIN_VERSION_MINOR); + return 0; +} +/*EOF OCP SEAGATE-PLUGIN Version */ diff --git a/plugins/seagate/seagate-nvme.h b/plugins/seagate/seagate-nvme.h index 6df1331616..99f63273f0 100644 --- a/plugins/seagate/seagate-nvme.h +++ b/plugins/seagate/seagate-nvme.h @@ -18,6 +18,8 @@ * * \file seagate-nvme.h * \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in. + * + * Author: Debabrata Bardhan */ #undef CMD_INC_FILE @@ -30,15 +32,18 @@ PLUGIN(NAME("seagate", "Seagate vendor specific extensions", NVME_VERSION), COMMAND_LIST( - ENTRY("vs-temperature-stats", "Retrieve Seagate temperature statistics ", temp_stats) - ENTRY("vs-log-page-sup", "Retrieve Seagate Supported Log-pages Information ", log_pages_supp) - ENTRY("vs-smart-add-log", "Retrieve Seagate extended-SMART Information ", vs_smart_log) - ENTRY("vs-pcie-stats", "Retrieve Seagate PCIe error statistics ", vs_pcie_error_log) - ENTRY("clear-pcie-correctable-errors", "Clear Seagate PCIe error statistics ", vs_clr_pcie_correctable_errs) - ENTRY("get-host-tele", "Retrieve Seagate Host-Initiated Telemetry ", get_host_tele) - ENTRY("get-ctrl-tele", "Retrieve Seagate Controller-Initiated Telemetry ", get_ctrl_tele) - ENTRY("vs-internal-log", "Retrieve Seagate Controller-Initiated Telemetry in binary format", vs_internal_log) - ENTRY("plugin-version", "Shows Seagate plugin's version information ", seagate_plugin_version) + ENTRY("vs-temperature-stats", "Retrieve Seagate temperature statistics ", temp_stats) + ENTRY("vs-log-page-sup", "Retrieve Seagate Supported Log-pages Information ", log_pages_supp) + ENTRY("vs-smart-add-log", "Retrieve Seagate extended-SMART Information ", vs_smart_log) + ENTRY("vs-pcie-stats", "Retrieve Seagate PCIe error statistics ", vs_pcie_error_log) + ENTRY("clear-pcie-correctable-errors", "Clear Seagate PCIe error statistics ", vs_clr_pcie_correctable_errs) + ENTRY("get-host-tele", "Retrieve Seagate Host-Initiated Telemetry ", get_host_tele) + ENTRY("get-ctrl-tele", "Retrieve Seagate Controller-Initiated Telemetry ", get_ctrl_tele) + ENTRY("vs-internal-log", "Retrieve Seagate Controller-Initiated Telemetry in binary format", vs_internal_log) + ENTRY("vs-fw-activate-history", "Retrieve the Firmware Activation History", stx_vs_fw_activate_history) + ENTRY("clear-fw-activate-history", "Clear Firmware Activation History", clear_fw_activate_history) + ENTRY("plugin-version", "Shows Seagate plugin's version information ", seagate_plugin_version) + ENTRY("cloud-SSD-plugin-version", "Shows OCP Seagate plugin's version information ", stx_ocp_plugin_version) ) ); diff --git a/plugins/sed/meson.build b/plugins/sed/meson.build new file mode 100644 index 0000000000..4a2e5449c5 --- /dev/null +++ b/plugins/sed/meson.build @@ -0,0 +1,4 @@ +sources += [ + 'plugins/sed/sed.c', + 'plugins/sed/sedopal_cmd.c', +] diff --git a/plugins/sed/sed.c b/plugins/sed/sed.c new file mode 100644 index 0000000000..0471e5406f --- /dev/null +++ b/plugins/sed/sed.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "nvme-print.h" +#include "sedopal_cmd.h" +#include + +#define CREATE_CMD +#include "sed.h" + +OPT_ARGS(no_opts) = { + OPT_END() +}; + +OPT_ARGS(key_opts) = { + OPT_FLAG("ask-key", 'k', &sedopal_ask_key, + "prompt for SED authentication key"), + OPT_END() +}; + +OPT_ARGS(revert_opts) = { + OPT_FLAG("destructive", 'e', &sedopal_destructive_revert, + "destructive revert"), + OPT_FLAG("psid", 'p', &sedopal_psid_revert, "PSID revert"), + OPT_END() +}; + + +/* + * Open the NVMe device specified on the command line. It must be the + * NVMe block device (e.g. /dev/nvme0n1). + */ +static int sed_opal_open_device(struct nvme_dev **dev, int argc, char **argv, + const char *desc, struct argconfig_commandline_options *opts) +{ + int err; + + err = parse_and_open(dev, argc, argv, desc, opts); + if (err) + return err; + + if (!S_ISBLK((*dev)->direct.stat.st_mode)) { + fprintf(stderr, + "ERROR : The NVMe block device must be specified\n"); + err = -EINVAL; + dev_close(*dev); + } + + return err; +} + +static int sed_opal_discover(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Query SED device and display locking features"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, no_opts); + if (err) + return err; + + err = sedopal_cmd_discover(dev->direct.fd); + + dev_close(dev); + return err; +} + +static int sed_opal_initialize(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Initialize a SED device for locking"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, no_opts); + if (err) + return err; + + err = sedopal_cmd_initialize(dev->direct.fd); + if (err != 0) + fprintf(stderr, "initialize: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_revert(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Revert a SED device from locking state"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, revert_opts); + if (err) + return err; + + err = sedopal_cmd_revert(dev->direct.fd); + if (err != 0) + fprintf(stderr, "revert: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_lock(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Lock a SED device"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, key_opts); + if (err) + return err; + + err = sedopal_cmd_lock(dev->direct.fd); + if (err != 0) + fprintf(stderr, "lock: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_unlock(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Unlock a SED device"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, key_opts); + if (err) + return err; + + err = sedopal_cmd_unlock(dev->direct.fd); + if (err != 0) + fprintf(stderr, "unlock: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} + +static int sed_opal_password(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + int err; + const char *desc = "Change the locking password of a SED device"; + struct nvme_dev *dev; + + err = sed_opal_open_device(&dev, argc, argv, desc, no_opts); + if (err) + return err; + + err = sedopal_cmd_password(dev->direct.fd); + if (err != 0) + fprintf(stderr, "password: SED error - %s\n", + sedopal_error_to_text(err)); + + dev_close(dev); + return err; +} diff --git a/plugins/sed/sed.h b/plugins/sed/sed.h new file mode 100644 index 0000000000..1618272cb8 --- /dev/null +++ b/plugins/sed/sed.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#undef CMD_INC_FILE +#define CMD_INC_FILE plugins/sed/sed + +#include "cmd.h" +#include + +PLUGIN(NAME("sed", "SED Opal Command Set", NVME_VERSION), + COMMAND_LIST( + ENTRY("discover", "Discover SED Opal Locking Features", sed_opal_discover, "1") + ENTRY("initialize", "Initialize a SED Opal Device for locking", sed_opal_initialize) + ENTRY("revert", "Revert a SED Opal Device from locking", sed_opal_revert) + ENTRY("lock", "Lock a SED Opal Device", sed_opal_lock) + ENTRY("unlock", "Unlock a SED Opal Device", sed_opal_unlock) + ENTRY("password", "Change the SED Opal Device password", sed_opal_password) + ) +); + +#include "define_cmd.h" diff --git a/plugins/sed/sedopal_cmd.c b/plugins/sed/sedopal_cmd.c new file mode 100644 index 0000000000..91a049f47f --- /dev/null +++ b/plugins/sed/sedopal_cmd.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sedopal_spec.h" +#include "sedopal_cmd.h" + +/* + * ask user for key rather than obtaining it from kernel keyring + */ +bool sedopal_ask_key; + +/* + * initiate dialog to ask for and confirm new password + */ +bool sedopal_ask_new_key; + +/* + * perform a destructive drive revert + */ +bool sedopal_destructive_revert; + +/* + * perform a PSID drive revert + */ +bool sedopal_psid_revert; + +/* + * Map method status codes to error text + */ +static const char * const sedopal_errors[] = { + [SED_STATUS_SUCCESS] = "Success", + [SED_STATUS_NOT_AUTHORIZED] = "Host Not Authorized", + [SED_STATUS_OBSOLETE_1] = "Obsolete", + [SED_STATUS_SP_BUSY] = "SP Session Busy", + [SED_STATUS_SP_FAILED] = "SP Failed", + [SED_STATUS_SP_DISABLED] = "SP Disabled", + [SED_STATUS_SP_FROZEN] = "SP Frozen", + [SED_STATUS_NO_SESSIONS_AVAILABLE] = "No Sessions Available", + [SED_STATUS_UNIQUENESS_CONFLICT] = "Uniqueness Conflict", + [SED_STATUS_INSUFFICIENT_SPACE] = "Insufficient Space", + [SED_STATUS_INSUFFICIENT_ROWS] = "Insufficient Rows", + [SED_STATUS_OBSOLETE_2] = "Obsolete", + [SED_STATUS_INVALID_PARAMETER] = "Invalid Parameter", + [SED_STATUS_OBSOLETE_3] = "Obsolete", + [SED_STATUS_OBSOLETE_4] = "Obsolete", + [SED_STATUS_TPER_MALFUNCTION] = "TPER Malfunction", + [SED_STATUS_TRANSACTION_FAILURE] = "Transaction Failure", + [SED_STATUS_RESPONSE_OVERFLOW] = "Response Overflow", + [SED_STATUS_AUTHORITY_LOCKED_OUT] = "Authority Locked Out", +}; + +const char *sedopal_error_to_text(int code) +{ + if (code == SED_STATUS_FAIL) + return "Failed"; + + if (code == SED_STATUS_NO_METHOD_STATUS) + return "Method returned no status"; + + if (code < SED_STATUS_SUCCESS || + code > SED_STATUS_AUTHORITY_LOCKED_OUT) + return("Unknown Error"); + + return sedopal_errors[code]; +} + +/* + * Read a user entered password and do some basic validity checks. + */ +char *sedopal_get_password(char *prompt) +{ + char *pass; + int len; + + pass = getpass(prompt); + if (pass == NULL) + return NULL; + + len = strlen(pass); + if (len < SEDOPAL_MIN_PASSWORD_LEN) + return NULL; + + if (len > SEDOPAL_MAX_PASSWORD_LEN) + return NULL; + + return pass; +} + +/* + * Initialize a SED Opal key. The key can either specify that the actual + * key should be looked up in the kernel keyring, or it should be + * populated in the key by prompting the user. + */ +int sedopal_set_key(struct opal_key *key) +{ +#if !HAVE_KEY_TYPE + /* + * If key_type isn't avaialable, force key prompt + */ + sedopal_ask_key = true; +#endif + + if (sedopal_ask_key) { + char *pass; + char *prompt; + + /* + * set proper prompt + */ + if (sedopal_ask_new_key) + prompt = SEDOPAL_NEW_PW_PROMPT; + else { + if (sedopal_psid_revert) + prompt = SEDOPAL_PSID_PROMPT; + else + prompt = SEDOPAL_CURRENT_PW_PROMPT; + } + + pass = sedopal_get_password(prompt); + if (pass == NULL) + return -EINVAL; + +#if HAVE_KEY_TYPE + key->key_type = OPAL_INCLUDED; +#endif + key->key_len = strlen(pass); + memcpy(key->key, pass, key->key_len); + + /* + * If getting a new key, ask for it to be re-entered + * and verify the two entries are the same. + */ + if (sedopal_ask_new_key) { + pass = sedopal_get_password(SEDOPAL_REENTER_PW_PROMPT); + if (strncmp((char *)key->key, pass, key->key_len)) { + fprintf(stderr, + "Error: passwords don't match\n"); + return -EINVAL; + } + } + } else { +#if HAVE_KEY_TYPE + key->key_type = OPAL_KEYRING; +#endif + key->key_len = 0; + } + + key->lr = 0; + + return 0; +} + +/* + * Prepare a drive for SED Opal locking. + */ +int sedopal_cmd_initialize(int fd) +{ + int rc; + struct opal_key key; + struct opal_lr_act lr_act = {}; + struct opal_user_lr_setup lr_setup = {}; + + sedopal_ask_key = true; + sedopal_ask_new_key = true; + rc = sedopal_set_key(&key); + if (rc != 0) + return rc; + + /* + * take ownership of the device + */ + rc = ioctl(fd, IOC_OPAL_TAKE_OWNERSHIP, &key); + if (rc != 0) { + fprintf(stderr, + "Error: failed to take device ownership - %d\n", rc); + return rc; + } + + /* + * activate lsp + */ + lr_act.num_lrs = 1; + lr_act.sum = false; + lr_act.key = key; + + rc = ioctl(fd, IOC_OPAL_ACTIVATE_LSP, &lr_act); + if (rc != 0) { + fprintf(stderr, "Error: failed to activate LSP - %d\n", rc); + return rc; + } + + /* + * setup global locking range + */ + lr_setup.range_start = 0; + lr_setup.range_length = 0; + lr_setup.RLE = true; + lr_setup.WLE = true; + + lr_setup.session.opal_key = key; + lr_setup.session.sum = 0; + lr_setup.session.who = OPAL_ADMIN1; + + rc = ioctl(fd, IOC_OPAL_LR_SETUP, &lr_setup); + if (rc != 0) { + fprintf(stderr, + "Error: failed to setup locking range - %d\n", rc); + return rc; + } + + return rc; +} + +/* + * Lock a SED Opal drive + */ +int sedopal_cmd_lock(int fd) +{ + + return sedopal_lock_unlock(fd, OPAL_LK); +} + +/* + * Unlock a SED Opal drive + */ +int sedopal_cmd_unlock(int fd) +{ + + return sedopal_lock_unlock(fd, OPAL_RW); +} + +/* + * Prepare and issue an ioctl to lock/unlock a drive + */ +int sedopal_lock_unlock(int fd, int lock_state) +{ + int rc; + struct opal_lock_unlock opal_lu = {}; + + rc = sedopal_set_key(&opal_lu.session.opal_key); + if (rc != 0) + return rc; + + opal_lu.session.sum = 0; + opal_lu.session.who = OPAL_ADMIN1; + opal_lu.l_state = lock_state; + + rc = ioctl(fd, IOC_OPAL_LOCK_UNLOCK, &opal_lu); + if (rc != 0) + fprintf(stderr, + "Error: failed locking or unlocking - %d\n", rc); + + /* + * If the unlock was successful, force a re-read of the + * partition table. + */ + if (rc == 0) { + rc = ioctl(fd, BLKRRPART, 0); + if (rc != 0) + fprintf(stderr, + "Error: failed re-reading partition\n"); + } + + return rc; +} + +/* + * Confirm a destructive drive so that data is inadvertently erased + */ +static bool sedopal_confirm_revert(void) +{ + int rc; + char ans; + bool confirmed = false; + + /* + * verify that destructive revert is really the intention + */ + fprintf(stdout, + "Destructive revert erases drive data. Continue (y/n)? "); + rc = fscanf(stdin, " %c", &ans); + if ((rc == 1) && (ans == 'y' || ans == 'Y')) { + fprintf(stdout, "Are you sure (y/n)? "); + rc = fscanf(stdin, " %c", &ans); + if ((rc == 1) && (ans == 'y' || ans == 'Y')) + confirmed = true; + } + + return confirmed; +} + +/* + * perform a destructive drive revert + */ +static int sedopal_revert_destructive(int fd) +{ + struct opal_key key; + int rc; + + if (!sedopal_confirm_revert()) { + fprintf(stderr, "Aborting destructive revert\n"); + return -1; + } + + /* + * for destructive revert, require that key is provided + */ + sedopal_ask_key = true; + + rc = sedopal_set_key(&key); + if (rc == 0) + rc = ioctl(fd, IOC_OPAL_REVERT_TPR, &key); + + return rc; +} + +/* + * perform a PSID drive revert + */ +static int sedopal_revert_psid(int fd) +{ +#ifdef IOC_OPAL_PSID_REVERT_TPR + struct opal_key key; + int rc; + + if (!sedopal_confirm_revert()) { + fprintf(stderr, "Aborting PSID revert\n"); + return -1; + } + + rc = sedopal_set_key(&key); + if (rc == 0) { + rc = ioctl(fd, IOC_OPAL_PSID_REVERT_TPR, &key); + if (rc != 0) + fprintf(stderr, "PSID_REVERT_TPR rc %d\n", rc); + } + + return rc; +#else + fprintf(stderr, "ERROR : PSID revert is not supported\n"); + return -EOPNOTSUPP; +#endif /* IOC_OPAL_PSID_REVERT_TPR */ +} + +/* + * revert a drive from the provisioned state to a state where locking + * is disabled. + */ +int sedopal_cmd_revert(int fd) +{ + int rc; + + /* + * for revert, require that key/PSID is provided + */ + sedopal_ask_key = true; + + if (sedopal_psid_revert) { + rc = sedopal_revert_psid(fd); + } else if (sedopal_destructive_revert) { + rc = sedopal_revert_destructive(fd); + } else { +#ifdef IOC_OPAL_REVERT_LSP + struct opal_revert_lsp revert_lsp; + + rc = sedopal_set_key(&revert_lsp.key); + if (rc != 0) + return rc; + + revert_lsp.options = OPAL_PRESERVE; + revert_lsp.__pad = 0; + + rc = ioctl(fd, IOC_OPAL_REVERT_LSP, &revert_lsp); +#else + rc = -EOPNOTSUPP; +#endif + } + + if (rc != 0) + fprintf(stderr, "Error: failed reverting drive - %d\n", rc); + + return rc; +} + +/* + * Change the password of a drive. The existing password must be + * provided and the new password is confirmed by re-entry. + */ +int sedopal_cmd_password(int fd) +{ + int rc; + struct opal_new_pw new_pw = {}; + + new_pw.new_user_pw.who = OPAL_ADMIN1; + new_pw.new_user_pw.opal_key.lr = 0; + new_pw.session.who = OPAL_ADMIN1; + new_pw.session.sum = 0; + new_pw.session.opal_key.lr = 0; + + /* + * get current key + */ + sedopal_ask_key = true; + if (sedopal_set_key(&new_pw.session.opal_key) != 0) + return -EINVAL; + + /* + * get new key + */ + sedopal_ask_new_key = true; + if (sedopal_set_key(&new_pw.new_user_pw.opal_key) != 0) + return -EINVAL; + + rc = ioctl(fd, IOC_OPAL_SET_PW, &new_pw); + if (rc != 0) + fprintf(stderr, "Error: failed setting password - %d\n", rc); + + return rc; +} + +/* + * Print the state of locking features. + */ +void sedopal_print_locking_features(uint8_t features) +{ + printf("Locking Features:\n"); + printf("\tLocking Supported: %s\n", + (features & OPAL_FEATURE_LOCKING_SUPPORTED) ? "Yes" : "No"); + printf("\tLocking Feature Enabled: %s\n", + (features & OPAL_FEATURE_LOCKING_ENABLED) ? "Yes" : "No"); + printf("\tLocked: %s\n", + (features & OPAL_FEATURE_LOCKED) ? "Yes" : "No"); +} + +/* + * Query a drive to determine if it's SED Opal capable and + * it's current locking status. + */ +int sedopal_cmd_discover(int fd) +{ +#ifdef IOC_OPAL_DISCOVERY + int rc; + bool sedopal_locking_supported = false; + struct opal_discovery discover; + struct level_0_discovery_header *dh; + struct level_0_discovery_features *feat; + struct level_0_discovery_features *feat_end; + uint16_t code; + uint8_t locking_flags; + char buf[4096]; + + discover.data = (__u64)buf; + discover.size = sizeof(buf); + + rc = ioctl(fd, IOC_OPAL_DISCOVERY, &discover); + if (rc < 0) { + fprintf(stderr, "Error: ioctl IOC_OPAL_DISCOVERY failed\n"); + return rc; + } + + /* + * The returned buffer contains a level 0 discovery header + * folowed by an array of level 0 feature records. + * + * TCG Opal Specification v2.0.2 section 3.1.1 + */ + dh = (struct level_0_discovery_header *)buf; + feat = (struct level_0_discovery_features *)(dh + 1); + feat_end = (struct level_0_discovery_features *) + (buf + be32toh(dh->parameter_length)); + + /* + * iterate through all the features that were returned + */ + while (feat < feat_end) { + code = be16toh(feat->code); + switch (code) { + case OPAL_FEATURE_CODE_LOCKING: + locking_flags = feat->feature; + break; + case OPAL_FEATURE_CODE_OPALV2: + sedopal_locking_supported = true; + break; + default: + break; + } + + feat++; + } + + rc = 0; + if (!sedopal_locking_supported) { + fprintf(stderr, "Error: device does not support SED Opal\n"); + rc = -1; + } else + sedopal_print_locking_features(locking_flags); + + return rc; +#else /* IOC_OPAL_DISCOVERY */ + fprintf(stderr, "ERROR : NVMe device discovery is not supported\n"); + return -EOPNOTSUPP; +#endif +} diff --git a/plugins/sed/sedopal_cmd.h b/plugins/sed/sedopal_cmd.h new file mode 100644 index 0000000000..3b6eae27a8 --- /dev/null +++ b/plugins/sed/sedopal_cmd.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _SED_OPAL_CMD_H +#define _SED_OPAL_CMD_H + +#define SEDOPAL_CURRENT_PW_PROMPT "Password: " +#define SEDOPAL_NEW_PW_PROMPT "New Password: " +#define SEDOPAL_REENTER_PW_PROMPT "Re-enter New Password: " +#define SEDOPAL_PSID_PROMPT "PSID: " + +#define SEDOPAL_MIN_PASSWORD_LEN 8 +#define SEDOPAL_MAX_PASSWORD_LEN 32 + +#define NVME_DEV_PATH "/dev/nvme" + +extern bool sedopal_ask_key; +extern bool sedopal_ask_new_key; +extern bool sedopal_destructive_revert; +extern bool sedopal_psid_revert; + +/* + * Sub-commands supported by the sedopal command + */ +enum sedopal_cmds { + SEDOPAL_CMD_NOT_SPECIFIED = -1, + SEDOPAL_CMD_INITIALIZE = 0, + SEDOPAL_CMD_LOCK = 1, + SEDOPAL_CMD_UNLOCK = 2, + SEDOPAL_CMD_REVERT = 3, + SEDOPAL_CMD_PASSWORD = 4, + SEDOPAL_CMD_DISCOVER = 5, +}; + +struct cmd_table { + int (*cmd_handler)(int fd); +}; + +/* + * command handlers + */ +int sedopal_cmd_initialize(int fd); +int sedopal_cmd_lock(int fd); +int sedopal_cmd_unlock(int fd); +int sedopal_cmd_revert(int fd); +int sedopal_cmd_password(int fd); +int sedopal_cmd_discover(int fd); + +/* + * utility functions + */ +int sedopal_open_nvme_device(char *device); +int sedopal_lock_unlock(int fd, int lock_state); +const char *sedopal_error_to_text(int code); + +#endif /* _SED_OPAL_CMD_H */ diff --git a/plugins/sed/sedopal_spec.h b/plugins/sed/sedopal_spec.h new file mode 100644 index 0000000000..75230607bf --- /dev/null +++ b/plugins/sed/sedopal_spec.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _SED_OPAL_SPEC_H +#define _SED_OPAL_SPEC_H + +/* + * TCP Storage Architecture Core Specification Version 2.01 + * section 5.1.5 Method Status Codes + */ +enum sed_status_codes { + SED_STATUS_SUCCESS = 0x00, + SED_STATUS_NOT_AUTHORIZED = 0x01, + SED_STATUS_OBSOLETE_1 = 0x02, + SED_STATUS_SP_BUSY = 0x03, + SED_STATUS_SP_FAILED = 0x04, + SED_STATUS_SP_DISABLED = 0x05, + SED_STATUS_SP_FROZEN = 0x06, + SED_STATUS_NO_SESSIONS_AVAILABLE = 0x07, + SED_STATUS_UNIQUENESS_CONFLICT = 0x08, + SED_STATUS_INSUFFICIENT_SPACE = 0x09, + SED_STATUS_INSUFFICIENT_ROWS = 0x0A, + SED_STATUS_OBSOLETE_2 = 0x0B, + SED_STATUS_INVALID_PARAMETER = 0x0C, + SED_STATUS_OBSOLETE_3 = 0x0D, + SED_STATUS_OBSOLETE_4 = 0x0E, + SED_STATUS_TPER_MALFUNCTION = 0x0F, + SED_STATUS_TRANSACTION_FAILURE = 0x10, + SED_STATUS_RESPONSE_OVERFLOW = 0x11, + SED_STATUS_AUTHORITY_LOCKED_OUT = 0x12, + SED_STATUS_FAIL = 0x3F, + SED_STATUS_NO_METHOD_STATUS = 0x89, +}; + +/* + * Definitions from TCG Opal Specification v2.0.2 + */ + +/* + * level 0 feature codes - section 3.1.1 + */ +#define OPAL_FEATURE_CODE_LOCKING 0x0002 +#define OPAL_FEATURE_CODE_OPALV2 0x0203 + +/* locking features */ +#define OPAL_FEATURE_LOCKING_SUPPORTED 0x01 +#define OPAL_FEATURE_LOCKING_ENABLED 0x02 +#define OPAL_FEATURE_LOCKED 0x04 + + +/* + * discovery header as specified in section 3.1.1.1 + */ +struct level_0_discovery_header { + uint32_t parameter_length; + uint32_t revision; + uint64_t reserved; + uint8_t vendor_specific[32]; +}; + +/* + * level 0 features as specified in section 3.1.1.3 + */ +struct level_0_discovery_features { + uint16_t code; + uint8_t version; + uint8_t length; + uint8_t feature; + uint8_t reserved[11]; +}; + +#endif /* _SED_OPAL_SPEC_H */ diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c index 424b3f73be..d4db8c7a47 100644 --- a/plugins/shannon/shannon-nvme.c +++ b/plugins/shannon/shannon-nvme.c @@ -16,25 +16,25 @@ #define CREATE_CMD #include "shannon-nvme.h" -typedef enum { +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, + 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) +#pragma pack(push, 1) struct nvme_shannon_smart_log_item { __u8 rsv1[3]; __u8 norm; @@ -45,7 +45,7 @@ struct nvme_shannon_smart_log_item { __le16 min; __le16 max; __le16 avg; - } wear_level ; + } wear_level; struct thermal_throttle { __u8 st; __u32 count; @@ -57,68 +57,67 @@ struct nvme_shannon_smart_log_item { struct nvme_shannon_smart_log { struct nvme_shannon_smart_log_item items[ADD_SMART_ITEMS]; - __u8 vend_spec_resv; + __u8 vend_spec_resv; }; -static void show_shannon_smart_log(struct nvme_shannon_smart_log *smart, - unsigned int nsid, const char *devname) +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); + 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)); + 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)); + 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)); + 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)); + 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)); + 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); + 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)); + 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)); + 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); + 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)); + 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)); + 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)); + 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)); + smart->items[HOST_WRITE].norm, + int48_to_long(smart->items[HOST_WRITE].item_val)); + printf("sram_error_count : %3d%% %"PRIu64"\n", + smart->items[RETRY_BUFFER_OVERFLOW].norm, + int48_to_long(smart->items[SRAM_ERROR_CNT].item_val)); } - static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { struct nvme_shannon_smart_log smart_log; - char *desc = "Get Shannon vendor specific additional smart log (optionally, "\ - "for the specified namespace), and show it."; + char *desc = + "Get Shannon vendor specific additional smart log (optionally, for the specified namespace), and show it."; const char *namespace = "(optional) desired namespace"; const char *raw = "dump output in binary format"; struct nvme_dev *dev; @@ -134,7 +133,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_END() }; @@ -145,30 +144,29 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd, sizeof(smart_log), &smart_log); if (!err) { if (!cfg.raw_binary) - show_shannon_smart_log(&smart_log, cfg.namespace_id, - dev->name); + show_shannon_smart_log(&smart_log, cfg.namespace_id, dev->name); else d_raw((unsigned char *)&smart_log, sizeof(smart_log)); - } - else if (err > 0) + } else if (err > 0) { nvme_show_status(err); + } dev_close(dev); return err; } static int get_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Read operating parameters of the "\ - "specified controller. Operating parameters are grouped "\ - "and identified by Feature Identifiers; each Feature "\ - "Identifier contains one or more attributes that may affect "\ - "behavior of the feature. Each Feature has three possible "\ - "settings: default, saveable, and current. If a Feature is "\ - "saveable, it may be modified by set-feature. Default values "\ - "are vendor-specific and not changeable. Use set-feature to "\ - "change saveable Features.\n\n"\ - "Available additional feature id:\n"\ - "0x02: Shannon power management\n"; + const char *desc = "Read operating parameters of the\n" + "specified controller. Operating parameters are grouped\n" + "and identified by Feature Identifiers; each Feature\n" + "Identifier contains one or more attributes that may affect\n" + "behavior of the feature. Each Feature has three possible\n" + "settings: default, saveable, and current. If a Feature is\n" + "saveable, it may be modified by set-feature. Default values\n" + "are vendor-specific and not changeable. Use set-feature to\n" + "change saveable Features.\n\n" + "Available additional feature id:\n" + "0x02: Shannon power management\n"; const char *raw = "show infos in binary format"; const char *namespace_id = "identifier of desired namespace"; const char *feature_id = "hexadecimal feature name"; @@ -194,19 +192,19 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st struct config cfg = { .namespace_id = 1, .feature_id = 0, - .sel = 0, - .cdw11 = 0, - .data_len = 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_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() }; @@ -217,16 +215,15 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st if (cfg.sel > 7) { fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel); dev_close(dev); - return EINVAL; + return -EINVAL; } if (!cfg.feature_id) { fprintf(stderr, "feature-id required param\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } if (cfg.data_len) { - if (posix_memalign(&buf, getpagesize(), cfg.data_len)) - { + if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { dev_close(dev); exit(ENOMEM); } @@ -247,23 +244,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st .result = &result, }; err = nvme_get_features(&args); - if (!err) { -#if 0 - 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); - } - } -#endif - } else if (err > 0) + if (err > 0) nvme_show_status(err); if (buf) free(buf); @@ -272,17 +253,17 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st 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 *desc = "Modify the saveable or changeable\n" + "current operating parameters of the controller. Operating\n" + "parameters are grouped and identified by Feature\n" + "Identifiers. Feature settings can be applied to the entire\n" + "controller and all associated namespaces, or to only a few\n" + "namespace(s) associated with the controller. Default values\n" + "for each Feature are vendor-specific and may not be modified.\n" + "Use get-feature to determine which Features are supported by\n" + "the controller and are saveable/changeable.\n\n" + "Available additional feature id:\n" + "0x02: Shannon power management\n"; const char *namespace_id = "desired namespace"; const char *feature_id = "hex feature name (required)"; const char *data_len = "buffer length if data required"; @@ -305,21 +286,21 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st }; struct config cfg = { - .file = "", + .file = "", .namespace_id = 0, .feature_id = 0, - .value = 0, + .value = 0, .data_len = 0, - .save = 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_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() }; @@ -330,14 +311,14 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st if (!cfg.feature_id) { fprintf(stderr, "feature-id required param\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } if (cfg.data_len) { - if (posix_memalign(&buf, getpagesize(), cfg.data_len)){ + if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { fprintf(stderr, "can not allocate feature payload\n"); dev_close(dev); - return ENOMEM; + return -ENOMEM; } memset(buf, 0, cfg.data_len); } @@ -380,10 +361,6 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st goto free; } if (!err) { -#if 0 - printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, - nvme_feature_to_string(cfg.feature_id), cfg.value); -#endif if (buf) d(buf, cfg.data_len, 16, 1); } else if (err > 0) diff --git a/plugins/solidigm/meson.build b/plugins/solidigm/meson.build index fb0f6a995e..052afa1a71 100644 --- a/plugins/solidigm/meson.build +++ b/plugins/solidigm/meson.build @@ -1,5 +1,16 @@ sources += [ + 'plugins/solidigm/solidigm-id-ctrl.c', + 'plugins/solidigm/solidigm-util.c', 'plugins/solidigm/solidigm-smart.c', 'plugins/solidigm/solidigm-garbage-collection.c', 'plugins/solidigm/solidigm-latency-tracking.c', + 'plugins/solidigm/solidigm-log-page-dir.c', + 'plugins/solidigm/solidigm-telemetry.c', + 'plugins/solidigm/solidigm-internal-logs.c', + 'plugins/solidigm/solidigm-market-log.c', + 'plugins/solidigm/solidigm-temp-stats.c', + 'plugins/solidigm/solidigm-get-drive-info.c', + 'plugins/solidigm/solidigm-ocp-version.c', ] +subdir('solidigm-telemetry') + diff --git a/plugins/solidigm/solidigm-garbage-collection.c b/plugins/solidigm/solidigm-garbage-collection.c index 4e05ec3be4..a37e9c5847 100644 --- a/plugins/solidigm/solidigm-garbage-collection.c +++ b/plugins/solidigm/solidigm-garbage-collection.c @@ -19,27 +19,29 @@ #include "linux/types.h" #include "nvme-print.h" #include "solidigm-garbage-collection.h" +#include "solidigm-util.h" -typedef struct __attribute__((packed)) gc_item { +struct __packed gc_item { __le32 timer_type; __le64 timestamp; -} gc_item_t; +}; #define VU_GC_MAX_ITEMS 100 -typedef struct garbage_control_collection_log { +struct garbage_control_collection_log { __le16 version_major; __le16 version_minor; - gc_item_t item[VU_GC_MAX_ITEMS]; + struct __packed gc_item item[VU_GC_MAX_ITEMS]; __u8 reserved[2892]; -} garbage_control_collection_log_t; +}; -static void vu_gc_log_show_json(garbage_control_collection_log_t *payload, const char *devname) +static void vu_gc_log_show_json(struct garbage_control_collection_log *payload, const char *devname) { struct json_object *gc_entries = json_create_array(); for (int i = 0; i < VU_GC_MAX_ITEMS; i++) { - gc_item_t item = payload->item[i]; + struct __packed gc_item item = payload->item[i]; struct json_object *entry = json_create_object(); + json_object_add_value_int(entry, "timestamp", le64_to_cpu(item.timestamp)); json_object_add_value_int(entry, "timer_type", le32_to_cpu(item.timer_type)); json_array_add_value_object(gc_entries, entry); @@ -49,22 +51,27 @@ static void vu_gc_log_show_json(garbage_control_collection_log_t *payload, const json_free_object(gc_entries); } -static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char *devname) +static void vu_gc_log_show(struct garbage_control_collection_log *payload, const char *devname, + __u8 uuid_index) { - printf("Solidigm Garbage Collection Log for NVME device: %s\n", devname); + printf("Solidigm Garbage Collection Log for NVME device:%s UUID-idx:%d\n", devname, + uuid_index); printf("Timestamp Timer Type\n"); for (int i = 0; i < VU_GC_MAX_ITEMS; i++) { - gc_item_t item = payload->item[i]; - printf("%-13lu %d\n",le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type)); + struct __packed gc_item item = payload->item[i]; + + printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type)); } } int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Get and parse Solidigm vendor specific garbage collection event log."; + enum nvme_print_flags flags; struct nvme_dev *dev; int err; + __u8 uuid_index; struct config { char *output_format; @@ -83,31 +90,49 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c if (err) return err; - enum nvme_print_flags flags = validate_output_format(cfg.output_format); - if (flags == -EINVAL) { + err = validate_output_format(cfg.output_format, &flags); + if (err) { fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format); dev_close(dev); - return flags; + return -EINVAL; } - garbage_control_collection_log_t gc_log; + uuid_index = solidigm_get_vu_uuid_index(dev); + + struct garbage_control_collection_log gc_log; const int solidigm_vu_gc_log_id = 0xfd; + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = &gc_log, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = solidigm_vu_gc_log_id, + .len = sizeof(gc_log), + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = NVME_LOG_LSP_NONE, + .uuidx = uuid_index, + .rae = false, + .ot = false, + }; - err = nvme_get_log_simple(dev_fd(dev), solidigm_vu_gc_log_id, - sizeof(gc_log), &gc_log); + err = nvme_get_log(&args); if (!err) { - if (flags & BINARY) { + if (flags & BINARY) d_raw((unsigned char *)&gc_log, sizeof(gc_log)); - } else if (flags & JSON) { + else if (flags & JSON) vu_gc_log_show_json(&gc_log, dev->name); - } else { - vu_gc_log_show(&gc_log, dev->name); - } - } - else if (err > 0) { + else + vu_gc_log_show(&gc_log, dev->name, uuid_index); + } else if (err > 0) { nvme_show_status(err); } + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); dev_close(dev); return err; } diff --git a/plugins/solidigm/solidigm-get-drive-info.c b/plugins/solidigm/solidigm-get-drive-info.c new file mode 100644 index 0000000000..21f59bb865 --- /dev/null +++ b/plugins/solidigm/solidigm-get-drive-info.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Authors: leonardo.da.cunha@solidigm.com + */ + +#include +#include "nvme-print.h" +#include "nvme-wrap.h" +#include "common.h" + +int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + const char *desc = "Get drive HW information"; + const char *FTL_unit_size_str = "FTL_unit_size"; + char *output_format = "normal"; + enum nvme_print_flags flags; + nvme_root_t r; + nvme_ctrl_t c; + nvme_ns_t n; + struct nvme_id_ns ns = { 0 }; + __u8 flbaf_inUse; + __u16 lba_size; + __u16 ftl_unit_size; + int err; + + OPT_ARGS(opts) = { + OPT_FMT("output-format", 'o', &output_format, "normal|json"), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = validate_output_format(output_format, &flags); + if ((err < 0) || !(flags == NORMAL || flags == JSON)) { + nvme_show_error("Invalid output format"); + return err; + } + + r = nvme_scan(NULL); + c = nvme_scan_ctrl(r, dev->name); + n = c ? nvme_ctrl_first_ns(c) : nvme_scan_namespace(dev->name); + if (!n) { + nvme_show_error("solidigm-vs-drive-info: drive missing namespace"); + return -EINVAL; + } + + err = nvme_ns_identify(n, &ns); + if (err) { + nvme_show_error("identify namespace: %s", nvme_strerror(errno)); + return err; + } + + if (!(ns.nsfeat & 0x10)) { + nvme_show_error("solidigm-vs-drive-info: performance options not available"); + return -EINVAL; + } + + nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbaf_inUse); + lba_size = 1 << ns.lbaf[flbaf_inUse].ds; + ftl_unit_size = (le16_to_cpu(ns.npwg) + 1) * lba_size / 1024; + + if (flags == JSON) { + struct json_object *root = json_create_object(); + + json_object_add_value_int(root, FTL_unit_size_str, ftl_unit_size); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + printf("%s: %d\n", FTL_unit_size_str, ftl_unit_size); + } + + return err; +} diff --git a/plugins/solidigm/solidigm-get-drive-info.h b/plugins/solidigm/solidigm-get-drive-info.h new file mode 100644 index 0000000000..ffc1bd2468 --- /dev/null +++ b/plugins/solidigm/solidigm-get-drive-info.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin); diff --git a/plugins/solidigm/solidigm-id-ctrl.c b/plugins/solidigm/solidigm-id-ctrl.c new file mode 100644 index 0000000000..f45e758659 --- /dev/null +++ b/plugins/solidigm/solidigm-id-ctrl.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include +#include "common.h" +#include "solidigm-id-ctrl.h" + +struct __packed nvme_vu_id_ctrl_field { /* CDR MR5 */ + __u8 rsvd1[3]; + __u8 ss; + char health[20]; + __u8 cls; + __u8 nlw; + __u8 scap; + __u8 sstat; + char bl[8]; + __u8 rsvd2[38]; + __le64 ww; + char mic_bl[4]; + char mic_fw[4]; +}; + +void sldgm_id_ctrl(uint8_t *vs, struct json_object *root) +{ + // text output aligns nicely with property name up to 10 chars + const char *str_ss = "stripeSize"; + const char *str_health = "health"; + const char *str_cls = "linkSpeed"; + const char *str_nlw = "negLnkWdth"; + const char *str_scap = "secCapab"; + const char *str_sstat = "secStatus"; + const char *str_bl = "bootLoader"; + const char *str_ww = "wwid"; + const char *str_mic_bl = "bwLimGran"; + const char *str_mic_fw = "ioLimGran"; + + struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs; + + const char str_heathy[sizeof(id->health)] = "healthy"; + const char *health = id->health[0] ? id->health : str_heathy; + + if (root == NULL) { + printf("%-10s: %u\n", str_ss, id->ss); + printf("%-10s: %.*s\n", str_health, (int)sizeof(id->health), health); + printf("%-10s: %u\n", str_cls, id->cls); + printf("%-10s: %u\n", str_nlw, id->nlw); + printf("%-10s: %u\n", str_scap, id->scap); + printf("%-10s: %u\n", str_sstat, id->sstat); + printf("%-10s: %.*s\n", str_bl, (int)sizeof(id->bl), id->bl); + printf("%-10s: 0x%016"PRIx64"\n", str_ww, le64_to_cpu(id->ww)); + printf("%-10s: %.*s\n", str_mic_bl, (int)sizeof(id->mic_bl), id->mic_bl); + printf("%-10s: %.*s\n", str_mic_fw, (int)sizeof(id->mic_fw), id->mic_fw); + return; + } + + json_object_add_value_uint(root, str_ss, id->ss); + json_object_object_add(root, str_health, + json_object_new_string_len(health, sizeof(id->health))); + json_object_add_value_uint(root, str_cls, id->cls); + json_object_add_value_uint(root, str_nlw, id->nlw); + json_object_add_value_uint(root, str_scap, id->scap); + json_object_add_value_uint(root, str_sstat, id->sstat); + json_object_object_add(root, str_bl, json_object_new_string_len(id->bl, sizeof(id->bl))); + json_object_add_value_uint64(root, str_ww, le64_to_cpu(id->ww)); + json_object_object_add(root, str_mic_bl, + json_object_new_string_len(id->mic_bl, sizeof(id->mic_bl))); + json_object_object_add(root, str_mic_fw, + json_object_new_string_len(id->mic_fw, sizeof(id->mic_fw))); +} diff --git a/plugins/solidigm/solidigm-id-ctrl.h b/plugins/solidigm/solidigm-id-ctrl.h new file mode 100644 index 0000000000..ed6e438e1f --- /dev/null +++ b/plugins/solidigm/solidigm-id-ctrl.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include +#include "util/json.h" +void sldgm_id_ctrl(uint8_t *vs, struct json_object *root); diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c new file mode 100644 index 0000000000..c604761b2e --- /dev/null +++ b/plugins/solidigm/solidigm-internal-logs.c @@ -0,0 +1,657 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Authors: leonardo.da.cunha@solidigm.com + * shankaralingegowda.singonahalli@solidigm.com + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "nvme-print.h" +#include "solidigm-util.h" + +#define DWORD_SIZE 4 + +enum log_type { + NLOG = 0, + EVENTLOG = 1, + ASSERTLOG = 2, +}; + +#pragma pack(push, internal_logs, 1) +struct version { + __u16 major; + __u16 minor; +}; + +struct event_dump_instance { + __u32 numeventdumps; + __u32 coresize; + __u32 coreoffset; + __u32 eventidoffset[16]; + __u8 eventIdValidity[16]; +}; + +struct commom_header { + struct version ver; + __u32 header_size; + __u32 log_size; + __u32 numcores; +}; + +struct event_dump_header { + struct commom_header header; + __u32 eventidsize; + struct event_dump_instance edumps[0]; +}; + +struct assert_dump_core { + __u32 coreoffset; + __u32 assertsize; + __u8 assertdumptype; + __u8 assertvalid; + __u8 reserved[2]; +}; + +struct assert_dump_header { + struct commom_header header; + struct assert_dump_core core[]; +}; + +struct nlog_dump_header_common { + struct version ver; + __u32 logselect; + __u32 totalnlogs; + __u32 nlognum; + char nlogname[4]; + __u32 nlogbytesize; + __u32 nlogprimarybuffsize; + __u32 tickspersecond; + __u32 corecount; +}; + +struct nlog_dump_header3_0 { + struct nlog_dump_header_common common; + __u32 nlogpausestatus; + __u32 selectoffsetref; + __u32 selectnlogpause; + __u32 selectaddedoffset; + __u32 nlogbufnum; + __u32 nlogbufnummax; +}; + +struct nlog_dump_header4_0 { + struct nlog_dump_header_common common; + __u64 nlogpausestatus; + __u32 selectoffsetref; + __u32 selectnlogpause; + __u32 selectaddedoffset; + __u32 nlogbufnum; + __u32 nlogbufnummax; + __u32 coreselected; + __u32 reserved[2]; +}; + +struct nlog_dump_header4_1 { + struct nlog_dump_header_common common; + __u64 nlogpausestatus; + __u32 selectoffsetref; + __u32 selectnlogpause; + __u32 selectaddedoffset; + __u32 nlogbufnum; + __u32 nlogbufnummax; + __u32 coreselected; + __u32 lpaPointer1High; + __u32 lpaPointer1Low; + __u32 lpaPointer2High; + __u32 lpaPointer2Low; +}; + +#pragma pack(pop, internal_logs) + +struct config { + __u32 namespace_id; + char *dir_prefix; + char *type; + bool verbose; +}; + +static void print_nlog_header(__u8 *buffer) +{ + struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *) buffer; + + if (nlog_header->ver.major >= 3) { + printf("Version Major %u\n", nlog_header->ver.major); + printf("Version Minor %u\n", nlog_header->ver.minor); + printf("Log_select %u\n", nlog_header->logselect); + printf("totalnlogs %u\n", nlog_header->totalnlogs); + printf("nlognum %u\n", nlog_header->nlognum); + printf("nlogname %c%c%c%c\n", nlog_header->nlogname[3], nlog_header->nlogname[2], + nlog_header->nlogname[1], nlog_header->nlogname[0]); + printf("nlogbytesize %u\n", nlog_header->nlogbytesize); + printf("nlogprimarybuffsize %u\n", nlog_header->nlogprimarybuffsize); + printf("tickspersecond %u\n", nlog_header->tickspersecond); + printf("corecount %u\n", nlog_header->corecount); + } + if (nlog_header->ver.major >= 4) { + struct nlog_dump_header4_0 *nlog_header = (struct nlog_dump_header4_0 *) buffer; + + printf("nlogpausestatus %"PRIu64"\n", (uint64_t)nlog_header->nlogpausestatus); + printf("selectoffsetref %u\n", nlog_header->selectoffsetref); + printf("selectnlogpause %u\n", nlog_header->selectnlogpause); + printf("selectaddedoffset %u\n", nlog_header->selectaddedoffset); + printf("nlogbufnum %u\n", nlog_header->nlogbufnum); + printf("nlogbufnummax %u\n", nlog_header->nlogbufnummax); + printf("coreselected %u\n\n", nlog_header->coreselected); + } +} + +#define INTERNAL_LOG_MAX_BYTE_TRANSFER 4096 +#define INTERNAL_LOG_MAX_DWORD_TRANSFER (INTERNAL_LOG_MAX_BYTE_TRANSFER / 4) + +static int cmd_dump_repeat(struct nvme_passthru_cmd *cmd, __u32 total_dw_size, + int out_fd, int ioctl_fd, bool force_max_transfer) +{ + int err = 0; + + while (total_dw_size > 0) { + size_t dword_tfer = min(INTERNAL_LOG_MAX_DWORD_TRANSFER, total_dw_size); + + cmd->cdw10 = force_max_transfer ? INTERNAL_LOG_MAX_DWORD_TRANSFER : dword_tfer; + cmd->data_len = dword_tfer * 4; + err = nvme_submit_admin_passthru(ioctl_fd, cmd, NULL); + if (err) + return err; + + if (out_fd > 0) { + err = write(out_fd, (const void *)(uintptr_t)cmd->addr, cmd->data_len); + if (err < 0) { + perror("write failure"); + return err; + } + err = 0; + } + total_dw_size -= dword_tfer; + cmd->cdw13 += dword_tfer; + } + return err; +} + +static int write_header(__u8 *buf, int fd, size_t amnt) +{ + if (write(fd, buf, amnt) < 0) + return 1; + return 0; +} + +static int read_header(struct nvme_passthru_cmd *cmd, int ioctl_fd) +{ + memset((void *)(uintptr_t)cmd->addr, 0, INTERNAL_LOG_MAX_BYTE_TRANSFER); + return cmd_dump_repeat(cmd, INTERNAL_LOG_MAX_DWORD_TRANSFER, -1, ioctl_fd, false); +} + +static int get_serial_number(char *str, int fd) +{ + struct nvme_id_ctrl ctrl = {0}; + int err; + + err = nvme_identify_ctrl(fd, &ctrl); + if (err) + return err; + + /* Remove trailing spaces */ + for (int i = sizeof(ctrl.sn) - 1; i && ctrl.sn[i] == ' '; i--) + ctrl.sn[i] = '\0'; + sprintf(str, "%-.*s", (int)sizeof(ctrl.sn), ctrl.sn); + return err; +} + +static int dump_assert_logs(struct nvme_dev *dev, struct config cfg) +{ + __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; + __u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; + char file_path[PATH_MAX]; + char file_name[] = "AssertLog.bin"; + struct assert_dump_header *ad = (struct assert_dump_header *) head_buf; + struct nvme_passthru_cmd cmd = { + .opcode = 0xd2, + .nsid = cfg.namespace_id, + .addr = (unsigned long)(void *)head_buf, + .cdw12 = ASSERTLOG, + .cdw13 = 0, + }; + int output, err; + + err = read_header(&cmd, dev_fd(dev)); + if (err) + return err; + + snprintf(file_path, sizeof(file_path), "%.*s/%s", + (int) (sizeof(file_path) - sizeof(file_name) - 1), cfg.dir_prefix, file_name); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) + return -errno; + err = write_header((__u8 *)ad, output, ad->header.header_size * DWORD_SIZE); + if (err) { + perror("write failure"); + close(output); + return err; + } + cmd.addr = (unsigned long)(void *)buf; + + if (cfg.verbose) { + printf("Assert Log, cores: %d log size: %d header size: %d\n", ad->header.numcores, + ad->header.log_size * DWORD_SIZE, ad->header.header_size * DWORD_SIZE); + for (__u32 i = 0; i < ad->header.numcores; i++) + printf("core %d assert size: %d\n", i, ad->core[i].assertsize * DWORD_SIZE); + } + + for (__u32 i = 0; i < ad->header.numcores; i++) { + if (!ad->core[i].assertvalid) + continue; + cmd.cdw13 = ad->core[i].coreoffset; + err = cmd_dump_repeat(&cmd, ad->core[i].assertsize, + output, + dev_fd(dev), false); + if (err) { + close(output); + return err; + } + } + close(output); + printf("Successfully wrote log to %s\n", file_path); + return err; +} + +static int dump_event_logs(struct nvme_dev *dev, struct config cfg) +{ + __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; + __u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; + char file_path[PATH_MAX]; + struct event_dump_header *ehdr = (struct event_dump_header *) head_buf; + struct nvme_passthru_cmd cmd = { + .opcode = 0xd2, + .nsid = cfg.namespace_id, + .addr = (unsigned long)(void *)head_buf, + .cdw12 = EVENTLOG, + .cdw13 = 0, + }; + int output; + int core_num, err; + + err = read_header(&cmd, dev_fd(dev)); + if (err) + return err; + snprintf(file_path, sizeof(file_path), "%s/EventLog.bin", cfg.dir_prefix); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) + return -errno; + err = write_header(head_buf, output, INTERNAL_LOG_MAX_BYTE_TRANSFER); + + core_num = ehdr->header.numcores; + + if (err) { + close(output); + return err; + } + cmd.addr = (unsigned long)(void *)buf; + + if (cfg.verbose) + printf("Event Log, cores: %d log size: %d\n", core_num, ehdr->header.log_size * 4); + + for (__u32 j = 0; j < core_num; j++) { + if (cfg.verbose) { + for (int k = 0 ; k < 16; k++) { + printf("core: %d event: %d ", j, k); + printf("validity: %d ", ehdr->edumps[j].eventIdValidity[k]); + printf("offset: %d\n", ehdr->edumps[j].eventidoffset[k]); + } + } + cmd.cdw13 = ehdr->edumps[j].coreoffset; + err = cmd_dump_repeat(&cmd, ehdr->edumps[j].coresize, + output, dev_fd(dev), false); + if (err) { + close(output); + return err; + } + } + close(output); + printf("Successfully wrote log to %s\n", file_path); + return err; +} + +static size_t get_nlog_header_size(struct nlog_dump_header_common *nlog_header) +{ + switch (nlog_header->ver.major) { + case 3: + return sizeof(struct nlog_dump_header3_0); + case 4: + if (nlog_header->ver.minor == 0) + return sizeof(struct nlog_dump_header4_0); + return sizeof(struct nlog_dump_header4_1); + default: + return INTERNAL_LOG_MAX_BYTE_TRANSFER; + } + +} + +/* dumps nlogs from specified core or all cores when core = -1 */ +static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core) +{ + int err = 0; + __u32 count, core_num; + __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; + char file_path[PATH_MAX]; + struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *)buf; + struct nvme_passthru_cmd cmd = { + .opcode = 0xd2, + .nsid = cfg.namespace_id, + .addr = (unsigned long)(void *)buf + }; + + struct dump_select { + union { + struct { + __u32 selectLog : 3; + __u32 selectCore : 2; + __u32 selectNlog : 8; + }; + __u32 raw; + }; + } log_select; + int output; + bool is_open = false; + size_t header_size = 0; + + log_select.selectCore = core < 0 ? 0 : core; + do { + log_select.selectNlog = 0; + do { + cmd.cdw13 = 0; + cmd.cdw12 = log_select.raw; + err = read_header(&cmd, dev_fd(dev)); + if (err) { + if (is_open) + close(output); + return err; + } + count = nlog_header->totalnlogs; + core_num = core < 0 ? nlog_header->corecount : 0; + if (!header_size) { + snprintf(file_path, sizeof(file_path), "%s/NLog.bin", + cfg.dir_prefix); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) + return -errno; + header_size = get_nlog_header_size(nlog_header); + is_open = true; + } + err = write_header(buf, output, header_size); + if (err) + break; + if (cfg.verbose) + print_nlog_header(buf); + cmd.cdw13 = 0x400; + err = cmd_dump_repeat(&cmd, nlog_header->nlogbytesize / 4, + output, dev_fd(dev), true); + if (err) + break; + } while (++log_select.selectNlog < count); + if (err) + break; + } while (++log_select.selectCore < core_num); + if (is_open) { + close(output); + printf("Successfully wrote log to %s\n", file_path); + } + return err; +} + +enum telemetry_type { + HOSTGENOLD, + HOSTGENNEW, + CONTROLLER +}; + +static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype) +{ + _cleanup_free_ struct nvme_telemetry_log *log = NULL; + size_t log_size = 0; + int err = 0; + __u8 *buffer = NULL; + size_t bytes_remaining = 0; + enum nvme_telemetry_da da; + size_t max_data_tx; + char file_path[PATH_MAX]; + char *file_name; + char *log_descr; + struct stat sb; + + _cleanup_file_ int output = -1; + + switch (ttype) { + case HOSTGENNEW: + file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin"; + log_descr = "Generated Host Initiated"; + break; + case HOSTGENOLD: + file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin"; + log_descr = "Existing Host Initiated"; + break; + case CONTROLLER: + file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin"; + log_descr = "Controller Initiated"; + break; + default: + return -EINVAL; + } + err = nvme_get_telemetry_max(dev_fd(dev), &da, &max_data_tx); + if (err) + return err; + + if (max_data_tx > DRIVER_MAX_TX_256K) + max_data_tx = DRIVER_MAX_TX_256K; + + switch (ttype) { + case HOSTGENNEW: + err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da, + &log, &log_size); + break; + case HOSTGENOLD: + err = nvme_get_telemetry_log(dev_fd(dev), false, false, false, max_data_tx, da, + &log, &log_size); + break; + case CONTROLLER: + err = nvme_get_telemetry_log(dev_fd(dev), false, true, true, max_data_tx, da, &log, + &log_size); + break; + } + + if (err) + return err; + + snprintf(file_path, sizeof(file_path), "%s/log_pages", cfg.dir_prefix); + if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) { + if (mkdir(file_path, 777) != 0) { + perror(file_path); + return -errno; + } + } + + snprintf(file_path, sizeof(file_path), "%s/log_pages/%s", cfg.dir_prefix, file_name); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (output < 0) + return -errno; + + bytes_remaining = log_size; + buffer = (__u8 *)log; + + while (bytes_remaining) { + ssize_t bytes_written = write(output, buffer, bytes_remaining); + + if (bytes_written < 0) { + err = -errno; + goto tele_close_output; + } + + bytes_remaining -= bytes_written; + buffer += bytes_written; + } + printf("Successfully wrote %s Telemetry log to %s\n", log_descr, file_path); + +tele_close_output: + close(output); + return err; +} + +int solidigm_get_internal_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + char folder[PATH_MAX]; + char zip_name[PATH_MAX]; + char *output_path; + char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1]; + int log_count = 0; + int err; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; + bool all = false; + time_t t; + struct tm tm; + + const char *desc = "Get Debug Firmware Logs and save them."; + const char *type = + "Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL."; + const char *prefix = "Output dir prefix; defaults to device serial number."; + const char *verbose = "To print out verbose info."; + const char *namespace_id = "Namespace to get logs from."; + + + struct config cfg = { + .namespace_id = NVME_NSID_ALL, + .dir_prefix = NULL, + .type = NULL, + }; + + OPT_ARGS(opts) = { + OPT_STR("type", 't', &cfg.type, type), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_FILE("dir-prefix", 'p', &cfg.dir_prefix, prefix), + OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + if (!cfg.dir_prefix) { + err = get_serial_number(sn_prefix, dev_fd(dev)); + if (err) + return err; + cfg.dir_prefix = sn_prefix; + } + t = time(NULL); + tm = *localtime(&t); + snprintf(folder, sizeof(folder), "%s-%d%02d%02d%02d%02d%02d", cfg.dir_prefix, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + if (mkdir(folder, 0777) != 0) { + perror("mkdir"); + return -errno; + } + cfg.dir_prefix = folder; + output_path = folder; + + if (!cfg.type) + cfg.type = "ALL"; + else { + for (char *p = cfg.type; *p; ++p) + *p = toupper(*p); + } + + if (!strcmp(cfg.type, "ALL")) { + all = true; + } + if (all || !strcmp(cfg.type, "ASSERT")) { + err = dump_assert_logs(dev, cfg); + if (err == 0) + log_count++; + else if (err < 0) + perror("Error retrieving Assert log"); + } + if (all || !strcmp(cfg.type, "EVENT")) { + err = dump_event_logs(dev, cfg); + if (err == 0) + log_count++; + else if (err < 0) + perror("Error retrieving Event log"); + } + if (all || !strcmp(cfg.type, "NLOG")) { + err = dump_nlogs(dev, cfg, -1); + if (err == 0) + log_count++; + else if (err < 0) + perror("Error retrieving Nlog"); + } + if (all || !strcmp(cfg.type, "CONTROLLERINITTELEMETRY")) { + err = dump_telemetry(dev, cfg, CONTROLLER); + if (err == 0) + log_count++; + else if (err < 0) + perror("Error retrieving Telemetry Controller Initiated"); + } + if (all || !strcmp(cfg.type, "HOSTINITTELEMETRYNOGEN")) { + err = dump_telemetry(dev, cfg, HOSTGENOLD); + if (err == 0) + log_count++; + else if (err < 0) + perror("Error retrieving previously existing Telemetry Host Initiated"); + } + if (all || !strcmp(cfg.type, "HOSTINITTELEMETRY")) { + err = dump_telemetry(dev, cfg, HOSTGENNEW); + if (err == 0) + log_count++; + else if (err < 0) + perror("Error retrieving Telemetry Host Initiated"); + } + + if (log_count > 0) { + int ret_cmd; + char cmd[ARG_MAX]; + char *where_err = cfg.verbose ? "" : ">/dev/null 2>&1"; + + snprintf(zip_name, sizeof(zip_name), "%s.zip", cfg.dir_prefix); + snprintf(cmd, sizeof(cmd), "cd \"%s\" && zip -r \"../%s\" ./* %s", cfg.dir_prefix, + zip_name, where_err); + printf("Compressing logs to %s\n", zip_name); + ret_cmd = system(cmd); + if (ret_cmd == -1) + perror(cmd); + else { + output_path = zip_name; + snprintf(cmd, sizeof(cmd), "rm -rf %s", cfg.dir_prefix); + printf("Removing %s\n", cfg.dir_prefix); + if (system(cmd) != 0) + perror("Failed removing logs folder"); + } + } + + if (log_count == 0) { + if (err > 0) + nvme_show_status(err); + } else if ((log_count > 1) || cfg.verbose) + printf("Total: %d log files in %s\n", log_count, output_path); + + return err; +} diff --git a/plugins/solidigm/solidigm-internal-logs.h b/plugins/solidigm/solidigm-internal-logs.h new file mode 100644 index 0000000000..801af246c7 --- /dev/null +++ b/plugins/solidigm/solidigm-internal-logs.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +int solidigm_get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin); diff --git a/plugins/solidigm/solidigm-latency-tracking.c b/plugins/solidigm/solidigm-latency-tracking.c index 3836bac63d..66f3c560df 100644 --- a/plugins/solidigm/solidigm-latency-tracking.c +++ b/plugins/solidigm/solidigm-latency-tracking.c @@ -17,6 +17,7 @@ #include "plugin.h" #include "linux/types.h" #include "nvme-print.h" +#include "solidigm-util.h" #define BUCKET_LIST_SIZE_4_0 152 #define BUCKET_LIST_SIZE_4_1 1216 @@ -42,6 +43,7 @@ struct config { struct latency_tracker { int fd; + __u8 uuid_index; struct config cfg; enum nvme_print_flags print_flags; struct latency_statistics stats; @@ -92,7 +94,6 @@ static void latency_tracker_bucket_parse(const struct latency_tracker *lt, int i __u32 bucket_data = le32_to_cpu(lt->stats.data[id]); if (lt->print_flags == NORMAL) { - printf("%-*d", COL_WIDTH, id); get_time_unit_label(buffer, lower_us, true); @@ -135,12 +136,10 @@ static void latency_tracker_parse_linear(const struct latency_tracker *lt, __u32 bytes_per, __u32 us_step, bool nonzero_print) { - for (int i = (start_offset / bytes_per) - 1; - i < end_offset / bytes_per; i++) { - if (nonzero_print && lt->stats.data[i] == 0) + for (int i = (start_offset / bytes_per) - 1; i < end_offset / bytes_per; i++) { + if (nonzero_print && !lt->stats.data[i]) continue; - latency_tracker_bucket_parse(lt, i, us_step * i, - us_step * (i + 1), true); + latency_tracker_bucket_parse(lt, i, us_step * i, us_step * (i + 1), true); } } @@ -151,6 +150,7 @@ static void latency_tracker_parse_linear(const struct latency_tracker *lt, static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i) { __u32 base_val = 1 << lt->base_range_bits; + if (i < (base_val << 1)) return i; @@ -169,15 +169,15 @@ static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i * "values" : { */ static void latency_tracker_populate_json_root(const struct latency_tracker *lt, - struct json_object *root) + struct json_object *root) { struct json_object *subroot = json_create_object(); json_object_add_value_object(root, "latstats", subroot); json_object_add_value_string(subroot, "type", lt->cfg.write ? "write" : "read"); - if (lt->has_average_latency_field) { - json_object_add_value_uint64(subroot, "average_latency", le64_to_cpu(lt->stats.average_latency)); - } + if (lt->has_average_latency_field) + json_object_add_value_uint64(subroot, "average_latency", + le64_to_cpu(lt->stats.average_latency)); json_object_add_value_object(subroot, "values", lt->bucket_list); } @@ -197,13 +197,12 @@ static void latency_tracker_parse_4_0(const struct latency_tracker *lt) int lower_us = latency_tracker_bucket_pos2us(lt, i); int upper_us = latency_tracker_bucket_pos2us(lt, i + 1); - latency_tracker_bucket_parse(lt, i, lower_us, - upper_us, + latency_tracker_bucket_parse(lt, i, lower_us, upper_us, i < (lt->bucket_list_size - 1)); } } -static void print_dash_separator() +static void print_dash_separator(void) { printf("--------------------------------------------------\n"); } @@ -213,18 +212,17 @@ static void latency_tracker_pre_parse(struct latency_tracker *lt) if (lt->print_flags == NORMAL) { printf("Solidigm IO %s Command Latency Tracking Statistics type %d\n", lt->cfg.write ? "Write" : "Read", lt->cfg.type); + printf("UUID-idx: %d\n", lt->uuid_index); printf("Major Revision: %u\nMinor Revision: %u\n", le16_to_cpu(lt->stats.version_major), le16_to_cpu(lt->stats.version_minor)); - if (lt->has_average_latency_field) { - printf("Average Latency: %lu\n", le64_to_cpu(lt->stats.average_latency)); - } + if (lt->has_average_latency_field) + printf("Average Latency: %" PRIu64 "\n", le64_to_cpu(lt->stats.average_latency)); print_dash_separator(); printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value"); print_dash_separator(); } - if (lt->print_flags == JSON) { + if (lt->print_flags == JSON) lt->bucket_list = json_object_new_array(); - } } static void latency_tracker_post_parse(struct latency_tracker *lt) @@ -250,11 +248,10 @@ static void latency_tracker_parse(struct latency_tracker *lt) latency_tracker_parse_3_0(lt); break; case 4: - if (version_minor >= 8){ + if (version_minor >= 8) lt->has_average_latency_field = true; - } latency_tracker_pre_parse(lt); - if (version_minor == 0){ + if (!version_minor) { lt->base_range_bits = BASE_RANGE_BITS_4_0; lt->bucket_list_size = BUCKET_LIST_SIZE_4_0; } @@ -272,16 +269,16 @@ static void latency_tracker_parse(struct latency_tracker *lt) #define LATENCY_TRACKING_FID 0xe2 #define LATENCY_TRACKING_FID_DATA_LEN 32 -static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 * enabled) +static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 *enabled) { struct nvme_get_features_args args_get = { .args_size = sizeof(args_get), - .fd = lt->fd, + .fd = lt->fd, + .uuidx = lt->uuid_index, .fid = LATENCY_TRACKING_FID, .nsid = 0, .sel = 0, .cdw11 = 0, - .uuidx = 0, .data_len = LATENCY_TRACKING_FID_DATA_LEN, .data = NULL, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, @@ -295,24 +292,23 @@ static int latency_tracking_enable(struct latency_tracker *lt) __u32 result; int err; - if (!(lt->cfg.enable || lt->cfg.disable)){ + if (!(lt->cfg.enable || lt->cfg.disable)) return 0; - } - if (lt->cfg.enable && lt->cfg.disable){ - fprintf(stderr,"Cannot enable and disable simultaneously.\n"); - return EINVAL; + if (lt->cfg.enable && lt->cfg.disable) { + fprintf(stderr, "Cannot enable and disable simultaneously.\n"); + return -EINVAL; } struct nvme_set_features_args args_set = { .args_size = sizeof(args_set), .fd = lt->fd, + .uuidx = lt->uuid_index, .fid = LATENCY_TRACKING_FID, .nsid = 0, .cdw11 = lt->cfg.enable, .cdw12 = 0, .save = 0, - .uuidx = 0, .cdw15 = 0, .data_len = LATENCY_TRACKING_FID_DATA_LEN, .data = NULL, @@ -328,8 +324,8 @@ static int latency_tracking_enable(struct latency_tracker *lt) fprintf(stderr, "Command failed while parsing.\n"); } else { if (lt->print_flags == NORMAL) { - printf("Successfully set enable bit for FID (0x%X) to %i.\n", - LATENCY_TRACKING_FID, lt->cfg.enable); + printf("Successfully set enable bit for UUID-idx:%d FID:0x%X, to %i.\n", + lt->uuid_index, LATENCY_TRACKING_FID, lt->cfg.enable); } } return err; @@ -342,9 +338,9 @@ static int latency_tracker_get_log(struct latency_tracker *lt) { int err; - if (lt->cfg.read && lt->cfg.write){ - fprintf(stderr,"Cannot capture read and write logs simultaneously.\n"); - return EINVAL; + if (lt->cfg.read && lt->cfg.write) { + fprintf(stderr, "Cannot capture read and write logs simultaneously.\n"); + return -EINVAL; } if (!(lt->cfg.read || lt->cfg.write)) @@ -356,6 +352,7 @@ static int latency_tracker_get_log(struct latency_tracker *lt) .log = <->stats, .args_size = sizeof(args), .fd = lt->fd, + .uuidx = lt->uuid_index, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .lid = lt->cfg.write ? WRITE_LOG_ID : READ_LOG_ID, .len = sizeof(lt->stats), @@ -363,7 +360,6 @@ static int latency_tracker_get_log(struct latency_tracker *lt) .csi = NVME_CSI_NVM, .lsi = NVME_LOG_LSI_NONE, .lsp = lt->cfg.type, - .uuidx = NVME_UUID_NONE, .rae = false, .ot = false, }; @@ -390,6 +386,7 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd int err; struct latency_tracker lt = { + .uuid_index = 0, .cfg = { .output_format = "normal", }, @@ -414,33 +411,35 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd lt.fd = dev_fd(dev); - lt.print_flags = validate_output_format(lt.cfg.output_format); - if (lt.print_flags == -EINVAL) { + err = validate_output_format(lt.cfg.output_format, <.print_flags); + if (err < 0) { fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format); dev_close(dev); - return EINVAL; + return -EINVAL; } if (lt.cfg.type > 0xf) { fprintf(stderr, "Invalid Log type value '%d'\n", lt.cfg.type); dev_close(dev); - return EINVAL; + return -EINVAL; } if (lt.cfg.type && !(lt.cfg.read || lt.cfg.write)) { fprintf(stderr, "Log type option valid only when retrieving statistics\n"); dev_close(dev); - return EINVAL; + return -EINVAL; } + lt.uuid_index = solidigm_get_vu_uuid_index(dev); + err = latency_tracking_enable(<); - if (err){ + if (err) { dev_close(dev); return err; } err = latency_tracker_get_log(<); - if (err){ + if (err) { dev_close(dev); return err; } @@ -454,20 +453,22 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd if (!err) { if (lt.print_flags == JSON) { struct json_object *root = json_create_object(); - json_object_add_value_int(root,"enabled", enabled); + + json_object_add_value_int(root, "enabled", enabled); json_print_object(root, NULL); json_free_object(root); printf("\n"); } else if (lt.print_flags == BINARY) { putchar(enabled); } else { - printf( - "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n", - LATENCY_TRACKING_FID, enabled); + printf("Latency Statistics Tracking (UUID-idx:%d, FID:0x%X) is currently %i.\n", + lt.uuid_index, LATENCY_TRACKING_FID, enabled); } } else { fprintf(stderr, "Could not read feature id 0xE2.\n"); } + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); dev_close(dev); return err; } diff --git a/plugins/solidigm/solidigm-log-page-dir.c b/plugins/solidigm/solidigm-log-page-dir.c new file mode 100644 index 0000000000..bf272f8da1 --- /dev/null +++ b/plugins/solidigm/solidigm-log-page-dir.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Author: karl.dedow@solidigm.com + */ + +#include "solidigm-log-page-dir.h" + +#include +#include +#include + +#include "common.h" +#include "nvme-print.h" + +#include "plugins/ocp/ocp-utils.h" + +#define MIN_VENDOR_LID 0xC0 +#define SOLIDIGM_MAX_UUID 2 + +static const char dash[100] = {[0 ... 99] = '-'}; + +struct lid_dir { + struct __packed { + bool supported; + const char *str; + } lid[NVME_LOG_SUPPORTED_LOG_PAGES_MAX]; +}; + +static void init_lid_dir(struct lid_dir *lid_dir) +{ + static const char *unknown_str = "Unknown"; + + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + lid_dir->lid[lid].supported = false; + lid_dir->lid[lid].str = unknown_str; + } +} + +static bool is_invalid_uuid(const struct nvme_id_uuid_list_entry entry) +{ + static const unsigned char ALL_ZERO_UUID[NVME_UUID_LEN] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + return memcmp(ALL_ZERO_UUID, entry.uuid, NVME_UUID_LEN) == 0; +} + +static bool is_solidigm_uuid(const struct nvme_id_uuid_list_entry entry) +{ + static const unsigned char SOLIDIGM_UUID[NVME_UUID_LEN] = { + 0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad, + 0xaa, 0xaa, 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2 + }; + + return memcmp(SOLIDIGM_UUID, entry.uuid, NVME_UUID_LEN) == 0; +} + +static bool is_ocp_uuid(const struct nvme_id_uuid_list_entry entry) +{ + static const unsigned char OCP_UUID[NVME_UUID_LEN] = { + 0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94, + 0xa2, 0x1d, 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f + }; + + return memcmp(OCP_UUID, entry.uuid, NVME_UUID_LEN) == 0; +} + +static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index, + struct nvme_supported_log_pages *supported) +{ + static const __u8 LID; + + memset(supported, 0, sizeof(*supported)); + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = supported, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = LID, + .len = sizeof(*supported), + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = 0, + .uuidx = uuid_index, + .rae = false, + .ot = false, + }; + + return nvme_get_log(&args); +} + +static struct lid_dir *get_standard_lids(struct nvme_supported_log_pages *supported) +{ + static struct lid_dir standard_dir = { 0 }; + + init_lid_dir(&standard_dir); + + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID) + continue; + + standard_dir.lid[lid].supported = true; + standard_dir.lid[lid].str = nvme_log_to_string(lid); + } + + return &standard_dir; +} + +static void update_vendor_lid_supported(struct nvme_supported_log_pages *supported, + struct lid_dir *lid_dir) +{ + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!supported->lid_support[lid] || lid < MIN_VENDOR_LID) + continue; + + lid_dir->lid[lid].supported = true; + } +} + +static struct lid_dir *get_solidigm_lids(struct nvme_supported_log_pages *supported) +{ + static struct lid_dir solidigm_dir = { 0 }; + + init_lid_dir(&solidigm_dir); + solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics"; + solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics"; + solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics"; + solidigm_dir.lid[0xC5].str = "Temperature Statistics"; + solidigm_dir.lid[0xCA].str = "SMART Attributes"; + solidigm_dir.lid[0xCB].str = "VU NVMe IO Queue Metrics Log Page"; + solidigm_dir.lid[0xDD].str = "VU Marketing Description Log Page"; + solidigm_dir.lid[0xEF].str = "Performance Rating and LBA Access Histogram"; + solidigm_dir.lid[0xF2].str = "Get Power Usage Log Page"; + solidigm_dir.lid[0xF6].str = "Vt Histo Get Log Page"; + solidigm_dir.lid[0xF9].str = "Workload Tracker Get Log Page"; + solidigm_dir.lid[0xFD].str = "Garbage Control Collection Log Page"; + solidigm_dir.lid[0xFE].str = "Latency Outlier Log Page"; + + update_vendor_lid_supported(supported, &solidigm_dir); + + return &solidigm_dir; +} + +static struct lid_dir *get_ocp_lids(struct nvme_supported_log_pages *supported) +{ + static struct lid_dir ocp_dir = { 0 }; + + init_lid_dir(&ocp_dir); + ocp_dir.lid[0xC0].str = "OCP SMART / Health Information Extended"; + ocp_dir.lid[0xC1].str = "OCP Error Recovery"; + ocp_dir.lid[0xC2].str = "OCP Firmware Activation History"; + ocp_dir.lid[0xC3].str = "OCP Latency Monitor"; + ocp_dir.lid[0xC4].str = "OCP Device Capabilities"; + ocp_dir.lid[0xC5].str = "OCP Unsupported Requirements"; + + update_vendor_lid_supported(supported, &ocp_dir); + + return &ocp_dir; +} + +static void supported_log_pages_normal(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1]) +{ + printf("%-5s %-4s %-42s\n", "uuidx", "LID", "Description"); + printf("%-.5s %-.4s %-.42s\n", dash, dash, dash); + + for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) { + if (!lid_dir[uuid_index]) + continue; + + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!lid_dir[uuid_index]->lid[lid].supported) + continue; + + printf("%-5d 0x%02x %s\n", le32_to_cpu(uuid_index), le32_to_cpu(lid), + lid_dir[uuid_index]->lid[lid].str); + } + } +} + +static void supported_log_pages_json(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1]) +{ + struct json_object *root = json_create_array(); + + for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) { + if (!lid_dir[uuid_index]) + continue; + + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (!lid_dir[uuid_index]->lid[lid].supported) + continue; + + struct json_object *lid_obj = json_create_object(); + + json_object_add_value_uint(lid_obj, "uuidx", le32_to_cpu(uuid_index)); + json_object_add_value_uint(lid_obj, "lid", le32_to_cpu(lid)); + json_object_add_value_string(lid_obj, "description", + lid_dir[uuid_index]->lid[lid].str); + json_array_add_value_object(root, lid_obj); + } + } + + json_print_object(root, NULL); + json_free_object(root); + printf("\n"); +} + +int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const int NO_UUID_INDEX = 0; + const char *description = "Retrieves list of supported log pages for each UUID index."; + char *format = "normal"; + + OPT_ARGS(options) = { + OPT_FMT("output-format", 'o', &format, "output format : normal | json"), + OPT_END() + }; + + struct nvme_dev *dev = NULL; + int err = parse_and_open(&dev, argc, argv, description, options); + + if (err) + return err; + + struct lid_dir *lid_dirs[SOLIDIGM_MAX_UUID + 1] = { 0 }; + struct nvme_id_uuid_list uuid_list = { 0 }; + struct nvme_supported_log_pages supported = { 0 }; + + err = get_supported_log_pages_log(dev, NO_UUID_INDEX, &supported); + + if (!err) { + lid_dirs[NO_UUID_INDEX] = get_standard_lids(&supported); + + // Assume VU logs are the Solidigm log pages if UUID not supported. + if (nvme_identify_uuid(dev_fd(dev), &uuid_list)) { + struct lid_dir *solidigm_lid_dir = get_solidigm_lids(&supported); + + // Transfer supported Solidigm lids to lid directory at UUID index 0 + for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) { + if (solidigm_lid_dir->lid[lid].supported) + lid_dirs[NO_UUID_INDEX]->lid[lid] = solidigm_lid_dir->lid[lid]; + } + } else { + for (int uuid_index = 1; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) { + if (is_invalid_uuid(uuid_list.entry[uuid_index - 1])) + break; + else if (get_supported_log_pages_log(dev, uuid_index, &supported)) + continue; + + if (is_solidigm_uuid(uuid_list.entry[uuid_index - 1])) + lid_dirs[uuid_index] = get_solidigm_lids(&supported); + else if (is_ocp_uuid(uuid_list.entry[uuid_index - 1])) + lid_dirs[uuid_index] = get_ocp_lids(&supported); + } + } + } else { + nvme_show_status(err); + } + + if (!err) { + enum nvme_print_flags print_flag; + + err = validate_output_format(format, &print_flag); + if (err < 0) { + fprintf(stderr, "Error: Invalid output format specified: %s.\n", format); + return err; + } + + if (print_flag == NORMAL) { + supported_log_pages_normal(lid_dirs); + } else if (print_flag == JSON) { + supported_log_pages_json(lid_dirs); + } + } + + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); + dev_close(dev); + return err; +} diff --git a/plugins/solidigm/solidigm-log-page-dir.h b/plugins/solidigm/solidigm-log-page-dir.h new file mode 100644 index 0000000000..48777df7d8 --- /dev/null +++ b/plugins/solidigm/solidigm-log-page-dir.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Authors: karl.dedow@solidigm.com + */ + +#ifndef SOLIDIGM_LOG_PAGE_DIRECTORY_H +#define SOLIDIGM_LOG_PAGE_DIRECTORY_H + +struct command; +struct plugin; + +int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin); + +#endif diff --git a/plugins/solidigm/solidigm-market-log.c b/plugins/solidigm/solidigm-market-log.c new file mode 100644 index 0000000000..d7d38daab0 --- /dev/null +++ b/plugins/solidigm/solidigm-market-log.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Authors: leonardo.da.cunha@solidigm.com + * Hardeep.Dhillon@solidigm.com + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "nvme-print.h" + +#define MARKET_LOG_MAX_SIZE 512 + +int sldgm_get_market_log(int argc, char **argv, struct command *command, + struct plugin *plugin) +{ + const char *desc = "Get Solidigm Marketing Name log and show it."; + const char *raw = "dump output in binary format"; + struct nvme_dev *dev; + char log[MARKET_LOG_MAX_SIZE]; + int err; + + struct config { + bool raw_binary; + }; + + struct config cfg = { + }; + + OPT_ARGS(opts) = { + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = nvme_get_log_simple(dev_fd(dev), 0xdd, sizeof(log), log); + if (!err) { + if (!cfg.raw_binary) + printf("Solidigm Marketing Name Log:\n%s\n", log); + else + d_raw((unsigned char *)&log, sizeof(log)); + } else if (err > 0) + + nvme_show_status(err); + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); + dev_close(dev); + return err; +} diff --git a/plugins/solidigm/solidigm-market-log.h b/plugins/solidigm/solidigm-market-log.h new file mode 100644 index 0000000000..6f808c4ed3 --- /dev/null +++ b/plugins/solidigm/solidigm-market-log.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: hardeep.dhillon@solidigm.com + */ + +int sldgm_get_market_log(int argc, char **argv, struct command *cmd, struct plugin *plugin); diff --git a/plugins/solidigm/solidigm-nvme.c b/plugins/solidigm/solidigm-nvme.c index 3eb3cc9139..3fb86f5299 100644 --- a/plugins/solidigm/solidigm-nvme.c +++ b/plugins/solidigm/solidigm-nvme.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2022 Solidigm. + * Copyright (c) 2022-2023 Solidigm. * * Author: leonardo.da.cunha@solidigm.com */ @@ -10,15 +10,37 @@ #define CREATE_CMD #include "solidigm-nvme.h" +#include "solidigm-id-ctrl.h" #include "solidigm-smart.h" +#include "solidigm-internal-logs.h" #include "solidigm-garbage-collection.h" #include "solidigm-latency-tracking.h" +#include "solidigm-telemetry.h" +#include "solidigm-log-page-dir.h" +#include "solidigm-market-log.h" +#include "solidigm-temp-stats.h" +#include "solidigm-get-drive-info.h" +#include "solidigm-ocp-version.h" + +#include "plugins/ocp/ocp-clear-features.h" +#include "plugins/ocp/ocp-smart-extended-log.h" +#include "plugins/ocp/ocp-fw-activation-history.h" + +static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + return __id_ctrl(argc, argv, cmd, plugin, sldgm_id_ctrl); +} static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { return solidigm_get_additional_smart_log(argc, argv, cmd, plugin); } +static int get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + return solidigm_get_internal_log(argc, argv, cmd, plugin); +} + static int get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { return solidigm_get_garbage_collection_log(argc, argv, cmd, plugin); @@ -27,4 +49,61 @@ static int get_garbage_collection_log(int argc, char **argv, struct command *cmd static int get_latency_tracking_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { return solidigm_get_latency_tracking_log(argc, argv, cmd, plugin); -} \ No newline at end of file +} + +static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + return solidigm_get_telemetry_log(argc, argv, cmd, plugin); +} + +static int clear_fw_update_history(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_clear_fw_update_history(argc, argv, cmd, plugin); +} + +static int clear_pcie_correctable_error_counters(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_clear_pcie_correctable_errors(argc, argv, cmd, plugin); +} + +static int smart_cloud(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_smart_add_log(argc, argv, cmd, plugin); +} + +static int fw_activation_history(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return ocp_fw_activation_history_log(argc, argv, cmd, plugin); +} + +static int get_log_page_directory_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return solidigm_get_log_page_directory_log(argc, argv, cmd, plugin); +} + +static int get_market_log(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return sldgm_get_market_log(argc, argv, cmd, plugin); +} + +static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + return sldgm_get_temp_stats_log(argc, argv, cmd, plugin); +} + +static int get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + return sldgm_get_drive_info(argc, argv, cmd, plugin); +} + +static int get_cloud_SSDplugin_version(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + return sldgm_ocp_version(argc, argv, cmd, plugin); +} diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h index 9fc8b4518e..bee8266bef 100644 --- a/plugins/solidigm/solidigm-nvme.h +++ b/plugins/solidigm/solidigm-nvme.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2022 Solidigm. + * Copyright (c) 2022-2023 Solidigm. * * Author: leonardo.da.cunha@solidigm.com */ @@ -13,13 +13,25 @@ #include "cmd.h" -#define SOLIDIGM_PLUGIN_VERSION "0.4" +#define SOLIDIGM_PLUGIN_VERSION "1.1" PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION), COMMAND_LIST( + ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log) + ENTRY("vs-smart-add-log", "Get SMART / health extended log (redirects to ocp plug-in)", smart_cloud) + ENTRY("vs-internal-log", "Retrieve Debug log binaries", get_internal_log) ENTRY("garbage-collect-log", "Retrieve Garbage Collection Log", get_garbage_collection_log) + ENTRY("market-log", "Retrieve Market Log", get_market_log) ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log) + ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log) + ENTRY("clear-pcie-correctable-errors ", "Clear PCIe Correctable Error Counters (redirects to ocp plug-in)", clear_pcie_correctable_error_counters) + ENTRY("clear-fw-activate-history", "Clear firmware update history log (redirects to ocp plug-in)", clear_fw_update_history) + ENTRY("vs-fw-activate-history", "Get firmware activation history log (redirects to ocp plug-in)", fw_activation_history) + ENTRY("log-page-directory", "Retrieve log page directory", get_log_page_directory_log) + ENTRY("temp-stats", "Retrieve Temperature Statistics log", get_temp_stats_log) + ENTRY("vs-drive-info", "Retrieve drive information", get_drive_info) + ENTRY("cloud-SSDplugin-version", "Prints plug-in OCP version", get_cloud_SSDplugin_version) ) ); diff --git a/plugins/solidigm/solidigm-ocp-version.c b/plugins/solidigm/solidigm-ocp-version.c new file mode 100644 index 0000000000..4048cc1bd3 --- /dev/null +++ b/plugins/solidigm/solidigm-ocp-version.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include +#include "nvme.h" + +int sldgm_ocp_version(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Prints OCP extensions version of Solidigm plugin"; + + OPT_ARGS(opts) = { + OPT_END() + }; + + int err = argconfig_parse(argc, argv, desc, opts); + + if (!err) + printf("1.0\n"); + + return err; +} diff --git a/plugins/solidigm/solidigm-ocp-version.h b/plugins/solidigm/solidigm-ocp-version.h new file mode 100644 index 0000000000..d79452cbcc --- /dev/null +++ b/plugins/solidigm/solidigm-ocp-version.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +int sldgm_ocp_version(int argc, char **argv, struct command *cmd, struct plugin *plugin); diff --git a/plugins/solidigm/solidigm-smart.c b/plugins/solidigm/solidigm-smart.c index 65340349a0..62245fa537 100644 --- a/plugins/solidigm/solidigm-smart.c +++ b/plugins/solidigm/solidigm-smart.c @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include "common.h" #include "nvme.h" @@ -21,33 +19,33 @@ #include "nvme-print.h" #include "solidigm-smart.h" +#include "solidigm-util.h" -struct __attribute__((packed)) nvme_additional_smart_log_item { +struct __packed nvme_additional_smart_log_item { __u8 id; __u8 _kp[2]; __u8 normalized; __u8 _np; - union __attribute__((packed)) { + union __packed { __u8 raw[6]; - struct __attribute__((packed)) wear_level { + struct __packed wear_level { __le16 min; __le16 max; __le16 avg; } wear_level; - struct __attribute__((packed)) thermal_throttle { + struct __packed thermal_throttle { __u8 pct; __u32 count; } thermal_throttle; - } ; + }; __u8 _rp; -} ; -typedef struct nvme_additional_smart_log_item smart_log_item_t; +}; #define VU_SMART_PAGE_SIZE 512 -#define VU_SMART_MAX_ITEMS VU_SMART_PAGE_SIZE / sizeof(smart_log_item_t) -typedef struct vu_smart_log { - smart_log_item_t item[VU_SMART_MAX_ITEMS]; -} vu_smart_log_t; +#define VU_SMART_MAX_ITEMS (VU_SMART_PAGE_SIZE / sizeof(struct nvme_additional_smart_log_item)) +struct vu_smart_log { + struct nvme_additional_smart_log_item item[VU_SMART_MAX_ITEMS]; +}; static char *id_to_name(__u8 id) { @@ -71,15 +69,17 @@ static char *id_to_name(__u8 id) case 0xE2: return "media_wear_percentage"; case 0xE3: - return "host_reads"; + return "timed_work_load_host_reads"; case 0xE4: - return "timed_work_load"; + return "timed_work_load_timer"; case 0xE5: return "read_commands_in_flight_counter"; case 0xE6: return "write_commands_in_flight_counter"; case 0xEA: return "thermal_throttle_status"; + case 0xEE: + return "re_sku_count"; case 0xF0: return "retry_buffer_overflow_counter"; case 0xF3: @@ -111,11 +111,10 @@ static char *id_to_name(__u8 id) } } -static void smart_log_item_print(smart_log_item_t *item) +static void smart_log_item_print(struct nvme_additional_smart_log_item *item) { - if (!item->id) { + if (!item->id) return; - } printf("%#x %-45s %3d ", item->id, id_to_name(item->id), item->normalized); @@ -137,13 +136,12 @@ static void smart_log_item_print(smart_log_item_t *item) } } -static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *dev_stats) +static void smart_log_item_add_json(struct nvme_additional_smart_log_item *item, struct json_object *dev_stats) { struct json_object *entry_stats = json_create_object(); - if (!item->id) { + if (!item->id) return; - } json_object_add_value_int(entry_stats, "normalized", item->normalized); @@ -163,15 +161,14 @@ static void smart_log_item_add_json(smart_log_item_t *item, struct json_object * json_object_add_value_object(dev_stats, id_to_name(item->id), entry_stats); } -static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, const char *devname) +static void vu_smart_log_show_json(struct vu_smart_log *payload, unsigned int nsid, const char *devname) { struct json_object *dev_stats = json_create_object(); - smart_log_item_t *item = payload->item; + struct nvme_additional_smart_log_item *item = payload->item; struct json_object *root; - for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) { + for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) smart_log_item_add_json(&item[i], dev_stats); - } root = json_create_object(); json_object_add_value_string(root, "Solidigm SMART log", devname); @@ -181,28 +178,29 @@ static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, c json_free_object(root); } -static void vu_smart_log_show(vu_smart_log_t *payload, unsigned int nsid, const char *devname) +static void vu_smart_log_show(struct vu_smart_log *payload, unsigned int nsid, const char *devname, + __u8 uuid_index) { - smart_log_item_t *item = payload->item; + struct nvme_additional_smart_log_item *item = payload->item; - printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", - devname, nsid); + printf("Additional Smart Log for NVMe device:%s namespace-id:%x UUID-idx:%d\n", + devname, nsid, uuid_index); printf("ID KEY Normalized Raw\n"); - for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) { + for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) smart_log_item_print(&item[i]); - } } int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Get Solidigm vendor specific smart log (optionally, "\ - "for the specified namespace), and show it."; + const char *desc = + "Get Solidigm vendor specific smart log (optionally, for the specified namespace), and show it."; const int solidigm_vu_smart_log_id = 0xCA; - vu_smart_log_t smart_log_payload; + struct vu_smart_log smart_log_payload; enum nvme_print_flags flags; struct nvme_dev *dev; int err; + __u8 uuid_index; struct config { __u32 namespace_id; @@ -224,29 +222,49 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd if (err) return err; - flags = validate_output_format(cfg.output_format); - if (flags == -EINVAL) { + err = validate_output_format(cfg.output_format, &flags); + if (err < 0) { fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format); dev_close(dev); - return flags; + return err; } - err = nvme_get_log_simple(dev_fd(dev), solidigm_vu_smart_log_id, - sizeof(smart_log_payload), &smart_log_payload); + uuid_index = solidigm_get_vu_uuid_index(dev); + + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = &smart_log_payload, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = solidigm_vu_smart_log_id, + .len = sizeof(smart_log_payload), + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = NVME_LOG_LSP_NONE, + .uuidx = uuid_index, + .rae = false, + .ot = false, + }; + + err = nvme_get_log(&args); if (!err) { - if (flags & JSON) { + if (flags & JSON) vu_smart_log_show_json(&smart_log_payload, cfg.namespace_id, dev->name); - } else if (flags & BINARY) { + else if (flags & BINARY) d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload)); - } else { + else vu_smart_log_show(&smart_log_payload, cfg.namespace_id, - dev->name); - } + dev->name, uuid_index); } else if (err > 0) { nvme_show_status(err); } + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); dev_close(dev); return err; } diff --git a/plugins/solidigm/solidigm-telemetry.c b/plugins/solidigm/solidigm-telemetry.c new file mode 100644 index 0000000000..2bebcccab9 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "nvme.h" +#include "libnvme.h" +#include "plugin.h" +#include "nvme-print.h" +#include "solidigm-telemetry.h" +#include "solidigm-telemetry/telemetry-log.h" +#include "solidigm-telemetry/cod.h" +#include "solidigm-telemetry/header.h" +#include "solidigm-telemetry/config.h" +#include "solidigm-telemetry/data-area.h" +#include "solidigm-util.h" + +static int read_file2buffer(char *file_name, char **buffer, size_t *length) +{ + FILE *fd = fopen(file_name, "rb"); + + if (!fd) + return errno; + + fseek(fd, 0, SEEK_END); + size_t length_bytes = ftell(fd); + + fseek(fd, 0, SEEK_SET); + + *buffer = malloc(length_bytes); + if (!*buffer) { + fclose(fd); + return errno; + } + *length = fread(*buffer, 1, length_bytes, fd); + fclose(fd); + return 0; +} + +struct config { + __u32 host_gen; + bool ctrl_init; + int data_area; + char *cfg_file; + bool is_input_file; +}; + +int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Parse Solidigm Telemetry log"; + const char *hgen = "Controls when to generate new host initiated report. Default value '1' generates new host initiated report, value '0' causes retrieval of existing log."; + const char *cgen = "Gather report generated by the controller."; + const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4."; + const char *cfile = "JSON configuration file"; + const char *sfile = "data source is binary file containing log dump instead of block or character device"; + struct nvme_dev *dev; + + struct telemetry_log tl = { + .root = json_create_object(), + .log = NULL, + }; + + struct config cfg = { + .host_gen = 1, + .ctrl_init = false, + .data_area = -1, + .cfg_file = NULL, + .is_input_file = false, + }; + + OPT_ARGS(opts) = { + OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen), + OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen), + OPT_UINT("data-area", 'd', &cfg.data_area, dgen), + OPT_FILE("config-file", 'j', &cfg.cfg_file, cfile), + OPT_FLAG("source-file", 's', &cfg.is_input_file, sfile), + OPT_END() + }; + + int err = argconfig_parse(argc, argv, desc, opts); + + if (err) + goto ret; + + /* When not selected on the command line, get minimum data area required */ + if (cfg.data_area == -1) + cfg.data_area = cfg.cfg_file ? 3 : 1; + + if (cfg.is_input_file) { + if (optind >= argc) { + err = errno = EINVAL; + perror(argv[0]); + goto ret; + } + char *binary_file_name = argv[optind]; + + err = read_file2buffer(binary_file_name, (char **)&tl.log, &tl.log_size); + } else { + err = parse_and_open(&dev, argc, argv, desc, opts); + } + if (err) + goto ret; + + if (cfg.host_gen > 1) { + SOLIDIGM_LOG_WARNING("Invalid host-generate value '%d'", cfg.host_gen); + err = EINVAL; + goto close_fd; + } + + if (cfg.cfg_file) { + char *conf_str = NULL; + size_t length = 0; + + err = read_file2buffer(cfg.cfg_file, &conf_str, &length); + if (err) { + SOLIDIGM_LOG_WARNING("Failed to open JSON configuration file %s: %s!", + cfg.cfg_file, strerror(err)); + goto close_fd; + } + struct json_tokener *jstok = json_tokener_new(); + + tl.configuration = json_tokener_parse_ex(jstok, conf_str, length); + free(conf_str); + if (jstok->err != json_tokener_success) { + SOLIDIGM_LOG_WARNING("Parsing error on JSON configuration file %s: %s (at offset %d)", + cfg.cfg_file, + json_tokener_error_desc(jstok->err), + jstok->char_offset); + json_tokener_free(jstok); + err = EINVAL; + goto close_fd; + } + json_tokener_free(jstok); + } + + if (!cfg.is_input_file) { + size_t max_data_tx; + + err = nvme_get_telemetry_max(dev_fd(dev), NULL, &max_data_tx); + if (err < 0) { + SOLIDIGM_LOG_WARNING("identify_ctrl: %s", + nvme_strerror(errno)); + goto close_fd; + } else if (err > 0) { + nvme_show_status(err); + SOLIDIGM_LOG_WARNING("Failed to acquire identify ctrl %d!", err); + goto close_fd; + } + if (max_data_tx > DRIVER_MAX_TX_256K) + max_data_tx = DRIVER_MAX_TX_256K; + + err = nvme_get_telemetry_log(dev_fd(dev), cfg.host_gen, cfg.ctrl_init, true, + max_data_tx, cfg.data_area, &tl.log, &tl.log_size); + if (err < 0) { + SOLIDIGM_LOG_WARNING("get-telemetry-log: %s", + nvme_strerror(errno)); + goto close_fd; + } else if (err > 0) { + nvme_show_status(err); + SOLIDIGM_LOG_WARNING("Failed to acquire telemetry log %d!", err); + goto close_fd; + } + } + solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area); + + json_print_object(tl.root, NULL); + json_free_object(tl.root); + printf("\n"); + +close_fd: + if (!cfg.is_input_file) { + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); + dev_close(dev); + } +ret: + json_free_object(tl.configuration); + free(tl.log); + return err; +} diff --git a/plugins/solidigm/solidigm-telemetry.h b/plugins/solidigm/solidigm-telemetry.h new file mode 100644 index 0000000000..971ee2acb0 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry.h @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin); diff --git a/plugins/solidigm/solidigm-telemetry/cod.c b/plugins/solidigm/solidigm-telemetry/cod.c new file mode 100644 index 0000000000..363822a556 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/cod.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ +#include "common.h" +#include "cod.h" + +const char *oemDataMapDesc[] = { + "Media Read Count", //Uid 0x00 + "Host Read count", //Uid 0x01 + "Media Write Count", //Uid 0x02 + "Host Write Count", //Uid 0x03 + "Device Model", // 0x04 + "Serial Number", // 0x05 + "Firmware Revision", // 0x06 + "Drive Status", // 0x07 + "Minimum Temperature", // 0x08 + "Maximum Temperature", // 0x09 + "Power Loss Protection Status", // 0x0a + "Lifetime Unsafe Shutdown Count", // 0x0b + "Lifetime Power Cycle Count", // 0x0c + "Minimum Read Latency", // 0x0d + "Maximum Read Latency", // 0x0e + "Average Read Latency", // 0x0f + "Minimum Write Latency", // 0x10 + "Maximum Write Latency", // 0x11 + "Average Write Latency", // 0x12 + "Grown Defects Count", // 0x13 + "DQS Recovery Count", // 0x14 + "Program Fail Count", // 0x15 + "Erase Fail Count", // 0x16 + "Defrag Writes in Progress Count", // 0x17 + "Total Defrag Writes Count", // 0x18 + "Max Die Offline Number", // 0x19 + "Current Die Offline Number", // 0x1A + "XOR Enable Status", // 0x1B + "Media Life Used", // 0x1C + "Uncorrectable Error Count", // 0x1D + "Current Wear Range Delta", // 0x1E + "Read Errors Corrected by XOR", // 0x1F + "Background Data Refresh", // 0x20 + "Pmic Vin History Data 1 Min", // 0x21 + "Pmic Vin History Data 1 Max", // 0x22 + "Pmic Vin History Data 1 Avg", // 0x23 + "Pmic Vin History Data 2 Min", // 0x24 + "Pmic Vin History Data 2 Max", // 0x25 + "Pmic Vin History Data 2 Avg", // 0x26 + "Pmic Vin History Data Total Readings", // 0x27 + "All Time Current Max Wear Level", // 0x28 + "Media Wear Remaining", // 0x29 + "Total Non-Defrag Writes", // 0x2A + "Media Health Relocations" //Uid 0x2B = 43 +}; + +static const char *getOemDataMapDescription(uint32_t id) +{ + if (id < ARRAY_SIZE(oemDataMapDesc)) + return oemDataMapDesc[id]; + return "unknown"; +} + +#define OEMSIGNATURE 0x504D4443 + +#pragma pack(push, cod, 1) +struct cod_header { + uint32_t versionMajor; + uint32_t versionMinor; + uint32_t Signature; //!Fixed signature value (0x504D4443) for identification and validation + uint32_t MapSizeInBytes; //!Total size of the map data structure in bytes + uint32_t EntryCount; //!Total number of entries in the entry list + uint8_t Reserved[12]; +}; + +struct cod_item { + uint32_t DataFieldMapUid; //!The data field unique identifier value + uint32_t reserved1 : 8; + uint32_t dataFieldType : 8; + uint32_t issigned : 1; + uint32_t bigEndian : 1; + uint32_t dataInvalid : 1; + uint32_t reserved2 : 13; + uint32_t DataFieldSizeInBytes; + uint8_t Reserved1[4]; + uint64_t DataFieldOffset; + uint8_t Reserved2[8]; +}; + +struct cod_map { + struct cod_header header; + struct cod_item items[]; +}; + +#pragma pack(pop, cod) + +void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl) +{ + enum cod_field_type { + INTEGER, + FLOAT, + STRING, + TWO_BYTE_ASCII, + FOUR_BYTE_ASCII, + + UNKNOWN = 0xFF, + }; + struct json_object *telemetry_header = NULL; + struct json_object *COD_offset = NULL; + struct json_object *reason_id = NULL; + + if (!json_object_object_get_ex(tl->root, "telemetryHeader", &telemetry_header)) + return; + if (!json_object_object_get_ex(telemetry_header, "reasonIdentifier", &reason_id)) + return; + if (!json_object_object_get_ex(reason_id, "oemDataMapOffset", &COD_offset)) + return; + + uint64_t offset = json_object_get_int(COD_offset); + + if (!offset) + return; + + if ((offset + sizeof(struct cod_header)) > tl->log_size) { + SOLIDIGM_LOG_WARNING("Warning: COD map header out of bounds."); + return; + } + + const struct cod_map *data = (struct cod_map *) (((uint8_t *)tl->log) + offset); + + uint32_t signature = be32_to_cpu(data->header.Signature); + + if (signature != OEMSIGNATURE) { + SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature); + return; + } + if ((offset + data->header.MapSizeInBytes) > tl->log_size) { + SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds."); + return; + } + + struct json_object *cod = json_create_object(); + + json_object_object_add(tl->root, "cod", cod); + + for (uint64_t i = 0; i < data->header.EntryCount; i++) { + if ((offset + sizeof(struct cod_header) + (i + 1) * sizeof(struct cod_item)) > + tl->log_size) { + SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %"PRIu64"!", + i); + return; + } + struct cod_item item = data->items[i]; + + if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size) + continue; + if (item.dataInvalid) + continue; + uint8_t *val = ((uint8_t *)tl->log) + item.DataFieldOffset; + const char *key = getOemDataMapDescription(item.DataFieldMapUid); + + switch (item.dataFieldType) { + case INTEGER: + if (item.issigned) + json_object_object_add(cod, key, + json_object_new_int64(le64_to_cpu(*(uint64_t *)val))); + else + json_object_add_value_uint64(cod, key, le64_to_cpu(*(uint64_t *)val)); + break; + case FLOAT: + json_object_add_value_float(cod, key, *(float *)val); + break; + case STRING: + json_object_object_add(cod, key, + json_object_new_string_len((const char *)val, item.DataFieldSizeInBytes)); + break; + case TWO_BYTE_ASCII: + json_object_object_add(cod, key, + json_object_new_string_len((const char *)val, 2)); + break; + case FOUR_BYTE_ASCII: + json_object_object_add(cod, key, + json_object_new_string_len((const char *)val, 4)); + break; + default: + SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid); + break; + } + } +} diff --git a/plugins/solidigm/solidigm-telemetry/cod.h b/plugins/solidigm/solidigm-telemetry/cod.h new file mode 100644 index 0000000000..032ccdcd51 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/cod.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "telemetry-log.h" +void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl); diff --git a/plugins/solidigm/solidigm-telemetry/config.c b/plugins/solidigm/solidigm-telemetry/config.c new file mode 100644 index 0000000000..eceeede5d2 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/config.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include +#include +#include "config.h" + +// max 16 bit unsigned integer number 65535 +#define MAX_16BIT_NUM_AS_STRING_SIZE 6 + +#define OBJ_NAME_PREFIX "UID_" +#define NLOG_OBJ_PREFIX OBJ_NAME_PREFIX "NLOG_" + +static bool config_get_by_version(const struct json_object *obj, int version_major, + int version_minor, struct json_object **value) +{ + char str_key[MAX_16BIT_NUM_AS_STRING_SIZE]; + char str_subkey[MAX_16BIT_NUM_AS_STRING_SIZE]; + + snprintf(str_key, sizeof(str_key), "%d", version_major); + snprintf(str_subkey, sizeof(str_subkey), "%d", version_minor); + struct json_object *major_obj = NULL; + + if (!json_object_object_get_ex(obj, str_key, &major_obj)) + return false; + if (!json_object_object_get_ex(major_obj, str_subkey, value)) + return false; + return value != NULL; +} + +bool solidigm_config_get_struct_by_token_version(const struct json_object *config, int token_id, + int version_major, int version_minor, + struct json_object **value) +{ + struct json_object *token = NULL; + char str_key[MAX_16BIT_NUM_AS_STRING_SIZE]; + + snprintf(str_key, sizeof(str_key), "%d", token_id); + if (!json_object_object_get_ex(config, str_key, &token)) + return false; + if (!config_get_by_version(token, version_major, version_minor, value)) + return false; + return value != NULL; +} + +const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token) +{ + struct json_object *nlog_names = NULL; + struct json_object *obj_name; + char hex_header[STR_HEX32_SIZE]; + const char *name; + + if (!json_object_object_get_ex(config, "TELEMETRY_OBJECT_UIDS", &nlog_names)) + return NULL; + snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", token); + + if (!json_object_object_get_ex(nlog_names, hex_header, &obj_name)) + return NULL; + name = json_object_get_string(obj_name); + if (strncmp(NLOG_OBJ_PREFIX, name, strlen(NLOG_OBJ_PREFIX))) + return NULL; + + return &name[strlen(OBJ_NAME_PREFIX)]; +} + +struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config) +{ + struct json_object *nlog_formats = NULL; + + json_object_object_get_ex(config, "NLOG_FORMATS", &nlog_formats); + return nlog_formats; +} diff --git a/plugins/solidigm/solidigm-telemetry/config.h b/plugins/solidigm/solidigm-telemetry/config.h new file mode 100644 index 0000000000..4e56ba3b5c --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/config.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ +#include +#include "util/json.h" + +#define STR_HEX32_SIZE sizeof("0x00000000") + +bool solidigm_config_get_struct_by_token_version(const struct json_object *obj, + int key, int subkey, + int subsubkey, + struct json_object **value); + +const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token); +struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config); + diff --git a/plugins/solidigm/solidigm-telemetry/data-area.c b/plugins/solidigm/solidigm-telemetry/data-area.c new file mode 100644 index 0000000000..14d612bcf2 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/data-area.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "common.h" +#include "header.h" +#include "cod.h" +#include "data-area.h" +#include "config.h" +#include "nlog.h" +#include + +#define SIGNED_INT_PREFIX "int" +#define BITS_IN_BYTE 8 + +#define MAX_WARNING_SIZE 1024 +#define MAX_ARRAY_RANK 16 + +static bool telemetry_log_get_value(const struct telemetry_log *tl, + uint64_t offset_bit, uint32_t size_bit, + bool is_signed, struct json_object **val_obj) +{ + uint32_t offset_bit_from_byte; + uint32_t additional_size_byte; + uint32_t offset_byte; + uint64_t val; + + if (!size_bit) { + char err_msg[MAX_WARNING_SIZE]; + + snprintf(err_msg, MAX_WARNING_SIZE, + "Value with size_bit=0 not supported."); + *val_obj = json_object_new_string(err_msg); + + return false; + } + additional_size_byte = (size_bit - 1) ? (size_bit - 1) / BITS_IN_BYTE : 0; + offset_byte = (uint32_t)offset_bit / BITS_IN_BYTE; + + if (offset_byte > (tl->log_size - additional_size_byte)) { + char err_msg[MAX_WARNING_SIZE]; + + snprintf(err_msg, MAX_WARNING_SIZE, + "Value offset greater than binary size (%u > %zu).", + offset_byte, tl->log_size); + *val_obj = json_object_new_string(err_msg); + + return false; + } + + offset_bit_from_byte = (uint32_t) (offset_bit - ((uint64_t)offset_byte * BITS_IN_BYTE)); + + if ((size_bit + offset_bit_from_byte) > (sizeof(uint64_t) * BITS_IN_BYTE)) { + char err_msg[MAX_WARNING_SIZE]; + + snprintf(err_msg, MAX_WARNING_SIZE, + "Value crossing 64 bit, byte aligned boundary, not supported. size_bit=%u, offset_bit_from_byte=%u.", + size_bit, offset_bit_from_byte); + *val_obj = json_object_new_string(err_msg); + + return false; + } + + val = *(uint64_t *)(((char *)tl->log) + offset_byte); + val >>= offset_bit_from_byte; + if (size_bit < 64) + val &= (1ULL << size_bit) - 1; + if (is_signed) { + if (val >> (size_bit - 1)) + val |= (0ULL - 1) << size_bit; + *val_obj = json_object_new_int64(val); + } else { + *val_obj = json_object_new_uint64(val); + } + + return true; +} + +static int telemetry_log_structure_parse(const struct telemetry_log *tl, + struct json_object *struct_def, + uint64_t parent_offset_bit, + struct json_object *output, + struct json_object *metadata) +{ + struct json_object *obj_arraySizeArray = NULL; + struct json_object *obj = NULL; + struct json_object *obj_memberList; + struct json_object *major_dimension = NULL; + struct json_object *sub_output; + bool is_enumeration = false; + bool has_member_list; + const char *type = ""; + const char *name; + size_t array_rank; + uint64_t offset_bit; + uint32_t size_bit; + uint64_t linear_array_pos_bit; + uint32_t array_size_dimension[MAX_ARRAY_RANK]; + + if (!json_object_object_get_ex(struct_def, "name", &obj)) { + SOLIDIGM_LOG_WARNING("Warning: Structure definition missing property 'name': %s", + json_object_to_json_string(struct_def)); + return -1; + } + + name = json_object_get_string(obj); + + if (metadata) { + json_object_get(obj); + json_object_object_add(metadata, "objName", obj); + } + + if (json_object_object_get_ex(struct_def, "type", &obj)) + type = json_object_get_string(obj); + + if (!json_object_object_get_ex(struct_def, "offsetBit", &obj)) { + SOLIDIGM_LOG_WARNING( + "Warning: Structure definition missing property 'offsetBit': %s", + json_object_to_json_string(struct_def)); + return -1; + } + + offset_bit = json_object_get_uint64(obj); + + if (!json_object_object_get_ex(struct_def, "sizeBit", &obj)) { + SOLIDIGM_LOG_WARNING( + "Warning: Structure definition missing property 'sizeBit': %s", + json_object_to_json_string(struct_def)); + return -1; + } + + size_bit = (uint32_t)json_object_get_uint64(obj); + + if (json_object_object_get_ex(struct_def, "enum", &obj)) + is_enumeration = json_object_get_boolean(obj); + + has_member_list = json_object_object_get_ex(struct_def, + "memberList", + &obj_memberList); + + if (!json_object_object_get_ex(struct_def, "arraySize", + &obj_arraySizeArray)) { + SOLIDIGM_LOG_WARNING( + "Warning: Structure definition missing property 'arraySize': %s", + json_object_to_json_string(struct_def)); + return -1; + } + + array_rank = json_object_array_length(obj_arraySizeArray); + if (!array_rank) { + SOLIDIGM_LOG_WARNING( + "Warning: Structure property 'arraySize' don't support flexible array: %s", + json_object_to_json_string(struct_def)); + return -1; + } + if (array_rank > MAX_ARRAY_RANK) { + SOLIDIGM_LOG_WARNING( + "Warning: Structure property 'arraySize' don't support more than %d dimensions: %s", + MAX_ARRAY_RANK, json_object_to_json_string(struct_def)); + return -1; + } + + for (size_t i = 0; i < array_rank; i++) { + struct json_object *dimension = json_object_array_get_idx(obj_arraySizeArray, i); + + array_size_dimension[i] = json_object_get_int(dimension); + major_dimension = dimension; + } + if (array_rank > 1) { + uint32_t linear_pos_per_index = array_size_dimension[0]; + uint32_t prev_index_offset_bit = 0; + struct json_object *dimension_output; + + for (unsigned int i = 1; i < (array_rank - 1); i++) + linear_pos_per_index *= array_size_dimension[i]; + + dimension_output = json_create_array(); + if (json_object_get_type(output) == json_type_array) + json_object_array_add(output, dimension_output); + else + json_object_add_value_array(output, name, dimension_output); + + /* + * Make sure major_dimension object will not be + * deleted from memory when deleted from array + */ + json_object_get(major_dimension); + json_object_array_del_idx(obj_arraySizeArray, array_rank - 1, 1); + + for (unsigned int i = 0 ; i < array_size_dimension[0]; i++) { + struct json_object *sub_array = json_create_array(); + uint64_t offset; + + offset = parent_offset_bit + prev_index_offset_bit; + + json_object_array_add(dimension_output, sub_array); + telemetry_log_structure_parse(tl, struct_def, + offset, sub_array, NULL); + prev_index_offset_bit += linear_pos_per_index * size_bit; + } + + json_object_array_put_idx(obj_arraySizeArray, array_rank - 1, + major_dimension); + + return 0; + } + + linear_array_pos_bit = 0; + sub_output = output; + + if (array_size_dimension[0] > 1) { + sub_output = json_create_array(); + if (json_object_get_type(output) == json_type_array) + json_object_array_add(output, sub_output); + else + json_object_add_value_array(output, name, sub_output); + } + + for (uint32_t j = 0; j < array_size_dimension[0]; j++) { + if (is_enumeration || !has_member_list) { + bool is_signed = !strncmp(type, SIGNED_INT_PREFIX, sizeof(SIGNED_INT_PREFIX)-1); + struct json_object *val_obj; + uint64_t offset; + + offset = parent_offset_bit + offset_bit + linear_array_pos_bit; + if (telemetry_log_get_value(tl, offset, size_bit, is_signed, &val_obj)) { + if (array_size_dimension[0] > 1) + json_object_array_put_idx(sub_output, j, val_obj); + else + json_object_object_add(sub_output, name, val_obj); + } else { + SOLIDIGM_LOG_WARNING( + "Warning: %s From property '%s', array index %u, structure definition: %s", + json_object_get_string(val_obj), name, j, + json_object_to_json_string(struct_def)); + json_free_object(val_obj); + } + } else { + struct json_object *sub_sub_output = json_create_object(); + int num_members; + + if (array_size_dimension[0] > 1) + json_object_array_put_idx(sub_output, j, sub_sub_output); + else + json_object_add_value_object(sub_output, name, sub_sub_output); + + num_members = json_object_array_length(obj_memberList); + for (int k = 0; k < num_members; k++) { + struct json_object *member = json_object_array_get_idx(obj_memberList, k); + uint64_t offset; + + offset = parent_offset_bit + offset_bit + linear_array_pos_bit; + telemetry_log_structure_parse(tl, member, offset, + sub_sub_output, NULL); + } + } + linear_array_pos_bit += size_bit; + } + return 0; +} + +static int telemetry_log_data_area_get_offset(const struct telemetry_log *tl, + enum nvme_telemetry_da da, + uint32_t *offset, uint32_t *size) +{ + uint32_t offset_blocks = 1; + uint32_t last_block = tl->log->dalb1; + uint32_t last; + + switch (da) { + case NVME_TELEMETRY_DA_1: + offset_blocks = 1; + last_block = tl->log->dalb1; + break; + case NVME_TELEMETRY_DA_2: + offset_blocks = tl->log->dalb1 + 1; + last_block = tl->log->dalb2; + break; + case NVME_TELEMETRY_DA_3: + offset_blocks = tl->log->dalb2 + 1; + last_block = tl->log->dalb3; + break; + case NVME_TELEMETRY_DA_4: + offset_blocks = tl->log->dalb3 + 1; + last_block = tl->log->dalb4; + break; + default: + return -1; + } + + *offset = offset_blocks * NVME_LOG_TELEM_BLOCK_SIZE; + last = (last_block + 1) * NVME_LOG_TELEM_BLOCK_SIZE; + *size = last - *offset; + if ((*offset > tl->log_size) || (last > tl->log_size) || (last <= *offset)) { + SOLIDIGM_LOG_WARNING("Warning: Data Area %d don't fit this Telemetry log.", da); + return -1; + } + + return 0; +} + +static int telemetry_log_nlog_parse(const struct telemetry_log *tl, struct json_object *formats, + uint64_t nlog_file_offset, uint64_t nlog_size, + struct json_object *output, struct json_object *metadata) +{ + /* boundary check */ + if (tl->log_size < (nlog_file_offset + nlog_size)) { + const char *name = ""; + int media_bank = -1; + struct json_object *jobj; + + if (json_object_object_get_ex(metadata, "objName", &jobj)) + name = json_object_get_string(jobj); + if (json_object_object_get_ex(metadata, "mediaBankId", &jobj)) + media_bank = json_object_get_int(jobj); + SOLIDIGM_LOG_WARNING("%s:%d do not fit this log dump.", name, media_bank); + return -1; + } + return solidigm_nlog_parse(((char *) tl->log) + nlog_file_offset, + nlog_size, formats, metadata, output); +} + +struct toc_item { + uint32_t OffsetBytes; + uint32_t ContentSizeBytes; +}; + +struct data_area_header { + uint8_t versionMajor; + uint8_t versionMinor; + uint16_t TableOfContentsCount; + uint32_t DataAreaSize; + uint8_t Reserved[8]; +}; + +struct table_of_contents { + struct data_area_header header; + struct toc_item items[]; +}; + +struct telemetry_object_header { + uint16_t versionMajor; + uint16_t versionMinor; + uint32_t Token; + uint8_t CoreId; + uint8_t Reserved[3]; +}; + +static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl, + enum nvme_telemetry_da da, + struct json_object *toc_array, + struct json_object *tele_obj_array) +{ + + const struct telemetry_object_header *header; + const struct table_of_contents *toc; + char *payload; + uint32_t da_offset; + uint32_t da_size; + struct json_object *nlog_formats; + + if (telemetry_log_data_area_get_offset(tl, da, &da_offset, &da_size)) + return; + + toc = (struct table_of_contents *)(((char *)tl->log) + da_offset); + payload = (char *) tl->log; + nlog_formats = solidigm_config_get_nlog_formats(tl->configuration); + + for (int i = 0; i < toc->header.TableOfContentsCount; i++) { + struct json_object *structure_definition = NULL; + struct json_object *toc_item; + uint32_t obj_offset; + bool has_struct; + const char *nlog_name = NULL; + uint32_t header_offset = sizeof(const struct telemetry_object_header); + + if ((char *)&toc->items[i] > + (((char *)toc) + da_size - sizeof(const struct toc_item))) { + SOLIDIGM_LOG_WARNING( + "Warning: Data Area %d, Table of Contents item %d crossed Data Area size.", + da, i); + return; + } + + obj_offset = toc->items[i].OffsetBytes; + if ((obj_offset + sizeof(const struct telemetry_object_header)) > da_size) { + SOLIDIGM_LOG_WARNING( + "Warning: Data Area %d, item %d data, crossed Data Area size.", da, i); + continue; + } + + toc_item = json_create_object(); + json_object_array_add(toc_array, toc_item); + json_object_add_value_uint(toc_item, "dataArea", da); + json_object_add_value_uint(toc_item, "dataAreaIndex", i); + json_object_add_value_uint(toc_item, "dataAreaOffset", obj_offset); + json_object_add_value_uint(toc_item, "fileOffset", obj_offset + da_offset); + json_object_add_value_uint(toc_item, "size", toc->items[i].ContentSizeBytes); + + header = (const struct telemetry_object_header *) (payload + da_offset + obj_offset); + json_object_add_value_uint(toc_item, "telemMajor", header->versionMajor); + json_object_add_value_uint(toc_item, "telemMinor", header->versionMinor); + json_object_add_value_uint(toc_item, "objectId", header->Token); + json_object_add_value_uint(toc_item, "mediaBankId", header->CoreId); + + has_struct = solidigm_config_get_struct_by_token_version(tl->configuration, + header->Token, + header->versionMajor, + header->versionMinor, + &structure_definition); + if (!has_struct) { + if (!nlog_formats) + continue; + nlog_name = solidigm_config_get_nlog_obj_name(tl->configuration, + header->Token); + if (!nlog_name) + continue; + } + struct json_object *tele_obj_item = json_create_object(); + + json_object_array_add(tele_obj_array, tele_obj_item); + json_object_get(toc_item); + json_object_add_value_object(tele_obj_item, "metadata", toc_item); + struct json_object *parsed_struct = json_create_object(); + + json_object_add_value_object(tele_obj_item, "objectData", parsed_struct); + struct json_object *obj_hasTelemObjHdr = NULL; + uint64_t object_file_offset; + + if (json_object_object_get_ex(structure_definition, + "hasTelemObjHdr", + &obj_hasTelemObjHdr)) { + bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr); + + if (hasHeader) + header_offset = 0; + } + object_file_offset = ((uint64_t)da_offset) + obj_offset + header_offset; + if (has_struct) { + telemetry_log_structure_parse(tl, structure_definition, + BITS_IN_BYTE * object_file_offset, + parsed_struct, toc_item); + } else if (nlog_formats) { + json_object_object_add(toc_item, "objName", + json_object_new_string(nlog_name)); + telemetry_log_nlog_parse(tl, nlog_formats, object_file_offset, + toc->items[i].ContentSizeBytes - header_offset, + parsed_struct, toc_item); + } + } +} + +int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl, + enum nvme_telemetry_da last_da) +{ + struct json_object *tele_obj_array = json_create_array(); + struct json_object *toc_array = json_create_array(); + + solidigm_telemetry_log_header_parse(tl); + solidigm_telemetry_log_cod_parse(tl); + if (tl->configuration) { + json_object_add_value_array(tl->root, "tableOfContents", toc_array); + json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array); + + for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++) + telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array); + } + return 0; +} diff --git a/plugins/solidigm/solidigm-telemetry/data-area.h b/plugins/solidigm/solidigm-telemetry/data-area.h new file mode 100644 index 0000000000..6b690d880e --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/data-area.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ +#include "telemetry-log.h" + +int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl, + enum nvme_telemetry_da last_da); diff --git a/plugins/solidigm/solidigm-telemetry/header.c b/plugins/solidigm/solidigm-telemetry/header.c new file mode 100644 index 0000000000..866ebfff58 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/header.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "common.h" +#include "header.h" + +#pragma pack(push, reason_indentifier, 1) +struct reason_indentifier_1_0 { + uint16_t versionMajor; + uint16_t versionMinor; + uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue. + char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020") + char FirmwareVersion[12]; //! Similar to IdentifyController.FR + char BootloaderVersion[12]; //! Bootloader version string + char SerialNumber[20]; //! Device serial number + uint8_t Reserved[56]; //! Reserved for future usage +}; +static_assert(sizeof(const struct reason_indentifier_1_0) == + MEMBER_SIZE(struct nvme_telemetry_log, rsnident), + "Size mismatch for reason_indentifier_1_0"); + +struct reason_indentifier_1_1 { + uint16_t versionMajor; + uint16_t versionMinor; + uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue. + char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020") + char FirmwareVersion[12]; //! Similar to IdentifyController.FR + char BootloaderVersion[12]; //! Bootloader version string + char SerialNumber[20]; //! Device serial number + uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset + uint8_t TelemetryMajorVersion; //! Shadow of version in TOC + uint8_t TelemetryMinorVersion; //! Shadow of version in TOC + uint8_t Reserved[46]; //! Reserved for future usage +}; +static_assert(sizeof(const struct reason_indentifier_1_1) == + MEMBER_SIZE(struct nvme_telemetry_log, rsnident), + "Size mismatch for reason_indentifier_1_1"); + +struct reason_indentifier_1_2 { + uint16_t versionMajor; + uint16_t versionMinor; + uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue. + char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020") + uint8_t Reserved1[24]; //! pad over Fields removed from version 1.1 + char SerialNumber[20]; //! Device serial number + uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset + uint8_t TelemetryMajorVersion; //! Shadow of version in TOC + uint8_t TelemetryMinorVersion; //! Shadow of version in TOC + uint8_t ProductFamilyId; + uint8_t Reserved2[5]; //! Reserved for future usage + uint8_t DualPortReserved[40]; //! Reserved for dual port +}; +static_assert(sizeof(const struct reason_indentifier_1_2) == + MEMBER_SIZE(struct nvme_telemetry_log, rsnident), + "Size mismatch for reason_indentifier_1_2"); +#pragma pack(pop, reason_indentifier) + +static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl, + struct json_object *reason_id) +{ + const struct reason_indentifier_1_0 *ri; + struct json_object *reserved; + + ri = (struct reason_indentifier_1_0 *) tl->log->rsnident; + json_object_object_add(reason_id, "firmwareVersion", + json_object_new_string_len(ri->FirmwareVersion, + sizeof(ri->FirmwareVersion))); + json_object_object_add(reason_id, "bootloaderVersion", + json_object_new_string_len(ri->BootloaderVersion, + sizeof(ri->BootloaderVersion))); + json_object_object_add(reason_id, "serialNumber", + json_object_new_string_len(ri->SerialNumber, + sizeof(ri->SerialNumber))); + + reserved = json_create_array(); + json_object_add_value_array(reason_id, "reserved", reserved); + for (int i = 0; i < sizeof(ri->Reserved); i++) { + struct json_object *val = json_object_new_int(ri->Reserved[i]); + + json_object_array_add(reserved, val); + } +} + +static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl, + struct json_object *reason_id) +{ + const struct reason_indentifier_1_1 *ri; + struct json_object *reserved; + + ri = (struct reason_indentifier_1_1 *) tl->log->rsnident; + json_object_object_add(reason_id, "firmwareVersion", + json_object_new_string_len(ri->FirmwareVersion, + sizeof(ri->FirmwareVersion))); + json_object_object_add(reason_id, "bootloaderVersion", + json_object_new_string_len(ri->BootloaderVersion, + sizeof(ri->BootloaderVersion))); + json_object_object_add(reason_id, "serialNumber", + json_object_new_string_len(ri->SerialNumber, + sizeof(ri->SerialNumber))); + json_object_add_value_uint64(reason_id, "oemDataMapOffset", + le64_to_cpu(ri->OemDataMapOffset)); + json_object_add_value_uint(reason_id, "telemetryMajorVersion", + le16_to_cpu(ri->TelemetryMajorVersion)); + json_object_add_value_uint(reason_id, "telemetryMinorVersion", + le16_to_cpu(ri->TelemetryMinorVersion)); + + reserved = json_create_array(); + json_object_add_value_array(reason_id, "reserved", reserved); + for (int i = 0; i < sizeof(ri->Reserved); i++) { + struct json_object *val = json_object_new_int(ri->Reserved[i]); + + json_object_array_add(reserved, val); + } +} + +static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl, + struct json_object *reason_id) +{ + const struct reason_indentifier_1_2 *ri; + struct json_object *dp_reserved; + struct json_object *reserved; + + ri = (struct reason_indentifier_1_2 *) tl->log->rsnident; + + json_object_object_add(reason_id, "serialNumber", + json_object_new_string_len(ri->SerialNumber, + sizeof(ri->SerialNumber))); + json_object_add_value_uint64(reason_id, "oemDataMapOffset", + le64_to_cpu(ri->OemDataMapOffset)); + json_object_add_value_uint(reason_id, "telemetryMajorVersion", + le16_to_cpu(ri->TelemetryMajorVersion)); + json_object_add_value_uint(reason_id, "telemetryMinorVersion", + le16_to_cpu(ri->TelemetryMinorVersion)); + json_object_add_value_uint(reason_id, "productFamilyId", ri->ProductFamilyId); + + reserved = json_create_array(); + json_object_add_value_array(reason_id, "reserved2", reserved); + for (int i = 0; i < sizeof(ri->Reserved2); i++) { + struct json_object *val = json_object_new_int(ri->Reserved2[i]); + + json_object_array_add(reserved, val); + } + + dp_reserved = json_create_array(); + json_object_add_value_array(reason_id, "dualPortReserved", dp_reserved); + for (int i = 0; i < sizeof(ri->DualPortReserved); i++) { + struct json_object *val = json_object_new_int(ri->DualPortReserved[i]); + + json_object_array_add(dp_reserved, val); + } +} + +static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *tl, struct json_object *reason_id) +{ + const struct reason_indentifier_1_0 *ri1_0 = + (struct reason_indentifier_1_0 *) tl->log->rsnident; + uint16_t version_major = le16_to_cpu(ri1_0->versionMajor); + uint16_t version_minor = le16_to_cpu(ri1_0->versionMinor); + + json_object_add_value_uint(reason_id, "versionMajor", version_major); + json_object_add_value_uint(reason_id, "versionMinor", version_minor); + json_object_add_value_uint(reason_id, "reasonCode", le32_to_cpu(ri1_0->reasonCode)); + json_object_add_value_object(reason_id, "driveStatus", + json_object_new_string_len(ri1_0->DriveStatus, + sizeof(ri1_0->DriveStatus))); + if (version_major == 1) { + switch (version_minor) { + case 0: + telemetry_log_reason_id_parse1_0_ext(tl, reason_id); + break; + case 1: + telemetry_log_reason_id_parse1_1_ext(tl, reason_id); + break; + default: + telemetry_log_reason_id_parse1_2_ext(tl, reason_id); + break; + } + } +} + +bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl) +{ + const struct nvme_telemetry_log *log; + struct json_object *ieee_oui_id; + struct json_object *reason_id; + struct json_object *header; + + if (tl->log_size < sizeof(const struct nvme_telemetry_log)) { + SOLIDIGM_LOG_WARNING("Telemetry log too short."); + return false; + } + + header = json_create_object(); + + json_object_object_add(tl->root, "telemetryHeader", header); + log = tl->log; + + json_object_add_value_uint(header, "logIdentifier", log->lpi); + ieee_oui_id = json_create_array(); + + json_object_object_add(header, "ieeeOuiIdentifier", ieee_oui_id); + for (int i = 0; i < sizeof(log->ieee); i++) { + struct json_object *val = json_object_new_int(log->ieee[i]); + + json_object_array_add(ieee_oui_id, val); + } + json_object_add_value_uint(header, "dataArea1LastBlock", log->dalb1); + json_object_add_value_uint(header, "dataArea2LastBlock", log->dalb2); + json_object_add_value_uint(header, "dataArea3LastBlock", log->dalb3); + json_object_add_value_uint(header, "hostInitiatedDataGeneration", log->hostdgn); + json_object_add_value_uint(header, "controllerInitiatedDataAvailable", log->ctrlavail); + json_object_add_value_uint(header, "controllerInitiatedDataGeneration", log->ctrldgn); + + reason_id = json_create_object(); + json_object_add_value_object(header, "reasonIdentifier", reason_id); + solidigm_telemetry_log_reason_id_parse(tl, reason_id); + + return true; +} diff --git a/plugins/solidigm/solidigm-telemetry/header.h b/plugins/solidigm/solidigm-telemetry/header.h new file mode 100644 index 0000000000..027af5573a --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/header.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "telemetry-log.h" +bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl); diff --git a/plugins/solidigm/solidigm-telemetry/meson.build b/plugins/solidigm/solidigm-telemetry/meson.build new file mode 100644 index 0000000000..96273b706d --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/meson.build @@ -0,0 +1,7 @@ +sources += [ + 'plugins/solidigm/solidigm-telemetry/cod.c', + 'plugins/solidigm/solidigm-telemetry/header.c', + 'plugins/solidigm/solidigm-telemetry/config.c', + 'plugins/solidigm/solidigm-telemetry/data-area.c', + 'plugins/solidigm/solidigm-telemetry/nlog.c', +] diff --git a/plugins/solidigm/solidigm-telemetry/nlog.c b/plugins/solidigm/solidigm-telemetry/nlog.c new file mode 100644 index 0000000000..926772b26c --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/nlog.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "nlog.h" +#include "config.h" +#include +#include + +#include "ccan/ilog/ilog.h" + +#define LOG_ENTRY_HEADER_SIZE 1 +#define LOG_ENTRY_TIMESTAMP_SIZE 2 +#define LOG_ENTRY_NUM_ARGS_MAX 8 +#define LOG_ENTRY_MAX_SIZE (LOG_ENTRY_HEADER_SIZE + LOG_ENTRY_TIMESTAMP_SIZE + \ + LOG_ENTRY_NUM_ARGS_MAX) +#define NUM_ARGS_MASK ((1 << ((int)STATIC_ILOG_32(LOG_ENTRY_NUM_ARGS_MAX))) - 1) +#define MAX_HEADER_MISMATCH_TRACK 10 + +static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format) +{ + char hex_header[STR_HEX32_SIZE]; + + snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", val); + return json_object_object_get_ex(formats, hex_header, format); +} + +static uint32_t nlog_get_pos(const uint32_t *nlog, const uint32_t nlog_size, int pos) +{ + return nlog[pos % nlog_size]; +} + +static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, int start_offset, + struct json_object *formats, struct json_object *events, uint32_t *tail_mismatches) +{ + uint32_t event_count = 0; + int last_bad_header_pos = nlog_size + 1; // invalid nlog offset + uint32_t tail_count = 0; + + for (int i = nlog_size - start_offset - 1; i >= -start_offset; i--) { + struct json_object *format; + uint32_t header = nlog_get_pos(nlog, nlog_size, i); + uint32_t num_data; + + if (header == 0 || !formats_find(formats, header, &format)) { + if (event_count > 0) { + //check if fould circular buffer tail + if (i != (last_bad_header_pos - 1)) { + if (tail_mismatches && + (tail_count < MAX_HEADER_MISMATCH_TRACK)) + tail_mismatches[tail_count] = header; + tail_count++; + } + last_bad_header_pos = i; + } + continue; + } + num_data = header & NUM_ARGS_MASK; + if (events) { + struct json_object *event = json_object_new_array(); + struct json_object *param = json_object_new_array(); + uint32_t val = nlog_get_pos(nlog, nlog_size, i - 1); + + json_object_array_add(events, event); + json_object_array_add(event, json_object_new_int64(val)); + val = nlog_get_pos(nlog, nlog_size, i - 2); + json_object_array_add(event, json_object_new_int64(val)); + json_object_array_add(event, json_object_new_int64(header)); + json_object_array_add(event, param); + for (uint32_t j = 0; j < num_data; j++) { + val = nlog_get_pos(nlog, nlog_size, i - 3 - j); + json_object_array_add(param, json_object_new_int64(val)); + } + json_object_get(format); + json_object_array_add(event, format); + } + i -= 2 + num_data; + event_count++; + } + return tail_count; +} + +int solidigm_nlog_parse(const char *buffer, uint64_t buff_size, struct json_object *formats, + struct json_object *metadata, struct json_object *output) +{ + uint32_t smaller_tail_count = UINT32_MAX; + int best_offset = 0; + uint32_t offset_tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK]; + struct json_object *events = json_object_new_array(); + const uint32_t *nlog = (uint32_t *)buffer; + const uint32_t nlog_size = buff_size / sizeof(uint32_t); + + for (int i = 0; i < LOG_ENTRY_MAX_SIZE; i++) { + uint32_t tail_count = nlog_get_events(nlog, nlog_size, i, formats, NULL, + offset_tail_mismatches[i]); + if (tail_count < smaller_tail_count) { + best_offset = i; + smaller_tail_count = tail_count; + } + if (tail_count == 0) + break; + } + if (smaller_tail_count > 1) { + const char *name = ""; + int media_bank = -1; + char str_mismatches[(STR_HEX32_SIZE + 1) * MAX_HEADER_MISMATCH_TRACK]; + int pos = 0; + int show_mismatch_num = smaller_tail_count < MAX_HEADER_MISMATCH_TRACK ? + smaller_tail_count : MAX_HEADER_MISMATCH_TRACK; + struct json_object *jobj; + + if (json_object_object_get_ex(metadata, "objName", &jobj)) + name = json_object_get_string(jobj); + if (json_object_object_get_ex(metadata, "mediaBankId", &jobj)) + media_bank = json_object_get_int(jobj); + + for (int i = 0; i < show_mismatch_num; i++) + pos += snprintf(&str_mismatches[pos], STR_HEX32_SIZE + 1, "0x%08X ", + offset_tail_mismatches[best_offset][i]); + + SOLIDIGM_LOG_WARNING("%s:%d with %d header mismatches ( %s). Configuration file may be missing format headers.", + name, media_bank, smaller_tail_count, str_mismatches); + } + nlog_get_events(nlog, nlog_size, best_offset, formats, events, NULL); + + json_object_object_add(output, "events", events); + return 0; +} diff --git a/plugins/solidigm/solidigm-telemetry/nlog.h b/plugins/solidigm/solidigm-telemetry/nlog.h new file mode 100644 index 0000000000..f33aa45419 --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/nlog.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ +#include "telemetry-log.h" + +int solidigm_nlog_parse(const char *buffer, uint64_t bufer_size, + struct json_object *formats, struct json_object *metadata, + struct json_object *output); diff --git a/plugins/solidigm/solidigm-telemetry/telemetry-log.h b/plugins/solidigm/solidigm-telemetry/telemetry-log.h new file mode 100644 index 0000000000..e9eff7340d --- /dev/null +++ b/plugins/solidigm/solidigm-telemetry/telemetry-log.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#ifndef _SOLIDIGM_TELEMETRY_LOG_H +#define _SOLIDIGM_TELEMETRY_LOG_H + +#include "libnvme.h" +#include "util/json.h" +#include + +#if !defined __cplusplus +#define static_assert _Static_assert +#endif + +#define VA_ARGS(...), ##__VA_ARGS__ +#define SOLIDIGM_LOG_WARNING(format, ...) fprintf(stderr, format"\n" VA_ARGS(__VA_ARGS__)) + +#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member) + +struct telemetry_log { + struct nvme_telemetry_log *log; + size_t log_size; + struct json_object *root; + struct json_object *configuration; +}; + +#endif /* _SOLIDIGM_TELEMETRY_LOG_H */ diff --git a/plugins/solidigm/solidigm-temp-stats.c b/plugins/solidigm/solidigm-temp-stats.c new file mode 100644 index 0000000000..85a3c37ed8 --- /dev/null +++ b/plugins/solidigm/solidigm-temp-stats.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include + +#include "common.h" +#include "nvme-print.h" +#include "solidigm-util.h" + +#define SLDGM_TEMP_STATS_LID 0xC5 + +struct temp_stats { + __le64 curr; + __le64 last_overtemp; + __le64 life_overtemp; + __le64 highest_temp; + __le64 lowest_temp; + __u8 rsvd[40]; + __le64 max_operating_temp; + __le64 min_operating_temp; + __le64 est_offset; +}; + +static void show_temp_stats(struct temp_stats *stats) +{ + printf("Current temperature : %"PRIu64"\n", le64_to_cpu(stats->curr)); + printf("Last critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->last_overtemp)); + printf("Life critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->life_overtemp)); + printf("Highest temperature : %"PRIu64"\n", le64_to_cpu(stats->highest_temp)); + printf("Lowest temperature : %"PRIu64"\n", le64_to_cpu(stats->lowest_temp)); + printf("Max operating temperature : %"PRIu64"\n", le64_to_cpu(stats->max_operating_temp)); + printf("Min operating temperature : %"PRIu64"\n", le64_to_cpu(stats->min_operating_temp)); + printf("Estimated offset : %"PRIu64"\n", le64_to_cpu(stats->est_offset)); +} + +int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + unsigned char buffer[4096] = {0}; + struct nvme_dev *dev; + __u8 uuid_idx; + int err; + + const char *desc = "Get/show Temperature Statistics log."; + const char *raw = "dump output in binary format"; + struct config { + bool raw_binary; + }; + + struct config cfg = { + .raw_binary = false, + }; + + OPT_ARGS(opts) = { + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + uuid_idx = solidigm_get_vu_uuid_index(dev); + + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = buffer, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .uuidx = uuid_idx, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = SLDGM_TEMP_STATS_LID, + .len = sizeof(buffer), + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = NVME_LOG_LSP_NONE, + .rae = false, + .ot = false, + }; + + err = nvme_get_log(&args); + if (!err) { + uint64_t *guid = (uint64_t *)&buffer[4080]; + + if (guid[1] == 0xC7BB98B7D0324863 && guid[0] == 0xBB2C23990E9C722F) { + fprintf(stderr, "Error: Log page has 'OCP unsupported Requirements' GUID\n"); + err = -EBADMSG; + goto closefd; + } + if (!cfg.raw_binary) + show_temp_stats((struct temp_stats *) buffer); + else + d_raw(buffer, sizeof(struct temp_stats)); + } else if (err > 0) { + nvme_show_status(err); + } + +closefd: + /* Redundant close() to make static code analysis happy */ + close(dev->direct.fd); + dev_close(dev); + return err; +} diff --git a/plugins/solidigm/solidigm-temp-stats.h b/plugins/solidigm/solidigm-temp-stats.h new file mode 100644 index 0000000000..58d5a86801 --- /dev/null +++ b/plugins/solidigm/solidigm-temp-stats.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin); diff --git a/plugins/solidigm/solidigm-util.c b/plugins/solidigm/solidigm-util.c new file mode 100644 index 0000000000..0171a494be --- /dev/null +++ b/plugins/solidigm/solidigm-util.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "plugins/ocp/ocp-utils.h" +#include "solidigm-util.h" + +__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev) +{ + int ocp_uuid_index = 0; + + if (ocp_get_uuid_index(dev, &ocp_uuid_index) == 0) + if (ocp_uuid_index == 2) + return 1; + + return 0; +} diff --git a/plugins/solidigm/solidigm-util.h b/plugins/solidigm/solidigm-util.h new file mode 100644 index 0000000000..fa5032fe20 --- /dev/null +++ b/plugins/solidigm/solidigm-util.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Solidigm. + * + * Author: leonardo.da.cunha@solidigm.com + */ + +#include "nvme.h" + +#define DRIVER_MAX_TX_256K (256 * 1024) + +__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev); diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c index 5540fea75d..49270128b7 100644 --- a/plugins/toshiba/toshiba-nvme.c +++ b/plugins/toshiba/toshiba-nvme.c @@ -21,37 +21,37 @@ 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_STATUS_COMMAND; 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 __u32 DW11_SCT_STATUS_COMMAND; +static const __u32 DW11_SCT_COMMAND_TRANSFER; static const __u16 INTERNAL_LOG_ACTION_CODE = 0xFFFB; static const __u16 CURRENT_LOG_FUNCTION_CODE = 0x0001; static const __u16 SAVED_LOG_FUNCTION_CODE = 0x0002; /* A bitmask field for supported devices */ -typedef enum { - MASK_0 = 1 << 0, - MASK_1 = 1 << 1, +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 { +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 ) +static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void *data, __u32 data_len) { - void *metadata = NULL; + void *metadata = NULL; const __u32 cdw2 = 0; const __u32 cdw3 = 0; const __u32 cdw12 = 0; @@ -63,26 +63,23 @@ static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void* da const __u32 namespace_id = 0x0; const __u32 flags = 0; const __u32 rsvd = 0; - int err = 0; - __u32 result; - err = nvme_admin_passthru(fd, opcode, flags, rsvd, - namespace_id, cdw2, cdw3, cdw10, - cdw11, cdw12, cdw13, cdw14, cdw15, - data_len, data, metadata_len, metadata, - timeout, &result); - return err; + + return nvme_admin_passthru(fd, opcode, flags, rsvd, namespace_id, cdw2, cdw3, cdw10, cdw11, + cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len, + metadata, timeout, &result); } static int nvme_get_sct_status(int fd, __u32 device_mask) { int err; - void* data = NULL; + void *data = NULL; size_t data_len = 512; unsigned char *status; + __u32 supported = 0; if (posix_memalign(&data, getpagesize(), data_len)) - return ENOMEM; + 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); @@ -102,22 +99,19 @@ static int nvme_get_sct_status(int fd, __u32 device_mask) /* 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]); + if (!supported) { + fprintf(stderr, "%s: command unsupported on this device: (0x%x)\n", __func__, status[1]); err = -1; errno = EINVAL; goto end; @@ -142,7 +136,7 @@ static int nvme_sct_command_transfer_log(int fd, bool current) function_code = SAVED_LOG_FUNCTION_CODE; if (posix_memalign(&data, getpagesize(), data_len)) - return ENOMEM; + return -ENOMEM; memset(data, 0, data_len); memcpy(data, &action_code, sizeof(action_code)); @@ -153,7 +147,7 @@ static int nvme_sct_command_transfer_log(int fd, bool current) return err; } -static int nvme_sct_data_transfer(int fd, void* data, size_t data_len, size_t offset) +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; @@ -170,7 +164,7 @@ static int nvme_sct_data_transfer(int fd, void* data, size_t data_len, size_t of 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) +static int d_raw_to_fd(const unsigned char *buf, unsigned int len, int fd) { int written = 0; int remaining = len; @@ -207,26 +201,26 @@ static void progress_runner(float progress) fprintf(stdout, " "); } - fprintf(stdout, "] %d %%\r",(int)(progress * 100.0)); + fprintf(stdout, "] %d %%\r", (int)(progress * 100.0)); fflush(stdout); } -static int nvme_get_internal_log(int fd, const char* const filename, bool current) +static int nvme_get_internal_log(int fd, const char *const filename, bool current) { int err; int o_fd = -1; - void* page_data = NULL; + 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 *area1_last_page; + uint32_t *area2_last_page; + uint32_t *area3_last_page; uint32_t log_sectors = 0; size_t pages; - + __u32 pages_chunk; /* * By trial and error it seems that the largest transfer chunk size - * is 128 * 32 = 4k sectors = 2MB + * is 128 * 32 = 4k sectors = 2MB */ const __u32 max_pages = 128; size_t i; @@ -248,7 +242,7 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren /* 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__); + fprintf(stderr, "%s: SCT data transfer failed, page 0\n", __func__); goto end; } @@ -274,7 +268,7 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren 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; + err = -EINVAL; goto end; } err = d_raw_to_fd(page_data, page_data_len, o_fd); @@ -286,7 +280,7 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren /* Now read the rest */ for (i = 1; i < pages;) { - __u32 pages_chunk = max_pages; + pages_chunk = max_pages; if (pages_chunk + i >= pages) pages_chunk = pages - i; @@ -318,23 +312,21 @@ static int nvme_get_internal_log(int fd, const char* const filename, bool curren } progress = 1.0f; progress_runner(progress); - fprintf(stdout,"\n"); + 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) { + if (o_fd >= 0) close(o_fd); - } - if (page_data) { + if (page_data) free(page_data); - } return err; } -static int nvme_get_internal_log_file(int fd, const char* const filename, bool current) +static int nvme_get_internal_log_file(int fd, const char *const filename, bool current) { int err; @@ -366,20 +358,20 @@ static void default_show_vendor_log_c0(struct nvme_dev *dev, __u32 nsid, { printf("Vendor Log Page Directory 0xC0 for NVME device:%s namespace-id:%x\n", dev->name, nsid); - printf("Error Log : %u \n", smart->items[ERROR_LOG_C0]); - printf("SMART Health Log : %u \n", smart->items[SMART_HEALTH_LOG_C0]); - printf("Firmware Slot Info : %u \n", smart->items[FIRMWARE_SLOT_INFO_C0]); - printf("Command Effects : %u \n", smart->items[COMMAND_EFFECTS_C0]); - printf("Device Self Test : %u \n", smart->items[DEVICE_SELF_TEST_C0]); - printf("Log Page Directory : %u \n", smart->items[LOG_PAGE_DIRECTORY_C0]); - printf("SMART Attributes : %u \n", smart->items[SMART_ATTRIBUTES_C0]); + printf("Error Log : %u\n", smart->items[ERROR_LOG_C0]); + printf("SMART Health Log : %u\n", smart->items[SMART_HEALTH_LOG_C0]); + printf("Firmware Slot Info : %u\n", smart->items[FIRMWARE_SLOT_INFO_C0]); + printf("Command Effects : %u\n", smart->items[COMMAND_EFFECTS_C0]); + printf("Device Self Test : %u\n", smart->items[DEVICE_SELF_TEST_C0]); + printf("Log Page Directory : %u\n", smart->items[LOG_PAGE_DIRECTORY_C0]); + printf("SMART Attributes : %u\n", smart->items[SMART_ATTRIBUTES_C0]); } static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id, - int log_page, const char* const filename) + int log_page, const char *const filename) { int err; - void* log = NULL; + void *log = NULL; size_t log_len = 512; if (posix_memalign(&log, getpagesize(), log_len)) { @@ -389,9 +381,8 @@ static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id, /* Check device supported */ err = nvme_get_sct_status(dev_fd(dev), MASK_0 | MASK_1); - if (err) { + if (err) goto end; - } err = nvme_get_nsid_log(dev_fd(dev), false, log_page, namespace_id, log_len, log); if (err) { @@ -405,7 +396,7 @@ static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id, if (o_fd < 0) { fprintf(stderr, "%s: couldn't output file %s\n", __func__, filename); - err = EINVAL; + err = -EINVAL; goto end; } err = d_raw_to_fd(log, log_len, o_fd); @@ -422,12 +413,11 @@ static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id, if (log_page == 0xc0) default_show_vendor_log_c0(dev, namespace_id, log); else - d(log, log_len,16,1); + d(log, log_len, 16, 1); } end: - if (log) { + if (log) free(log); - } return err; } @@ -442,7 +432,7 @@ static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin struct config { __u32 namespace_id; - const char* output_file; + const char *output_file; int log; }; @@ -461,13 +451,13 @@ static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - fprintf(stderr,"%s: failed to parse arguments\n", __func__); - return EINVAL; + 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; + err = -EINVAL; goto end; } @@ -491,7 +481,7 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi int err; struct config { - const char* output_file; + const char *output_file; bool prev_log; }; @@ -501,15 +491,15 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi }; OPT_ARGS(opts) = { - OPT_FILE("output-file", 'o', &cfg.output_file, output_file), + OPT_FILE("output-file", 'o', &cfg.output_file, output_file), OPT_FLAG("prev-log", 'p', &cfg.prev_log, prev_log), OPT_END() }; err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - fprintf(stderr,"%s: failed to parse arguments\n", __func__); - return EINVAL; + fprintf(stderr, "%s: failed to parse arguments\n", __func__); + return -EINVAL; } if (cfg.prev_log) @@ -520,7 +510,7 @@ static int internal_log(int argc, char **argv, struct command *cmd, struct plugi err = nvme_get_internal_log_file(dev_fd(dev), cfg.output_file, !cfg.prev_log); if (err < 0) - fprintf(stderr, "%s: couldn't get fw log \n", __func__); + fprintf(stderr, "%s: couldn't get fw log\n", __func__); if (err > 0) nvme_show_status(err); @@ -547,8 +537,8 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd, err = parse_and_open(&dev, argc, argv, desc, opts); if (err) { - fprintf(stderr,"%s: failed to parse arguments\n", __func__); - return EINVAL; + fprintf(stderr, "%s: failed to parse arguments\n", __func__); + return -EINVAL; } /* Check device supported */ @@ -573,7 +563,7 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd, }; err = nvme_set_features(&args); if (err) - fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n", + fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n", __func__); end: if (err > 0) diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c index 024351f542..547fbf4ea9 100644 --- a/plugins/transcend/transcend-nvme.c +++ b/plugins/transcend/transcend-nvme.c @@ -21,7 +21,7 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu { struct nvme_smart_log smart_log; char *desc = "Get nvme health percentage."; - int percent_used = 0, healthvalue=0; + int percent_used = 0, healthvalue = 0; struct nvme_dev *dev; int result; @@ -31,59 +31,55 @@ static int getHealthValue(int argc, char **argv, struct command *cmd, struct plu result = parse_and_open(&dev, argc, argv, desc, opts); if (result) { - printf("\nDevice not found \n");; + printf("\nDevice not found\n"); return -1; } result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log); if (!result) { printf("Transcend NVME heath value: "); - percent_used =smart_log.percent_used; - - if(percent_used>100 || percent_used<0) - { + percent_used = smart_log.percent_used; + + if (percent_used > 100 || percent_used < 0) { printf("0%%\n"); - } - else - { + } else { healthvalue = 100 - percent_used; - printf("%d%%\n",healthvalue); + printf("%d%%\n", healthvalue); } - } dev_close(dev); return result; } - static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin *plugin) { char *desc = "Get nvme bad block number."; struct nvme_dev *dev; int result; - + OPT_ARGS(opts) = { - OPT_END() }; result = parse_and_open(&dev, argc, argv, desc, opts); if (result) { - printf("\nDevice not found \n");; + printf("\nDevice not found\n"); return -1; } - unsigned char data[1]={0}; + 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; + + memset(&nvmecmd, 0, sizeof(nvmecmd)); + nvmecmd.opcode = OP_BAD_BLOCK; + nvmecmd.cdw10 = DW10_BAD_BLOCK; + nvmecmd.cdw12 = DW12_BAD_BLOCK; nvmecmd.addr = (__u64)(uintptr_t)data; nvmecmd.data_len = 0x1; result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL); - if(!result) { + if (!result) { int badblock = data[0]; - printf("Transcend NVME badblock count: %d\n",badblock); + + printf("Transcend NVME badblock count: %d\n", badblock); } dev_close(dev); return result; diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c index 8c7190abb0..0ba4b155e9 100644 --- a/plugins/virtium/virtium-nvme.c +++ b/plugins/virtium/virtium-nvme.c @@ -14,11 +14,12 @@ #include "nvme.h" #include "libnvme.h" #include "plugin.h" +#include "util/types.h" #define CREATE_CMD #include "virtium-nvme.h" -#define MIN2(a, b) ( ((a) < (b))? (a) : (b)) +#define MIN2(a, b) (((a) < (b)) ? (a) : (b)) #define HOUR_IN_SECONDS 3600 @@ -29,40 +30,28 @@ 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_slot raw_fw; + char path[256]; + char test_name[256]; + long time_stamp; + struct nvme_id_ctrl raw_ctrl; + struct nvme_firmware_slot raw_fw; }; struct vtview_smart_log_entry { - char path[256]; - long int time_stamp; + char path[256]; + long time_stamp; struct nvme_id_ns raw_ns; struct nvme_id_ctrl raw_ctrl; struct nvme_smart_log raw_smart; }; struct vtview_save_log_settings { - double run_time_hrs; - double log_record_frequency_hrs; - const char* output_file; - const char* test_name; + 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)); @@ -83,7 +72,7 @@ static void vt_convert_data_buffer_to_hex_string(const unsigned char *bufPtr, memset(output, 0, (size * 2) + 1); for (i = 0; i < size; i++) { - if(isReverted) + if (isReverted) pos = size - 1 - i; else pos = i; @@ -97,7 +86,7 @@ static void vt_convert_data_buffer_to_hex_string(const unsigned char *bufPtr, * 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) +static void vt_generate_vtview_log_file_name(char *fname) { time_t current; struct tm tstamp; @@ -123,17 +112,19 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l char *curlocale; char *templocale; __u8 lba_index; + nvme_id_ns_flbas_to_lbaf_inuse(smart->raw_ns.flbas, &lba_index); curlocale = setlocale(LC_ALL, NULL); templocale = strdup(curlocale); - if (NULL == templocale) + if (!templocale) printf("Cannot malloc buffer\n"); setlocale(LC_ALL, "C"); - unsigned long long int lba = 1ULL << smart->raw_ns.lbaf[lba_index].ds; + unsigned long long lba = 1ULL << smart->raw_ns.lbaf[lba_index].ds; + capacity = le64_to_cpu(smart->raw_ns.nsze) * lba; snprintf(tempbuff, sizeof(tempbuff), "log;%s;%lu;%s;%s;%-.*s;", smart->raw_ctrl.sn, smart->time_stamp, smart->path, @@ -151,25 +142,25 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l 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)); + snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Read;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.data_units_read))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Written;%0.Lf;", int128_to_double(smart->raw_smart.data_units_written)); + snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Written;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.data_units_written))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Host_Read_Commands;%0.Lf;", int128_to_double(smart->raw_smart.host_reads)); + snprintf(tempbuff, sizeof(tempbuff), "Host_Read_Commands;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.host_reads))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Host_Write_Commands;%0.Lf;", int128_to_double(smart->raw_smart.host_writes)); + snprintf(tempbuff, sizeof(tempbuff), "Host_Write_Commands;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.host_writes))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Controller_Busy_Time;%0.Lf;", int128_to_double(smart->raw_smart.ctrl_busy_time)); + snprintf(tempbuff, sizeof(tempbuff), "Controller_Busy_Time;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.ctrl_busy_time))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Power_Cycles;%0.Lf;", int128_to_double(smart->raw_smart.power_cycles)); + snprintf(tempbuff, sizeof(tempbuff), "Power_Cycles;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.power_cycles))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Power_On_Hours;%0.Lf;", int128_to_double(smart->raw_smart.power_on_hours)); + snprintf(tempbuff, sizeof(tempbuff), "Power_On_Hours;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.power_on_hours))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Unsafe_Shutdowns;%0.Lf;", int128_to_double(smart->raw_smart.unsafe_shutdowns)); + snprintf(tempbuff, sizeof(tempbuff), "Unsafe_Shutdowns;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.unsafe_shutdowns))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Media_Errors;%0.Lf;", int128_to_double(smart->raw_smart.media_errors)); + snprintf(tempbuff, sizeof(tempbuff), "Media_Errors;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.media_errors))); strcat(text, tempbuff); - snprintf(tempbuff, sizeof(tempbuff), "Num_Err_Log_Entries;%0.Lf;", int128_to_double(smart->raw_smart.num_err_log_entries)); + snprintf(tempbuff, sizeof(tempbuff), "Num_Err_Log_Entries;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.num_err_log_entries))); strcat(text, tempbuff); snprintf(tempbuff, sizeof(tempbuff), "Warning_Temperature_Time;%u;", le32_to_cpu(smart->raw_smart.warning_temp_time)); strcat(text, tempbuff); @@ -178,7 +169,8 @@ static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_l for (i = 0; i < 8; i++) { __s32 temp = le16_to_cpu(smart->raw_smart.temp_sensor[i]); - if (0 == temp) { + + if (!temp) { snprintf(tempbuff, sizeof(tempbuff), "Temperature_Sensor_%d;NC;", i); strcat(text, tempbuff); continue; @@ -228,7 +220,7 @@ static int vt_append_text_file(const char *text, const char *filename) FILE *f; f = fopen(filename, "a"); - if(NULL == f) { + if (!f) { printf("Cannot open %s\n", filename); return -1; } @@ -258,11 +250,11 @@ static void vt_process_string(char *str, const size_t size) { size_t i; - if (size == 0) + if (!size) return; i = size - 1; - while ((0 != i) && (' ' == str[i])) { + while (i && (' ' == str[i])) { str[i] = 0; i--; } @@ -273,11 +265,11 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi struct vtview_smart_log_entry smart; const char *filename; int ret = 0; - unsigned nsid = 0; + unsigned int nsid = 0; memset(smart.path, 0, sizeof(smart.path)); strncpy(smart.path, path, sizeof(smart.path) - 1); - if(NULL == cfg->output_file) + if (!cfg->output_file) filename = vt_default_log_file_name; else filename = cfg->output_file; @@ -312,7 +304,7 @@ static int vt_add_entry_to_log(const int fd, const char *path, const struct vtvi vt_process_string(smart.raw_ctrl.mn, sizeof(smart.raw_ctrl.mn)); ret = vt_append_log(&smart, filename); - return (ret); + return ret; } static int vt_update_vtview_log_header(const int fd, const char *path, const struct vtview_save_log_settings *cfg) @@ -329,9 +321,9 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str } strcpy(header.path, path); - if (NULL == cfg->test_name) + if (!cfg->test_name) { strcpy(header.test_name, DEFAULT_TEST_NAME); - else { + } else { if (strlen(cfg->test_name) > sizeof(header.test_name)) { printf("test name too long\n"); errno = EINVAL; @@ -340,7 +332,7 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str strcpy(header.test_name, cfg->test_name); } - if(NULL == cfg->output_file) + if (!cfg->output_file) filename = vt_default_log_file_name; else filename = cfg->output_file; @@ -364,7 +356,7 @@ static int vt_update_vtview_log_header(const int fd, const char *path, const str vt_process_string(header.raw_ctrl.mn, sizeof(header.raw_ctrl.mn)); ret = vt_append_header(&header, filename); - return (ret); + return ret; } static void vt_build_identify_lv2(unsigned int data, unsigned int start, @@ -382,13 +374,13 @@ static void vt_build_identify_lv2(unsigned int data, unsigned int start, printf(" \"bit %u\":\"%ub %s\"\n", i, temp, table[pos]); printf(" %s", table[pos + 1]); - if((end - 1) != i || !isEnd) + if ((end - 1) != i || !isEnd) printf(",\n"); else printf("\n"); } - if(isEnd) + if (isEnd) printf(" },\n"); } @@ -429,7 +421,7 @@ static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl) unsigned int temp; printf("%6d", i); - buf = (unsigned char*) (&ctrl->psd[i]); + buf = (unsigned char *) (&ctrl->psd[i]); vt_convert_data_buffer_to_hex_string(&buf[0], 4, true, s); printf("%9sh", s); @@ -480,36 +472,35 @@ static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl) } -static void vt_dump_hex_data(const unsigned char *pbuff, size_t pbuffsize) { - +static void vt_dump_hex_data(const unsigned char *pbuff, size_t pbuffsize) +{ char textbuf[33]; - unsigned long int i, j; + unsigned long i, j; textbuf[32] = '\0'; printf("[%08X] ", 0); for (i = 0; i < pbuffsize; i++) { printf("%02X ", pbuff[i]); - if (pbuff[i] >= ' ' && pbuff[i] <= '~') + if (pbuff[i] >= ' ' && pbuff[i] <= '~') textbuf[i % 32] = pbuff[i]; - else + else textbuf[i % 32] = '.'; - if ((((i + 1) % 8) == 0) || ((i + 1) == pbuffsize)) { + if (!(((i + 1) % 8)) || ((i + 1) == pbuffsize)) { printf(" "); - if ((i + 1) % 32 == 0) { + if (!((i + 1) % 32)) { printf(" %s\n", textbuf); - if((i + 1) != pbuffsize) - printf("[%08lX] ", (i + 1)); - } - else if (i + 1 == pbuffsize) { + if ((i + 1) != pbuffsize) + printf("[%08lX] ", (i + 1)); + } else if (i + 1 == pbuffsize) { textbuf[(i + 1) % 32] = '\0'; - if(((i + 1) % 8) == 0) + if (!((i + 1) % 8)) printf(" "); for (j = ((i + 1) % 32); j < 32; j++) { printf(" "); - if(((j + 1) % 8) == 0) + if (!((j + 1) % 8)) printf(" "); } @@ -526,174 +517,174 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl) 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"}; + "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"}; + "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"}; + "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"}; + "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"}; + "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" }; + "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"}; + "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"}; + "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"}; + "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"}; + "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"}; + "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"}; + "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"}; + "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"}; + "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"}; + "1 = a volatile write cache is present"}; const char *ICSVSCCtable[2] = {"0 = the format of all NVM Vendor Specific Commands are vendor specific", - "1 = all NVM Vendor Specific Commands use the format defined in NVM Express specification"}; + "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"}; + "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"}; + "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); @@ -802,12 +793,12 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl) 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); + 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"); + 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)); @@ -928,18 +919,18 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl) static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { int ret, err = 0; - 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; + long total_time = 0; + long freq_time = 0; + long cur_time = 0; + long remain_time = 0; + long start_time = 0; + long end_time = 0; char path[256] = ""; char *desc = "Save SMART data into log file with format that is easy to analyze (comma delimited). Maximum log file will be 4K.\n\n" "Typical usages:\n\n" - "Temperature characterization: \n" + "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" + "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"; @@ -990,13 +981,13 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm if (ret) { err = EINVAL; dev_close(dev); - return (err); + 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) + if (!freq_time) freq_time = 1; start_time = time(NULL); @@ -1006,7 +997,7 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm while (1) { cur_time = time(NULL); - if(cur_time >= end_time) + if (cur_time >= end_time) break; ret = vt_add_entry_to_log(dev_fd(dev), path, &cfg); @@ -1022,7 +1013,7 @@ static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cm } dev_close(dev); - return (err); + return err; } static int vt_show_identify(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -1048,7 +1039,7 @@ static int vt_show_identify(int argc, char **argv, struct command *cmd, struct p if (ret) { printf("Cannot read identify device\n"); dev_close(dev); - return (-1); + return -1; } vt_process_string(ctrl.sn, sizeof(ctrl.sn)); @@ -1056,5 +1047,5 @@ static int vt_show_identify(int argc, char **argv, struct command *cmd, struct p vt_parse_detail_identify(&ctrl); dev_close(dev); - return (err); + return err; } diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index cf9809d7f5..c8323c6c5a 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -20,7 +20,7 @@ * Author: Chaitanya Kulkarni , * Dong Ho , * Jeff Lien - * Brandon Paupore + * Brandon Paupore */ #include #include @@ -36,6 +36,8 @@ #include "libnvme.h" #include "plugin.h" #include "linux/types.h" +#include "util/cleanup.h" +#include "util/types.h" #include "nvme-print.h" #define CREATE_CMD @@ -50,7 +52,7 @@ #define WDC_NVME_LOG_SIZE_HDR_LEN 0x08 /* Enclosure */ -#define WDC_OPENFLEX_MI_DEVICE_MODEL "OpenFlex" +#define WDC_OPENFLEX_MI_DEVICE_MODEL "OpenFlex" #define WDC_RESULT_MORE_DATA 0x80000000 #define WDC_RESULT_NOT_AVAILABLE 0x7FFFFFFF @@ -68,38 +70,73 @@ #define WDC_NVME_SN640_DEV_ID 0x2400 #define WDC_NVME_SN640_DEV_ID_1 0x2401 #define WDC_NVME_SN640_DEV_ID_2 0x2402 -#define WDC_NVME_SN640_DEV_ID_3 0x2404 -#define WDC_NVME_ZN540_DEV_ID 0x2600 -#define WDC_NVME_SN540_DEV_ID 0x2610 +#define WDC_NVME_SN640_DEV_ID_3 0x2404 +#define WDC_NVME_ZN540_DEV_ID 0x2600 +#define WDC_NVME_SN540_DEV_ID 0x2610 #define WDC_NVME_SN650_DEV_ID 0x2700 -#define WDC_NVME_SN650_DEV_ID_1 0x2701 -#define WDC_NVME_SN650_DEV_ID_2 0x2702 -#define WDC_NVME_SN650_DEV_ID_3 0x2720 -#define WDC_NVME_SN650_DEV_ID_4 0x2721 -#define WDC_NVME_SN655_DEV_ID 0x2722 -#define WDC_NVME_SN560_DEV_ID_1 0x2712 -#define WDC_NVME_SN560_DEV_ID_2 0x2713 -#define WDC_NVME_SN560_DEV_ID_3 0x2714 -#define WDC_NVME_SN860_DEV_ID 0x2730 -#define WDC_NVME_SN550_DEV_ID 0x2708 +#define WDC_NVME_SN650_DEV_ID_1 0x2701 +#define WDC_NVME_SN650_DEV_ID_2 0x2702 +#define WDC_NVME_SN650_DEV_ID_3 0x2720 +#define WDC_NVME_SN650_DEV_ID_4 0x2721 +#define WDC_NVME_SN655_DEV_ID 0x2722 +#define WDC_NVME_SN860_DEV_ID 0x2730 +#define WDC_NVME_SN660_DEV_ID 0x2704 +#define WDC_NVME_SN560_DEV_ID_1 0x2712 +#define WDC_NVME_SN560_DEV_ID_2 0x2713 +#define WDC_NVME_SN560_DEV_ID_3 0x2714 +#define WDC_NVME_SN861_DEV_ID 0x2750 +#define WDC_NVME_SN861_DEV_ID_1 0x2751 + +/* This id's are no longer supported, delete ?? */ +#define WDC_NVME_SN550_DEV_ID 0x2708 + #define WDC_NVME_SXSLCL_DEV_ID 0x2001 #define WDC_NVME_SN520_DEV_ID 0x5003 #define WDC_NVME_SN520_DEV_ID_1 0x5004 #define WDC_NVME_SN520_DEV_ID_2 0x5005 -#define WDC_NVME_SN530_DEV_ID 0x5009 + +#define WDC_NVME_SN530_DEV_ID_1 0x5007 +#define WDC_NVME_SN530_DEV_ID_2 0x5008 +#define WDC_NVME_SN530_DEV_ID_3 0x5009 +#define WDC_NVME_SN530_DEV_ID_4 0x500b +#define WDC_NVME_SN530_DEV_ID_5 0x501d + +#define WDC_NVME_SN350_DEV_ID 0x5019 + +#define WDC_NVME_SN570_DEV_ID 0x501A + +#define WDC_NVME_SN850X_DEV_ID 0x5030 + +#define WDC_NVME_SN5000_DEV_ID_1 0x5034 +#define WDC_NVME_SN5000_DEV_ID_2 0x5035 +#define WDC_NVME_SN5000_DEV_ID_3 0x5036 +#define WDC_NVME_SN5000_DEV_ID_4 0x504A + +#define WDC_NVME_SN7000S_DEV_ID_1 0x5039 + +#define WDC_NVME_SN7150_DEV_ID_1 0x503b +#define WDC_NVME_SN7150_DEV_ID_2 0x503c +#define WDC_NVME_SN7150_DEV_ID_3 0x503d +#define WDC_NVME_SN7150_DEV_ID_4 0x503e +#define WDC_NVME_SN7150_DEV_ID_5 0x503f + +#define WDC_NVME_SN7100_DEV_ID_1 0x5043 +#define WDC_NVME_SN7100_DEV_ID_2 0x5044 +#define WDC_NVME_SN7100_DEV_ID_3 0x5045 + +#define WDC_NVME_SN8000S_DEV_ID 0x5049 + #define WDC_NVME_SN720_DEV_ID 0x5002 -#define WDC_NVME_SN730A_DEV_ID 0x5006 -#define WDC_NVME_SN730B_DEV_ID 0x3714 -#define WDC_NVME_SN730B_DEV_ID_1 0x3734 +#define WDC_NVME_SN730_DEV_ID 0x5006 #define WDC_NVME_SN740_DEV_ID 0x5015 -#define WDC_NVME_SN740_DEV_ID_1 0x5016 -#define WDC_NVME_SN740_DEV_ID_2 0x5017 -#define WDC_NVME_SN740_DEV_ID_3 0x5025 +#define WDC_NVME_SN740_DEV_ID_1 0x5016 +#define WDC_NVME_SN740_DEV_ID_2 0x5017 +#define WDC_NVME_SN740_DEV_ID_3 0x5025 #define WDC_NVME_SN340_DEV_ID 0x500d #define WDC_NVME_ZN350_DEV_ID 0x5010 -#define WDC_NVME_ZN350_DEV_ID_1 0x5018 +#define WDC_NVME_ZN350_DEV_ID_1 0x5018 #define WDC_NVME_SN810_DEV_ID 0x5011 -#define WDC_NVME_SN820CL_DEV_ID 0x5037 +#define WDC_NVME_SN820CL_DEV_ID 0x5037 #define WDC_DRIVE_CAP_CAP_DIAG 0x0000000000000001 #define WDC_DRIVE_CAP_INTERNAL_LOG 0x0000000000000002 @@ -111,49 +148,56 @@ #define WDC_DRIVE_CAP_CLEAR_PCIE 0x0000000000000080 #define WDC_DRIVE_CAP_RESIZE 0x0000000000000100 #define WDC_DRIVE_CAP_NAND_STATS 0x0000000000000200 -#define WDC_DRIVE_CAP_DRIVE_LOG 0x0000000000000400 -#define WDC_DRIVE_CAP_CRASH_DUMP 0x0000000000000800 -#define WDC_DRIVE_CAP_PFAIL_DUMP 0x0000000000001000 -#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY 0x0000000000002000 -#define WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY 0x0000000000004000 -#define WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG 0x0000000000008000 -#define WDC_DRIVE_CAP_REASON_ID 0x0000000000010000 -#define WDC_DRIVE_CAP_LOG_PAGE_DIR 0x0000000000020000 -#define WDC_DRIVE_CAP_NS_RESIZE 0x0000000000040000 -#define WDC_DRIVE_CAP_INFO 0x0000000000080000 -#define WDC_DRIVE_CAP_C0_LOG_PAGE 0x0000000000100000 -#define WDC_DRIVE_CAP_TEMP_STATS 0x0000000000200000 -#define WDC_DRIVE_CAP_VUC_CLEAR_PCIE 0x0000000000400000 -#define WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE 0x0000000000800000 -#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 0x0000000001000000 +#define WDC_DRIVE_CAP_DRIVE_LOG 0x0000000000000400 +#define WDC_DRIVE_CAP_CRASH_DUMP 0x0000000000000800 +#define WDC_DRIVE_CAP_PFAIL_DUMP 0x0000000000001000 +#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY 0x0000000000002000 +#define WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY 0x0000000000004000 +#define WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG 0x0000000000008000 +#define WDC_DRIVE_CAP_REASON_ID 0x0000000000010000 +#define WDC_DRIVE_CAP_LOG_PAGE_DIR 0x0000000000020000 +#define WDC_DRIVE_CAP_NS_RESIZE 0x0000000000040000 +#define WDC_DRIVE_CAP_INFO 0x0000000000080000 +#define WDC_DRIVE_CAP_C0_LOG_PAGE 0x0000000000100000 +#define WDC_DRIVE_CAP_TEMP_STATS 0x0000000000200000 +#define WDC_DRIVE_CAP_VUC_CLEAR_PCIE 0x0000000000400000 +#define WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE 0x0000000000800000 +#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 0x0000000001000000 #define WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY 0x0000000002000000 -#define WDC_DRIVE_CAP_CLOUD_SSD_VERSION 0x0000000004000000 +#define WDC_DRIVE_CAP_CLOUD_SSD_VERSION 0x0000000004000000 #define WDC_DRIVE_CAP_PCIE_STATS 0x0000000008000000 -#define WDC_DRIVE_CAP_HW_REV_LOG_PAGE 0x0000000010000000 +#define WDC_DRIVE_CAP_HW_REV_LOG_PAGE 0x0000000010000000 #define WDC_DRIVE_CAP_C3_LOG_PAGE 0x0000000020000000 #define WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION 0x0000000040000000 -#define WDC_DRIVE_CAP_CLOUD_LOG_PAGE 0x0000000080000000 +#define WDC_DRIVE_CAP_CLOUD_LOG_PAGE 0x0000000080000000 -#define WDC_DRIVE_CAP_DRIVE_ESSENTIALS 0x0000000100000000 +#define WDC_DRIVE_CAP_DRIVE_ESSENTIALS 0x0000000100000000 #define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000 #define WDC_SN730B_CAP_VUC_LOG 0x0000000400000000 -#define WDC_DRIVE_CAP_DUI 0x0000000800000000 -#define WDC_DRIVE_CAP_PURGE 0x0000001000000000 -#define WDC_DRIVE_CAP_OCP_C1_LOG_PAGE 0x0000002000000000 -#define WDC_DRIVE_CAP_OCP_C4_LOG_PAGE 0x0000004000000000 -#define WDC_DRIVE_CAP_OCP_C5_LOG_PAGE 0x0000008000000000 -#define WDC_DRIVE_CAP_DEVICE_WAF 0x0000010000000000 -#define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C0_LOG_PAGE | WDC_DRIVE_CAP_C1_LOG_PAGE | \ - WDC_DRIVE_CAP_CA_LOG_PAGE | WDC_DRIVE_CAP_D0_LOG_PAGE) -#define WDC_DRIVE_CAP_CLEAR_PCIE_MASK (WDC_DRIVE_CAP_CLEAR_PCIE | \ - WDC_DRIVE_CAP_VUC_CLEAR_PCIE | \ - WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE) +#define WDC_DRIVE_CAP_DUI 0x0000000800000000 +#define WDC_DRIVE_CAP_PURGE 0x0000001000000000 +#define WDC_DRIVE_CAP_OCP_C1_LOG_PAGE 0x0000002000000000 +#define WDC_DRIVE_CAP_OCP_C4_LOG_PAGE 0x0000004000000000 +#define WDC_DRIVE_CAP_OCP_C5_LOG_PAGE 0x0000008000000000 +#define WDC_DRIVE_CAP_DEVICE_WAF 0x0000010000000000 +#define WDC_DRIVE_CAP_SET_LATENCY_MONITOR 0x0000020000000000 + +#define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C0_LOG_PAGE | \ + WDC_DRIVE_CAP_C1_LOG_PAGE | \ + WDC_DRIVE_CAP_CA_LOG_PAGE | \ + WDC_DRIVE_CAP_D0_LOG_PAGE) +#define WDC_DRIVE_CAP_CLEAR_PCIE_MASK (WDC_DRIVE_CAP_CLEAR_PCIE | \ + WDC_DRIVE_CAP_VUC_CLEAR_PCIE | \ + WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE) #define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK (WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | \ - WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) + WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2) #define WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | \ - WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY) -#define WDC_DRIVE_CAP_INTERNAL_LOG_MASK (WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_DUI | \ - WDC_DRIVE_CAP_DUI_DATA | WDC_SN730B_CAP_VUC_LOG) + WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY) +#define WDC_DRIVE_CAP_INTERNAL_LOG_MASK (WDC_DRIVE_CAP_INTERNAL_LOG | \ + WDC_DRIVE_CAP_DUI | \ + WDC_DRIVE_CAP_DUI_DATA | \ + WDC_SN730B_CAP_VUC_LOG) + /* SN730 Get Log Capabilities */ #define SN730_NVME_GET_LOG_OPCODE 0xc2 #define SN730_GET_FULL_LOG_LENGTH 0x00080009 @@ -168,9 +212,9 @@ #define SN730_LOG_CHUNK_SIZE 0x1000 /* Customer ID's */ -#define WDC_CUSTOMER_ID_GN 0x0001 -#define WDC_CUSTOMER_ID_GD 0x0101 -#define WDC_CUSTOMER_ID_BD 0x1009 +#define WDC_CUSTOMER_ID_GN 0x0001 +#define WDC_CUSTOMER_ID_GD 0x0101 +#define WDC_CUSTOMER_ID_BD 0x1009 #define WDC_CUSTOMER_ID_0x1005 0x1005 @@ -179,27 +223,27 @@ #define WDC_CUSTOMER_ID_0x1304 0x1304 #define WDC_INVALID_CUSTOMER_ID -1 -#define WDC_ALL_PAGE_MASK 0xFFFF -#define WDC_C0_PAGE_MASK 0x0001 -#define WDC_C1_PAGE_MASK 0x0002 -#define WDC_CA_PAGE_MASK 0x0004 -#define WDC_D0_PAGE_MASK 0x0008 +#define WDC_ALL_PAGE_MASK 0xFFFF +#define WDC_C0_PAGE_MASK 0x0001 +#define WDC_C1_PAGE_MASK 0x0002 +#define WDC_CA_PAGE_MASK 0x0004 +#define WDC_D0_PAGE_MASK 0x0008 /* Drive Resize */ #define WDC_NVME_DRIVE_RESIZE_OPCODE 0xCC #define WDC_NVME_DRIVE_RESIZE_CMD 0x03 #define WDC_NVME_DRIVE_RESIZE_SUBCMD 0x01 -/* Namespace Resize */ -#define WDC_NVME_NAMESPACE_RESIZE_OPCODE 0xFB +/* 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 +#define WDC_NVME_DRIVE_INFO_OPCODE 0xC6 +#define WDC_NVME_DRIVE_INFO_CMD 0x22 +#define WDC_NVME_DRIVE_INFO_SUBCMD 0x06 /* VS PCIE Stats */ -#define WDC_NVME_PCIE_STATS_OPCODE 0xD1 +#define WDC_NVME_PCIE_STATS_OPCODE 0xD1 /* Capture Diagnostics */ #define WDC_NVME_CAP_DIAG_HEADER_TOC_SIZE WDC_NVME_LOG_SIZE_DATA_LEN @@ -214,19 +258,19 @@ /* 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_CAP_DUI_DISABLE_IO 0x01 #define WDC_NVME_DUI_MAX_SECTION 0x3A #define WDC_NVME_DUI_MAX_SECTION_V2 0x26 #define WDC_NVME_DUI_MAX_SECTION_V3 0x23 #define WDC_NVME_DUI_MAX_DATA_AREA 0x05 -#define WDC_NVME_SN730_SECTOR_SIZE 512 +#define WDC_NVME_SN730_SECTOR_SIZE 512 -/* Telemtery types for vs-internal-log command */ -#define WDC_TELEMETRY_TYPE_NONE 0x0 -#define WDC_TELEMETRY_TYPE_HOST 0x1 -#define WDC_TELEMETRY_TYPE_CONTROLLER 0x2 -#define WDC_TELEMETRY_HEADER_LENGTH 512 -#define WDC_TELEMETRY_BLOCK_SIZE 512 +/* 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 @@ -281,7 +325,7 @@ #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_OPCODE 0xC6 #define WDC_NVME_CLEAR_FW_ACT_HIST_CMD 0x23 #define WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD 0x05 #define WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID 0xC1 @@ -293,11 +337,11 @@ #define WDC_NVME_GET_STAT_PERF_INTERVAL_LIFETIME 0x0F /* C2 Log Page */ -#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE 0xC2 -#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 0xC8 +#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID 0xC2 +#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8 0xC8 #define WDC_C2_LOG_BUF_LEN 0x1000 #define WDC_C2_LOG_PAGES_SUPPORTED_ID 0x08 -#define WDC_C2_CUSTOMER_ID_ID 0x15 +#define WDC_C2_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 @@ -318,69 +362,72 @@ /* 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 0xA0 /* Added 4 padding bytes to resolve build warning messages */ +#define WDC_FB_CA_LOG_BUF_LEN 0x80 +/* Added 4 padding bytes to resolve build warning messages */ +#define WDC_BD_CA_LOG_BUF_LEN 0xA0 /* C0 EOL Status Log Page */ #define WDC_NVME_GET_EOL_STATUS_LOG_OPCODE 0xC0 -#define WDC_NVME_EOL_STATUS_LOG_LEN 0x200 +#define WDC_NVME_EOL_STATUS_LOG_LEN 0x200 #define WDC_NVME_SMART_CLOUD_ATTR_LEN 0x200 /* C0 SMART Cloud Attributes Log Page*/ -#define WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID 0xC0 +#define WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID 0xC0 /* CB - FW Activate History Log Page */ -#define WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID 0xCB -#define WDC_FW_ACT_HISTORY_LOG_BUF_LEN 0x3d0 +#define WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID 0xCB +#define WDC_FW_ACT_HISTORY_LOG_BUF_LEN 0x3d0 /* C2 - FW Activation History Log Page */ -#define WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID 0xC2 -#define WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN 0x1000 -#define WDC_MAX_NUM_ACT_HIST_ENTRIES 20 -#define WDC_C2_GUID_LENGTH 16 +#define WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID 0xC2 +#define WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN 0x1000 +#define WDC_MAX_NUM_ACT_HIST_ENTRIES 20 +#define WDC_C2_GUID_LENGTH 16 /* C3 Latency Monitor Log Page */ -#define WDC_LATENCY_MON_LOG_BUF_LEN 0x200 -#define WDC_LATENCY_MON_LOG_ID 0xC3 -#define WDC_LATENCY_MON_VERSION 0x0001 - -#define WDC_C3_GUID_LENGTH 16 -static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = { 0x92, 0x7a, 0xc0, 0x8c, 0xd0, 0x84, 0x6c, 0x9c, - 0x70, 0x43, 0xe6, 0xd4, 0x58, 0x5e, 0xd4, 0x85 }; +#define WDC_LATENCY_MON_LOG_BUF_LEN 0x200 +#define WDC_LATENCY_MON_LOG_ID 0xC3 +#define WDC_LATENCY_MON_VERSION 0x0001 + +#define WDC_C3_GUID_LENGTH 16 +static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = { + 0x92, 0x7a, 0xc0, 0x8c, 0xd0, 0x84, 0x6c, 0x9c, + 0x70, 0x43, 0xe6, 0xd4, 0x58, 0x5e, 0xd4, 0x85 +}; /* D0 Smart Log Page */ #define WDC_NVME_GET_VU_SMART_LOG_OPCODE 0xD0 -#define WDC_NVME_VU_SMART_LOG_LEN 0x200 - -/* Log Page Directory defines */ -#define NVME_LOG_PERSISTENT_EVENT 0x0D -#define WDC_LOG_ID_C0 0xC0 -#define WDC_LOG_ID_C1 0xC1 -#define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE -#define WDC_LOG_ID_C3 0xC3 -#define WDC_LOG_ID_C4 0xC4 -#define WDC_LOG_ID_C5 0xC5 -#define WDC_LOG_ID_C6 0xC6 -#define WDC_LOG_ID_C8 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 -#define WDC_LOG_ID_CA WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE -#define WDC_LOG_ID_CB WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID -#define WDC_LOG_ID_D0 WDC_NVME_GET_VU_SMART_LOG_OPCODE -#define WDC_LOG_ID_D1 0xD1 -#define WDC_LOG_ID_D6 0xD6 -#define WDC_LOG_ID_D7 0xD7 -#define WDC_LOG_ID_D8 0xD8 -#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 +#define WDC_NVME_VU_SMART_LOG_LEN 0x200 + +/* Log Page Directory defines */ +#define NVME_LOG_PERSISTENT_EVENT 0x0D +#define WDC_LOG_ID_C0 0xC0 +#define WDC_LOG_ID_C1 0xC1 +#define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID +#define WDC_LOG_ID_C3 0xC3 +#define WDC_LOG_ID_C4 0xC4 +#define WDC_LOG_ID_C5 0xC5 +#define WDC_LOG_ID_C6 0xC6 +#define WDC_LOG_ID_C8 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8 +#define WDC_LOG_ID_CA WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE +#define WDC_LOG_ID_CB WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID +#define WDC_LOG_ID_D0 WDC_NVME_GET_VU_SMART_LOG_OPCODE +#define WDC_LOG_ID_D1 0xD1 +#define WDC_LOG_ID_D6 0xD6 +#define WDC_LOG_ID_D7 0xD7 +#define WDC_LOG_ID_D8 0xD8 +#define WDC_LOG_ID_DE 0xDE +#define WDC_LOG_ID_F0 0xF0 +#define WDC_LOG_ID_F1 0xF1 +#define WDC_LOG_ID_F2 0xF2 +#define WDC_LOG_ID_FA 0xFA /* Clear PCIe Correctable Errors */ -#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE -#define WDC_NVME_CLEAR_PCIE_CORR_CMD 0x22 -#define WDC_NVME_CLEAR_PCIE_CORR_SUBCMD 0x04 -#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE_VUC 0xD2 -#define WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID 0xC3 +#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE +#define WDC_NVME_CLEAR_PCIE_CORR_CMD 0x22 +#define WDC_NVME_CLEAR_PCIE_CORR_SUBCMD 0x04 +#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE_VUC 0xD2 +#define WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID 0xC3 /* Clear Assert Dump Status */ #define WDC_NVME_CLEAR_ASSERT_DUMP_OPCODE 0xD8 #define WDC_NVME_CLEAR_ASSERT_DUMP_CMD 0x03 @@ -420,52 +467,76 @@ static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = { 0x92, 0x7a, 0xc0, 0x8c, #define WDC_DE_DESTN_SPI 1 #define WDC_DE_DUMPTRACE_DESTINATION 6 -#define NVME_ID_CTRL_MODEL_NUMBER_SIZE 40 -#define NVME_ID_CTRL_SERIAL_NUMBER_SIZE 20 +#define NVME_ID_CTRL_MODEL_NUMBER_SIZE 40 +#define NVME_ID_CTRL_SERIAL_NUMBER_SIZE 20 /* Enclosure log */ -#define WDC_NVME_ENC_LOG_SIZE_CHUNK 0x1000 -#define WDC_NVME_ENC_NIC_LOG_SIZE 0x400000 +#define WDC_NVME_ENC_LOG_SIZE_CHUNK 0x1000 +#define WDC_NVME_ENC_NIC_LOG_SIZE 0x400000 /* Enclosure nic crash dump get-log id */ -#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_1 0xD1 -#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_2 0xD2 -#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_3 0xD3 -#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_4 0xD4 -#define WDC_ENC_CRASH_DUMP_ID 0xE4 -#define WDC_ENC_LOG_DUMP_ID 0xE2 - -typedef enum _NVME_FEATURES_SELECT -{ - FS_CURRENT = 0, - 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 -{ +#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_1 0xD1 +#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_2 0xD2 +#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_3 0xD3 +#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_4 0xD4 +#define WDC_ENC_CRASH_DUMP_ID 0xE4 +#define WDC_ENC_LOG_DUMP_ID 0xE2 + +/* OCP Log Page Directory Data Structure */ +#define BYTE_TO_BIT(byte) ((byte) * 8) + +/* Set latency monitor feature */ +#define NVME_FEAT_OCP_LATENCY_MONITOR 0xC5 + +enum _NVME_FEATURES_SELECT { + FS_CURRENT = 0, + FS_DEFAULT = 1, + FS_SAVED = 2, + FS_SUPPORTED_CAPBILITIES = 3 +}; + +enum NVME_FEATURE_IDENTIFIERS { + FID_ARBITRATION = 0x01, + FID_POWER_MANAGEMENT = 0x02, + FID_LBA_RANGE_TYPE = 0x03, + FID_TEMPERATURE_THRESHOLD = 0x04, + FID_ERROR_RECOVERY = 0x05, + FID_VOLATILE_WRITE_CACHE = 0x06, + FID_NUMBER_OF_QUEUES = 0x07, + FID_INTERRUPT_COALESCING = 0x08, + FID_INTERRUPT_VECTOR_CONFIGURATION = 0x09, + FID_WRITE_ATOMICITY = 0x0A, + FID_ASYNCHRONOUS_EVENT_CONFIGURATION = 0x0B, + FID_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C, + /*Below FID's are NVM Command Set Specific*/ + FID_SOFTWARE_PROGRESS_MARKER = 0x80, + FID_HOST_IDENTIFIER = 0x81, + FID_RESERVATION_NOTIFICATION_MASK = 0x82, + FID_RESERVATION_PERSISTENCE = 0x83 +}; + +/* WDC UUID value */ +const uint8_t WDC_UUID[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0xb9, 0x8c, 0x52, 0x0c, 0x4c, + 0x5a, 0x15, 0xab, 0xe6, 0x33, 0x29, 0x9a, 0x70, 0xdf, 0xd0 +}; + +/* WDC_UUID value for SN640_3 devices */ +const uint8_t WDC_UUID_SN640_3[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 +}; + +/* UUID field with value of 0 indicates end of UUID List*/ +const uint8_t UUID_END[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +enum WDC_DRIVE_ESSENTIAL_TYPE { WDC_DE_TYPE_IDENTIFY = 0x1, WDC_DE_TYPE_SMARTATTRIBUTEDUMP = 0x2, WDC_DE_TYPE_EVENTLOG = 0x4, @@ -493,13 +564,12 @@ typedef enum WDC_DE_TYPE_NVME_MANF_INFO = 0x2000000, WDC_DE_TYPE_NONE = 0x1000000, WDC_DE_TYPE_ALL = 0xFFFFFFF, -} WDC_DRIVE_ESSENTIAL_TYPE; +}; #define WDC_C0_GUID_LENGTH 16 #define WDC_SCA_V1_NAND_STATS 0x1 #define WDC_SCA_V1_ALL 0xF -typedef enum -{ +enum { SCAO_V1_PMUWT = 0, /* Physical media units written TLC */ SCAO_V1_PMUWS = 16, /* Physical media units written SLC */ SCAO_V1_BUNBN = 32, /* Bad user nand blocks normalized */ @@ -525,7 +595,7 @@ typedef enum SCAO_V1_SVN = 160, /* Security Version Number */ SCAO_V1_PFBS = 168, /* Percent free blocks (System) */ SCAO_V1_DCC = 172, /* Deallocate Commands Completed */ - SCAO_V1_TNU = 188, /* Total Namespace Utilization */ + SCAO_V1_TNU = 188, /* Total Namespace Utilization */ SCAO_V1_FCC = 196, /* Format NVM Commands Completed */ SCAO_V1_BBPG = 198, /* Background Back-Pressure Gauge */ SCAO_V1_SEEC = 202, /* Soft ECC error count */ @@ -545,18 +615,19 @@ typedef enum SCAO_V1_MIVF = 302, /* Boot SSD minor version field */ SCAO_V1_PVF = 304, /* Boot SSD point version field */ SCAO_V1_EVF = 306, /* Boot SSD errata version field */ - SCAO_V1_FTLUS = 308, /* FTL Unit Size */ + SCAO_V1_FTLUS = 308, /* FTL Unit Size */ SCAO_V1_TCGOS = 312, /* TCG Ownership Status */ SCAO_V1_LPV = 494, /* Log page version - 0x0001 */ SCAO_V1_LPG = 496, /* Log page GUID */ -} SMART_CLOUD_ATTRIBUTE_OFFSETS_V1; +}; -static __u8 ext_smart_guid[WDC_C0_GUID_LENGTH] = { 0x65, 0x43, 0x88, 0x78, 0xAC, 0xD8, 0x78, 0xA1, - 0x66, 0x42, 0x1E, 0x0F, 0x92, 0xD7, 0x6D, 0xC4 }; +static __u8 ext_smart_guid[WDC_C0_GUID_LENGTH] = { + 0x65, 0x43, 0x88, 0x78, 0xAC, 0xD8, 0x78, 0xA1, + 0x66, 0x42, 0x1E, 0x0F, 0x92, 0xD7, 0x6D, 0xC4 +}; -typedef struct __attribute__((__packed__)) wdc_nvme_ext_smart_log -{ +struct __packed wdc_nvme_ext_smart_log { __u8 ext_smart_pmuwt[16]; /* 000 Physical media units written TLC */ __u8 ext_smart_pmuws[16]; /* 016 Physical media units written SLC */ __u8 ext_smart_bunbc[8]; /* 032 Bad user nand block count */ @@ -573,8 +644,8 @@ typedef struct __attribute__((__packed__)) wdc_nvme_ext_smart_log __u64 ext_smart_mnec; /* 108 Min Erase counts (SLC) */ __u64 ext_smart_mxec; /* 116 Max Erase counts (SLC) */ __u64 ext_smart_avec; /* 124 Average Erase counts (SLC) */ - __u8 ext_smart_pfc[8]; /* 132 Program fail count */ - __u8 ext_smart_efc[8]; /* 140 Erase fail count */ + __u8 ext_smart_pfc[8]; /* 132 Program fail count */ + __u8 ext_smart_efc[8]; /* 140 Erase fail count */ __u64 ext_smart_pcec; /* 148 PCIe correctable error count */ __u8 ext_smart_pfbu; /* 156 Percent free blocks (User) */ __u8 ext_smart_rsvd2[3]; /* 157 reserved */ @@ -582,17 +653,17 @@ typedef struct __attribute__((__packed__)) wdc_nvme_ext_smart_log __u8 ext_smart_pfbs; /* 168 Percent free blocks (System) */ __u8 ext_smart_rsvd3[3]; /* 169 reserved */ __u8 ext_smart_dcc[16]; /* 172 Deallocate Commands Completed */ - __u64 ext_smart_tnu; /* 188 Total Namespace Utilization */ - __u16 ext_smart_fcc; /* 196 Format NVM Commands Completed */ + __u64 ext_smart_tnu; /* 188 Total Namespace Utilization */ + __u16 ext_smart_fcc; /* 196 Format NVM Commands Completed */ __u8 ext_smart_bbpg; /* 198 Background Back-Pressure Gauge */ __u8 ext_smart_rsvd4[3]; /* 199 reserved */ __u64 ext_smart_seec; /* 202 Soft ECC error count */ __u64 ext_smart_rfsc; /* 210 Refresh count */ __u8 ext_smart_bsnbc[8]; /* 218 Bad system nand block count */ __u8 ext_smart_eest[16]; /* 226 Endurance estimate */ - __u16 ext_smart_ttc; /* 242 Thermal throttling count */ + __u16 ext_smart_ttc; /* 242 Thermal throttling count */ __u64 ext_smart_uio; /* 244 Unaligned I/O */ - __u8 ext_smart_pmur[16]; /* 252 Physical media units read */ + __u8 ext_smart_pmur[16]; /* 252 Physical media units read */ __u32 ext_smart_rtoc; /* 268 Read command timeout count */ __u32 ext_smart_wtoc; /* 272 Write command timeout count */ __u32 ext_smart_ttoc; /* 276 Trim command timeout count */ @@ -601,144 +672,202 @@ typedef struct __attribute__((__packed__)) wdc_nvme_ext_smart_log __u64 ext_smart_pscc; /* 292 Power State Change Count */ __u16 ext_smart_maj; /* 300 Boot SSD major version field */ __u16 ext_smart_min; /* 302 Boot SSD minor version field */ - __u16 ext_smart_pt; /* 304 Boot SSD point version field */ + __u16 ext_smart_pt; /* 304 Boot SSD point version field */ __u16 ext_smart_err; /* 306 Boot SSD errata version field */ - __u32 ext_smart_ftlus; /* 308 FTL Unit Size */ + __u32 ext_smart_ftlus; /* 308 FTL Unit Size */ __u32 ext_smart_tcgos; /* 312 TCG Ownership Status */ __u8 ext_smart_rsvd6[178]; /* 316 reserved */ __u16 ext_smart_lpv; /* 494 Log page version - 0x0001 */ __u8 ext_smart_lpg[16]; /* 496 Log page GUID */ -} wdc_nvme_ext_smart_log; - -typedef enum -{ - SCAO_PMUW = 0, /* Physical media units written */ - SCAO_PMUR = 16, /* Physical media units read */ - SCAO_BUNBR = 32, /* Bad user nand blocks raw */ - SCAO_BUNBN = 38, /* Bad user nand blocks normalized */ - SCAO_BSNBR = 40, /* Bad system nand blocks raw */ - SCAO_BSNBN = 46, /* Bad system nand blocks normalized */ - SCAO_XRC = 48, /* XOR recovery count */ - SCAO_UREC = 56, /* Uncorrectable read error count */ - SCAO_SEEC = 64, /* Soft ecc error count */ - SCAO_EECE = 72, /* End to end corrected errors */ - SCAO_EEDC = 76, /* End to end detected errors */ - SCAO_SDPU = 80, /* System data percent used */ - SCAO_RFSC = 81, /* Refresh counts */ - SCAO_MXUDEC = 88, /* Max User data erase counts */ - SCAO_MNUDEC = 92, /* Min User data erase counts */ - SCAO_NTTE = 96, /* Number of Thermal throttling events */ - SCAO_CTS = 97, /* Current throttling status */ - SCAO_EVF = 98, /* Errata Version Field */ - SCAO_PVF = 99, /* Point Version Field */ - SCAO_MIVF = 101, /* Minor Version Field */ - SCAO_MAVF = 103, /* Major Version Field */ - SCAO_PCEC = 104, /* PCIe correctable error count */ - SCAO_ICS = 112, /* Incomplete shutdowns */ - SCAO_PFB = 120, /* Percent free blocks */ - SCAO_CPH = 128, /* Capacitor health */ - SCAO_NEV = 130, /* NVMe Errata Version */ - SCAO_UIO = 136, /* Unaligned I/O */ - SCAO_SVN = 144, /* Security Version Number */ - SCAO_NUSE = 152, /* NUSE - Namespace utilization */ - SCAO_PSC = 160, /* PLP start count */ - SCAO_EEST = 176, /* Endurance estimate */ - SCAO_PLRC = 192, /* PCIe Link Retraining Count */ - SCAO_PSCC = 200, /* Power State Change Count */ - SCAO_LPV = 494, /* Log page version */ - SCAO_LPG = 496, /* Log page GUID */ -} SMART_CLOUD_ATTRIBUTE_OFFSETS_V3; - -static __u8 scao_guid[WDC_C0_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4, - 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF }; - -typedef enum -{ - EOL_RBC = 76, /* Realloc Block Count */ - EOL_ECCR = 80, /* ECC Rate */ - EOL_WRA = 84, /* Write Amp */ - EOL_PLR = 88, /* Percent Life Remaining */ - EOL_RSVBC = 92, /* Reserved Block Count */ - EOL_PFC = 96, /* Program Fail Count */ - EOL_EFC = 100, /* Erase Fail Count */ - EOL_RRER = 108, /* Raw Read Error Rate */ -} EOL_LOG_PAGE_C0_OFFSETS; +}; + +enum { + SCAO_PMUW = 0, /* Physical media units written */ + SCAO_PMUR = 16, /* Physical media units read */ + SCAO_BUNBR = 32, /* Bad user nand blocks raw */ + SCAO_BUNBN = 38, /* Bad user nand blocks normalized */ + SCAO_BSNBR = 40, /* Bad system nand blocks raw */ + SCAO_BSNBN = 46, /* Bad system nand blocks normalized */ + SCAO_XRC = 48, /* XOR recovery count */ + SCAO_UREC = 56, /* Uncorrectable read error count */ + SCAO_SEEC = 64, /* Soft ecc error count */ + SCAO_EECE = 72, /* End to end corrected errors */ + SCAO_EEDC = 76, /* End to end detected errors */ + SCAO_SDPU = 80, /* System data percent used */ + SCAO_RFSC = 81, /* Refresh counts */ + SCAO_MXUDEC = 88, /* Max User data erase counts */ + SCAO_MNUDEC = 92, /* Min User data erase counts */ + SCAO_NTTE = 96, /* Number of Thermal throttling events */ + SCAO_CTS = 97, /* Current throttling status */ + SCAO_EVF = 98, /* Errata Version Field */ + SCAO_PVF = 99, /* Point Version Field */ + SCAO_MIVF = 101, /* Minor Version Field */ + SCAO_MAVF = 103, /* Major Version Field */ + SCAO_PCEC = 104, /* PCIe correctable error count */ + SCAO_ICS = 112, /* Incomplete shutdowns */ + SCAO_PFB = 120, /* Percent free blocks */ + SCAO_CPH = 128, /* Capacitor health */ + SCAO_NEV = 130, /* NVMe Errata Version */ + SCAO_UIO = 136, /* Unaligned I/O */ + SCAO_SVN = 144, /* Security Version Number */ + SCAO_NUSE = 152, /* NUSE - Namespace utilization */ + SCAO_PSC = 160, /* PLP start count */ + SCAO_EEST = 176, /* Endurance estimate */ + SCAO_PLRC = 192, /* PCIe Link Retraining Count */ + SCAO_PSCC = 200, /* Power State Change Count */ + SCAO_LPV = 494, /* Log page version */ + SCAO_LPG = 496, /* Log page GUID */ +}; + +struct ocp_bad_nand_block_count { + __u64 raw : 48; + __u16 normalized : 16; +}; + +struct ocp_e2e_correction_count { + __u32 detected; + __u32 corrected; +}; + +struct ocp_user_data_erase_count { + __u32 maximum; + __u32 minimum; +}; + +struct ocp_thermal_status { + __u8 num_events; + __u8 current_status; +}; + +struct __packed ocp_dssd_specific_ver { + __u8 errata_ver; + __u16 point_ver; + __u16 minor_ver; + __u8 major_ver; +}; + +struct ocp_cloud_smart_log { + __u8 physical_media_units_written[16]; + __u8 physical_media_units_read[16]; + struct ocp_bad_nand_block_count bad_user_nand_blocks; + struct ocp_bad_nand_block_count bad_system_nand_blocks; + __u64 xor_recovery_count; + __u64 uncorrectable_read_error_count; + __u64 soft_ecc_error_count; + struct ocp_e2e_correction_count e2e_correction_counts; + __u8 system_data_percent_used; + __u64 refresh_counts : 56; + struct ocp_user_data_erase_count user_data_erase_counts; + struct ocp_thermal_status thermal_status; + struct ocp_dssd_specific_ver dssd_specific_ver; + __u64 pcie_correctable_error_count; + __u32 incomplete_shutdowns; + __u8 rsvd116[4]; + __u8 percent_free_blocks; + __u8 rsvd121[7]; + __u16 capacitor_health; + __u8 nvme_errata_ver; + __u8 rsvd131[5]; + __u64 unaligned_io; + __u64 security_version_number; + __u64 total_nuse; + __u8 plp_start_count[16]; + __u8 endurance_estimate[16]; + __u64 pcie_link_retraining_cnt; + __u64 power_state_change_cnt; + __u8 rsvd208[286]; + __u16 log_page_version; + __u8 log_page_guid[16]; +}; + +static __u8 scao_guid[WDC_C0_GUID_LENGTH] = { + 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4, + 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF +}; + +enum { + EOL_RBC = 76, /* Realloc Block Count */ + EOL_ECCR = 80, /* ECC Rate */ + EOL_WRA = 84, /* Write Amp */ + EOL_PLR = 88, /* Percent Life Remaining */ + EOL_RSVBC = 92, /* Reserved Block Count */ + EOL_PFC = 96, /* Program Fail Count */ + EOL_EFC = 100, /* Erase Fail Count */ + EOL_RRER = 108, /* Raw Read Error Rate */ +}; #define WDC_NVME_C6_GUID_LENGTH 16 #define WDC_NVME_GET_HW_REV_LOG_OPCODE 0xc6 #define WDC_NVME_HW_REV_LOG_PAGE_LEN 512 -typedef struct __attribute__((__packed__)) wdc_nvme_hw_rev_log -{ - __u8 hw_rev_gdr; /* 0 Global Device HW Revision */ - __u8 hw_rev_ar; /* 1 ASIC HW Revision */ - __u8 hw_rev_pbc_mc; /* 2 PCB Manufacturer Code */ - __u8 hw_rev_dram_mc; /* 3 DRAM Manufacturer Code */ - __u8 hw_rev_nand_mc; /* 4 NAND Manufacturer Code */ - __u8 hw_rev_pmic1_mc; /* 5 PMIC 1 Manufacturer Code */ - __u8 hw_rev_pmic2_mc; /* 6 PMIC 2 Manufacturer Code */ - __u8 hw_rev_c1_mc; /* 7 Other Component 1 Manf Code */ - __u8 hw_rev_c2_mc; /* 8 Other Component 2 Manf Code */ - __u8 hw_rev_c3_mc; /* 9 Other Component 3 Manf Code */ - __u8 hw_rev_c4_mc; /* 10 Other Component 4 Manf Code */ - __u8 hw_rev_c5_mc; /* 11 Other Component 5 Manf Code */ - __u8 hw_rev_c6_mc; /* 12 Other Component 6 Manf Code */ - __u8 hw_rev_c7_mc; /* 13 Other Component 7 Manf Code */ - __u8 hw_rev_c8_mc; /* 14 Other Component 8 Manf Code */ - __u8 hw_rev_c9_mc; /* 15 Other Component 9 Manf Code */ - __u8 hw_rev_rsrvd1[48]; /* 16 Reserved 48 bytes */ - __u8 hw_rev_dev_mdi[16]; /* 64 Device Manf Detailed Info */ - __u8 hw_rev_asic_di[16]; /* 80 ASIC Detailed Info */ - __u8 hw_rev_pcb_di[16]; /* 96 PCB Detailed Info */ - __u8 hw_rev_dram_di[16]; /* 112 DRAM Detailed Info */ - __u8 hw_rev_nand_di[16]; /* 128 NAND Detailed Info */ - __u8 hw_rev_pmic1_di[16]; /* 144 PMIC1 Detailed Info */ - __u8 hw_rev_pmic2_di[16]; /* 160 PMIC2 Detailed Info */ - __u8 hw_rev_c1_di[16]; /* 176 Component 1 Detailed Info */ - __u8 hw_rev_c2_di[16]; /* 192 Component 2 Detailed Info */ - __u8 hw_rev_c3_di[16]; /* 208 Component 3 Detailed Info */ - __u8 hw_rev_c4_di[16]; /* 224 Component 4 Detailed Info */ - __u8 hw_rev_c5_di[16]; /* 240 Component 5 Detailed Info */ - __u8 hw_rev_c6_di[16]; /* 256 Component 6 Detailed Info */ - __u8 hw_rev_c7_di[16]; /* 272 Component 7 Detailed Info */ - __u8 hw_rev_c8_di[16]; /* 288 Component 8 Detailed Info */ - __u8 hw_rev_c9_di[16]; /* 304 Component 9 Detailed Info */ - __u8 hw_rev_sn[32]; /* 320 Serial Number */ - __u8 hw_rev_rsrvd2[142]; /* 352 Reserved 143 bytes */ - __u16 hw_rev_version; /* 494 Log Page Version */ - __u8 hw_rev_guid[16]; /* 496 Log Page GUID */ -} wdc_nvme_hw_rev_log; - -static __u8 hw_rev_log_guid[WDC_NVME_C6_GUID_LENGTH] = { 0xAA, 0xB0, 0x05, 0xF5, 0x13, 0x5E, 0x48, 0x15, - 0xAB, 0x89, 0x05, 0xBA, 0x8B, 0xE2, 0xBF, 0x3C }; - -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 { +struct __packed wdc_nvme_hw_rev_log { + __u8 hw_rev_gdr; /* 0 Global Device HW Revision */ + __u8 hw_rev_ar; /* 1 ASIC HW Revision */ + __u8 hw_rev_pbc_mc; /* 2 PCB Manufacturer Code */ + __u8 hw_rev_dram_mc; /* 3 DRAM Manufacturer Code */ + __u8 hw_rev_nand_mc; /* 4 NAND Manufacturer Code */ + __u8 hw_rev_pmic1_mc; /* 5 PMIC 1 Manufacturer Code */ + __u8 hw_rev_pmic2_mc; /* 6 PMIC 2 Manufacturer Code */ + __u8 hw_rev_c1_mc; /* 7 Other Component 1 Manf Code */ + __u8 hw_rev_c2_mc; /* 8 Other Component 2 Manf Code */ + __u8 hw_rev_c3_mc; /* 9 Other Component 3 Manf Code */ + __u8 hw_rev_c4_mc; /* 10 Other Component 4 Manf Code */ + __u8 hw_rev_c5_mc; /* 11 Other Component 5 Manf Code */ + __u8 hw_rev_c6_mc; /* 12 Other Component 6 Manf Code */ + __u8 hw_rev_c7_mc; /* 13 Other Component 7 Manf Code */ + __u8 hw_rev_c8_mc; /* 14 Other Component 8 Manf Code */ + __u8 hw_rev_c9_mc; /* 15 Other Component 9 Manf Code */ + __u8 hw_rev_rsrvd1[48]; /* 16 Reserved 48 bytes */ + __u8 hw_rev_dev_mdi[16]; /* 64 Device Manf Detailed Info */ + __u8 hw_rev_asic_di[16]; /* 80 ASIC Detailed Info */ + __u8 hw_rev_pcb_di[16]; /* 96 PCB Detailed Info */ + __u8 hw_rev_dram_di[16]; /* 112 DRAM Detailed Info */ + __u8 hw_rev_nand_di[16]; /* 128 NAND Detailed Info */ + __u8 hw_rev_pmic1_di[16]; /* 144 PMIC1 Detailed Info */ + __u8 hw_rev_pmic2_di[16]; /* 160 PMIC2 Detailed Info */ + __u8 hw_rev_c1_di[16]; /* 176 Component 1 Detailed Info */ + __u8 hw_rev_c2_di[16]; /* 192 Component 2 Detailed Info */ + __u8 hw_rev_c3_di[16]; /* 208 Component 3 Detailed Info */ + __u8 hw_rev_c4_di[16]; /* 224 Component 4 Detailed Info */ + __u8 hw_rev_c5_di[16]; /* 240 Component 5 Detailed Info */ + __u8 hw_rev_c6_di[16]; /* 256 Component 6 Detailed Info */ + __u8 hw_rev_c7_di[16]; /* 272 Component 7 Detailed Info */ + __u8 hw_rev_c8_di[16]; /* 288 Component 8 Detailed Info */ + __u8 hw_rev_c9_di[16]; /* 304 Component 9 Detailed Info */ + __u8 hw_rev_sn[32]; /* 320 Serial Number */ + __u8 hw_rev_rsrvd2[142]; /* 352 Reserved 143 bytes */ + __u16 hw_rev_version; /* 494 Log Page Version */ + __u8 hw_rev_guid[16]; /* 496 Log Page GUID */ +}; + +static __u8 hw_rev_log_guid[WDC_NVME_C6_GUID_LENGTH] = { + 0xAA, 0xB0, 0x05, 0xF5, 0x13, 0x5E, 0x48, 0x15, + 0xAB, 0x89, 0x05, 0xBA, 0x8B, 0xE2, 0xBF, 0x3C +}; + +struct __packed WDC_DE_VU_FILE_META_DATA { + __u8 fileName[WDC_DE_FILE_NAME_SIZE]; + __u16 fileID; + __u64 fileSize; +}; + +struct WDC_DRIVE_ESSENTIALS { + struct __packed WDC_DE_VU_FILE_META_DATA metaData; + enum WDC_DRIVE_ESSENTIAL_TYPE essentialType; +}; + +struct WDC_DE_VU_LOG_DIRECTORY { + struct WDC_DRIVE_ESSENTIALS *logEntry; /* Caller to allocate memory */ + __u32 maxNumLogEntries; /* Caller to input memory allocated */ + __u32 numOfValidLogEntries; /* API will output this value */ +}; + +struct WDC_DE_CSA_FEATURE_ID_LIST { + enum NVME_FEATURE_IDENTIFIERS featureId; + __u8 featureName[WDC_DE_GENERIC_BUFFER_SIZE]; +}; + +struct tarfile_metadata { char fileName[MAX_PATH_LEN]; int8_t bufferFolderPath[MAX_PATH_LEN]; char bufferFolderName[MAX_PATH_LEN]; @@ -747,107 +876,133 @@ typedef struct tarfile_metadata { 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"}, + uint8_t *timeString[MAX_PATH_LEN]; }; -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; +static struct WDC_DE_CSA_FEATURE_ID_LIST deFeatureIdList[] = { + {0x00, "Dummy Placeholder"}, + {FID_ARBITRATION, "Arbitration"}, + {FID_POWER_MANAGEMENT, "PowerMgmnt"}, + {FID_LBA_RANGE_TYPE, "LbaRangeType"}, + {FID_TEMPERATURE_THRESHOLD, "TempThreshold"}, + {FID_ERROR_RECOVERY, "ErrorRecovery"}, + {FID_VOLATILE_WRITE_CACHE, "VolatileWriteCache"}, + {FID_NUMBER_OF_QUEUES, "NumOfQueues"}, + {FID_INTERRUPT_COALESCING, "InterruptCoalesing"}, + {FID_INTERRUPT_VECTOR_CONFIGURATION, "InterruptVectorConfig"}, + {FID_WRITE_ATOMICITY, "WriteAtomicity"}, + {FID_ASYNCHRONOUS_EVENT_CONFIGURATION, "AsynEventConfig"}, + {FID_AUTONOMOUS_POWER_STATE_TRANSITION, "AutonomousPowerState"}, +}; + +enum NVME_VU_DE_LOGPAGE_NAMES { + NVME_DE_LOGPAGE_E3 = 0x01, + NVME_DE_LOGPAGE_C0 = 0x02 +}; + +struct NVME_VU_DE_LOGPAGE_LIST { + enum NVME_VU_DE_LOGPAGE_NAMES logPageName; __u32 logPageId; __u32 logPageLen; char logPageIdStr[5]; -} 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; +struct WDC_NVME_DE_VU_LOGPAGES { + enum NVME_VU_DE_LOGPAGE_NAMES vuLogPageReqd; + __u32 numOfVULogPages; +}; -static NVME_VU_DE_LOGPAGE_LIST deVULogPagesList[] = -{ - { NVME_DE_LOGPAGE_E3, 0xE3, 1072, "0xe3"}, - { NVME_DE_LOGPAGE_C0, 0xC0, 512, "0xc0"} +static struct 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(struct nvme_dev *dev, char *file, size_t len, - const char *suffix); -static int wdc_create_log_file(char *file, __u8 *drive_log_data, - __u32 drive_log_length); +enum { + WDC_NVME_ADMIN_VUC_OPCODE_D2 = 0xD2, + WDC_VUC_SUBOPCODE_VS_DRIVE_INFO_D2 = 0x0000010A, + WDC_VUC_SUBOPCODE_LOG_PAGE_DIR_D2 = 0x00000105, +}; + +enum { + NVME_LOG_NS_BASE = 0x80, + NVME_LOG_VS_BASE = 0xC0, +}; + +/*drive_info struct*/ +struct ocp_drive_info { + __u32 hw_revision; + __u32 ftl_unit_size; +}; + +/*get log page directory struct*/ +struct log_page_directory { + __u64 supported_lid_bitmap; + __u64 rsvd; + __u64 supported_ns_lid_bitmap; + __u64 supported_vs_lid_bitmap; +}; + +/*set latency monitor feature */ +struct __packed feature_latency_monitor { + __u16 active_bucket_timer_threshold; + __u8 active_threshold_a; + __u8 active_threshold_b; + __u8 active_threshold_c; + __u8 active_threshold_d; + __u16 active_latency_config; + __u8 active_latency_minimum_window; + __u16 debug_log_trigger_enable; + __u8 discard_debug_log; + __u8 latency_monitor_feature_enable; + __u8 reserved[4083]; +}; + +static int wdc_get_serial_name(struct nvme_dev *dev, char *file, size_t len, const char *suffix); +static int wdc_create_log_file(char *file, __u8 *drive_log_data, __u32 drive_log_length); static int wdc_do_clear_dump(struct nvme_dev *dev, __u8 opcode, __u32 cdw12); -static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode,__u32 data_len, - __u32 cdw12, char *file, __u32 xfer_size); +static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode, __u32 data_len, __u32 cdw12, char *file, + __u32 xfer_size); static int wdc_do_crash_dump(struct nvme_dev *dev, char *file, int type); static int wdc_crash_dump(struct nvme_dev *dev, char *file, int type); static int wdc_get_crash_dump(int argc, char **argv, struct command *command, - struct plugin *plugin); + struct plugin *plugin); static int wdc_do_drive_log(struct nvme_dev *dev, char *file); -static int wdc_drive_log(int argc, char **argv, struct command *command, - struct plugin *plugin); -static const char* wdc_purge_mon_status_to_string(__u32 status); -static int wdc_purge(int argc, char **argv, - struct command *command, struct plugin *plugin); -static int wdc_purge_monitor(int argc, char **argv, - struct command *command, struct plugin *plugin); -static bool wdc_nvme_check_supported_log_page(nvme_root_t r, - struct nvme_dev *dev, __u8 log_id); +static int wdc_drive_log(int argc, char **argv, struct command *command, struct plugin *plugin); +static const char *wdc_purge_mon_status_to_string(__u32 status); +static int wdc_purge(int argc, char **argv, struct command *command, struct plugin *plugin); +static int wdc_purge_monitor(int argc, char **argv, struct command *command, struct plugin *plugin); +static bool wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *dev, __u8 log_id); static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct command *command, - struct plugin *plugin); + struct plugin *plugin); static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev, char *dir, char *key); static int wdc_drive_essentials(int argc, char **argv, struct command *command, - struct plugin *plugin); -static int wdc_drive_status(int argc, char **argv, struct command *command, - struct plugin *plugin); + 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); + struct plugin *plugin); +static int wdc_drive_resize(int argc, char **argv, struct command *command, struct plugin *plugin); static int wdc_do_drive_resize(struct nvme_dev *dev, uint64_t new_size); -static int wdc_namespace_resize(int argc, char **argv, - struct command *command, struct plugin *plugin); -static int wdc_do_namespace_resize(struct nvme_dev *dev, __u32 nsid, - __u32 op_option); -static int wdc_reason_identifier(int argc, char **argv, - struct command *command, struct plugin *plugin); +static int wdc_namespace_resize(int argc, char **argv, struct command *command, + struct plugin *plugin); +static int wdc_do_namespace_resize(struct nvme_dev *dev, __u32 nsid, __u32 op_option); +static int wdc_reason_identifier(int argc, char **argv, struct command *command, + struct plugin *plugin); static int wdc_do_get_reason_id(struct nvme_dev *dev, char *file, int log_id); static int wdc_save_reason_id(struct nvme_dev *dev, __u8 *rsn_ident, int size); static int wdc_clear_reason_id(struct nvme_dev *dev); static int wdc_log_page_directory(int argc, char **argv, struct command *command, - struct plugin *plugin); + struct plugin *plugin); static int wdc_do_drive_info(struct nvme_dev *dev, __u32 *result); -static int wdc_vs_drive_info(int argc, char **argv, struct command *command, - struct plugin *plugin); +static int wdc_vs_drive_info(int argc, char **argv, struct command *command, struct plugin *plugin); static int wdc_vs_temperature_stats(int argc, char **argv, struct command *command, - struct plugin *plugin); + struct plugin *plugin); static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r, struct nvme_dev *dev); -static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, - __u32 xfer_size, __u32 data_len, FILE *out); -static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, - int xfer_size, FILE *out, int data_id, int cdw14, int cdw15); -static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, - __u8 log_id, void **cbs_data); +static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, __u32 xfer_size, __u32 data_len, + FILE *out); +static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, int xfer_size, + FILE *out, int data_id, int cdw14, int cdw15); +static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, __u8 log_id, + void **cbs_data); static __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev); /* Drive log data size */ @@ -864,12 +1019,12 @@ struct wdc_e6_log_hdr { /* DUI log header */ struct wdc_dui_log_section { __le16 section_type; - __le16 data_area_id; + __le16 reserved; __le32 section_size; }; /* DUI log header V2 */ -struct __attribute__((__packed__)) wdc_dui_log_section_v2 { +struct __packed wdc_dui_log_section_v2 { __le16 section_type; __le16 data_area_id; __le64 section_size; @@ -892,7 +1047,7 @@ struct wdc_dui_log_hdr { __u8 log_data[40]; }; -struct __attribute__((__packed__)) wdc_dui_log_hdr_v2 { +struct __packed wdc_dui_log_hdr_v2 { __u8 telemetry_hdr[512]; __u8 hdr_version; __u8 product_id; @@ -902,7 +1057,7 @@ struct __attribute__((__packed__)) wdc_dui_log_hdr_v2 { __u8 log_data[40]; }; -struct __attribute__((__packed__)) wdc_dui_log_hdr_v3 { +struct __packed wdc_dui_log_hdr_v3 { __u8 telemetry_hdr[512]; __u8 hdr_version; __u8 product_id; @@ -913,7 +1068,7 @@ struct __attribute__((__packed__)) wdc_dui_log_hdr_v3 { __u8 log_data[40]; }; -struct __attribute__((__packed__)) wdc_dui_log_hdr_v4 { +struct __packed wdc_dui_log_hdr_v4 { __u8 telemetry_hdr[512]; __u8 hdr_version; __u8 product_id; @@ -925,17 +1080,17 @@ struct __attribute__((__packed__)) wdc_dui_log_hdr_v4 { /* 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]; + __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 */ @@ -952,21 +1107,21 @@ struct wdc_log_page_subpage_header { }; struct wdc_ssd_perf_stats { - __le64 hr_cmds; /* Host Read Commands */ - __le64 hr_blks; /* Host Read Blocks */ + __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_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 */ + __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 */ @@ -986,38 +1141,42 @@ struct wdc_c2_cbs_data { __u8 data[]; }; -struct __attribute__((__packed__)) wdc_bd_ca_log_format { +struct __packed wdc_bd_ca_log_format { __u8 field_id; __u8 reserved1[2]; __u8 normalized_value; __u8 raw_value[8]; }; -#define READ 0 -#define WRITE 1 -#define TRIM 2 -#define RESERVED 3 - -struct __attribute__((__packed__)) wdc_ssd_latency_monitor_log { - __u8 feature_status; /* 0x00 */ - __u8 rsvd1; /* 0x01 */ - __le16 active_bucket_timer; /* 0x02 */ - __le16 active_bucket_timer_threshold; /* 0x04 */ - __u8 active_threshold_a; /* 0x06 */ - __u8 active_threshold_b; /* 0x07 */ - __u8 active_threshold_c; /* 0x08 */ - __u8 active_threshold_d; /* 0x09 */ - __le16 active_latency_config; /* 0x0A */ - __u8 active_latency_min_window; /* 0x0C */ - __u8 rsvd2[0x13]; /* 0x0D */ - - __le32 active_bucket_counter[4][4] ; /* 0x20 - 0x5F */ - __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */ - __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */ - __le16 active_latency_stamp_units; /* 0xD8 */ - __u8 rsvd3[0x16]; /* 0xDA */ - - __le32 static_bucket_counter[4][4] ; /* 0xF0 - 0x12F */ +#define LATENCY_LOG_BUCKET_READ 3 +#define LATENCY_LOG_BUCKET_WRITE 2 +#define LATENCY_LOG_BUCKET_TRIM 1 +#define LATENCY_LOG_BUCKET_RESERVED 0 + +#define LATENCY_LOG_MEASURED_LAT_READ 2 +#define LATENCY_LOG_MEASURED_LAT_WRITE 1 +#define LATENCY_LOG_MEASURED_LAT_TRIM 0 + +struct __packed wdc_ssd_latency_monitor_log { + __u8 feature_status; /* 0x00 */ + __u8 rsvd1; /* 0x01 */ + __le16 active_bucket_timer; /* 0x02 */ + __le16 active_bucket_timer_threshold; /* 0x04 */ + __u8 active_threshold_a; /* 0x06 */ + __u8 active_threshold_b; /* 0x07 */ + __u8 active_threshold_c; /* 0x08 */ + __u8 active_threshold_d; /* 0x09 */ + __le16 active_latency_config; /* 0x0A */ + __u8 active_latency_min_window; /* 0x0C */ + __u8 rsvd2[0x13]; /* 0x0D */ + + __le32 active_bucket_counter[4][4]; /* 0x20 - 0x5F */ + __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */ + __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */ + __le16 active_latency_stamp_units; /* 0xD8 */ + __u8 rsvd3[0x16]; /* 0xDA */ + + __le32 static_bucket_counter[4][4] ; /* 0xF0 - 0x12F */ __le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */ __le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */ __le16 static_latency_stamp_units; /* 0x1A8 */ @@ -1035,56 +1194,56 @@ struct __attribute__((__packed__)) wdc_ssd_latency_monitor_log { __u8 log_page_guid[0x10]; /* 0x1F0 */ }; -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 __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 */ +struct __packed wdc_ssd_d0_smart_log { + __le32 smart_log_page_header; /* 0x00 - Smart Log Page Header */ + __le32 lifetime_realloc_erase_block_count; /* 0x04 - Lifetime reallocated erase block count */ + __le32 lifetime_power_on_hours; /* 0x08 - Lifetime power on hours */ + __le32 lifetime_uecc_count; /* 0x0C - Lifetime UECC count */ + __le32 lifetime_wrt_amp_factor; /* 0x10 - Lifetime write amplification factor */ + __le32 trailing_hr_wrt_amp_factor; /* 0x14 - Trailing hour write amplification factor */ + __le32 reserve_erase_block_count; /* 0x18 - Reserve erase block count */ + __le32 lifetime_program_fail_count; /* 0x1C - Lifetime program fail count */ + __le32 lifetime_block_erase_fail_count; /* 0x20 - Lifetime block erase fail count */ + __le32 lifetime_die_failure_count; /* 0x24 - Lifetime die failure count */ + __le32 lifetime_link_rate_downgrade_count; /* 0x28 - Lifetime link rate downgrade count */ + __le32 lifetime_clean_shutdown_count; /* 0x2C - Lifetime clean shutdown count on power loss */ + __le32 lifetime_unclean_shutdown_count; /* 0x30 - Lifetime unclean shutdowns on power loss */ + __le32 current_temp; /* 0x34 - Current temperature */ + __le32 max_recorded_temp; /* 0x38 - Max recorded temperature */ + __le32 lifetime_retired_block_count; /* 0x3C - Lifetime retired block count */ + __le32 lifetime_read_disturb_realloc_events; /* 0x40 - Lifetime read disturb reallocation events */ + __le64 lifetime_nand_writes; /* 0x44 - Lifetime NAND write Lpages */ + __le32 capacitor_health; /* 0x4C - Capacitor health */ + __le64 lifetime_user_writes; /* 0x50 - Lifetime user writes */ + __le64 lifetime_user_reads; /* 0x58 - Lifetime user reads */ + __le32 lifetime_thermal_throttle_act; /* 0x60 - Lifetime thermal throttle activations */ + __le32 percentage_pe_cycles_remaining; /* 0x64 - Percentage of P/E cycles remaining */ + __u8 rsvd[408]; /* 0x68 - 408 Reserved bytes */ }; #define WDC_OCP_C1_GUID_LENGTH 16 @@ -1093,29 +1252,29 @@ struct __attribute__((__packed__)) wdc_ssd_d0_smart_log { #define WDC_ERROR_REC_LOG_VERSION1 0001 #define WDC_ERROR_REC_LOG_VERSION2 0002 -struct __attribute__((__packed__)) wdc_ocp_c1_error_recovery_log { - __le16 panic_reset_wait_time; /* 000 - Panic Reset Wait Time */ - __u8 panic_reset_action; /* 002 - Panic Reset Action */ - __u8 dev_recovery_action1; /* 003 - Device Recovery Action 1 */ - __le64 panic_id; /* 004 - Panic ID */ - __le32 dev_capabilities; /* 012 - Device Capabilities */ - __u8 vs_recovery_opc; /* 016 - Vendor Specific Recovery Opcode */ - __u8 rsvd1[3]; /* 017 - 3 Reserved Bytes */ - __le32 vs_cmd_cdw12; /* 020 - Vendor Specific Command CDW12 */ - __le32 vs_cmd_cdw13; /* 024 - Vendor Specific Command CDW13 */ - __u8 vs_cmd_to; /* 028 - Vendor Specific Command Timeout V2 */ - __u8 dev_recovery_action2; /* 029 - Device Recovery Action 2 V2 */ - __u8 dev_recovery_action2_to; /* 030 - Device Recovery Action 2 Timeout V2*/ - __u8 rsvd2[463]; /* 031 - 463 Reserved Bytes */ - __le16 log_page_version; /* 494 - Log Page Version */ - __u8 log_page_guid[WDC_OCP_C1_GUID_LENGTH]; /* 496 - Log Page GUID */ +struct __packed wdc_ocp_c1_error_recovery_log { + __le16 panic_reset_wait_time; /* 000 - Panic Reset Wait Time */ + __u8 panic_reset_action; /* 002 - Panic Reset Action */ + __u8 dev_recovery_action1; /* 003 - Device Recovery Action 1 */ + __le64 panic_id; /* 004 - Panic ID */ + __le32 dev_capabilities; /* 012 - Device Capabilities */ + __u8 vs_recovery_opc; /* 016 - Vendor Specific Recovery Opcode */ + __u8 rsvd1[3]; /* 017 - 3 Reserved Bytes */ + __le32 vs_cmd_cdw12; /* 020 - Vendor Specific Command CDW12 */ + __le32 vs_cmd_cdw13; /* 024 - Vendor Specific Command CDW13 */ + __u8 vs_cmd_to; /* 028 - Vendor Specific Command Timeout V2 */ + __u8 dev_recovery_action2; /* 029 - Device Recovery Action 2 V2 */ + __u8 dev_recovery_action2_to; /* 030 - Device Recovery Action 2 Timeout V2 */ + __u8 rsvd2[463]; /* 031 - 463 Reserved Bytes */ + __le16 log_page_version; /* 494 - Log Page Version */ + __u8 log_page_guid[WDC_OCP_C1_GUID_LENGTH]; /* 496 - Log Page GUID */ }; static __u8 wdc_ocp_c1_guid[WDC_OCP_C1_GUID_LENGTH] = { 0x44, 0xD9, 0x31, 0x21, 0xFE, 0x30, 0x34, 0xAE, 0xAB, 0x4D, 0xFD, 0x3D, 0xBA, 0x83, 0x19, 0x5A }; /* NAND Stats */ -struct __attribute__((__packed__)) wdc_nand_stats { +struct __packed wdc_nand_stats { __u8 nand_write_tlc[16]; __u8 nand_write_slc[16]; __le32 nand_prog_failure; @@ -1125,10 +1284,10 @@ struct __attribute__((__packed__)) wdc_nand_stats { __le64 e2e_error_counter; __le64 successful_ns_resize_event; __u8 rsvd[442]; - __u16 log_page_version; + __u16 log_page_version; }; -struct __attribute__((__packed__)) wdc_nand_stats_V3 { +struct __packed wdc_nand_stats_V3 { __u8 nand_write_tlc[16]; __u8 nand_write_slc[16]; __u8 bad_nand_block_count[8]; @@ -1137,8 +1296,8 @@ struct __attribute__((__packed__)) wdc_nand_stats_V3 { __u8 ssd_correction_counts[16]; __u8 percent_life_used; __le64 user_data_erase_counts[4]; - __u8 program_fail_count[8]; - __u8 erase_fail_count[8]; + __u8 program_fail_count[8]; + __u8 erase_fail_count[8]; __le64 correctable_error_count; __u8 percent_free_blocks_user; __le64 security_version_number; @@ -1153,53 +1312,52 @@ struct __attribute__((__packed__)) wdc_nand_stats_V3 { __le64 unaligned_IO; __u8 physical_media_units[16]; __u8 reserved[279]; - __u16 log_page_version; + __u16 log_page_version; }; -struct wdc_vs_pcie_stats -{ - __le64 unsupportedRequestErrorCount; - __le64 ecrcErrorStatusCount; - __le64 malformedTlpStatusCount; - __le64 receiverOverflowStatusCount; - __le64 unexpectedCmpltnStatusCount; - __le64 completeAbortStatusCount; - __le64 cmpltnTimoutStatusCount; - __le64 flowControlErrorStatusCount; - __le64 poisonedTlpStatusCount; - __le64 dLinkPrtclErrorStatusCount; - __le64 advsryNFatalErrStatusCount; - __le64 replayTimerToStatusCount; - __le64 replayNumRolloverStCount; - __le64 badDllpStatusCount; - __le64 badTlpStatusCount; - __le64 receiverErrStatusCount; - __u8 reserved1[384]; +struct wdc_vs_pcie_stats { + __le64 unsupportedRequestErrorCount; + __le64 ecrcErrorStatusCount; + __le64 malformedTlpStatusCount; + __le64 receiverOverflowStatusCount; + __le64 unexpectedCmpltnStatusCount; + __le64 completeAbortStatusCount; + __le64 cmpltnTimoutStatusCount; + __le64 flowControlErrorStatusCount; + __le64 poisonedTlpStatusCount; + __le64 dLinkPrtclErrorStatusCount; + __le64 advsryNFatalErrStatusCount; + __le64 replayTimerToStatusCount; + __le64 replayNumRolloverStCount; + __le64 badDllpStatusCount; + __le64 badTlpStatusCount; + __le64 receiverErrStatusCount; + __u8 reserved1[384]; }; struct wdc_fw_act_history_log_hdr { - __le32 eye_catcher; - __u8 version; - __u8 reserved1; - __u8 num_entries; - __u8 reserved2; - __le32 entry_size; - __le32 reserved3; + __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]; + __le32 entry_num; + __le32 power_cycle_count; + __le64 power_on_seconds; + __le64 previous_fw_version; + __le64 new_fw_version; + __u8 slot_number; + __u8 commit_action_type; + __le16 result; + __u8 reserved[12]; }; -struct __attribute__((__packed__)) wdc_fw_act_history_log_entry_c2 { +struct __packed wdc_fw_act_history_log_entry_c2 { __u8 entry_version_num; __u8 entry_len; __le16 reserved; @@ -1215,14 +1373,14 @@ struct __attribute__((__packed__)) wdc_fw_act_history_log_entry_c2 { __u8 reserved3[14]; }; -struct __attribute__((__packed__)) wdc_fw_act_history_log_format_c2 { +struct __packed wdc_fw_act_history_log_format_c2 { __u8 log_identifier; - __u8 reserved[3]; + __u8 reserved[3]; __le32 num_entries; - struct wdc_fw_act_history_log_entry_c2 entry[WDC_MAX_NUM_ACT_HIST_ENTRIES]; - __u8 reserved2[2790]; - __le16 log_page_version; - __u8 log_page_guid[WDC_C2_GUID_LENGTH]; + struct wdc_fw_act_history_log_entry_c2 entry[WDC_MAX_NUM_ACT_HIST_ENTRIES]; + __u8 reserved2[2790]; + __le16 log_page_version; + __u8 log_page_guid[WDC_C2_GUID_LENGTH]; }; #define WDC_OCP_C4_GUID_LENGTH 16 @@ -1231,24 +1389,26 @@ struct __attribute__((__packed__)) wdc_fw_act_history_log_format_c2 { #define WDC_DEV_CAP_LOG_VERSION 0001 #define WDC_OCP_C4_NUM_PS_DESCR 127 -struct __attribute__((__packed__)) wdc_ocp_C4_dev_cap_log { - __le16 num_pcie_ports; /* 0000 - Number of PCI Express Ports */ - __le16 oob_mgmt_support; /* 0002 - OOB Management Interfaces Supported */ - __le16 wrt_zeros_support; /* 0004 - Write Zeros Commmand Support */ - __le16 sanitize_support; /* 0006 - Sanitize Command Support */ - __le16 dsm_support; /* 0008 - Dataset Management Command Support */ - __le16 wrt_uncor_support; /* 0010 - Write Uncorrectable Command Support */ - __le16 fused_support; /* 0012 - Fused Operation Support */ - __le16 min_dssd_ps; /* 0014 - Minimum Valid DSSD Power State */ - __u8 rsvd1; /* 0016 - Reserved must be cleared to zero */ - __u8 dssd_ps_descr[WDC_OCP_C4_NUM_PS_DESCR];/* 0017 - DSSD Power State Descriptors */ - __u8 rsvd2[3934]; /* 0144 - Reserved must be cleared to zero */ - __le16 log_page_version; /* 4078 - Log Page Version */ - __u8 log_page_guid[WDC_OCP_C4_GUID_LENGTH]; /* 4080 - Log Page GUID */ +struct __packed wdc_ocp_C4_dev_cap_log { + __le16 num_pcie_ports; /* 0000 - Number of PCI Express Ports */ + __le16 oob_mgmt_support; /* 0002 - OOB Management Interfaces Supported */ + __le16 wrt_zeros_support; /* 0004 - Write Zeros Command Support */ + __le16 sanitize_support; /* 0006 - Sanitize Command Support */ + __le16 dsm_support; /* 0008 - Dataset Management Command Support */ + __le16 wrt_uncor_support; /* 0010 - Write Uncorrectable Command Support */ + __le16 fused_support; /* 0012 - Fused Operation Support */ + __le16 min_dssd_ps; /* 0014 - Minimum Valid DSSD Power State */ + __u8 rsvd1; /* 0016 - Reserved must be cleared to zero */ + __u8 dssd_ps_descr[WDC_OCP_C4_NUM_PS_DESCR];/* 0017 - DSSD Power State Descriptors */ + __u8 rsvd2[3934]; /* 0144 - Reserved must be cleared to zero */ + __le16 log_page_version; /* 4078 - Log Page Version */ + __u8 log_page_guid[WDC_OCP_C4_GUID_LENGTH]; /* 4080 - Log Page GUID */ }; -static __u8 wdc_ocp_c4_guid[WDC_OCP_C4_GUID_LENGTH] = { 0x97, 0x42, 0x05, 0x0D, 0xD1, 0xE1, 0xC9, 0x98, - 0x5D, 0x49, 0x58, 0x4B, 0x91, 0x3C, 0x05, 0xB7 }; +static __u8 wdc_ocp_c4_guid[WDC_OCP_C4_GUID_LENGTH] = { + 0x97, 0x42, 0x05, 0x0D, 0xD1, 0xE1, 0xC9, 0x98, + 0x5D, 0x49, 0x58, 0x4B, 0x91, 0x3C, 0x05, 0xB7 +}; #define WDC_OCP_C5_GUID_LENGTH 16 #define WDC_UNSUPPORTED_REQS_LOG_BUF_LEN 4096 @@ -1256,13 +1416,13 @@ static __u8 wdc_ocp_c4_guid[WDC_OCP_C4_GUID_LENGTH] = { 0x97, 0x42, 0x05, 0x0 #define WDC_UNSUPPORTED_REQS_LOG_VERSION 0001 #define WDC_NUM_UNSUPPORTED_REQ_ENTRIES 253 -struct __attribute__((__packed__)) wdc_ocp_C5_unsupported_reqs { - __le16 unsupported_count; /* 0000 - Number of Unsupported Requirement IDs */ - __u8 rsvd1[14]; /* 0002 - Reserved must be cleared to zero */ - __u8 unsupported_req_list[WDC_NUM_UNSUPPORTED_REQ_ENTRIES][16]; /* 0016 - Unsupported Requirements List */ - __u8 rsvd2[14]; /* 4064 - Reserved must be cleared to zero */ - __le16 log_page_version; /* 4078 - Log Page Version */ - __u8 log_page_guid[WDC_OCP_C5_GUID_LENGTH]; /* 4080 - Log Page GUID */ +struct __packed wdc_ocp_C5_unsupported_reqs { + __le16 unsupported_count; /* 0000 - Number of Unsupported Requirement IDs */ + __u8 rsvd1[14]; /* 0002 - Reserved must be cleared to zero */ + __u8 unsupported_req_list[WDC_NUM_UNSUPPORTED_REQ_ENTRIES][16]; /* 0016 - Unsupported Requirements List */ + __u8 rsvd2[14]; /* 4064 - Reserved must be cleared to zero */ + __le16 log_page_version; /* 4078 - Log Page Version */ + __u8 log_page_guid[WDC_OCP_C5_GUID_LENGTH]; /* 4080 - Log Page GUID */ }; static __u8 wdc_ocp_c5_guid[WDC_OCP_C5_GUID_LENGTH] = { 0x2F, 0x72, 0x9C, 0x0E, 0x99, 0x23, 0x2C, 0xBB, @@ -1272,6 +1432,21 @@ static __u8 wdc_ocp_c5_guid[WDC_OCP_C5_GUID_LENGTH] = { 0x2F, 0x72, 0x9C, 0x0 #define WDC_REASON_ID_ENTRY_LEN 128 #define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli" +const char *log_page_name[256] = { + [NVME_LOG_LID_ERROR] = "Error Information", + [NVME_LOG_LID_SMART] = "SMART / Health Information", + [NVME_LOG_LID_FW_SLOT] = "Firmware Slot Information", + [NVME_LOG_LID_CHANGED_NS] = "Changed Namespace List", + [NVME_LOG_LID_CMD_EFFECTS] = "Command Supported and Effects", + [NVME_LOG_LID_TELEMETRY_HOST] = "Telemetry Host-Initiated", + [NVME_LOG_LID_TELEMETRY_CTRL] = "Telemetry Controller-Initiated", + [NVME_LOG_LID_SANITIZE] = "Sanitize Status", + [WDC_LOG_ID_C0] = "Extended SMART Information", + [WDC_LOG_ID_C2] = "Firmware Activation History", + [WDC_LOG_ID_C3] = "Latency Monitor", + [WDC_LOG_ID_C4] = "Device Capabilities", + [WDC_LOG_ID_C5] = "Unsupported Requirements", +}; static double safe_div_fp(double numerator, double denominator) { @@ -1284,18 +1459,6 @@ static double calc_percent(uint64_t numerator, uint64_t 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(nvme_root_t r, struct nvme_dev *dev, uint32_t *device_id, uint32_t *vendor_id) { @@ -1327,7 +1490,7 @@ static int wdc_get_pci_ids(nvme_root_t r, struct nvme_dev *dev, fd = open(vid, O_RDONLY); if (fd < 0) { - fprintf(stderr, "ERROR : WDC : %s : Open vendor file failed\n", __func__); + fprintf(stderr, "ERROR: WDC: %s : Open vendor file failed\n", __func__); return -1; } @@ -1347,7 +1510,7 @@ static int wdc_get_pci_ids(nvme_root_t r, struct nvme_dev *dev, fd = open(did, O_RDONLY); if (fd < 0) { - fprintf(stderr, "ERROR : WDC : %s : Open device file failed\n", __func__); + fprintf(stderr, "ERROR: WDC: %s : Open device file failed\n", __func__); return -1; } @@ -1374,8 +1537,7 @@ static int wdc_get_vendor_id(struct nvme_dev *dev, uint32_t *vendor_id) memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " - "0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret); return -1; } @@ -1384,29 +1546,83 @@ static int wdc_get_vendor_id(struct nvme_dev *dev, uint32_t *vendor_id) return ret; } +static bool wdc_is_sn861(__u32 device_id) +{ + if ((device_id == WDC_NVME_SN861_DEV_ID) || + (device_id == WDC_NVME_SN861_DEV_ID_1)) + return true; + else + return false; +} + + +static bool wdc_is_sn640(__u32 device_id) +{ + if ((device_id == WDC_NVME_SN640_DEV_ID) || + (device_id == WDC_NVME_SN640_DEV_ID_1) || + (device_id == WDC_NVME_SN640_DEV_ID_2)) + return true; + else + return false; +} + +static bool wdc_is_sn640_3(__u32 device_id) +{ + if (device_id == WDC_NVME_SN640_DEV_ID_3) + return true; + else + return false; +} + +static bool wdc_is_sn650_u2(__u32 device_id) +{ + if (device_id == WDC_NVME_SN650_DEV_ID_3) + return true; + else + return false; +} + +static bool wdc_is_sn650_e1l(__u32 device_id) +{ + if (device_id == WDC_NVME_SN650_DEV_ID_4) + return true; + else + return false; +} + +static bool needs_c2_log_page_check(__u32 device_id) +{ + if ((wdc_is_sn640(device_id)) || + (wdc_is_sn650_u2(device_id)) || + (wdc_is_sn650_e1l(device_id))) + return true; + else + return false; +} + static bool wdc_check_power_of_2(int num) { - return (num && ( !(num & (num-1)))); + return num && (!(num & (num-1))); } static int wdc_get_model_number(struct nvme_dev *dev, char *model) { - int ret,i; + int ret, i; struct nvme_id_ctrl ctrl; memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " - "0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret); return -1; } - memcpy(model,ctrl.mn,NVME_ID_CTRL_MODEL_NUMBER_SIZE); + memcpy(model, ctrl.mn, NVME_ID_CTRL_MODEL_NUMBER_SIZE); /* get rid of the padded spaces */ i = NVME_ID_CTRL_MODEL_NUMBER_SIZE-1; - while (model[i] == ' ') i--; - model[i+1]=0; + while (model[i] == ' ') + i--; + model[i+1] = 0; return ret; } @@ -1431,8 +1647,9 @@ static bool wdc_check_device(nvme_root_t r, struct nvme_dev *dev) 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); + fprintf(stderr, + "ERROR: WDC: unsupported WDC device, Vendor ID = 0x%x, Device ID = 0x%x\n", + read_vendor_id, read_device_id); return supported; } @@ -1449,10 +1666,10 @@ static bool wdc_enc_check_model(struct nvme_dev *dev) supported = false; model[NVME_ID_CTRL_MODEL_NUMBER_SIZE] = 0; /* forced termination */ - if (strstr(model,WDC_OPENFLEX_MI_DEVICE_MODEL) != NULL) + if (strstr(model, WDC_OPENFLEX_MI_DEVICE_MODEL)) supported = true; else - fprintf(stderr, "ERROR : WDC: unsupported WDC enclosure, Model = %s\n",model); + fprintf(stderr, "ERROR: WDC: unsupported WDC enclosure, Model = %s\n", model); return supported; } @@ -1465,15 +1682,13 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) __u32 cust_id; ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id); - if (ret < 0) - { + if (ret < 0) { if (wdc_get_vendor_id(dev, &read_vendor_id) < 0) return capabilities; } /* below check condition is added due in NVMeOF device we dont have device_id so we need to use only vendor_id*/ - if (read_device_id == -1 && read_vendor_id != -1) - { + if (read_device_id == -1 && read_vendor_id != -1) { capabilities = wdc_get_enc_drive_capabilities(r, dev); return capabilities; } @@ -1486,6 +1701,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | WDC_DRIVE_CAP_PURGE); break; + case WDC_NVME_SN200_DEV_ID: capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE | WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | @@ -1501,14 +1717,15 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_NVME_ADD_LOG_OPCODE)) capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE; break; + default: capabilities = 0; } break; + case WDC_NVME_VID_2: switch (read_device_id) { case WDC_NVME_SN630_DEV_ID: - /* 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 | @@ -1520,23 +1737,18 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) /* verify the 0xD0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, - WDC_NVME_GET_VU_SMART_LOG_OPCODE) - == true) + WDC_NVME_GET_VU_SMART_LOG_OPCODE)) 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_SN560_DEV_ID_1: - /* FALLTHRU */ - case WDC_NVME_SN560_DEV_ID_2: - /* FALLTHRU */ - case WDC_NVME_SN560_DEV_ID_3: + case WDC_NVME_SN640_DEV_ID_3: + case WDC_NVME_SN560_DEV_ID_1: + case WDC_NVME_SN560_DEV_ID_2: + case WDC_NVME_SN560_DEV_ID_3: + case WDC_NVME_SN660_DEV_ID: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID) @@ -1565,7 +1777,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_DEV_CAP_LOG_ID)) capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE; - /* verify the 0xC5 (OCP Unsupported Requirments) log page is supported */ + /* verify the 0xC5 (OCP Unsupported Requirements) log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, WDC_UNSUPPORTED_REQS_LOG_ID)) capabilities |= WDC_DRIVE_CAP_OCP_C5_LOG_PAGE; @@ -1582,7 +1794,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) cust_id = wdc_get_fw_cust_id(r, dev); if (cust_id == WDC_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); + fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__); return -1; } @@ -1593,27 +1805,24 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) else capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE); - break; + break; + case WDC_NVME_SN840_DEV_ID: - /* FALLTHRU */ case WDC_NVME_SN840_DEV_ID_1: - /* FALLTHRU */ case WDC_NVME_SN860_DEV_ID: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE)) capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; - /* FALLTHRU */ + fallthrough; case WDC_NVME_ZN540_DEV_ID: - /* FALLTHRU */ - case WDC_NVME_SN540_DEV_ID: - /* FALLTHRU */ + case WDC_NVME_SN540_DEV_ID: capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_CLEAR_PCIE | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID | - WDC_DRIVE_CAP_LOG_PAGE_DIR ); + WDC_DRIVE_CAP_LOG_PAGE_DIR); /* verify the 0xCA log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, @@ -1625,6 +1834,7 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) WDC_NVME_GET_VU_SMART_LOG_OPCODE)) capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; break; + case WDC_NVME_SN650_DEV_ID: case WDC_NVME_SN650_DEV_ID_1: case WDC_NVME_SN650_DEV_ID_2: @@ -1649,81 +1859,153 @@ static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev) if (wdc_nvme_check_supported_log_page(r, dev, WDC_DEV_CAP_LOG_ID)) capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE; - /* verify the 0xC5 (OCP Unsupported Requirments) log page is supported */ + /* verify the 0xC5 (OCP Unsupported Requirements) log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, WDC_UNSUPPORTED_REQS_LOG_ID)) capabilities |= WDC_DRIVE_CAP_OCP_C5_LOG_PAGE; capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | - WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | - WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | - WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID | - WDC_DRIVE_CAP_LOG_PAGE_DIR); + WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | + WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | + WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | + WDC_DRIVE_CAP_REASON_ID | WDC_DRIVE_CAP_LOG_PAGE_DIR); cust_id = wdc_get_fw_cust_id(r, dev); if (cust_id == WDC_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); + fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__); return -1; } - if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || - (cust_id == WDC_CUSTOMER_ID_0x1005) || (cust_id == WDC_CUSTOMER_ID_0x1304)) - capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | - WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION); + if ((cust_id == WDC_CUSTOMER_ID_0x1004) || + (cust_id == WDC_CUSTOMER_ID_0x1008) || + (cust_id == WDC_CUSTOMER_ID_0x1005) || + (cust_id == WDC_CUSTOMER_ID_0x1304)) + capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | + WDC_DRIVE_CAP_INFO | + WDC_DRIVE_CAP_CLOUD_SSD_VERSION); else - capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE); + capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | + WDC_DRIVE_CAP_CLEAR_PCIE); break; - case WDC_NVME_SN730B_DEV_ID: - /* FALLTHRU */ - case WDC_NVME_SN730B_DEV_ID_1: - capabilities = WDC_SN730B_CAP_VUC_LOG; + + case WDC_NVME_SN861_DEV_ID: + case WDC_NVME_SN861_DEV_ID_1: + capabilities |= (WDC_DRIVE_CAP_C0_LOG_PAGE | + WDC_DRIVE_CAP_C3_LOG_PAGE | + WDC_DRIVE_CAP_CA_LOG_PAGE | + WDC_DRIVE_CAP_OCP_C4_LOG_PAGE | + WDC_DRIVE_CAP_OCP_C5_LOG_PAGE | + WDC_DRIVE_CAP_INTERNAL_LOG | + WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | + WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | + WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + WDC_DRIVE_CAP_INFO | + WDC_DRIVE_CAP_CLOUD_SSD_VERSION | + WDC_DRIVE_CAP_LOG_PAGE_DIR | + WDC_DRIVE_CAP_DRIVE_STATUS | + WDC_DRIVE_CAP_SET_LATENCY_MONITOR); break; + default: capabilities = 0; } break; + case WDC_NVME_SNDK_VID: switch (read_device_id) { case WDC_NVME_SXSLCL_DEV_ID: capabilities = WDC_DRIVE_CAP_DRIVE_ESSENTIALS; break; + case WDC_NVME_SN520_DEV_ID: - /* FALLTHRU */ case WDC_NVME_SN520_DEV_ID_1: - /* FALLTHRU */ case WDC_NVME_SN520_DEV_ID_2: - case WDC_NVME_SN530_DEV_ID: case WDC_NVME_SN810_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI_DATA; break; + case WDC_NVME_SN820CL_DEV_ID: - capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION | - WDC_DRIVE_CAP_CLOUD_LOG_PAGE | WDC_DRIVE_CAP_C0_LOG_PAGE | - WDC_DRIVE_CAP_HW_REV_LOG_PAGE | WDC_DRIVE_CAP_INFO | - WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_NAND_STATS | - WDC_DRIVE_CAP_DEVICE_WAF | WDC_DRIVE_CAP_TEMP_STATS; + capabilities = WDC_DRIVE_CAP_DUI_DATA | + WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION | + WDC_DRIVE_CAP_CLOUD_LOG_PAGE | WDC_DRIVE_CAP_C0_LOG_PAGE | + WDC_DRIVE_CAP_HW_REV_LOG_PAGE | WDC_DRIVE_CAP_INFO | + WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_NAND_STATS | + WDC_DRIVE_CAP_DEVICE_WAF | WDC_DRIVE_CAP_TEMP_STATS; break; + case WDC_NVME_SN720_DEV_ID: - capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_NS_RESIZE; + 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 | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO | - WDC_DRIVE_CAP_TEMP_STATS | WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS; + + case WDC_NVME_SN730_DEV_ID: + capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | + WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_TEMP_STATS | + WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS; break; - case WDC_NVME_SN740_DEV_ID: - case WDC_NVME_SN740_DEV_ID_1: - case WDC_NVME_SN740_DEV_ID_2: - case WDC_NVME_SN740_DEV_ID_3: + + case WDC_NVME_SN530_DEV_ID_1: + fallthrough; + case WDC_NVME_SN530_DEV_ID_2: + fallthrough; + case WDC_NVME_SN530_DEV_ID_3: + fallthrough; + case WDC_NVME_SN530_DEV_ID_4: + fallthrough; + case WDC_NVME_SN530_DEV_ID_5: + fallthrough; + case WDC_NVME_SN350_DEV_ID: + fallthrough; + case WDC_NVME_SN570_DEV_ID: + fallthrough; + case WDC_NVME_SN850X_DEV_ID: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_1: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_2: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_3: + fallthrough; + case WDC_NVME_SN5000_DEV_ID_4: + fallthrough; + case WDC_NVME_SN7000S_DEV_ID_1: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_1: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_2: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_3: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_4: + fallthrough; + case WDC_NVME_SN7150_DEV_ID_5: + fallthrough; + case WDC_NVME_SN7100_DEV_ID_1: + fallthrough; + case WDC_NVME_SN7100_DEV_ID_2: + fallthrough; + case WDC_NVME_SN7100_DEV_ID_3: + fallthrough; + case WDC_NVME_SN8000S_DEV_ID: + fallthrough; + case WDC_NVME_SN740_DEV_ID: + case WDC_NVME_SN740_DEV_ID_1: + case WDC_NVME_SN740_DEV_ID_2: + case WDC_NVME_SN740_DEV_ID_3: case WDC_NVME_SN340_DEV_ID: capabilities = WDC_DRIVE_CAP_DUI; break; + case WDC_NVME_ZN350_DEV_ID: - /* FALLTHRU */ case WDC_NVME_ZN350_DEV_ID_1: - capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_C0_LOG_PAGE | - WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | - WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION | WDC_DRIVE_CAP_LOG_PAGE_DIR; + capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | + WDC_DRIVE_CAP_C0_LOG_PAGE | + WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | + WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 | WDC_DRIVE_CAP_INFO | + WDC_DRIVE_CAP_CLOUD_SSD_VERSION | WDC_DRIVE_CAP_LOG_PAGE_DIR; break; + default: capabilities = 0; } @@ -1748,57 +2030,57 @@ static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r, return capabilities; switch (read_vendor_id) { - case WDC_NVME_VID: - capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE | - WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); + case WDC_NVME_VID: + capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE | + WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); - /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) - capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; + /* verify the 0xCA log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; - /* verify the 0xC1 log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_ADD_LOG_OPCODE) == true) - capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE; - break; - case WDC_NVME_VID_2: - capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | - WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | - WDC_DRIVE_CAP_RESIZE); + /* verify the 0xC1 log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_ADD_LOG_OPCODE) == true) + capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE; + break; + case WDC_NVME_VID_2: + capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | + WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT | + WDC_DRIVE_CAP_RESIZE); - /* verify the 0xC3 log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_LATENCY_MON_LOG_ID) == true) - capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE; + /* verify the 0xC3 log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, WDC_LATENCY_MON_LOG_ID) == true) + capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE; - /* verify the 0xCB log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == true) - capabilities |= WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY; + /* verify the 0xCB log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == true) + capabilities |= WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY; - /* verify the 0xCA log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) - capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; + /* verify the 0xCA log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) + capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE; - /* verify the 0xD0 log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) - capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; + /* verify the 0xD0 log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true) + capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE; - cust_id = wdc_get_fw_cust_id(r, dev); - if (cust_id == WDC_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); - return -1; - } + cust_id = wdc_get_fw_cust_id(r, dev); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__); + return -1; + } - if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || - (cust_id == WDC_CUSTOMER_ID_0x1005) || (cust_id == WDC_CUSTOMER_ID_0x1304)) - capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE); - else - capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE); + if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || + (cust_id == WDC_CUSTOMER_ID_0x1005) || (cust_id == WDC_CUSTOMER_ID_0x1304)) + capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE); + else + capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE); - break; - case WDC_NVME_SNDK_VID: - capabilities = WDC_DRIVE_CAP_DRIVE_ESSENTIALS; - break; - default: - capabilities = 0; + break; + case WDC_NVME_SNDK_VID: + capabilities = WDC_DRIVE_CAP_DRIVE_ESSENTIALS; + break; + default: + capabilities = 0; } return capabilities; @@ -1812,16 +2094,15 @@ static int wdc_get_serial_name(struct nvme_dev *dev, char *file, size_t len, int res_len = 0; char orig[PATH_MAX] = {0}; struct nvme_id_ctrl ctrl; - int ctrl_sn_len = sizeof (ctrl.sn); + int ctrl_sn_len = sizeof(ctrl.sn); - i = sizeof (ctrl.sn) - 1; + i = sizeof(ctrl.sn) - 1; strncpy(orig, file, PATH_MAX - 1); memset(file, 0, len); - memset(&ctrl, 0, sizeof (struct nvme_id_ctrl)); + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " - "0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret); return -1; } /* Remove trailing spaces from the name */ @@ -1829,14 +2110,13 @@ static int wdc_get_serial_name(struct nvme_dev *dev, char *file, size_t len, ctrl.sn[i] = '\0'; i--; } - if (ctrl.sn[sizeof (ctrl.sn) - 1] == '\0') { + 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"); + fprintf(stderr, + "ERROR: WDC: cannot format serial number due to data of unexpected length\n"); return -1; } @@ -1849,21 +2129,21 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data, int fd; int ret; - if (drive_log_length == 0) { - fprintf(stderr, "ERROR : WDC: invalid log file length\n"); + if (!drive_log_length) { + fprintf(stderr, "ERROR: WDC: invalid log file length\n"); return -1; } fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) { - fprintf(stderr, "ERROR : WDC: open : %s\n", strerror(errno)); + 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)); + fprintf(stderr, "ERROR: WDC: write: %s\n", strerror(errno)); close(fd); return -1; } @@ -1873,13 +2153,13 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data, ret = write(fd, drive_log_data, drive_log_length); if (ret < 0) { - fprintf(stderr, "ERROR : WDC : write : %s\n", strerror(errno)); + fprintf(stderr, "ERROR: WDC: write: %s\n", strerror(errno)); close(fd); return -1; } if (fsync(fd) < 0) { - fprintf(stderr, "ERROR : WDC : fsync : %s\n", strerror(errno)); + fprintf(stderr, "ERROR: WDC: fsync: %s\n", strerror(errno)); close(fd); return -1; } @@ -1887,125 +2167,122 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data, return 0; } -bool wdc_get_dev_mng_log_entry(__u32 log_length, - __u32 entry_id, - struct wdc_c2_log_page_header* p_log_hdr, - struct wdc_c2_log_subpage_header **p_p_found_log_entry) -{ - __u32 remaining_len = 0; - __u32 log_entry_hdr_size = sizeof(struct wdc_c2_log_subpage_header) - 1; - __u32 log_entry_size = 0; - __u32 size = 0; - bool valid_log; - __u32 current_data_offset = 0; - struct wdc_c2_log_subpage_header *p_next_log_entry = NULL; - - if (*p_p_found_log_entry == NULL) { - fprintf(stderr, "ERROR : WDC - wdc_get_dev_mng_log_entry: No ppLogEntry pointer.\n"); - return false; - } - - *p_p_found_log_entry = NULL; - - /* Ensure log data is large enough for common header */ - if (log_length < sizeof(struct wdc_c2_log_page_header)) { - fprintf(stderr, "ERROR : WDC - wdc_get_dev_mng_log_entry: \ - Buffer is not large enough for the common header. BufSize: 0x%x HdrSize: %"PRIxPTR"\n", - log_length, sizeof(struct wdc_c2_log_page_header)); - return false; - } - - /* Get pointer to first log Entry */ - size = sizeof(struct wdc_c2_log_page_header); - current_data_offset = size; - p_next_log_entry = (struct wdc_c2_log_subpage_header *)((__u8*)p_log_hdr + current_data_offset); - remaining_len = log_length - size; - valid_log = false; - - /* Walk the entire structure. Perform a sanity check to make sure this is a - standard version of the structure. This means making sure each entry looks - valid. But allow for the data to overflow the allocated - buffer (we don't want a false negative because of a FW formatting error) */ - - /* Proceed only if there is at least enough data to read an entry header */ - while (remaining_len >= log_entry_hdr_size) { - /* Get size of the next entry */ - log_entry_size = p_next_log_entry->length; - - /* If log entry size is 0 or the log entry goes past the end - of the data, we must be at the end of the data */ - if ((log_entry_size == 0) || - (log_entry_size > remaining_len)) { - fprintf(stderr, "ERROR : WDC: wdc_get_dev_mng_log_entry: \ - Detected unaligned end of the data. Data Offset: 0x%x \ - Entry Size: 0x%x, Remaining Log Length: 0x%x Entry Id: 0x%x\n", - current_data_offset, log_entry_size, remaining_len, p_next_log_entry->entry_id); - - /* Force the loop to end */ - remaining_len = 0; - } else if ((p_next_log_entry->entry_id == 0) || - (p_next_log_entry->entry_id > 200)) { - /* Invalid entry - fail the search */ - fprintf(stderr, "ERROR : WDC: wdc_get_dev_mng_log_entry: \ - Invalid entry found at offset: 0x%x Entry Size: 0x%x, \ - Remaining Log Length: 0x%x Entry Id: 0x%x\n", - current_data_offset, log_entry_size, remaining_len, p_next_log_entry->entry_id); - - /* Force the loop to end */ - remaining_len = 0; - valid_log = false; - - /* The struture is invalid, so any match that was found is invalid. */ - *p_p_found_log_entry = NULL; - } else { - /* Structure must have at least one valid entry to be considered valid */ - valid_log = true; - if (p_next_log_entry->entry_id == entry_id) { - /* A potential match. */ - *p_p_found_log_entry = p_next_log_entry; - } - - remaining_len -= log_entry_size; - - if (remaining_len > 0) { - /* Increment the offset counter */ - current_data_offset += log_entry_size; - - /* Get the next entry */ - p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8*)p_log_hdr) + current_data_offset); - } - } - } - - return valid_log; +bool wdc_get_dev_mng_log_entry(__u32 log_length, __u32 entry_id, + struct wdc_c2_log_page_header *p_log_hdr, + struct wdc_c2_log_subpage_header **p_p_found_log_entry) +{ + __u32 remaining_len = 0; + __u32 log_entry_hdr_size = sizeof(struct wdc_c2_log_subpage_header) - 1; + __u32 log_entry_size = 0; + __u32 size = 0; + bool valid_log; + __u32 current_data_offset = 0; + struct wdc_c2_log_subpage_header *p_next_log_entry = NULL; + + if (!*p_p_found_log_entry) { + fprintf(stderr, "ERROR: WDC - %s: No ppLogEntry pointer.\n", __func__); + return false; + } + + *p_p_found_log_entry = NULL; + + /* Ensure log data is large enough for common header */ + if (log_length < sizeof(struct wdc_c2_log_page_header)) { + fprintf(stderr, + "ERROR: WDC - %s: Buffer is not large enough for the common header. BufSize: 0x%x HdrSize: %"PRIxPTR"\n", + __func__, log_length, sizeof(struct wdc_c2_log_page_header)); + return false; + } + + /* Get pointer to first log Entry */ + size = sizeof(struct wdc_c2_log_page_header); + current_data_offset = size; + p_next_log_entry = (struct wdc_c2_log_subpage_header *)((__u8 *)p_log_hdr + current_data_offset); + remaining_len = log_length - size; + valid_log = false; + + /* + * Walk the entire structure. Perform a sanity check to make sure this is a + * standard version of the structure. This means making sure each entry looks + * valid. But allow for the data to overflow the allocated + * buffer (we don't want a false negative because of a FW formatting error) + */ + + /* Proceed only if there is at least enough data to read an entry header */ + while (remaining_len >= log_entry_hdr_size) { + /* Get size of the next entry */ + log_entry_size = p_next_log_entry->length; + + /* + * If log entry size is 0 or the log entry goes past the end + * of the data, we must be at the end of the data + */ + if (!log_entry_size || log_entry_size > remaining_len) { + fprintf(stderr, "ERROR: WDC: %s: Detected unaligned end of the data. ", + __func__); + fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ", + current_data_offset, log_entry_size); + fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n", + remaining_len, p_next_log_entry->entry_id); + + /* Force the loop to end */ + remaining_len = 0; + } else if (!p_next_log_entry->entry_id || p_next_log_entry->entry_id > 200) { + /* Invalid entry - fail the search */ + fprintf(stderr, "ERROR: WDC: %s: Invalid entry found at offset: 0x%x ", + __func__, current_data_offset); + fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ", + log_entry_size, remaining_len); + fprintf(stderr, "Entry Id: 0x%x\n", p_next_log_entry->entry_id); + + /* Force the loop to end */ + remaining_len = 0; + valid_log = false; + + /* The structure is invalid, so any match that was found is invalid. */ + *p_p_found_log_entry = NULL; + } else { + /* Structure must have at least one valid entry to be considered valid */ + valid_log = true; + if (p_next_log_entry->entry_id == entry_id) + /* A potential match. */ + *p_p_found_log_entry = p_next_log_entry; + + remaining_len -= log_entry_size; + + if (remaining_len > 0) { + /* Increment the offset counter */ + current_data_offset += log_entry_size; + + /* Get the next entry */ + p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8 *)p_log_hdr) + current_data_offset); + } + } + } + + return valid_log; } -static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, - __u8 log_id, void **cbs_data) +static bool get_dev_mgmt_log_page_lid_data(struct nvme_dev *dev, + void **cbs_data, + __u8 lid, + __u8 log_id, + __u8 uuid_ix) { - int ret = -1; - void* data; + void *data; struct wdc_c2_log_page_header *hdr_ptr; struct wdc_c2_log_subpage_header *sph; __u32 length = 0; + int ret = 0; bool found = false; - __u8 uuid_ix = 1; - __u8 lid = 0; - *cbs_data = NULL; - __u32 device_id, read_vendor_id; - - ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); - if(device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) { - lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8; - uuid_ix = 0; - } else - lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE; - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_C2_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_C2_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return false; } - memset(data, 0, sizeof (__u8) * WDC_C2_LOG_BUF_LEN); + + memset(data, 0, sizeof(__u8) * WDC_C2_LOG_BUF_LEN); /* get the log page length */ struct nvme_get_log_args args_len = { @@ -2027,7 +2304,9 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, }; ret = nvme_get_log(&args_len); if (ret) { - fprintf(stderr, "ERROR : WDC : Unable to get 0x%x Log Page length, ret = 0x%x\n", lid, ret); + fprintf(stderr, + "ERROR: WDC: Unable to get 0x%x Log Page length with uuid %d, ret = 0x%x\n", + lid, uuid_ix, ret); goto end; } @@ -2038,56 +2317,14 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, /* Log Page buffer too small, free and reallocate the necessary size */ free(data); data = calloc(length, sizeof(__u8)); - if (data == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); - return false; + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); + goto end; } - } - /* get the log page data */ - struct nvme_get_log_args args_data = { - .args_size = sizeof(args_data), - .fd = dev_fd(dev), - .lid = lid, - .nsid = 0xFFFFFFFF, - .lpo = 0, - .lsp = NVME_LOG_LSP_NONE, - .lsi = 0, - .rae = false, - .uuidx = uuid_ix, - .csi = NVME_CSI_NVM, - .ot = false, - .len = length, - .log = data, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - ret = nvme_get_log(&args_data); - - if (ret) { - fprintf(stderr, "ERROR : WDC : Unable to read 0x%x Log Page data, ret = 0x%x\n", lid, ret); - goto end; - } - - /* Check the log data to see if the WD version of log page ID's is found */ - - length = sizeof(struct wdc_c2_log_page_header); - hdr_ptr = (struct wdc_c2_log_page_header *)data; - sph = (struct wdc_c2_log_subpage_header *)(data + length); - found = wdc_get_dev_mng_log_entry(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph); - if (found) { - *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8)); - if (*cbs_data == NULL) { - fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); - goto end; - } - memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length)); - } else { - /* not found with uuid = 1 try with uuid = 0 */ - uuid_ix = 0; - /* get the log page data */ - struct nvme_get_log_args args = { - .args_size = sizeof(args), + /* get the log page data with the increased length */ + struct nvme_get_log_args args_data = { + .args_size = sizeof(args_data), .fd = dev_fd(dev), .lid = lid, .nsid = 0xFFFFFFFF, @@ -2098,44 +2335,135 @@ static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, .uuidx = uuid_ix, .csi = NVME_CSI_NVM, .ot = false, - .len = le32_to_cpu(hdr_ptr->length), + .len = length, .log = data, .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, .result = NULL, }; - ret = nvme_get_log(&args); + ret = nvme_get_log(&args_data); - hdr_ptr = (struct wdc_c2_log_page_header *)data; - sph = (struct wdc_c2_log_subpage_header *)(data + length); - found = wdc_get_dev_mng_log_entry(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph); - if (found) { - *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8)); - if (*cbs_data == NULL) { - fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); - goto end; - } - memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length)); + if (ret) { + fprintf(stderr, + "ERROR: WDC: Unable to read 0x%x Log Page data with uuid %d, ret = 0x%x\n", + lid, uuid_ix, ret); + goto end; + } + } - } else { - /* WD version not found */ - fprintf(stderr, "ERROR : WDC : Unable to find correct version of page 0x%x, entry id = %d\n", lid, log_id); + /* Check the log data to see if the WD version of log page ID's is found */ + length = sizeof(struct wdc_c2_log_page_header); + hdr_ptr = (struct wdc_c2_log_page_header *)data; + sph = (struct wdc_c2_log_subpage_header *)(data + length); + found = wdc_get_dev_mng_log_entry(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph); + if (found) { + *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8)); + if (!*cbs_data) { + fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno)); + found = false; + goto end; } + memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length)); + } else { + fprintf(stderr, "ERROR: WDC: C2 log id 0x%x not found with uuid index %d\n", + log_id, uuid_ix); } + end: free(data); return found; } -static bool wdc_nvme_check_supported_log_page(nvme_root_t r, - struct nvme_dev *dev, - __u8 log_id) +static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, + __u8 log_id, void **cbs_data) +{ + int ret = -1; + bool found = false; + __u8 uuid_ix = 0; + __u8 lid = 0; + *cbs_data = NULL; + __u32 device_id, read_vendor_id; + bool uuid_present = false; + int index = 0, uuid_index = 0; + struct nvme_id_uuid_list uuid_list; + + ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); + if (ret == 0) { + if (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) { + lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8; + uuid_ix = 0; + } else { + lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID; + } + } else { + fprintf(stderr, "ERROR: WDC: get pci ids: %d\n", ret); + return false; + } + + typedef struct nvme_id_uuid_list_entry *uuid_list_entry; + + memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list)); + if (wdc_CheckUuidListSupport(dev, &uuid_list)) { + uuid_list_entry uuid_list_entry_ptr = (uuid_list_entry)&uuid_list.entry[0]; + + while (index <= NVME_ID_UUID_LIST_MAX && + !wdc_UuidEqual(uuid_list_entry_ptr, (uuid_list_entry)UUID_END)) { + + if (wdc_UuidEqual(uuid_list_entry_ptr, + (uuid_list_entry)WDC_UUID)) { + uuid_present = true; + break; + } else if (wdc_UuidEqual(uuid_list_entry_ptr, + (uuid_list_entry)WDC_UUID_SN640_3) && + wdc_is_sn640_3(device_id)) { + uuid_present = true; + break; + } + index++; + uuid_list_entry_ptr = (uuid_list_entry)&uuid_list.entry[index]; + } + if (uuid_present) + uuid_index = index + 1; + } + + if (uuid_present) { + /* use the uuid index found above */ + found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_index); + } else if (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) { + uuid_index = 0; + found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_index); + } else { + if (!uuid_index && needs_c2_log_page_check(device_id)) { + /* In certain devices that don't support UUID lists, there are multiple + * definitions of the C2 logpage. In those cases, the code + * needs to try two UUID indexes and use an identification algorithm + * to determine which is returning the correct log page data. + */ + uuid_ix = 1; + } + + found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix); + + if (!found) { + /* not found with uuid = 1 try with uuid = 0 */ + uuid_ix = 0; + fprintf(stderr, "Not found, requesting log page with uuid_index %d\n", + uuid_index); + + found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix); + } + } + + return found; +} + +static bool wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *dev, __u8 log_id) { int i; bool found = false; struct wdc_c2_cbs_data *cbs_data = NULL; if (get_dev_mgment_cbs_data(r, dev, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) { - if (cbs_data != NULL) { + if (cbs_data) { for (i = 0; i < le32_to_cpu(cbs_data->length); i++) { if (log_id == cbs_data->data[i]) { found = true; @@ -2145,30 +2473,31 @@ static bool wdc_nvme_check_supported_log_page(nvme_root_t r, #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"); + fprintf(stderr, "ERROR: WDC: Log Page 0x%x not supported\n", log_id); + fprintf(stderr, "WDC: Supported Log Pages:\n"); /* print the supported pages */ d((__u8 *)cbs_data->data, le32_to_cpu(cbs_data->length), 16, 1); } #endif free(cbs_data); - } else - fprintf(stderr, "ERROR : WDC : cbs_data ptr = NULL\n"); - } else - fprintf(stderr, "ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", WDC_C2_LOG_PAGES_SUPPORTED_ID); + } else { + fprintf(stderr, "ERROR: WDC: cbs_data ptr = NULL\n"); + } + } else { + fprintf(stderr, "ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n", + WDC_C2_LOG_PAGES_SUPPORTED_ID); + } return found; } -static bool wdc_nvme_get_dev_status_log_data(nvme_root_t r, - struct nvme_dev *dev, - __le32 *ret_data, - __u8 log_id) +static bool wdc_nvme_get_dev_status_log_data(nvme_root_t r, struct nvme_dev *dev, __le32 *ret_data, + __u8 log_id) { __u32 *cbs_data = NULL; if (get_dev_mgment_cbs_data(r, dev, log_id, (void *)&cbs_data)) { - if (cbs_data != NULL) { + if (cbs_data) { memcpy((void *)ret_data, (void *)cbs_data, 4); free(cbs_data); @@ -2185,13 +2514,12 @@ static int wdc_do_clear_dump(struct nvme_dev *dev, __u8 opcode, __u32 cdw12) int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = opcode; admin_cmd.cdw12 = cdw12; ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); - if (ret != 0) { - fprintf(stdout, "ERROR : WDC : Crash dump erase failed\n"); - } + if (ret) + fprintf(stdout, "ERROR: WDC: Crash dump erase failed\n"); nvme_show_status(ret); return ret; } @@ -2204,7 +2532,7 @@ static __u32 wdc_dump_length(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, __u struct nvme_passthru_cmd admin_cmd; l = (struct wdc_log_size *) buf; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = opcode; admin_cmd.addr = (__u64)(uintptr_t)buf; admin_cmd.data_len = WDC_NVME_LOG_SIZE_DATA_LEN; @@ -2212,10 +2540,10 @@ static __u32 wdc_dump_length(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, __u admin_cmd.cdw12 = cdw12; ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); - if (ret != 0) { + if (ret) { l->log_size = 0; ret = -1; - fprintf(stderr, "ERROR : WDC : reading dump length failed\n"); + fprintf(stderr, "ERROR: WDC: reading dump length failed\n"); nvme_show_status(ret); return ret; } @@ -2232,7 +2560,7 @@ static __u32 wdc_dump_length_e6(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = opcode; admin_cmd.addr = (__u64)(uintptr_t)dump_hdr; admin_cmd.data_len = WDC_NVME_LOG_SIZE_HDR_LEN; @@ -2240,8 +2568,8 @@ static __u32 wdc_dump_length_e6(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, admin_cmd.cdw12 = cdw12; ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); - if (ret != 0) { - fprintf(stderr, "ERROR : WDC : reading dump length failed\n"); + if (ret) { + fprintf(stderr, "ERROR: WDC: reading dump length failed\n"); nvme_show_status(ret); } @@ -2253,7 +2581,7 @@ static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_d int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE; admin_cmd.nsid = 0xFFFFFFFF; admin_cmd.addr = (__u64)(uintptr_t)dump_data; @@ -2267,8 +2595,8 @@ static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_d ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); - if (ret != 0) { - fprintf(stderr, "ERROR : WDC : reading DUI data failed\n"); + if (ret) { + fprintf(stderr, "ERROR: WDC: reading DUI data failed\n"); nvme_show_status(ret); } @@ -2281,7 +2609,7 @@ static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dum struct nvme_passthru_cmd admin_cmd; __u64 offset_lo, offset_hi; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE; admin_cmd.nsid = 0xFFFFFFFF; admin_cmd.addr = (__u64)(uintptr_t)dump_data; @@ -2298,15 +2626,15 @@ static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dum admin_cmd.cdw14 = WDC_NVME_CAP_DUI_DISABLE_IO; ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); - if (ret != 0) { - fprintf(stderr, "ERROR : WDC : reading DUI data V2 failed\n"); + if (ret) { + fprintf(stderr, "ERROR: WDC: reading DUI data V2 failed\n"); nvme_show_status(ret); } return ret; } -static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode,__u32 data_len, +static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode, __u32 data_len, __u32 cdw12, char *file, __u32 xfer_size) { int ret = 0; @@ -2316,13 +2644,13 @@ static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode,__u32 data_len, struct nvme_passthru_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)); + dump_data = (__u8 *)malloc(sizeof(__u8) * dump_length); + if (!dump_data) { + fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno)); return -1; } - memset(dump_data, 0, sizeof (__u8) * dump_length); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(dump_data, 0, sizeof(__u8) * dump_length); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); curr_data_offset = 0; curr_data_len = xfer_size; i = 0; @@ -2337,10 +2665,10 @@ static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode,__u32 data_len, while (curr_data_offset < data_len) { ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); - if (ret != 0) { + if (ret) { nvme_show_status(ret); - fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", - __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr); + fprintf(stderr, "%s: ERROR: WDC: Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", + __func__, i, admin_cmd.data_len, curr_data_offset, (unsigned long)admin_cmd.addr); break; } @@ -2357,7 +2685,7 @@ static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode,__u32 data_len, i++; } - if (ret == 0) { + if (!ret) { nvme_show_status(ret); ret = wdc_create_log_file(file, dump_data, dump_length); } @@ -2365,7 +2693,7 @@ static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode,__u32 data_len, return ret; } -static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, +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; @@ -2374,14 +2702,24 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, int i; struct nvme_passthru_cmd admin_cmd; - dump_data = (__u8 *) malloc(sizeof (__u8) * data_len); + /* if data_len is not 4 byte aligned */ + if (data_len & 0x00000003) { + /* Round down to the next 4 byte aligned value */ + fprintf(stderr, "%s: INFO: data_len 0x%x not 4 byte aligned.\n", + __func__, data_len); + fprintf(stderr, "%s: INFO: Round down to 0x%x.\n", + __func__, (data_len &= 0xFFFFFFFC)); + data_len &= 0xFFFFFFFC; + } - if (dump_data == NULL) { - fprintf(stderr, "%s: ERROR : malloc : %s\n", __func__, strerror(errno)); + dump_data = (__u8 *)malloc(sizeof(__u8) * data_len); + + if (!dump_data) { + fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno)); return -1; } - memset(dump_data, 0, sizeof (__u8) * data_len); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(dump_data, 0, sizeof(__u8) * data_len); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); curr_data_offset = WDC_NVME_LOG_SIZE_HDR_LEN; i = 0; @@ -2391,7 +2729,8 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, admin_cmd.opcode = opcode; admin_cmd.cdw12 = cdw12; - log_size = data_len; + /* subtract off the header size since that was already copied into the buffer */ + log_size = (data_len - curr_data_offset); while (log_size > 0) { xfer_size = min(xfer_size, log_size); @@ -2401,10 +2740,10 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, admin_cmd.cdw13 = curr_data_offset >> 2; ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); - if (ret != 0) { + if (ret) { nvme_show_status(ret); - fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", - __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr); + fprintf(stderr, "%s: ERROR: WDC: Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", + __func__, i, admin_cmd.data_len, curr_data_offset, (unsigned long)admin_cmd.addr); break; } @@ -2413,13 +2752,13 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, i++; } - if (ret == 0) { - fprintf(stderr, "%s: ", __func__); + if (!ret) { + fprintf(stderr, "%s: INFO: ", __func__); nvme_show_status(ret); } else { - fprintf(stderr, "%s: FAILURE: ", __func__); + fprintf(stderr, "%s: FAILURE: ", __func__); nvme_show_status(ret); - fprintf(stderr, "%s: Partial data may have been captured\n", __func__); + fprintf(stderr, "%s: Partial data may have been captured\n", __func__); snprintf(file + strlen(file), PATH_MAX, "%s", "-PARTIAL"); } @@ -2430,7 +2769,7 @@ static int wdc_do_dump_e6(int fd, __u32 opcode,__u32 data_len, } static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file, - __u32 bs, int type, int data_area) + __u32 bs, int type, int data_area) { struct nvme_telemetry_log *log; size_t full_size = 0; @@ -2445,11 +2784,10 @@ static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file, __u64 capabilities = 0; nvme_root_t r; - memset(&ctrl, 0, sizeof (struct nvme_id_ctrl)); + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); err = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (err) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " - "0x%x\n", err); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", err); return err; } @@ -2468,26 +2806,23 @@ static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file, if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) { /* Verify the Controller Initiated Option is enabled */ err = nvme_get_features_data(dev_fd(dev), - WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, - 0, 4, buf, &result); - if (err == 0) { - if (result == 0) { + WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, + 0, 4, buf, &result); + if (!err) { + if (!result) { /* enabled */ host_gen = 0; ctrl_init = 1; - } - else { + } else { fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__); return -EINVAL; } - } - else { - fprintf(stderr, "ERROR : WDC: Get telemetry option feature failed."); + } else { + fprintf(stderr, "ERROR: WDC: Get telemetry option feature failed."); nvme_show_status(err); return -EPERM; } - } - else { + } else { host_gen = 0; ctrl_init = 1; } @@ -2510,13 +2845,13 @@ static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file, if (ctrl_init) err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log, - data_area, &full_size); + data_area, &full_size); else if (host_gen) err = nvme_get_new_host_telemetry(dev_fd(dev), &log, data_area, &full_size); else err = nvme_get_host_telemetry(dev_fd(dev), &log, data_area, - &full_size); + &full_size); if (err < 0) { perror("get-telemetry-log"); @@ -2528,8 +2863,8 @@ static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file, } /* - * Continuously pull data until the offset hits the end of the last - * block. + *Continuously pull data until the offset hits the end of the last + *block. */ data_written = 0; data_remaining = full_size; @@ -2553,7 +2888,7 @@ static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file, } if (fsync(output) < 0) { - fprintf(stderr, "ERROR : %s: fsync : %s\n", __func__, strerror(errno)); + fprintf(stderr, "ERROR: %s: fsync: %s\n", __func__, strerror(errno)); err = -1; } @@ -2571,9 +2906,9 @@ static int wdc_do_cap_diag(nvme_root_t r, struct nvme_dev *dev, char *file, 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)); + log_hdr = (struct wdc_e6_log_hdr *)malloc(e6_log_hdr_size); + if (!log_hdr) { + fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno)); ret = -1; goto out; } @@ -2593,401 +2928,481 @@ static int wdc_do_cap_diag(nvme_root_t r, struct nvme_dev *dev, char *file, 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"); + if (!cap_diag_length) { + fprintf(stderr, "INFO: WDC: Capture Diagnostics log is empty\n"); } else { ret = wdc_do_dump_e6(dev_fd(dev), - WDC_NVME_CAP_DIAG_OPCODE, + 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); + fprintf(stderr, "INFO: WDC: Capture Diagnostics log, length = 0x%x\n", cap_diag_length); } } else if ((type == WDC_TELEMETRY_TYPE_HOST) || (type == WDC_TELEMETRY_TYPE_CONTROLLER)) { /* Get the desired telemetry log page */ ret = wdc_do_cap_telemetry_log(dev, file, xfer_size, type, data_area); - } else - fprintf(stderr, "%s: ERROR : Invalid type : %d\n", __func__, type); + } 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) +static int wdc_do_cap_dui_v1(int fd, char *file, __u32 xfer_size, int data_area, int verbose, + struct wdc_dui_log_hdr *log_hdr, __s64 *total_size) { - 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; - __u64 cap_dui_length_v4; - __u8 *dump_data = NULL; + __s32 log_size = 0; + __u32 cap_dui_length = le32_to_cpu(log_hdr->log_size); + __u32 curr_data_offset = 0; __u8 *buffer_addr; - __s64 total_size = 0; + __u8 *dump_data = NULL; + bool last_xfer = false; + int err; int i; int j; - bool last_xfer = false; - int err = 0, output = 0; + int output; + int ret = 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); + if (verbose) { + fprintf(stderr, "INFO: WDC: Capture V1 Device Unit Info log, data area = %d\n", + data_area); + fprintf(stderr, "INFO: WDC: DUI Header Version = 0x%x\n", log_hdr->hdr_version); + fprintf(stderr, "INFO: WDC: DUI section count = 0x%x\n", log_hdr->section_count); + fprintf(stderr, "INFO: WDC: DUI log size = 0x%x\n", log_hdr->log_size); + } + + if (!cap_dui_length) { + fprintf(stderr, "INFO: WDC: Capture V1 Device Unit Info log is empty\n"); + return 0; + } + + /* parse log header for all sections up to specified data area inclusively */ + if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) { + for (j = 0; j < log_hdr->section_count; j++) { + log_size += log_hdr->log_section[j].section_size; + if (verbose) + fprintf(stderr, + "%s: section size 0x%x, total size = 0x%x\n", + __func__, + (unsigned int)log_hdr->log_section[j].section_size, + (unsigned int)log_size); + + } + } else { + log_size = cap_dui_length; + } + + *total_size = log_size; + + dump_data = (__u8 *)malloc(sizeof(__u8) * xfer_size); + if (!dump_data) { + fprintf(stderr, "%s: ERROR: dump data V1 malloc failed : status %s, size = 0x%x\n", + __func__, strerror(errno), (unsigned int)xfer_size); return -1; } - memset(log_hdr, 0, dui_log_hdr_size); + memset(dump_data, 0, sizeof(__u8) * xfer_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 : ", __func__); - nvme_show_status(ret); - goto out; + output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) { + fprintf(stderr, "%s: Failed to open output file %s: %s!\n", __func__, file, + strerror(errno)); + free(dump_data); + return output; } - /* Check the Log Header version */ - if ((log_hdr->hdr_version & 0xFF) == 0x00 || - (log_hdr->hdr_version & 0xFF) == 0x01) { - __s32 log_size = 0; - __u32 curr_data_offset = 0; + /* 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; + } - cap_dui_length = le32_to_cpu(log_hdr->log_size); + log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE; + curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE; + i = 0; + buffer_addr = dump_data; - 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); - } + for (; log_size > 0; log_size -= xfer_size) { + xfer_size = min(xfer_size, log_size); - 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; + if (log_size <= xfer_size) + last_xfer = true; + + ret = wdc_dump_dui_data(fd, xfer_size, curr_data_offset, buffer_addr, last_xfer); + if (ret) { + fprintf(stderr, + "%s: ERROR: WDC: Get chunk %d, size = 0x%"PRIx64", offset = 0x%x, addr = %p\n", + __func__, i, (uint64_t)log_size, curr_data_offset, buffer_addr); + fprintf(stderr, "%s: ERROR: WDC: ", __func__); + nvme_show_status(ret); + break; + } - total_size = log_size; + /* write the dump data into the file */ + err = write(output, (void *)buffer_addr, xfer_size); + if (err != xfer_size) { + fprintf(stderr, + "%s: ERROR: WDC: Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%x\n", + __func__, i, err, xfer_size); + ret = -1; + goto free_mem; + } - 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; - } + curr_data_offset += xfer_size; + i++; + } - /* 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; - } +free_mem: + close(output); + free(dump_data); + return ret; +} - log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE; - curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE; - i = 0; - buffer_addr = dump_data; +static int wdc_do_cap_dui_v2_v3(int fd, char *file, __u32 xfer_size, int data_area, int verbose, + struct wdc_dui_log_hdr *log_hdr, __s64 *total_size, __u64 file_size, + __u64 offset) +{ + __u64 cap_dui_length_v3; + __u64 curr_data_offset = 0; + __s64 log_size = 0; + __u64 xfer_size_long = (__u64)xfer_size; + __u8 *buffer_addr; + __u8 *dump_data = NULL; + bool last_xfer = false; + int err; + int i; + int j; + int output; + int ret = 0; + struct wdc_dui_log_hdr_v3 *log_hdr_v3 = (struct wdc_dui_log_hdr_v3 *)log_hdr; - for(; log_size > 0; log_size -= xfer_size) { - xfer_size = min(xfer_size, log_size); + cap_dui_length_v3 = le64_to_cpu(log_hdr_v3->log_size); - if (log_size <= xfer_size) - last_xfer = true; + if (verbose) { + fprintf(stderr, + "INFO: WDC: Capture V2 or V3 Device Unit Info log, data area = %d\n", + data_area); - ret = wdc_dump_dui_data(fd, xfer_size, curr_data_offset, buffer_addr, last_xfer); - if (ret != 0) { - fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%x, addr = %p\n", - __func__, i, (uint64_t)log_size, curr_data_offset, buffer_addr); - fprintf(stderr, "%s: ERROR : WDC : ", - __func__); - nvme_show_status(ret); - break; - } + fprintf(stderr, "INFO: WDC: DUI Header Version = 0x%x\n", + log_hdr_v3->hdr_version); + if ((log_hdr->hdr_version & 0xFF) == 0x03) + fprintf(stderr, "INFO: WDC: DUI Product ID = 0x%x/%c\n", + log_hdr_v3->product_id, log_hdr_v3->product_id); + } - /* 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; - } + if (!cap_dui_length_v3) { + fprintf(stderr, "INFO: WDC: Capture V2 or V3 Device Unit Info log is empty\n"); + return 0; + } - curr_data_offset += xfer_size; - i++; + /* parse log header for all sections up to specified data area inclusively */ + if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) { + for (j = 0; j < WDC_NVME_DUI_MAX_SECTION_V3; j++) { + if (log_hdr_v3->log_section[j].data_area_id <= data_area && + log_hdr_v3->log_section[j].data_area_id) { + log_size += log_hdr_v3->log_section[j].section_size; + if (verbose) + fprintf(stderr, + "%s: Data area ID %d : section size 0x%x, total size = 0x%"PRIx64"\n", + __func__, log_hdr_v3->log_section[j].data_area_id, + (unsigned int)log_hdr_v3->log_section[j].section_size, + (uint64_t)log_size); + } else { + if (verbose) + fprintf(stderr, "%s: break, total size = 0x%"PRIx64"\n", + __func__, (uint64_t)log_size); + break; } } + } else { + log_size = cap_dui_length_v3; } - else if (((log_hdr->hdr_version & 0xFF) == 0x02) || - ((log_hdr->hdr_version & 0xFF) == 0x03)) { /* Process Version 2 or 3 header */ - __s64 log_size = 0; - __u64 curr_data_offset = 0; - __u64 xfer_size_long = (__u64)xfer_size; - log_hdr_v3 = (struct wdc_dui_log_hdr_v3 *)log_hdr; + *total_size = log_size; - cap_dui_length_v3 = le64_to_cpu(log_hdr_v3->log_size); + if (offset >= *total_size) { + fprintf(stderr, + "%s: INFO: WDC: Offset 0x%"PRIx64" exceeds total size 0x%"PRIx64", no data retrieved\n", + __func__, (uint64_t)offset, (uint64_t)*total_size); + return -1; + } - if (verbose) { - fprintf(stderr, "INFO : WDC : Capture V2 or V3 Device Unit Info log, data area = %d\n", data_area); + dump_data = (__u8 *)malloc(sizeof(__u8) * xfer_size_long); + if (!dump_data) { + fprintf(stderr, + "%s: ERROR: dump data v3 malloc failed : status %s, size = 0x%"PRIx64"\n", + __func__, strerror(errno), (uint64_t)xfer_size_long); + return -1; + } + memset(dump_data, 0, sizeof(__u8) * xfer_size_long); - fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr_v3->hdr_version); - if ((log_hdr->hdr_version & 0xFF) == 0x03) - fprintf(stderr, "INFO : WDC : DUI Product ID = 0x%x/%c\n", log_hdr_v3->product_id, log_hdr_v3->product_id); - } + output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) { + fprintf(stderr, "%s: Failed to open output file %s: %s!\n", + __func__, file, strerror(errno)); + free(dump_data); + return output; + } - 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%"PRIx64"\n", - __func__, log_hdr_v3->log_section[j].data_area_id, (unsigned int)log_hdr_v3->log_section[j].section_size, (uint64_t)log_size); - } - else { - if (verbose) - fprintf(stderr, "%s: break, total size = 0x%"PRIx64"\n", __func__, (uint64_t)log_size); - break; - } - } - } else - log_size = cap_dui_length_v3; + curr_data_offset = 0; - total_size = log_size; + if (file_size) { + /* Write the DUI data based on the passed in file size */ + if ((offset + file_size) > *total_size) + log_size = min((*total_size - offset), file_size); + else + log_size = min(*total_size, file_size); - if (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; - } + 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); - 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%"PRIx64"\n", - __func__, strerror(errno), (uint64_t)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 = offset; + } - curr_data_offset = 0; + i = 0; + buffer_addr = dump_data; - 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); + for (; log_size > 0; log_size -= xfer_size_long) { + xfer_size_long = min(xfer_size_long, log_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); + if (log_size <= xfer_size_long) + last_xfer = true; + + ret = wdc_dump_dui_data_v2(fd, (__u32)xfer_size_long, curr_data_offset, buffer_addr, + last_xfer); + if (ret) { + fprintf(stderr, + "%s: ERROR: WDC: Get chunk %d, size = 0x%"PRIx64", offset = 0x%"PRIx64", addr = %p\n", + __func__, i, (uint64_t)*total_size, (uint64_t)curr_data_offset, + buffer_addr); + fprintf(stderr, "%s: ERROR: WDC: ", __func__); + nvme_show_status(ret); + break; + } - curr_data_offset = offset; + /* write the dump data into the file */ + err = write(output, (void *)buffer_addr, xfer_size_long); + if (err != xfer_size_long) { + fprintf(stderr, + "%s: ERROR: WDC: Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%"PRIx64"\n", + __func__, i, err, (uint64_t)xfer_size_long); + ret = -1; + goto free_mem; + } - } + curr_data_offset += xfer_size_long; + i++; + } - i = 0; - buffer_addr = dump_data; +free_mem: + close(output); + free(dump_data); + return ret; +} - for(; log_size > 0; log_size -= xfer_size_long) { - xfer_size_long = min(xfer_size_long, log_size); +static int wdc_do_cap_dui_v4(int fd, char *file, __u32 xfer_size, int data_area, int verbose, + struct wdc_dui_log_hdr *log_hdr, __s64 *total_size, __u64 file_size, + __u64 offset) +{ + __s64 log_size = 0; + __s64 section_size_bytes = 0; + __s64 xfer_size_long = (__s64)xfer_size; + __u64 cap_dui_length_v4; + __u64 curr_data_offset = 0; + __u8 *buffer_addr; + __u8 *dump_data = NULL; + int err; + int i; + int j; + int output; + int ret = 0; + bool last_xfer = false; + struct wdc_dui_log_hdr_v4 *log_hdr_v4 = (struct wdc_dui_log_hdr_v4 *)log_hdr; - if (log_size <= xfer_size_long) - last_xfer = true; + cap_dui_length_v4 = le64_to_cpu(log_hdr_v4->log_size_sectors) * WDC_NVME_SN730_SECTOR_SIZE; - 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%"PRIx64", offset = 0x%"PRIx64", addr = %p\n", - __func__, i, (uint64_t)total_size, (uint64_t)curr_data_offset, buffer_addr); - fprintf(stderr, "%s: ERROR : WDC : ", __func__); - nvme_show_status(ret); - break; - } + if (verbose) { + fprintf(stderr, "INFO: WDC: Capture V4 Device Unit Info log, data area = %d\n", data_area); + fprintf(stderr, "INFO: WDC: DUI Header Version = 0x%x\n", log_hdr_v4->hdr_version); + fprintf(stderr, "INFO: WDC: DUI Product ID = 0x%x/%c\n", log_hdr_v4->product_id, log_hdr_v4->product_id); + fprintf(stderr, "INFO: WDC: DUI log size sectors = 0x%x\n", log_hdr_v4->log_size_sectors); + fprintf(stderr, "INFO: WDC: DUI cap_dui_length = 0x%"PRIx64"\n", (uint64_t)cap_dui_length_v4); + } - /* write the dump data into the file */ - err = write(output, (void *)buffer_addr, xfer_size_long); - if (err != xfer_size_long) { - fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%"PRIx64"\n", - __func__, i, err, (uint64_t)xfer_size_long); - goto free_mem; - } + if (!cap_dui_length_v4) { + fprintf(stderr, "INFO: WDC: Capture V4 Device Unit Info log is empty\n"); + return 0; + } - curr_data_offset += xfer_size_long; - i++; + /* parse log header for all sections up to specified data area inclusively */ + if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) { + for (j = 0; j < WDC_NVME_DUI_MAX_SECTION; j++) { + if (log_hdr_v4->log_section[j].data_area_id <= data_area && + log_hdr_v4->log_section[j].data_area_id) { + section_size_bytes = ((__s64)log_hdr_v4->log_section[j].section_size_sectors * WDC_NVME_SN730_SECTOR_SIZE); + log_size += section_size_bytes; + if (verbose) + fprintf(stderr, + "%s: Data area ID %d : section size 0x%x sectors, section size 0x%"PRIx64" bytes, total size = 0x%"PRIx64"\n", + __func__, log_hdr_v4->log_section[j].data_area_id, + log_hdr_v4->log_section[j].section_size_sectors, + (uint64_t)section_size_bytes, (uint64_t)log_size); + } else { + if (verbose) + fprintf(stderr, "%s: break, total size = 0x%"PRIx64"\n", __func__, (uint64_t)log_size); + break; } } + } else { + log_size = cap_dui_length_v4; } - else if ((log_hdr->hdr_version & 0xFF) == 0x04) { - __s64 log_size = 0; - __u64 curr_data_offset = 0; - struct wdc_dui_log_hdr_v4 *log_hdr_v4; - log_hdr_v4 = (struct wdc_dui_log_hdr_v4 *)log_hdr; - __s64 xfer_size_long = (__s64)xfer_size; - __s64 section_size_bytes = 0; - cap_dui_length_v4 = le64_to_cpu(log_hdr_v4->log_size_sectors) * WDC_NVME_SN730_SECTOR_SIZE; + *total_size = log_size; - if (verbose) { - fprintf(stderr, "INFO : WDC : Capture V4 Device Unit Info log, data area = %d\n", data_area); - fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr_v4->hdr_version); - fprintf(stderr, "INFO : WDC : DUI Product ID = 0x%x/%c\n", log_hdr_v4->product_id, log_hdr_v4->product_id); - fprintf(stderr, "INFO : WDC : DUI log size sectors = 0x%x\n", log_hdr_v4->log_size_sectors); - fprintf(stderr, "INFO : WDC : DUI cap_dui_length = 0x%"PRIx64"\n", (uint64_t)cap_dui_length_v4); - } + if (offset >= *total_size) { + fprintf(stderr, + "%s: INFO: WDC: Offset 0x%"PRIx64" exceeds total size 0x%"PRIx64", no data retrieved\n", + __func__, (uint64_t)offset, (uint64_t)*total_size); + return -1; + } - if (cap_dui_length_v4 == 0) { - fprintf(stderr, "INFO : WDC : Capture V4 Device Unit Info log is empty\n"); - } else { - /* parse log header for all sections up to specified data area inclusively */ - if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) { - for(j = 0; j < WDC_NVME_DUI_MAX_SECTION; j++) { - if (log_hdr_v4->log_section[j].data_area_id <= data_area && - log_hdr_v4->log_section[j].data_area_id != 0) { - section_size_bytes = ((__s64)log_hdr_v4->log_section[j].section_size_sectors * WDC_NVME_SN730_SECTOR_SIZE); - log_size += section_size_bytes; - if (verbose) - fprintf(stderr, "%s: Data area ID %d : section size 0x%x sectors, section size 0x%"PRIx64" bytes, total size = 0x%"PRIx64"\n", - __func__, log_hdr_v4->log_section[j].data_area_id, log_hdr_v4->log_section[j].section_size_sectors, (uint64_t)section_size_bytes, - (uint64_t)log_size); - } - else { - if (verbose) - fprintf(stderr, "%s: break, total size = 0x%"PRIx64"\n", __func__, (uint64_t)log_size); - break; - } - } - } else - log_size = cap_dui_length_v4; + dump_data = (__u8 *)malloc(sizeof(__u8) * xfer_size_long); + if (!dump_data) { + fprintf(stderr, "%s: ERROR: dump data V4 malloc failed : status %s, size = 0x%x\n", + __func__, strerror(errno), (unsigned int)xfer_size_long); + return -1; + } + memset(dump_data, 0, sizeof(__u8) * xfer_size_long); - total_size = log_size; + output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) { + fprintf(stderr, "%s: Failed to open output file %s: %s!\n", __func__, file, + strerror(errno)); + free(dump_data); + return output; + } - 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; - } + curr_data_offset = 0; - dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size_long); - if (dump_data == NULL) { - fprintf(stderr, "%s: ERROR : dump data V4 malloc failed : status %s, size = 0x%x\n", - __func__, strerror(errno), (unsigned int)xfer_size_long); - ret = -1; - goto out; - } - memset(dump_data, 0, sizeof (__u8) * xfer_size_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; - } + if (file_size) { + /* Write the DUI data based on the passed in file size */ + if ((offset + file_size) > *total_size) + log_size = min((*total_size - offset), file_size); + else + log_size = min(*total_size, file_size); - curr_data_offset = 0; + 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); - 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); + curr_data_offset = offset; + } - 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); + i = 0; + buffer_addr = dump_data; - curr_data_offset = offset; + 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; - i = 0; - buffer_addr = dump_data; + ret = wdc_dump_dui_data_v2(fd, (__u32)xfer_size_long, curr_data_offset, buffer_addr, last_xfer); + if (ret) { + fprintf(stderr, + "%s: ERROR: WDC: Get chunk %d, size = 0x%"PRIx64", offset = 0x%"PRIx64", addr = %p\n", + __func__, i, (uint64_t)log_size, (uint64_t)curr_data_offset, + buffer_addr); + fprintf(stderr, "%s: ERROR: WDC:", __func__); + nvme_show_status(ret); + break; + } - for(; log_size > 0; log_size -= xfer_size_long) { - xfer_size_long = min(xfer_size_long, log_size); + /* write the dump data into the file */ + err = write(output, (void *)buffer_addr, xfer_size_long); + if (err != xfer_size_long) { + fprintf(stderr, + "%s: ERROR: WDC: Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size_long = 0x%"PRIx64"\n", + __func__, i, err, (uint64_t)xfer_size_long); + ret = -1; + goto free_mem; + } - if (log_size <= xfer_size_long) - last_xfer = true; + curr_data_offset += xfer_size_long; + i++; + } - 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%"PRIx64", offset = 0x%"PRIx64", addr = %p\n", - __func__, i, (uint64_t)log_size, (uint64_t)curr_data_offset, buffer_addr); - fprintf(stderr, "%s: ERROR : WDC :", __func__); - nvme_show_status(ret); - break; - } +free_mem: + close(output); + free(dump_data); + return ret; +} - /* write the dump data into the file */ - err = write(output, (void *)buffer_addr, xfer_size_long); - if (err != xfer_size_long) { - fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size_long = 0x%"PRIx64"\n", - __func__, i, err, (uint64_t)xfer_size_long); - goto free_mem; - } +static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, int verbose, + __u64 file_size, __u64 offset) +{ + int ret = 0; + __u32 dui_log_hdr_size = WDC_NVME_CAP_DUI_HEADER_SIZE; + struct wdc_dui_log_hdr *log_hdr; + __s64 total_size = 0; + bool last_xfer = false; - curr_data_offset += xfer_size_long; - i++; - } - } + log_hdr = (struct wdc_dui_log_hdr *)malloc(dui_log_hdr_size); + if (!log_hdr) { + fprintf(stderr, "%s: ERROR: log header malloc failed : status %s, size 0x%x\n", + __func__, strerror(errno), dui_log_hdr_size); + return -1; } - else { - fprintf(stderr, "INFO : WDC : Unsupported header version = 0x%x\n", log_hdr->hdr_version); - goto out; + memset(log_hdr, 0, dui_log_hdr_size); + + /* get the dui telemetry and log headers */ + ret = wdc_dump_dui_data(fd, WDC_NVME_CAP_DUI_HEADER_SIZE, 0x00, (__u8 *)log_hdr, last_xfer); + if (ret) { + fprintf(stderr, "%s: ERROR: WDC: Get DUI headers failed\n", __func__); + fprintf(stderr, "%s: ERROR: WDC: ", __func__); + nvme_show_status(ret); + goto out; + } + + /* Check the Log Header version */ + if ((log_hdr->hdr_version & 0xFF) == 0x00 || (log_hdr->hdr_version & 0xFF) == 0x01) { + ret = wdc_do_cap_dui_v1(fd, file, xfer_size, data_area, verbose, log_hdr, + &total_size); + if (ret) + goto out; + } else if ((log_hdr->hdr_version & 0xFF) == 0x02 || + (log_hdr->hdr_version & 0xFF) == 0x03) { + /* Process Version 2 or 3 header */ + ret = wdc_do_cap_dui_v2_v3(fd, file, xfer_size, data_area, verbose, log_hdr, + &total_size, file_size, offset); + if (ret) + goto out; + } else if ((log_hdr->hdr_version & 0xFF) == 0x04) { + ret = wdc_do_cap_dui_v4(fd, file, xfer_size, data_area, verbose, log_hdr, + &total_size, file_size, offset); + if (ret) + goto out; + } else { + fprintf(stderr, "INFO: WDC: Unsupported header version = 0x%x\n", + log_hdr->hdr_version); + goto out; } nvme_show_status(ret); if (verbose) - fprintf(stderr, "INFO : WDC : Capture Device Unit Info log, length = 0x%"PRIx64"\n", (uint64_t)total_size); + fprintf(stderr, "INFO: WDC: Capture Device Unit Info log, length = 0x%"PRIx64"\n", + (uint64_t)total_size); - free_mem: - close(output); - free(dump_data); - - out: +out: free(log_hdr); return ret; } @@ -3027,18 +3442,18 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command, r = nvme_scan(NULL); - if (cfg.file != NULL) + if (cfg.file) strncpy(f, cfg.file, PATH_MAX - 1); - if (cfg.xfer_size != 0) + if (cfg.xfer_size) xfer_size = cfg.xfer_size; ret = wdc_get_serial_name(dev, f, PATH_MAX, "cap_diag"); if (ret) { - fprintf(stderr, "ERROR : WDC: failed to generate file name\n"); + fprintf(stderr, "ERROR: WDC: failed to generate file name\n"); goto out; } - if (cfg.file == NULL) { + if (!cfg.file) { if (strlen(f) > PATH_MAX - 5) { - fprintf(stderr, "ERROR : WDC: file name overflow\n"); + fprintf(stderr, "ERROR: WDC: file name overflow\n"); ret = -1; goto out; } @@ -3049,8 +3464,7 @@ static int wdc_cap_diag(int argc, char **argv, struct command *command, if ((capabilities & WDC_DRIVE_CAP_CAP_DIAG) == WDC_DRIVE_CAP_CAP_DIAG) ret = wdc_do_cap_diag(r, dev, f, xfer_size, 0, 0); else - fprintf(stderr, - "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); out: nvme_free_tree(r); dev_close(dev); @@ -3063,12 +3477,13 @@ static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcod uint32_t *output = NULL; struct nvme_passthru_cmd admin_cmd; - if ((output = (uint32_t*)malloc(sizeof(uint32_t))) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + output = (uint32_t *)malloc(sizeof(uint32_t)); + if (!output) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(output, 0, sizeof (uint32_t)); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(output, 0, sizeof(uint32_t)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.data_len = 8; admin_cmd.opcode = SN730_NVME_GET_LOG_OPCODE; @@ -3077,23 +3492,24 @@ static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcod admin_cmd.cdw10 = SN730_LOG_CHUNK_SIZE / 4; ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); - if (ret == 0) + if (!ret) *len_buf = *output; free(output); return ret; } -static int wdc_do_get_sn730_log(int fd, void * log_buf, uint32_t offset, uint32_t subopcode) +static int wdc_do_get_sn730_log(int fd, void *log_buf, uint32_t offset, uint32_t subopcode) { int ret; uint8_t *output = NULL; struct nvme_passthru_cmd admin_cmd; - if ((output = (uint8_t*)calloc(SN730_LOG_CHUNK_SIZE, sizeof(uint8_t))) == NULL) { - fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); + output = (uint8_t *)calloc(SN730_LOG_CHUNK_SIZE, sizeof(uint8_t)); + if (!output) { + fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno)); return -1; } - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.data_len = SN730_LOG_CHUNK_SIZE; admin_cmd.opcode = SN730_NVME_GET_LOG_OPCODE; admin_cmd.addr = (uintptr_t)output; @@ -3107,15 +3523,16 @@ static int wdc_do_get_sn730_log(int fd, void * log_buf, uint32_t offset, uint32_ return ret; } -static int get_sn730_log_chunks(int fd, uint8_t* log_buf, uint32_t log_len, uint32_t subopcode) +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; + 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)); + chunk_buf = (uint8_t *)malloc(sizeof(uint8_t) * SN730_LOG_CHUNK_SIZE); + if (!chunk_buf) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); ret = -1; goto out; } @@ -3133,59 +3550,59 @@ static int get_sn730_log_chunks(int fd, uint8_t* log_buf, uint32_t log_len, uint } remaining -= SN730_LOG_CHUNK_SIZE; curr_offset += 1; - } else + } else { goto out; + } } out: free(chunk_buf); return ret; } -static int wdc_do_sn730_get_and_tar(int fd, char * outputName) +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; + 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; + struct tarfile_metadata *tarInfo = NULL; - tarInfo = (struct tarfile_metadata*) malloc(sizeof(tarfile_metadata)); - if (tarInfo == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + tarInfo = (struct tarfile_metadata *)malloc(sizeof(struct tarfile_metadata)); + if (!tarInfo) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); ret = -1; goto free_buf; } - memset(tarInfo, 0, sizeof(tarfile_metadata)); + memset(tarInfo, 0, sizeof(struct tarfile_metadata)); - /* Create Logs directory */ + /* 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", + 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); + 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", + retPtr = getcwd((char *)tarInfo->currDir, MAX_PATH_LEN); + if (retPtr) { + wdc_UtilsSnprintf((char *)tarInfo->bufferFolderPath, MAX_PATH_LEN, "%s%s%s", (char *)tarInfo->currDir, WDC_DE_PATH_SEPARATOR, (char *)tarInfo->bufferFolderName); - else { - fprintf(stderr, "ERROR : WDC : get current working directory failed\n"); + } 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); + 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); @@ -3212,13 +3629,13 @@ static int wdc_do_sn730_get_and_tar(int fd, char * outputName) 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)); + 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)); + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); ret = -1; goto free_buf; } @@ -3252,43 +3669,139 @@ static int wdc_do_sn730_get_and_tar(int fd, char * outputName) } /* 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, + "full_log", (char *)tarInfo->timeString); + wdc_WriteToFile(tarInfo->fileName, (char *)full_log_buf, full_log_len); + + wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR, + "key_log", (char *)tarInfo->timeString); + wdc_WriteToFile(tarInfo->fileName, (char *)key_log_buf, key_log_len); + + wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR, + "core_dump_log", (char *)tarInfo->timeString); + wdc_WriteToFile(tarInfo->fileName, (char *)core_dump_log_buf, core_dump_log_len); + + wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR, + "extended_log", (char *)tarInfo->timeString); + wdc_WriteToFile(tarInfo->fileName, (char *)extended_log_buf, extended_log_len); + + /* Tar the log directory */ + wdc_UtilsSnprintf(tarInfo->tarFileName, sizeof(tarInfo->tarFileName), "%s%s", (char *)tarInfo->bufferFolderPath, WDC_DE_TAR_FILE_EXTN); + wdc_UtilsSnprintf(tarInfo->tarFiles, sizeof(tarInfo->tarFiles), "%s%s%s", (char *)tarInfo->bufferFolderName, WDC_DE_PATH_SEPARATOR, WDC_DE_TAR_FILES); + wdc_UtilsSnprintf(tarInfo->tarCmd, sizeof(tarInfo->tarCmd), "%s %s %s", WDC_DE_TAR_CMD, (char *)tarInfo->tarFileName, (char *)tarInfo->tarFiles); + + ret = system(tarInfo->tarCmd); + + if (ret) + fprintf(stderr, "ERROR: WDC: Tar of log data failed, ret = %d\n", ret); + +free_buf: + free(tarInfo); + free(full_log_buf); + free(core_dump_log_buf); + free(key_log_buf); + free(extended_log_buf); + return ret; +} + +static int dump_internal_logs(struct nvme_dev *dev, char *dir_name, int verbose) +{ + char file_path[128]; + void *telemetry_log; + const size_t bs = 512; + struct nvme_telemetry_log *hdr; + size_t full_size, offset = bs; + int err, output; + + if (verbose) + printf("NVMe Telemetry log...\n"); + + hdr = malloc(bs); + telemetry_log = malloc(bs); + if (!hdr || !telemetry_log) { + fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n", bs, strerror(errno)); + err = -ENOMEM; + goto free_mem; + } + memset(hdr, 0, bs); + + sprintf(file_path, "%s/telemetry.bin", dir_name); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (output < 0) { + fprintf(stderr, "Failed to open output file %s: %s!\n", file_path, strerror(errno)); + err = output; + goto free_mem; + } + + struct nvme_get_log_args args = { + .lpo = 0, + .result = NULL, + .log = hdr, + .args_size = sizeof(args), + .fd = dev_fd(dev), + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .lid = NVME_LOG_LID_TELEMETRY_HOST, + .len = bs, + .nsid = NVME_NSID_ALL, + .csi = NVME_CSI_NVM, + .lsi = NVME_LOG_LSI_NONE, + .lsp = NVME_LOG_TELEM_HOST_LSP_CREATE, + .uuidx = NVME_UUID_NONE, + .rae = true, + .ot = false, + }; - 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); + err = nvme_get_log(&args); + if (err < 0) + perror("get-telemetry-log"); + else if (err > 0) { + nvme_show_status(err); + fprintf(stderr, "Failed to acquire telemetry header %d!\n", err); + goto close_output; + } - 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); + err = write(output, (void *)hdr, bs); + if (err != bs) { + fprintf(stderr, "Failed to flush all data to file!\n"); + goto close_output; + } - 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); + full_size = (le16_to_cpu(hdr->dalb3) * bs) + offset; - /* 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); + while (offset != full_size) { + args.log = telemetry_log; + args.lpo = offset; + args.lsp = NVME_LOG_LSP_NONE; + err = nvme_get_log(&args); + if (err < 0) { + perror("get-telemetry-log"); + break; + } else if (err > 0) { + fprintf(stderr, "Failed to acquire full telemetry log!\n"); + nvme_show_status(err); + break; + } - ret = system(tarInfo->tarCmd); + err = write(output, (void *)telemetry_log, bs); + if (err != bs) { + fprintf(stderr, "Failed to flush all data to file!\n"); + break; + } + err = 0; + offset += bs; + } - if (ret) - fprintf(stderr, "ERROR : WDC : Tar of log data failed, ret = %d\n", ret); +close_output: + close(output); +free_mem: + free(hdr); + free(telemetry_log); -free_buf: - free(tarInfo); - free(full_log_buf); - free(core_dump_log_buf); - free(key_log_buf); - free(extended_log_buf); - return ret; + return err; } static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command, - struct plugin *plugin) + struct plugin *plugin) { char *desc = "Internal Firmware Log."; char *file = "Output file pathname."; @@ -3299,6 +3812,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command char *type = "Telemetry type - NONE, HOST, or CONTROLLER. Currently only supported on the SN530, SN640, SN730, SN740, SN810, SN840 and ZN350 devices."; char *verbose = "Display more debug messages."; char f[PATH_MAX] = {0}; + char fb[PATH_MAX/2] = {0}; char fileSuffix[PATH_MAX] = {0}; struct nvme_dev *dev; nvme_root_t r; @@ -3307,6 +3821,9 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command UtilsTimeInfo timeInfo; __u8 timeStamp[MAX_PATH_LEN]; __u64 capabilities = 0; + __u32 device_id, read_vendor_id; + char file_path[PATH_MAX/2] = {0}; + char cmd_buf[PATH_MAX] = {0}; int ret = -1; struct config { @@ -3348,112 +3865,185 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command if (!wdc_check_device(r, dev)) goto out; - if (cfg.xfer_size != 0) + if (cfg.xfer_size) { xfer_size = cfg.xfer_size; - else { - fprintf(stderr, "ERROR : WDC : Invalid length\n"); + } else { + fprintf(stderr, "ERROR: WDC: Invalid length\n"); goto out; } - if (cfg.file != NULL) { - int verify_file; + ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); - /* 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)); - goto out; + if (!wdc_is_sn861(device_id)) { + if (cfg.file) { + int verify_file; + + /* verify file name and path is valid before getting dump data */ + verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (verify_file < 0) { + fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno)); + goto out; + } + close(verify_file); + strncpy(f, cfg.file, PATH_MAX - 1); + } else { + wdc_UtilsGetTime(&timeInfo); + memset(timeStamp, 0, sizeof(timeStamp)); + wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN, + "%02u%02u%02u_%02u%02u%02u", timeInfo.year, + timeInfo.month, timeInfo.dayOfMonth, + timeInfo.hour, timeInfo.minute, + timeInfo.second); + snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp); + + ret = wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix); + if (ret) { + fprintf(stderr, "ERROR: WDC: failed to generate file name\n"); + goto out; + } } - close(verify_file); - strncpy(f, cfg.file, PATH_MAX - 1); - } else { - wdc_UtilsGetTime(&timeInfo); - memset(timeStamp, 0, sizeof(timeStamp)); - wdc_UtilsSnprintf((char*)timeStamp, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u", - timeInfo.year, timeInfo.month, timeInfo.dayOfMonth, - timeInfo.hour, timeInfo.minute, timeInfo.second); - snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char*)timeStamp); - ret = wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix); - if (ret) { - fprintf(stderr, "ERROR : WDC: failed to generate file name\n"); - goto out; + if (!cfg.file) { + if (strlen(f) > PATH_MAX - 5) { + fprintf(stderr, "ERROR: WDC: file name overflow\n"); + ret = -1; + goto out; + } + strcat(f, ".bin"); } - } + fprintf(stderr, "%s: filename = %s\n", __func__, f); - if (cfg.file == NULL) { - if (strlen(f) > PATH_MAX - 5) { - fprintf(stderr, "ERROR : WDC: file name overflow\n"); + if (cfg.data_area) { + if (cfg.data_area > 5 || cfg.data_area < 1) { + fprintf(stderr, "ERROR: WDC: Data area must be 1-5\n"); + ret = -1; + goto out; + } + } + + if (!cfg.type || !strcmp(cfg.type, "NONE") || !strcmp(cfg.type, "none")) { + telemetry_type = WDC_TELEMETRY_TYPE_NONE; + data_area = 0; + } else if (!strcmp(cfg.type, "HOST") || !strcmp(cfg.type, "host")) { + telemetry_type = WDC_TELEMETRY_TYPE_HOST; + telemetry_data_area = cfg.data_area; + } else if (!strcmp(cfg.type, "CONTROLLER") || !strcmp(cfg.type, "controller")) { + telemetry_type = WDC_TELEMETRY_TYPE_CONTROLLER; + telemetry_data_area = cfg.data_area; + } else { + fprintf(stderr, + "ERROR: WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n"); ret = -1; goto out; } - strcat(f, ".bin"); - } - fprintf(stderr, "%s: filename = %s\n", __func__, f); + } else { + if (cfg.file) { + strncpy(fb, cfg.file, PATH_MAX/2 - 8); + } else { + wdc_UtilsGetTime(&timeInfo); + memset(timeStamp, 0, sizeof(timeStamp)); + wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN, + "%02u%02u%02u_%02u%02u%02u", timeInfo.year, + timeInfo.month, timeInfo.dayOfMonth, + timeInfo.hour, timeInfo.minute, + timeInfo.second); + snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp); + + ret = wdc_get_serial_name(dev, fb, PATH_MAX/2 - 7, fileSuffix); + if (ret) { + fprintf(stderr, "ERROR: WDC: failed to generate file name\n"); + goto out; + } + + if (strlen(fb) > PATH_MAX/2 - 7) { + fprintf(stderr, "ERROR: WDC: file name overflow\n"); + ret = -1; + goto out; + } + } + fprintf(stderr, "%s: filename = %s.tar.gz\n", __func__, fb); - if (cfg.data_area) { - if (cfg.data_area > 5 || cfg.data_area < 1) { - fprintf(stderr, "ERROR : WDC: Data area must be 1-5\n"); + + memset(file_path, 0, sizeof(file_path)); + if (snprintf(file_path, PATH_MAX/2 - 8, "%s.tar.gz", fb) >= PATH_MAX/2 - 8) { + fprintf(stderr, "File path is too long!\n"); ret = -1; goto out; } - } - - if ((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"); - ret = -1; - goto out; + if (access(file_path, F_OK) != -1) { + fprintf(stderr, "Output file already exists!\n"); + ret = -EEXIST; + goto out; + } } capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) { - if (telemetry_data_area == 0) - telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ + if (!wdc_is_sn861(device_id)) { + /* Set the default DA to 3 if not specified */ + if (!telemetry_data_area) + telemetry_data_area = 3; + + ret = wdc_do_cap_diag(r, dev, f, xfer_size, + telemetry_type, telemetry_data_area); + } else { + if (cfg.verbose) + printf("Creating temp directory...\n"); + + ret = mkdir(fb, 0666); + if (ret) { + fprintf(stderr, "Failed to create directory!\n"); + goto out; + } - ret = wdc_do_cap_diag(r, dev, f, xfer_size, - telemetry_type, telemetry_data_area); + ret = dump_internal_logs(dev, fb, cfg.verbose); + if (ret < 0) + perror("vs-internal-log"); + + if (cfg.verbose) + printf("Archiving...\n"); + + if (snprintf(cmd_buf, PATH_MAX, + "tar --remove-files -czf %s %s", + file_path, fb) >= PATH_MAX) { + fprintf(stderr, "Command buffer is too long!\n"); + ret = -1; + goto out; + } + + ret = system(cmd_buf); + if (ret) + fprintf(stderr, "Failed to create an archive file!\n"); + } goto out; } if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) { if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) || (telemetry_type == WDC_TELEMETRY_TYPE_CONTROLLER)) { - if (telemetry_data_area == 0) + if (!telemetry_data_area) telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ /* Get the desired telemetry log page */ ret = wdc_do_cap_telemetry_log(dev, f, xfer_size, telemetry_type, telemetry_data_area); goto out; } else { - if (cfg.data_area == 0) + if (!cfg.data_area) cfg.data_area = 1; /* FW requirement - xfer size must be 256k for data area 4 */ if (cfg.data_area >= 4) xfer_size = 0x40000; ret = wdc_do_cap_dui(dev_fd(dev), f, xfer_size, - cfg.data_area, - cfg.verbose, cfg.file_size, - cfg.offset); + cfg.data_area, + cfg.verbose, cfg.file_size, + cfg.offset); goto out; } } - if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA){ + if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA) { if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) || (telemetry_type == WDC_TELEMETRY_TYPE_CONTROLLER)) { - if (telemetry_data_area == 0) + if (!telemetry_data_area) telemetry_data_area = 3; /* Set the default DA to 3 if not specified */ /* Get the desired telemetry log page */ ret = wdc_do_cap_telemetry_log(dev, f, xfer_size, @@ -3466,10 +4056,10 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command goto out; } } - if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG) + if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG) { ret = wdc_do_sn730_get_and_tar(dev_fd(dev), f); - else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + } else { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } out: @@ -3523,18 +4113,18 @@ static int wdc_do_crash_dump(struct nvme_dev *dev, char *file, int type) if (ret == -1) { if (type == WDC_NVME_PFAIL_DUMP_TYPE) - fprintf(stderr, "INFO : WDC: Pfail dump get size failed\n"); + fprintf(stderr, "INFO: WDC: Pfail dump get size failed\n"); else - fprintf(stderr, "INFO : WDC: Crash dump get size failed\n"); + fprintf(stderr, "INFO: WDC: Crash dump get size failed\n"); return -1; } - if (crash_dump_length == 0) { + if (!crash_dump_length) { if (type == WDC_NVME_PFAIL_DUMP_TYPE) - fprintf(stderr, "INFO : WDC: Pfail dump is empty\n"); + fprintf(stderr, "INFO: WDC: Pfail dump is empty\n"); else - fprintf(stderr, "INFO : WDC: Crash dump is empty\n"); + fprintf(stderr, "INFO: WDC: Crash dump is empty\n"); } else { ret = wdc_do_dump(dev, opcode, @@ -3543,7 +4133,7 @@ static int wdc_do_crash_dump(struct nvme_dev *dev, char *file, int type) file, crash_dump_length); - if (ret == 0) + if (!ret) ret = wdc_do_clear_dump(dev, WDC_NVME_CLEAR_DUMP_OPCODE, cdw12_clear); } @@ -3556,9 +4146,8 @@ static int wdc_crash_dump(struct nvme_dev *dev, char *file, int type) const char *dump_type; int ret; - if (file != NULL) { + if (file) strncpy(f, file, PATH_MAX - 1); - } if (type == WDC_NVME_PFAIL_DUMP_TYPE) dump_type = "_pfail_dump"; @@ -3567,7 +4156,7 @@ static int wdc_crash_dump(struct nvme_dev *dev, char *file, int type) ret = wdc_get_serial_name(dev, f, PATH_MAX, dump_type); if (ret) - fprintf(stderr, "ERROR : WDC : failed to generate file name\n"); + fprintf(stderr, "ERROR: WDC: failed to generate file name\n"); else ret = wdc_do_crash_dump(dev, f, type); return ret; @@ -3585,18 +4174,17 @@ static int wdc_do_drive_log(struct nvme_dev *dev, char *file) (WDC_NVME_DRIVE_LOG_SIZE_SUBCMD << WDC_NVME_SUBCMD_SHIFT | WDC_NVME_DRIVE_LOG_SIZE_CMD), &drive_log_length); - if (ret == -1) { + 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)); + drive_log_data = (__u8 *)malloc(sizeof(__u8) * drive_log_length); + if (!drive_log_data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(drive_log_data, 0, sizeof (__u8) * drive_log_length); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(drive_log_data, 0, sizeof(__u8) * drive_log_length); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_DRIVE_LOG_OPCODE; admin_cmd.addr = (__u64)(uintptr_t)drive_log_data; admin_cmd.data_len = drive_log_length; @@ -3606,9 +4194,8 @@ static int wdc_do_drive_log(struct nvme_dev *dev, char *file) ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); nvme_show_status(ret); - if (ret == 0) { + if (!ret) ret = wdc_create_log_file(file, drive_log_data, drive_log_length); - } free(drive_log_data); return ret; } @@ -3649,16 +4236,15 @@ static int wdc_drive_log(int argc, char **argv, struct command *command, } capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_DRIVE_LOG) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_DRIVE_LOG)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } else { - if (cfg.file != NULL) { + if (cfg.file) strncpy(f, cfg.file, PATH_MAX - 1); - } ret = wdc_get_serial_name(dev, f, PATH_MAX, "drive_log"); if (ret) - fprintf(stderr, "ERROR : WDC : failed to generate file name\n"); + fprintf(stderr, "ERROR: WDC: failed to generate file name\n"); else ret = wdc_do_drive_log(dev, f); } @@ -3705,14 +4291,13 @@ static int wdc_get_crash_dump(int argc, char **argv, struct command *command, capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_CRASH_DUMP) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_CRASH_DUMP)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } else { ret = wdc_crash_dump(dev, cfg.file, WDC_NVME_CRASH_DUMP_TYPE); - if (ret != 0) { - fprintf(stderr, "ERROR : WDC : failed to read crash dump\n"); - } + if (ret) + fprintf(stderr, "ERROR: WDC: failed to read crash dump\n"); } nvme_free_tree(r); dev_close(dev); @@ -3754,14 +4339,13 @@ static int wdc_get_pfail_dump(int argc, char **argv, struct command *command, } capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_PFAIL_DUMP) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_PFAIL_DUMP)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } else { ret = wdc_crash_dump(dev, cfg.file, WDC_NVME_PFAIL_DUMP_TYPE); - if (ret != 0) { - fprintf(stderr, "ERROR : WDC : failed to read pfail crash dump\n"); - } + if (ret) + fprintf(stderr, "ERROR: WDC: failed to read pfail crash dump\n"); } nvme_free_tree(r); dev_close(dev); @@ -3778,7 +4362,7 @@ static void wdc_do_id_ctrl(__u8 *vs, struct json_object *root) 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"); + 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) @@ -3786,7 +4370,7 @@ static int wdc_id_ctrl(int argc, char **argv, struct command *cmd, struct plugin return __id_ctrl(argc, argv, cmd, plugin, wdc_do_id_ctrl); } -static const char* wdc_purge_mon_status_to_string(__u32 status) +static const char *wdc_purge_mon_status_to_string(__u32 status) { const char *str; @@ -3801,14 +4385,12 @@ static const char* wdc_purge_mon_status_to_string(__u32 status) str = "Purge State Busy."; break; case WDC_NVME_PURGE_STATE_REQ_PWR_CYC: - str = "Purge Operation resulted in an error that requires " - "power cycle."; + 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."; + str = "The previous purge operation was interrupted by a power cycle\n" + "or reset interruption. Other commands may be rejected until\n" + "Purge Execute is issued and completed."; break; default: str = "Unknown."; @@ -3844,12 +4426,12 @@ static int wdc_purge(int argc, char **argv, } capabilities = wdc_get_drive_capabilities(r, dev); - if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { + if (!(capabilities & WDC_DRIVE_CAP_PURGE)) { ret = -1; - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); } else { err_str = ""; - memset(&admin_cmd, 0, sizeof (admin_cmd)); + memset(&admin_cmd, 0, sizeof(admin_cmd)); admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE; ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, @@ -3857,14 +4439,13 @@ static int wdc_purge(int argc, char **argv, 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"; + 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"; + err_str = "ERROR: WDC: Internal Device Error.\n"; break; default: - err_str = "ERROR : WDC\n"; + err_str = "ERROR: WDC\n"; } } @@ -3905,12 +4486,12 @@ static int wdc_purge_monitor(int argc, char **argv, } capabilities = wdc_get_drive_capabilities(r, dev); - if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { + if (!(capabilities & WDC_DRIVE_CAP_PURGE)) { ret = -1; - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); } else { - memset(output, 0, sizeof (output)); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(output, 0, sizeof(output)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_PURGE_MONITOR_OPCODE; admin_cmd.addr = (__u64)(uintptr_t)output; admin_cmd.data_len = WDC_NVME_PURGE_MONITOR_DATA_LEN; @@ -3919,7 +4500,7 @@ static int wdc_purge_monitor(int argc, char **argv, ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); - if (ret == 0) { + if (!ret) { mon = (struct wdc_nvme_purge_monitor_data *) output; printf("Purge state = 0x%0x\n", admin_cmd.result); printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result)); @@ -3940,7 +4521,7 @@ static int wdc_purge_monitor(int argc, char **argv, static void wdc_print_log_normal(struct wdc_ssd_perf_stats *perf) { - printf(" C1 Log Page Performance Statistics :- \n"); + 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", @@ -3995,9 +4576,8 @@ static void wdc_print_log_normal(struct wdc_ssd_perf_stats *perf) static void wdc_print_log_json(struct wdc_ssd_perf_stats *perf) { - struct json_object *root; + struct json_object *root = json_create_object(); - root = json_create_object(); json_object_add_value_int(root, "Host Read Commands", le64_to_cpu(perf->hr_cmds)); json_object_add_value_int(root, "Host Read Blocks", le64_to_cpu(perf->hr_blks)); json_object_add_value_int(root, "Average Read Size", @@ -4054,7 +4634,7 @@ static void wdc_print_log_json(struct wdc_ssd_perf_stats *perf) 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"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read perf stats\n"); return -1; } switch (fmt) { @@ -4068,100 +4648,83 @@ static int wdc_print_log(struct wdc_ssd_perf_stats *perf, int fmt) return 0; } -static int wdc_convert_ts(time_t time, char *ts_buf) -{ - struct tm gmTimeInfo; - time_t time_Human, time_ms; - char buf[80]; - - time_Human = time/1000; - time_ms = time % 1000; - - gmtime_r((const time_t *)&time_Human, &gmTimeInfo); - - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &gmTimeInfo); - sprintf(ts_buf, "%s.%03ld GMT", buf, time_ms); - - return 0; -} - static int wdc_print_latency_monitor_log_normal(struct nvme_dev *dev, struct wdc_ssd_latency_monitor_log *log_data) { - printf("Latency Monitor/C3 Log Page Data \n"); + printf("Latency Monitor/C3 Log Page Data\n"); printf(" Controller : %s\n", dev->name); int err = -1, i, j; struct nvme_id_ctrl ctrl; - char ts_buf[128]; + char ts_buf[128]; err = nvme_identify_ctrl(dev_fd(dev), &ctrl); - if (!err) + if (!err) { printf(" Serial Number: %-.*s\n", (int)sizeof(ctrl.sn), ctrl.sn); - else { - fprintf(stderr, "ERROR : WDC : latency monitor read id ctrl failure, err = %d\n", err); + } else { + fprintf(stderr, "ERROR: WDC: latency monitor read id ctrl failure, err = %d\n", err); return err; } - printf(" Feature Status 0x%x \n", log_data->feature_status); - printf(" Active Bucket Timer %d min \n", 5*le16_to_cpu(log_data->active_bucket_timer)); - printf(" Active Bucket Timer Threshold %d min \n", 5*le16_to_cpu(log_data->active_bucket_timer_threshold)); - printf(" Active Threshold A %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_a+1))); - printf(" Active Threshold B %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_b+1))); - printf(" Active Threshold C %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_c+1))); - printf(" Active Threshold D %d ms \n", 5*(le16_to_cpu(log_data->active_threshold_d+1))); - printf(" Active Latency Config 0x%x \n", le16_to_cpu(log_data->active_latency_config)); - printf(" Active Latency Minimum Window %d ms \n", 100*log_data->active_latency_min_window); - printf(" Active Latency Stamp Units %d \n", le16_to_cpu(log_data->active_latency_stamp_units)); - printf(" Static Latency Stamp Units %d \n", le16_to_cpu(log_data->static_latency_stamp_units)); - printf(" Debug Log Trigger Enable %d \n", le16_to_cpu(log_data->debug_log_trigger_enable)); - - printf(" Read Write Deallocate/Trim \n"); - for (i = 0; i <= 3; i++) { - printf(" Active Bucket Counter: Bucket %d %27d %27d %27d \n", - i, le32_to_cpu(log_data->active_bucket_counter[i][READ]), le32_to_cpu(log_data->active_bucket_counter[i][WRITE]), - le32_to_cpu(log_data->active_bucket_counter[i][TRIM])); - } - - for (i = 0; i <= 3; i++) { - printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms \n", - i, le16_to_cpu(log_data->active_measured_latency[i][READ]), le16_to_cpu(log_data->active_measured_latency[i][WRITE]), - le16_to_cpu(log_data->active_measured_latency[i][TRIM])); - } - - for (i = 0; i <= 3; i++) { - printf(" Active Latency Time Stamp: Bucket %d ", i); - for (j = 0; j <= 2; j++) { - if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) - printf(" N/A "); - else { - wdc_convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf); - printf("%s ", ts_buf); - } + printf(" Feature Status 0x%x\n", log_data->feature_status); + printf(" Active Bucket Timer %d min\n", 5*le16_to_cpu(log_data->active_bucket_timer)); + printf(" Active Bucket Timer Threshold %d min\n", 5*le16_to_cpu(log_data->active_bucket_timer_threshold)); + printf(" Active Threshold A %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_a+1))); + printf(" Active Threshold B %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_b+1))); + printf(" Active Threshold C %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_c+1))); + printf(" Active Threshold D %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_d+1))); + printf(" Active Latency Config 0x%x\n", le16_to_cpu(log_data->active_latency_config)); + printf(" Active Latency Minimum Window %d ms\n", 100*log_data->active_latency_min_window); + printf(" Active Latency Stamp Units %d\n", le16_to_cpu(log_data->active_latency_stamp_units)); + printf(" Static Latency Stamp Units %d\n", le16_to_cpu(log_data->static_latency_stamp_units)); + printf(" Debug Log Trigger Enable %d\n", le16_to_cpu(log_data->debug_log_trigger_enable)); + + printf(" Read Write Deallocate/Trim\n"); + for (i = 0; i <= 3; i++) + printf(" Active Bucket Counter: Bucket %d %27d %27d %27d\n", + i, le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_READ]), + le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_WRITE]), + le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_TRIM])); + + for (i = 3; i >= 0; i--) + printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n", + 3-i, le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_READ]), + le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_WRITE]), + le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_TRIM])); + + for (i = 3; i >= 0; i--) { + printf(" Active Latency Time Stamp: Bucket %d ", 3-i); + for (j = 2; j >= 0; j--) { + if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) { + printf(" N/A "); + } else { + convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf); + printf("%s ", ts_buf); + } } printf("\n"); } - for (i = 0; i <= 3; i++) { - printf(" Static Bucket Counter: Bucket %d %27d %27d %27d \n", - i, le32_to_cpu(log_data->static_bucket_counter[i][READ]), le32_to_cpu(log_data->static_bucket_counter[i][WRITE]), - le32_to_cpu(log_data->static_bucket_counter[i][TRIM])); - } + for (i = 0; i <= 3; i++) + printf(" Static Bucket Counter: Bucket %d %27d %27d %27d\n", + i, le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_READ]), + le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_WRITE]), + le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_TRIM])); - for (i = 0; i <= 3; i++) { - printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms \n", - i, le16_to_cpu(log_data->static_measured_latency[i][READ]), le16_to_cpu(log_data->static_measured_latency[i][WRITE]), - le16_to_cpu(log_data->static_measured_latency[i][TRIM])); - } + for (i = 3; i >= 0; i--) + printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n", + 3-i, le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_READ]), + le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_WRITE]), + le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_TRIM])); - for (i = 0; i <= 3; i++) { - printf(" Static Latency Time Stamp: Bucket %d ", i); - for (j = 0; j <= 2; j++) { - if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) - printf(" N/A "); - else { - wdc_convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf); - printf("%s ", ts_buf); - } + for (i = 3; i >= 0; i--) { + printf(" Static Latency Time Stamp: Bucket %d ", 3-i); + for (j = 2; j >= 0; j--) { + if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) { + printf(" N/A "); + } else { + convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf); + printf("%s ", ts_buf); + } } printf("\n"); } @@ -4172,10 +4735,9 @@ static int wdc_print_latency_monitor_log_normal(struct nvme_dev *dev, static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_log *log_data) { int i, j; - char buf[128]; - char *operation[3] = {"Read", "Write", "Trim"}; - struct json_object *root; - root = json_create_object(); + char buf[128]; + char *operation[3] = {"Read", "Write", "Trim"}; + struct json_object *root = json_create_object(); json_object_add_value_int(root, "Feature Status", log_data->feature_status); json_object_add_value_int(root, "Active Bucket Timer", 5*le16_to_cpu(log_data->active_bucket_timer)); @@ -4191,38 +4753,38 @@ static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_lo json_object_add_value_int(root, "Debug Log Trigger Enable", le16_to_cpu(log_data->debug_log_trigger_enable)); for (i = 0; i <= 3; i++) { - for (j = 0; j <= 2; j++) { - sprintf(buf, "Active Bucket Counter: Bucket %d %s", i, operation[j]); - json_object_add_value_int(root, buf, le32_to_cpu(log_data->active_bucket_counter[i][j])); + for (j = 2; j >= 0; j--) { + sprintf(buf, "Active Bucket Counter: Bucket %d %s", i, operation[2-j]); + json_object_add_value_int(root, buf, le32_to_cpu(log_data->active_bucket_counter[i][j+1])); } } - for (i = 0; i <= 3; i++) { - for (j = 0; j <= 2; j++) { - sprintf(buf, "Active Measured Latency: Bucket %d %s", i, operation[j]); + for (i = 3; i >= 0; i--) { + for (j = 2; j >= 0; j--) { + sprintf(buf, "Active Measured Latency: Bucket %d %s", 3-i, operation[2-j]); json_object_add_value_int(root, buf, le16_to_cpu(log_data->active_measured_latency[i][j])); } } - for (i = 0; i <= 3; i++) { - for (j = 0; j <= 2; j++) { - sprintf(buf, "Active Latency Time Stamp: Bucket %d %s", i, operation[j]); + for (i = 3; i >= 0; i--) { + for (j = 2; j >= 0; j--) { + sprintf(buf, "Active Latency Time Stamp: Bucket %d %s", 3-i, operation[2-j]); json_object_add_value_int(root, buf, le64_to_cpu(log_data->active_latency_timestamp[i][j])); } } for (i = 0; i <= 3; i++) { - for (j = 0; j <= 2; j++) { - sprintf(buf, "Static Bucket Counter: Bucket %d %s", i, operation[j]); - json_object_add_value_int(root, buf, le32_to_cpu(log_data->static_bucket_counter[i][j])); + for (j = 2; j >= 0; j--) { + sprintf(buf, "Static Bucket Counter: Bucket %d %s", i, operation[2-j]); + json_object_add_value_int(root, buf, le32_to_cpu(log_data->static_bucket_counter[i][j+1])); } } - for (i = 0; i <= 3; i++) { - for (j = 0; j <= 2; j++) { - sprintf(buf, "Static Measured Latency: Bucket %d %s", i, operation[j]); + for (i = 3; i >= 0; i--) { + for (j = 2; j >= 0; j--) { + sprintf(buf, "Static Measured Latency: Bucket %d %s", 3-i, operation[2-j]); json_object_add_value_int(root, buf, le16_to_cpu(log_data->static_measured_latency[i][j])); } } - for (i = 0; i <= 3; i++) { - for (j = 0; j <= 2; j++) { - sprintf(buf, "Static Latency Time Stamp: Bucket %d %s", i, operation[j]); + for (i = 3; i >= 0; i--) { + for (j = 2; j >= 0; j--) { + sprintf(buf, "Static Latency Time Stamp: Bucket %d %s", 3-i, operation[2-j]); json_object_add_value_int(root, buf, le64_to_cpu(log_data->static_latency_timestamp[i][j])); } } @@ -4236,33 +4798,32 @@ static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_lo static void wdc_print_error_rec_log_normal(struct wdc_ocp_c1_error_recovery_log *log_data) { int j; - printf("Error Recovery/C1 Log Page Data \n"); - - printf(" Panic Reset Wait Time : 0x%x \n", le16_to_cpu(log_data->panic_reset_wait_time)); - printf(" Panic Reset Action : 0x%x \n", log_data->panic_reset_action); - printf(" Device Recovery Action 1 : 0x%x \n", log_data->dev_recovery_action1); - printf(" Panic ID : 0x%lx \n", le64_to_cpu(log_data->panic_id)); - printf(" Device Capabilities : 0x%x \n", le32_to_cpu(log_data->dev_capabilities)); - printf(" Vendor Specific Recovery Opcode : 0x%x \n", log_data->vs_recovery_opc); - printf(" Vendor Specific Command CDW12 : 0x%x \n", le32_to_cpu(log_data->vs_cmd_cdw12)); - printf(" Vendor Specific Command CDW13 : 0x%x \n", le32_to_cpu(log_data->vs_cmd_cdw13)); + + printf("Error Recovery/C1 Log Page Data\n"); + + printf(" Panic Reset Wait Time : 0x%x\n", le16_to_cpu(log_data->panic_reset_wait_time)); + printf(" Panic Reset Action : 0x%x\n", log_data->panic_reset_action); + printf(" Device Recovery Action 1 : 0x%x\n", log_data->dev_recovery_action1); + printf(" Panic ID : 0x%" PRIu64 "\n", le64_to_cpu(log_data->panic_id)); + printf(" Device Capabilities : 0x%x\n", le32_to_cpu(log_data->dev_capabilities)); + printf(" Vendor Specific Recovery Opcode : 0x%x\n", log_data->vs_recovery_opc); + printf(" Vendor Specific Command CDW12 : 0x%x\n", le32_to_cpu(log_data->vs_cmd_cdw12)); + printf(" Vendor Specific Command CDW13 : 0x%x\n", le32_to_cpu(log_data->vs_cmd_cdw13)); if (le16_to_cpu(log_data->log_page_version) == WDC_ERROR_REC_LOG_VERSION2) { - printf(" Vendor Specific Command Timeout : 0x%x \n", log_data->vs_cmd_to); - printf(" Device Recovery Action 2 : 0x%x \n", log_data->dev_recovery_action2); - printf(" Device Recovery Action 2 Timeout : 0x%x \n", log_data->dev_recovery_action2_to); + printf(" Vendor Specific Command Timeout : 0x%x\n", log_data->vs_cmd_to); + printf(" Device Recovery Action 2 : 0x%x\n", log_data->dev_recovery_action2); + printf(" Device Recovery Action 2 Timeout : 0x%x\n", log_data->dev_recovery_action2_to); } - printf(" Log Page Version : 0x%x \n", le16_to_cpu(log_data->log_page_version)); + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); printf(" Log page GUID : 0x"); - for (j = 0; j < WDC_OCP_C1_GUID_LENGTH; j++) { + for (j = 0; j < WDC_OCP_C1_GUID_LENGTH; j++) printf("%x", log_data->log_page_guid[j]); - } printf("\n"); } static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *log_data) { - struct json_object *root; - root = json_create_object(); + struct json_object *root = json_create_object(); json_object_add_value_int(root, "Panic Reset Wait Time", le16_to_cpu(log_data->panic_reset_wait_time)); json_object_add_value_int(root, "Panic Reset Action", log_data->panic_reset_wait_time); @@ -4280,8 +4841,10 @@ static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *l json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); char guid[40]; - memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + + memset((void *)guid, 0, 40); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); json_object_add_value_string(root, "Log page GUID", guid); @@ -4294,34 +4857,32 @@ static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *l static void wdc_print_dev_cap_log_normal(struct wdc_ocp_C4_dev_cap_log *log_data) { int j; - printf("Device Capabilities/C4 Log Page Data \n"); - printf(" Number PCIE Ports : 0x%x \n", le16_to_cpu(log_data->num_pcie_ports)); - printf(" Number OOB Management Interfaces : 0x%x \n", le16_to_cpu(log_data->oob_mgmt_support)); - printf(" Write Zeros Command Support : 0x%x \n", le16_to_cpu(log_data->wrt_zeros_support)); - printf(" Sanitize Command Support : 0x%x \n", le16_to_cpu(log_data->sanitize_support)); - printf(" DSM Command Support : 0x%x \n", le16_to_cpu(log_data->dsm_support)); - printf(" Write Uncorr Command Support : 0x%x \n", le16_to_cpu(log_data->wrt_uncor_support)); - printf(" Fused Command Support : 0x%x \n", le16_to_cpu(log_data->fused_support)); - printf(" Minimum DSSD Power State : 0x%x \n", le16_to_cpu(log_data->min_dssd_ps)); + printf("Device Capabilities/C4 Log Page Data\n"); - for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++) { - printf(" DSSD Power State %d Desriptor : 0x%x \n", j, log_data->dssd_ps_descr[j]); - } + printf(" Number PCIE Ports : 0x%x\n", le16_to_cpu(log_data->num_pcie_ports)); + printf(" Number OOB Management Interfaces : 0x%x\n", le16_to_cpu(log_data->oob_mgmt_support)); + printf(" Write Zeros Command Support : 0x%x\n", le16_to_cpu(log_data->wrt_zeros_support)); + printf(" Sanitize Command Support : 0x%x\n", le16_to_cpu(log_data->sanitize_support)); + printf(" DSM Command Support : 0x%x\n", le16_to_cpu(log_data->dsm_support)); + printf(" Write Uncorr Command Support : 0x%x\n", le16_to_cpu(log_data->wrt_uncor_support)); + printf(" Fused Command Support : 0x%x\n", le16_to_cpu(log_data->fused_support)); + printf(" Minimum DSSD Power State : 0x%x\n", le16_to_cpu(log_data->min_dssd_ps)); + + for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++) + printf(" DSSD Power State %d Descriptor : 0x%x\n", j, log_data->dssd_ps_descr[j]); - printf(" Log Page Version : 0x%x \n", le16_to_cpu(log_data->log_page_version)); + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); printf(" Log page GUID : 0x"); - for (j = 0; j < WDC_OCP_C4_GUID_LENGTH; j++) { + for (j = 0; j < WDC_OCP_C4_GUID_LENGTH; j++) printf("%x", log_data->log_page_guid[j]); - } printf("\n"); } static void wdc_print_dev_cap_log_json(struct wdc_ocp_C4_dev_cap_log *log_data) { int j; - struct json_object *root; - root = json_create_object(); + struct json_object *root = json_create_object(); json_object_add_value_int(root, "Number PCIE Ports", le16_to_cpu(log_data->num_pcie_ports)); json_object_add_value_int(root, "Number OOB Management Interfaces", le16_to_cpu(log_data->num_pcie_ports)); @@ -4333,6 +4894,7 @@ static void wdc_print_dev_cap_log_json(struct wdc_ocp_C4_dev_cap_log *log_data) json_object_add_value_int(root, "Minimum DSSD Power State", le16_to_cpu(log_data->num_pcie_ports)); char dssd_descr_str[40]; + memset((void *)dssd_descr_str, 0, 40); for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++) { sprintf((char *)dssd_descr_str, "DSSD Power State %d Descriptor", j); @@ -4341,8 +4903,10 @@ static void wdc_print_dev_cap_log_json(struct wdc_ocp_C4_dev_cap_log *log_data) json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); char guid[40]; - memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + + memset((void *)guid, 0, 40); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); json_object_add_value_string(root, "Log page GUID", guid); @@ -4355,41 +4919,45 @@ static void wdc_print_dev_cap_log_json(struct wdc_ocp_C4_dev_cap_log *log_data) static void wdc_print_unsupported_reqs_log_normal(struct wdc_ocp_C5_unsupported_reqs *log_data) { int j; - printf("Unsupported Requirements/C5 Log Page Data \n"); - printf(" Number Unsupported Req IDs : 0x%x \n", le16_to_cpu(log_data->unsupported_count)); + printf("Unsupported Requirements/C5 Log Page Data\n"); - for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) { - printf(" Unsupported Requirement List %d : %s \n", j, log_data->unsupported_req_list[j]); - } + printf(" Number Unsupported Req IDs : 0x%x\n", + le16_to_cpu(log_data->unsupported_count)); + + for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) + printf(" Unsupported Requirement List %d : %s\n", j, + log_data->unsupported_req_list[j]); - printf(" Log Page Version : 0x%x \n", le16_to_cpu(log_data->log_page_version)); + printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version)); printf(" Log page GUID : 0x"); - for (j = 0; j < WDC_OCP_C5_GUID_LENGTH; j++) { + for (j = 0; j < WDC_OCP_C5_GUID_LENGTH; j++) printf("%x", log_data->log_page_guid[j]); - } printf("\n"); } static void wdc_print_unsupported_reqs_log_json(struct wdc_ocp_C5_unsupported_reqs *log_data) { int j; - struct json_object *root; - root = json_create_object(); + struct json_object *root = json_create_object(); json_object_add_value_int(root, "Number Unsupported Req IDs", le16_to_cpu(log_data->unsupported_count)); char unsup_req_list_str[40]; + memset((void *)unsup_req_list_str, 0, 40); for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) { sprintf((char *)unsup_req_list_str, "Unsupported Requirement List %d", j); json_object_add_value_string(root, unsup_req_list_str, (char *)log_data->unsupported_req_list[j]); } - json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version)); + json_object_add_value_int(root, "Log Page Version", + le16_to_cpu(log_data->log_page_version)); char guid[40]; - memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), + + memset((void *)guid, 0, 40); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0])); json_object_add_value_string(root, "Log page GUID", guid); @@ -4403,7 +4971,7 @@ 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(" 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", @@ -4464,10 +5032,9 @@ static void wdc_print_fb_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf) static void wdc_print_fb_ca_log_json(struct wdc_ssd_ca_perf_stats *perf) { - struct json_object *root; + struct json_object *root = json_create_object(); 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)); @@ -4532,18 +5099,18 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) __u8 *byte_raw; if (bd_data->field_id == 0x00) { - raw = (__u64*)&bd_data->raw_value[0]; - printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", - dev->name, WDC_DE_GLOBAL_NSID); + raw = (__u64 *)&bd_data->raw_value[0]; + printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", dev->name, + WDC_DE_GLOBAL_NSID); printf("key normalized raw\n"); - printf("program_fail_count : %3"PRIu8"%% %"PRIu64"\n", - bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); + printf("program_fail_count : %3"PRIu8"%% %"PRIu64"\n", + bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x01) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("erase_fail_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4551,9 +5118,9 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) } bd_data++; if (bd_data->field_id == 0x02) { - word_raw1 = (__u16*)&bd_data->raw_value[1]; - word_raw2 = (__u16*)&bd_data->raw_value[3]; - word_raw3 = (__u16*)&bd_data->raw_value[5]; + word_raw1 = (__u16 *)&bd_data->raw_value[1]; + word_raw2 = (__u16 *)&bd_data->raw_value[3]; + word_raw3 = (__u16 *)&bd_data->raw_value[5]; printf("wear_leveling : %3"PRIu8"%% min: %"PRIu16", max: %"PRIu16", avg: %"PRIu16"\n", bd_data->normalized_value, le16_to_cpu(*word_raw1), @@ -4564,7 +5131,7 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) } bd_data++; if (bd_data->field_id == 0x03) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("end_to_end_error_detection_count: %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4572,7 +5139,7 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) } bd_data++; if (bd_data->field_id == 0x04) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("crc_error_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4580,49 +5147,48 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) } bd_data++; if (bd_data->field_id == 0x05) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("timed_workload_media_wear : %3"PRIu8"%% %-.3f%%\n", - bd_data->normalized_value, - safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0)); + bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x06) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("timed_workload_host_reads : %3"PRIu8"%% %"PRIu64"%%\n", - bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); + bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x07) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("timed_workload_timer : %3"PRIu8"%% %"PRIu64"\n", - bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); + bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x08) { - byte_raw = (__u8*)&bd_data->raw_value[1]; - dword_raw = (__u32*)&bd_data->raw_value[2]; + byte_raw = (__u8 *)&bd_data->raw_value[1]; + dword_raw = (__u32 *)&bd_data->raw_value[2]; printf("thermal_throttle_status : %3"PRIu8"%% %"PRIu16"%%, cnt: %"PRIu16"\n", - bd_data->normalized_value, *byte_raw, le32_to_cpu(*dword_raw)); + bd_data->normalized_value, *byte_raw, le32_to_cpu(*dword_raw)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x09) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("retry_buffer_overflow_count : %3"PRIu8"%% %"PRIu64"\n", - bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); + bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x0A) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("pll_lock_loss_count : %3"PRIu8"%% %"PRIu64"\n", bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { @@ -4630,7 +5196,7 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) } bd_data++; if (bd_data->field_id == 0x0B) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("nand_bytes_written : %3"PRIu8"%% sectors: %.f\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); } else { @@ -4638,7 +5204,7 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) } bd_data++; if (bd_data->field_id == 0x0C) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; printf("host_bytes_written : %3"PRIu8"%% sectors: %.f\n", bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF)); } else { @@ -4647,11 +5213,11 @@ static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data) goto done; - invalid_id: - printf(" Invalid Field ID = %d\n", bd_data->field_id); +invalid_id: + printf(" Invalid Field ID = %d\n", bd_data->field_id); - done: - return; +done: + return; } @@ -4662,11 +5228,10 @@ static void wdc_print_bd_ca_log_json(void *data) __u16 *word_raw; __u32 *dword_raw; __u8 *byte_raw; - struct json_object *root; + struct json_object *root = json_create_object(); - root = json_create_object(); if (bd_data->field_id == 0x00) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "program_fail_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "program_fail_count raw", @@ -4676,7 +5241,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x01) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "erase_fail_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "erase_fail_count raw", @@ -4686,19 +5251,19 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x02) { - word_raw = (__u16*)&bd_data->raw_value[1]; + word_raw = (__u16 *)&bd_data->raw_value[1]; json_object_add_value_int(root, "wear_leveling normalized", bd_data->normalized_value); json_object_add_value_int(root, "wear_leveling min", le16_to_cpu(*word_raw)); - word_raw = (__u16*)&bd_data->raw_value[3]; + word_raw = (__u16 *)&bd_data->raw_value[3]; json_object_add_value_int(root, "wear_leveling max", le16_to_cpu(*word_raw)); - word_raw = (__u16*)&bd_data->raw_value[5]; + word_raw = (__u16 *)&bd_data->raw_value[5]; json_object_add_value_int(root, "wear_leveling avg", le16_to_cpu(*word_raw)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x03) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "end_to_end_error_detection_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "end_to_end_error_detection_count raw", @@ -4708,7 +5273,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x04) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "crc_error_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "crc_error_count raw", @@ -4718,7 +5283,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x05) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "timed_workload_media_wear normalized", bd_data->normalized_value); json_object_add_value_double(root, "timed_workload_media_wear raw", @@ -4728,7 +5293,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x06) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "timed_workload_host_reads normalized", bd_data->normalized_value); json_object_add_value_int(root, "timed_workload_host_reads raw", @@ -4738,28 +5303,28 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x07) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "timed_workload_timer normalized", - bd_data->normalized_value); + bd_data->normalized_value); json_object_add_value_int(root, "timed_workload_timer", - le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); + le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x08) { - byte_raw = (__u8*)&bd_data->raw_value[1]; + byte_raw = (__u8 *)&bd_data->raw_value[1]; json_object_add_value_int(root, "thermal_throttle_status normalized", bd_data->normalized_value); json_object_add_value_int(root, "thermal_throttle_status", *byte_raw); - dword_raw = (__u32*)&bd_data->raw_value[2]; + dword_raw = (__u32 *)&bd_data->raw_value[2]; json_object_add_value_int(root, "thermal_throttle_cnt", le32_to_cpu(*dword_raw)); } else { goto invalid_id; } bd_data++; if (bd_data->field_id == 0x09) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "retry_buffer_overflow_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "retry_buffer_overflow_count raw", @@ -4769,7 +5334,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x0A) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "pll_lock_loss_count normalized", bd_data->normalized_value); json_object_add_value_int(root, "pll_lock_loss_count raw", @@ -4779,7 +5344,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x0B) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "nand_bytes_written normalized", bd_data->normalized_value); json_object_add_value_double(root, "nand_bytes_written raw", @@ -4789,7 +5354,7 @@ static void wdc_print_bd_ca_log_json(void *data) } bd_data++; if (bd_data->field_id == 0x0C) { - raw = (__u64*)&bd_data->raw_value[0]; + raw = (__u64 *)&bd_data->raw_value[0]; json_object_add_value_int(root, "host_bytes_written normalized", bd_data->normalized_value); json_object_add_value_double(root, "host_bytes_written raw", @@ -4800,10 +5365,10 @@ static void wdc_print_bd_ca_log_json(void *data) goto done; - invalid_id: +invalid_id: printf(" Invalid Field ID = %d\n", bd_data->field_id); - done: +done: json_print_object(root, NULL); printf("\n"); json_free_object(root); @@ -4814,7 +5379,7 @@ static void wdc_print_bd_ca_log_json(void *data) static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf) { - printf(" D0 Smart Log Page Statistics :- \n"); + 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", @@ -4823,11 +5388,11 @@ static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf) (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", + 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", + 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)); @@ -4839,7 +5404,7 @@ static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf) (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", + 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)); @@ -4849,7 +5414,7 @@ static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf) (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", + 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)); @@ -4863,9 +5428,8 @@ static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf) static void wdc_print_d0_log_json(struct wdc_ssd_d0_smart_log *perf) { - struct json_object *root; + struct json_object *root = json_create_object(); - root = json_create_object(); json_object_add_value_int(root, "Lifetime Reallocated Erase Block Count", le32_to_cpu(perf->lifetime_realloc_erase_block_count)); json_object_add_value_int(root, "Lifetime Power on Hours", @@ -4919,39 +5483,40 @@ static void wdc_print_d0_log_json(struct wdc_ssd_d0_smart_log *perf) static void wdc_get_commit_action_bin(__u8 commit_action_type, char *action_bin) { - switch (commit_action_type) - { - case(0): + switch (commit_action_type) { + case 0: strcpy(action_bin, "000b"); break; - case(1): + case 1: strcpy(action_bin, "001b"); - break; - case(2): + break; + case 2: strcpy(action_bin, "010b"); - break; - case(3): + break; + case 3: strcpy(action_bin, "011b"); - break; - case(4): + break; + case 4: strcpy(action_bin, "100b"); - break; - case(5): + break; + case 5: strcpy(action_bin, "101b"); - break; - case(6): + break; + case 6: strcpy(action_bin, "110b"); - break; - case(7): - strcpy(action_bin, "111b"); - break; + break; + case 7: + strcpy(action_bin, "111b"); + break; default: strcpy(action_bin, "INVALID"); } } -static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id) +static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, + __u32 cust_id, __u32 vendor_id, + __u32 device_id) { int i, j; char previous_fw[9]; @@ -4960,17 +5525,20 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u char time_str[11]; __u16 oldestEntryIdx = 0, entryIdx = 0; char *null_fw = "--------"; + memset((void *)time_str, 0, 11); if (data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { - printf(" Firmware Activate History Log \n"); - if (cust_id == WDC_CUSTOMER_ID_0x1005 || vendor_id == WDC_NVME_SNDK_VID) { - printf(" Power on Hour Power Cycle Previous New \n"); - printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n"); + printf(" Firmware Activate History Log\n"); + if (cust_id == WDC_CUSTOMER_ID_0x1005 || + vendor_id == WDC_NVME_SNDK_VID || + wdc_is_sn861(device_id)) { + printf(" Power on Hour Power Cycle Previous New\n"); + printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result\n"); printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n"); } else { - printf(" Power Cycle Previous New \n"); - printf(" Entry Timestamp Count Firmware Firmware Slot Action Result \n"); + printf(" Power Cycle Previous New\n"); + printf(" Entry Timestamp Count Firmware Firmware Slot Action Result\n"); printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n"); } @@ -5014,17 +5582,39 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf("%s", time_str); printf(" "); - } else if(vendor_id == WDC_NVME_SNDK_VID) { + } else if (vendor_id == WDC_NVME_SNDK_VID) { printf(" "); uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + memset((void *)time_str, 0, 9); sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60), (int)((timestamp/1000)%60)); printf("%s", time_str); printf(" "); + } else if (wdc_is_sn861(device_id)) { + printf(" "); + char timestamp[20]; + __u64 hour; + __u8 min; + __u8 sec; + __u64 timestamp_sec; + + timestamp_sec = + le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp) + / 1000; + hour = timestamp_sec / 3600; + min = (timestamp_sec % 3600) / 60; + sec = timestamp_sec % 60; + + sprintf(timestamp, + "%"PRIu64":%02"PRIu8":%02"PRIu8, + (uint64_t)hour, min, sec); + printf("%-11s", timestamp); + printf(" "); } else { printf(" "); uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + printf("%16"PRIu64"", timestamp); printf(" "); } @@ -5037,10 +5627,12 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf(" "); printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->entry[entryIdx].slot_number); printf(" "); - wdc_get_commit_action_bin(fw_act_history_entry->entry[entryIdx].commit_action_type,(char *)&commit_action_bin); + wdc_get_commit_action_bin( + fw_act_history_entry->entry[entryIdx].commit_action_type, + (char *)&commit_action_bin); printf(" %s", (char *)commit_action_bin); printf(" "); - if (le16_to_cpu(fw_act_history_entry->entry[entryIdx].result) == 0) + if (!le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)) printf("pass"); else printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)); @@ -5050,12 +5642,10 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES) entryIdx = 0; } - } - else - { - printf(" Firmware Activate History Log \n"); - printf(" Power on Hour Power Cycle Previous New \n"); - printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n"); + } else { + printf(" Firmware Activate History Log\n"); + printf(" Power on Hour Power Cycle Previous New\n"); + printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result\n"); printf(" ----- -------------- -------------------- ---------- ---------- ----- ------ -------\n"); struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr)); @@ -5101,10 +5691,11 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf(" "); printf("%2"PRIu8"", (uint8_t)fw_act_history_entry[entryIdx].slot_number); printf(" "); - wdc_get_commit_action_bin(fw_act_history_entry[entryIdx].commit_action_type,(char *)&commit_action_bin); + wdc_get_commit_action_bin(fw_act_history_entry[entryIdx].commit_action_type, + (char *)&commit_action_bin); printf(" %s", (char *)commit_action_bin); printf(" "); - if (le16_to_cpu(fw_act_history_entry[entryIdx].result) == 0) + if (!le16_to_cpu(fw_act_history_entry[entryIdx].result)) printf("pass"); else printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry[entryIdx].result)); @@ -5118,25 +5709,28 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u } } -static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id) +static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, + __u32 cust_id, __u32 vendor_id, + __u32 device_id) { - struct json_object *root; + struct json_object *root = json_create_object(); int i, j; char previous_fw[9]; char new_fw[9]; char commit_action_bin[8]; char fail_str[32]; char time_str[11]; + char ext_time_str[20]; + memset((void *)previous_fw, 0, 9); memset((void *)new_fw, 0, 9); memset((void *)commit_action_bin, 0, 8); memset((void *)time_str, 0, 11); + memset((void *)ext_time_str, 0, 20); memset((void *)fail_str, 0, 11); char *null_fw = "--------"; __u16 oldestEntryIdx = 0, entryIdx = 0; - root = json_create_object(); - if (data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data); @@ -5158,14 +5752,18 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 entryIdx = oldestEntryIdx; for (i = 0; i < num_entries; i++) { - memcpy(previous_fw, (char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version), 8); + memcpy(previous_fw, + (char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version), + 8); if (strlen((char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version)) > 1) - memcpy(new_fw, (char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version), 8); + memcpy(new_fw, + (char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version), + 8); else memcpy(new_fw, null_fw, 8); json_object_add_value_int(root, "Entry", - le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries)); + le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries)); if (cust_id == WDC_CUSTOMER_ID_0x1005) { sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)/3600), @@ -5176,11 +5774,24 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 } else if (vendor_id == WDC_NVME_SNDK_VID) { uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60), (int)((timestamp/1000)%60)); json_object_add_value_string(root, "Power on Hour", time_str); + } else if (wdc_is_sn861(device_id)) { + __u64 timestamp_sec = + le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp) + / 1000; + + sprintf((char *)ext_time_str, + "%"PRIu64":%02"PRIu8":%02"PRIu8, + (uint64_t)(__u64)(timestamp_sec/3600), + (__u8)((timestamp_sec%3600)/60), + (__u8)(timestamp_sec%60)); + json_object_add_value_string(root, "Power on Hour", ext_time_str); } else { uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + json_object_add_value_uint64(root, "Timestamp", timestamp); } @@ -5193,12 +5804,14 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 json_object_add_value_int(root, "Slot", fw_act_history_entry->entry[entryIdx].slot_number); - wdc_get_commit_action_bin(fw_act_history_entry->entry[entryIdx].commit_action_type,(char *)&commit_action_bin); + wdc_get_commit_action_bin( + fw_act_history_entry->entry[entryIdx].commit_action_type, + (char *)&commit_action_bin); json_object_add_value_string(root, "Action", commit_action_bin); - if (le16_to_cpu(fw_act_history_entry->entry[entryIdx].result) == 0) + if (!le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)) { json_object_add_value_string(root, "Result", "pass"); - else { + } else { sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->entry[entryIdx].result))); json_object_add_value_string(root, "Result", fail_str); } @@ -5210,8 +5823,7 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES) entryIdx = 0; } - } - else { + } else { struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr)); oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES; @@ -5230,9 +5842,11 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 entryIdx = oldestEntryIdx; for (i = 0; i < num_entries; i++) { - memcpy(previous_fw, (char *)&(fw_act_history_entry[entryIdx].previous_fw_version), 8); + memcpy(previous_fw, + (char *)&(fw_act_history_entry[entryIdx].previous_fw_version), 8); if (strlen((char *)&(fw_act_history_entry[entryIdx].new_fw_version)) > 1) - memcpy(new_fw, (char *)&(fw_act_history_entry[entryIdx].new_fw_version), 8); + memcpy(new_fw, + (char *)&(fw_act_history_entry[entryIdx].new_fw_version), 8); else memcpy(new_fw, null_fw, 8); @@ -5253,12 +5867,13 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 json_object_add_value_int(root, "Slot", fw_act_history_entry[entryIdx].slot_number); - wdc_get_commit_action_bin(fw_act_history_entry[entryIdx].commit_action_type,(char *)&commit_action_bin); + wdc_get_commit_action_bin(fw_act_history_entry[entryIdx].commit_action_type, + (char *)&commit_action_bin); json_object_add_value_string(root, "Action", commit_action_bin); - if (le16_to_cpu(fw_act_history_entry[entryIdx].result) == 0) + if (!le16_to_cpu(fw_act_history_entry[entryIdx].result)) { json_object_add_value_string(root, "Result", "pass"); - else { + } else { sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry[entryIdx].result))); json_object_add_value_string(root, "Result", fail_str); } @@ -5280,8 +5895,9 @@ static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u int ret, i; __u8 *log_ptr = NULL; - if ((log_ptr = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + log_ptr = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN); + if (!log_ptr) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } @@ -5305,21 +5921,19 @@ static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u }; ret = nvme_get_log(&args); - if (ret == 0) { - + if (!ret) { /* Verify GUID matches */ for (i = 0; i < WDC_C0_GUID_LENGTH; i++) { - if (ext_smart_guid[i] != *&log_ptr[SCAO_V1_LPG + i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in C0 Log Page V1 data\n"); + if (ext_smart_guid[i] != *&log_ptr[SCAO_V1_LPG + i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in C0 Log Page V1 data\n"); int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j < WDC_C0_GUID_LENGTH; j++) { + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < WDC_C0_GUID_LENGTH; j++) fprintf(stderr, "%x", ext_smart_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j < WDC_C0_GUID_LENGTH; j++) { + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < WDC_C0_GUID_LENGTH; j++) fprintf(stderr, "%x", *&log_ptr[SCAO_V1_LPG + j]); - } fprintf(stderr, "\n"); ret = -1; @@ -5337,10 +5951,11 @@ static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u static int nvme_get_hw_rev_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id) { int ret, i; - wdc_nvme_hw_rev_log *log_ptr = NULL; + struct wdc_nvme_hw_rev_log *log_ptr = NULL; - if ((log_ptr = (wdc_nvme_hw_rev_log *)malloc(sizeof (__u8) * WDC_NVME_HW_REV_LOG_PAGE_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + log_ptr = (struct wdc_nvme_hw_rev_log *)malloc(sizeof(__u8) * WDC_NVME_HW_REV_LOG_PAGE_LEN); + if (!log_ptr) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } @@ -5364,21 +5979,19 @@ static int nvme_get_hw_rev_log(int fd, __u8 **data, int uuid_index, __u32 namesp }; ret = nvme_get_log(&args); - if (ret == 0) { - + if (!ret) { /* Verify GUID matches */ for (i = 0; i < WDC_NVME_C6_GUID_LENGTH; i++) { - if (hw_rev_log_guid[i] != log_ptr->hw_rev_guid[i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in HW Revision Log Page data\n"); + if (hw_rev_log_guid[i] != log_ptr->hw_rev_guid[i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in HW Revision Log Page data\n"); int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) { + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) fprintf(stderr, "%x", hw_rev_log_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) { + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++) fprintf(stderr, "%x", log_ptr->hw_rev_guid[j]); - } fprintf(stderr, "\n"); ret = -1; @@ -5396,9 +6009,9 @@ static int nvme_get_hw_rev_log(int fd, __u8 **data, int uuid_index, __u32 namesp static void wdc_print_hw_rev_log_normal(void *data) { int i; - wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data; + struct wdc_nvme_hw_rev_log *log_data = (struct wdc_nvme_hw_rev_log *)data; - printf(" Hardware Revision Log:- \n"); + printf(" Hardware Revision Log:-\n"); printf(" Global Device HW Revision : %d\n", log_data->hw_rev_gdr); @@ -5545,7 +6158,7 @@ static void wdc_print_hw_rev_log_normal(void *data) printf(" 0x"); } printf("\n"); - printf(" Serial Number : 0x"); + printf(" Serial Number : 0x"); for (i = 0; i < 32; i++) { if ((i > 1) & !(i % 8)) printf(" 0x"); @@ -5553,21 +6166,19 @@ static void wdc_print_hw_rev_log_normal(void *data) } printf("\n"); - printf(" Log Page Version : %d\n", - log_data->hw_rev_version); + printf(" Log Page Version : %d\n", log_data->hw_rev_version); printf(" Log page GUID : 0x"); - printf("%"PRIx64"%"PRIx64"\n",le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]), - le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0])); + printf("%"PRIx64"%"PRIx64"\n", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]), + le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0])); printf("\n"); } static void wdc_print_hw_rev_log_json(void *data) { - wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data; - struct json_object *root; + struct wdc_nvme_hw_rev_log *log_data = (struct wdc_nvme_hw_rev_log *)data; + struct json_object *root = json_create_object(); char json_data[80]; - root = json_create_object(); json_object_add_value_uint(root, "Global Device HW Revision", log_data->hw_rev_gdr); json_object_add_value_uint(root, "ASIC HW Revision", @@ -5601,88 +6212,88 @@ static void wdc_print_hw_rev_log_json(void *data) json_object_add_value_uint(root, "Other Component 9 Manf Code", log_data->hw_rev_c9_mc); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[0])); json_object_add_value_string(root, "Device Manf Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[0])); json_object_add_value_string(root, "ASIC Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[0])); json_object_add_value_string(root, "PCB Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[0])); json_object_add_value_string(root, "DRAM Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[0])); json_object_add_value_string(root, "NAND Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[0])); json_object_add_value_string(root, "PMIC 1 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[0])); json_object_add_value_string(root, "PMIC 2 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[0])); json_object_add_value_string(root, "Component 1 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[0])); json_object_add_value_string(root, "Component 2 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[0])); json_object_add_value_string(root, "Component 3 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[0])); json_object_add_value_string(root, "Component 4 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[0])); json_object_add_value_string(root, "Component 5 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[0])); json_object_add_value_string(root, "Component 6 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[0])); json_object_add_value_string(root, "Component 7 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[0])); json_object_add_value_string(root, "Component 8 Detailed Info", json_data); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[0])); json_object_add_value_string(root, "Component 9 Detailed Info", json_data); - memset((void*)json_data, 0, 80); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"%"PRIx64"%"PRIx64"", + memset((void *)json_data, 0, 80); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[0]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[16]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[24])); json_object_add_value_string(root, "Serial Number", json_data); @@ -5690,8 +6301,8 @@ static void wdc_print_hw_rev_log_json(void *data) json_object_add_value_uint(root, "Log Page Version", le16_to_cpu(log_data->hw_rev_version)); - memset((void*)json_data, 0, 40); - sprintf((char*)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]), + memset((void *)json_data, 0, 40); + sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0])); json_object_add_value_string(root, "Log Page GUID", json_data); @@ -5703,17 +6314,19 @@ static void wdc_print_hw_rev_log_json(void *data) static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask) { int i; - wdc_nvme_ext_smart_log *ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data; if (mask == WDC_SCA_V1_NAND_STATS) - printf(" NAND Statistics :- \n"); + printf(" NAND Statistics :-\n"); else - printf(" SMART Cloud Attributes :- \n"); - - printf(" Physical Media Units Written TLC (Bytes) : %'.0Lf\n", - int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt)); - printf(" Physical Media Units Written SLC (Bytes) : %'.0Lf\n", - int128_to_double(ext_smart_log_ptr->ext_smart_pmuws)); + printf(" SMART Cloud Attributes :-\n"); + + printf(" Physical Media Units Written TLC (Bytes): %s\n", + uint128_t_to_string(le128_to_cpu( + ext_smart_log_ptr->ext_smart_pmuwt))); + printf(" Physical Media Units Written SLC (Bytes): %s\n", + uint128_t_to_string(le128_to_cpu( + ext_smart_log_ptr->ext_smart_pmuws))); printf(" Bad User NAND Block Count (Normalized) (Int) : %d\n", le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc)); printf(" Bad User NAND Block Count (Raw) (Int) : %"PRIu64"\n", @@ -5761,8 +6374,9 @@ static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask) le64_to_cpu(ext_smart_log_ptr->ext_smart_svn)); printf(" %% Free Blocks (System) (Int) : %d %%\n", ext_smart_log_ptr->ext_smart_pfbs); - printf(" NVMe Stats (# Data Set Management/TRIM Commands Completed) (Int) : %'.0Lf\n", - int128_to_double(ext_smart_log_ptr->ext_smart_dcc)); + printf(" NVMe Stats (# Data Set Management/TRIM Commands Completed) (Int): %s\n", + uint128_t_to_string(le128_to_cpu( + ext_smart_log_ptr->ext_smart_dcc))); printf(" Total Namespace Utilization (nvme0n1 NUSE) (Bytes) : %"PRIu64"\n", le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu)); printf(" NVMe Stats (# NVMe Format Commands Completed) (Int) : %d\n", @@ -5780,16 +6394,18 @@ static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask) le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc)); printf(" Bad System NAND Block Count (Raw) (Int) : %"PRIu64"\n", le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000)); - printf(" Endurance Estimate (Total Writable Lifetime Bytes) (Bytes) : %'.0Lf\n", - int128_to_double(ext_smart_log_ptr->ext_smart_eest)); + printf(" Endurance Estimate (Total Writable Lifetime Bytes) (Bytes) : %s\n", + uint128_t_to_string( + le128_to_cpu(ext_smart_log_ptr->ext_smart_eest))); if (mask == WDC_SCA_V1_ALL) { printf(" Thermal Throttling Status & Count (Number of thermal throttling events) (Int) : %d\n", le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc)); printf(" Total # Unaligned I/O (Int) : %"PRIu64"\n", le64_to_cpu(ext_smart_log_ptr->ext_smart_uio)); } - printf(" Total Physical Media Units Read (Bytes) (Int) : %'.0Lf\n", - int128_to_double(ext_smart_log_ptr->ext_smart_pmur)); + printf(" Total Physical Media Units Read (Bytes) (Int) : %s\n", + uint128_t_to_string( + le128_to_cpu(ext_smart_log_ptr->ext_smart_pmur))); if (mask == WDC_SCA_V1_ALL) { printf(" Command Timeout (# of READ Commands > 5 Seconds) (Int) : %"PRIu32"\n", le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc)); @@ -5826,123 +6442,127 @@ static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask) static void wdc_print_ext_smart_cloud_log_json(void *data, int mask) { - wdc_nvme_ext_smart_log *ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; - struct json_object *root; + struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = + (struct __packed wdc_nvme_ext_smart_log *)data; + struct json_object *root = json_create_object(); - root = json_create_object(); - json_object_add_value_double(root, "physical_media_units_bytes_tlc", - int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt)); - json_object_add_value_double(root, "physical_media_units_bytes_slc", - int128_to_double(ext_smart_log_ptr->ext_smart_pmuws)); + json_object_add_value_uint128(root, "physical_media_units_bytes_tlc", + le128_to_cpu(ext_smart_log_ptr->ext_smart_pmuwt)); + json_object_add_value_uint128(root, "physical_media_units_bytes_slc", + le128_to_cpu(ext_smart_log_ptr->ext_smart_pmuws)); json_object_add_value_uint(root, "bad_user_blocks_normalized", - le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc)); + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc)); json_object_add_value_uint64(root, "bad_user_blocks_raw", - le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000)); + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000)); json_object_add_value_uint64(root, "xor_recovery_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc)); json_object_add_value_uint64(root, "uncorrectable_read_errors", - le64_to_cpu(ext_smart_log_ptr->ext_smart_urec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_urec)); if (mask == WDC_SCA_V1_ALL) { json_object_add_value_uint64(root, "corrected_e2e_errors", - le64_to_cpu(ext_smart_log_ptr->ext_smart_eece)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_eece)); json_object_add_value_uint64(root, "detected_e2e_errors", - le64_to_cpu(ext_smart_log_ptr->ext_smart_eede)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_eede)); json_object_add_value_uint64(root, "uncorrected_e2e_errors", - le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue)); json_object_add_value_uint(root, "system_data_life_used_pct", - (__u8)ext_smart_log_ptr->ext_smart_sdpu); + (__u8)ext_smart_log_ptr->ext_smart_sdpu); } json_object_add_value_uint64(root, "min_slc_user_data_erase_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec)); json_object_add_value_uint64(root, "min_tlc_user_data_erase_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec)); json_object_add_value_uint64(root, "max_slc_user_data_erase_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec)); json_object_add_value_uint64(root, "max_tlc_user_data_erase_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec)); json_object_add_value_uint64(root, "avg_slc_user_data_erase_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_avec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_avec)); json_object_add_value_uint64(root, "avg_tlc_user_data_erase_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec)); json_object_add_value_uint(root, "program_fail_count_normalized", - le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc)); + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc)); json_object_add_value_uint64(root, "program_fail_count_raw", - le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000)); + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000)); json_object_add_value_uint(root, "erase_fail_count_normalized", - le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc)); + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc)); json_object_add_value_uint64(root, "erase_fail_count_raw", - le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000)); + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000)); if (mask == WDC_SCA_V1_ALL) { json_object_add_value_uint64(root, "pcie_correctable_errors", - le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec)); json_object_add_value_uint(root, "pct_free_blocks_user", - (__u8)ext_smart_log_ptr->ext_smart_pfbu); + (__u8)ext_smart_log_ptr->ext_smart_pfbu); json_object_add_value_uint64(root, "security_version", - le64_to_cpu(ext_smart_log_ptr->ext_smart_svn)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_svn)); json_object_add_value_uint(root, "pct_free_blocks_system", - (__u8)ext_smart_log_ptr->ext_smart_pfbs); - json_object_add_value_double(root, "num_of_trim_commands", - int128_to_double(ext_smart_log_ptr->ext_smart_dcc)); + (__u8)ext_smart_log_ptr->ext_smart_pfbs); + json_object_add_value_uint128(root, "num_of_trim_commands", + le128_to_cpu(ext_smart_log_ptr->ext_smart_dcc)); json_object_add_value_uint64(root, "total_nuse_bytes", - le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu)); json_object_add_value_uint(root, "num_of_format_commands", - le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc)); + le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc)); json_object_add_value_uint(root, "background_pressure_gauge", - (__u8)ext_smart_log_ptr->ext_smart_bbpg); + (__u8)ext_smart_log_ptr->ext_smart_bbpg); } json_object_add_value_uint64(root, "soft_ecc_error_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_seec)); - if (mask == WDC_SCA_V1_ALL) { + le64_to_cpu(ext_smart_log_ptr->ext_smart_seec)); + if (mask == WDC_SCA_V1_ALL) json_object_add_value_uint64(root, "read_refresh_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc)); - } + le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc)); json_object_add_value_uint(root, "bad_system_block_normalized", - le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc)); + le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc)); json_object_add_value_uint64(root, "bad_system_block_raw", - le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000)); - json_object_add_value_double(root, "endurance_est_bytes", - int128_to_double(ext_smart_log_ptr->ext_smart_eest)); + le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000)); + json_object_add_value_uint128(root, "endurance_est_bytes", + le128_to_cpu(ext_smart_log_ptr->ext_smart_eest)); if (mask == WDC_SCA_V1_ALL) { json_object_add_value_uint(root, "num_throttling_events", - le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc)); + le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc)); json_object_add_value_uint64(root, "total_unaligned_io", - le64_to_cpu(ext_smart_log_ptr->ext_smart_uio)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_uio)); } - json_object_add_value_double(root, "physical_media_units_read_bytes", - int128_to_double(ext_smart_log_ptr->ext_smart_pmur)); + json_object_add_value_uint128(root, "physical_media_units_read_bytes", + le128_to_cpu(ext_smart_log_ptr->ext_smart_pmur)); if (mask == WDC_SCA_V1_ALL) { json_object_add_value_uint(root, "num_read_timeouts", - le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc)); + le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc)); json_object_add_value_uint(root, "num_write_timeouts", - le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc)); + le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc)); json_object_add_value_uint(root, "num_trim_timeouts", - le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc)); + le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc)); json_object_add_value_uint64(root, "pcie_link_retrain_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc)); json_object_add_value_uint64(root, "active_power_state_change_count", - le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc)); + le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc)); } char vers_str[40]; - memset((void*)vers_str, 0, 40); - sprintf((char*)vers_str, "%d.%d.%d.%d", - le16_to_cpu(ext_smart_log_ptr->ext_smart_maj), le16_to_cpu(ext_smart_log_ptr->ext_smart_min), - le16_to_cpu(ext_smart_log_ptr->ext_smart_pt), le16_to_cpu(ext_smart_log_ptr->ext_smart_err)); + + memset((void *)vers_str, 0, 40); + sprintf((char *)vers_str, "%d.%d.%d.%d", + le16_to_cpu(ext_smart_log_ptr->ext_smart_maj), + le16_to_cpu(ext_smart_log_ptr->ext_smart_min), + le16_to_cpu(ext_smart_log_ptr->ext_smart_pt), + le16_to_cpu(ext_smart_log_ptr->ext_smart_err)); json_object_add_value_string(root, "cloud_boot_ssd_spec_ver", vers_str); - memset((void*)vers_str, 0, 40); - sprintf((char*)vers_str, "%d.%d.%d.%d", 0, 0, 0, 0); + memset((void *)vers_str, 0, 40); + sprintf((char *)vers_str, "%d.%d.%d.%d", 0, 0, 0, 0); json_object_add_value_string(root, "cloud_boot_ssd_hw_ver", vers_str); if (mask == WDC_SCA_V1_ALL) { json_object_add_value_uint(root, "ftl_unit_size", - le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus)); + le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus)); json_object_add_value_uint(root, "tcg_ownership_status", - le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos)); + le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos)); json_object_add_value_uint(root, "log_page_ver", - le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv)); + le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv)); char guid[40]; - memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[8]), - le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[0])); + + memset((void *)guid, 0, 40); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", + le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[8]), + le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[0])); json_object_add_value_string(root, "log_page_guid", guid); } @@ -5953,92 +6573,96 @@ static void wdc_print_ext_smart_cloud_log_json(void *data, int mask) static void wdc_print_smart_cloud_attr_C0_normal(void *data) { - __u8 *log_data = (__u8*)data; + __u8 *log_data = (__u8 *)data; uint16_t smart_log_ver = 0; - printf(" SMART Cloud Attributes :- \n"); + printf(" SMART Cloud Attributes :-\n"); - printf(" Physical media units written : %'.0Lf\n", int128_to_double(&log_data[SCAO_PMUW])); - printf(" Physical media units read : %'.0Lf\n", int128_to_double(&log_data[SCAO_PMUR])); + printf(" Physical media units written : %s\n", + uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PMUW]))); + printf(" Physical media units read : %s\n", + uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PMUR]))); printf(" Bad user nand blocks Raw : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); printf(" Bad user nand blocks Normalized : %d\n", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN])); printf(" Bad system nand blocks Raw : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF)); printf(" Bad system nand blocks Normalized : %d\n", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); - printf(" XOR recovery count : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN])); + printf(" XOR recovery count : %"PRIu64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC])); printf(" Uncorrectable read error count : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC])); printf(" Soft ecc error count : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC])); printf(" End to end corrected errors : %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE])); printf(" End to end detected errors : %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC])); printf(" System data percent used : %d\n", (__u8)log_data[SCAO_SDPU]); printf(" Refresh counts : %"PRIu64"\n", - (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); + (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF)); printf(" Max User data erase counts : %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); printf(" Min User data erase counts : %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC])); printf(" Number of Thermal throttling events : %d\n", (__u8)log_data[SCAO_NTTE]); printf(" Current throttling status : 0x%x\n", (__u8)log_data[SCAO_CTS]); printf(" PCIe correctable error count : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC])); printf(" Incomplete shutdowns : %"PRIu32"\n", - (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); + (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS])); printf(" Percent free blocks : %d\n", (__u8)log_data[SCAO_PFB]); printf(" Capacitor health : %"PRIu16"\n", - (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); + (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH])); printf(" Unaligned I/O : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO])); printf(" Security Version Number : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); printf(" NUSE Namespace utilization : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - printf(" PLP start count : %'.0Lf\n", int128_to_double(&log_data[SCAO_PSC])); - printf(" Endurance estimate : %'.0Lf\n", int128_to_double(&log_data[SCAO_EEST])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); + printf(" PLP start count : %s\n", + uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PSC]))); + printf(" Endurance estimate : %s\n", + uint128_t_to_string(le128_to_cpu(&log_data[SCAO_EEST]))); smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); - printf(" Log page version : %"PRIu16"\n",smart_log_ver); + printf(" Log page version : %"PRIu16"\n", smart_log_ver); printf(" Log page GUID : 0x"); - printf("%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); - if(smart_log_ver > 2) { + printf("%"PRIx64"%"PRIx64"\n", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); + if (smart_log_ver > 2) { printf(" Errata Version Field : %d\n", - (__u8)log_data[SCAO_EVF]); + (__u8)log_data[SCAO_EVF]); printf(" Point Version Field : %"PRIu16"\n", - (uint16_t)log_data[SCAO_PVF]); + (uint16_t)log_data[SCAO_PVF]); printf(" Minor Version Field : %"PRIu16"\n", - (uint16_t)log_data[SCAO_MIVF]); + (uint16_t)log_data[SCAO_MIVF]); printf(" Major Version Field : %d\n", - (__u8)log_data[SCAO_MAVF]); + (__u8)log_data[SCAO_MAVF]); printf(" NVMe Errata Version : %d\n", - (__u8)log_data[SCAO_NEV]); + (__u8)log_data[SCAO_NEV]); printf(" PCIe Link Retraining Count : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); } if (smart_log_ver > 3) { printf(" Power State Change Count : %"PRIu64"\n", - (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); } printf("\n"); } static void wdc_print_smart_cloud_attr_C0_json(void *data) { - __u8 *log_data = (__u8*)data; - struct json_object *root; + __u8 *log_data = (__u8 *)data; + struct json_object *root = json_create_object(); uint16_t smart_log_ver = 0; - root = json_create_object(); - json_object_add_value_double(root, "Physical media units written", - int128_to_double(&log_data[SCAO_PMUW])); - json_object_add_value_double(root, "Physical media units read", - int128_to_double(&log_data[SCAO_PMUR])); + json_object_add_value_uint128(root, "Physical media units written", + le128_to_cpu(&log_data[SCAO_PMUW])); + json_object_add_value_uint128(root, "Physical media units read", + le128_to_cpu(&log_data[SCAO_PMUR])); json_object_add_value_uint64(root, "Bad user nand blocks - Raw", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF)); json_object_add_value_uint(root, "Bad user nand blocks - Normalized", @@ -6060,7 +6684,7 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) json_object_add_value_uint(root, "System data percent used", (__u8)log_data[SCAO_SDPU]); json_object_add_value_uint64(root, "Refresh counts", - (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF)); + (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC]) & 0x00FFFFFFFFFFFFFF)); json_object_add_value_uint(root, "Max User data erase counts", (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC])); json_object_add_value_uint(root, "Min User data erase counts", @@ -6083,18 +6707,20 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN])); json_object_add_value_uint64(root, "NUSE - Namespace utilization", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE])); - json_object_add_value_double(root, "PLP start count", - int128_to_double(&log_data[SCAO_PSC])); - json_object_add_value_double(root, "Endurance estimate", - int128_to_double(&log_data[SCAO_EEST])); + json_object_add_value_uint128(root, "PLP start count", + le128_to_cpu(&log_data[SCAO_PSC])); + json_object_add_value_uint128(root, "Endurance estimate", + le128_to_cpu(&log_data[SCAO_EEST])); smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); json_object_add_value_uint(root, "Log page version", smart_log_ver); char guid[40]; - memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + + memset((void *)guid, 0, 40); + sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); json_object_add_value_string(root, "Log page GUID", guid); - if(smart_log_ver > 2){ + if (smart_log_ver > 2) { json_object_add_value_uint(root, "Errata Version Field", (__u8)log_data[SCAO_EVF]); json_object_add_value_uint(root, "Point Version Field", @@ -6108,7 +6734,7 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) json_object_add_value_uint64(root, "PCIe Link Retraining Count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC])); } - if(smart_log_ver > 3) { + if (smart_log_ver > 3) { json_object_add_value_uint64(root, "Power State Change Count", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC])); } @@ -6120,9 +6746,9 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) static void wdc_print_eol_c0_normal(void *data) { - __u8 *log_data = (__u8*)data; + __u8 *log_data = (__u8 *)data; - printf(" End of Life Log Page 0xC0 :- \n"); + printf(" End of Life Log Page 0xC0 :-\n"); printf(" Realloc Block Count %"PRIu32"\n", (uint32_t)le32_to_cpu(log_data[EOL_RBC])); @@ -6143,10 +6769,8 @@ static void wdc_print_eol_c0_normal(void *data) static void wdc_print_eol_c0_json(void *data) { - __u8 *log_data = (__u8*)data; - struct json_object *root; - - root = json_create_object(); + __u8 *log_data = (__u8 *)data; + struct json_object *root = json_create_object(); json_object_add_value_uint(root, "Realloc Block Count", (uint32_t)le32_to_cpu(log_data[EOL_RBC])); @@ -6171,7 +6795,7 @@ static void wdc_print_eol_c0_json(void *data) static int wdc_print_ext_smart_cloud_log(void *data, int fmt) { if (!data) { - fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 V1 log\n"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read 0xC0 V1 log\n"); return -1; } switch (fmt) { @@ -6188,7 +6812,7 @@ static int wdc_print_ext_smart_cloud_log(void *data, int fmt) static int wdc_print_c0_cloud_attr_log(void *data, int fmt) { if (!data) { - fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 log\n"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read 0xC0 log\n"); return -1; } switch (fmt) { @@ -6205,7 +6829,7 @@ static int wdc_print_c0_cloud_attr_log(void *data, int fmt) static int wdc_print_c0_eol_log(void *data, int fmt) { if (!data) { - fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 log\n"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read 0xC0 log\n"); return -1; } switch (fmt) { @@ -6219,28 +6843,193 @@ static int wdc_print_c0_eol_log(void *data, int fmt) return 0; } -static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format, - int uuid_index, __u32 namespace_id) +static int wdc_get_c0_log_page_sn_customer_id_0x100X(struct nvme_dev *dev, int uuid_index, + char *format, __u32 namespace_id, int fmt) { - int ret = 0; - int fmt = -1; - int i = 0; + int ret; __u8 *data; + int i; + + if (!uuid_index) { + data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); + return -1; + } + + if (namespace_id == NVME_NSID_ALL) { + ret = nvme_get_nsid(dev_fd(dev), &namespace_id); + if (ret < 0) + namespace_id = NVME_NSID_ALL; + } + + /* Get the 0xC0 log data */ + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID, + .nsid = namespace_id, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_index, + .csi = NVME_CSI_NVM, + .ot = false, + .len = WDC_NVME_SMART_CLOUD_ATTR_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); + + if (strcmp(format, "json")) + nvme_show_status(ret); + + if (!ret) { + /* Verify GUID matches */ + for (i = 0; i < 16; i++) { + if (scao_guid[i] != data[SCAO_LPG + i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in C0 Log Page data\n"); + int j; + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", scao_guid[j]); + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%x", data[SCAO_LPG + j]); + fprintf(stderr, "\n"); + + ret = -1; + break; + } + } + + if (!ret) + /* parse the data */ + wdc_print_c0_cloud_attr_log(data, fmt); + } else { + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n"); + ret = -1; + } + + free(data); + } else if (uuid_index == 1) { + data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_EOL_STATUS_LOG_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); + return -1; + } + + /* Get the 0xC0 log data */ + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, + .nsid = NVME_NSID_ALL, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_index, + .csi = NVME_CSI_NVM, + .ot = false, + .len = WDC_NVME_EOL_STATUS_LOG_LEN, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); + + if (strcmp(format, "json")) + nvme_show_status(ret); + + if (!ret) { + /* parse the data */ + wdc_print_c0_eol_log(data, fmt); + } else { + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n"); + ret = -1; + } + + free(data); + } else { + fprintf(stderr, "ERROR: WDC: Unknown uuid index\n"); + ret = -1; + } + + return ret; +} + +static int wdc_get_c0_log_page_sn(nvme_root_t r, struct nvme_dev *dev, int uuid_index, char *format, + __u32 namespace_id, int fmt) +{ + int ret = 0; __u32 cust_id; + __u8 *data; + + cust_id = wdc_get_fw_cust_id(r, dev); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__); + return -1; + } + + if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || + (cust_id == WDC_CUSTOMER_ID_0x1005)) { + ret = wdc_get_c0_log_page_sn_customer_id_0x100X(dev, uuid_index, format, + namespace_id, fmt); + } else { + data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_EOL_STATUS_LOG_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); + return -1; + } + + /* Get the 0xC0 log data */ + ret = nvme_get_log_simple(dev_fd(dev), + WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, + WDC_NVME_EOL_STATUS_LOG_LEN, + data); + + if (strcmp(format, "json")) + nvme_show_status(ret); + + if (!ret) { + /* parse the data */ + wdc_print_c0_eol_log(data, fmt); + } else { + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n"); + ret = -1; + } + + free(data); + } + + return ret; +} + +static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format, int uuid_index, + __u32 namespace_id) +{ uint32_t device_id, read_vendor_id; + enum nvme_print_flags fmt; + int ret; + __u8 *data; + __u8 log_id; + __u32 length; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); switch (device_id) { - case WDC_NVME_SN640_DEV_ID: case WDC_NVME_SN640_DEV_ID_1: case WDC_NVME_SN640_DEV_ID_2: @@ -6248,170 +7037,79 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format case WDC_NVME_SN840_DEV_ID: case WDC_NVME_SN840_DEV_ID_1: case WDC_NVME_SN860_DEV_ID: + case WDC_NVME_SN560_DEV_ID_1: + case WDC_NVME_SN560_DEV_ID_2: + case WDC_NVME_SN560_DEV_ID_3: + case WDC_NVME_SN550_DEV_ID: + ret = wdc_get_c0_log_page_sn(r, dev, uuid_index, format, namespace_id, fmt); + break; case WDC_NVME_SN650_DEV_ID: case WDC_NVME_SN650_DEV_ID_1: case WDC_NVME_SN650_DEV_ID_2: case WDC_NVME_SN650_DEV_ID_3: case WDC_NVME_SN650_DEV_ID_4: case WDC_NVME_SN655_DEV_ID: - case WDC_NVME_SN560_DEV_ID_1: - case WDC_NVME_SN560_DEV_ID_2: - case WDC_NVME_SN560_DEV_ID_3: - case WDC_NVME_SN550_DEV_ID: - cust_id = wdc_get_fw_cust_id(r, dev); - if (cust_id == WDC_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); - return -1; + if (uuid_index == 0) { + log_id = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID; + length = WDC_NVME_SMART_CLOUD_ATTR_LEN; + } else { + log_id = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE; + length = WDC_NVME_EOL_STATUS_LOG_LEN; } - if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) || (cust_id == WDC_CUSTOMER_ID_0x1005)) - { - if (uuid_index == 0) - { - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); - return -1; - } - - if (namespace_id == NVME_NSID_ALL) { - ret = nvme_get_nsid(dev_fd(dev), - &namespace_id); - if (ret < 0) { - namespace_id = NVME_NSID_ALL; - } - } - - /* Get the 0xC0 log data */ - struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID, - .nsid = namespace_id, - .lpo = 0, - .lsp = NVME_LOG_LSP_NONE, - .lsi = 0, - .rae = false, - .uuidx = uuid_index, - .csi = NVME_CSI_NVM, - .ot = false, - .len = WDC_NVME_SMART_CLOUD_ATTR_LEN, - .log = data, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - ret = nvme_get_log(&args); - - if (strcmp(format, "json")) - nvme_show_status(ret); - - if (ret == 0) { - - /* Verify GUID matches */ - for (i=0; i<16; i++) { - if (scao_guid[i] != data[SCAO_LPG + i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in C0 Log Page data\n"); - int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j<16; j++) { - fprintf(stderr, "%x", scao_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j<16; j++) { - fprintf(stderr, "%x", data[SCAO_LPG + j]); - } - fprintf(stderr, "\n"); - - ret = -1; - break; - } - } - - if (ret == 0) { - - /* parse the data */ - wdc_print_c0_cloud_attr_log(data, fmt); - } - } else { - fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n"); - ret = -1; - } - - free(data); - } else if (uuid_index == 1) { - - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_EOL_STATUS_LOG_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); - return -1; - } - - /* Get the 0xC0 log data */ - struct nvme_get_log_args args = { - .args_size = sizeof(args), - .fd = dev_fd(dev), - .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - .nsid = NVME_NSID_ALL, - .lpo = 0, - .lsp = NVME_LOG_LSP_NONE, - .lsi = 0, - .rae = false, - .uuidx = uuid_index, - .csi = NVME_CSI_NVM, - .ot = false, - .len = WDC_NVME_EOL_STATUS_LOG_LEN, - .log = data, - .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, - .result = NULL, - }; - ret = nvme_get_log(&args); - - if (strcmp(format, "json")) - nvme_show_status(ret); - - if (ret == 0) { - /* parse the data */ - wdc_print_c0_eol_log(data, fmt); - } else { - fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n"); - ret = -1; - } + data = (__u8 *)malloc(sizeof(__u8) * length); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); + return -1; + } - free(data); - } else { - fprintf(stderr, "ERROR : WDC : Unknown uuid index\n"); - ret = -1; - } + if (namespace_id == NVME_NSID_ALL) { + ret = nvme_get_nsid(dev_fd(dev), &namespace_id); + if (ret < 0) + namespace_id = NVME_NSID_ALL; } - else { - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_EOL_STATUS_LOG_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); - return -1; - } - /* Get the 0xC0 log data */ - ret = nvme_get_log_simple(dev_fd(dev), - WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - WDC_NVME_EOL_STATUS_LOG_LEN, - data); + /* Get the 0xC0 log data */ + struct nvme_get_log_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .lid = log_id, + .nsid = namespace_id, + .lpo = 0, + .lsp = NVME_LOG_LSP_NONE, + .lsi = 0, + .rae = false, + .uuidx = uuid_index, + .csi = NVME_CSI_NVM, + .ot = false, + .len = length, + .log = data, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = NULL, + }; + ret = nvme_get_log(&args); - if (strcmp(format, "json")) - nvme_show_status(ret); + if (strcmp(format, "json")) + nvme_show_status(ret); - if (ret == 0) { - /* parse the data */ + if (!ret) { + /* parse the data */ + if (uuid_index == 0) + wdc_print_c0_cloud_attr_log(data, fmt); + else wdc_print_c0_eol_log(data, fmt); - } else { - fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n"); - ret = -1; - } - - free(data); + } else { + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data "); + fprintf(stderr, "with uuid index %d\n", uuid_index); + ret = -1; } + free(data); break; - case WDC_NVME_ZN350_DEV_ID: case WDC_NVME_ZN350_DEV_ID_1: - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } @@ -6423,17 +7121,16 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ wdc_print_c0_cloud_attr_log(data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data\n"); ret = -1; } free(data); break; - case WDC_NVME_SN820CL_DEV_ID: /* Get the 0xC0 Extended Smart Cloud Attribute log data */ data = NULL; @@ -6443,20 +7140,19 @@ static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ wdc_print_ext_smart_cloud_log(data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page V1 data\n"); ret = -1; } if (data) free(data); break; - default: - fprintf(stderr, "ERROR : WDC : Unknown device id - 0x%x\n", device_id); + fprintf(stderr, "ERROR: WDC: Unknown device id - 0x%x\n", device_id); ret = -1; break; @@ -6470,7 +7166,7 @@ static int wdc_print_latency_monitor_log(struct nvme_dev *dev, int fmt) { if (!log_data) { - fprintf(stderr, "ERROR : WDC : Invalid C3 log data buffer\n"); + fprintf(stderr, "ERROR: WDC: Invalid C3 log data buffer\n"); return -1; } switch (fmt) { @@ -6487,7 +7183,7 @@ static int wdc_print_latency_monitor_log(struct nvme_dev *dev, static int wdc_print_error_rec_log(struct wdc_ocp_c1_error_recovery_log *log_data, int fmt) { if (!log_data) { - fprintf(stderr, "ERROR : WDC : Invalid C1 log data buffer\n"); + fprintf(stderr, "ERROR: WDC: Invalid C1 log data buffer\n"); return -1; } switch (fmt) { @@ -6504,7 +7200,7 @@ static int wdc_print_error_rec_log(struct wdc_ocp_c1_error_recovery_log *log_dat static int wdc_print_dev_cap_log(struct wdc_ocp_C4_dev_cap_log *log_data, int fmt) { if (!log_data) { - fprintf(stderr, "ERROR : WDC : Invalid C4 log data buffer\n"); + fprintf(stderr, "ERROR: WDC: Invalid C4 log data buffer\n"); return -1; } switch (fmt) { @@ -6521,7 +7217,7 @@ static int wdc_print_dev_cap_log(struct wdc_ocp_C4_dev_cap_log *log_data, int fm static int wdc_print_unsupported_reqs_log(struct wdc_ocp_C5_unsupported_reqs *log_data, int fmt) { if (!log_data) { - fprintf(stderr, "ERROR : WDC : Invalid C5 log data buffer\n"); + fprintf(stderr, "ERROR: WDC: Invalid C5 log data buffer\n"); return -1; } switch (fmt) { @@ -6538,7 +7234,7 @@ static int wdc_print_unsupported_reqs_log(struct wdc_ocp_C5_unsupported_reqs *lo 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"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read perf stats\n"); return -1; } switch (fmt) { @@ -6555,7 +7251,7 @@ static int wdc_print_fb_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt) static int wdc_print_bd_ca_log(struct nvme_dev *dev, void *bd_data, int fmt) { if (!bd_data) { - fprintf(stderr, "ERROR : WDC : Invalid buffer to read data\n"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read data\n"); return -1; } switch (fmt) { @@ -6566,7 +7262,7 @@ static int wdc_print_bd_ca_log(struct nvme_dev *dev, void *bd_data, int fmt) wdc_print_bd_ca_log_json(bd_data); break; default: - fprintf(stderr, "ERROR : WDC : Unknown format - %d\n", fmt); + fprintf(stderr, "ERROR: WDC: Unknown format - %d\n", fmt); return -1; } return 0; @@ -6575,7 +7271,7 @@ static int wdc_print_bd_ca_log(struct nvme_dev *dev, void *bd_data, int fmt) 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"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read perf stats\n"); return -1; } switch (fmt) { @@ -6589,19 +7285,23 @@ static int wdc_print_d0_log(struct wdc_ssd_d0_smart_log *perf, int fmt) return 0; } -static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id, __u32 vendor_id) +static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, + __u32 cust_id, __u32 vendor_id, + __u32 device_id) { if (!data) { - fprintf(stderr, "ERROR : WDC : Invalid buffer to read fw activate history entries\n"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read fw activate history entries\n"); return -1; } switch (fmt) { case NORMAL: - wdc_print_fw_act_history_log_normal(data, num_entries, cust_id, vendor_id); + wdc_print_fw_act_history_log_normal(data, num_entries, cust_id, + vendor_id, device_id); break; case JSON: - wdc_print_fw_act_history_log_json(data, num_entries, cust_id, vendor_id); + wdc_print_fw_act_history_log_json(data, num_entries, cust_id, + vendor_id, device_id); break; } return 0; @@ -6609,48 +7309,46 @@ static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; - __u8 *data; - struct wdc_ssd_ca_perf_stats *perf; uint32_t read_device_id, read_vendor_id; + struct wdc_ssd_ca_perf_stats *perf; + enum nvme_print_flags fmt; __u32 cust_id; + __u8 *data; + int ret; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } /* verify the 0xCA log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == false) { - fprintf(stderr, "ERROR : WDC : 0xCA Log Page not supported\n"); + fprintf(stderr, "ERROR: WDC: 0xCA Log Page not supported\n"); return -1; } /* get the FW customer id */ cust_id = wdc_get_fw_cust_id(r, dev); if (cust_id == WDC_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); + fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__); return -1; } ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id); switch (read_device_id) { - case WDC_NVME_SN200_DEV_ID: - if (cust_id == WDC_CUSTOMER_ID_0x1005) { - - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, @@ -6658,21 +7356,20 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ perf = (struct wdc_ssd_ca_perf_stats *)(data); ret = wdc_print_fb_ca_log(perf, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read CA Log Page data\n"); ret = -1; } } else { - fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", cust_id); + fprintf(stderr, "ERROR: WDC: Unsupported Customer id, id = 0x%x\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: @@ -6681,13 +7378,13 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format case WDC_NVME_SN840_DEV_ID_1: case WDC_NVME_SN860_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)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, @@ -6695,49 +7392,44 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ perf = (struct wdc_ssd_ca_perf_stats *)(data); ret = wdc_print_fb_ca_log(perf, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read CA Log Page data\n"); ret = -1; } } else if ((cust_id == WDC_CUSTOMER_ID_GN) || (cust_id == WDC_CUSTOMER_ID_GD) || (cust_id == WDC_CUSTOMER_ID_BD)) { - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_BD_CA_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_BD_CA_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE, WDC_BD_CA_LOG_BUF_LEN, data); if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ ret = wdc_print_bd_ca_log(dev, data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read CA Log Page data\n"); ret = -1; } - - break; } else { - - fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", cust_id); + fprintf(stderr, "ERROR: WDC: Unsupported Customer id, id = 0x%x\n", cust_id); return -1; } break; - default: - - fprintf(stderr, "ERROR : WDC : Log page 0xCA not supported for this device\n"); + fprintf(stderr, "ERROR: WDC: Log page 0xCA not supported for this device\n"); return -1; - break; } free(data); @@ -6747,57 +7439,58 @@ static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *format, uint8_t interval) { - int ret = 0; - int fmt = -1; + struct wdc_log_page_subpage_header *sph; + struct wdc_ssd_perf_stats *perf; + struct wdc_log_page_header *l; + enum nvme_print_flags fmt; + int total_subpages; + int skip_cnt = 4; __u8 *data; __u8 *p; int i; - int 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; + int ret; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } if (interval < 1 || interval > 15) { - fprintf(stderr, "ERROR : WDC : interval out of range [1-15]\n"); + 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)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_ADD_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_ADD_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_ADD_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_ADD_LOG_OPCODE, WDC_ADD_LOG_BUF_LEN, data); if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { - l = (struct wdc_log_page_header*)data; + if (!ret) { + l = (struct wdc_log_page_header *)data; total_subpages = l->num_subpages + WDC_NVME_GET_STAT_PERF_INTERVAL_LIFETIME - 1; for (i = 0, p = data + skip_cnt; i < total_subpages; i++, p += skip_cnt) { - sph = (struct wdc_log_page_subpage_header *) p; + 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); + 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"); - } + if (ret) + fprintf(stderr, "ERROR: WDC: Unable to read data from buffer\n"); } free(data); return ret; @@ -6805,25 +7498,27 @@ static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev, static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; + struct wdc_ssd_latency_monitor_log *log_data; + enum nvme_print_flags fmt; __u8 *data; + int ret; int i; - struct wdc_ssd_latency_monitor_log *log_data; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } - if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_LATENCY_MON_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_LATENCY_MON_LOG_ID, WDC_LATENCY_MON_LOG_BUF_LEN, data); @@ -6831,30 +7526,29 @@ static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); - if (ret == 0) { - log_data = (struct wdc_ssd_latency_monitor_log*)data; + if (!ret) { + log_data = (struct wdc_ssd_latency_monitor_log *)data; /* check log page version */ if (log_data->log_page_version != WDC_LATENCY_MON_VERSION) { - fprintf(stderr, "ERROR : WDC : invalid latency monitor version\n"); + fprintf(stderr, "ERROR: WDC: invalid latency monitor version\n"); ret = -1; - goto out; + goto out; } /* check log page guid */ /* Verify GUID matches */ - for (i=0; i<16; i++) { - if (wdc_lat_mon_guid[i] != log_data->log_page_guid[i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in C3 Log Page data\n"); + for (i = 0; i < 16; i++) { + if (wdc_lat_mon_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in C3 Log Page data\n"); int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j<16; j++) { + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", wdc_lat_mon_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j<16; j++) { + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", log_data->log_page_guid[j]); - } fprintf(stderr, "\n"); ret = -1; @@ -6865,7 +7559,7 @@ static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format /* parse the data */ wdc_print_latency_monitor_log(dev, log_data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read C3 data from buffer\n"); + fprintf(stderr, "ERROR: WDC: Unable to read C3 data from buffer\n"); } out: @@ -6876,25 +7570,27 @@ static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; + struct wdc_ocp_c1_error_recovery_log *log_data; + enum nvme_print_flags fmt; __u8 *data; + int ret; int i; - struct wdc_ocp_c1_error_recovery_log *log_data; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } - if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_ERROR_REC_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_ERROR_REC_LOG_ID, WDC_ERROR_REC_LOG_BUF_LEN, data); @@ -6902,30 +7598,29 @@ static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); - if (ret == 0) { + if (!ret) { log_data = (struct wdc_ocp_c1_error_recovery_log *)data; /* check log page version */ if ((log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION1) && - (log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION2)) { - fprintf(stderr, "ERROR : WDC : invalid error recovery log version - %d\n", log_data->log_page_version); + (log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION2)) { + fprintf(stderr, "ERROR: WDC: invalid error recovery log version - %d\n", log_data->log_page_version); ret = -1; goto out; } /* Verify GUID matches */ - for (i=0; i < WDC_OCP_C1_GUID_LENGTH; i++) { - if (wdc_ocp_c1_guid[i] != log_data->log_page_guid[i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in C1 Log Page data\n"); + for (i = 0; i < WDC_OCP_C1_GUID_LENGTH; i++) { + if (wdc_ocp_c1_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in C1 Log Page data\n"); int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j<16; j++) { + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", wdc_ocp_c1_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j<16; j++) { + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", log_data->log_page_guid[j]); - } fprintf(stderr, "\n"); ret = -1; @@ -6936,7 +7631,7 @@ static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo /* parse the data */ wdc_print_error_rec_log(log_data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read error recovery (C1) data from buffer\n"); + fprintf(stderr, "ERROR: WDC: Unable to read error recovery (C1) data from buffer\n"); } out: @@ -6946,25 +7641,27 @@ static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; + struct wdc_ocp_C4_dev_cap_log *log_data; + enum nvme_print_flags fmt; __u8 *data; + int ret; int i; - struct wdc_ocp_C4_dev_cap_log *log_data; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } - if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_DEV_CAP_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_DEV_CAP_LOG_ID, WDC_DEV_CAP_LOG_BUF_LEN, data); @@ -6972,29 +7669,28 @@ static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); - if (ret == 0) { + if (!ret) { log_data = (struct wdc_ocp_C4_dev_cap_log *)data; /* check log page version */ if (log_data->log_page_version != WDC_DEV_CAP_LOG_VERSION) { - fprintf(stderr, "ERROR : WDC : invalid device capabilities log version - %d\n", log_data->log_page_version); + fprintf(stderr, "ERROR: WDC: invalid device capabilities log version - %d\n", log_data->log_page_version); ret = -1; goto out; } /* Verify GUID matches */ - for (i=0; i < WDC_OCP_C4_GUID_LENGTH; i++) { - if (wdc_ocp_c4_guid[i] != log_data->log_page_guid[i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in C4 Log Page data\n"); + for (i = 0; i < WDC_OCP_C4_GUID_LENGTH; i++) { + if (wdc_ocp_c4_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in C4 Log Page data\n"); int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j<16; j++) { + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", wdc_ocp_c4_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j<16; j++) { + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", log_data->log_page_guid[j]); - } fprintf(stderr, "\n"); ret = -1; @@ -7005,7 +7701,7 @@ static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo /* parse the data */ wdc_print_dev_cap_log(log_data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read device capabilities (C4) data from buffer\n"); + fprintf(stderr, "ERROR: WDC: Unable to read device capabilities (C4) data from buffer\n"); } out: @@ -7015,25 +7711,27 @@ static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; + struct wdc_ocp_C5_unsupported_reqs *log_data; + enum nvme_print_flags fmt; + int ret; __u8 *data; int i; - struct wdc_ocp_C5_unsupported_reqs *log_data; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } - if ((data = (__u8 *) malloc(sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_UNSUPPORTED_REQS_LOG_ID, WDC_UNSUPPORTED_REQS_LOG_BUF_LEN, data); @@ -7041,29 +7739,28 @@ static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret); - if (ret == 0) { + if (!ret) { log_data = (struct wdc_ocp_C5_unsupported_reqs *)data; /* check log page version */ if (log_data->log_page_version != WDC_UNSUPPORTED_REQS_LOG_VERSION) { - fprintf(stderr, "ERROR : WDC : invalid unsupported requirements log version - %d\n", log_data->log_page_version); + fprintf(stderr, "ERROR: WDC: invalid unsupported requirements log version - %d\n", log_data->log_page_version); ret = -1; goto out; } /* Verify GUID matches */ - for (i=0; i < WDC_OCP_C5_GUID_LENGTH; i++) { - if (wdc_ocp_c5_guid[i] != log_data->log_page_guid[i]) { - fprintf(stderr, "ERROR : WDC : Unknown GUID in C5 Log Page data\n"); + for (i = 0; i < WDC_OCP_C5_GUID_LENGTH; i++) { + if (wdc_ocp_c5_guid[i] != log_data->log_page_guid[i]) { + fprintf(stderr, "ERROR: WDC: Unknown GUID in C5 Log Page data\n"); int j; - fprintf(stderr, "ERROR : WDC : Expected GUID: 0x"); - for (j = 0; j<16; j++) { + + fprintf(stderr, "ERROR: WDC: Expected GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", wdc_ocp_c5_guid[j]); - } - fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x"); - for (j = 0; j<16; j++) { + fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x"); + for (j = 0; j < 16; j++) fprintf(stderr, "%x", log_data->log_page_guid[j]); - } fprintf(stderr, "\n"); ret = -1; @@ -7074,7 +7771,7 @@ static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo /* parse the data */ wdc_print_unsupported_reqs_log(log_data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read unsupported requirements (C5) data from buffer\n"); + fprintf(stderr, "ERROR: WDC: Unable to read unsupported requirements (C5) data from buffer\n"); } out: @@ -7084,30 +7781,32 @@ static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *fo static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format) { + struct wdc_ssd_d0_smart_log *perf; + enum nvme_print_flags fmt; int ret = 0; - int fmt = -1; __u8 *data; - struct wdc_ssd_d0_smart_log *perf; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } /* verify the 0xD0 log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == false) { - fprintf(stderr, "ERROR : WDC : 0xD0 Log Page not supported\n"); + 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)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_VU_SMART_LOG_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_NVME_VU_SMART_LOG_LEN); + memset(data, 0, sizeof(__u8) * WDC_NVME_VU_SMART_LOG_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_GET_VU_SMART_LOG_OPCODE, @@ -7115,12 +7814,12 @@ static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ perf = (struct wdc_ssd_d0_smart_log *)(data); ret = wdc_print_d0_log(perf, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read D0 Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read D0 Log Page data\n"); ret = -1; } @@ -7128,6 +7827,235 @@ static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format return ret; } +static long double le_to_float(__u8 *data, int byte_len) +{ + long double result = 0; + int i; + + for (i = 0; i < byte_len; i++) { + result *= 256; + result += data[15 - i]; + } + + return result; +} + +static void stringify_log_page_guid(__u8 *guid, char *buf) +{ + char *ptr = buf; + int i; + + memset(buf, 0, sizeof(char) * 19); + + ptr += sprintf(ptr, "0x"); + for (i = 0; i < 16; i++) + ptr += sprintf(ptr, "%x", guid[15 - i]); +} + +static const char *const cloud_smart_log_thermal_status[] = { + [0x00] = "unthrottled", + [0x01] = "first_level", + [0x02] = "second_level", + [0x03] = "third_level", +}; + +static const char *stringify_cloud_smart_log_thermal_status(__u8 status) +{ + if (status < ARRAY_SIZE(cloud_smart_log_thermal_status) && + cloud_smart_log_thermal_status[status]) + return cloud_smart_log_thermal_status[status]; + return "unrecognized"; +} + +static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log) +{ + struct json_object *root; + struct json_object *bad_user_nand_blocks; + struct json_object *bad_system_nand_blocks; + struct json_object *e2e_correction_counts; + struct json_object *user_data_erase_counts; + struct json_object *thermal_status; + struct json_object *dssd_specific_ver; + char buf[2 * sizeof(log->log_page_guid) + 3]; + + bad_user_nand_blocks = json_create_object(); + json_object_add_value_uint(bad_user_nand_blocks, "normalized", + le16_to_cpu(log->bad_user_nand_blocks.normalized)); + json_object_add_value_uint(bad_user_nand_blocks, "raw", + le64_to_cpu(log->bad_user_nand_blocks.raw)); + + bad_system_nand_blocks = json_create_object(); + json_object_add_value_uint(bad_system_nand_blocks, "normalized", + le16_to_cpu(log->bad_system_nand_blocks.normalized)); + json_object_add_value_uint(bad_system_nand_blocks, "raw", + le64_to_cpu(log->bad_system_nand_blocks.raw)); + + e2e_correction_counts = json_create_object(); + json_object_add_value_uint(e2e_correction_counts, "corrected", + le32_to_cpu(log->e2e_correction_counts.corrected)); + json_object_add_value_uint(e2e_correction_counts, "detected", + le32_to_cpu(log->e2e_correction_counts.detected)); + + user_data_erase_counts = json_create_object(); + json_object_add_value_uint(user_data_erase_counts, "minimum", + le32_to_cpu(log->user_data_erase_counts.minimum)); + json_object_add_value_uint(user_data_erase_counts, "maximum", + le32_to_cpu(log->user_data_erase_counts.maximum)); + + thermal_status = json_create_object(); + json_object_add_value_string(thermal_status, "current_status", + stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status)); + json_object_add_value_uint(thermal_status, "num_events", + log->thermal_status.num_events); + + dssd_specific_ver = json_create_object(); + json_object_add_value_uint(dssd_specific_ver, "major_ver", + log->dssd_specific_ver.major_ver); + json_object_add_value_uint(dssd_specific_ver, "minor_ver", + le16_to_cpu(log->dssd_specific_ver.minor_ver)); + json_object_add_value_uint(dssd_specific_ver, "point_ver", + le16_to_cpu(log->dssd_specific_ver.point_ver)); + json_object_add_value_uint(dssd_specific_ver, "errata_ver", + log->dssd_specific_ver.errata_ver); + + root = json_create_object(); + json_object_add_value_uint64(root, "physical_media_units_written", + le_to_float(log->physical_media_units_written, 16)); + json_object_add_value_uint64(root, "physical_media_units_read", + le_to_float(log->physical_media_units_read, 16)); + json_object_add_value_object(root, "bad_user_nand_blocks", + bad_user_nand_blocks); + json_object_add_value_object(root, "bad_system_nand_blocks", + bad_system_nand_blocks); + json_object_add_value_uint(root, "xor_recovery_count", + le64_to_cpu(log->xor_recovery_count)); + json_object_add_value_uint(root, "uncorrectable_read_error_count", + le64_to_cpu(log->uncorrectable_read_error_count)); + json_object_add_value_uint(root, "soft_ecc_error_count", + le64_to_cpu(log->soft_ecc_error_count)); + json_object_add_value_object(root, "e2e_correction_counts", + e2e_correction_counts); + json_object_add_value_uint(root, "system_data_percent_used", + log->system_data_percent_used); + json_object_add_value_uint(root, "refresh_counts", + le64_to_cpu(log->refresh_counts)); + json_object_add_value_object(root, "user_data_erase_counts", + user_data_erase_counts); + json_object_add_value_object(root, "thermal_status", thermal_status); + json_object_add_value_object(root, "dssd_specific_ver", + dssd_specific_ver); + json_object_add_value_uint(root, "pcie_correctable_error_count", + le64_to_cpu(log->pcie_correctable_error_count)); + json_object_add_value_uint(root, "incomplete_shutdowns", + le32_to_cpu(log->incomplete_shutdowns)); + json_object_add_value_uint(root, "percent_free_blocks", + log->percent_free_blocks); + json_object_add_value_uint(root, "capacitor_health", + le16_to_cpu(log->capacitor_health)); + sprintf(buf, "%c", log->nvme_errata_ver); + json_object_add_value_string(root, "nvme_errata_version", buf); + json_object_add_value_uint(root, "unaligned_io", + le64_to_cpu(log->unaligned_io)); + json_object_add_value_uint(root, "security_version_number", + le64_to_cpu(log->security_version_number)); + json_object_add_value_uint(root, "total_nuse", + le64_to_cpu(log->total_nuse)); + json_object_add_value_uint64(root, "plp_start_count", + le_to_float(log->plp_start_count, 16)); + json_object_add_value_uint64(root, "endurance_estimate", + le_to_float(log->endurance_estimate, 16)); + json_object_add_value_uint(root, "pcie_link_retraining_count", + le64_to_cpu(log->pcie_link_retraining_cnt)); + json_object_add_value_uint(root, "power_state_change_count", + le64_to_cpu(log->power_state_change_cnt)); + json_object_add_value_uint(root, "log_page_version", + le16_to_cpu(log->log_page_version)); + stringify_log_page_guid(log->log_page_guid, buf); + json_object_add_value_string(root, "log_page_guid", buf); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct nvme_dev *dev) +{ + char buf[2 * sizeof(log->log_page_guid) + 3]; + + printf("Smart Extended Log for NVME device:%s\n", dev->name); + printf("Physical Media Units Written : %'.0Lf\n", + le_to_float(log->physical_media_units_written, 16)); + printf("Physical Media Units Read : %'.0Lf\n", + le_to_float(log->physical_media_units_read, 16)); + printf("Bad User NAND Blocks (Normalized) : %" PRIu16 "%%\n", + le16_to_cpu(log->bad_user_nand_blocks.normalized)); + printf("Bad User NAND Blocks (Raw) : %" PRIu64 "\n", + le64_to_cpu(log->bad_user_nand_blocks.raw)); + printf("Bad System NAND Blocks (Normalized) : %" PRIu16 "%%\n", + le16_to_cpu(log->bad_system_nand_blocks.normalized)); + printf("Bad System NAND Blocks (Raw) : %" PRIu64 "\n", + le64_to_cpu(log->bad_system_nand_blocks.raw)); + printf("XOR Recovery Count : %" PRIu64 "\n", + le64_to_cpu(log->xor_recovery_count)); + printf("Uncorrectable Read Error Count : %" PRIu64 "\n", + le64_to_cpu(log->uncorrectable_read_error_count)); + printf("Soft ECC Error Count : %" PRIu64 "\n", + le64_to_cpu(log->soft_ecc_error_count)); + printf("End to End Correction Counts (Corrected) : %" PRIu32 "\n", + le32_to_cpu(log->e2e_correction_counts.corrected)); + printf("End to End Correction Counts (Detected) : %" PRIu32 "\n", + le32_to_cpu(log->e2e_correction_counts.detected)); + printf("System Data %% Used : %" PRIu8 "%%\n", + log->system_data_percent_used); + printf("Refresh Counts : %" PRIu64 "\n", + le64_to_cpu(log->refresh_counts)); + printf("User Data Erase Counts (Minimum) : %" PRIu32 "\n", + le32_to_cpu(log->user_data_erase_counts.minimum)); + printf("User Data Erase Counts (Maximum) : %" PRIu32 "\n", + le32_to_cpu(log->user_data_erase_counts.maximum)); + printf("Thermal Throttling Status (Current Status) : %s\n", + stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status)); + printf("Thermal Throttling Status (Number of Events) : %" PRIu8 "\n", + log->thermal_status.num_events); + printf("NVMe Major Version : %" PRIu8 "\n", + log->dssd_specific_ver.major_ver); + printf(" Minor Version : %" PRIu16 "\n", + le16_to_cpu(log->dssd_specific_ver.minor_ver)); + printf(" Point Version : %" PRIu16 "\n", + le16_to_cpu(log->dssd_specific_ver.point_ver)); + printf(" Errata Version : %" PRIu8 "\n", + log->dssd_specific_ver.errata_ver); + printf("PCIe Correctable Error Count : %" PRIu64 "\n", + le64_to_cpu(log->pcie_correctable_error_count)); + printf("Incomplete Shutdowns : %" PRIu32 "\n", + le32_to_cpu(log->incomplete_shutdowns)); + printf("%% Free Blocks : %" PRIu8 "%%\n", + log->percent_free_blocks); + printf("Capacitor Health : %" PRIu16 "%%\n", + le16_to_cpu(log->capacitor_health)); + printf("NVMe Errata Version : %c\n", + log->nvme_errata_ver); + printf("Unaligned IO : %" PRIu64 "\n", + le64_to_cpu(log->unaligned_io)); + printf("Security Version Number : %" PRIu64 "\n", + le64_to_cpu(log->security_version_number)); + printf("Total NUSE : %" PRIu64 "\n", + le64_to_cpu(log->total_nuse)); + printf("PLP Start Count : %'.0Lf\n", + le_to_float(log->plp_start_count, 16)); + printf("Endurance Estimate : %'.0Lf\n", + le_to_float(log->endurance_estimate, 16)); + printf("PCIe Link Retraining Count : %" PRIu64 "\n", + le64_to_cpu(log->pcie_link_retraining_cnt)); + printf("Power State Change Count : %" PRIu64 "\n", + le64_to_cpu(log->power_state_change_cnt)); + printf("Log Page Version : %" PRIu16 "\n", + le16_to_cpu(log->log_page_version)); + stringify_log_page_guid(log->log_page_guid, buf); + printf("Log Page GUID : %s\n", buf); + printf("\n\n"); +} + static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, struct plugin *plugin) { @@ -7136,6 +8064,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, const char *log_page_version = "Log Page Version: 0 = vendor, 1 = WDC"; const char *log_page_mask = "Log Page Mask, comma separated list: 0xC0, 0xC1, 0xCA, 0xD0"; const char *namespace_id = "desired namespace id"; + enum nvme_print_flags fmt; struct nvme_dev *dev; nvme_root_t r; int ret = 0; @@ -7143,6 +8072,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, int page_mask = 0, num, i; int log_page_list[16]; __u64 capabilities = 0; + __u32 device_id, read_vendor_id; struct config { uint8_t interval; @@ -7162,7 +8092,7 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, OPT_ARGS(opts) = { OPT_UINT("interval", 'i', &cfg.interval, interval), - OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_BYTE("log-page-version", 'l', &cfg.log_page_version, log_page_version), OPT_LIST("log-page-mask", 'p', &cfg.log_page_mask, log_page_mask), OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), @@ -7174,12 +8104,12 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, return ret; r = nvme_scan(NULL); - if (cfg.log_page_version == 0) { + if (!cfg.log_page_version) { uuid_index = 0; } else if (cfg.log_page_version == 1) { uuid_index = 1; } else { - fprintf(stderr, "ERROR : WDC: unsupported log page version for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported log page version for this command\n"); ret = -1; goto out; } @@ -7192,69 +8122,105 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command, goto out; } - if (num == 0) - { + if (!num) { page_mask |= WDC_ALL_PAGE_MASK; - } - else - { - for (i = 0; i < num; i++) - { - if (log_page_list[i] == 0xc0) { + } else { + for (i = 0; i < num; i++) { + if (log_page_list[i] == 0xc0) page_mask |= WDC_C0_PAGE_MASK; - } - if (log_page_list[i] == 0xc1) { + if (log_page_list[i] == 0xc1) page_mask |= WDC_C1_PAGE_MASK; - } - if (log_page_list[i] == 0xca) { + if (log_page_list[i] == 0xca) page_mask |= WDC_CA_PAGE_MASK; - } - if (log_page_list[i] == 0xd0) { + if (log_page_list[i] == 0xd0) page_mask |= WDC_D0_PAGE_MASK; - } } } - if (page_mask == 0) - fprintf(stderr, "ERROR : WDC: Unknown log page mask - %s\n", cfg.log_page_mask); + if (!page_mask) + fprintf(stderr, "ERROR: WDC: Unknown log page mask - %s\n", cfg.log_page_mask); - capabilities = wdc_get_drive_capabilities(r, dev); + ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); - if ((capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + capabilities = wdc_get_drive_capabilities(r, dev); + if (!(capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } if (((capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE) == WDC_DRIVE_CAP_C0_LOG_PAGE) && - (page_mask & WDC_C0_PAGE_MASK)) { + (page_mask & WDC_C0_PAGE_MASK)) { /* Get 0xC0 log page if possible. */ - ret = wdc_get_c0_log_page(r, dev, cfg.output_format, - uuid_index, cfg.namespace_id); - if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the C0 Log Page, ret = %d\n", ret); + if (!wdc_is_sn861(device_id)) { + ret = wdc_get_c0_log_page(r, dev, cfg.output_format, + uuid_index, cfg.namespace_id); + if (ret) + fprintf(stderr, + "ERROR: WDC: Failure reading the C0 Log Page, ret = %d\n", + ret); + } else { + struct ocp_cloud_smart_log log; + char buf[2 * sizeof(log.log_page_guid) + 3]; + + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "Invalid output format: %s\n", cfg.output_format); + goto out; + } + + ret = nvme_get_log_simple(dev_fd(dev), + WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID, + sizeof(log), &log); + if (!ret) { + char *ptr = buf; + int i; + __u8 *guid = log.log_page_guid; + + memset(buf, 0, sizeof(char) * 19); + + ptr += sprintf(ptr, "0x"); + for (i = 0; i < 16; i++) + ptr += sprintf(ptr, "%x", guid[15 - i]); + if (strcmp(buf, "0xafd514c97c6f4f9ca4f2bfea2810afc5")) + fprintf(stderr, "Invalid GUID: %s\n", buf); + else { + if (fmt == BINARY) + d_raw((unsigned char *)&log, sizeof(log)); + else if (fmt == JSON) + show_cloud_smart_log_json(&log); + else + show_cloud_smart_log_normal(&log, dev); + } + } else if (ret > 0) { + nvme_show_status(ret); + } else { + perror("vs-smart-add-log"); + } + } } - if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) && - (page_mask & WDC_CA_PAGE_MASK)) { + if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) && + (page_mask & WDC_CA_PAGE_MASK) && + (!wdc_is_sn861(device_id))) { /* Get the CA Log Page */ ret = wdc_get_ca_log_page(r, dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the CA Log Page, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the CA Log Page, ret = %d\n", ret); } if (((capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE) == WDC_DRIVE_CAP_C1_LOG_PAGE) && - (page_mask & WDC_C1_PAGE_MASK)) { + (page_mask & WDC_C1_PAGE_MASK)) { /* Get the C1 Log Page */ ret = wdc_get_c1_log_page(r, dev, cfg.output_format, cfg.interval); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the C1 Log Page, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the C1 Log Page, ret = %d\n", ret); } if (((capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE) == WDC_DRIVE_CAP_D0_LOG_PAGE) && - (page_mask & WDC_D0_PAGE_MASK)) { + (page_mask & WDC_D0_PAGE_MASK)) { /* Get the D0 Log Page */ ret = wdc_get_d0_log_page(r, dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the D0 Log Page, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the D0 Log Page, ret = %d\n", ret); } out: @@ -7268,10 +8234,11 @@ static int wdc_vs_cloud_log(int argc, char **argv, struct command *command, { const char *desc = "Retrieve Cloud Log Smart/Health Information"; const char *namespace_id = "desired namespace id"; + enum nvme_print_flags fmt; __u64 capabilities = 0; struct nvme_dev *dev; - int ret, fmt = -1; nvme_root_t r; + int ret; __u8 *data; struct config { @@ -7298,8 +8265,8 @@ static int wdc_vs_cloud_log(int argc, char **argv, struct command *command, capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -7311,17 +8278,16 @@ static int wdc_vs_cloud_log(int argc, char **argv, struct command *command, if (strcmp(cfg.output_format, "json")) nvme_show_status(ret); - if (ret == 0) { - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__); - ret = fmt; + if (!ret) { + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__); + } else { + /* parse the data */ + wdc_print_ext_smart_cloud_log(data, fmt); } - - /* parse the data */ - wdc_print_ext_smart_cloud_log(data, fmt); } else { - fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page V1 data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page V1 data\n"); ret = -1; } @@ -7339,9 +8305,10 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command, { const char *desc = "Retrieve Hardware Revision Log Information"; const char *namespace_id = "desired namespace id"; + enum nvme_print_flags fmt; __u64 capabilities = 0; struct nvme_dev *dev; - int ret, fmt = -1; + int ret; __u8 *data = NULL; nvme_root_t r; @@ -7369,8 +8336,8 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command, capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -7380,16 +8347,15 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command, if (strcmp(cfg.output_format, "json")) nvme_show_status(ret); - if (ret == 0) { - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__); - ret = fmt; + if (!ret) { + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__); goto free_buf; } if (!data) { - fprintf(stderr, "ERROR : WDC : Invalid buffer to read Hardware Revision log\n"); + fprintf(stderr, "ERROR: WDC: Invalid buffer to read Hardware Revision log\n"); ret = -1; goto out; } @@ -7400,9 +8366,11 @@ static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command, case JSON: wdc_print_hw_rev_log_json(data); break; + default: + break; } } else { - fprintf(stderr, "ERROR : WDC : Unable to read Hardware Revision Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read Hardware Revision Log Page data\n"); ret = -1; } @@ -7422,13 +8390,13 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command, const char *desc = "Retrieve Device Write Amplication Factor"; const char *namespace_id = "desired namespace id"; struct nvme_smart_log smart_log; + enum nvme_print_flags fmt; struct nvme_dev *dev; __u8 *data; nvme_root_t r; int ret = 0; - int fmt = -1; __u64 capabilities = 0; - wdc_nvme_ext_smart_log *ext_smart_log_ptr; + struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr; long double data_units_written = 0, phys_media_units_written_tlc = 0, phys_media_units_written_slc = 0; @@ -7460,8 +8428,8 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command, capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_DEVICE_WAF) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_DEVICE_WAF)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -7471,8 +8439,7 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command, &smart_log); if (!ret) { data_units_written = int128_to_double(smart_log.data_units_written); - } - else if (ret > 0) { + } else if (ret > 0) { nvme_show_status(ret); ret = -1; goto out; @@ -7487,15 +8454,15 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command, ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0, cfg.namespace_id); - if (ret == 0) { - ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + if (!ret) { + ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data; phys_media_units_written_tlc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt); phys_media_units_written_slc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuws); if (data) free(data); } else { - fprintf(stderr, "ERROR : WDC %s: get smart cloud log failure\n", __func__); + fprintf(stderr, "ERROR: WDC %s: get smart cloud log failure\n", __func__); ret = -1; goto out; } @@ -7503,15 +8470,14 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command, if (strcmp(cfg.output_format, "json")) nvme_show_status(ret); - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC %s: invalid output format\n", __func__); - ret = fmt; + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__); goto out; } - if (data_units_written == 0) { - fprintf(stderr, "ERROR : WDC %s: 0 data units written\n", __func__); + if (!data_units_written) { + fprintf(stderr, "ERROR: WDC %s: 0 data units written\n", __func__); ret = -1; goto out; } @@ -7521,11 +8487,10 @@ static int wdc_vs_device_waf(int argc, char **argv, struct command *command, (phys_media_units_written_tlc/data_units_written)); printf("Device Write Amplification Factor SLC : %4.2Lf\n", (phys_media_units_written_slc/data_units_written)); - } - else if (fmt == JSON) { - root = json_create_object(); - sprintf(tlc_waf_str, "%4.2Lf", (phys_media_units_written_tlc/data_units_written)); - sprintf(slc_waf_str, "%4.2Lf", (phys_media_units_written_slc/data_units_written)); + } else if (fmt == JSON) { + root = json_create_object(); + sprintf(tlc_waf_str, "%4.2Lf", (phys_media_units_written_tlc/data_units_written)); + sprintf(slc_waf_str, "%4.2Lf", (phys_media_units_written_slc/data_units_written)); json_object_add_value_string(root, "Device Write Amplification Factor TLC", tlc_waf_str); json_object_add_value_string(root, "Device Write Amplification Factor SLC", slc_waf_str); @@ -7571,15 +8536,15 @@ static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *co r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } ret = wdc_get_c3_log_page(r, dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the Latency Monitor (C3) Log Page, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the Latency Monitor (C3) Log Page, ret = %d\n", ret); out: nvme_free_tree(r); @@ -7616,15 +8581,15 @@ static int wdc_get_error_recovery_log(int argc, char **argv, struct command *com r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } ret = wdc_get_ocp_c1_log_page(r, dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the Error Recovery (C1) Log Page, ret = 0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the Error Recovery (C1) Log Page, ret = 0x%x\n", ret); out: nvme_free_tree(r); @@ -7661,15 +8626,15 @@ static int wdc_get_dev_capabilities_log(int argc, char **argv, struct command *c r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } ret = wdc_get_ocp_c4_log_page(r, dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the Device Capabilities (C4) Log Page, ret = 0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the Device Capabilities (C4) Log Page, ret = 0x%x\n", ret); out: nvme_free_tree(r); @@ -7706,15 +8671,15 @@ static int wdc_get_unsupported_reqs_log(int argc, char **argv, struct command *c r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } ret = wdc_get_ocp_c5_log_page(r, dev, cfg.output_format); if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the Unsupported Requirements (C5) Log Page, ret = 0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the Unsupported Requirements (C5) Log Page, ret = 0x%x\n", ret); out: nvme_free_tree(r); @@ -7727,7 +8692,7 @@ static int wdc_do_clear_pcie_correctable_errors(int fd) int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (admin_cmd)); + 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); @@ -7742,7 +8707,7 @@ static int wdc_do_clear_pcie_correctable_errors_vuc(int fd) int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (admin_cmd)); + memset(&admin_cmd, 0, sizeof(admin_cmd)); admin_cmd.opcode = WDC_NVME_CLEAR_PCIE_CORR_OPCODE_VUC; ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL); @@ -7787,21 +8752,18 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma } capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } - - if (capabilities & WDC_DRIVE_CAP_CLEAR_PCIE) { + + if (capabilities & WDC_DRIVE_CAP_CLEAR_PCIE) ret = wdc_do_clear_pcie_correctable_errors(dev_fd(dev)); - } - else if (capabilities & WDC_DRIVE_CAP_VUC_CLEAR_PCIE) { + else if (capabilities & WDC_DRIVE_CAP_VUC_CLEAR_PCIE) ret = wdc_do_clear_pcie_correctable_errors_vuc(dev_fd(dev)); - } - else { + else ret = wdc_do_clear_pcie_correctable_errors_fid(dev_fd(dev)); - } out: nvme_free_tree(r); @@ -7835,15 +8797,15 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_DRIVE_STATUS) != WDC_DRIVE_CAP_DRIVE_STATUS) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } /* verify the 0xC2 Device Manageability log page is supported */ if (wdc_nvme_check_supported_log_page(r, dev, - WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == false) { - fprintf(stderr, "ERROR : WDC : 0xC2 Log Page not supported\n"); + WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID) == false) { + fprintf(stderr, "ERROR: WDC: 0xC2 Log Page not supported\n"); ret = -1; goto out; } @@ -7851,51 +8813,52 @@ static int wdc_drive_status(int argc, char **argv, struct command *command, /* Get the assert dump present status */ if (!wdc_nvme_get_dev_status_log_data(r, dev, &assert_status, WDC_C2_ASSERT_DUMP_PRESENT_ID)) - fprintf(stderr, "ERROR : WDC : Get Assert Status Failed\n"); + fprintf(stderr, "ERROR: WDC: Get Assert Status Failed\n"); /* Get the thermal throttling status */ if (!wdc_nvme_get_dev_status_log_data(r, dev, &thermal_status, WDC_C2_THERMAL_THROTTLE_STATUS_ID)) - fprintf(stderr, "ERROR : WDC : Get Thermal Throttling Status Failed\n"); + fprintf(stderr, "ERROR: WDC: Get Thermal Throttling Status Failed\n"); /* Get EOL status */ if (!wdc_nvme_get_dev_status_log_data(r, dev, &eol_status, WDC_C2_USER_EOL_STATUS_ID)) { - fprintf(stderr, "ERROR : WDC : Get User EOL Status Failed\n"); + fprintf(stderr, "ERROR: WDC: Get User EOL Status Failed\n"); eol_status = cpu_to_le32(-1); } /* Get Customer EOL state */ if (!wdc_nvme_get_dev_status_log_data(r, dev, &user_eol_state, WDC_C2_USER_EOL_STATE_ID)) - fprintf(stderr, "ERROR : WDC : Get User EOL State Failed\n"); + fprintf(stderr, "ERROR: WDC: Get User EOL State Failed\n"); /* Get System EOL state*/ if (!wdc_nvme_get_dev_status_log_data(r, dev, &system_eol_state, WDC_C2_SYSTEM_EOL_STATE_ID)) - fprintf(stderr, "ERROR : WDC : Get System EOL State Failed\n"); + fprintf(stderr, "ERROR: WDC: Get System EOL State Failed\n"); /* Get format corrupt reason*/ if (!wdc_nvme_get_dev_status_log_data(r, dev, &format_corrupt_reason, WDC_C2_FORMAT_CORRUPT_REASON_ID)) - fprintf(stderr, "ERROR : WDC : Get Format Corrupt Reason Failed\n"); + fprintf(stderr, "ERROR: WDC: Get Format Corrupt Reason Failed\n"); - printf(" Drive Status :- \n"); - if ((int)le32_to_cpu(eol_status) >= 0) { + printf(" Drive Status :-\n"); + if ((int)le32_to_cpu(eol_status) >= 0) printf(" Percent Used: %"PRIu32"%%\n", - le32_to_cpu(eol_status)); - } + 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 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)); + 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"); @@ -7950,20 +8913,20 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_CLEAR_ASSERT) != WDC_DRIVE_CAP_CLEAR_ASSERT) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } if (!wdc_nvme_get_dev_status_log_data(r, dev, &assert_status, WDC_C2_ASSERT_DUMP_PRESENT_ID)) { - fprintf(stderr, "ERROR : WDC : Get Assert Status Failed\n"); + 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)); + 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); @@ -7972,7 +8935,7 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, NULL); nvme_show_status(ret); } else - fprintf(stderr, "INFO : WDC : No Assert Dump Present\n"); + fprintf(stderr, "INFO: WDC: No Assert Dump Present\n"); out: nvme_free_tree(r); @@ -7983,32 +8946,34 @@ static int wdc_clear_assert_dump(int argc, char **argv, struct command *command, static int wdc_get_fw_act_history(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; - __u8 *data; struct wdc_fw_act_history_log_hdr *fw_act_history_hdr; + enum nvme_print_flags fmt; + int ret; + __u8 *data; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } /* verify the FW Activate History log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == false) { - fprintf(stderr, "ERROR : WDC : %d Log Page not supported\n", WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID); + if (!wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID)) { + fprintf(stderr, "ERROR: WDC: %d Log Page not supported\n", + WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID); return -1; } - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID, @@ -8017,22 +8982,25 @@ static int wdc_get_fw_act_history(nvme_root_t r, struct nvme_dev *dev, if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data); - if ((fw_act_history_hdr->num_entries > 0) && (fw_act_history_hdr->num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) - ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, fmt, 0, 0); - else if (fw_act_history_hdr->num_entries == 0) { - fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); + if ((fw_act_history_hdr->num_entries > 0) && + (fw_act_history_hdr->num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) { + ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, + fmt, 0, 0, 0); + } else if (!fw_act_history_hdr->num_entries) { + fprintf(stderr, "INFO: WDC: No FW Activate History entries found.\n"); ret = 0; - } - else { - fprintf(stderr, "ERROR : WDC : Invalid number entries found in FW Activate History Log Page - %d\n", fw_act_history_hdr->num_entries); + } else { + fprintf(stderr, + "ERROR: WDC: Invalid number entries found in FW Activate History Log Page - %d\n", + fw_act_history_hdr->num_entries); ret = -1; } } else { - fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read FW Activate History Log Page data\n"); ret = -1; } @@ -8046,11 +9014,11 @@ static __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev) __u32 cust_id = WDC_INVALID_CUSTOMER_ID; __u32 *cust_id_ptr = NULL; - if (!(get_dev_mgment_cbs_data(r, dev, WDC_C2_CUSTOMER_ID_ID, (void*)&cust_id_ptr))) { - fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); - } else { + if (!get_dev_mgment_cbs_data(r, dev, WDC_C2_CUSTOMER_ID_ID, (void *)&cust_id_ptr)) + fprintf(stderr, "%s: ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n", + __func__, WDC_C2_CUSTOMER_ID_ID); + else cust_id = *cust_id_ptr; - } free(cust_id_ptr); return cust_id; @@ -8059,31 +9027,32 @@ static __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev) static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev, char *format) { - int ret = 0; - int fmt = -1; - __u8 *data; - __u32 cust_id; struct wdc_fw_act_history_log_format_c2 *fw_act_history_log; __u32 tot_entries = 0, num_entries = 0; __u32 vendor_id = 0, device_id = 0; + __u32 cust_id = 0; + enum nvme_print_flags fmt; + __u8 *data; + int ret; if (!wdc_check_device(r, dev)) return -1; - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - return fmt; + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); + return ret; } ret = wdc_get_pci_ids(r, dev, &device_id, &vendor_id); - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + data = (__u8 *)malloc(sizeof(__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); return -1; } - memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN); + memset(data, 0, sizeof(__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN); ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID, @@ -8092,28 +9061,33 @@ static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev, if (strcmp(format, "json")) nvme_show_status(ret); - if (ret == 0) { + if (!ret) { /* parse the data */ - fw_act_history_log = (struct wdc_fw_act_history_log_format_c2*)(data); + fw_act_history_log = (struct wdc_fw_act_history_log_format_c2 *)(data); tot_entries = le32_to_cpu(fw_act_history_log->num_entries); if (tot_entries > 0) { /* get the FW customer id */ - cust_id = wdc_get_fw_cust_id(r, dev); - if (cust_id == WDC_INVALID_CUSTOMER_ID) { - fprintf(stderr, "%s: ERROR : WDC : invalid customer id\n", __func__); - ret = -1; - goto freeData; + if (!wdc_is_sn861(device_id)) { + cust_id = wdc_get_fw_cust_id(r, dev); + if (cust_id == WDC_INVALID_CUSTOMER_ID) { + fprintf(stderr, + "%s: ERROR: WDC: invalid customer id\n", + __func__); + ret = -1; + goto freeData; + } } num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ? tot_entries : WDC_MAX_NUM_ACT_HIST_ENTRIES; - ret = wdc_print_fw_act_history_log(data, num_entries, fmt, cust_id, vendor_id); + ret = wdc_print_fw_act_history_log(data, num_entries, + fmt, cust_id, vendor_id, device_id); } else { - fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); + fprintf(stderr, "INFO: WDC: No FW Activate History entries found.\n"); ret = 0; } } else { - fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read FW Activate History Log Page data\n"); ret = -1; } @@ -8150,8 +9124,8 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -8162,10 +9136,13 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com __u8 *data; int i; - /* check for the GUID in the 0xC0 log page to determine which log page to use to */ - /* to retrieve fw activate history data */ - if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) { - fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); + /* + * check for the GUID in the 0xC0 log page to determine which log page to use to + * retrieve fw activate history data + */ + data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN); + if (!data) { + fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno)); ret = -1; goto out; } @@ -8190,35 +9167,30 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com }; ret = nvme_get_log(&args); - if (ret == 0) { + if (!ret) { /* Verify GUID matches */ - for (i=0; i<16; i++) { - if (scao_guid[i] != data[SCAO_LPG + i]) { + for (i = 0; i < 16; i++) { + if (scao_guid[i] != data[SCAO_LPG + i]) { c0GuidMatch = false; break; } } - if (i == 16) { + if (i == 16) c0GuidMatch = true; - } } free(data); - if (c0GuidMatch) { - ret = wdc_get_fw_act_history_C2(r, dev, - cfg.output_format); - } - else { - ret = wdc_get_fw_act_history(r, dev, - cfg.output_format); - } + if (c0GuidMatch) + ret = wdc_get_fw_act_history_C2(r, dev, cfg.output_format); + else + ret = wdc_get_fw_act_history(r, dev, cfg.output_format); } else { ret = wdc_get_fw_act_history_C2(r, dev, cfg.output_format); } if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading the FW Activate History, ret = %d\n", ret); out: nvme_free_tree(r); dev_close(dev); @@ -8230,7 +9202,7 @@ static int wdc_do_clear_fw_activate_history_vuc(int fd) int ret = -1; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (admin_cmd)); + 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); @@ -8273,8 +9245,8 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command * r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -8330,7 +9302,7 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG) != WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -8338,7 +9310,7 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm /* allow only one option at a time */ if ((cfg.disable + cfg.enable + cfg.status) > 1) { - fprintf(stderr, "ERROR : WDC : Invalid option\n"); + fprintf(stderr, "ERROR: WDC: Invalid option\n"); ret = -1; goto out; } @@ -8349,18 +9321,16 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm 0, 1, false, &result); wdc_clear_reason_id(dev); - } - else { - if (cfg.enable) { + } else { + if (cfg.enable) { ret = nvme_set_features_simple(dev_fd(dev), WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, false, &result); - } - else if (cfg.status) { + } else if (cfg.status) { ret = nvme_get_features_simple(dev_fd(dev), WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, &result); - if (ret == 0) { + if (!ret) { if (result) fprintf(stderr, "Controller Option Telemetry Log Page State: Disabled\n"); else @@ -8368,14 +9338,12 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm } else { nvme_show_status(ret); } - } - else { - fprintf(stderr, "ERROR : WDC: unsupported option for this command\n"); + } 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: @@ -8391,14 +9359,13 @@ static int wdc_get_serial_and_fw_rev(struct nvme_dev *dev, char *sn, char *fw_re int ret; struct nvme_id_ctrl ctrl; - i = sizeof (ctrl.sn) - 1; + 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)); + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " - "0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret); return -1; } /* Remove trailing spaces from the name */ @@ -8419,10 +9386,10 @@ static int wdc_get_max_transfer_len(struct nvme_dev *dev, __u32 *maxTransferLen) __u32 maxTransferLenDevice = 0; - memset(&ctrl, 0, sizeof (struct nvme_id_ctrl)); + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed 0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret); return -1; } @@ -8432,57 +9399,53 @@ static int wdc_get_max_transfer_len(struct nvme_dev *dev, __u32 *maxTransferLen) return ret; } -static int wdc_de_VU_read_size(struct nvme_dev *dev, __u32 fileId, - __u16 spiDestn, __u32* logSize) +static int wdc_de_VU_read_size(struct nvme_dev *dev, __u32 fileId, __u16 spiDestn, __u32 *logSize) { int ret = WDC_STATUS_FAILURE; struct nvme_passthru_cmd cmd; - if(!dev || !logSize ) - { + if (!dev || !logSize) { ret = WDC_STATUS_INVALID_PARAMETER; goto end; } - memset(&cmd,0,sizeof(struct nvme_passthru_cmd)); + memset(&cmd, 0, sizeof(struct nvme_passthru_cmd)); cmd.opcode = WDC_DE_VU_READ_SIZE_OPCODE; cmd.nsid = WDC_DE_DEFAULT_NAMESPACE_ID; - cmd.cdw13 = fileId<<16; + cmd.cdw13 = fileId << 16; cmd.cdw14 = spiDestn; ret = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); if (!ret && logSize) *logSize = cmd.result; - if( ret != WDC_STATUS_SUCCESS) { - fprintf(stderr, "ERROR : WDC : VUReadSize() failed, "); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR: WDC: VUReadSize() failed, "); nvme_show_status(ret); } - end: +end: return ret; } -static int wdc_de_VU_read_buffer(struct nvme_dev *dev, __u32 fileId, - __u16 spiDestn, __u32 offsetInDwords, - __u8* dataBuffer, __u32* bufferSize) +static int wdc_de_VU_read_buffer(struct nvme_dev *dev, __u32 fileId, __u16 spiDestn, + __u32 offsetInDwords, __u8 *dataBuffer, __u32 *bufferSize) { int ret = WDC_STATUS_FAILURE; struct nvme_passthru_cmd cmd; __u32 noOfDwordExpected = 0; - if(!dev || !dataBuffer || !bufferSize) - { + if (!dev || !dataBuffer || !bufferSize) { ret = WDC_STATUS_INVALID_PARAMETER; goto end; } - memset(&cmd,0,sizeof(struct nvme_passthru_cmd)); - noOfDwordExpected = *bufferSize/sizeof(__u32); + memset(&cmd, 0, sizeof(struct nvme_passthru_cmd)); + noOfDwordExpected = *bufferSize / sizeof(__u32); cmd.opcode = WDC_DE_VU_READ_BUFFER_OPCODE; cmd.nsid = WDC_DE_DEFAULT_NAMESPACE_ID; cmd.cdw10 = noOfDwordExpected; - cmd.cdw13 = fileId<<16; + cmd.cdw13 = fileId << 16; cmd.cdw14 = spiDestn; cmd.cdw15 = offsetInDwords; @@ -8491,92 +9454,92 @@ static int wdc_de_VU_read_buffer(struct nvme_dev *dev, __u32 fileId, ret = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL); - if( ret != WDC_STATUS_SUCCESS) { - fprintf(stderr, "ERROR : WDC : VUReadBuffer() failed, "); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR: WDC: VUReadBuffer() failed, "); nvme_show_status(ret); } - end: +end: return ret; } -static int wdc_get_log_dir_max_entries(struct nvme_dev *dev, __u32* maxNumOfEntries) +static int wdc_get_log_dir_max_entries(struct nvme_dev *dev, __u32 *maxNumOfEntries) { - int ret = WDC_STATUS_FAILURE; - __u32 headerPayloadSize = 0; - __u8* fileIdOffsetsBuffer = NULL; - __u32 fileIdOffsetsBufferSize = 0; - __u32 fileNum = 0; - __u16 fileOffset = 0; + int ret = WDC_STATUS_FAILURE; + __u32 headerPayloadSize = 0; + __u8 *fileIdOffsetsBuffer = NULL; + __u32 fileIdOffsetsBufferSize = 0; + __u32 fileNum = 0; + __u16 fileOffset = 0; - if (!dev || !maxNumOfEntries) - { + if (!dev || !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(dev, 0, 5, (__u32*)&headerPayloadSize))) - { - fprintf(stderr, "ERROR : WDC : %s: Failed to get headerPayloadSize from file directory 0x%x\n", - __func__, ret); + ret = wdc_de_VU_read_size(dev, 0, 5, (__u32 *)&headerPayloadSize); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, + "ERROR: WDC: %s: Failed to get headerPayloadSize from file directory 0x%x\n", + __func__, ret); return ret; } - fileIdOffsetsBufferSize = WDC_DE_FILE_HEADER_SIZE + (headerPayloadSize * WDC_DE_FILE_OFFSET_SIZE); - fileIdOffsetsBuffer = (__u8*)calloc(1, fileIdOffsetsBufferSize); + 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(dev, 0, 5, 0, fileIdOffsetsBuffer, &fileIdOffsetsBufferSize))) - { - fprintf(stderr, "ERROR : WDC : %s: Failed to get fileIdOffsets from file directory 0x%x\n", - __func__, ret); + ret = wdc_de_VU_read_buffer(dev, 0, 5, 0, fileIdOffsetsBuffer, &fileIdOffsetsBufferSize); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, + "ERROR: WDC: %s: Failed to get fileIdOffsets from file directory 0x%x\n", + __func__, ret); goto end; } /* 3.Determine valid entries */ - for (fileNum = 0; fileNum < (headerPayloadSize - WDC_DE_FILE_HEADER_SIZE) / WDC_DE_FILE_OFFSET_SIZE; fileNum++) - { - fileOffset = (fileIdOffsetsBuffer[WDC_DE_FILE_HEADER_SIZE + (fileNum * WDC_DE_FILE_OFFSET_SIZE)] << 8) + - fileIdOffsetsBuffer[WDC_DE_FILE_HEADER_SIZE + (fileNum * WDC_DE_FILE_OFFSET_SIZE) + 1]; + for (fileNum = 0; + fileNum < (headerPayloadSize - WDC_DE_FILE_HEADER_SIZE) / WDC_DE_FILE_OFFSET_SIZE; + fileNum++) { + fileOffset = (fileIdOffsetsBuffer[WDC_DE_FILE_HEADER_SIZE + + (fileNum * WDC_DE_FILE_OFFSET_SIZE)] << 8) + + fileIdOffsetsBuffer[WDC_DE_FILE_HEADER_SIZE + + (fileNum * WDC_DE_FILE_OFFSET_SIZE) + 1]; if (!fileOffset) continue; (*maxNumOfEntries)++; } + end: free(fileIdOffsetsBuffer); return ret; } -static WDC_DRIVE_ESSENTIAL_TYPE wdc_get_essential_type(__u8 fileName[]) +static enum WDC_DRIVE_ESSENTIAL_TYPE wdc_get_essential_type(__u8 fileName[]) { - WDC_DRIVE_ESSENTIAL_TYPE essentialType = WDC_DE_TYPE_NONE; + enum WDC_DRIVE_ESSENTIAL_TYPE essentialType = WDC_DE_TYPE_NONE; - if (wdc_UtilsStrCompare((char*)fileName, WDC_DE_CORE_DUMP_FILE_NAME) == 0) - { + if (!wdc_UtilsStrCompare((char *)fileName, WDC_DE_CORE_DUMP_FILE_NAME)) essentialType = WDC_DE_TYPE_DUMPSNAPSHOT; - } - else if (wdc_UtilsStrCompare((char*)fileName, WDC_DE_EVENT_LOG_FILE_NAME) == 0) - { + else if (!wdc_UtilsStrCompare((char *)fileName, WDC_DE_EVENT_LOG_FILE_NAME)) essentialType = WDC_DE_TYPE_EVENTLOG; - } - else if (wdc_UtilsStrCompare((char*)fileName, WDC_DE_MANUFACTURING_INFO_PAGE_FILE_NAME) == 0) - { + else if (!wdc_UtilsStrCompare((char *)fileName, WDC_DE_MANUFACTURING_INFO_PAGE_FILE_NAME)) essentialType = WDC_DE_TYPE_NVME_MANF_INFO; - } return essentialType; } -static int wdc_fetch_log_directory(struct nvme_dev *dev, PWDC_DE_VU_LOG_DIRECTORY directory) +static int wdc_fetch_log_directory(struct nvme_dev *dev, struct WDC_DE_VU_LOG_DIRECTORY *directory) { - int ret = WDC_STATUS_FAILURE; - __u8 *fileOffset = NULL; - __u8 *fileDirectory = NULL; - __u32 headerSize = 0; - __u32 fileNum = 0, startIdx = 0; - __u16 fileOffsetTemp = 0; - __u32 entryId = 0; - __u32 fileDirectorySize = 0; + int ret = WDC_STATUS_FAILURE; + __u8 *fileOffset = NULL; + __u8 *fileDirectory = NULL; + __u32 headerSize = 0; + __u32 fileNum = 0, startIdx = 0; + __u16 fileOffsetTemp = 0; + __u32 entryId = 0; + __u32 fileDirectorySize = 0; if (!dev || !directory) { ret = WDC_STATUS_INVALID_PARAMETER; @@ -8584,18 +9547,17 @@ static int wdc_fetch_log_directory(struct nvme_dev *dev, PWDC_DE_VU_LOG_DIRECTOR } ret = wdc_de_VU_read_size(dev, 0, 5, &fileDirectorySize); - if (WDC_STATUS_SUCCESS != ret) { + if (ret != WDC_STATUS_SUCCESS) { fprintf(stderr, - "ERROR : WDC : %s: Failed to get filesystem directory size, ret = %d\n", + "ERROR: WDC: %s: Failed to get filesystem directory size, ret = %d\n", __func__, ret); goto end; } - fileDirectory = (__u8*)calloc(1, fileDirectorySize); + fileDirectory = (__u8 *)calloc(1, fileDirectorySize); ret = wdc_de_VU_read_buffer(dev, 0, 5, 0, fileDirectory, &fileDirectorySize); - if (WDC_STATUS_SUCCESS != ret) { - fprintf(stderr, - "ERROR : WDC : %s: Failed to get filesystem directory, ret = %d\n", + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR: WDC: %s: Failed to get filesystem directory, ret = %d\n", __func__, ret); goto end; } @@ -8604,7 +9566,7 @@ static int wdc_fetch_log_directory(struct nvme_dev *dev, PWDC_DE_VU_LOG_DIRECTOR memcpy(&headerSize, fileDirectory, WDC_DE_FILE_HEADER_SIZE); /* minimum buffer for 1 entry is required */ - if (directory->maxNumLogEntries == 0) { + if (!directory->maxNumLogEntries) { ret = WDC_STATUS_INVALID_PARAMETER; goto end; } @@ -8619,34 +9581,31 @@ static int wdc_fetch_log_directory(struct nvme_dev *dev, PWDC_DE_VU_LOG_DIRECTOR memcpy(&fileOffsetTemp, fileDirectory + startIdx, sizeof(fileOffsetTemp)); fileOffset = fileDirectory + fileOffsetTemp; - if (0 == fileOffsetTemp) + if (!fileOffsetTemp) continue; - memset(&directory->logEntry[entryId], 0, sizeof(WDC_DRIVE_ESSENTIALS)); - memcpy(&directory->logEntry[entryId].metaData, fileOffset, sizeof(WDC_DE_VU_FILE_META_DATA)); + memset(&directory->logEntry[entryId], 0, sizeof(struct WDC_DRIVE_ESSENTIALS)); + memcpy(&directory->logEntry[entryId].metaData, fileOffset, sizeof(struct __packed WDC_DE_VU_FILE_META_DATA)); directory->logEntry[entryId].metaData.fileName[WDC_DE_FILE_NAME_SIZE - 1] = '\0'; - wdc_UtilsDeleteCharFromString((char*)directory->logEntry[entryId].metaData.fileName, + wdc_UtilsDeleteCharFromString((char *)directory->logEntry[entryId].metaData.fileName, WDC_DE_FILE_NAME_SIZE, ' '); - if (0 == directory->logEntry[entryId].metaData.fileID) + if (!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) + if (fileDirectory) free(fileDirectory); return ret; } static int wdc_fetch_log_file_from_device(struct nvme_dev *dev, __u32 fileId, - __u16 spiDestn, __u64 fileSize, __u8* dataBuffer) + __u16 spiDestn, __u64 fileSize, __u8 *dataBuffer) { int ret = WDC_STATUS_FAILURE; __u32 chunckSize = WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET; @@ -8654,8 +9613,7 @@ static int wdc_fetch_log_file_from_device(struct nvme_dev *dev, __u32 fileId, __u32 buffSize = 0; __u64 offsetIdx = 0; - if (!dev || !dataBuffer || !fileSize) - { + if (!dev || !dataBuffer || !fileSize) { ret = WDC_STATUS_INVALID_PARAMETER; goto end; } @@ -8666,43 +9624,40 @@ static int wdc_fetch_log_file_from_device(struct nvme_dev *dev, __u32 fileId, } /* Fetch Log File Data */ - if ((fileSize >= maximumTransferLength) || (fileSize > 0xFFFFFFFF)) - { + 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++) - { + for (offsetIdx = 0; (offsetIdx * chunckSize) < fileSize; offsetIdx++) { if (((offsetIdx * chunckSize) + buffSize) > fileSize) buffSize = (__u32)(fileSize - (offsetIdx * chunckSize)); /* Limitation in VU read buffer - offsetIdx and bufferSize are not greater than u32 */ ret = wdc_de_VU_read_buffer(dev, fileId, spiDestn, (__u32)((offsetIdx * chunckSize) / sizeof(__u32)), dataBuffer + (offsetIdx * chunckSize), &buffSize); - if (ret != WDC_STATUS_SUCCESS) - { - fprintf(stderr, "ERROR : WDC : %s: wdc_de_VU_read_buffer failed with ret = %d, fileId = 0x%x, fileSize = 0x%lx\n", - __func__, ret, fileId, (long unsigned int)fileSize); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR: WDC: %s: wdc_de_VU_read_buffer failed with ret = %d, fileId = 0x%x, fileSize = 0x%lx\n", + __func__, ret, fileId, (unsigned long)fileSize); break; } } } else { buffSize = (__u32)fileSize; ret = wdc_de_VU_read_buffer(dev, fileId, spiDestn, - (__u32)((offsetIdx * chunckSize) / sizeof(__u32)), dataBuffer, &buffSize); - if (ret != WDC_STATUS_SUCCESS) - { - fprintf(stderr, "ERROR : WDC : %s: wdc_de_VU_read_buffer failed with ret = %d, fileId = 0x%x, fileSize = 0x%lx\n", - __func__, ret, fileId, (long unsigned int)fileSize); + (__u32)((offsetIdx * chunckSize) / sizeof(__u32)), + dataBuffer, &buffSize); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "ERROR: WDC: %s: wdc_de_VU_read_buffer failed with ret = %d, fileId = 0x%x, fileSize = 0x%lx\n", + __func__, ret, fileId, (unsigned long)fileSize); } } - end: +end: return ret; } -static int wdc_de_get_dump_trace(struct nvme_dev *dev, char * filePath, __u16 binFileNameLen, char *binFileName) +static int wdc_de_get_dump_trace(struct nvme_dev *dev, char *filePath, __u16 binFileNameLen, char *binFileName) { int ret = WDC_STATUS_FAILURE; __u8 *readBuffer = NULL; @@ -8717,8 +9672,7 @@ static int wdc_de_get_dump_trace(struct nvme_dev *dev, char * filePath, __u16 bi __u16 i = 0; __u32 maximumTransferLength = 0; - if (!dev || !binFileName || !filePath) - { + if (!dev || !binFileName || !filePath) { ret = WDC_STATUS_INVALID_PARAMETER; return ret; } @@ -8726,22 +9680,19 @@ static int wdc_de_get_dump_trace(struct nvme_dev *dev, char * filePath, __u16 bi if (wdc_get_max_transfer_len(dev, &maximumTransferLength) < 0) return WDC_STATUS_FAILURE; - do - { + do { /* Get dumptrace size */ ret = wdc_de_VU_read_size(dev, 0, WDC_DE_DUMPTRACE_DESTINATION, &dumptraceSize); - if (ret != WDC_STATUS_SUCCESS) - { - fprintf(stderr, "ERROR : WDC : %s: wdc_de_VU_read_size failed with ret = %d\n", + 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) - { + 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", + 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; } @@ -8761,47 +9712,120 @@ static int wdc_de_get_dump_trace(struct nvme_dev *dev, char * filePath, __u16 bi readBufferLen = chunkSize; lastPktReadBufferLen = (dumptraceSize % maxTransferLen) ? (dumptraceSize % maxTransferLen) : chunkSize; - if (readBuffer == NULL) - { - fprintf(stderr, "ERROR : WDC : %s: readBuffer calloc failed\n", __func__); + if (!readBuffer) { + fprintf(stderr, "ERROR: WDC: %s: readBuffer calloc failed\n", __func__); ret = WDC_STATUS_INSUFFICIENT_MEMORY; break; } - for (i = 0; i < chunks; i++) - { + for (i = 0; i < chunks; i++) { offset = ((i*chunkSize) / 4); /* Last loop call, Assign readBufferLen to read only left over bytes */ if (i == (chunks - 1)) - { readBufferLen = lastPktReadBufferLen; - } - ret = wdc_de_VU_read_buffer(dev, 0, WDC_DE_DUMPTRACE_DESTINATION, 0, readBuffer + offset, &readBufferLen); - if (ret != WDC_STATUS_SUCCESS) - { - fprintf(stderr, "ERROR : WDC : %s: wdc_de_VU_read_buffer failed, ret = %d on offset 0x%x\n", - __func__, ret, offset); + ret = wdc_de_VU_read_buffer(dev, 0, WDC_DE_DUMPTRACE_DESTINATION, 0, + readBuffer + offset, &readBufferLen); + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, + "ERROR: WDC: %s: wdc_de_VU_read_buffer failed, ret = %d on offset 0x%x\n", + __func__, ret, offset); break; } } } while (loop); - if (ret == WDC_STATUS_SUCCESS) - { - ret = wdc_WriteToFile(binFileName, (char*)readBuffer, dumptraceSize); + if (ret == WDC_STATUS_SUCCESS) { + 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); + 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); + fprintf(stderr, "ERROR: WDC: %s: Read Buffer Loop failed, ret = %d\n", __func__, + ret); } if (readBuffer) - { free(readBuffer); + + return ret; +} + +int wdc_fetch_vu_file_directory(struct nvme_dev *dev, + struct WDC_DE_VU_LOG_DIRECTORY deEssentialsList, + __s8 *bufferFolderPath, __u8 *serialNo, __u8 *timeString) +{ + int ret = wdc_fetch_log_directory(dev, &deEssentialsList); + __u32 listIdx; + char *dataBuffer; + char fileName[MAX_PATH_LEN]; + + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "WDC: wdc_fetch_log_directory failed, ret = %d\n", ret); + return ret; + } + + /* Get Debug Data Files */ + for (listIdx = 0; listIdx < deEssentialsList.numOfValidLogEntries; listIdx++) { + if (!deEssentialsList.logEntry[listIdx].metaData.fileSize) { + fprintf(stderr, "ERROR: WDC: File Size for %s is 0\n", + deEssentialsList.logEntry[listIdx].metaData.fileName); + ret = WDC_STATUS_FILE_SIZE_ZERO; + } else { + /* Fetch Log File Data */ + dataBuffer = (char *)calloc(1, (size_t)deEssentialsList.logEntry[listIdx].metaData.fileSize); + ret = wdc_fetch_log_file_from_device(dev, + deEssentialsList.logEntry[listIdx].metaData.fileID, + WDC_DE_DESTN_SPI, + deEssentialsList.logEntry[listIdx].metaData.fileSize, + (__u8 *)dataBuffer); + + /* Write databuffer to file */ + if (ret == WDC_STATUS_SUCCESS) { + memset(fileName, 0, sizeof(fileName)); + wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", bufferFolderPath, WDC_DE_PATH_SEPARATOR, + deEssentialsList.logEntry[listIdx].metaData.fileName, serialNo, timeString); + if (deEssentialsList.logEntry[listIdx].metaData.fileSize > 0xFFFFFFFF) { + wdc_WriteToFile(fileName, dataBuffer, 0xFFFFFFFF); + wdc_WriteToFile(fileName, dataBuffer + 0xFFFFFFFF, (__u32)(deEssentialsList.logEntry[listIdx].metaData.fileSize - 0xFFFFFFFF)); + } else { + wdc_WriteToFile(fileName, dataBuffer, (__u32)deEssentialsList.logEntry[listIdx].metaData.fileSize); + } + } else { + fprintf(stderr, "ERROR: WDC: wdc_fetch_log_file_from_device: %s failed, ret = %d\n", + deEssentialsList.logEntry[listIdx].metaData.fileName, ret); + } + free(dataBuffer); + } + } + + return ret; +} + +int wdc_read_debug_directory(struct nvme_dev *dev, __s8 *bufferFolderPath, __u8 *serialNo, + __u8 *timeString) +{ + __u32 maxNumOfVUFiles = 0; + int ret = wdc_get_log_dir_max_entries(dev, &maxNumOfVUFiles); + struct WDC_DE_VU_LOG_DIRECTORY deEssentialsList; + + if (ret != WDC_STATUS_SUCCESS) { + fprintf(stderr, "WDC: wdc_get_log_dir_max_entries failed, ret = %d\n", ret); + return ret; } + memset(&deEssentialsList, 0, sizeof(deEssentialsList)); + deEssentialsList.logEntry = + (struct WDC_DRIVE_ESSENTIALS *)calloc(1, sizeof(struct WDC_DRIVE_ESSENTIALS) * maxNumOfVUFiles); + deEssentialsList.maxNumLogEntries = maxNumOfVUFiles; + + ret = wdc_fetch_vu_file_directory(dev, deEssentialsList, bufferFolderPath, serialNo, + timeString); + + free(deEssentialsList.logEntry); + deEssentialsList.logEntry = NULL; + return ret; } @@ -8810,113 +9834,110 @@ static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev, { 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; + char fileName[MAX_PATH_LEN]; + __s8 bufferFolderPath[MAX_PATH_LEN]; + char bufferFolderName[MAX_PATH_LEN]; + char tarFileName[MAX_PATH_LEN]; + char tarFiles[MAX_PATH_LEN]; + char tarCmd[MAX_PATH_LEN+MAX_PATH_LEN]; + UtilsTimeInfo timeInfo; + __u8 timeString[MAX_PATH_LEN]; + __u8 serialNo[WDC_SERIAL_NO_LEN]; + __u8 firmwareRevision[WDC_NVME_FIRMWARE_REV_LEN]; + __u8 idSerialNo[WDC_SERIAL_NO_LEN]; + __u8 idFwRev[WDC_NVME_FIRMWARE_REV_LEN]; + __u8 featureIdBuff[4]; + char currDir[MAX_PATH_LEN]; + char *dataBuffer = NULL; + __u32 elogNumEntries, elogBufferSize; + __u32 dataBufferSize; + __u32 listIdx = 0; + __u32 vuLogIdx = 0; + __u32 result; struct nvme_id_ctrl ctrl; struct nvme_id_ns ns; struct nvme_error_log_page *elogBuffer; struct nvme_smart_log smart_log; struct nvme_firmware_slot fw_log; - 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)); - - if (wdc_get_serial_and_fw_rev(dev, (char *)idSerialNo, (char *)idFwRev)) - { - fprintf(stderr, "ERROR : WDC : get serial # and fw revision failed\n"); + struct WDC_NVME_DE_VU_LOGPAGES *vuLogInput = NULL; + + memset(bufferFolderPath, 0, sizeof(bufferFolderPath)); + memset(bufferFolderName, 0, sizeof(bufferFolderName)); + memset(tarFileName, 0, sizeof(tarFileName)); + memset(tarFiles, 0, sizeof(tarFiles)); + memset(tarCmd, 0, sizeof(tarCmd)); + memset(&timeInfo, 0, sizeof(timeInfo)); + + if (wdc_get_serial_and_fw_rev(dev, (char *)idSerialNo, (char *)idFwRev)) { + fprintf(stderr, "ERROR: WDC: get serial # and fw revision failed\n"); return -1; - } else { - fprintf(stderr, "Get Drive Essentials Data for device serial #: %s and fw revision: %s\n", - idSerialNo, idFwRev); } - /* Create Drive Essentials directory */ + 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", + 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); + wdc_UtilsSnprintf((char *)serialNo, WDC_SERIAL_NO_LEN, (char *)idSerialNo); /* Remove any space form serialNo */ - wdc_UtilsDeleteCharFromString((char*)serialNo, WDC_SERIAL_NO_LEN, ' '); + wdc_UtilsDeleteCharFromString((char *)serialNo, WDC_SERIAL_NO_LEN, ' '); memset(firmwareRevision, 0, sizeof(firmwareRevision)); - wdc_UtilsSnprintf((char*)firmwareRevision, WDC_NVME_FIRMWARE_REV_LEN, (char*)idFwRev); + 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_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); + 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", + if (dir) { + wdc_UtilsSnprintf((char *)bufferFolderPath, MAX_PATH_LEN, "%s%s%s", (char *)dir, WDC_DE_PATH_SEPARATOR, (char *)bufferFolderName); } else { - retPtr = getcwd((char*)currDir, MAX_PATH_LEN); - if (retPtr != NULL) - wdc_UtilsSnprintf((char*)bufferFolderPath, MAX_PATH_LEN, "%s%s%s", + retPtr = getcwd((char *)currDir, MAX_PATH_LEN); + if (retPtr) { + wdc_UtilsSnprintf((char *)bufferFolderPath, MAX_PATH_LEN, "%s%s%s", (char *)currDir, WDC_DE_PATH_SEPARATOR, (char *)bufferFolderName); - else { - fprintf(stderr, "ERROR : WDC : get current working directory failed\n"); + } 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); + ret = wdc_UtilsCreateDir((char *)bufferFolderPath); + if (ret) { + 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); } + fprintf(stderr, "Store Drive Essentials bin files in directory: %s\n", bufferFolderPath); + /* Get Identify Controller Data */ - memset(&ctrl, 0, sizeof (struct nvme_id_ctrl)); + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed, ret = %d\n", 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)); + wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, + WDC_DE_PATH_SEPARATOR, "IdentifyController", (char *)serialNo, + (char *)timeString); + wdc_WriteToFile(fileName, (char *)&ctrl, sizeof(struct nvme_id_ctrl)); + + memset(&ns, 0, sizeof(struct nvme_id_ns)); ret = nvme_identify_ns(dev_fd(dev), 1, &ns); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ns() failed, ret = %d\n", ret); + 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)); + 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) */ @@ -8928,46 +9949,45 @@ static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev, ret = nvme_get_log_error(dev_fd(dev), elogNumEntries, false, elogBuffer); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_error_log() failed, ret = %d\n", ret); + 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); + 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)); + /* Get Smart log page */ + memset(&smart_log, 0, sizeof(struct nvme_smart_log)); ret = nvme_get_log_smart(dev_fd(dev), NVME_NSID_ALL, false, &smart_log); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_smart_log() failed, ret = %d\n", ret); + 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)); + wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR, + "SmartLog", (char *)serialNo, (char *)timeString); + wdc_WriteToFile(fileName, (char *)&smart_log, sizeof(struct nvme_smart_log)); } - /* Get FW Slot log page */ - memset(&fw_log, 0, sizeof (struct nvme_firmware_slot)); + /* Get FW Slot log page */ + memset(&fw_log, 0, sizeof(struct nvme_firmware_slot)); ret = nvme_get_log_fw_slot(dev_fd(dev), false, &fw_log); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_fw_log() failed, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_fw_log() failed, ret = %d\n", ret); } else { - wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char*)bufferFolderPath, WDC_DE_PATH_SEPARATOR, - "FwSLotLog", (char*)serialNo, (char*)timeString); - wdc_WriteToFile(fileName, (char*)&fw_log, sizeof(struct nvme_firmware_slot)); + wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR, + "FwSLotLog", (char *)serialNo, (char *)timeString); + wdc_WriteToFile(fileName, (char *)&fw_log, sizeof(struct nvme_firmware_slot)); } - /* Get VU log pages */ + /* 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]); + vuLogInput = (struct WDC_NVME_DE_VU_LOGPAGES *)calloc(1, sizeof(struct WDC_NVME_DE_VU_LOGPAGES)); + vuLogInput->numOfVULogPages = ARRAY_SIZE(deVULogPagesList); - for (vuLogIdx = 0; vuLogIdx < vuLogInput->numOfVULogPages; vuLogIdx++) - { + for (vuLogIdx = 0; vuLogIdx < vuLogInput->numOfVULogPages; vuLogIdx++) { dataBufferSize = deVULogPagesList[vuLogIdx].logPageLen; dataBuffer = calloc(1, dataBufferSize); memset(dataBuffer, 0, dataBufferSize); @@ -8976,13 +9996,13 @@ static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev, deVULogPagesList[vuLogIdx].logPageId, dataBufferSize, dataBuffer); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_get_log() for log page 0x%x failed, ret = %d\n", + 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); + 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); @@ -8992,108 +10012,52 @@ static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev, 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++) - { + for (listIdx = 1; listIdx < ARRAY_SIZE(deFeatureIdList); listIdx++) { memset(featureIdBuff, 0, sizeof(featureIdBuff)); /* skipping LbaRangeType as it is an optional nvme command and not supported */ if (deFeatureIdList[listIdx].featureId == FID_LBA_RANGE_TYPE) continue; ret = nvme_get_features_data(dev_fd(dev), - deFeatureIdList[listIdx].featureId, + (enum nvme_features_id)deFeatureIdList[listIdx].featureId, WDC_DE_GLOBAL_NSID, sizeof(featureIdBuff), &featureIdBuff, &result); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_get_feature id 0x%x failed, ret = %d\n", + 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, + 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(dev, &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(dev, &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(dev, deEssentialsList.logEntry[listIdx].metaData.fileID, WDC_DE_DESTN_SPI, deEssentialsList.logEntry[listIdx].metaData.fileSize, - (__u8 *)dataBuffer); - - /* Write databuffer to file */ - if (ret == WDC_STATUS_SUCCESS) - { - memset(fileName, 0, sizeof(fileName)); - wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", bufferFolderPath, WDC_DE_PATH_SEPARATOR, - deEssentialsList.logEntry[listIdx].metaData.fileName, serialNo, timeString); - if (deEssentialsList.logEntry[listIdx].metaData.fileSize > 0xFFFFFFFF) - { - wdc_WriteToFile(fileName, dataBuffer, 0xFFFFFFFF); - wdc_WriteToFile(fileName, dataBuffer + 0xFFFFFFFF, (__u32)(deEssentialsList.logEntry[listIdx].metaData.fileSize - 0xFFFFFFFF)); - } else { - wdc_WriteToFile(fileName, dataBuffer, (__u32)deEssentialsList.logEntry[listIdx].metaData.fileSize); - } - } else { - fprintf(stderr, "ERROR : WDC : wdc_fetch_log_file_from_device: %s failed, ret = %d\n", - deEssentialsList.logEntry[listIdx].metaData.fileName, ret); - } - free(dataBuffer); - dataBuffer = NULL; - } - } - } else { - fprintf(stderr, "WDC : wdc_fetch_log_directory failed, ret = %d\n", ret); + wdc_WriteToFile(fileName, (char *)featureIdBuff, sizeof(featureIdBuff)); } - - free(deEssentialsList.logEntry); - deEssentialsList.logEntry = NULL; - } else { - fprintf(stderr, "WDC : wdc_get_log_dir_max_entries failed, ret = %d\n", ret); } + ret = wdc_read_debug_directory(dev, bufferFolderPath, serialNo, timeString); + /* Get Dump Trace Data */ - wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char*)bufferFolderPath, WDC_DE_PATH_SEPARATOR, "dumptrace", serialNo, timeString); - if (WDC_STATUS_SUCCESS != (ret = wdc_de_get_dump_trace(dev, (char*)bufferFolderPath, 0, fileName))) - { - fprintf(stderr, "ERROR : WDC : wdc_de_get_dump_trace failed, ret = %d\n", ret); - } + wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR, "dumptrace", serialNo, timeString); + ret = wdc_de_get_dump_trace(dev, (char *)bufferFolderPath, 0, fileName); + if (ret != WDC_STATUS_SUCCESS) + fprintf(stderr, "ERROR: WDC: wdc_de_get_dump_trace failed, ret = %d\n", ret); /* Tar the Drive Essentials directory */ - wdc_UtilsSnprintf(tarFileName, sizeof(tarFileName), "%s%s", (char*)bufferFolderPath, WDC_DE_TAR_FILE_EXTN); - if (dir != 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); + wdc_UtilsSnprintf(tarFileName, sizeof(tarFileName), "%s%s", (char *)bufferFolderPath, WDC_DE_TAR_FILE_EXTN); + if (dir) + wdc_UtilsSnprintf(tarFiles, sizeof(tarFiles), "%s%s%s%s%s", (char *)dir, + WDC_DE_PATH_SEPARATOR, (char *)bufferFolderName, + WDC_DE_PATH_SEPARATOR, WDC_DE_TAR_FILES); + else + wdc_UtilsSnprintf(tarFiles, sizeof(tarFiles), "%s%s%s", (char *)bufferFolderName, + WDC_DE_PATH_SEPARATOR, WDC_DE_TAR_FILES); + wdc_UtilsSnprintf(tarCmd, sizeof(tarCmd), "%s %s %s", WDC_DE_TAR_CMD, (char *)tarFileName, (char *)tarFiles); ret = system(tarCmd); - if (ret) { - fprintf(stderr, "ERROR : WDC : Tar of Drive Essentials data failed, ret = %d\n", ret); - } + if (ret) + fprintf(stderr, "ERROR: WDC: Tar of Drive Essentials data failed, ret = %d\n", + ret); fprintf(stderr, "Get of Drive Essentials data successful\n"); nvme_free_tree(r); @@ -9134,12 +10098,12 @@ static int wdc_drive_essentials(int argc, char **argv, struct command *command, r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS) != WDC_DRIVE_CAP_DRIVE_ESSENTIALS) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } - if (cfg.dirName != NULL) { + if (cfg.dirName) { strncpy(d, cfg.dirName, PATH_MAX - 1); d_ptr = d; } else { @@ -9158,7 +10122,7 @@ static int wdc_do_drive_resize(struct nvme_dev *dev, uint64_t new_size) int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_DRIVE_RESIZE_OPCODE; admin_cmd.cdw12 = ((WDC_NVME_DRIVE_RESIZE_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_DRIVE_RESIZE_CMD); @@ -9173,7 +10137,7 @@ static int wdc_do_namespace_resize(struct nvme_dev *dev, __u32 nsid, __u32 op_op int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_NAMESPACE_RESIZE_OPCODE; admin_cmd.nsid = nsid; admin_cmd.cdw10 = op_option; @@ -9187,7 +10151,7 @@ static int wdc_do_drive_info(struct nvme_dev *dev, __u32 *result) int ret; struct nvme_passthru_cmd admin_cmd; - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_DRIVE_INFO_OPCODE; admin_cmd.cdw12 = ((WDC_NVME_DRIVE_INFO_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_DRIVE_INFO_CMD); @@ -9233,7 +10197,7 @@ static int wdc_drive_resize(int argc, char **argv, if ((capabilities & WDC_DRIVE_CAP_RESIZE) == WDC_DRIVE_CAP_RESIZE) { ret = wdc_do_drive_resize(dev, cfg.size); } else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } @@ -9277,12 +10241,9 @@ static int wdc_namespace_resize(int argc, char **argv, if (ret) return ret; - if ((cfg.op_option != 0x1) && - (cfg.op_option != 0x2) && - (cfg.op_option != 0x3) && - (cfg.op_option != 0xF)) - { - fprintf(stderr, "ERROR : WDC: unsupported OP option parameter\n"); + if ((cfg.op_option != 0x1) && (cfg.op_option != 0x2) && (cfg.op_option != 0x3) && + (cfg.op_option != 0xF)) { + fprintf(stderr, "ERROR: WDC: unsupported OP option parameter\n"); dev_close(dev); return -1; } @@ -9294,10 +10255,10 @@ static int wdc_namespace_resize(int argc, char **argv, ret = wdc_do_namespace_resize(dev, 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); + if (ret) + printf("ERROR: WDC: Namespace Resize of namespace id 0x%x, op option 0x%x failed\n", cfg.namespace_id, cfg.op_option); } else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } @@ -9345,44 +10306,45 @@ static int wdc_reason_identifier(int argc, char **argv, r = nvme_scan(NULL); - if (cfg.log_id != NVME_LOG_LID_TELEMETRY_HOST&& cfg.log_id != NVME_LOG_LID_TELEMETRY_CTRL) { - fprintf(stderr, "ERROR : WDC: Invalid Log ID. It must be 7 (Host) or 8 (Controller)\n"); + if (cfg.log_id != NVME_LOG_LID_TELEMETRY_HOST && + cfg.log_id != NVME_LOG_LID_TELEMETRY_CTRL) { + fprintf(stderr, "ERROR: WDC: Invalid Log ID. It must be 7 (Host) or 8 (Controller)\n"); ret = -1; - goto close_fd; + goto close_dev; } - if (cfg.file != NULL) { + if (cfg.file) { int verify_file; /* verify the passed in file name and path is valid before getting the dump data */ verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (verify_file < 0) { - fprintf(stderr, "ERROR : WDC: open : %s\n", strerror(errno)); + fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno)); ret = -1; - goto close_fd; + goto close_dev; } close(verify_file); strncpy(f, cfg.file, PATH_MAX - 1); } else { wdc_UtilsGetTime(&timeInfo); memset(timeStamp, 0, sizeof(timeStamp)); - wdc_UtilsSnprintf((char*)timeStamp, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u", + wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u", timeInfo.year, timeInfo.month, timeInfo.dayOfMonth, timeInfo.hour, timeInfo.minute, timeInfo.second); if (cfg.log_id == NVME_LOG_LID_TELEMETRY_CTRL) - snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_ctlr_%s", (char*)timeStamp); + snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_ctlr_%s", (char *)timeStamp); else - snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_host_%s", (char*)timeStamp); + snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_host_%s", (char *)timeStamp); if (wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix) == -1) { - fprintf(stderr, "ERROR : WDC: failed to generate file name\n"); + fprintf(stderr, "ERROR: WDC: failed to generate file name\n"); ret = -1; - goto close_fd; + goto close_dev; } if (strlen(f) > PATH_MAX - 5) { - fprintf(stderr, "ERROR : WDC: file name overflow\n"); + fprintf(stderr, "ERROR: WDC: file name overflow\n"); ret = -1; - goto close_fd; + goto close_dev; } strcat(f, ".bin"); } @@ -9393,13 +10355,13 @@ static int wdc_reason_identifier(int argc, char **argv, if ((capabilities & WDC_DRIVE_CAP_REASON_ID) == WDC_DRIVE_CAP_REASON_ID) { ret = wdc_do_get_reason_id(dev, f, cfg.log_id); } else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC:unsupported device for this command\n"); ret = -1; } nvme_show_status(ret); - close_fd: +close_dev: dev_close(dev); nvme_free_tree(r); return ret; @@ -9408,43 +10370,169 @@ static int wdc_reason_identifier(int argc, char **argv, static const char *nvme_log_id_to_string(__u8 log_id) { switch (log_id) { - case NVME_LOG_LID_ERROR: return "Error Information Log ID"; - case NVME_LOG_LID_SMART: return "Smart/Health Information Log ID"; - case NVME_LOG_LID_FW_SLOT: return "Firmware Slot Information Log ID"; - case NVME_LOG_LID_CHANGED_NS: return "Namespace Changed Log ID"; - case NVME_LOG_LID_CMD_EFFECTS: return "Commamds Supported and Effects Log ID"; - case NVME_LOG_LID_DEVICE_SELF_TEST: return "Device Self Test Log ID"; - case NVME_LOG_LID_TELEMETRY_HOST: return "Telemetry Host Initiated Log ID"; - case NVME_LOG_LID_TELEMETRY_CTRL: return "Telemetry Controller Generated Log ID"; - case NVME_LOG_LID_ENDURANCE_GROUP: return "Endurance Group Log ID"; - case NVME_LOG_LID_ANA: return "ANA Log ID"; - case NVME_LOG_LID_PERSISTENT_EVENT: return "Persistent Event Log ID"; - case NVME_LOG_LID_DISCOVER: return "Discovery Log ID"; - case NVME_LOG_LID_RESERVATION: return "Reservation Notification Log ID"; - case NVME_LOG_LID_SANITIZE: return "Sanitize Status Log ID"; - - case WDC_LOG_ID_C0: return "WDC Vendor Unique Log ID C0"; - case WDC_LOG_ID_C1: return "WDC Vendor Unique Log ID C1"; - case WDC_LOG_ID_C2: return "WDC Vendor Unique Log ID C2"; - case WDC_LOG_ID_C3: return "WDC Vendor Unique Log ID C3"; - case WDC_LOG_ID_C4: return "WDC Vendor Unique Log ID C4"; - case WDC_LOG_ID_C5: return "WDC Vendor Unique Log ID C5"; - case WDC_LOG_ID_C6: return "WDC Vendor Unique Log ID C6"; - case WDC_LOG_ID_C8: return "WDC Vendor Unique Log ID C8"; - case WDC_LOG_ID_CA: return "WDC Vendor Unique Log ID CA"; - case WDC_LOG_ID_CB: return "WDC Vendor Unique Log ID CB"; - case WDC_LOG_ID_D0: return "WDC Vendor Unique Log ID D0"; - case WDC_LOG_ID_D1: return "WDC Vendor Unique Log ID D1"; - case WDC_LOG_ID_D6: return "WDC Vendor Unique Log ID D6"; - case WDC_LOG_ID_D7: return "WDC Vendor Unique Log ID D7"; - case WDC_LOG_ID_D8: return "WDC Vendor Unique Log ID D8"; - case WDC_LOG_ID_DE: return "WDC Vendor Unique Log ID DE"; - case WDC_LOG_ID_F0: return "WDC Vendor Unique Log ID F0"; - case WDC_LOG_ID_F1: return "WDC Vendor Unique Log ID F1"; - case WDC_LOG_ID_F2: return "WDC Vendor Unique Log ID F2"; - case WDC_LOG_ID_FA: return "WDC Vendor Unique Log ID FA"; - - default: return "Unknown Log ID"; + case NVME_LOG_LID_ERROR: + return "Error Information Log ID"; + case NVME_LOG_LID_SMART: + return "Smart/Health Information Log ID"; + case NVME_LOG_LID_FW_SLOT: + return "Firmware Slot Information Log ID"; + case NVME_LOG_LID_CHANGED_NS: + return "Namespace Changed Log ID"; + case NVME_LOG_LID_CMD_EFFECTS: + return "Commamds Supported and Effects Log ID"; + case NVME_LOG_LID_DEVICE_SELF_TEST: + return "Device Self Test Log ID"; + case NVME_LOG_LID_TELEMETRY_HOST: + return "Telemetry Host Initiated Log ID"; + case NVME_LOG_LID_TELEMETRY_CTRL: + return "Telemetry Controller Generated Log ID"; + case NVME_LOG_LID_ENDURANCE_GROUP: + return "Endurance Group Log ID"; + case NVME_LOG_LID_ANA: + return "ANA Log ID"; + case NVME_LOG_LID_PERSISTENT_EVENT: + return "Persistent Event Log ID"; + case NVME_LOG_LID_DISCOVER: + return "Discovery Log ID"; + case NVME_LOG_LID_RESERVATION: + return "Reservation Notification Log ID"; + case NVME_LOG_LID_SANITIZE: + return "Sanitize Status Log ID"; + case WDC_LOG_ID_C0: + return "WDC Vendor Unique Log ID C0"; + case WDC_LOG_ID_C1: + return "WDC Vendor Unique Log ID C1"; + case WDC_LOG_ID_C2: + return "WDC Vendor Unique Log ID C2"; + case WDC_LOG_ID_C3: + return "WDC Vendor Unique Log ID C3"; + case WDC_LOG_ID_C4: + return "WDC Vendor Unique Log ID C4"; + case WDC_LOG_ID_C5: + return "WDC Vendor Unique Log ID C5"; + case WDC_LOG_ID_C6: + return "WDC Vendor Unique Log ID C6"; + case WDC_LOG_ID_C8: + return "WDC Vendor Unique Log ID C8"; + case WDC_LOG_ID_CA: + return "WDC Vendor Unique Log ID CA"; + case WDC_LOG_ID_CB: + return "WDC Vendor Unique Log ID CB"; + case WDC_LOG_ID_D0: + return "WDC Vendor Unique Log ID D0"; + case WDC_LOG_ID_D1: + return "WDC Vendor Unique Log ID D1"; + case WDC_LOG_ID_D6: + return "WDC Vendor Unique Log ID D6"; + case WDC_LOG_ID_D7: + return "WDC Vendor Unique Log ID D7"; + case WDC_LOG_ID_D8: + return "WDC Vendor Unique Log ID D8"; + case WDC_LOG_ID_DE: + return "WDC Vendor Unique Log ID DE"; + case WDC_LOG_ID_F0: + return "WDC Vendor Unique Log ID F0"; + case WDC_LOG_ID_F1: + return "WDC Vendor Unique Log ID F1"; + case WDC_LOG_ID_F2: + return "WDC Vendor Unique Log ID F2"; + case WDC_LOG_ID_FA: + return "WDC Vendor Unique Log ID FA"; + default: + return "Unknown Log ID"; + } +} + +static void __json_log_page_directory(struct log_page_directory *directory) +{ + __u32 bitmap_idx; + __u8 log_id; + struct json_object *root; + struct json_object *entries; + + root = json_create_object(); + + entries = json_create_array(); + json_object_add_value_array(root, "Entries", entries); + + for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) { + log_id = bitmap_idx; + if (!log_page_name[log_id]) + continue; + if (directory->supported_lid_bitmap & (1ULL << bitmap_idx)) { + struct json_object *json_entry = json_create_object(); + + json_object_add_value_uint(json_entry, "Log ID", log_id); + json_object_add_value_string(json_entry, "Log Page Name", + log_page_name[log_id]); + + json_array_add_value_object(entries, json_entry); + } + } + + for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) { + log_id = NVME_LOG_NS_BASE + bitmap_idx; + if (!log_page_name[log_id]) + continue; + if (directory->supported_ns_lid_bitmap & (1ULL << bitmap_idx)) { + struct json_object *json_entry = json_create_object(); + + json_object_add_value_uint(json_entry, "Log ID", log_id); + json_object_add_value_string(json_entry, "Log Page Name", + log_page_name[log_id]); + + json_array_add_value_object(entries, json_entry); + } + } + + for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) { + log_id = NVME_LOG_VS_BASE + bitmap_idx; + if (!log_page_name[log_id]) + continue; + if (directory->supported_vs_lid_bitmap & (1ULL << bitmap_idx)) { + struct json_object *json_entry = json_create_object(); + + json_object_add_value_uint(json_entry, "Log ID", log_id); + json_object_add_value_string(json_entry, "Log Page Name", + log_page_name[log_id]); + + json_array_add_value_object(entries, json_entry); + } + } + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + + +static void __show_log_page_directory(struct log_page_directory *directory) +{ + __u32 bitmap_idx; + __u8 log_id; + + for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) { + if (directory->supported_lid_bitmap & (1ULL << bitmap_idx)) { + log_id = bitmap_idx; + if (log_page_name[log_id]) + printf("0x%02X: %s\n", log_id, log_page_name[log_id]); + } + } + + for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) { + if (directory->supported_ns_lid_bitmap & (1ULL << bitmap_idx)) { + log_id = NVME_LOG_NS_BASE + bitmap_idx; + if (log_page_name[log_id]) + printf("0x%02X: %s\n", log_id, log_page_name[log_id]); + } + } + + for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) { + if (directory->supported_vs_lid_bitmap & (1ULL << bitmap_idx)) { + log_id = NVME_LOG_VS_BASE + bitmap_idx; + if (log_page_name[log_id]) + printf("0x%02X: %s\n", log_id, log_page_name[log_id]); + } } } @@ -9452,14 +10540,17 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command struct plugin *plugin) { const char *desc = "Retrieve Log Page Directory."; + enum nvme_print_flags fmt; struct nvme_dev *dev; int ret = 0; nvme_root_t r; __u64 capabilities = 0; struct wdc_c2_cbs_data *cbs_data = NULL; - int i; + int i; __u8 log_id = 0; __u32 device_id, read_vendor_id; + bool uuid_supported = false; + struct nvme_id_uuid_list uuid_list; struct config { char *output_format; @@ -9478,67 +10569,127 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command if (ret) return ret; - ret = validate_output_format(cfg.output_format); + ret = validate_output_format(cfg.output_format, &fmt); if (ret < 0) { - fprintf(stderr, "%s: ERROR : WDC : invalid output format\n", __func__); + fprintf(stderr, "%s: ERROR: WDC: invalid output format\n", __func__); dev_close(dev); return ret; } - ret = 0; r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } else { - ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); - log_id = (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) ? - WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 : WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE; - /* verify the 0xC2 Device Manageability log page is supported */ - if (wdc_nvme_check_supported_log_page(r, dev, log_id) == false) { - fprintf(stderr, "%s: ERROR : WDC : 0x%x Log Page not supported\n", __func__, log_id); - ret = -1; - goto out; - } - if (get_dev_mgment_cbs_data(r, dev, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) { - 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(); + memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list)); + if (wdc_CheckUuidListSupport(dev, &uuid_list)) + uuid_supported = true; + + if (uuid_supported) + fprintf(stderr, "WDC: UUID lists supported\n"); + else + fprintf(stderr, "WDC: UUID lists NOT supported\n"); - 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); + ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id); + log_id = (device_id == WDC_NVME_ZN350_DEV_ID || + device_id == WDC_NVME_ZN350_DEV_ID_1) ? + WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8 : + WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID; + + if (!wdc_is_sn861(device_id)) { + /* verify the 0xC2 Device Manageability log page is supported */ + if (wdc_nvme_check_supported_log_page(r, dev, log_id) == false) { + fprintf(stderr, + "%s: ERROR: WDC: 0x%x Log Page not supported\n", + __func__, log_id); + ret = -1; + goto out; + } + + if (!get_dev_mgment_cbs_data(r, dev, + WDC_C2_LOG_PAGES_SUPPORTED_ID, + (void *)&cbs_data)) { + fprintf(stderr, + "%s: ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n", + __func__, WDC_C2_LOG_PAGES_SUPPORTED_ID); + ret = -1; + goto out; + } + if (!cbs_data) { + fprintf(stderr, "%s: ERROR: WDC: NULL_data ptr\n", __func__); + ret = -1; + goto out; + } + printf("Log Page Directory\n"); + /* print the supported pages */ + if (!strcmp(cfg.output_format, "normal")) { + for (i = 0; i < le32_to_cpu(cbs_data->length); i++) + printf("0x%x - %s\n", cbs_data->data[i], + nvme_log_id_to_string(cbs_data->data[i])); + } else if (!strcmp(cfg.output_format, "binary")) { + d((__u8 *)cbs_data->data, + le32_to_cpu(cbs_data->length), 16, 1); + } else if (!strcmp(cfg.output_format, "json")) { + struct json_object *root = json_create_object(); + + for (i = 0; i < le32_to_cpu(cbs_data->length); i++) { + json_object_add_value_int(root, + nvme_log_id_to_string(cbs_data->data[i]), + cbs_data->data[i]); + } - free(cbs_data); - } 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); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + fprintf(stderr, + "%s: ERROR: WDC: Invalid format, format = %s\n", + __func__, cfg.output_format); + } + + free(cbs_data); + } else { + struct log_page_directory *dir; + void *data = NULL; + __u32 result; + + if (posix_memalign(&data, getpagesize(), 512)) { + fprintf(stderr, + "can not allocate log page directory payload\n"); + ret = ENOMEM; + goto out; + } + dir = (struct log_page_directory *)data; + ret = nvme_admin_passthru(dev_fd(dev), WDC_NVME_ADMIN_VUC_OPCODE_D2, 0, 0, + 0, 0, 0, 8, + 0, WDC_VUC_SUBOPCODE_LOG_PAGE_DIR_D2, 0, 0, 0, + 32, data, 0, NULL, + 0, &result); + if (!ret) { + switch (fmt) { + case BINARY: + d_raw((unsigned char *)data, 32); + break; + case JSON: + __json_log_page_directory(dir); + break; + default: + __show_log_page_directory(dir); + } + } else { + fprintf(stderr, "NVMe Status:%s(%x)\n", + nvme_status_to_string(ret, false), ret); + } + } } - out: +out: nvme_free_tree(r); dev_close(dev); return ret; @@ -9552,14 +10703,13 @@ static int wdc_get_drive_reason_id(struct nvme_dev *dev, char *drive_reason_id, struct nvme_id_ctrl ctrl; char *reason_id_str = "reason_id"; - i = sizeof (ctrl.sn) - 1; - j = sizeof (ctrl.mn) - 1; + i = sizeof(ctrl.sn) - 1; + j = sizeof(ctrl.mn) - 1; memset(drive_reason_id, 0, len); - memset(&ctrl, 0, sizeof (struct nvme_id_ctrl)); + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed " - "0x%x\n", ret); + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret); return -1; } /* Remove trailing spaces from the sn and mn */ @@ -9575,8 +10725,8 @@ static int wdc_get_drive_reason_id(struct nvme_dev *dev, char *drive_reason_id, 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"); + fprintf(stderr, + "ERROR: WDC: cannot format serial number due to data of unexpected length\n"); return -1; } @@ -9592,14 +10742,14 @@ static int wdc_save_reason_id(struct nvme_dev *dev, __u8 *rsn_ident, int size) struct stat st = {0}; if (wdc_get_drive_reason_id(dev, drive_reason_id, PATH_MAX) == -1) { - fprintf(stderr, "%s: ERROR : failed to get drive reason id\n", __func__); + fprintf(stderr, "%s: ERROR: failed to get drive reason id\n", __func__); return -1; } /* make the nvmecli dir in /usr/local if it doesn't already exist */ if (stat(reason_id_path, &st) == -1) { if (mkdir(reason_id_path, 0700) < 0) { - fprintf(stderr, "%s: ERROR : failed to mkdir %s : %s\n", + fprintf(stderr, "%s: ERROR: failed to mkdir %s: %s\n", __func__, reason_id_path, strerror(errno)); return -1; } @@ -9611,7 +10761,7 @@ static int wdc_save_reason_id(struct nvme_dev *dev, __u8 *rsn_ident, int size) 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 */ + /* 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); @@ -9626,7 +10776,7 @@ static int wdc_clear_reason_id(struct nvme_dev *dev) char drive_reason_id[PATH_MAX] = {0}; if (wdc_get_drive_reason_id(dev, drive_reason_id, PATH_MAX) == -1) { - fprintf(stderr, "%s: ERROR : failed to get drive reason id\n", __func__); + fprintf(stderr, "%s: ERROR: failed to get drive reason id\n", __func__); return -1; } @@ -9645,7 +10795,7 @@ static int wdc_clear_reason_id(struct nvme_dev *dev) /* remove the reason id file */ ret = remove(reason_id_file); - free: +free: free(reason_id_file); return ret; @@ -9661,11 +10811,11 @@ static int wdc_dump_telemetry_hdr(struct nvme_dev *dev, int log_id, struct nvme_ ret = nvme_get_log_telemetry_ctrl(dev_fd(dev), false, 0, 512, (void *)log_hdr); - if (ret < 0) + if (ret < 0) { perror("get-telemetry-log"); - else if (ret > 0) { + } else if (ret > 0) { nvme_show_status(ret); - fprintf(stderr, "%s: ERROR : Failed to acquire telemetry header, ret = %d!\n", __func__, ret); + fprintf(stderr, "%s: ERROR: Failed to acquire telemetry header, ret = %d!\n", __func__, ret); } return ret; @@ -9678,17 +10828,17 @@ static int wdc_do_get_reason_id(struct nvme_dev *dev, char *file, int log_id) __u32 log_hdr_size = sizeof(struct nvme_telemetry_log); __u32 reason_id_size = 0; - log_hdr = (struct nvme_telemetry_log *) malloc(log_hdr_size); - if (log_hdr == NULL) { - fprintf(stderr, "%s: ERROR : malloc failed, size : 0x%x, status : %s\n", __func__, log_hdr_size, strerror(errno)); + log_hdr = (struct nvme_telemetry_log *)malloc(log_hdr_size); + if (!log_hdr) { + fprintf(stderr, "%s: ERROR: malloc failed, size : 0x%x, status: %s\n", __func__, log_hdr_size, strerror(errno)); ret = -1; goto out; } memset(log_hdr, 0, log_hdr_size); ret = wdc_dump_telemetry_hdr(dev, log_id, log_hdr); - if (ret != 0) { - fprintf(stderr, "%s: ERROR : get telemetry header failed, ret : %d\n", __func__, ret); + if (ret) { + fprintf(stderr, "%s: ERROR: get telemetry header failed, ret : %d\n", __func__, ret); ret = -1; goto out; } @@ -9713,15 +10863,16 @@ static void wdc_print_nand_stats_normal(__u16 version, void *data) __u16 temp_norm; __u64 *temp_ptr = NULL; - switch (version) - { + switch (version) { case 0: - printf(" NAND Statistics :- \n"); - printf(" NAND Writes TLC (Bytes) %.0Lf\n", - int128_to_double(nand_stats->nand_write_tlc)); - printf(" NAND Writes SLC (Bytes) %.0Lf\n", - int128_to_double(nand_stats->nand_write_slc)); - printf(" NAND Program Failures %"PRIu32"\n", + printf(" NAND Statistics :-\n"); + printf(" NAND Writes TLC (Bytes) %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats->nand_write_tlc))); + printf(" NAND Writes SLC (Bytes) %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats->nand_write_slc))); + printf(" NAND Program Failures %"PRIu32"\n", (uint32_t)le32_to_cpu(nand_stats->nand_prog_failure)); printf(" NAND Erase Failures %"PRIu32"\n", (uint32_t)le32_to_cpu(nand_stats->nand_erase_failure)); @@ -9729,7 +10880,7 @@ static void wdc_print_nand_stats_normal(__u16 version, void *data) (uint32_t)le32_to_cpu(nand_stats->bad_block_count)); printf(" NAND XOR/RAID Recovery Trigger Events %"PRIu64"\n", le64_to_cpu(nand_stats->nand_rec_trigger_event)); - printf(" E2E Error Counter %"PRIu64"\n", + printf(" E2E Error Counter %"PRIu64"\n", le64_to_cpu(nand_stats->e2e_error_counter)); printf(" Number Successful NS Resizing Events %"PRIu64"\n", le64_to_cpu(nand_stats->successful_ns_resize_event)); @@ -9737,17 +10888,19 @@ static void wdc_print_nand_stats_normal(__u16 version, void *data) le16_to_cpu(nand_stats->log_page_version)); break; case 3: - printf(" NAND Statistics V3:- \n"); - printf(" TLC Units Written %.0Lf\n", - int128_to_double(nand_stats_v3->nand_write_tlc)); - printf(" SLC Units Written %.0Lf\n", - int128_to_double(nand_stats_v3->nand_write_slc)); + printf(" NAND Statistics V3:-\n"); + printf(" TLC Units Written %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats_v3->nand_write_tlc))); + printf(" SLC Units Written %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats_v3->nand_write_slc))); temp_ptr = (__u64 *)nand_stats_v3->bad_nand_block_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); - printf(" Bad NAND Blocks Count - Normalized %"PRIu16"\n", + printf(" Bad NAND Blocks Count - Normalized %"PRIu16"\n", le16_to_cpu(temp_norm)); - printf(" Bad NAND Blocks Count - Raw %"PRIu64"\n", + printf(" Bad NAND Blocks Count - Raw %"PRIu64"\n", le64_to_cpu(temp_raw)); printf(" NAND XOR Recovery count %"PRIu64"\n", le64_to_cpu(nand_stats_v3->xor_recovery_count)); @@ -9772,14 +10925,14 @@ static void wdc_print_nand_stats_normal(__u16 version, void *data) temp_ptr = (__u64 *)nand_stats_v3->program_fail_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); - printf(" Program Fail Count - Normalized %"PRIu16"\n", + printf(" Program Fail Count - Normalized %"PRIu16"\n", le16_to_cpu(temp_norm)); - printf(" Program Fail Count - Raw %"PRIu64"\n", + printf(" Program Fail Count - Raw %"PRIu64"\n", le64_to_cpu(temp_raw)); temp_ptr = (__u64 *)nand_stats_v3->erase_fail_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); - printf(" Erase Fail Count - Normalized %"PRIu16"\n", + printf(" Erase Fail Count - Normalized %"PRIu16"\n", le16_to_cpu(temp_norm)); printf(" Erase Fail Count - Raw %"PRIu64"\n", le64_to_cpu(temp_raw)); @@ -9791,8 +10944,9 @@ static void wdc_print_nand_stats_normal(__u16 version, void *data) le64_to_cpu(nand_stats_v3->security_version_number)); printf(" %% Free Blocks (System) %u\n", nand_stats_v3->percent_free_blocks_system); - printf(" Data Set Management Commands %.0Lf\n", - int128_to_double(nand_stats_v3->trim_completions)); + printf(" Data Set Management Commands %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats_v3->trim_completions))); printf(" Estimate of Incomplete Trim Data %"PRIu64"\n", le64_to_cpu(nand_stats_v3->trim_completions[16])); printf(" %% of completed trim %u\n", @@ -9810,22 +10964,24 @@ static void wdc_print_nand_stats_normal(__u16 version, void *data) le16_to_cpu(temp_norm)); printf(" Bad System Nand Block Count - Raw %"PRIu64"\n", le64_to_cpu(temp_raw)); - printf(" Endurance Estimate %.0Lf\n", - int128_to_double(nand_stats_v3->endurance_estimate)); + printf(" Endurance Estimate %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats_v3->endurance_estimate))); printf(" Thermal Throttling Count %u\n", nand_stats_v3->thermal_throttling_st_ct[0]); printf(" Thermal Throttling Status %u\n", nand_stats_v3->thermal_throttling_st_ct[1]); printf(" Unaligned I/O %"PRIu64"\n", le64_to_cpu(nand_stats_v3->unaligned_IO)); - printf(" Physical Media Units Read %.0Lf\n", - int128_to_double(nand_stats_v3->physical_media_units)); + printf(" Physical Media Units Read %s\n", + uint128_t_to_string( + le128_to_cpu(nand_stats_v3->physical_media_units))); printf(" log page version %"PRIu16"\n", le16_to_cpu(nand_stats_v3->log_page_version)); break; default: - fprintf(stderr, "WDC: Nand Stats ERROR : Invalid version\n"); + fprintf(stderr, "WDC: Nand Stats ERROR: Invalid version\n"); break; } @@ -9835,21 +10991,17 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) { struct wdc_nand_stats *nand_stats = (struct wdc_nand_stats *)(data); struct wdc_nand_stats_V3 *nand_stats_v3 = (struct wdc_nand_stats_V3 *)(data); - struct json_object *root; - root = json_create_object(); + struct json_object *root = json_create_object(); __u64 temp_raw; __u16 temp_norm; __u64 *temp_ptr = NULL; - switch (version) - { - + switch (version) { case 0: - - json_object_add_value_double(root, "NAND Writes TLC (Bytes)", - int128_to_double(nand_stats->nand_write_tlc)); - json_object_add_value_double(root, "NAND Writes SLC (Bytes)", - int128_to_double(nand_stats->nand_write_slc)); + json_object_add_value_uint128(root, "NAND Writes TLC (Bytes)", + le128_to_cpu(nand_stats->nand_write_tlc)); + json_object_add_value_uint128(root, "NAND Writes SLC (Bytes)", + le128_to_cpu(nand_stats->nand_write_slc)); json_object_add_value_uint(root, "NAND Program Failures", le32_to_cpu(nand_stats->nand_prog_failure)); json_object_add_value_uint(root, "NAND Erase Failures", @@ -9866,13 +11018,11 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) json_print_object(root, NULL); printf("\n"); break; - case 3: - - json_object_add_value_double(root, "NAND Writes TLC (Bytes)", - int128_to_double(nand_stats_v3->nand_write_tlc)); - json_object_add_value_double(root, "NAND Writes SLC (Bytes)", - int128_to_double(nand_stats_v3->nand_write_slc)); + json_object_add_value_uint128(root, "NAND Writes TLC (Bytes)", + le128_to_cpu(nand_stats_v3->nand_write_tlc)); + json_object_add_value_uint128(root, "NAND Writes SLC (Bytes)", + le128_to_cpu(nand_stats_v3->nand_write_slc)); temp_ptr = (__u64 *)nand_stats_v3->bad_nand_block_count; temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF); temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16); @@ -9922,8 +11072,8 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) le64_to_cpu(nand_stats_v3->security_version_number)); json_object_add_value_uint(root, "% Free Blocks (System)", nand_stats_v3->percent_free_blocks_system); - json_object_add_value_double(root, "Data Set Management Commands", - int128_to_double(nand_stats_v3->trim_completions)); + json_object_add_value_uint128(root, "Data Set Management Commands", + le128_to_cpu(nand_stats_v3->trim_completions)); json_object_add_value_uint64(root, "Estimate of Incomplete Trim Data", le64_to_cpu(nand_stats_v3->trim_completions[16])); json_object_add_value_uint(root, "%% of completed trim", @@ -9941,27 +11091,25 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) le16_to_cpu(temp_norm)); json_object_add_value_uint64(root, "Bad System Nand Block Count - Raw", le64_to_cpu(temp_raw)); - json_object_add_value_double(root, "Endurance Estimate", - int128_to_double(nand_stats_v3->endurance_estimate)); + json_object_add_value_uint128(root, "Endurance Estimate", + le128_to_cpu(nand_stats_v3->endurance_estimate)); json_object_add_value_uint(root, "Thermal Throttling Status", nand_stats_v3->thermal_throttling_st_ct[0]); json_object_add_value_uint(root, "Thermal Throttling Count", nand_stats_v3->thermal_throttling_st_ct[1]); json_object_add_value_uint64(root, "Unaligned I/O", le64_to_cpu(nand_stats_v3->unaligned_IO)); - json_object_add_value_double(root, "Physical Media Units Read", - int128_to_double(nand_stats_v3->physical_media_units)); + json_object_add_value_uint128(root, "Physical Media Units Read", + le128_to_cpu(nand_stats_v3->physical_media_units)); json_object_add_value_uint(root, "log page version", le16_to_cpu(nand_stats_v3->log_page_version)); json_print_object(root, NULL); printf("\n"); break; - default: printf("%s: Invalid Stats Version = %d\n", __func__, version); break; - } json_free_object(root); @@ -9970,7 +11118,7 @@ static void wdc_print_nand_stats_json(__u16 version, void *data) static void wdc_print_pcie_stats_normal(struct wdc_vs_pcie_stats *pcie_stats) { - printf(" PCIE Statistics :- \n"); + printf(" PCIE Statistics :-\n"); printf(" Unsupported Request Error Counter %20"PRIu64"\n", le64_to_cpu(pcie_stats->unsupportedRequestErrorCount)); printf(" ECRC Error Status Counter %20"PRIu64"\n", @@ -10008,8 +11156,7 @@ static void wdc_print_pcie_stats_normal(struct wdc_vs_pcie_stats *pcie_stats) static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats) { - struct json_object *root; - root = json_create_object(); + struct json_object *root = json_create_object(); json_object_add_value_uint64(root, "Unsupported Request Error Counter", le64_to_cpu(pcie_stats->unsupportedRequestErrorCount)); @@ -10053,22 +11200,21 @@ static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats) static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format) { - int ret; - int fmt = -1; + enum nvme_print_flags fmt; uint8_t *data = NULL; + int ret; data = NULL; ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0, NVME_NSID_ALL); if (ret) { - fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__); + fprintf(stderr, "ERROR: WDC: %s : Failed to retrieve NAND stats\n", __func__); goto out; } else { - fmt = validate_output_format(format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : %s : invalid output format\n", __func__); - ret = fmt; + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: %s : invalid output format\n", __func__); goto out; } @@ -10080,6 +11226,8 @@ static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format) case JSON: wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_NAND_STATS); break; + default: + break; } } @@ -10091,27 +11239,27 @@ static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format) static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format) { - int ret; - int fmt = -1; + enum nvme_print_flags fmt; uint8_t *output = NULL; __u16 version = 0; + int ret; - if ((output = (uint8_t*)calloc(WDC_NVME_NAND_STATS_SIZE, sizeof(uint8_t))) == NULL) { - fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno)); + output = (uint8_t *)calloc(WDC_NVME_NAND_STATS_SIZE, sizeof(uint8_t)); + if (!output) { + fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno)); ret = -1; goto out; } ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_NAND_STATS_LOG_ID, - WDC_NVME_NAND_STATS_SIZE, (void*)output); + WDC_NVME_NAND_STATS_SIZE, (void *)output); if (ret) { - fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__); + fprintf(stderr, "ERROR: WDC: %s : Failed to retrieve 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; + ret = validate_output_format(format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); goto out; } @@ -10125,6 +11273,8 @@ static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format) case JSON: wdc_print_nand_stats_json(version, output); break; + default: + break; } } @@ -10163,14 +11313,13 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, r = nvme_scan(NULL); capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_NAND_STATS) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_NAND_STATS)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } else { ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id); - if (ret < 0) - { - fprintf(stderr, "ERROR : WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret); return -1; } @@ -10186,7 +11335,7 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command, } if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret); + fprintf(stderr, "ERROR: WDC: Failure reading NAND statistics, ret = %d\n", ret); nvme_free_tree(r); dev_close(dev); @@ -10200,7 +11349,7 @@ static int wdc_do_vs_pcie_stats(struct nvme_dev *dev, struct nvme_passthru_cmd admin_cmd; int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); admin_cmd.opcode = WDC_NVME_PCIE_STATS_OPCODE; admin_cmd.addr = (__u64)(uintptr_t)pcieStatsPtr; admin_cmd.data_len = pcie_stats_size; @@ -10214,14 +11363,14 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Retrieve PCIE statistics."; + enum nvme_print_flags fmt; struct nvme_dev *dev; - int ret = 0; nvme_root_t r; + int ret; __u64 capabilities = 0; - int fmt = -1; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; struct wdc_vs_pcie_stats *pcieStatsPtr = NULL; int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats); - bool huge; struct config { char *output_format; @@ -10240,18 +11389,16 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, if (ret) return ret; - r = nvme_scan(NULL); - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - ret = fmt; + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); goto out; } - pcieStatsPtr = nvme_alloc(pcie_stats_size, &huge); - if (pcieStatsPtr == NULL) { - fprintf(stderr, "ERROR : WDC : PCIE Stats alloc : %s\n", strerror(errno)); + pcieStatsPtr = nvme_alloc_huge(pcie_stats_size, &mh); + if (!pcieStatsPtr) { + fprintf(stderr, "ERROR: WDC: PCIE Stats alloc: %s\n", strerror(errno)); ret = -1; goto out; } @@ -10260,14 +11407,14 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, capabilities = wdc_get_drive_capabilities(r, dev); - if ((capabilities & WDC_DRIVE_CAP_PCIE_STATS) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_PCIE_STATS)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; } else { ret = wdc_do_vs_pcie_stats(dev, pcieStatsPtr); - if (ret) - fprintf(stderr, "ERROR : WDC : Failure reading PCIE statistics, ret = 0x%x\n", ret); - else { + if (ret) { + fprintf(stderr, "ERROR: WDC: Failure reading PCIE statistics, ret = 0x%x\n", ret); + } else { /* parse the data */ switch (fmt) { case NORMAL: @@ -10276,12 +11423,11 @@ static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command, case JSON: wdc_print_pcie_stats_json(pcieStatsPtr); break; + default: + break; } } } - - nvme_free(pcieStatsPtr, huge); - out: nvme_free_tree(r); dev_close(dev); @@ -10292,6 +11438,7 @@ static int wdc_vs_drive_info(int argc, char **argv, struct command *command, struct plugin *plugin) { const char *desc = "Send a vs-drive-info command."; + enum nvme_print_flags fmt; nvme_root_t r; uint64_t capabilities = 0; struct nvme_dev *dev; @@ -10305,12 +11452,14 @@ static int wdc_vs_drive_info(int argc, char **argv, __u8 *data = NULL; __u32 ftl_unit_size = 0, tcg_dev_ownership = 0; __u16 boot_spec_major = 0, boot_spec_minor = 0; - int fmt = -1; struct json_object *root = NULL; char formatter[41] = { 0 }; char rev_str[16] = { 0 }; uint32_t read_device_id = -1, read_vendor_id = -1; - wdc_nvme_ext_smart_log *ext_smart_log_ptr = NULL; + struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = NULL; + struct ocp_drive_info info; + __u32 data_len = 0; + unsigned int num_dwords = 0; struct config { char *output_format; @@ -10329,18 +11478,18 @@ static int wdc_vs_drive_info(int argc, char **argv, if (ret) return ret; - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC %s invalid output format\n", __func__); + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC %s invalid output format\n", __func__); dev_close(dev); - return fmt; + return ret; } /* get the id ctrl data used to fill in drive info below */ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl); if (ret) { - fprintf(stderr, "ERROR : WDC %s: Identify Controller failed\n", __func__); + fprintf(stderr, "ERROR: WDC %s: Identify Controller failed\n", __func__); dev_close(dev); return ret; } @@ -10350,9 +11499,8 @@ static int wdc_vs_drive_info(int argc, char **argv, capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_INFO) == WDC_DRIVE_CAP_INFO) { ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id); - if (ret < 0) - { - fprintf(stderr, "ERROR : WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret); goto out; } @@ -10380,14 +11528,13 @@ static int wdc_vs_drive_info(int argc, char **argv, rev = (double)(cpu_to_le32(result) & 0x0000ffff); if (fmt == NORMAL) { - printf("Drive HW Revison: %4.1f\n", (.1 * rev)); + printf("Drive HW Revision: %4.1f\n", (.1 * rev)); printf("FTL Unit Size: 0x%x KB\n", size); printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]); - } - else if (fmt == JSON) { - root = json_create_object(); - sprintf(rev_str, "%4.1f", (.1 * rev)); - json_object_add_value_string(root, "Drive HW Revison", rev_str); + } else if (fmt == JSON) { + root = json_create_object(); + sprintf(rev_str, "%4.1f", (.1 * rev)); + json_object_add_value_string(root, "Drive HW Revision", rev_str); json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size)); wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn)); @@ -10400,19 +11547,18 @@ static int wdc_vs_drive_info(int argc, char **argv, } } break; - case WDC_NVME_SN730A_DEV_ID: + case WDC_NVME_SN730_DEV_ID: memcpy(vsData, &ctrl.vs[0], 32); major_rev = ctrl.sn[12]; minor_rev = ctrl.sn[13]; if (fmt == NORMAL) { - printf("Drive HW Revision: %c.%c \n", major_rev, minor_rev); + printf("Drive HW Revision: %c.%c\n", major_rev, minor_rev); printf("Customer SN: %-.*s\n", 14, &ctrl.sn[0]); - } - else if (fmt == JSON) { - root = json_create_object(); - sprintf(rev_str, "%c.%c", major_rev, minor_rev); + } else if (fmt == JSON) { + root = json_create_object(); + sprintf(rev_str, "%c.%c", major_rev, minor_rev); json_object_add_value_string(root, "Drive HW Revison", rev_str); wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], 14); json_object_add_value_string(root, "Customer SN", formatter); @@ -10427,21 +11573,22 @@ static int wdc_vs_drive_info(int argc, char **argv, /* Get the Drive HW Rev from the C6 Log page */ ret = nvme_get_hw_rev_log(dev_fd(dev), &data, 0, NVME_NSID_ALL); - if (ret == 0) { - wdc_nvme_hw_rev_log *log_data = (wdc_nvme_hw_rev_log *)data; + if (!ret) { + struct wdc_nvme_hw_rev_log *log_data = (struct wdc_nvme_hw_rev_log *)data; + major_rev = log_data->hw_rev_gdr; free(data); data = NULL; } else { - fprintf(stderr, "ERROR : WDC: %s: failure to get hw revision log\n", __func__); + fprintf(stderr, "ERROR: WDC: %s: failure to get hw revision log\n", __func__); ret = -1; goto out; } /* Get the Smart C0 log page */ - if ((capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE) == 0) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + if (!(capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; } @@ -10449,8 +11596,8 @@ static int wdc_vs_drive_info(int argc, char **argv, ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0, NVME_NSID_ALL); - if (ret == 0) { - ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; + if (!ret) { + ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data; /* Set the FTL Unit size */ ftl_unit_size = le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus); @@ -10463,7 +11610,7 @@ static int wdc_vs_drive_info(int argc, char **argv, tcg_dev_ownership = le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos); free(data); } else { - fprintf(stderr, "ERROR : WDC: %s: failure to get extended smart cloud log\n", __func__); + fprintf(stderr, "ERROR: WDC: %s: failure to get extended smart cloud log\n", __func__); ret = -1; goto out; } @@ -10474,13 +11621,12 @@ static int wdc_vs_drive_info(int argc, char **argv, printf("HyperScale Boot Version Spec: %d.%d\n", boot_spec_major, boot_spec_minor); printf("TCG Device Ownership Status: %2d\n", tcg_dev_ownership); - } - else if (fmt == JSON) { - root = json_create_object(); + } else if (fmt == JSON) { + root = json_create_object(); json_object_add_value_int(root, "Drive HW Revison", major_rev); json_object_add_value_int(root, "FTL Unit Size", ftl_unit_size); - sprintf(rev_str, "%d.%d", boot_spec_major, boot_spec_minor); + sprintf(rev_str, "%d.%d", boot_spec_major, boot_spec_minor); json_object_add_value_string(root, "HyperScale Boot Version Spec", rev_str); json_object_add_value_int(root, "TCG Device Ownership Status", tcg_dev_ownership); @@ -10490,14 +11636,59 @@ static int wdc_vs_drive_info(int argc, char **argv, json_free_object(root); } + break; + case WDC_NVME_SN861_DEV_ID: + case WDC_NVME_SN861_DEV_ID_1: + data_len = sizeof(info); + num_dwords = data_len / 4; + if (data_len % 4 != 0) + num_dwords += 1; + + ret = nvme_admin_passthru(dev_fd(dev), + WDC_NVME_ADMIN_VUC_OPCODE_D2, + 0, 0, 0, 0, 0, num_dwords, 0, + WDC_VUC_SUBOPCODE_VS_DRIVE_INFO_D2, + 0, 0, 0, data_len, &info, 0, + NULL, 0, NULL); + + if (!ret) { + __u16 hw_rev_major, hw_rev_minor; + + hw_rev_major = le32_to_cpu(info.hw_revision) / 10; + hw_rev_minor = le32_to_cpu(info.hw_revision) % 10; + if (fmt == NORMAL) { + printf("HW Revision : %" PRIu32 ".%" PRIu32 "\n", + hw_rev_major, hw_rev_minor); + printf("FTL Unit Size : %" PRIu32 "\n", + le32_to_cpu(info.ftl_unit_size)); + } else if (fmt == JSON) { + char buf[20]; + + root = json_create_object(); + + memset((void *)buf, 0, 20); + sprintf(buf, "%" PRIu32 ".%" PRIu32, + hw_rev_major, hw_rev_minor); + + json_object_add_value_string(root, + "hw_revision", buf); + json_object_add_value_uint(root, + "ftl_unit_size", + le32_to_cpu(info.ftl_unit_size)); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } + } break; default: - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; break; } } else { - fprintf(stderr, "ERROR : WDC: capability not supported by this device\n"); + fprintf(stderr, "ERROR: WDC: capability not supported by this device\n"); ret = -1; } @@ -10514,12 +11705,13 @@ static int wdc_vs_temperature_stats(int argc, char **argv, const char *desc = "Send a vs-temperature-stats command."; struct nvme_smart_log smart_log; struct nvme_id_ctrl id_ctrl; + enum nvme_print_flags fmt; struct nvme_dev *dev; nvme_root_t r; uint64_t capabilities = 0; - __u32 hctm_tmt; + __u32 hctm_tmt; int temperature, temp_tmt1, temp_tmt2; - int ret, fmt = -1; + int ret; struct config { char *output_format; @@ -10539,10 +11731,9 @@ static int wdc_vs_temperature_stats(int argc, char **argv, return ret; r = nvme_scan(NULL); - fmt = validate_output_format(cfg.output_format); - if (fmt < 0) { - fprintf(stderr, "ERROR : WDC : invalid output format\n"); - ret = fmt; + ret = validate_output_format(cfg.output_format, &fmt); + if (ret < 0) { + fprintf(stderr, "ERROR: WDC: invalid output format\n"); goto out; } @@ -10550,29 +11741,29 @@ static int wdc_vs_temperature_stats(int argc, char **argv, wdc_check_device(r, dev); capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_TEMP_STATS) != WDC_DRIVE_CAP_TEMP_STATS) { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); ret = -1; goto out; - } + } - /* get the temperature stats or report errors */ + /* get the temperature stats or report errors */ ret = nvme_identify_ctrl(dev_fd(dev), &id_ctrl); - if (ret != 0) + if (ret) goto out; ret = nvme_get_log_smart(dev_fd(dev), NVME_NSID_ALL, false, &smart_log); - if (ret != 0) + if (ret) goto out; - /* convert from Kelvin to degrees Celsius */ + /* convert from kelvins to degrees Celsius */ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]) - 273; /* retrieve HCTM Thermal Management Temperatures */ nvme_get_features_simple(dev_fd(dev), 0x10, 0, &hctm_tmt); - temp_tmt1 = ((hctm_tmt >> 16) & 0xffff) ? ((hctm_tmt >> 16) & 0xffff) - 273 : 0; - temp_tmt2 = (hctm_tmt & 0xffff) ? (hctm_tmt & 0xffff) - 273 : 0; + temp_tmt1 = ((hctm_tmt >> 16) & 0xffff) ? ((hctm_tmt >> 16) & 0xffff) - 273 : 0; + temp_tmt2 = (hctm_tmt & 0xffff) ? (hctm_tmt & 0xffff) - 273 : 0; - if (fmt == NORMAL) { + if (fmt == NORMAL) { /* print the temperature stats */ printf("Temperature Stats for NVME device:%s namespace-id:%x\n", dev->name, WDC_DE_GLOBAL_NSID); @@ -10591,10 +11782,10 @@ static int wdc_vs_temperature_stats(int argc, char **argv, printf("TMT2 Transition Counter : %"PRIu32"\n", smart_log.thm_temp2_trans_count); printf("TMT2 Total Time : %"PRIu32"\n", smart_log.thm_temp2_total_time); printf("Thermal Shutdown Threshold : 95 °C\n"); - } - else if (fmt == JSON) { - struct json_object *root; - root = json_create_object(); + } else if (fmt == JSON) { + struct json_object *root; + + root = json_create_object(); json_object_add_value_int(root, "Current Composite Temperature", le32_to_cpu(temperature)); json_object_add_value_int(root, "WCTEMP", le16_to_cpu(id_ctrl.wctemp - 273)); @@ -10615,9 +11806,9 @@ static int wdc_vs_temperature_stats(int argc, char **argv, printf("\n"); json_free_object(root); - } - else - printf("%s: Invalid format\n", __func__); + } else { + printf("%s: Invalid format\n", __func__); + } out: nvme_show_status(ret); @@ -10626,114 +11817,114 @@ static int wdc_vs_temperature_stats(int argc, char **argv, return ret; } -static int wdc_capabilities(int argc, char **argv, - struct command *command, struct plugin *plugin) -{ - const char *desc = "Send a capabilities command."; - uint64_t capabilities = 0; - struct nvme_dev *dev; - nvme_root_t r; - int ret; - - OPT_ARGS(opts) = - { - OPT_END() - }; - - ret = parse_and_open(&dev, argc, argv, desc, opts); - if (ret) - return ret; - - /* get capabilities */ - r = nvme_scan(NULL); - wdc_check_device(r, dev); - capabilities = wdc_get_drive_capabilities(r, dev); - - /* print command and supported status */ - printf("WDC Plugin Capabilities for NVME device:%s\n", dev->name); - printf("cap-diag : %s\n", - capabilities & WDC_DRIVE_CAP_CAP_DIAG ? "Supported" : "Not Supported"); - printf("drive-log : %s\n", - capabilities & WDC_DRIVE_CAP_DRIVE_LOG ? "Supported" : "Not Supported"); - printf("get-crash-dump : %s\n", - capabilities & WDC_DRIVE_CAP_CRASH_DUMP ? "Supported" : "Not Supported"); - printf("get-pfail-dump : %s\n", - capabilities & WDC_DRIVE_CAP_PFAIL_DUMP ? "Supported" : "Not Supported"); - printf("id-ctrl : Supported\n"); - printf("purge : %s\n", - capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); - printf("purge-monitor : %s\n", - capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); - printf("vs-internal-log : %s\n", - capabilities & WDC_DRIVE_CAP_INTERNAL_LOG_MASK ? "Supported" : "Not Supported"); - printf("vs-nand-stats : %s\n", - capabilities & WDC_DRIVE_CAP_NAND_STATS ? "Supported" : "Not Supported"); - printf("vs-smart-add-log : %s\n", - capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK ? "Supported" : "Not Supported"); - printf("--C0 Log Page : %s\n", - capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE ? "Supported" : "Not Supported"); - printf("--C1 Log Page : %s\n", - capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE ? "Supported" : "Not Supported"); - printf("--C3 Log Page : %s\n", - capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported"); - printf("--CA Log Page : %s\n", - capabilities & WDC_DRIVE_CAP_CA_LOG_PAGE ? "Supported" : "Not Supported"); - printf("--D0 Log Page : %s\n", - capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE ? "Supported" : "Not Supported"); - printf("clear-pcie-correctable-errors : %s\n", - capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK ? "Supported" : "Not Supported"); - printf("drive-essentials : %s\n", - capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS ? "Supported" : "Not Supported"); - printf("get-drive-status : %s\n", - capabilities & WDC_DRIVE_CAP_DRIVE_STATUS ? "Supported" : "Not Supported"); - printf("clear-assert-dump : %s\n", - capabilities & WDC_DRIVE_CAP_CLEAR_ASSERT ? "Supported" : "Not Supported"); - printf("drive-resize : %s\n", - capabilities & WDC_DRIVE_CAP_RESIZE ? "Supported" : "Not Supported"); - printf("vs-fw-activate-history : %s\n", - capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK ? "Supported" : "Not Supported"); - printf("clear-fw-activate-history : %s\n", - capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK ? "Supported" : "Not Supported"); - printf("vs-telemetry-controller-option: %s\n", - capabilities & WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG ? "Supported" : "Not Supported"); - printf("vs-error-reason-identifier : %s\n", - capabilities & WDC_DRIVE_CAP_REASON_ID ? "Supported" : "Not Supported"); - printf("log-page-directory : %s\n", - capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR ? "Supported" : "Not Supported"); - printf("namespace-resize : %s\n", - capabilities & WDC_DRIVE_CAP_NS_RESIZE ? "Supported" : "Not Supported"); - printf("vs-drive-info : %s\n", - capabilities & WDC_DRIVE_CAP_INFO ? "Supported" : "Not Supported"); - printf("vs-temperature-stats : %s\n", - capabilities & WDC_DRIVE_CAP_TEMP_STATS ? "Supported" : "Not Supported"); - printf("cloud-SSD-plugin-version : %s\n", - capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION ? "Supported" : "Not Supported"); - printf("vs-pcie-stats : %s\n", - capabilities & WDC_DRIVE_CAP_PCIE_STATS ? "Supported" : "Not Supported"); - printf("get-error-recovery-log : %s\n", - capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE ? "Supported" : "Not Supported"); - printf("get-dev-capabilities-log : %s\n", - capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE ? "Supported" : "Not Supported"); - printf("get-unsupported-reqs-log : %s\n", - capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE ? "Supported" : "Not Supported"); - printf("get-latency-monitor-log : %s\n", - capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported"); - printf("cloud-boot-SSD-version : %s\n", - capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION ? "Supported" : "Not Supported"); - printf("vs-cloud-log : %s\n", - capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE ? "Supported" : "Not Supported"); - printf("vs-hw-rev-log : %s\n", - capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE ? "Supported" : "Not Supported"); - printf("vs-device_waf : %s\n", - capabilities & WDC_DRIVE_CAP_DEVICE_WAF ? "Supported" : "Not Supported"); - printf("capabilities : Supported\n"); - nvme_free_tree(r); - dev_close(dev); - return 0; -} - -static int wdc_cloud_ssd_plugin_version(int argc, char **argv, - struct command *command, struct plugin *plugin) +static int wdc_capabilities(int argc, char **argv, struct command *command, struct plugin *plugin) +{ + const char *desc = "Send a capabilities command."; + uint64_t capabilities = 0; + struct nvme_dev *dev; + nvme_root_t r; + int ret; + + OPT_ARGS(opts) = { + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + if (ret) + return ret; + + /* get capabilities */ + r = nvme_scan(NULL); + wdc_check_device(r, dev); + capabilities = wdc_get_drive_capabilities(r, dev); + + /* print command and supported status */ + printf("WDC Plugin Capabilities for NVME device:%s\n", dev->name); + printf("cap-diag : %s\n", + capabilities & WDC_DRIVE_CAP_CAP_DIAG ? "Supported" : "Not Supported"); + printf("drive-log : %s\n", + capabilities & WDC_DRIVE_CAP_DRIVE_LOG ? "Supported" : "Not Supported"); + printf("get-crash-dump : %s\n", + capabilities & WDC_DRIVE_CAP_CRASH_DUMP ? "Supported" : "Not Supported"); + printf("get-pfail-dump : %s\n", + capabilities & WDC_DRIVE_CAP_PFAIL_DUMP ? "Supported" : "Not Supported"); + printf("id-ctrl : Supported\n"); + printf("purge : %s\n", + capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); + printf("purge-monitor : %s\n", + capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); + printf("vs-internal-log : %s\n", + capabilities & WDC_DRIVE_CAP_INTERNAL_LOG_MASK ? "Supported" : "Not Supported"); + printf("vs-nand-stats : %s\n", + capabilities & WDC_DRIVE_CAP_NAND_STATS ? "Supported" : "Not Supported"); + printf("vs-smart-add-log : %s\n", + capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK ? "Supported" : "Not Supported"); + printf("--C0 Log Page : %s\n", + capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE ? "Supported" : "Not Supported"); + printf("--C1 Log Page : %s\n", + capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE ? "Supported" : "Not Supported"); + printf("--C3 Log Page : %s\n", + capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported"); + printf("--CA Log Page : %s\n", + capabilities & WDC_DRIVE_CAP_CA_LOG_PAGE ? "Supported" : "Not Supported"); + printf("--D0 Log Page : %s\n", + capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE ? "Supported" : "Not Supported"); + printf("clear-pcie-correctable-errors : %s\n", + capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK ? "Supported" : "Not Supported"); + printf("drive-essentials : %s\n", + capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS ? "Supported" : "Not Supported"); + printf("get-drive-status : %s\n", + capabilities & WDC_DRIVE_CAP_DRIVE_STATUS ? "Supported" : "Not Supported"); + printf("clear-assert-dump : %s\n", + capabilities & WDC_DRIVE_CAP_CLEAR_ASSERT ? "Supported" : "Not Supported"); + printf("drive-resize : %s\n", + capabilities & WDC_DRIVE_CAP_RESIZE ? "Supported" : "Not Supported"); + printf("vs-fw-activate-history : %s\n", + capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK ? "Supported" : "Not Supported"); + printf("clear-fw-activate-history : %s\n", + capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK ? "Supported" : "Not Supported"); + printf("vs-telemetry-controller-option: %s\n", + capabilities & WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG ? "Supported" : "Not Supported"); + printf("vs-error-reason-identifier : %s\n", + capabilities & WDC_DRIVE_CAP_REASON_ID ? "Supported" : "Not Supported"); + printf("log-page-directory : %s\n", + capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR ? "Supported" : "Not Supported"); + printf("namespace-resize : %s\n", + capabilities & WDC_DRIVE_CAP_NS_RESIZE ? "Supported" : "Not Supported"); + printf("vs-drive-info : %s\n", + capabilities & WDC_DRIVE_CAP_INFO ? "Supported" : "Not Supported"); + printf("vs-temperature-stats : %s\n", + capabilities & WDC_DRIVE_CAP_TEMP_STATS ? "Supported" : "Not Supported"); + printf("cloud-SSD-plugin-version : %s\n", + capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION ? "Supported" : "Not Supported"); + printf("vs-pcie-stats : %s\n", + capabilities & WDC_DRIVE_CAP_PCIE_STATS ? "Supported" : "Not Supported"); + printf("get-error-recovery-log : %s\n", + capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE ? "Supported" : "Not Supported"); + printf("get-dev-capabilities-log : %s\n", + capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE ? "Supported" : "Not Supported"); + printf("get-unsupported-reqs-log : %s\n", + capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE ? "Supported" : "Not Supported"); + printf("get-latency-monitor-log : %s\n", + capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported"); + printf("cloud-boot-SSD-version : %s\n", + capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION ? "Supported" : "Not Supported"); + printf("vs-cloud-log : %s\n", + capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE ? "Supported" : "Not Supported"); + printf("vs-hw-rev-log : %s\n", + capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE ? "Supported" : "Not Supported"); + printf("vs-device_waf : %s\n", + capabilities & WDC_DRIVE_CAP_DEVICE_WAF ? "Supported" : "Not Supported"); + printf("set-latency-monitor-feature : %s\n", + capabilities & WDC_DRIVE_CAP_SET_LATENCY_MONITOR ? "Supported" : "Not Supported"); + printf("capabilities : Supported\n"); + nvme_free_tree(r); + dev_close(dev); + return 0; +} + +static int wdc_cloud_ssd_plugin_version(int argc, char **argv, struct command *command, + struct plugin *plugin) { const char *desc = "Get Cloud SSD Plugin Version command."; uint64_t capabilities = 0; @@ -10755,10 +11946,10 @@ static int wdc_cloud_ssd_plugin_version(int argc, char **argv, capabilities = wdc_get_drive_capabilities(r, dev); if ((capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION) == WDC_DRIVE_CAP_CLOUD_SSD_VERSION) { - /* print command and supported status */ - printf("WDC Cloud SSD Plugin Version: 1.0\n"); + /* print command and supported status */ + printf("WDC Cloud SSD Plugin Version: 1.0\n"); } else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); } nvme_free_tree(r); @@ -10766,8 +11957,8 @@ static int wdc_cloud_ssd_plugin_version(int argc, char **argv, return 0; } -static int wdc_cloud_boot_SSD_version(int argc, char **argv, - struct command *command, struct plugin *plugin) +static int wdc_cloud_boot_SSD_version(int argc, char **argv, struct command *command, + struct plugin *plugin) { const char *desc = "Get Cloud Boot SSD Version command."; const char *namespace_id = "desired namespace id"; @@ -10777,7 +11968,7 @@ static int wdc_cloud_boot_SSD_version(int argc, char **argv, int ret; int major = 0, minor = 0; __u8 *data = NULL; - wdc_nvme_ext_smart_log *ext_smart_log_ptr = NULL; + struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = NULL; struct config { __u32 namespace_id; @@ -10806,23 +11997,22 @@ static int wdc_cloud_boot_SSD_version(int argc, char **argv, ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0, cfg.namespace_id); - ext_smart_log_ptr = (wdc_nvme_ext_smart_log *)data; - if (ret == 0) { + ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data; + if (!ret) { major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj); minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min); - /* print the version returned from the log page */ - printf("HyperScale Boot Version: %d.%d\n", major, minor); - + /* print the version returned from the log page */ + printf("HyperScale Boot Version: %d.%d\n", major, minor); } else { - fprintf(stderr, "ERROR : WDC : Unable to read Extended Smart/C0 Log Page data\n"); + fprintf(stderr, "ERROR: WDC: Unable to read Extended Smart/C0 Log Page data\n"); ret = -1; } if (data) free(data); } else { - fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); } nvme_free_tree(r); @@ -10830,8 +12020,7 @@ static int wdc_cloud_boot_SSD_version(int argc, char **argv, return ret; } -static int wdc_enc_get_log(int argc, char **argv, struct command *command, - struct plugin *plugin) +static int wdc_enc_get_log(int argc, char **argv, struct command *command, struct plugin *plugin) { char *desc = "Get Enclosure Log."; char *file = "Output file pathname."; @@ -10872,14 +12061,17 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command, } if (cfg.log_id > 0xff) { - fprintf(stderr, "Invalid log identifier: %d. Valid 0xd1, 0xd2, 0xd3, 0xd4, 0xe2, 0xe4\n", cfg.log_id); + fprintf(stderr, + "Invalid log identifier: %d. Valid 0xd1, 0xd2, 0xd3, 0xd4, 0xe2, 0xe4\n", + cfg.log_id); goto closed_fd; } - if (cfg.xfer_size != 0) { + if (cfg.xfer_size) { xfer_size = cfg.xfer_size; if (!wdc_check_power_of_2(cfg.xfer_size)) { - fprintf(stderr, "%s: ERROR : xfer-size (%d) must be a power of 2\n", __func__, cfg.xfer_size); + fprintf(stderr, "%s: ERROR: xfer-size (%d) must be a power of 2\n", + __func__, cfg.xfer_size); err = -EINVAL; goto closed_fd; } @@ -10888,28 +12080,30 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command, /* Log IDs are only for specific enclosures */ if (cfg.log_id) { xfer_size = (xfer_size) ? xfer_size : WDC_NVME_ENC_LOG_SIZE_CHUNK; - len = cfg.file==NULL?0:strlen(cfg.file); + len = !cfg.file ? 0 : strlen(cfg.file); if (len > 0) { - output_fd = fopen(cfg.file,"wb"); - if (output_fd == 0) { - fprintf(stderr, "%s: ERROR : opening:%s : %s\n", __func__,cfg.file, strerror(errno)); + output_fd = fopen(cfg.file, "wb"); + if (!output_fd) { + fprintf(stderr, "%s: ERROR: opening:%s: %s\n", __func__, cfg.file, + strerror(errno)); err = -EINVAL; goto closed_fd; } } else { output_fd = stdout; } - if (cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_1 || cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_2 - || cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_3 || cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_4) { - fprintf(stderr, "args - sz:%x logid:%x of:%s\n",xfer_size,cfg.log_id,cfg.file); - err = wdc_enc_get_nic_log(dev, cfg.log_id, - xfer_size, - WDC_NVME_ENC_NIC_LOG_SIZE, - output_fd); + if (cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_1 || + cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_2 || + cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_3 || + cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_4) { + fprintf(stderr, "args - sz:%x logid:%x of:%s\n", xfer_size, cfg.log_id, + cfg.file); + err = wdc_enc_get_nic_log(dev, cfg.log_id, xfer_size, + WDC_NVME_ENC_NIC_LOG_SIZE, output_fd); } else { - fprintf(stderr, "args - sz:%x logid:%x of:%s\n",xfer_size,cfg.log_id,cfg.file); - err = wdc_enc_submit_move_data(dev, NULL, 0, - xfer_size, output_fd, + fprintf(stderr, "args - sz:%x logid:%x of:%s\n", xfer_size, cfg.log_id, + cfg.file); + err = wdc_enc_submit_move_data(dev, NULL, 0, xfer_size, output_fd, cfg.log_id, 0, 0); } @@ -10917,7 +12111,8 @@ static int wdc_enc_get_log(int argc, char **argv, struct command *command, fprintf(stderr, "No Log/Crashdump available\n"); err = 0; } else if (err) { - fprintf(stderr, "ERROR:0x%x Failed to collect log-id:%x \n",err, cfg.log_id); + fprintf(stderr, "ERROR: 0x%x Failed to collect log-id:%x\n", err, + cfg.log_id); } } closed_fd: @@ -10938,8 +12133,8 @@ static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, char *buf; buf = (char *)malloc(sizeof(__u8) * xfer_size); - if (buf == NULL) { - fprintf(stderr, "%s: ERROR : malloc : %s\n", __func__, strerror(errno)); + if (!buf) { + fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno)); return -1; } /* send something no matter what */ @@ -10950,7 +12145,7 @@ static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, .opcode = WDC_NVME_ADMIN_ENC_MGMT_SND, .nsid = 0, .addr = (__u64)(uintptr_t) cmd, - .data_len = ((len + sizeof(uint32_t) - 1)/sizeof(uint32_t)) * sizeof(uint32_t), + .data_len = ((len + sizeof(uint32_t) - 1) / sizeof(uint32_t)) * sizeof(uint32_t), .cdw10 = len, .cdw12 = log_id, .cdw13 = 0, @@ -10960,36 +12155,32 @@ static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, clock_gettime(CLOCK_REALTIME, &time); srand(time.tv_nsec); - handle = random(); /* Handle to associate send request with receive request */ + handle = random(); /* Handle to associate send request with receive request */ nvme_cmd.cdw11 = handle; #ifdef WDC_NVME_CLI_DEBUG - unsigned char *d = (unsigned char*) nvme_cmd.addr; - unsigned char *md = (unsigned char*) nvme_cmd.metadata; - printf("NVME_ADMIN_COMMAND:\n" \ - "opcode: 0x%02x, flags: 0x%02x, rsvd: 0x%04x, nsid: 0x%08x, cdw2: 0x%08x, cdw3: 0x%08x, " \ - "metadata_len: 0x%08x, data_len: 0x%08x, cdw10: 0x%08x, cdw11: 0x%08x, cdw12: 0x%08x, " \ - "cdw13: 0x%08x, cdw14: 0x%08x, cdw15: 0x%08x, timeout_ms: 0x%08x, result: 0x%08x, " \ - "metadata: %s, " \ - "data: %s\n", \ - nvme_cmd.opcode, nvme_cmd.flags, nvme_cmd.rsvd1, nvme_cmd.nsid, nvme_cmd.cdw2, nvme_cmd.cdw3, \ - nvme_cmd.metadata_len, nvme_cmd.data_len, nvme_cmd.cdw10, nvme_cmd.cdw11, nvme_cmd.cdw12, \ - nvme_cmd.cdw13, nvme_cmd.cdw14, nvme_cmd.cdw15, nvme_cmd.timeout_ms, nvme_cmd.result, - md, \ - d); + unsigned char *d = (unsigned char *)nvme_cmd.addr; + unsigned char *md = (unsigned char *)nvme_cmd.metadata; + + printf("NVME_ADMIN_COMMAND:\n"); + printf("opcode: 0x%02x, flags: 0x%02x, rsvd: 0x%04x, nsid: 0x%08x, cdw2: 0x%08x, ", + nvme_cmd.opcode, nvme_cmd.flags, nvme_cmd.rsvd1, nvme_cmd.nsid, nvme_cmd.cdw2); + printf("cdw3: 0x%08x, metadata_len: 0x%08x, data_len: 0x%08x, cdw10: 0x%08x, " + nvme_cmd.cdw3, nvme_cmd.metadata_len, nvme_cmd.data_len, nvme_cmd.cdw10); + printf("cdw11: 0x%08x, cdw12: 0x%08x, cdw13: 0x%08x, cdw14: 0x%08x, cdw15: 0x%08x, " + nvme_cmd.cdw11, nvme_cmd.cdw12, nvme_cmd.cdw13, nvme_cmd.cdw14, nvme_cmd.cdw15); + printf("timeout_ms: 0x%08x, result: 0x%08x, metadata: %s, data: %s\n", + nvme_cmd.timeout_ms, nvme_cmd.result, md, d); #endif nvme_cmd.result = 0; err = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); - if (err == NVME_SC_INTERNAL) { - fprintf(stderr, "%s: WARNING : WDC : No log ID:x%x available\n", - __func__, log_id); - } - else if (err != 0) { - fprintf(stderr, "%s: ERROR : WDC : NVMe Snd Mgmt\n", __func__); + if (nvme_status_equals(err, NVME_STATUS_TYPE_NVME, NVME_SC_INTERNAL)) { + fprintf(stderr, "%s: WARNING : WDC: No log ID:x%x available\n", __func__, log_id); + } else if (err) { + fprintf(stderr, "%s: ERROR: WDC: NVMe Snd Mgmt\n", __func__); nvme_show_status(err); } else { - if (nvme_cmd.result == WDC_RESULT_NOT_AVAILABLE) - { + if (nvme_cmd.result == WDC_RESULT_NOT_AVAILABLE) { free(buf); return WDC_RESULT_NOT_AVAILABLE; } @@ -11009,9 +12200,9 @@ static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, nvme_cmd.result = 0; /* returned result !=0 indicates more data available */ err = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL); - if (err != 0) { + if (err) { more = 0; - fprintf(stderr, "%s: ERROR : WDC : NVMe Rcv Mgmt ", __func__); + fprintf(stderr, "%s: ERROR: WDC: NVMe Rcv Mgmt ", __func__); nvme_show_status(err); } else { more = nvme_cmd.result & WDC_RESULT_MORE_DATA; @@ -11019,7 +12210,7 @@ static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, fwrite(buf, response_size, 1, out); offset += response_size; if (more && (response_size & (sizeof(uint32_t)-1))) { - fprintf(stderr, "%s: ERROR : WDC : NVMe Rcv Mgmt response size:x%x not LW aligned\n", + fprintf(stderr, "%s: ERROR: WDC: NVMe Rcv Mgmt response size:x%x not LW aligned\n", __func__, response_size); } } @@ -11040,13 +12231,13 @@ static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, __u32 xfer_siz __u32 numd; __u16 numdu, numdl; - dump_data = (__u8 *) malloc(sizeof (__u8) * dump_length); - if (dump_data == NULL) { - fprintf(stderr, "%s: ERROR : malloc : %s\n",__func__, strerror(errno)); + dump_data = (__u8 *)malloc(sizeof(__u8) * dump_length); + if (!dump_data) { + fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno)); return -1; } - memset(dump_data, 0, sizeof (__u8) * dump_length); - memset(&admin_cmd, 0, sizeof (struct nvme_passthru_cmd)); + memset(dump_data, 0, sizeof(__u8) * dump_length); + memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd)); curr_data_offset = 0; curr_data_len = xfer_size; i = 0; @@ -11063,14 +12254,16 @@ static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, __u32 xfer_siz while (curr_data_offset < data_len) { #ifdef WDC_NVME_CLI_DEBUG - fprintf(stderr, "nsid 0x%08x addr 0x%08llx, data_len 0x%08x, cdw10 0x%08x, cdw11 0x%08x, cdw12 0x%08x, cdw13 0x%08x, cdw14 0x%08x \n", admin_cmd.nsid, admin_cmd.addr, admin_cmd.data_len, admin_cmd.cdw10, admin_cmd.cdw11, admin_cmd.cdw12, admin_cmd.cdw13, admin_cmd.cdw14); + fprintf(stderr, + "nsid 0x%08x addr 0x%08llx, data_len 0x%08x, cdw10 0x%08x, cdw11 0x%08x, cdw12 0x%08x, cdw13 0x%08x, cdw14 0x%08x\n", + admin_cmd.nsid, admin_cmd.addr, admin_cmd.data_len, admin_cmd.cdw10, + admin_cmd.cdw11, admin_cmd.cdw12, admin_cmd.cdw13, admin_cmd.cdw14); #endif - ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, - NULL); - if (ret != 0) { + ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL); + if (ret) { nvme_show_status(ret); - fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", - __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr); + fprintf(stderr, "%s: ERROR: WDC: Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n", + __func__, i, admin_cmd.data_len, curr_data_offset, (unsigned long)admin_cmd.addr); break; } @@ -11094,3 +12287,159 @@ static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, __u32 xfer_siz free(dump_data); return ret; } + +//------------------------------------------------------------------------------------ +// Description: set latency monitor feature +// +int wdc_set_latency_monitor_feature(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Set Latency Monitor feature."; + + uint64_t capabilities = 0; + struct nvme_dev *dev; + nvme_root_t r; + int ret; + __u32 result; + struct feature_latency_monitor buf = {0,}; + + const char *active_bucket_timer_threshold = + "This is the value that loads the Active Bucket Timer Threshold."; + const char *active_threshold_a = + "This is the value that loads into the Active Threshold A."; + const char *active_threshold_b = + "This is the value that loads into the Active Threshold B."; + const char *active_threshold_c = + "This is the value that loads into the Active Threshold C."; + const char *active_threshold_d = + "This is the value that loads into the Active Threshold D."; + const char *active_latency_config = + "This is the value that loads into the Active Latency Configuration."; + const char *active_latency_minimum_window = + "This is the value that loads into the Active Latency Minimum Window."; + const char *debug_log_trigger_enable = + "This is the value that loads into the Debug Log Trigger Enable."; + const char *discard_debug_log = "Discard Debug Log."; + const char *latency_monitor_feature_enable = "Latency Monitor Feature Enable."; + + struct config { + __u16 active_bucket_timer_threshold; + __u8 active_threshold_a; + __u8 active_threshold_b; + __u8 active_threshold_c; + __u8 active_threshold_d; + __u16 active_latency_config; + __u8 active_latency_minimum_window; + __u16 debug_log_trigger_enable; + __u8 discard_debug_log; + __u8 latency_monitor_feature_enable; + }; + + struct config cfg = { + .active_bucket_timer_threshold = 0x7E0, + .active_threshold_a = 0x5, + .active_threshold_b = 0x13, + .active_threshold_c = 0x1E, + .active_threshold_d = 0x2E, + .active_latency_config = 0xFFF, + .active_latency_minimum_window = 0xA, + .debug_log_trigger_enable = 0, + .discard_debug_log = 0, + .latency_monitor_feature_enable = 0x7, + }; + + OPT_ARGS(opts) = { + OPT_UINT("active_bucket_timer_threshold", 't', + &cfg.active_bucket_timer_threshold, + active_bucket_timer_threshold), + OPT_UINT("active_threshold_a", 'a', &cfg.active_threshold_a, + active_threshold_a), + OPT_UINT("active_threshold_b", 'b', &cfg.active_threshold_b, + active_threshold_b), + OPT_UINT("active_threshold_c", 'c', &cfg.active_threshold_c, + active_threshold_c), + OPT_UINT("active_threshold_d", 'd', &cfg.active_threshold_d, + active_threshold_d), + OPT_UINT("active_latency_config", 'f', + &cfg.active_latency_config, active_latency_config), + OPT_UINT("active_latency_minimum_window", 'w', + &cfg.active_latency_minimum_window, + active_latency_minimum_window), + OPT_UINT("debug_log_trigger_enable", 'r', + &cfg.debug_log_trigger_enable, debug_log_trigger_enable), + OPT_UINT("discard_debug_log", 'l', &cfg.discard_debug_log, + discard_debug_log), + OPT_UINT("latency_monitor_feature_enable", 'e', + &cfg.latency_monitor_feature_enable, + latency_monitor_feature_enable), + OPT_END() + }; + + ret = parse_and_open(&dev, argc, argv, desc, opts); + + if (ret < 0) + return ret; + + /* get capabilities */ + r = nvme_scan(NULL); + wdc_check_device(r, dev); + capabilities = wdc_get_drive_capabilities(r, dev); + + if (!(capabilities & WDC_DRIVE_CAP_SET_LATENCY_MONITOR)) { + fprintf(stderr, "ERROR: WDC: unsupported device for this command\n"); + return -1; + } + + memset(&buf, 0, sizeof(struct feature_latency_monitor)); + + buf.active_bucket_timer_threshold = cfg.active_bucket_timer_threshold; + buf.active_threshold_a = cfg.active_threshold_a; + buf.active_threshold_b = cfg.active_threshold_b; + buf.active_threshold_c = cfg.active_threshold_c; + buf.active_threshold_d = cfg.active_threshold_d; + buf.active_latency_config = cfg.active_latency_config; + buf.active_latency_minimum_window = cfg.active_latency_minimum_window; + buf.debug_log_trigger_enable = cfg.debug_log_trigger_enable; + buf.discard_debug_log = cfg.discard_debug_log; + buf.latency_monitor_feature_enable = cfg.latency_monitor_feature_enable; + + struct nvme_set_features_args args = { + .args_size = sizeof(args), + .fd = dev_fd(dev), + .fid = NVME_FEAT_OCP_LATENCY_MONITOR, + .nsid = 0, + .cdw12 = 0, + .save = 1, + .data_len = sizeof(struct feature_latency_monitor), + .data = (void *)&buf, + .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, + .result = &result, + }; + + ret = nvme_set_features(&args); + + if (ret < 0) { + perror("set-feature"); + } else if (!ret) { + printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n", + NVME_FEAT_OCP_LATENCY_MONITOR); + printf("active bucket timer threshold: 0x%x\n", + buf.active_bucket_timer_threshold); + printf("active threshold a: 0x%x\n", buf.active_threshold_a); + printf("active threshold b: 0x%x\n", buf.active_threshold_b); + printf("active threshold c: 0x%x\n", buf.active_threshold_c); + printf("active threshold d: 0x%x\n", buf.active_threshold_d); + printf("active latency config: 0x%x\n", buf.active_latency_config); + printf("active latency minimum window: 0x%x\n", + buf.active_latency_minimum_window); + printf("debug log trigger enable: 0x%x\n", + buf.debug_log_trigger_enable); + printf("discard debug log: 0x%x\n", buf.discard_debug_log); + printf("latency monitor feature enable: 0x%x\n", + buf.latency_monitor_feature_enable); + } else if (ret > 0) + fprintf(stderr, "NVMe Status:%s(%x)\n", + nvme_status_to_string(ret, false), ret); + + return ret; +} diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h index ab403dcdbe..d1f87406bd 100644 --- a/plugins/wdc/wdc-nvme.h +++ b/plugins/wdc/wdc-nvme.h @@ -5,7 +5,7 @@ #if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ) #define WDC_NVME -#define WDC_PLUGIN_VERSION "2.1.1" +#define WDC_PLUGIN_VERSION "2.8.0" #include "cmd.h" PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION), @@ -17,34 +17,72 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERS 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-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("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-fw-activate-history", "WDC Get FW Activate History", + wdc_vs_fw_activate_history) + ENTRY("clear-fw-activate-history", + "WDC Clear FW Activate History", + wdc_clear_fw_activate_history) ENTRY("enc-get-log", "WDC Get Enclosure Log", wdc_enc_get_log) - ENTRY("vs-telemetry-controller-option", "WDC Enable/Disable Controller Initiated Telemetry Log", wdc_vs_telemetry_controller_option) - ENTRY("vs-error-reason-identifier", "WDC Telemetry Reason Identifier", wdc_reason_identifier) - ENTRY("log-page-directory", "WDC Get Log Page Directory", wdc_log_page_directory) - ENTRY("namespace-resize", "WDC NamespaceDrive Resize", wdc_namespace_resize) + ENTRY("vs-telemetry-controller-option", + "WDC Enable/Disable Controller Initiated Telemetry Log", + wdc_vs_telemetry_controller_option) + ENTRY("vs-error-reason-identifier", + "WDC Telemetry Reason Identifier", + wdc_reason_identifier) + ENTRY("log-page-directory", "WDC Get Log Page Directory", + wdc_log_page_directory) + ENTRY("namespace-resize", "WDC NamespaceDrive Resize", + wdc_namespace_resize) ENTRY("vs-drive-info", "WDC Get Drive Info", wdc_vs_drive_info) - ENTRY("vs-temperature-stats", "WDC Get Temperature Stats", wdc_vs_temperature_stats) - ENTRY("capabilities", "WDC Device Capabilities", wdc_capabilities) - ENTRY("cloud-SSD-plugin-version", "WDC Cloud SSD Plugin Version", wdc_cloud_ssd_plugin_version) - ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics", wdc_vs_pcie_stats) - ENTRY("get-latency-monitor-log", "WDC Get Latency Monitor Log Page", wdc_get_latency_monitor_log) - ENTRY("get-error-recovery-log", "WDC Get Error Recovery Log Page", wdc_get_error_recovery_log) - ENTRY("get-dev-capabilities-log", "WDC Get Device Capabilities Log Page", wdc_get_dev_capabilities_log) - ENTRY("get-unsupported-reqs-log", "WDC Get Unsupported Requirements Log Page", wdc_get_unsupported_reqs_log) - ENTRY("cloud-boot-SSD-version", "WDC Get the Cloud Boot SSD Version", wdc_cloud_boot_SSD_version) - ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page", wdc_vs_cloud_log) - ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page", wdc_vs_hw_rev_log) - ENTRY("vs-device-waf", "WDC Calculate Device Write Amplication Factor", wdc_vs_device_waf) + ENTRY("vs-temperature-stats", "WDC Get Temperature Stats", + wdc_vs_temperature_stats) + ENTRY("capabilities", "WDC Device Capabilities", + wdc_capabilities) + ENTRY("cloud-SSD-plugin-version", + "WDC Cloud SSD Plugin Version", + wdc_cloud_ssd_plugin_version) + ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics", + wdc_vs_pcie_stats) + ENTRY("get-latency-monitor-log", + "WDC Get Latency Monitor Log Page", + wdc_get_latency_monitor_log) + ENTRY("get-error-recovery-log", + "WDC Get Error Recovery Log Page", + wdc_get_error_recovery_log) + ENTRY("get-dev-capabilities-log", + "WDC Get Device Capabilities Log Page", + wdc_get_dev_capabilities_log) + ENTRY("get-unsupported-reqs-log", + "WDC Get Unsupported Requirements Log Page", + wdc_get_unsupported_reqs_log) + ENTRY("cloud-boot-SSD-version", + "WDC Get the Cloud Boot SSD Version", + wdc_cloud_boot_SSD_version) + ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page", + wdc_vs_cloud_log) + ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page", + wdc_vs_hw_rev_log) + ENTRY("vs-device-waf", + "WDC Calculate Device Write Amplication Factor", + wdc_vs_device_waf) + ENTRY("set-latency-monitor-feature", + "WDC set Latency Monitor feature", + wdc_set_latency_monitor_feature) ) ); diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c index 38e61ed2cc..1b52e7c04a 100644 --- a/plugins/wdc/wdc-utils.c +++ b/plugins/wdc/wdc-utils.c @@ -24,6 +24,9 @@ #include #include #include +#include "nvme.h" +#include "libnvme.h" +#include "nvme-print.h" #include "wdc-utils.h" int wdc_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer, const char *format, ...) @@ -38,7 +41,7 @@ int wdc_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer, const char *forma return res; } -void wdc_UtilsDeleteCharFromString(char* buffer, int buffSize, char charToRemove) +void wdc_UtilsDeleteCharFromString(char *buffer, int buffSize, char charToRemove) { int i = 0; int count = 0; @@ -62,7 +65,7 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo) time_t currTime; struct tm currTimeInfo; - if(!timeInfo) + if (!timeInfo) return WDC_STATUS_INVALID_PARAMETER; tzset(); @@ -81,7 +84,7 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo) #if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__) timeInfo->zone = -currTimeInfo.tm_gmtoff / 60; #else - timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN); + timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN); #endif return WDC_STATUS_SUCCESS; @@ -92,7 +95,7 @@ int wdc_UtilsCreateDir(char *path) int retStatus; int status = WDC_STATUS_SUCCESS; - if (!path ) + if (!path) return WDC_STATUS_INVALID_PARAMETER; retStatus = mkdir(path, 0x999); @@ -125,7 +128,7 @@ int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen) status = WDC_STATUS_UNABLE_TO_WRITE_ALL_DATA; end: - if(file) + if (file) fclose(file); return status; } @@ -133,8 +136,8 @@ int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen) /** * 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. + * @param pcSrc Points to a null terminated string for comparing. + * @param pcDst Points to a null terminated string for comparing. * * @returns zero if the string matches or * 1 if the pcSrc string is lexically higher than pcDst or @@ -151,9 +154,7 @@ int wdc_UtilsStrCompare(char *pcSrc, char *pcDst) void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz) { - - fmt_sz = snprintf(formatter,fmt_sz, "%-*.*s", - (int)tofmtsz, (int)tofmtsz, tofmt); + 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') { @@ -164,3 +165,32 @@ void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz) } } +bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uuid_list) +{ + int err; + struct nvme_id_ctrl ctrl; + + memset(&ctrl, 0, sizeof(struct nvme_id_ctrl)); + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) { + fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", err); + return false; + } + + if ((ctrl.ctratt & NVME_CTRL_CTRATT_UUID_LIST) == NVME_CTRL_CTRATT_UUID_LIST) { + err = nvme_identify_uuid(dev_fd(dev), uuid_list); + if (!err) + return true; + else if (err > 0) + nvme_show_status(err); + else + nvme_show_error("identify UUID list: %s", nvme_strerror(errno)); + } + + return false; +} + +bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2) +{ + return !memcmp(entry1->uuid, entry2->uuid, NVME_UUID_LEN); +} diff --git a/plugins/wdc/wdc-utils.h b/plugins/wdc/wdc-utils.h index 83b208eec4..3fc47ca21a 100644 --- a/plugins/wdc/wdc-utils.h +++ b/plugins/wdc/wdc-utils.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -76,4 +77,5 @@ int wdc_UtilsStrCompare(char *pcSrc, char *pcDst); int wdc_UtilsCreateDir(char *path); int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen); void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz); - +bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uuid_list); +bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2); diff --git a/plugins/ymtc/ymtc-nvme.c b/plugins/ymtc/ymtc-nvme.c index d04481c8ce..5568c80f50 100644 --- a/plugins/ymtc/ymtc-nvme.c +++ b/plugins/ymtc/ymtc-nvme.c @@ -17,145 +17,145 @@ static void get_ymtc_smart_info(struct nvme_ymtc_smart_log *smart, int index, u8 *nm_val, u8 *raw_val) { - memcpy(nm_val, smart->itemArr[index].nmVal, NM_SIZE); - memcpy(raw_val, smart->itemArr[index].rawVal, RAW_SIZE); + memcpy(nm_val, smart->itemArr[index].nmVal, NM_SIZE); + memcpy(raw_val, smart->itemArr[index].rawVal, RAW_SIZE); } static int show_ymtc_smart_log(struct nvme_dev *dev, __u32 nsid, struct nvme_ymtc_smart_log *smart) { - struct nvme_id_ctrl ctrl; - char fw_ver[10]; - int err = 0; - - u8 *nm = malloc(NM_SIZE * sizeof(u8)); - u8 *raw = malloc(RAW_SIZE * sizeof(u8)); - - if (!nm) { - if (raw) - free(raw); - return -1; - } - if (!raw) { - free(nm); - return -1; - } - err = nvme_identify_ctrl(dev_fd(dev), &ctrl); - if (err) { - free(nm); - free(raw); - return err; - } - - snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c", - ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3], - ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]); - - /* Table Title */ - printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", - dev->name, nsid); - /* Clumn Name*/ - printf("key normalized raw\n"); - /* 00 SI_VD_PROGRAM_FAIL */ - get_ymtc_smart_info(smart, SI_VD_PROGRAM_FAIL, nm, raw); - printf("program_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 01 SI_VD_ERASE_FAIL */ - get_ymtc_smart_info(smart, SI_VD_ERASE_FAIL, nm, raw); - printf("erase_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 02 SI_VD_WEARLEVELING_COUNT */ - get_ymtc_smart_info(smart, SI_VD_WEARLEVELING_COUNT, nm, raw); - printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", *nm, - *(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(raw+4)); - /* 03 SI_VD_E2E_DECTECTION_COUNT */ - get_ymtc_smart_info(smart, SI_VD_E2E_DECTECTION_COUNT, nm, raw); - printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 04 SI_VD_PCIE_CRC_ERR_COUNT */ - get_ymtc_smart_info(smart, SI_VD_PCIE_CRC_ERR_COUNT, nm, raw); - printf("crc_error_count : %3d%% %"PRIu32"\n", *nm, *(uint32_t *)raw); - /* 08 SI_VD_THERMAL_THROTTLE_STATUS */ - get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw); - printf("thermal_throttle_status : %3d%% %d%%, cnt: %"PRIu32"\n", *nm, - *raw, *(uint32_t *)(raw+1)); - /* 11 SI_VD_TOTAL_WRITE */ - get_ymtc_smart_info(smart, SI_VD_TOTAL_WRITE, nm, raw); - printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 12 SI_VD_HOST_WRITE */ - get_ymtc_smart_info(smart, SI_VD_HOST_WRITE, nm, raw); - printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 14 SI_VD_TOTAL_READ */ - get_ymtc_smart_info(smart, SI_VD_TOTAL_READ, nm, raw); - printf("nand_bytes_read : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 15 SI_VD_TEMPT_SINCE_BORN */ - get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BORN, nm, raw); - printf("tempt_since_born : %3d%% max: %u, min: %u, curr: %u\n", *nm, - *(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(int16_t *)(raw+4)-273); - /* 16 SI_VD_POWER_CONSUMPTION */ - get_ymtc_smart_info(smart, SI_VD_POWER_CONSUMPTION, nm, raw); - printf("power_consumption : %3d%% max: %u, min: %u, curr: %u\n", *nm, - *(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(raw+4)); - /* 17 SI_VD_TEMPT_SINCE_BOOTUP */ - get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BOOTUP, nm, raw); - printf("tempt_since_bootup : %3d%% max: %u, min: %u, curr: %u\n", *nm, - *(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(uint16_t *)(raw+4)-273); - /* 18 SI_VD_POWER_LOSS_PROTECTION */ - get_ymtc_smart_info(smart, SI_VD_POWER_LOSS_PROTECTION, nm, raw); - printf("power_loss_protection : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 19 SI_VD_READ_FAIL */ - get_ymtc_smart_info(smart, SI_VD_READ_FAIL, nm, raw); - printf("read_fail : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - /* 20 SI_VD_THERMAL_THROTTLE_TIME */ - get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_TIME, nm, raw); - printf("thermal_throttle_time : %3d%% %u, time: %"PRIu32"\n", *nm, - *raw, *(uint32_t *)(raw+1)); - /* 21 SI_VD_FLASH_MEDIA_ERROR */ - get_ymtc_smart_info(smart, SI_VD_FLASH_MEDIA_ERROR, nm, raw); - printf("flash_error_media_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); - - free(nm); - free(raw); - - return err; + struct nvme_id_ctrl ctrl; + char fw_ver[10]; + int err = 0; + + u8 *nm = malloc(NM_SIZE * sizeof(u8)); + u8 *raw = malloc(RAW_SIZE * sizeof(u8)); + + if (!nm) { + if (raw) + free(raw); + return -1; + } + if (!raw) { + free(nm); + return -1; + } + err = nvme_identify_ctrl(dev_fd(dev), &ctrl); + if (err) { + free(nm); + free(raw); + return err; + } + + snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c", + ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3], + ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]); + + /* Table Title */ + printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", + dev->name, nsid); + /* Column Name*/ + printf("key normalized raw\n"); + /* 00 SI_VD_PROGRAM_FAIL */ + get_ymtc_smart_info(smart, SI_VD_PROGRAM_FAIL, nm, raw); + printf("program_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 01 SI_VD_ERASE_FAIL */ + get_ymtc_smart_info(smart, SI_VD_ERASE_FAIL, nm, raw); + printf("erase_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 02 SI_VD_WEARLEVELING_COUNT */ + get_ymtc_smart_info(smart, SI_VD_WEARLEVELING_COUNT, nm, raw); + printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", *nm, + *(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(raw+4)); + /* 03 SI_VD_E2E_DECTECTION_COUNT */ + get_ymtc_smart_info(smart, SI_VD_E2E_DECTECTION_COUNT, nm, raw); + printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 04 SI_VD_PCIE_CRC_ERR_COUNT */ + get_ymtc_smart_info(smart, SI_VD_PCIE_CRC_ERR_COUNT, nm, raw); + printf("crc_error_count : %3d%% %"PRIu32"\n", *nm, *(uint32_t *)raw); + /* 08 SI_VD_THERMAL_THROTTLE_STATUS */ + get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw); + printf("thermal_throttle_status : %3d%% %d%%, cnt: %"PRIu32"\n", *nm, + *raw, *(uint32_t *)(raw+1)); + /* 11 SI_VD_TOTAL_WRITE */ + get_ymtc_smart_info(smart, SI_VD_TOTAL_WRITE, nm, raw); + printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 12 SI_VD_HOST_WRITE */ + get_ymtc_smart_info(smart, SI_VD_HOST_WRITE, nm, raw); + printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 14 SI_VD_TOTAL_READ */ + get_ymtc_smart_info(smart, SI_VD_TOTAL_READ, nm, raw); + printf("nand_bytes_read : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 15 SI_VD_TEMPT_SINCE_BORN */ + get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BORN, nm, raw); + printf("tempt_since_born : %3d%% max: %u, min: %u, curr: %u\n", *nm, + *(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(int16_t *)(raw+4)-273); + /* 16 SI_VD_POWER_CONSUMPTION */ + get_ymtc_smart_info(smart, SI_VD_POWER_CONSUMPTION, nm, raw); + printf("power_consumption : %3d%% max: %u, min: %u, curr: %u\n", *nm, + *(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(raw+4)); + /* 17 SI_VD_TEMPT_SINCE_BOOTUP */ + get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BOOTUP, nm, raw); + printf("tempt_since_bootup : %3d%% max: %u, min: %u, curr: %u\n", *nm, + *(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(uint16_t *)(raw+4)-273); + /* 18 SI_VD_POWER_LOSS_PROTECTION */ + get_ymtc_smart_info(smart, SI_VD_POWER_LOSS_PROTECTION, nm, raw); + printf("power_loss_protection : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 19 SI_VD_READ_FAIL */ + get_ymtc_smart_info(smart, SI_VD_READ_FAIL, nm, raw); + printf("read_fail : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + /* 20 SI_VD_THERMAL_THROTTLE_TIME */ + get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_TIME, nm, raw); + printf("thermal_throttle_time : %3d%% %u, time: %"PRIu32"\n", *nm, + *raw, *(uint32_t *)(raw+1)); + /* 21 SI_VD_FLASH_MEDIA_ERROR */ + get_ymtc_smart_info(smart, SI_VD_FLASH_MEDIA_ERROR, nm, raw); + printf("flash_error_media_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw)); + + free(nm); + free(raw); + + return err; } static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - struct nvme_ymtc_smart_log smart_log; - char *desc = "Get Ymtc vendor specific additional smart log (optionally, "\ - "for the specified namespace), and show it."; - const char *namespace = "(optional) desired namespace"; - const char *raw = "dump output in binary format"; - struct nvme_dev *dev; - struct config { - __u32 namespace_id; - bool raw_binary; - }; - int err; - - struct config cfg = { - .namespace_id = NVME_NSID_ALL, - }; - - OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), - OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), - OPT_END() - }; - - err = parse_and_open(&dev, argc, argv, desc, opts); - if (err) - return err; - - err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id, - sizeof(smart_log), &smart_log); - if (!err) { - if (!cfg.raw_binary) - err = show_ymtc_smart_log(dev, cfg.namespace_id, &smart_log); - else - d_raw((unsigned char *)&smart_log, sizeof(smart_log)); - } - if (err > 0) - nvme_show_status(err); - - dev_close(dev); - return err; + struct nvme_ymtc_smart_log smart_log; + char *desc = + "Get Ymtc vendor specific additional smart log (optionally, for the specified namespace), and show it."; + const char *namespace = "(optional) desired namespace"; + const char *raw = "dump output in binary format"; + struct nvme_dev *dev; + struct config { + __u32 namespace_id; + bool raw_binary; + }; + int err; + + struct config cfg = { + .namespace_id = NVME_NSID_ALL, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), + OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), + OPT_END() + }; + + err = parse_and_open(&dev, argc, argv, desc, opts); + if (err) + return err; + + err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id, + sizeof(smart_log), &smart_log); + if (!err) { + if (!cfg.raw_binary) + err = show_ymtc_smart_log(dev, cfg.namespace_id, &smart_log); + else + d_raw((unsigned char *)&smart_log, sizeof(smart_log)); + } + if (err > 0) + nvme_show_status(err); + + dev_close(dev); + return err; } diff --git a/plugins/ymtc/ymtc-utils.h b/plugins/ymtc/ymtc-utils.h index 39f79cb5a9..e9a3572513 100644 --- a/plugins/ymtc/ymtc-utils.h +++ b/plugins/ymtc/ymtc-utils.h @@ -34,7 +34,7 @@ typedef unsigned char u8; #define SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB #define SI_VD_FLASH_MEDIA_ERROR_ID 0xED -/* Addtional smart internal ID */ +/* Additional smart internal ID */ typedef enum { /* smart attr following intel */ diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index ffa45eb159..a7a37663b5 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -12,6 +12,7 @@ #include "nvme.h" #include "libnvme.h" #include "nvme-print.h" +#include "util/cleanup.h" #define CREATE_CMD #include "zns.h" @@ -49,9 +50,8 @@ static int print_zns_list_ns(nvme_ns_t ns) return err; } - if (supported) { + if (supported) nvme_show_list_item(ns); - } return err; } @@ -63,21 +63,17 @@ static int print_zns_list(nvme_root_t nvme_root) nvme_subsystem_t s; nvme_ctrl_t c; nvme_ns_t n; - nvme_for_each_host(nvme_root, h) - { - nvme_for_each_subsystem(h, s) - { - nvme_subsystem_for_each_ns(s, n) - { + + nvme_for_each_host(nvme_root, h) { + nvme_for_each_subsystem(h, s) { + nvme_subsystem_for_each_ns(s, n) { err = print_zns_list_ns(n); if (err) return err; } - nvme_subsystem_for_each_ctrl(s, c) - { - nvme_ctrl_for_each_ns(c, n) - { + nvme_subsystem_for_each_ctrl(s, c) { + nvme_ctrl_for_each_ns(c, n) { err = print_zns_list_ns(n); if (err) return err; @@ -114,9 +110,9 @@ static int list(int argc, char **argv, struct command *cmd, static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an ZNS specific Identify Controller command to "\ - "the given device and report information about the specified "\ - "controller in various formats."; + const char *desc = "Send a ZNS specific Identify Controller command to\n" + "the given device and report information about the specified\n" + "controller in various formats."; enum nvme_print_flags flags; struct nvme_zns_id_ctrl ctrl; @@ -140,9 +136,9 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl if (err) return errno; - err = flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_fd; + err = validate_output_format(cfg.output_format, &flags); + if (err < 0) + goto close_dev; err = nvme_zns_identify_ctrl(dev_fd(dev), &ctrl); if (!err) @@ -151,16 +147,16 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl nvme_show_status(err); else perror("zns identify controller"); -close_fd: +close_dev: dev_close(dev); return err; } static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Send an ZNS specific Identify Namespace command to "\ - "the given device and report information about the specified "\ - "namespace in varios formats."; + const char *desc = "Send a ZNS specific Identify Namespace command to\n" + "the given device and report information about the specified\n" + "namespace in varios formats."; const char *vendor_specific = "dump binary vendor fields"; const char *human_readable = "show identify in readable format"; @@ -193,9 +189,9 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug if (err) return errno; - flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_fd; + err = validate_output_format(cfg.output_format, &flags); + if (err < 0) + goto close_dev; if (cfg.vendor_specific) flags |= VS; if (cfg.human_readable) @@ -205,14 +201,14 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); - goto close_fd; + goto close_dev; } } err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id, &id_ns); if (err) { nvme_show_status(err); - goto close_fd; + goto close_dev; } err = nvme_zns_identify_ns(dev_fd(dev), cfg.namespace_id, &ns); @@ -222,7 +218,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug nvme_show_status(err); else perror("zns identify namespace"); -close_fd: +close_dev: dev_close(dev); return err; } @@ -292,11 +288,11 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug printf("%s: Success, action:%d zone:%"PRIx64" all:%d zcapc:%u nsid:%d\n", command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all, zcapc, cfg.namespace_id); - } - else if (err > 0) + } else if (err > 0) { nvme_show_status(err); - else + } else { perror(desc); + } free: free(command); close_dev: @@ -337,8 +333,8 @@ static int get_zdes_bytes(int fd, __u32 nsid) static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Zone Management Send"; - const char *zslba = "starting LBA of the zone for this command"\ - "(for flush action, last lba to flush)"; + const char *zslba = + "starting LBA of the zone for this command(for flush action, last lba to flush)"; const char *zsaso = "Zone Send Action Specific Option"; const char *select_all = "send command to all zones"; const char *zsa = "zone send action"; @@ -356,8 +352,8 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu bool zsaso; bool select_all; __u8 zsa; - int data_len; - char *file; + int data_len; + char *file; __u32 timeout; }; @@ -394,13 +390,12 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu } if (cfg.zsa == NVME_ZNS_ZSA_SET_DESC_EXT) { - if(!cfg.data_len) { + if (!cfg.data_len) { int data_len = get_zdes_bytes(dev_fd(dev), cfg.namespace_id); if (data_len == 0) { - fprintf(stderr, - "Zone Descriptor Extensions are not supported\n"); + fprintf(stderr, "Zone Descriptor Extensions are not supported\n"); goto close_dev; } else if (data_len < 0) { err = data_len; @@ -429,8 +424,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu } } else { if (cfg.file || cfg.data_len) { - fprintf(stderr, - "data, data_len only valid with set extended descriptor\n"); + fprintf(stderr, "data, data_len only valid with set extended descriptor\n"); err = -EINVAL; goto close_dev; } @@ -451,10 +445,8 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu }; err = nvme_zns_mgmt_send(&args); if (!err) - printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" " - "all:%d nsid:%d\n", - cfg.zsa, (uint64_t)cfg.zslba, (int)cfg.select_all, - cfg.namespace_id); + printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" all:%d nsid:%d\n", + cfg.zsa, (uint64_t)cfg.zslba, (int)cfg.select_all, cfg.namespace_id); else if (err > 0) nvme_show_status(err); else @@ -542,7 +534,7 @@ static int open_zone(int argc, char **argv, struct command *cmd, struct plugin * err = nvme_zns_mgmt_send(&args); if (!err) printf("zns-open-zone: Success zone slba:%"PRIx64" nsid:%d\n", - (uint64_t)cfg.zslba, cfg.namespace_id); + (uint64_t)cfg.zslba, cfg.namespace_id); else nvme_show_status(err); close_dev: @@ -569,7 +561,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug const char *desc = "Set Zone Descriptor Extension\n"; const char *zslba = "starting LBA of the zone for this command"; const char *zrwaa = "Allocate Zone Random Write Area to zone"; - const char *data = "optional file for zone extention data (default stdin)"; + const char *data = "optional file for zone extension data (default stdin)"; const char *timeout = "timeout value, in milliseconds"; int ffd = STDIN_FILENO, err; @@ -612,7 +604,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug if (!data_len || data_len < 0) { fprintf(stderr, - "zone format does not provide descriptor extention\n"); + "zone format does not provide descriptor extension\n"); errno = EINVAL; err = -1; goto close_dev; @@ -656,7 +648,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug err = nvme_zns_mgmt_send(&args); if (!err) printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n", - (uint64_t)cfg.zslba, cfg.namespace_id); + (uint64_t)cfg.zslba, cfg.namespace_id); else if (err > 0) nvme_show_status(err); else @@ -723,7 +715,7 @@ static int zrwa_flush_zone(int argc, char **argv, struct command *cmd, struct pl err = nvme_zns_mgmt_send(&args); if (!err) printf("zrwa-flush-zone: Success, lba:%"PRIx64" nsid:%d\n", - (uint64_t)cfg.lba, cfg.namespace_id); + (uint64_t)cfg.lba, cfg.namespace_id); else nvme_show_status(err); close_dev: @@ -737,7 +729,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu const char *zslba = "starting LBA of the zone"; const char *zra = "Zone Receive Action"; const char *zrasf = "Zone Receive Action Specific Field(Reporting Options)"; - const char *partial = "Zone Receive Action Specific Features(Partial Report)"; + const char *partial = "Zone Receive Action Specific Features(Partial Report)"; const char *data_len = "length of data in bytes"; enum nvme_print_flags flags; @@ -774,8 +766,8 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu if (err) return errno; - flags = validate_output_format(cfg.output_format); - if (flags < 0) + err = validate_output_format(cfg.output_format, &flags); + if (err < 0) goto close_dev; if (!cfg.namespace_id) { @@ -816,7 +808,7 @@ static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plu err = nvme_zns_mgmt_recv(&args); if (!err) printf("zone-mgmt-recv: Success, action:%d zone:%"PRIx64" nsid:%d\n", - cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id); + cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id); else if (err > 0) nvme_show_status(err); else @@ -842,21 +834,20 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi int zdes = 0, err = -1; struct nvme_dev *dev; __u32 report_size; - void *report; - bool huge = false; - struct nvme_zone_report *buff; + struct nvme_zone_report *report, *buff; + _cleanup_huge_ struct nvme_mem_huge mh = { 0, }; unsigned int nr_zones_chunks = 1024, /* 1024 entries * 64 bytes per entry = 64k byte transfer */ nr_zones_retrieved = 0, nr_zones, - offset, log_len; + __u64 offset; int total_nr_zones = 0; struct nvme_zns_id_ns id_zns; struct nvme_id_ns id_ns; uint8_t lbaf; __le64 zsze; - struct json_object *zone_list = 0; + struct json_object *zone_list = NULL; struct config { char *output_format; @@ -890,8 +881,8 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi if (err) return errno; - flags = validate_output_format(cfg.output_format); - if (flags < 0) + err = validate_output_format(cfg.output_format, &flags); + if (err < 0) goto close_dev; if (cfg.verbose) flags |= VERBOSE; @@ -922,9 +913,8 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi if (!err) { /* get zsze field from zns id ns data - needed for offset calculation */ nvme_id_ns_flbas_to_lbaf_inuse(id_ns.flbas, &lbaf); - zsze = le64_to_cpu(id_zns.lbafe[lbaf].zsze); - } - else { + zsze = le64_to_cpu(id_zns.lbafe[lbaf].zsze); + } else { nvme_show_status(err); goto close_dev; } @@ -943,17 +933,15 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi if (err > 0) { nvme_show_status(err); goto free_buff; - } - else if (err < 0) { + } else if (err < 0) { perror("zns report-zones"); goto free_buff; } total_nr_zones = le64_to_cpu(buff->nr_zones); - if (cfg.num_descs == -1) { + if (cfg.num_descs == -1) cfg.num_descs = total_nr_zones; - } nr_zones = cfg.num_descs; if (nr_zones < nr_zones_chunks) @@ -962,7 +950,7 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi log_len = sizeof(struct nvme_zone_report) + ((sizeof(struct nvme_zns_desc) * nr_zones_chunks) + (nr_zones_chunks * zdes)); report_size = log_len; - report = nvme_alloc(report_size, &huge); + report = nvme_alloc_huge(report_size, &mh); if (!report) { perror("alloc"); err = -ENOMEM; @@ -970,10 +958,8 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi } offset = cfg.zslba; - if (flags & JSON) - zone_list = json_create_array(); - else - printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(total_nr_zones)); + + nvme_zns_start_zone_list(total_nr_zones, &zone_list, flags); while (nr_zones_retrieved < nr_zones) { if (nr_zones_retrieved >= nr_zones) @@ -995,17 +981,14 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi } if (!err) - nvme_show_zns_report_zones(report, nr_zones_chunks, - zdes, log_len, flags, zone_list); + nvme_show_zns_report_zones(report, nr_zones_chunks, + zdes, log_len, zone_list, flags); nr_zones_retrieved += nr_zones_chunks; - offset = (nr_zones_retrieved * zsze); - } - - if (flags & JSON) - json_nvme_finish_zone_list(total_nr_zones, zone_list); + offset = le64_to_cpu(report->entries[nr_zones_chunks-1].zslba) + zsze; + } - nvme_free(report, huge); + nvme_zns_finish_zone_list(total_nr_zones, zone_list, flags); free_buff: free(buff); @@ -1016,9 +999,9 @@ static int report_zones(int argc, char **argv, struct command *cmd, struct plugi static int zone_append(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "The zone append command is used to write to a zone "\ - "using the slba of the zone, and the write will be appended from the "\ - "write pointer of the zone"; + const char *desc = "The zone append command is used to write to a zone\n" + "using the slba of the zone, and the write will be appended from the\n" + "write pointer of the zone"; const char *zslba = "starting LBA of the zone"; const char *data = "file containing data to write"; const char *metadata = "file with metadata to be written"; @@ -1117,7 +1100,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin meta_size = ns.lbaf[lba_index].ms; if (meta_size && !(meta_size == 8 && (cfg.prinfo & 0x8)) && - (!cfg.metadata_size || cfg.metadata_size % meta_size)) { + (!cfg.metadata_size || cfg.metadata_size % meta_size)) { fprintf(stderr, "Metadata size:%#"PRIx64" not aligned to metadata size:%#x\n", (uint64_t)cfg.metadata_size, meta_size); @@ -1126,7 +1109,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin } if (cfg.prinfo > 0xf) { - fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo); + fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo); errno = EINVAL; goto close_dev; } @@ -1209,7 +1192,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin gettimeofday(&end_time, NULL); if (cfg.latency) printf(" latency: zone append: %llu us\n", - elapsed_utime(start_time, end_time)); + elapsed_utime(start_time, end_time)); if (!err) printf("Success appended data to LBA %"PRIx64"\n", (uint64_t)result); @@ -1264,15 +1247,15 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct if (err) return errno; - flags = validate_output_format(cfg.output_format); - if (flags < 0) - goto close_fd; + err = validate_output_format(cfg.output_format, &flags); + if (err < 0) + goto close_dev; if (!cfg.namespace_id) { err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id); if (err < 0) { perror("get-namespace-id"); - goto close_fd; + goto close_dev; } } @@ -1285,7 +1268,7 @@ static int changed_zone_list(int argc, char **argv, struct command *cmd, struct else perror("zns changed-zone-list"); -close_fd: +close_dev: dev_close(dev); return err; } diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h index 77bfdd66ab..43c4ecd1b0 100644 --- a/plugins/zns/zns.h +++ b/plugins/zns/zns.h @@ -15,7 +15,7 @@ PLUGIN(NAME("zns", "Zoned Namespace Command Set", NVME_VERSION), ENTRY("report-zones", "Report zones associated to a Zoned Namespace", report_zones) ENTRY("reset-zone", "Reset one or more zones", reset_zone) ENTRY("close-zone", "Close one or more zones", close_zone) - ENTRY("finish-zone", "Finishe one or more zones", finish_zone) + ENTRY("finish-zone", "Finish one or more zones", finish_zone) ENTRY("open-zone", "Open one or more zones", open_zone) ENTRY("offline-zone", "Offline one or more zones", offline_zone) ENTRY("set-zone-desc", "Attach zone descriptor extension data to a zone", set_zone_desc) diff --git a/release.sh b/release.sh deleted file mode 100755 index 320da46a34..0000000000 --- a/release.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash - -usage() { - echo "Usage: release.sh [-d] VERSION" - echo "" - echo "The script does all necessary steps to create a new release." - echo "" - echo " -d: no documentation update" - echo "" - echo "Note: The version number needs to be exactly" - echo " '^v[\d]+.[\d]+(.[\d\]+(-rc[0-9]+)?$'" - echo "" - echo "example:" - echo " release.sh v2.1-rc0 # v2.1 release candidate 0" - echo " release.sh v2.1 # v2.1 release" -} - -build_doc=true - -while getopts "d" o; do - case "${o}" in - d) - build_doc=false - ;; - *) - usage - ;; - esac -done -shift $((OPTIND-1)) - -VERSION=${1:-} - -if [ -z "$VERSION" ] ; then - usage - exit 1 -fi - -ver="" - -re='^v([0-9]+\.[0-9]+(\.[0-9]+)?)(-rc[0-9]+)?$' -if [[ "$VERSION" =~ $re ]]; then - echo "Valid version $VERSION string" - # remove the leading 'v' - ver=${VERSION#v} -else - echo "Invalid version string $VERSION" - exit 1 -fi - -if [[ -n $(git status -s) ]]; then - echo "tree is dirty. abort." - exit 1 -fi - -if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ] ; then - echo "currently not on master branch. abort." - exit 1 -fi - -# update all docs -doc_dir="" -if [ -d "Documentation" ]; then - doc_dir="Documentation" -elif [ -d "doc" ]; then - doc_dir="doc" -else - echo "documenation directory not found" - exit 1 -fi - -# update meson.build -sed -i -e "0,/[ \t]version: /s/\([ \t]version: \).*/\1\'$ver\',/" meson.build -git add meson.build -git commit -s -m "build: Update version to $VERSION" - -if [ "$build_doc" = true ]; then - # update documentation - ./$doc_dir/update-docs.sh - git add $doc_dir - git commit -s -m "doc: Regenerate all docs for $VERSION" -fi - -git tag -s -m "Release $VERSION" "$VERSION" -git push --dry-run origin "$VERSION"^{}:master tag "$VERSION" - -read -p "All good? Ready to push changes to remote? [Yy]" -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - git push origin "$VERSION"^{}:master tag "$VERSION" -fi diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000000..470f39a885 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,230 @@ +#!/bin/bash +set -e + +usage() { + echo "Usage: build.sh [-b [release|debug]] " + echo " [-c [gcc|clang]]" + echo " [-m [meson|muon]" + echo " [config]" + echo "" + echo "CI build script." + echo "" + echo " -b [release]|debug build type" + echo " -c [gcc]|clang compiler to use" + echo " -m [meson]|muon use meson or muon" + echo " -t [arm]|ppc64le|s390x cross compile target" + echo "" + echo "configs with meson:" + echo " [default] default settings" + echo " fallback download all dependencies" + echo " and build them as shared libraries" + echo " cross use cross toolchain to build" + echo " coverage build coverage report" + echo " appimage build AppImage target" + echo "" + echo "configs with muon:" + echo " [default] minimal static build" +} + +BUILDTOOL=meson +MESON=meson +BUILDTYPE=release +CROSS_TARGET=arm +CC=${CC:-"gcc"} + +while getopts "b:c:m:t:" o; do + case "${o}" in + b) + BUILDTYPE="${OPTARG}" + ;; + c) + CC="${OPTARG}" + ;; + m) + BUILDTOOL="${OPTARG}" + ;; + t) + CROSS_TARGET="${OPTARG}" + ;; + *) + usage + exit 1 + ;; + esac +done +shift $((OPTIND-1)) + +CONFIG=${1:-"default"} + +cd "$(git rev-parse --show-toplevel)" || exit 1 + +BUILDDIR="$(pwd)/.build-ci" +TOOLDIR="$(pwd)/.build-tools" + +fn_exists() { declare -F "$1" > /dev/null; } + +config_meson_default() { + CC="${CC}" "${MESON}" setup \ + --werror \ + --buildtype="${BUILDTYPE}" \ + --force-fallback-for=libnvme \ + -Dlibnvme:werror=false \ + "${BUILDDIR}" +} + +config_meson_fallback() { + CC="${CC}" "${MESON}" setup \ + --werror \ + --buildtype="${BUILDTYPE}" \ + --wrap-mode=forcefallback \ + --default-library=both \ + -Dlibnvme:werror=false \ + -Dopenssl:werror=false \ + "${BUILDDIR}" +} + +config_meson_cross() { + CC="${CC}" "${MESON}" setup \ + --werror \ + --buildtype="${BUILDTYPE}" \ + --cross-file=.github/cross/ubuntu-cross-${CROSS_TARGET}.txt \ + --force-fallback-for=libnvme \ + -Dlibnvme:werror=false \ + -Dlibnvme:python=disabled \ + -Dlibnvme:openssl=disabled \ + "${BUILDDIR}" +} + +config_meson_coverage() { + CC="${CC}" "${MESON}" setup \ + --werror \ + --buildtype="${BUILDTYPE}" \ + --force-fallback-for=libnvme \ + -Dlibnvme:werror=false \ + -Db_coverage=true \ + "${BUILDDIR}" +} + +config_meson_appimage() { + CC="${CC}" "${MESON}" setup \ + --werror \ + --buildtype="${BUILDTYPE}" \ + --force-fallback-for=libnvme \ + --prefix=/usr \ + -Dlibnvme:werror=false \ + "${BUILDDIR}" +} + +build_meson() { + "${MESON}" compile \ + -C "${BUILDDIR}" +} + +test_meson() { + "${MESON}" test \ + -C "${BUILDDIR}" +} + +test_meson_coverage() { + "${MESON}" test \ + -C "${BUILDDIR}" + ninja -C "${BUILDDIR}" coverage --verbose +} + +install_meson_appimage() { + "${MESON}" install \ + -C "${BUILDDIR}" +} + +tools_build_samurai() { + if [ ! -d "${TOOLDIR}"/samurai ]; then + git clone --depth 1 https://github.com/michaelforney/samurai.git \ + "${TOOLDIR}/samurai" + fi + + if [[ -f "${TOOLDIR}/samurai/samu" ]]; then + return + fi + + pushd "${TOOLDIR}/samurai" || exit 1 + CC="${CC}" make + popd || exit 1 +} + +tools_build_muon() { + if [ ! -d "${TOOLDIR}/muon" ]; then + git clone --depth 1 https://git.sr.ht/~lattis/muon \ + "${TOOLDIR}/muon" + fi + + if [[ -f "${TOOLDIR}/build-muon/muon" ]]; then + return + fi + + pushd "${TOOLDIR}/muon" || exit 1 + + CC="${CC}" CFLAGS="${CFLAGS} -std=c99" ninja="${SAMU}" ./bootstrap.sh stage1 + + CC="${CC}" ninja="${SAMU}" stage1/muon setup \ + -Dprefix="${TOOLDIR}" \ + -Ddocs=disabled \ + -Dsamurai=disabled \ + -Dbestline=disabled \ + "${TOOLDIR}/build-muon" + "${SAMU}" -C "${TOOLDIR}/build-muon" + MUON="${BUILDDIR}/build-tools/.build-muon/muon" + + # "${TOOLDIR}/build-muon/muon" \ + # -C "${TOOLDIR}/build-muon" test + + popd || exit 1 +} + +config_muon_default() { + # wrap_mode=forcefallback depends on git being available + + CC="${CC}" CFLAGS="${CFLAGS}" ninja="${SAMU}" \ + "${MUON}" setup \ + -Ddefault_library=static \ + -Dc_link_args="-static" \ + -Dwrap_mode=forcefallback \ + -Dlibnvme:json-c=disabled \ + -Dlibnvme:python=disabled \ + -Dlibnvme:openssl=disabled \ + -Dlibnvme:keyutils=disabled \ + -Djson-c=disabled \ + "${BUILDDIR}" +} + +build_muon() { + "${SAMU}" -C "${BUILDDIR}" +} + +test_muon() { + ninja="${SAMU}" "${MUON}" -C "${BUILDDIR}" test + ldd "${BUILDDIR}/nvme" 2>&1 | grep 'not a dynamic executable' || exit 1 +} + +if [[ "${BUILDTOOL}" == "muon" ]]; then + SAMU="$(which samu 2> /dev/null)" || true + if [[ -z "${SAMU}" ]]; then + tools_build_samurai + SAMU="${TOOLDIR}/samurai/samu" + fi + + MUON="$(which muon 2> /dev/null)" || true + if [[ -z "${MUON}" ]]; then + tools_build_muon + MUON="${TOOLDIR}/build-muon/muon" + fi +fi + +echo "samu: ${SAMU}" +echo "muon: ${MUON}" + +rm -rf "${BUILDDIR}" + +config_"${BUILDTOOL}"_"${CONFIG}" +fn_exists "build_${BUILDTOOL}_${CONFIG}" && "build_${BUILDTOOL}_${CONFIG}" || build_"${BUILDTOOL}" +fn_exists "test_${BUILDTOOL}_${CONFIG}" && "test_${BUILDTOOL}_${CONFIG}" || test_"${BUILDTOOL}" +fn_exists "install_${BUILDTOOL}_${CONFIG}" && "install_${BUILDTOOL}_${CONFIG}" || true; diff --git a/meson-vcs-tag.sh b/scripts/meson-vcs-tag.sh similarity index 100% rename from meson-vcs-tag.sh rename to scripts/meson-vcs-tag.sh diff --git a/regress b/scripts/regress similarity index 100% rename from regress rename to scripts/regress diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000000..d2cbb0855c --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +usage() { + echo "Usage: release.sh [-d] VERSION" + echo "" + echo "The script does all necessary steps to create a new release." + echo "" + echo " -d: no documentation update" + echo " -n: dry run" + echo "" + echo "Note: The version number needs to be exactly" + echo " '^v[\d]+.[\d]+(.[\d\]+(-rc[0-9]+)?$'" + echo "" + echo "example:" + echo " release.sh v2.1-rc0 # v2.1 release candidate 0" + echo " release.sh v2.1 # v2.1 release" +} + +build_doc=true +dry_run=false + +while getopts "dn" o; do + case "${o}" in + d) + build_doc=false + ;; + n) + dry_run=true + ;; + *) + usage + ;; + esac +done +shift $((OPTIND-1)) + +VERSION=${1:-} + +if [ -z "$VERSION" ] ; then + usage + exit 1 +fi + +# expected version regex +re='^v([0-9]+\.[0-9]+(\.[0-9]+)?)(-rc[0-9]+)?$' + +# use the version string provided from the command line +if [[ "$VERSION" =~ ${re} ]]; then + echo "valid version $VERSION string" + + # remove the leading 'v' + ver="${VERSION#v}" +else + echo "invalid version string $VERSION" + exit 1 +fi + +cd "$(git rev-parse --show-toplevel)" || exit 1 + +if [[ -f subprojects/libnvme.wrap ]]; then + git -C subprojects/libnvme fetch --all + + # extract the version string from libnvme by using the ref + # defined in libnvme.wrap. + libnvme_ref=$(sed -n "s/revision = \([0-9a-z]\+\)/\1/p" subprojects/libnvme.wrap) + libnvme_VERSION=$(git -C subprojects/libnvme describe "${libnvme_ref}") + if [[ "${libnvme_VERSION}" =~ ${re} ]]; then + echo "libnvme: valid version ${libnvme_VERSION} string" + + # remove the leading 'v' + libnvme_ver="${libnvme_VERSION#v}" + else + echo "libnvme: invalid version string ${libnvme_VERSION}" + exit 1 + fi +fi + +if [[ -n $(git status -s) ]]; then + echo "tree is dirty." + if [[ "${dry_run}" = false ]]; then + exit 1 + fi +fi + +if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ] ; then + echo "currently not on master branch. abort." + exit 1 +fi + +# update all docs +doc_dir="" +if [ -d "Documentation" ]; then + doc_dir="Documentation" +elif [ -d "doc" ]; then + doc_dir="doc" +else + echo "documentation directory not found" + exit 1 +fi + +# update meson.build +sed -i -e "0,/[ \t]version: /s/\([ \t]version: \).*/\1\'$ver\',/" meson.build +if [[ -f subprojects/libnvme.wrap ]]; then + sed -i -e "s/\(dependency('libnvme', version: '>=\)\([\.1-9]\+\)/\1$libnvme_ver/" meson.build +fi + +if [[ "${dry_run}" = false ]]; then + git add meson.build + git commit -s -m "build: Update version to $VERSION" +fi + +if [ "$build_doc" = true ]; then + # update documentation + ./scripts/update-docs.sh + if [[ "${dry_run}" = false ]]; then + git add $doc_dir + git commit -s -m "doc: Regenerate all docs for $VERSION" + fi +fi + +if [[ "${dry_run}" = true ]]; then + exit 0 +fi + +git tag -s -m "Release $VERSION" "$VERSION" +git push --dry-run origin "$VERSION"^{}:master tag "$VERSION" + +read -p "All good? Ready to push changes to remote? [Yy]" -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + git push origin "$VERSION"^{}:master tag "$VERSION" +fi diff --git a/scripts/update-docs.sh b/scripts/update-docs.sh new file mode 100755 index 0000000000..6fe1132f05 --- /dev/null +++ b/scripts/update-docs.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +cd "$(git rev-parse --show-toplevel)" || exit 1 + +BUILDDIR="$(mktemp -d)" +trap 'rm -rf -- $BUILDDIR' EXIT + +meson setup \ + -Ddocs=all \ + -Ddocs-build=true \ + --force-fallback-for=libnvme \ + "${BUILDDIR}" +meson compile -C "${BUILDDIR}" +find "${BUILDDIR}/Documentation" -maxdepth 1 \ + \( -name '*.1' -o -name '*.html' \) \ + -exec cp {} Documentation/ \; diff --git a/subprojects/json-c.wrap b/subprojects/json-c.wrap index 50849327ac..569f78e042 100644 --- a/subprojects/json-c.wrap +++ b/subprojects/json-c.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = json-c-0.16 -source_url = https://s3.amazonaws.com/json-c_releases/releases/json-c-0.16.tar.gz -source_filename = json-c-0.16.tar.gz -source_hash = 8e45ac8f96ec7791eaf3bb7ee50e9c2100bbbc87b8d0f1d030c5ba8a0288d96b -patch_filename = json-c_0.16-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/json-c_0.16-1/get_patch -patch_hash = 69db1e0c391c6a00c42d05c0d845bd551d92db10171f4a40d0b070f29f918101 -wrapdb_version = 0.16-1 +directory = json-c-0.17 +source_url = https://s3.amazonaws.com/json-c_releases/releases/json-c-0.17.tar.gz +source_filename = json-c-0.17.tar.gz +source_hash = 7550914d58fb63b2c3546f3ccfbe11f1c094147bd31a69dcd23714d7956159e6 +patch_filename = json-c_0.17-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/json-c_0.17-2/get_patch +patch_hash = c1a9a7e2ea6bed89a59e13a5684be25899a5a510963154c4450c5a492b8f3984 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/json-c_0.17-2/json-c-0.17.tar.gz +wrapdb_version = 0.17-2 [provide] json-c = json_c_dep - diff --git a/subprojects/libnvme.wrap b/subprojects/libnvme.wrap index 2cdd6796a9..4b0975691e 100644 --- a/subprojects/libnvme.wrap +++ b/subprojects/libnvme.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/linux-nvme/libnvme.git -revision = 501347ffdf6321d42ceabf173792c95bd44dac0d +revision = d706ff266b45d1c17522d3c54a026fdab13fe346 [provide] libnvme = libnvme_dep diff --git a/subprojects/uuid.wrap b/subprojects/uuid.wrap deleted file mode 100644 index 0692c4e4ee..0000000000 --- a/subprojects/uuid.wrap +++ /dev/null @@ -1,6 +0,0 @@ -[wrap-git] -url = https://github.com/util-linux/util-linux.git -revision = eefff5aac7bce6979c950e3931a578efe03acbac - -[provide] -dependency_names = uuid \ No newline at end of file diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap deleted file mode 100644 index 3c7b5757de..0000000000 --- a/subprojects/zlib.wrap +++ /dev/null @@ -1,12 +0,0 @@ -[wrap-file] -directory = zlib-1.2.12 -source_url = http://zlib.net/fossils/zlib-1.2.12.tar.gz -source_filename = zlib-1.2.12.tar.gz -source_hash = 91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9 -patch_filename = zlib_1.2.12-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.2.12-1/get_patch -patch_hash = 8ec8344f3fe7b06ad4be768fd416694bc56cb4545ce78b0f1c18b3e72b3ec936 - -[provide] -zlib = zlib_dep - diff --git a/tests/README b/tests/README index 14b24e5080..a5fa7084fd 100644 --- a/tests/README +++ b/tests/README @@ -1,13 +1,20 @@ nvmetests ========= - This contains NVMe unit tests framework. The purpose of this framework + This contains a NVMe tests framework. The purpose of this framework to use nvme cli and test various supported commands and scenarios for NVMe device. - In current implementation this framework uses nvme cli to + In current implementation this framework uses nvme-cli to interact with underlying controller/namespace. + Note these tests expect to run against real hardware and will + read and write data to /dev/nvme0! + + DO NOT RUN THEM IF YOU DO NOT KNOW WHAT YOU ARE DOING! + + You have been warned. + 1. Common Package Dependencies ------------------------------ diff --git a/tests/meson.build b/tests/meson.build index bc49d05f6c..f8c6aa2260 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -28,10 +28,17 @@ tests = [ 'nvme_verify_test.py', 'nvme_lba_status_log_test.py', 'nvme_get_lba_status_test.py', + 'nvme_ctrl_reset_test.py', ] runtests = find_program('nose2', required : false) +if meson.version().version_compare('>= 0.56') + nvmecli_path = meson.project_build_root() +else + nvmecli_path = meson.build_root() +endif + if runtests.found() foreach file : infra + tests configure_file( @@ -43,8 +50,8 @@ if runtests.found() foreach t : tests t_name = t.split('.')[0] test(t_name, runtests, - args: ['--verbose', '--start-dir', meson.build_root() + '/tests', t_name], - env: ['PATH=' + meson.build_root() + ':/usr/bin:/usr/sbin'], + args: ['--verbose', '--start-dir', meson.current_build_dir(), t_name], + env: ['PATH=' + nvmecli_path + ':/usr/bin:/usr/sbin'], timeout: 500) endforeach endif @@ -88,5 +95,5 @@ if autopep8.found() and isort.found() command : [python, linter_script, 'format'], ) else - message('autopep8 or isort not found. Python formating disabled') + message('autopep8 or isort not found. Python formatting disabled') endif diff --git a/tests/nvme_attach_detach_ns_test.py b/tests/nvme_attach_detach_ns_test.py index 07c118fae7..075f211a63 100644 --- a/tests/nvme_attach_detach_ns_test.py +++ b/tests/nvme_attach_detach_ns_test.py @@ -64,7 +64,7 @@ def tearDown(self): Post Section for TestNVMeAttachDetachNSCmd - Create primary namespace. - - Atttach it to controller. + - Attach it to controller. - Call super class's destructor. """ self.assertEqual(self.create_and_validate_ns(self.default_nsid, diff --git a/tests/nvme_copy_test.py b/tests/nvme_copy_test.py index 12676eaee4..a5472312fa 100644 --- a/tests/nvme_copy_test.py +++ b/tests/nvme_copy_test.py @@ -1,59 +1,113 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of nvme-cli # # Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. # -# Author: Arunpandian J +# Authors: Arunpandian J +# Joy Gu """ NVMe Copy Testcase:- 1. Issue copy command on set of block; shall pass. + 2. If cross-namespace copy formats are supported, enable and test + cross-namespace copy formats. """ +import subprocess + from nvme_test import TestNVMe class TestNVMeCopy(TestNVMe): """ - Represents NVMe Verify testcase. + Represents NVMe Copy testcase. - Attributes: - - start_block : starting block of to verify operation. - - range : Range of blocks for DSM operation. - - slbs : 64-bit addr of first block per range + - ocfs : optional copy formats supported + - host_behavior_data : host behavior support data to restore during teardown - test_log_dir : directory for logs, temp files. """ def setUp(self): """ Pre Section for TestNVMeCopy """ super().setUp() - self.start_block = 0 - self.range = 1 - self.slbs = 1 - self.namespace = 1 + print("\nSetting up test...") + self.ocfs = self.get_ocfs() + cross_namespace_copy = self.ocfs & 0xc + if cross_namespace_copy: + # get host behavior support data + get_features_cmd = ["nvme", "get-feature", self.ctrl, "--feature-id=0x16", "--data-len=512", "-b"] + print("Running command:", " ".join(get_features_cmd)) + self.host_behavior_data = subprocess.check_output(get_features_cmd) + # enable cross-namespace copy formats + if self.host_behavior_data[4] & cross_namespace_copy: + # skip if already enabled + print("Cross-namespace copy already enabled, skipping set-features") + self.host_behavior_data = None + else: + data = self.host_behavior_data[:4] + cross_namespace_copy.to_bytes(2, 'little') + self.host_behavior_data[6:] + set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"] + print("Running command:", " ".join(set_features_cmd)) + proc = subprocess.Popen(set_features_cmd, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE) + proc.communicate(input=data) + self.assertEqual(proc.returncode, 0, "Failed to enable cross-namespace copy formats") + get_ns_id_cmd = ["nvme", "get-ns-id", self.ns1] + print("Running command:", " ".join(get_ns_id_cmd)) + output = subprocess.check_output(get_ns_id_cmd) + self.ns1_nsid = int(output.decode().strip().split(':')[-1]) self.setup_log_dir(self.__class__.__name__) def tearDown(self): """ Post Section for TestNVMeCopy """ + print("Tearing down test...") + if self.host_behavior_data: + # restore saved host behavior support data + set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"] + print("Running command:", " ".join(set_features_cmd)) + proc = subprocess.Popen(set_features_cmd, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE) + proc.communicate(input=self.host_behavior_data) super().tearDown() - def copy(self): + def copy(self, sdlba, blocks, slbs, **kwargs): """ Wrapper for nvme copy - Args: - - None + - sdlba : destination logical block address + - blocks : number of logical blocks (0-based) + - slbs : source range logical block address + - descriptor_format : copy descriptor format (optional) + - snsids : source namespace id (optional) + - sopts : source options (optional) - Returns: - - return code for nvme copy command. + - None """ - copy_cmd = "nvme copy " + self.ctrl + \ - " --namespace-id=" + str(self.namespace) + \ - " --sdlba=" + str(self.start_block) + \ - " --blocks=" + str(self.range) + \ - " --slbs=" + str(self.range) - return self.exec_cmd(copy_cmd) + # skip if descriptor format not supported (default format is 0) + desc_format = kwargs.get("descriptor_format", 0) + if not self.ocfs & (1 << desc_format): + print(f"Skip copy because descriptor format {desc_format} is not supported") + return + # build copy command + copy_cmd = f"nvme copy {self.ns1} --format={desc_format} --sdlba={sdlba} --blocks={blocks} --slbs={slbs}" + if "snsids" in kwargs: + copy_cmd += f" --snsids={kwargs['snsids']}" + if "sopts" in kwargs: + copy_cmd += f" --sopts={kwargs['sopts']}" + # run and assert success + print("Running command:", copy_cmd) + self.assertEqual(self.exec_cmd(copy_cmd), 0) def test_copy(self): """ Testcase main """ - self.assertEqual(self.copy(), 0) + print("Running test...") + self.copy(0, 1, 2, descriptor_format=0) + self.copy(0, 1, 2, descriptor_format=1) + self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid) + self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid, sopts=0) + self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid) + self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid, sopts=0) diff --git a/tests/nvme_create_max_ns_test.py b/tests/nvme_create_max_ns_test.py index 51797111b4..bda93e1963 100644 --- a/tests/nvme_create_max_ns_test.py +++ b/tests/nvme_create_max_ns_test.py @@ -66,7 +66,7 @@ def tearDown(self): Post Section for TestNVMeAttachDetachNSCmd - Create primary namespace. - - Atttach it to controller. + - Attach it to controller. - Call super class's destructor. """ self.assertEqual(self.create_and_validate_ns(self.default_nsid, diff --git a/tests/nvme_ctrl_reset_test.py b/tests/nvme_ctrl_reset_test.py new file mode 100644 index 0000000000..b8b3c3b937 --- /dev/null +++ b/tests/nvme_ctrl_reset_test.py @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# This file is part of nvme-cli +# +# Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved. +# +# Author: Arunpandian J + +""" +NVMe controller reset Testcase:- + + 1. Execute nvme controller reset. + +""" + +from nvme_test import TestNVMe + + +class TestNVMeCtrlReset(TestNVMe): + + """ + Represents NVMe Controller reset testcase. + - Attributes: + - test_log_dir : directory for logs, temp files. + """ + + def setUp(self): + """ Pre Section for TestNVMeCtrlReset """ + super().setUp() + self.setup_log_dir(self.__class__.__name__) + + def tearDown(self): + """ Post Section for TestNVMeCtrlReset """ + super().tearDown() + + def ctrl_reset(self): + """ Wrapper for nvme controller reset + - Args: + - None + - Returns: + - return code for nvme controller reset. + """ + ctrl_reset_cmd = "nvme reset " + self.ctrl + return self.exec_cmd(ctrl_reset_cmd) + + def test_ctrl_reset(self): + """ Testcase main """ + self.assertEqual(self.ctrl_reset(), 0) diff --git a/tests/nvme_dsm_test.py b/tests/nvme_dsm_test.py index 7d5e477187..d92bf58e59 100644 --- a/tests/nvme_dsm_test.py +++ b/tests/nvme_dsm_test.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of nvme-cli # diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py index 68e5a2f8ce..40635c155e 100644 --- a/tests/nvme_format_test.py +++ b/tests/nvme_format_test.py @@ -81,7 +81,7 @@ def tearDown(self): Post Section for TestNVMeFormatCmd - Create primary namespace. - - Atttach it to controller. + - Attach it to controller. - Call super class's destructor. """ self.assertEqual(self.create_and_validate_ns(self.default_nsid, diff --git a/tests/nvme_get_features_test.py b/tests/nvme_get_features_test.py index 784f2bee0c..974fc347c8 100644 --- a/tests/nvme_get_features_test.py +++ b/tests/nvme_get_features_test.py @@ -47,7 +47,7 @@ class TestNVMeGetMandatoryFeatures(TestNVMe): - 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. + - vector_list_len : number of the interrupt vectors. """ def setUp(self): diff --git a/tests/nvme_get_lba_status_test.py b/tests/nvme_get_lba_status_test.py index 924a7ce95e..539c493763 100644 --- a/tests/nvme_get_lba_status_test.py +++ b/tests/nvme_get_lba_status_test.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of nvme-cli # diff --git a/tests/nvme_lba_status_log_test.py b/tests/nvme_lba_status_log_test.py index 90bfe914c4..c91d1e5690 100644 --- a/tests/nvme_lba_status_log_test.py +++ b/tests/nvme_lba_status_log_test.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of nvme-cli # diff --git a/tests/nvme_test.py b/tests/nvme_test.py index d5eca180dd..0df3dacc2c 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -39,7 +39,7 @@ class TestNVMe(unittest.TestCase): """ - Represents a testcase, each testcase shuold inherit this + Represents a testcase, each testcase should inherit this class or appropriate subclass which is a child of this class. Common utility functions used in various testcases. @@ -58,11 +58,13 @@ def setUp(self): self.ctrl = "XXX" self.ns1 = "XXX" self.test_log_dir = "XXX" + self.do_validate_pci_device = True self.default_nsid = 0x1 self.config_file = 'tests/config.json' self.load_config() - self.validate_pci_device() + if self.do_validate_pci_device: + self.validate_pci_device() def tearDown(self): """ Post Section for TestNVMe. """ @@ -70,7 +72,7 @@ def tearDown(self): shutil.rmtree(self.log_dir, ignore_errors=True) def validate_pci_device(self): - """ Validate underlaying device belogs to pci subsystem. + """ Validate underlying device belongs to pci subsystem. - Args: - None - Returns: @@ -93,6 +95,7 @@ def load_config(self): self.ctrl = config['controller'] self.ns1 = config['ns1'] self.log_dir = config['log_dir'] + self.do_validate_pci_device = config.get('do_validate_pci_device', self.do_validate_pci_device) self.clear_log_dir = False if self.clear_log_dir is True: @@ -162,7 +165,7 @@ def get_ctrl_id(self): return ctrl_id def get_ns_list(self): - """ Wrapper for extrating the namespace list. + """ Wrapper for extracting the namespace list. - Args: - None - Returns: @@ -181,7 +184,7 @@ def get_ns_list(self): return ns_list def get_max_ns(self): - """ Wrapper for extracting maximum number of namspaces supported. + """ Wrapper for extracting maximum number of namespaces supported. - Args: - None - Returns: @@ -228,6 +231,19 @@ def get_ncap(self): print(ncap) return int(ncap) + def get_ocfs(self): + """ Wrapper for extracting optional copy formats supported + - Args: + - None + - Returns: + - Optional Copy Formats Supported + """ + pattern = re.compile(r'^ocfs\s*: 0x[0-9a-fA-F]+$') + output = subprocess.check_output(["nvme", "id-ctrl", self.ctrl], encoding='utf-8') + ocfs_line = next(line for line in output.splitlines() if pattern.match(line)) + ocfs = ocfs_line.split(":")[1].strip() + return int(ocfs, 16) + def get_format(self): """ Wrapper for extracting format. - Args: diff --git a/tests/nvme_verify_test.py b/tests/nvme_verify_test.py index 68e5165bd5..7c30828f51 100644 --- a/tests/nvme_verify_test.py +++ b/tests/nvme_verify_test.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0-or-later # # This file is part of nvme-cli # diff --git a/unit/meson.build b/unit/meson.build new file mode 100644 index 0000000000..7e0e87848f --- /dev/null +++ b/unit/meson.build @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +test_uint128 = executable( + 'test-uint128', + ['test-uint128.c', '../util/types.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('uint128', test_uint128) + +test_suffix_si_parse = executable( + 'test-suffix-si-parse', + ['test-suffix-si-parse.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('suffix_si_parse', test_suffix_si_parse) + +test_suffix_binary_parse = executable( + 'test-suffix-binary-parse', + ['test-suffix-binary-parse.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('suffix_binary_parse', test_suffix_binary_parse) + +test_uint128_si = executable( + 'test-uint128-si', + ['test-uint128-si.c', '../util/types.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('uint128-si', test_uint128_si) + +test_argconfig_parse = executable( + 'test-argconfig-parse', + ['test-argconfig-parse.c', '../util/argconfig.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('argconfig_parse', test_argconfig_parse) diff --git a/unit/test-argconfig-parse.c b/unit/test-argconfig-parse.c new file mode 100644 index 0000000000..23c8d4feef --- /dev/null +++ b/unit/test-argconfig-parse.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include + +#include "../util/argconfig.h" +#include "nvme/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static int test_rc; + +union val { + bool flag; + __u64 suffix; + __u32 uint; + int int_val; + __u64 long_val; + double double_val; + __u8 byte; + __u16 shrt; + int incr; + char *string; + char *fmt; + char *file; + char *list; + char *str; +}; + +struct toval_test { + char *arg; + void *val; + union val exp; + int size; + int ret; +}; + +static void check_val(const char *arg, void *exp, void *val, int size) +{ + if ((size && !memcmp(exp, val, size)) || + (!size && !strcmp(*(char **)exp, *(char **)val))) + return; + + switch (size) { + case 0: + printf("ERROR: printing {%s}, got '%s', expected '%s'\n", + arg, *(char **)val, *(char **)exp); + break; + default: + printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n", + arg, *(unsigned long long *)val, *(unsigned long long *)exp); + break; + } + + test_rc = 1; +} + +struct cfg { + bool flag; + __u64 suffix; + __u32 uint; + int int_val; + __u64 long_val; + double double_val; + __u8 byte; + __u16 shrt; + int incr; + char *string; + char *fmt; + char *file; + char *list; + char *str; +}; + +static struct cfg cfg; + +#define VAL_TEST(a, c, v, l, r) \ + { a, &cfg.c, { .c = v }, l ? sizeof(cfg.c) : 0, r } + +static struct toval_test toval_tests[] = { + VAL_TEST("--flag", flag, true, true, 0), + VAL_TEST("--flag=1", flag, false, true, -EINVAL), + VAL_TEST("--suffix=0", suffix, 0, true, 0), + VAL_TEST("--suffix=1", suffix, 1, true, 0), + VAL_TEST("--suffix=1234", suffix, 1234, true, 0), + VAL_TEST("--suffix=4096", suffix, 4096, true, 0), + VAL_TEST("--suffix=1Ki", suffix, 1024, true, 0), + VAL_TEST("--suffix=34Gi", suffix, 36507222016, true, 0), + VAL_TEST("--suffix=34.9Ki", suffix, 0, true, -EINVAL), + VAL_TEST("--suffix=32Gii", suffix, 0, true, -EINVAL), + VAL_TEST("--uint=1", uint, 1, true, 0), + VAL_TEST("--int=1", int_val, 1, true, 0), + VAL_TEST("--long=1", long_val, 1, true, 0), + VAL_TEST("--double=1", double_val, 1, true, 0), + VAL_TEST("--byte=1", byte, 1, true, 0), + VAL_TEST("--byte=256", byte, 0, true, -EINVAL), + VAL_TEST("--shrt=1", shrt, 1, true, 0), + VAL_TEST("--incr", incr, 1, true, 0), + VAL_TEST("--incr=1", incr, 0, true, -EINVAL), + VAL_TEST("--string=string", string, "string", false, 0), + VAL_TEST("--fmt=fmt", fmt, "fmt", false, 0), + VAL_TEST("--file=file", file, "file", false, 0), + VAL_TEST("--list=list", list, "list", false, 0), + VAL_TEST("--str=str", str, "str", false, 0), +}; + +void toval_test(struct toval_test *test) +{ + const char *desc = "Test argconfig parse"; + int ret; + char *argv[] = { "test-argconfig", test->arg }; + + OPT_ARGS(opts) = { + OPT_FLAG("flag",'f', &cfg.flag, "flag"), + OPT_SUFFIX("suffix", 's', &cfg.suffix, "suffix"), + OPT_UINT("uint", 'u', &cfg.uint, "uint"), + OPT_INT("int", 'i', &cfg.int_val, "int"), + OPT_LONG("long", 'l', &cfg.long_val, "long"), + OPT_DOUBLE("double", 'd', &cfg.double_val, "double"), + OPT_BYTE("byte", 'b', &cfg.byte, "byte"), + OPT_SHRT("shrt", 'S', &cfg.shrt, "shrt"), + OPT_INCR("incr", 'I', &cfg.incr, "incr"), + OPT_STRING("string", 't', "STRING", &cfg.string, "string"), + OPT_FMT("fmt", 'F', &cfg.fmt, "fmt"), + OPT_FILE("file", 'L', &cfg.file, "file"), + OPT_LIST("list", 'T', &cfg.list, "list"), + OPT_STR("str", 'r', &cfg.str, "str"), + OPT_END() + }; + + ret = argconfig_parse(2, argv, desc, opts); + if (ret != test->ret) { + printf("ERROR: converting {%s} failed\n", test->arg); + test_rc = 1; + return; + } + if (ret) + return; + + check_val(test->arg, &test->exp, test->val, test->size); +} + +int main(void) +{ + unsigned int i; + FILE *f; + + test_rc = 0; + setlocale(LC_NUMERIC, "C"); + f = freopen("/dev/null", "w", stderr); + if (!f) + printf("ERROR: reopening stderr failed: %s\n", strerror(errno)); + + for (i = 0; i < ARRAY_SIZE(toval_tests); i++) + toval_test(&toval_tests[i]); + + if (f) + fclose(f); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/unit/test-suffix-binary-parse.c b/unit/test-suffix-binary-parse.c new file mode 100644 index 0000000000..5f6ac4a896 --- /dev/null +++ b/unit/test-suffix-binary-parse.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include "../util/suffix.h" +#include "../util/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static int test_rc; + +static void check_num(const char *val, __u64 exp, __u64 num) +{ + if (exp == num) + return; + + printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n", + val, (unsigned long long)num, (unsigned long long)exp); + + test_rc = 1; +} + +struct tonum_test { + const char *val; + const uint64_t exp; + int ret; +}; + +static struct tonum_test tonum_tests[] = { + { "1234", 1234, 0 }, + { "1Ki", 1024, 0}, + { "34Gi", 36507222016, 0 }, + { "34.9Ki", 0, -EINVAL}, + { "32Gii", 0, -EINVAL }, +}; + +void tonum_test(struct tonum_test *test) +{ + char *endptr; + uint64_t num; + int ret; + + ret = suffix_binary_parse(test->val, &endptr, &num); + if (ret != test->ret) { + printf("ERROR: converting {%s} failed\n", test->val); + test_rc = 1; + return; + } + if (ret) + return; + + check_num(test->val, test->exp, num); +} + +int main(void) +{ + unsigned int i; + + test_rc = 0; + + for (i = 0; i < ARRAY_SIZE(tonum_tests); i++) + tonum_test(&tonum_tests[i]); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/unit/test-suffix-si-parse.c b/unit/test-suffix-si-parse.c new file mode 100644 index 0000000000..54cff0e644 --- /dev/null +++ b/unit/test-suffix-si-parse.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include + +#include "../util/suffix.h" +#include "../util/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static int test_rc; + +static void check_num(const char *val, __u64 exp, __u64 num) +{ + if (exp == num) + return; + + printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n", + val, (unsigned long long)num, (unsigned long long)exp); + + test_rc = 1; +} + +struct tonum_test { + const char *val; + const uint64_t exp; + int ret; +}; + +static struct tonum_test tonum_tests[] = { + { "11995709440", 11995709440, 0 }, + { "1199570940", 1199570940, 0}, + { "234.567M", 234567000, 0 }, + { "1.2k", 1200, 0 }, + { "6.14T", 6140000000000, 0 }, + { "123.4567k", 123456, 0 }, + { "12345.6789101112M", 12345678910, 0}, + { "6.14", 6, 0 }, + { "6.14#", 0, -EINVAL }, + { "2,33", 0, -EINVAL }, + { "3..3", 0, -EINVAL }, + { "123.12MM", 0, -EINVAL }, + { "800G", 800000000000, 0 }, + { "800GG", 0, -EINVAL }, + { "800G800", 0, -EINVAL }, + { "800.0G", 800000000000, 0 }, + { "800.G", 0, -EINVAL }, + { "800.", 0, -EINVAL }, +}; + +void tonum_test(struct tonum_test *test) +{ + char *endptr; + uint64_t num; + int ret; + + ret = suffix_si_parse(test->val, &endptr, &num); + if (ret != test->ret) { + printf("ERROR: converting {%s} failed\n", test->val); + test_rc = 1; + return; + } + if (ret) + return; + + check_num(test->val, test->exp, num); +} + +int main(void) +{ + unsigned int i; + + test_rc = 0; + setlocale(LC_NUMERIC, "C"); + + for (i = 0; i < ARRAY_SIZE(tonum_tests); i++) + tonum_test(&tonum_tests[i]); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/unit/test-uint128-si.c b/unit/test-uint128-si.c new file mode 100644 index 0000000000..cc13450c45 --- /dev/null +++ b/unit/test-uint128-si.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "../util/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +/* create a uint128_t from four uint32_ts. w0 is the most significant value, + * w2 the least */ +#define U128(w0, w1, w2, w3) { .words = { w0, w1, w2, w3 } } + +static int test_rc; + +static void check_str(nvme_uint128_t val, __u32 bytes_per_unit, const char *exp, + const char *res) +{ + if (!strcmp(res, exp)) + return; + + printf("ERROR: printing {%08x.%08x.%08x.%08x} (bytes per unit %u), got '%s', expected '%s'\n", + val.words[3], val.words[2], val.words[1], val.words[0], + bytes_per_unit, res, exp); + + test_rc = 1; +} + +struct tostr_test { + nvme_uint128_t val; + __u32 bytes_per_unit; + const char *exp; +}; + +static struct tostr_test tostr_tests[] = { + { U128(0, 0, 0, 0), 1, "0.00 B" }, + { U128(0, 0, 0, 1), 1, "1.00 B" }, + { U128(0, 0, 0, 10), 1, "10.00 B" }, + { U128(4, 3, 2, 1), 1, "316.91 RB" }, + { U128(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff), 1, + "340282366.92 QB" }, + { U128(0, 0, 0, 0xae0dc2), 1000 * 512, "5.84 TB" }, + { U128(0, 0, 0, 0xf9c546), 1000 * 512, "8.38 TB" }, + { U128(0, 0, 0, 0x4c2aa594), 1000 * 512, "654.27 TB" }, + { U128(0, 0, 0, 0x5b013de8), 1000 * 512, "781.73 TB" }, +}; + +void tostr_test(struct tostr_test *test) +{ + char *str; + str = uint128_t_to_si_string(test->val, test->bytes_per_unit); + check_str(test->val, test->bytes_per_unit, test->exp, str); +} + +int main(void) +{ + unsigned int i; + + test_rc = 0; + + for (i = 0; i < ARRAY_SIZE(tostr_tests); i++) + tostr_test(&tostr_tests[i]); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/unit/test-uint128.c b/unit/test-uint128.c new file mode 100644 index 0000000000..f8478ef57d --- /dev/null +++ b/unit/test-uint128.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include "../util/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +/* create a uint128_t from four uint32_ts. w0 is the most significant value, + * w2 the least */ +#define U128(w0, w1, w2, w3) { .words = { w0, w1, w2, w3 } } + +static int test_rc; + +static void check_str(nvme_uint128_t val, const char *exp, const char *res) +{ + if (!strcmp(res, exp)) + return; + + printf("ERROR: printing {%08x.%08x.%08x.%08x}, got '%s', expected '%s'\n", + val.words[3], val.words[2], val.words[1], val.words[0], + res, exp); + + test_rc = 1; +} + +struct tostr_test { + const char *locale; + nvme_uint128_t val; + const char *exp; +}; + +static struct tostr_test tostr_tests[] = { + { NULL, U128(0, 0, 0, 0),"0" }, + { NULL, U128(0, 0, 0, 1), "1" }, + { NULL, U128(0, 0, 0, 10), "10" }, + { NULL, U128(4, 3, 2, 1), "316912650112397582603894390785" }, + { + NULL, + U128(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff), + "340282366920938463463374607431768211455" + }, + { "fr_FR.utf-8", U128(0, 0, 0, 1000), "1\u202f000" }, +}; + +void tostr_test(struct tostr_test *test) +{ + char *str; + + if (!setlocale(LC_NUMERIC, test->locale)) + return; + + if (test->locale) + str = uint128_t_to_l10n_string(test->val); + else + str = uint128_t_to_string(test->val); + + check_str(test->val, test->exp, str); +} + +int main(void) +{ + unsigned int i; + + test_rc = 0; + + for (i = 0; i < ARRAY_SIZE(tostr_tests); i++) + tostr_test(&tostr_tests[i]); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/util/argconfig.c b/util/argconfig.c index 2c328ffefd..5ec3d6f215 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -41,19 +41,19 @@ #include #include #include - -static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = { NULL }; - -static char END_DEFAULT[] = "__end_default__"; +#include static const char *append_usage_str = ""; +static int argconfig_parse_val(struct argconfig_commandline_options *s, struct option *option, + int index); + void argconfig_append_usage(const char *str) { append_usage_str = str; } -void print_word_wrapped(const char *s, int indent, int start) +void print_word_wrapped(const char *s, int indent, int start, FILE *stream) { const int width = 76; const char *c, *t; @@ -61,7 +61,7 @@ void print_word_wrapped(const char *s, int indent, int start) int last_line = indent; while (start < indent) { - putc(' ', stderr); + putc(' ', stream); start++; } @@ -78,14 +78,14 @@ void print_word_wrapped(const char *s, int indent, int start) int i; new_line: last_line = (int) (c-s) + start; - putc('\n', stderr); + putc('\n', stream); for (i = 0; i < indent; i++) - putc(' ', stderr); + putc(' ', stream); start = indent; continue; } } - putc(*c, stderr); + putc(*c, stream); } } @@ -115,59 +115,232 @@ static void show_option(const struct argconfig_commandline_options *option) fprintf(stderr, "%s", buffer); if (option->help) { - print_word_wrapped("--- ", 40, b - buffer); - print_word_wrapped(option->help, 44, 44); + print_word_wrapped("--- ", 40, b - buffer, stderr); + print_word_wrapped(option->help, 44, 44, stderr); } fprintf(stderr, "\n"); } void argconfig_print_help(const char *program_desc, - const struct argconfig_commandline_options *options) + struct argconfig_commandline_options *s) { - const struct argconfig_commandline_options *s; - - printf("\033[1mUsage: %s\033[0m\n\n", - append_usage_str); + fprintf(stderr, "\033[1mUsage: %s\033[0m\n\n", + append_usage_str); - print_word_wrapped(program_desc, 0, 0); - printf("\n"); + print_word_wrapped(program_desc, 0, 0, stderr); + fprintf(stderr, "\n"); - if (!options || !options->option) + if (!s || !s->option) return; - printf("\n\033[1mOptions:\033[0m\n"); - for (s = options; (s != NULL) && (s->option != NULL); s++) + fprintf(stderr, "\n\033[1mOptions:\033[0m\n"); + for (; s && s->option; s++) show_option(s); } +static int argconfig_error(char *type, const char *opt, const char *arg) +{ + fprintf(stderr, "Expected %s argument for '%s' but got '%s'!\n", type, opt, arg); + return -EINVAL; +} + +int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val) +{ + char *endptr; + unsigned long tmp = strtoul(str, &endptr, 0); + + if (errno || tmp >= 1 << 8 || str == endptr) + return argconfig_error("byte", opt, str); + + *val = tmp; + + return 0; +} + +static int argconfig_parse_type(struct argconfig_commandline_options *s, struct option *option, + int index) +{ + void *value = (void *)(char *)s->default_value; + char *endptr; + int ret = 0; + + errno = 0; /* To distinguish success/failure after strtol/stroul call */ + + switch (s->config_type) { + case CFG_STRING: + *((char **)value) = optarg; + break; + case CFG_SIZE: + *((size_t *)value) = strtol(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("integer", option[index].name, optarg); + break; + case CFG_INT: + *((int *)value) = strtol(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("integer", option[index].name, optarg); + break; + case CFG_BYTE: + ret = argconfig_parse_byte(option[index].name, optarg, (uint8_t *)value); + break; + case CFG_SHORT: { + unsigned long tmp = strtoul(optarg, &endptr, 0); + + if (errno || tmp >= 1 << 16 || optarg == endptr) + ret = argconfig_error("short", option[index].name, optarg); + else + *((uint16_t *)value) = tmp; + break; + } + case CFG_POSITIVE: { + uint32_t tmp = strtoul(optarg, &endptr, 0); + + if (errno || optarg == endptr) + ret = argconfig_error("word", option[index].name, optarg); + else + *((uint32_t *)value) = tmp; + break; + } + case CFG_INCREMENT: + *((int *)value) += 1; + break; + case CFG_LONG: + *((unsigned long *)value) = strtoul(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("long integer", option[index].name, optarg); + break; + case CFG_LONG_SUFFIX: + ret = suffix_binary_parse(optarg, &endptr, (uint64_t *)value); + if (ret) + argconfig_error("long suffixed integer", option[index].name, optarg); + break; + case CFG_DOUBLE: + *((double *)value) = strtod(optarg, &endptr); + if (errno || optarg == endptr) + ret = argconfig_error("float", option[index].name, optarg); + break; + case CFG_FLAG: + *((bool *)value) = true; + break; + default: + break; + } + + return ret; +} + +static int argconfig_get_val_len(struct argconfig_opt_val *opt_val, const char *str) +{ + struct argconfig_opt_val *v; + int len; + int match; + + for (len = 1; len <= strlen(str); len++) { + match = 0; + for (v = opt_val; v && v->str; v++) { + if (!strncasecmp(str, v->str, len)) + match++; + } + if (match == 1) + break; + } + + return len; +} + +static int argconfig_set_opt_val(enum argconfig_types type, union argconfig_val *opt_val, void *val) +{ + switch (type) { + case CFG_FLAG: + *(bool *)val = opt_val->bool_val; + break; + case CFG_LONG_SUFFIX: + *(uint64_t *)val = opt_val->long_suffix; + break; + case CFG_POSITIVE: + *(uint32_t *)val = opt_val->positive; + break; + case CFG_INT: + *(int *)val = opt_val->int_val; + break; + case CFG_LONG: + *(unsigned long *)val = opt_val->long_val; + break; + case CFG_DOUBLE: + *(double *)val = opt_val->double_val; + break; + case CFG_BYTE: + *(uint8_t *)val = opt_val->byte; + break; + case CFG_SHORT: + *(uint16_t *)val = opt_val->short_val; + break; + case CFG_INCREMENT: + *(int *)val = opt_val->increment; + break; + case CFG_STRING: + *(char **)val = opt_val->string; + break; + default: + break; + } + + return 0; +} + +static int argconfig_parse_val(struct argconfig_commandline_options *s, struct option *option, + int index) +{ + const char *str = optarg; + void *val = s->default_value; + int len = strlen(optarg); + struct argconfig_opt_val *v; + int val_len; + + for (v = s->opt_val; v && v->str; v++) { + val_len = argconfig_get_val_len(s->opt_val, v->str); + if (strncasecmp(str, v->str, len > val_len ? len : val_len)) + continue; + return argconfig_set_opt_val(v->type, &v->val, val); + } + + return argconfig_parse_type(s, option, index); +} + +static bool argconfig_check_human_readable(struct argconfig_commandline_options *s) +{ + for (; s && s->option; s++) { + if (!strcmp(s->option, "human-readable") && s->config_type == CFG_FLAG) + return s->seen; + } + + return false; +} + int argconfig_parse(int argc, char *argv[], const char *program_desc, - const struct argconfig_commandline_options *options) + struct argconfig_commandline_options *options) { char *short_opts; - char *endptr; struct option *long_opts; - const struct argconfig_commandline_options *s; + struct argconfig_commandline_options *s; int c, option_index = 0, short_index = 0, options_count = 0; - void *value_addr; - int ret = -EINVAL; + int ret = 0; errno = 0; - for (s = options; s->option != NULL; s++) + for (s = options; s->option; s++) options_count++; - long_opts = malloc(sizeof(struct option) * (options_count + 2)); - short_opts = malloc(sizeof(*short_opts) * (options_count * 3 + 4)); + long_opts = calloc(1, sizeof(struct option) * (options_count + 3)); + short_opts = calloc(1, sizeof(*short_opts) * (options_count * 3 + 5)); if (!long_opts || !short_opts) { - fprintf(stderr, "failed to allocate memory for opts: %s\n", - strerror(errno)); + 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) { + for (s = options; s->option && option_index < options_count; s++) { + if (s->short_option) { short_opts[short_index++] = s->short_option; if (s->argument_type == required_argument || s->argument_type == optional_argument) @@ -178,35 +351,26 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (s->option && strlen(s->option)) { long_opts[option_index].name = s->option; long_opts[option_index].has_arg = s->argument_type; - long_opts[option_index].flag = NULL; - long_opts[option_index].val = 0; } + s->seen = false; 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; + short_opts[short_index] = 'h'; optind = 0; - while ((c = getopt_long_only(argc, argv, short_opts, long_opts, - &option_index)) != -1) { - if (c != 0) { + while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &option_index)) != -1) { + if (c) { if (c == '?' || c == 'h') { argconfig_print_help(program_desc, options); - goto out; + ret = -EINVAL; + break; } - for (option_index = 0; option_index < options_count; - option_index++) { + for (option_index = 0; option_index < options_count; option_index++) { if (c == options[option_index].short_option) break; } @@ -215,235 +379,29 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, } 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) += 1; - } 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++; - } + s->seen = true; - if (!enddefault) { - *opts = END_DEFAULT; - remaining_space -= 2; - opts += 2; - } + if (!s->default_value) + continue; - 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; - } else if (s->config_type == CFG_FLAG) { - *((bool *)value_addr) = true; - } + if (s->opt_val) + ret = argconfig_parse_val(s, long_opts, option_index); + else + ret = argconfig_parse_type(s, long_opts, option_index); + if (ret) + break; } - free(short_opts); - free(long_opts); - return 0; - out: + if (!argconfig_check_human_readable(options)) + setlocale(LC_ALL, "C"); + +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; -} - -int argconfig_parse_comma_sep_array(char *string, int *val, - unsigned max_length) +int argconfig_parse_comma_sep_array(char *string, int *val, unsigned int max_length) { int ret = 0; unsigned long v; @@ -489,7 +447,7 @@ int argconfig_parse_comma_sep_array(char *string, int *val, } int argconfig_parse_comma_sep_array_short(char *string, unsigned short *val, - unsigned max_length) + unsigned int max_length) { int ret = 0; unsigned long v; @@ -533,9 +491,8 @@ int argconfig_parse_comma_sep_array_short(char *string, unsigned short *val, } } -int argconfig_parse_comma_sep_array_long(char *string, - unsigned long long *val, - unsigned max_length) +int argconfig_parse_comma_sep_array_long(char *string, unsigned long long *val, + unsigned int max_length) { int ret = 0; char *tmp; @@ -568,15 +525,65 @@ int argconfig_parse_comma_sep_array_long(char *string, } } -void argconfig_register_help_func(argconfig_help_func * f) +#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(size) \ +int argconfig_parse_comma_sep_array_u##size(char *string, \ + __u##size *val, \ + unsigned int max_length) \ +{ \ + int ret = 0; \ + uintmax_t v; \ + char *tmp; \ + char *p; \ + \ + if (!string || !strlen(string)) \ + return 0; \ + \ + tmp = strtok(string, ","); \ + if (!tmp) \ + return 0; \ + \ + v = strtoumax(tmp, &p, 0); \ + if (*p != 0) \ + return -1; \ + if (v > UINT##size##_MAX) { \ + fprintf(stderr, "%s out of range\n", tmp); \ + return -1; \ + } \ + val[ret] = v; \ + \ + ret++; \ + while (1) { \ + tmp = strtok(NULL, ","); \ + \ + if (tmp == NULL) \ + return ret; \ + \ + if (ret >= max_length) \ + return -1; \ + \ + v = strtoumax(tmp, &p, 0); \ + if (*p != 0) \ + return -1; \ + if (v > UINT##size##_MAX) { \ + fprintf(stderr, "%s out of range\n", tmp); \ + return -1; \ + } \ + val[ret] = v; \ + ret++; \ + } \ +} + +DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(16); +DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(32); +DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(64); + +bool argconfig_parse_seen(struct argconfig_commandline_options *s, + const char *option) { - int i; - for (i = 0; i < MAX_HELP_FUNC; i++) { - if (help_funcs[i] == NULL) { - help_funcs[i] = f; - if (i < MAX_HELP_FUNC - 1) - help_funcs[i + 1] = NULL; - break; - } + for (; s && s->option; s++) { + if (!strcmp(s->option, option)) + return s->seen; } + + return false; } diff --git a/util/argconfig.h b/util/argconfig.h index b66706a699..2a04a32e72 100644 --- a/util/argconfig.h +++ b/util/argconfig.h @@ -37,6 +37,11 @@ #include #include #include +#include +#include +#include + +#include enum argconfig_types { CFG_FLAG, @@ -46,62 +51,107 @@ enum argconfig_types { 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[] + struct argconfig_commandline_options n[] #define OPT_END() { NULL } -#define OPT_FLAG(l, s, v, d) \ - {l, s, NULL, CFG_FLAG, v, no_argument, d} +#define OPT_FLAG(l, s, v, d, ...) \ + {l, s, NULL, CFG_FLAG, v, no_argument, d, false, __VA_ARGS__} + +#define OPT_SUFFIX(l, s, v, d, ...) \ + {l, s, "IONUM", CFG_LONG_SUFFIX, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_UINT(l, s, v, d, ...) \ + {l, s, "NUM", CFG_POSITIVE, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_INT(l, s, v, d, ...) \ + {l, s, "NUM", CFG_INT, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_LONG(l, s, v, d, ...) \ + {l, s, "NUM", CFG_LONG, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_DOUBLE(l, s, v, d, ...) \ + {l, s, "NUM", CFG_DOUBLE, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_BYTE(l, s, v, d, ...) \ + {l, s, "NUM", CFG_BYTE, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_SHRT(l, s, v, d, ...) \ + {l, s, "NUM", CFG_SHORT, v, required_argument, d, false, __VA_ARGS__} + +#define OPT_INCR(l, s, v, d, ...) \ + {l, s, "NUM", CFG_INCREMENT, v, no_argument, d, false, __VA_ARGS__} -#define OPT_SUFFIX(l, s, v, d) \ - {l, s, "IONUM", CFG_LONG_SUFFIX, v, required_argument, d} +#define OPT_STRING(l, s, m, v, d, ...) \ + {l, s, m, CFG_STRING, v, required_argument, d, false, __VA_ARGS__} -#define OPT_LONG(l, s, v, d) \ - {l, s, "NUM", CFG_LONG, v, required_argument, d} +#define OPT_FMT(l, s, v, d, ...) OPT_STRING(l, s, "FMT", v, d, __VA_ARGS__) +#define OPT_FILE(l, s, v, d, ...) OPT_STRING(l, s, "FILE", v, d, __VA_ARGS__) +#define OPT_LIST(l, s, v, d, ...) OPT_STRING(l, s, "LIST", v, d, __VA_ARGS__) +#define OPT_STR(l, s, v, d, ...) OPT_STRING(l, s, "STRING", v, d, __VA_ARGS__) -#define OPT_UINT(l, s, v, d) \ - {l, s, "NUM", CFG_POSITIVE, v, required_argument, d} +#define OPT_VALS(n) \ + struct argconfig_opt_val n[] -#define OPT_INT(l, s, v, d) \ - {l, s, "NUM", CFG_INT, v, required_argument, d} +#define VAL_END() { NULL } -#define OPT_LONG(l, s, v, d) \ - {l, s, "NUM", CFG_LONG, v, required_argument, d} +#define VAL_FLAG(s, l, v) \ + {s, CFG_FLAG, .val.flag = v} -#define OPT_DOUBLE(l, s, v, d) \ - {l, s, "NUM", CFG_DOUBLE, v, required_argument, d} +#define VAL_LONG_SUFFIX(s, v) \ + {s, CFG_LONG_SUFFIX, .val.long_suffix = v} -#define OPT_BYTE(l, s, v, d) \ - {l, s, "NUM", CFG_BYTE, v, required_argument, d} +#define VAL_UINT(s, v) \ + {s, CFG_POSITIVE, v} -#define OPT_SHRT(l, s, v, d) \ - {l, s, "NUM", CFG_SHORT, v, required_argument, d} +#define VAL_INT(s, v) \ + {s, CFG_INT, .val.int_val = v} -#define OPT_INCR(l, s, v, d) \ - {l, s, "NUM", CFG_INCREMENT, v, no_argument, d} +#define VAL_LONG(s, v) \ + {s, CFG_LONG, .val.long_val = v} -#define OPT_STRING(l, s, m, v, d) \ - {l, s, m, CFG_STRING, v, required_argument, d} +#define VAL_DOUBLE(s, v) \ + {s, CFG_DOUBLE, .val.double_val = v} -#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) -#define OPT_STR(l, s, v, d) OPT_STRING(l, s, "STRING", v, d) +#define VAL_BYTE(s, v) \ + {s, CFG_BYTE, .val.byte = v} + +#define VAL_SHRT(s, v) \ + {s, CFG_SHORT, .val.short_val = v} + +#define VAL_INCR(s, v) \ + {s, CFG_INCREMENT, .val.increment = v} + +#define VAL_STRING(s, m, v) \ + {s, CFG_STRING, .val.string = v} + +union argconfig_val { + char *string; + size_t size; + int int_val; + int bool_val; + uint8_t byte; + uint16_t short_val; + uint32_t positive; + int increment; + unsigned long long_val; + uint64_t long_suffix; + double double_val; + bool flag; +}; + +struct argconfig_opt_val { + const char *str; + enum argconfig_types type; + union argconfig_val val; +}; struct argconfig_commandline_options { const char *option; @@ -111,27 +161,29 @@ struct argconfig_commandline_options { void *default_value; int argument_type; const char *help; + bool seen; + struct argconfig_opt_val *opt_val; }; -#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); + 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); -int argconfig_parse_comma_sep_array(char *string, int *ret, - unsigned max_length); + struct argconfig_commandline_options *options); +int argconfig_parse_comma_sep_array(char *string, int *ret, unsigned int max_length); int argconfig_parse_comma_sep_array_short(char *string, unsigned short *ret, - unsigned max_length); -int argconfig_parse_comma_sep_array_long(char *string, - unsigned long long *ret, - unsigned max_length); -void argconfig_register_help_func(argconfig_help_func * f); - -void print_word_wrapped(const char *s, int indent, int start); + unsigned int max_length); +int argconfig_parse_comma_sep_array_long(char *string, unsigned long long *ret, + unsigned int max_length); +int argconfig_parse_comma_sep_array_u16(char *string, __u16 *val, + unsigned int max_length); +int argconfig_parse_comma_sep_array_u32(char *string, __u32 *val, + unsigned int max_length); +int argconfig_parse_comma_sep_array_u64(char *string, __u64 *val, + unsigned int max_length); +int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val); + +void print_word_wrapped(const char *s, int indent, int start, FILE *stream); +bool argconfig_parse_seen(struct argconfig_commandline_options *options, + const char *option); #endif diff --git a/util/base64.c b/util/base64.c index 07f975c8e5..7f47cda6c3 100644 --- a/util/base64.c +++ b/util/base64.c @@ -81,24 +81,24 @@ int base64_decode(const char *src, int srclen, unsigned char *dst) int i, bits = 0; unsigned char *bp = dst; - for (i = 0; i < srclen; i++) { - const char *p = strchr(base64_table, src[i]); + for (i = 0; i < srclen; i++) { + const char *p = strchr(base64_table, src[i]); - if (src[i] == '=') { - ac = (ac << 6); + if (src[i] == '=') { + ac = (ac << 6); bits += 6; if (bits >= 8) bits -= 8; - continue; - } - if (p == NULL || src[i] == 0) - return -EINVAL; - ac = (ac << 6) | (p - base64_table); - bits += 6; - if (bits >= 8) { - bits -= 8; - *bp++ = (unsigned char)(ac >> bits); - } + continue; + } + if (!p || !src[i]) + return -EINVAL; + ac = (ac << 6) | (p - base64_table); + bits += 6; + if (bits >= 8) { + bits -= 8; + *bp++ = (unsigned char)(ac >> bits); + } } if (ac && ((1 << bits) - 1)) return -EAGAIN; diff --git a/util/cleanup.c b/util/cleanup.c deleted file mode 100644 index d6ac7c6761..0000000000 --- a/util/cleanup.c +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include -#include "cleanup.h" - -DEFINE_CLEANUP_FUNC(cleanup_charp, char *, free); diff --git a/util/cleanup.h b/util/cleanup.h index 575a25d701..ee9b120606 100644 --- a/util/cleanup.h +++ b/util/cleanup.h @@ -2,6 +2,11 @@ #ifndef __CLEANUP_H #define __CLEANUP_H +#include +#include + +#include "util/mem.h" + #define __cleanup__(fn) __attribute__((cleanup(fn))) #define DECLARE_CLEANUP_FUNC(name, type) \ @@ -14,6 +19,19 @@ DECLARE_CLEANUP_FUNC(name, type) \ free_fn(*__p); \ } -DECLARE_CLEANUP_FUNC(cleanup_charp, char *); +static inline void freep(void *p) +{ + free(*(void**) p); +} +#define _cleanup_free_ __cleanup__(freep) + +#define _cleanup_huge_ __cleanup__(nvme_free_huge) + +static inline void close_file(int *f) +{ + if (*f > STDERR_FILENO) + close(*f); +} +#define _cleanup_file_ __cleanup__(close_file) #endif diff --git a/util/crc32.c b/util/crc32.c new file mode 100644 index 0000000000..bb5f129a60 --- /dev/null +++ b/util/crc32.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2002 Red Hat, Inc. + * This file is part of elfutils. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * * the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version + * + * or + * + * * the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version + * + * or both in parallel, as here. + * + * elfutils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received copies of the GNU General Public License and + * the GNU Lesser General Public License along with this program. If + * not, see . + */ + +/* https://sourceware.org/git/?p=elfutils.git;a=blob;f=lib/crc32.c;hb=575198c29a427392823cc8f2400579a23d06a875 */ + +#include "crc32.h" + +/* Table computed with Mark Adler's makecrc.c utility. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + +uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len) +{ + unsigned char *end; + + crc = ~crc; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} diff --git a/util/crc32.h b/util/crc32.h new file mode 100644 index 0000000000..e48c97da8e --- /dev/null +++ b/util/crc32.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef crc32_H +#define crc32_H + +#include +#include + +uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len); + +#endif diff --git a/util/json.c b/util/json.c index 8627bc8e75..2de5848288 100644 --- a/util/json.c +++ b/util/json.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include "json.h" +#include "types.h" struct json_object *util_json_object_new_double(long double d) { @@ -32,3 +34,41 @@ struct json_object *util_json_object_new_uint64(uint64_t i) return obj; } + +static int util_json_object_string_to_number(struct json_object *jso, + struct printbuf *pb, int level, + int flags) +{ + ssize_t len = json_object_get_string_len(jso); + + printbuf_memappend(pb, json_object_get_string(jso), len); + + return 0; +} + +struct json_object *util_json_object_new_uint128(nvme_uint128_t val) +{ + struct json_object *obj; + + obj = json_object_new_string(uint128_t_to_string(val)); + json_object_set_serializer(obj, util_json_object_string_to_number, NULL, NULL); + + return obj; +} + +uint64_t util_json_object_get_uint64(struct json_object *obj) +{ + uint64_t val = 0; + + if (json_object_is_type(obj, json_type_string)) { + char *end = NULL; + const char *buf; + + buf = json_object_get_string(obj); + val = strtoull(buf, &end, 10); + if ((val == 0 && errno != 0) || (end == buf)) + return 0; + } + + return val; +} diff --git a/util/json.h b/util/json.h index b5efe14c3a..54e33e397e 100644 --- a/util/json.h +++ b/util/json.h @@ -2,7 +2,9 @@ #ifndef __JSON__H #define __JSON__H +#ifdef CONFIG_JSONC #include +#include "util/types.h" /* Wrappers around json-c's API */ @@ -11,30 +13,33 @@ #define json_free_object(o) json_object_put(o) #define json_free_array(a) json_object_put(a) #define json_object_add_value_uint(o, k, v) \ - json_object_object_add(o, k, json_object_new_int(v)) + json_object_object_add(o, k, json_object_new_uint64(v)) #define json_object_add_value_int(o, k, v) \ json_object_object_add(o, k, json_object_new_int(v)) -#ifdef CONFIG_JSONC_14 +#ifndef CONFIG_JSONC_14 +#define json_object_new_uint64(v) util_json_object_new_uint64(v) +#define json_object_get_uint64(v) util_json_object_get_uint64(v) +#endif #define json_object_add_value_uint64(o, k, v) \ json_object_object_add(o, k, json_object_new_uint64(v)) -#else -#define json_object_add_value_uint64(o, k, v) \ - json_object_object_add(o, k, util_json_object_new_uint64(v)) -#endif +#define json_object_add_value_uint128(o, k, v) \ + json_object_object_add(o, k, util_json_object_new_uint128(v)) #define json_object_add_value_double(o, k, v) \ json_object_object_add(o, k, util_json_object_new_double(v)) #define json_object_add_value_float(o, k, v) \ json_object_object_add(o, k, json_object_new_double(v)) -#define json_object_add_value_string(o, k, v) \ - json_object_object_add(o, k, json_object_new_string(v)) +static inline int json_object_add_value_string(struct json_object *o, const char *k, const char *v) { + return json_object_object_add(o, k, v ? json_object_new_string(v) : NULL); +} #define json_object_add_value_array(o, k, v) \ json_object_object_add(o, k, v) #define json_object_add_value_object(o, k, v) \ json_object_object_add(o, k, v) #define json_array_add_value_object(o, k) \ json_object_array_add(o, k) -#define json_array_add_value_string(o, v) \ - json_object_array_add(o, json_object_new_string(v)) +static inline int json_array_add_value_string(struct json_object *o, const char *v) { + return json_object_array_add(o, v ? json_object_new_string(v) : NULL); +} #define json_print_object(o, u) \ printf("%s", json_object_to_json_string_ext(o, \ JSON_C_TO_STRING_PRETTY | \ @@ -42,5 +47,15 @@ struct json_object *util_json_object_new_double(long double d); struct json_object *util_json_object_new_uint64(uint64_t i); +struct json_object *util_json_object_new_uint128(nvme_uint128_t val); +struct json_object *util_json_object_new_uint128(nvme_uint128_t val); + +uint64_t util_json_object_get_uint64(struct json_object *obj); + +#else /* !CONFIG_JSONC */ + +struct json_object; + +#endif #endif diff --git a/util/logging.c b/util/logging.c new file mode 100644 index 0000000000..cf3336f4b9 --- /dev/null +++ b/util/logging.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include +#include +#include +#include +#include + +#include + +#include "logging.h" + +int log_level; + +int map_log_level(int verbose, bool quiet) +{ + int log_level; + + /* + * LOG_NOTICE is unused thus the user has to provide two 'v' for getting + * any feedback at all. Thus skip this level + */ + verbose++; + + switch (verbose) { + case 0: + log_level = LOG_WARNING; + break; + case 1: + log_level = LOG_NOTICE; + break; + case 2: + log_level = LOG_INFO; + break; + default: + log_level = LOG_DEBUG; + break; + } + if (quiet) + log_level = LOG_ERR; + + return log_level; +} + +static void nvme_show_common(struct nvme_passthru_cmd *cmd) +{ + printf("opcode : %02x\n", cmd->opcode); + printf("flags : %02x\n", cmd->flags); + printf("rsvd1 : %04x\n", cmd->rsvd1); + printf("nsid : %08x\n", cmd->nsid); + printf("cdw2 : %08x\n", cmd->cdw2); + printf("cdw3 : %08x\n", cmd->cdw3); + printf("data_len : %08x\n", cmd->data_len); + printf("metadata_len : %08x\n", cmd->metadata_len); + printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->addr); + printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->metadata); + printf("cdw10 : %08x\n", cmd->cdw10); + printf("cdw11 : %08x\n", cmd->cdw11); + printf("cdw12 : %08x\n", cmd->cdw12); + printf("cdw13 : %08x\n", cmd->cdw13); + printf("cdw14 : %08x\n", cmd->cdw14); + printf("cdw15 : %08x\n", cmd->cdw15); + printf("timeout_ms : %08x\n", cmd->timeout_ms); +} + +static void nvme_show_command(struct nvme_passthru_cmd *cmd, int err, struct timeval start, + struct timeval end) +{ + nvme_show_common(cmd); + printf("result : %08x\n", cmd->result); + printf("err : %d\n", err); + printf("latency : %lu us\n", + (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec)); +} + +static void nvme_show_command64(struct nvme_passthru_cmd64 *cmd, int err, struct timeval start, + struct timeval end) +{ + nvme_show_common((struct nvme_passthru_cmd *)cmd); + printf("result : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->result); + printf("err : %d\n", err); + printf("latency : %lu us\n", + (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec)); +} + +int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, + struct nvme_passthru_cmd *cmd, __u32 *result) +{ + struct timeval start; + struct timeval end; + int err; + + if (log_level >= LOG_DEBUG) + gettimeofday(&start, NULL); + + err = ioctl(fd, ioctl_cmd, cmd); + + if (log_level >= LOG_DEBUG) { + gettimeofday(&end, NULL); + nvme_show_command(cmd, err, start, end); + } + + if (err >= 0 && result) + *result = cmd->result; + + return err; +} + +int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd, + struct nvme_passthru_cmd64 *cmd, + __u64 *result) +{ + struct timeval start; + struct timeval end; + int err; + + if (log_level >= LOG_DEBUG) + gettimeofday(&start, NULL); + + + err = ioctl(fd, ioctl_cmd, cmd); + + if (log_level >= LOG_DEBUG) { + gettimeofday(&end, NULL); + nvme_show_command64(cmd, err, start, end); + } + + if (err >= 0 && result) + *result = cmd->result; + + return err; +} diff --git a/util/logging.h b/util/logging.h new file mode 100644 index 0000000000..7b1814cb78 --- /dev/null +++ b/util/logging.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#include + +extern int log_level; + +int map_log_level(int verbose, bool quiet); + +#endif // DEBUG_H_ diff --git a/util/mem.c b/util/mem.c new file mode 100644 index 0000000000..d2be46e870 --- /dev/null +++ b/util/mem.c @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include +#include +#include +#include +#include + +#include "mem.h" + +#include "common.h" + +#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) +#define HUGE_MIN 0x80000 + +void *nvme_alloc(size_t len) +{ + void *p; + + len = ROUND_UP(len, 0x1000); + if (posix_memalign((void *)&p, getpagesize(), len)) + return NULL; + + memset(p, 0, len); + return p; +} + +void *nvme_realloc(void *p, size_t len) +{ + size_t old_len = malloc_usable_size(p); + + void *result = nvme_alloc(len); + + if (p) { + memcpy(result, p, min(old_len, len)); + free(p); + } + + return result; +} + +void *nvme_alloc_huge(size_t len, struct nvme_mem_huge *mh) +{ + memset(mh, 0, sizeof(*mh)); + + len = ROUND_UP(len, 0x1000); + + /* + * For smaller allocation we just use posix_memalign and hope the kernel + * is able to convert to a contiguous memory region. + */ + if (len < HUGE_MIN) { + mh->p = nvme_alloc(len); + if (!mh->p) + return NULL; + mh->posix_memalign = true; + mh->len = len; + return mh->p; + } + + /* + * Larger allocation will almost certainly fail with the small + * allocation approach. Instead try pre-allocating memory from the + * HugeTLB pool. + * + * https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt + */ + mh->p = mmap(NULL, len, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB, -1, 0); + if (mh->p != MAP_FAILED) { + mh->len = len; + return mh->p; + } + + /* + * And if mmap fails because the pool is empty, try to use + * posix_memalign/madvise as fallback with a 2MB aligmnent in order to + * fullfil the request. This gives the kernel a chance to try to claim + * some huge pages. This might still fail though. + */ + len = ROUND_UP(len, 0x200000); + if (posix_memalign(&mh->p, 0x200000, len)) + return NULL; + mh->posix_memalign = true; + mh->len = len; + + memset(mh->p, 0, mh->len); + + if (madvise(mh->p, mh->len, MADV_HUGEPAGE) < 0) { + nvme_free_huge(mh); + return NULL; + } + + return mh->p; +} + +void nvme_free_huge(struct nvme_mem_huge *mh) + +{ + if (!mh || mh->len == 0) + return; + + if (mh->posix_memalign) + free(mh->p); + else + munmap(mh->p, mh->len); + + mh->len = 0; + mh->p = NULL; +} diff --git a/util/mem.h b/util/mem.h new file mode 100644 index 0000000000..d13eb3a213 --- /dev/null +++ b/util/mem.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef MEM_H_ +#define MEM_H_ + +#include +#include + +void *nvme_alloc(size_t len); +void *nvme_realloc(void *p, size_t len); + +struct nvme_mem_huge { + size_t len; + bool posix_memalign; /* p has been allocated using posix_memalign */ + void *p; +}; + +void *nvme_alloc_huge(size_t len, struct nvme_mem_huge *mh); +void nvme_free_huge(struct nvme_mem_huge *mh); + +#endif /* MEM_H_ */ diff --git a/util/meson.build b/util/meson.build index a999b80f16..0065b863c5 100644 --- a/util/meson.build +++ b/util/meson.build @@ -2,8 +2,16 @@ sources += [ 'util/argconfig.c', - 'util/cleanup.c', - 'util/json.c', - 'util/suffix.c', 'util/base64.c', + 'util/crc32.c', + 'util/logging.c', + 'util/mem.c', + 'util/suffix.c', + 'util/types.c', ] + +if json_c_dep.found() + sources += [ + 'util/json.c', + ] +endif diff --git a/util/suffix.c b/util/suffix.c index 6cd4f0b5d3..f010f3b6a9 100644 --- a/util/suffix.c +++ b/util/suffix.c @@ -31,35 +31,148 @@ */ #include "suffix.h" +#include "common.h" #include #include #include #include +#include +#include +#include +#include static struct si_suffix { - double magnitude; + long double magnitude; + unsigned int exponent; 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} + {1e30, 30, "Q"}, + {1e27, 27, "R"}, + {1e24, 24, "Y"}, + {1e21, 21, "Z"}, + {1e18, 18, "E"}, + {1e15, 15, "P"}, + {1e12, 12, "T"}, + {1e9, 9, "G"}, + {1e6, 6, "M"}, + {1e3, 3, "k"}, }; const char *suffix_si_get(double *value) { + long double value_ld = *value; + const char *suffix = suffix_si_get_ld(&value_ld); + + *value = value_ld; + + return suffix; +} + +static bool suffix_si_check(const char val) +{ + int i; struct si_suffix *s; - for (s = si_suffixes; s->magnitude != 0; s++) { + for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) { + s = &si_suffixes[i]; + + if (val == *s->suffix) + return true; + } + + return false; +} + +int suffix_si_parse(const char *str, char **endptr, uint64_t *val) +{ + unsigned long long num, frac = 0; + char *sep, *tmp; + int frac_len = 0, len, i; + + num = strtoull(str, endptr, 0); + if (str == *endptr || + ((num == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + /* simple number, no decimal point not suffix */ + if ((*endptr)[0] == '\0') { + *val = num; + return 0; + } + + /* get rid of the decimal point */ + sep = localeconv()->decimal_point; + if (sep) + len = strlen(sep); + else + len = 0; + + for (i = 0; i < len; i++) { + if (suffix_si_check((*endptr)[i])) + break; + if (((*endptr)[i] == '\0') || (*endptr)[i] != sep[i]) + return -EINVAL; + } + + if (suffix_si_check((*endptr)[i])) { + if ((*endptr)[i + 1] != '\0') + return -EINVAL; + } else { + *endptr += len; + tmp = *endptr; + + /* extract the digits after decimal point */ + frac = strtoull(tmp, endptr, 0); + if (tmp == *endptr || + ((frac == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + /* test that we have max one character as suffix */ + if ((*endptr)[0] != '\0' && (*endptr)[1] != '\0') + return -EINVAL; + + frac_len = *endptr - tmp; + } + + for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) { + struct si_suffix *s = &si_suffixes[i]; + + if ((*endptr)[0] != s->suffix[0]) + continue; + + /* we should check for overflow */ + for (int j = 0; j < s->exponent; j++) + num *= 10; + + if (s->exponent > frac_len) { + for (int j = 0; j < s->exponent - frac_len; j++) + frac *= 10; + } else if (s->exponent < frac_len) { + for (int j = 0; j < frac_len - s->exponent; j++) + frac /= 10; + } else { + frac = 0; + } + + *val = num + frac; + return 0; + } + + if ((*endptr)[0] != '\0') + return -EINVAL; + + *val = num; + return 0; +} + +const char *suffix_si_get_ld(long double *value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) { + struct si_suffix *s = &si_suffixes[i]; + if (*value >= s->magnitude) { *value /= s->magnitude; return s->suffix; @@ -78,14 +191,15 @@ static struct binary_suffix { {30, "Gi"}, {20, "Mi"}, {10, "Ki"}, - {0, ""} }; const char *suffix_binary_get(long long *value) { - struct binary_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - for (s = binary_suffixes; s->shift != 0; s++) { if (llabs(*value) >= (1LL << s->shift)) { *value = (*value + (1LL << (s->shift - 1))) / (1LL << s->shift); @@ -98,9 +212,11 @@ const char *suffix_binary_get(long long *value) const char *suffix_dbinary_get(double *value) { - struct binary_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - for (s = binary_suffixes; s->shift != 0; s++) { if (fabs(*value) >= (1LL << s->shift)) { *value = *value / (1LL << s->shift); return s->suffix; @@ -110,24 +226,41 @@ const char *suffix_dbinary_get(double *value) return ""; } -uint64_t suffix_binary_parse(const char *value) +int suffix_binary_parse(const char *str, char **endptr, uint64_t *val) { - char *suffix; - errno = 0; - uint64_t ret = strtoll(value, &suffix, 0); - if (errno) + uint64_t ret; + int i; + + ret = strtoull(str, endptr, 0); + if (str == *endptr || + ((ret == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + if (str == *endptr) { + *val = ret; return 0; + } + + /* simple number, no decimal point, no suffix */ + if ((*endptr)[0] == '\0') { + *val = ret; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - struct binary_suffix *s; - for (s = binary_suffixes; s->shift != 0; s++) { - if (tolower(suffix[0]) == tolower(s->suffix[0])) { + if (tolower((*endptr)[0]) == tolower(s->suffix[0]) && + (s->suffix[0] != '\0' && + (((*endptr)[0] != '\0' && + (*endptr)[1] != '\0' && + (*endptr)[2] == '\0') && + (tolower((*endptr)[1]) == tolower(s->suffix[1]))))) { ret <<= s->shift; - return ret; + *val = ret; + return 0; } } - if (suffix[0] != '\0') - errno = EINVAL; - - return ret; + return -EINVAL; } diff --git a/util/suffix.h b/util/suffix.h index 4f8e041bfd..5ea58f48ac 100644 --- a/util/suffix.h +++ b/util/suffix.h @@ -33,10 +33,13 @@ #ifndef __ARGCONFIG_SUFFIX_H__ #include +#include const char *suffix_si_get(double *value); +int suffix_si_parse(const char *str, char **endptr, uint64_t *val); +const char *suffix_si_get_ld(long double *value); const char *suffix_binary_get(long long *value); const char *suffix_dbinary_get(double *value); -uint64_t suffix_binary_parse(const char *value); +int suffix_binary_parse(const char *str, char **endptr, uint64_t *val); #endif diff --git a/util/types.c b/util/types.c new file mode 100644 index 0000000000..376c73435e --- /dev/null +++ b/util/types.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include + +#include + +#include "types.h" +#include "util/suffix.h" + +nvme_uint128_t le128_to_cpu(__u8 *data) +{ + nvme_uint128_t u; + nvme_uint128_t tmp; + + memcpy(tmp.bytes, data, 16); + u.words[0] = le32_to_cpu(tmp.words[3]); + u.words[1] = le32_to_cpu(tmp.words[2]); + u.words[2] = le32_to_cpu(tmp.words[1]); + u.words[3] = le32_to_cpu(tmp.words[0]); + return u; +} + +long double int128_to_double(__u8 *data) +{ + long double result = 0; + int i; + + for (i = 0; i < 16; i++) { + result *= 256; + result += data[15 - i]; + } + return result; +} + +uint64_t int48_to_long(__u8 *data) +{ + int i; + uint64_t result = 0; + + for (i = 0; i < 6; i++) { + result *= 256; + result += data[5 - i]; + } + return result; +} + +static long double uint128_t_to_double(nvme_uint128_t data) +{ + long double result = 0; + int i; + + for (i = 0; i < sizeof(data.words) / sizeof(*data.words); i++) { + result *= 4294967296; + result += data.words[i]; + } + + return result; +} + +static char *__uint128_t_to_string(nvme_uint128_t val, bool l10n) +{ + static char str[60]; + int idx = 60; + __u64 div, rem; + char *sep = NULL; + int i, len = 0, cl = 0; + + if (l10n) { + sep = localeconv()->thousands_sep; + len = strlen(sep); + cl = 1; + } + + /* terminate at the end, and build up from the ones */ + str[--idx] = '\0'; + + do { + if (len && !((sizeof(str) - idx) % (3 + cl))) { + for (i = 0; i < len; i++) + str[--idx] = sep[len - i - 1]; + } + + rem = val.words[0]; + + div = rem / 10; + rem = ((rem - div * 10) << 32) + val.words[1]; + val.words[0] = div; + + div = rem / 10; + rem = ((rem - div * 10) << 32) + val.words[2]; + val.words[1] = div; + + div = rem / 10; + rem = ((rem - div * 10) << 32) + val.words[3]; + val.words[2] = div; + + div = rem / 10; + rem = rem - div * 10; + val.words[3] = div; + + str[--idx] = '0' + rem; + } while (val.words[0] || val.words[1] || val.words[2] || val.words[3]); + + return str + idx; +} + +char *uint128_t_to_string(nvme_uint128_t val) +{ + return __uint128_t_to_string(val, false); +} + +char *uint128_t_to_l10n_string(nvme_uint128_t val) +{ + return __uint128_t_to_string(val, true); +} + +char *uint128_t_to_si_string(nvme_uint128_t val, __u32 bytes_per_unit) +{ + long double bytes = uint128_t_to_double(val) * bytes_per_unit; + static char str[40]; + const char *suffix = suffix_si_get_ld(&bytes); + int n = snprintf(str, sizeof(str), "%.2Lf %sB", bytes, suffix); + + if (n <= 0) + return ""; + + if (n >= sizeof(str)) + str[sizeof(str) - 1] = '\0'; + + return str; +} + +const char *util_uuid_to_string(unsigned char uuid[NVME_UUID_LEN]) +{ + static char uuid_str[NVME_UUID_LEN_STRING]; + + nvme_uuid_to_string(uuid, uuid_str); + + return uuid_str; +} + +const char *util_fw_to_string(char *c) +{ + static char ret[9]; + int i; + + for (i = 0; i < 8; i++) + ret[i] = c[i] >= '!' && c[i] <= '~' ? c[i] : '.'; + ret[i] = '\0'; + return ret; +} + +int convert_ts(time_t time, char *ts_buf) +{ + struct tm time_info; + time_t time_human, time_ms; + char buf[80]; + + time_human = time / 1000; + time_ms = time % 1000; + + gmtime_r((const time_t *)&time_human, &time_info); + + strftime(buf, sizeof(buf), "%Y-%m-%dD|%H:%M:%S", &time_info); + sprintf(ts_buf, "%s:%03ld", buf, time_ms); + + return 0; +} + +void util_spinner(const char *disp_name, float percent) +{ + static const char dash[51] = {[0 ... 49] = '=', '\0'}; + static const char space[51] = {[0 ... 49] = ' ', '\0'}; + static const char spin[] = {'-', '\\', '|', '/' }; + static int progress; + static int i; + const char *dn = disp_name ? disp_name : ""; + + if (percent < 0) + percent = 0; + else if (percent > 1) + percent = 1; + + progress = (int)(percent * 100.0); + if (progress < 2) + printf("\r%s [%c%.*s] %3d%%", dn, + spin[i % 4], 49, + space, progress); + else if (progress < 100) + printf("\r%s [%.*s%c%.*s] %3d%%", dn, + progress / 2 - 1, dash, + spin[i % 4], 50 - progress / 2, + space, progress); + else + printf("\r%s [%.*s] %3d%%\n", dn, + 50, dash, 100); + i++; + + fflush(stdout); +} diff --git a/util/types.h b/util/types.h new file mode 100644 index 0000000000..595958bb7c --- /dev/null +++ b/util/types.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _MISC_H +#define _MISC_H + +/* type conversion helpers */ + +#include +#include + +#include + +#define ABSOLUTE_ZERO_CELSIUS -273 + +static inline long kelvin_to_celsius(long t) +{ + return t + ABSOLUTE_ZERO_CELSIUS; +} + +/* uint128_t is not always available, define our own. */ +union nvme_uint128 { + __u8 bytes[16]; + __u32 words[4]; /* [0] is most significant word */ +}; + +typedef union nvme_uint128 nvme_uint128_t; + +nvme_uint128_t le128_to_cpu(__u8 *data); +long double int128_to_double(__u8 *data); +uint64_t int48_to_long(__u8 *data); + +char *uint128_t_to_string(nvme_uint128_t val); +char *uint128_t_to_l10n_string(nvme_uint128_t val); +char *uint128_t_to_si_string(nvme_uint128_t val, __u32 bytes_per_unit); +const char *util_uuid_to_string(unsigned char uuid[NVME_UUID_LEN]); +const char *util_fw_to_string(char *c); + +/** + * @brief convert time_t format time to a human readable string + * + * @param time, input time_t time + * @param ts_buf, output time string + * @Note, time string format is "Y-M-D|H:M:S:MS" + * + * @return 0 success + */ +int convert_ts(time_t time, char *ts_buf); + +/** + * @brief print once a progress of spinner to stdout + * the output will be looks like if disp_name is "LogDump" and percent is 0.5 + * LogDump [========================- ] 50% + + * + * @param disp_name, const string displayed before spiner + * @param percent [0, 1.0] about the progress + * + */ +void util_spinner(const char *disp_name, float percent); + +#endif /* _MISC_H */ diff --git a/wrapper.c b/wrapper.c deleted file mode 100644 index 2ba5b322a3..0000000000 --- a/wrapper.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * This file is part of nvme-cli - * - * Copyright (c) 2022 Daniel Wagner, SUSE - */ - -#include - -#include - -#define PROTO(args...) args -#define ARGS(args...) args - -#define VOID_FN(name, proto, args) \ -void __attribute__((weak)) name(proto) \ -{ \ - void (*fn)(proto); \ - fn = dlsym(RTLD_NEXT, #name); \ - if (fn) \ - fn(args); \ -} - -#define FN(name, rtype, proto, args, fallback) \ -rtype __attribute__((weak)) name(proto) \ -{ \ - rtype (*fn)(proto); \ - fn = dlsym(RTLD_NEXT, #name); \ - if (fn) \ - return fn(args); \ - return fallback; \ -} - -FN(nvme_get_version, - const char *, PROTO(enum nvme_version type), - ARGS(type), "n/a") - -VOID_FN(nvme_init_copy_range_f1, - PROTO(struct nvme_copy_range_f1 *copy, __u16 *nlbs, - __u64 *slbas, __u64 *eilbrts, __u32 *elbatms, - __u32 *elbats, __u16 nr), - ARGS(copy, nlbs, slbas, eilbrts, elbatms, elbats, nr))