nvmeコマンド逆引きマニュアル(1/2)

# はじめに
　NVMe SSDが広く使われるようになり、Windowsではメーカーが配布するツールや[CrystalDiskInfo](https://crystalmark.info/ja/software/crystaldiskinfo/)などのツールを使うことで様々な情報取得や操作ができるようになりました。

　しかしLinuxでは一部を除いてメーカー配布ツールは存在せず、またWindowsの制約によりWindows上ではできない操作も存在します。

　そこで、NVMe SSDに対してLinux用のNVMe SSD操作ツール（コマンド）を使用して所望の操作を行う方法、いわゆる「逆引きマニュアル」をまとめます。

　例えばPCIe / NVMe M.2 SSDを直結できるRaspberry Pi 5にM.2 SSDを接続すれば、簡単な情報の取得と表示（図1）や廃棄前のデータ消去などの操作を大掛かりな装置なしに実行できます。

![Raspberry Pi 5にPCIe/NVMe M.2 SSDを接続した様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/a6234d0d-8099-8734-b7cd-44df18c92cd1.png "Raspberry Pi 5にPCIe/NVMe M.2 SSDを接続した様子")
_図1：Raspberry Pi 5にPCIe/NVMe M.2 SSDを接続した様子（画像は一部加工しています）_

# 記載する内容
　色々項目を追加していたら記事が肥大化しましたので、2つの記事に分割しました。今回の記事に記載している内容と、次回の記事に記載予定の内容は以下の通りです。

* この記事に記載している内容
    * 個体情報取得
    * 容量取得
    * 温度取得
    * 残寿命取得
    * サポートコマンドリスト取得
    * サーマルスロットリング関連温度の取得
    * サーマルスロットリング関連温度の設定
    * サーマルスロットリングの無効化と有効化
* 次回記事に記載予定の内容
    * 自己診断実行
    * フォーマット実行
    * Trim実行
    * 揮発ライトキャッシュの無効化／有効化
    * SSDが備える低消費電力状態を調べる
    * 低消費電力状態への自動遷移
    * 低消費電力状態への自動遷移の無効化／有効化
    * 廃棄や譲渡を前提としたデータの難読化
    * Host Memory Buffer (HMB)の有効無効切り替え

# 準備
　この記事では[``nvme-cli``パッケージ](https://github.com/linux-nvme/nvme-cli)をLinux (Ubuntu)上で使用することを前提とします。また、操作対象のNVMe SSDは``/dev/nvme0``として認識されているとします。このあたりはお使いの環境に合わせて適宜読み替えてください。

　なお動作確認したOSはUbuntu 20.04.6 LTS、カーネルは5.4.0-173 (amd64)、``nvme-cli``パッケージのバージョンは1.9.1ubuntu0.1です。

　加えて、操作の際にはデバイスを直接読み書きしますので例えば``sudo``コマンドなどで適切な権限のもと実行できるようにしておく必要があります。

:::note warn
設定変更を伴う操作は、SSDの挙動が不安定になる、記録されていたデータが読み出せなくなる、などの副作用を伴う可能性があります。操作の内容を良く理解し、十分に注意して実行してください。
:::

# 個体情報取得
　ここで言う個体情報とは、モデル名、シリアル番号、ファームウェアリビジョンを指します。

　これらの情報は``id-ctrl``サブコマンドを使用して取得できるコントローラ情報(Identify Controller Data Structure)にあります。コントローラ情報は内容がとても多いのですが、個体情報のみであれば冒頭の10行程度を見れば十分です。以下が実行例です。
```
% sudo nvme id-ctrl /dev/nvme0 -H | head
NVME Identify Controller:
vid       : 0x126f
ssvid     : 0x126f
sn        : J411003E03366
mn        : BIOSTAR M700-256GB
fr        : S0614B0
rab       : 6
ieee      : 000000
cmic      : 0
  [3:3] : 0     ANA not supported
```
　``sn``がシリアル番号、``mn``がモデル名、``fr``がファームウェアリビジョンです。

# 容量取得
　SSDの容量（ユーザが使用できる容量）は、``id-ns``サブコマンドを使用して取得できるネームスペースの情報(Identify Namespace Data Structure)にあります。
 
　一般的な使いかたであればSSDにネームスペースは1つしか存在しないと思いますので、その唯一のネームスペース（ネームスペース番号1）を指定してコマンドを発行します。以下が実行例です。
```
% sudo nvme id-ns /dev/nvme0 -H -n 1
nsze    : 0x1dcf32b0
ncap    : 0x1dcf32b0
nuse    : 0x1dcf32b0
nsfeat  : 0x4
  [4:4] : 0     NPWG, NPWA, NPDG, NPDA, and NOWS are Not Supported
  [2:2] : 0x1   Deallocated or Unwritten Logical Block error Supported
  [1:1] : 0     Namespace uses AWUN, AWUPF, and ACWU
  [0:0] : 0     Thin Provisioning Not Supported

nlbaf   : 0
flbas   : 0
  [4:4] : 0     Metadata Transferred in Separate Contiguous Buffer
  [3:0] : 0     Current LBA Format Selected
(snip)
LBA Format  0 : Metadata Size: 0   bytes - Data Size: 512 bytes - Relative Performance: 0 Best (in use)
```
　まず、現在のセクタサイズを特定します。``flbas``フィールドのビット0から3が現在のフォーマット番号(Current LBA Format Selected)ですのでこの例ではフォーマット0となります。そして取得結果の一番下を見るとフォーマット0のサイズは512バイトと書かれていますので、現在のセクタサイズは512バイトとわかります。

　加えて``nsze``フィールドが総セクタ数（16進数であることに注意）ですのでこの値と512を掛け算すると256,060,514,304バイト、およそ250 GBとわかります。

# 温度取得
　SSDの温度はComposite Temperatureというデータが対応し、このデータは``smart-log``サブコマンドを使用して取得できるS.M.A.R.T.情報にあります。以下が実行例です。
```
% sudo nvme smart-log /dev/nvme0 | grep temperature
temperature                         : 34 C
```

# 残寿命取得
　SSDの残寿命もS.M.A.R.T.情報を使用して計算します。以下が実行例です。
```
% sudo nvme smart-log /dev/nvme0 | grep percentage_used
percentage_used                     : 0%
```
　Percentage Usedは使用率ですのでこの値を100から引き算して残寿命が求まります。

# サポートコマンドリスト取得
　NVMe仕様には多くのオプションコマンドがあります。例えばフォーマットに使用する``Format NVM``コマンドや、データ消去（難読化）に使用する``Sanitize``コマンド、さらにはいわゆる「Trimコマンド」に相当する``Dataset Management``コマンドもオプションコマンドです。
 
　操作対象のSSDがそれらのオプションコマンドをサポートしているかどうかを調べるには、``effects-log``サブコマンドを使用しCommand Supported and Effects Logという情報を取得して調べるのがわかりやすいです。

　そこで早速このサブコマンドを発行したいのですが、実はCommand Supported and Effects Logの取得に対応しているかどうかもオプションなので、まずはこの情報を取得できるかどうかを調べます。これは``id-ctrl``サブコマンドで取得できるコントローラ情報にあります。以下が実行例です。
```
% sudo nvme id-ctrl -H /dev/nvme0 | grep "Command Effects"
  [1:1] : 0x1   Command Effects Log Page Supported
```
　このSSDはCommand Supported and Effects Logの取得に対応していることがわかりました。そこで実際に取得した結果が以下の通りです。
```
% sudo nvme effects-log -H /dev/nvme0
Admin Command Set
ACS0     [Delete I/O Submission Queue     ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS1     [Create I/O Submission Queue     ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS2     [Get Log Page                    ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS4     [Delete I/O Completion Queue     ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS5     [Create I/O Completion Queue     ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS6     [Identify                        ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS8     [Abort                           ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS9     [Set Features                    ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS10    [Get Features                    ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS12    [Asynchronous Event Request      ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS16    [Firmware Commit                 ] 00000011  CSUPP+  LBCC-  NCC-  NIC-  CCC+  USS-  No command restriction
ACS17    [Firmware Image Download         ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS128   [Format NVM                      ] 00000007  CSUPP+  LBCC+  NCC+  NIC-  CCC-  USS-  No command restriction
ACS129   [Security Send                   ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS130   [Security Receive                ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS132   [Sanitize                        ] 00000003  CSUPP+  LBCC+  NCC-  NIC-  CCC-  USS-  No command restriction
ACS192   [Unknown                         ] 00000009  CSUPP+  LBCC-  NCC-  NIC+  CCC-  USS-  No command restriction
ACS193   [Unknown                         ] 00020001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No other command for any namespace
ACS194   [Unknown                         ] 00020001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No other command for any namespace
ACS196   [Unknown                         ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
ACS200   [Unknown                         ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction

NVM Command Set
IOCS0    [Flush                           ] 00000003  CSUPP+  LBCC+  NCC-  NIC-  CCC-  USS-  No command restriction
IOCS1    [Write                           ] 00000003  CSUPP+  LBCC+  NCC-  NIC-  CCC-  USS-  No command restriction
IOCS2    [Read                            ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
IOCS4    [Write Uncorrectable             ] 00000003  CSUPP+  LBCC+  NCC-  NIC-  CCC-  USS-  No command restriction
IOCS5    [Compare                         ] 00000001  CSUPP+  LBCC-  NCC-  NIC-  CCC-  USS-  No command restriction
IOCS8    [Write Zeroes                    ] 00000007  CSUPP+  LBCC+  NCC+  NIC-  CCC-  USS-  No command restriction
IOCS9    [Dataset Management              ] 00000003  CSUPP+  LBCC+  NCC-  NIC-  CCC-  USS-  No command restriction
```
　結果に表示されたコマンド（正確には「``CSUPP+``と記載されたコマンド」だがサポートしているコマンドしか表示されない）がこのSSDのサポートするコマンドです。

　このSSDは、``Format NVM``コマンド、``Sanitize``コマンド、そして``Dataset Management``コマンドをサポートしていることがわかります。

　コマンド名に``Unknown``と書かれたコマンドは「ベンダ固有コマンド(Vendor Specific Command)」です。

# サーマルスロットリング関連温度の取得
　特に高性能NVMe SSDを語る際、発熱そしてサーマルスロットリングについて話題になることが多いです。

　NVMe仕様はホストが制御可能なサーマルスロットリング機能(Host Controlled Thermal Management: HCTM)を備えます。

　この機能のサポート有無はコントローラ情報で判別できます。以下が実行例です。
```
% sudo nvme id-ctrl -H /dev/nvme0 | grep "Thermal Management"
  [0:0] : 0x1   Host Controlled Thermal Management Supported
```
　このSSDはHCTMに対応していることがわかりました。

　HCTMにはThermal Management Temperatureと呼ばれる設定可能な温度が2種類存在します。それぞれTMT1、TMT2と略されます。

　この温度は``get-feature``サブコマンドで取得できます。以下が実行例です。
```
% sudo nvme get-feature -H /dev/nvme0 -f 0x10
get-feature:0x10 (Host Controlled Thermal Management), Current value:0x1620166
        Thermal Management Temperature 1 (TMT1) : 354 Kelvin
        Thermal Management Temperature 2 (TMT2) : 358 Kelvin
```
　このSSDの現在のTMT1は華氏354度（摂氏約81度）でTMT2は華氏358度（摂氏約85度）であることがわかりました。
  
# サーマルスロットリング関連温度の設定
　SSDがHCTMに対応している場合、ホストがTMT1およびTMT2を変更できる可能性があります。

　TMT1およびTMT2を変更できるかどうかは、以下のようにして調べます。
```
% sudo nvme get-feature -H /dev/nvme0 -f 0x10 -s 3
get-feature:0x10 (Host Controlled Thermal Management), Supported capabilities value:0x000005
  Feature is saveable
  Feature is changeable
```
　このSSDの場合、設定値は変更可能(changeable)でかつ不揮発化可能(saveable)と表示されました。「不揮発化可能」とは、電源断を経ても設定内容が維持（保存）される、ことを指します。

　「変更可能」と判明したので早速TMT1とTMT2を変更したいのですが、実はTMT1とTMT2に設定できる温度には2つの制約があります。

　ひとつは、TMT1のほうがTMT2よりも小さい温度でなければならないことです。これは、NVMe仕様においてTMT1は弱いサーマルスロットリングを開始する温度、TMT2は強いサーマルスロットリングを開始する温度、と規定されているからです。

　そしてもうひとつは、TMT1とTMT2に設定可能な温度の範囲がSSDごとに規定されていることです。この範囲はコントローラ情報の中にあります。以下が実行例です。
```
% sudo nvme id-ctrl -H /dev/nvme0 | grep tmt
mntmt     : 348
mxtmt     : 358
```
　この例の場合、TMT1とTMT2に設定可能な最小温度(Minimum Thermal Management Temperature: MNTMT)は華氏348度（摂氏約75度）で最高温度(Maximum Thermal Management Temperature: MXTMT)は華氏358度（摂氏約85度）であることがわかります。

　そこで、TMT2は華氏358度（摂氏約84度）のままにしてTMT1を華氏355度（摂氏約82度）に変更してみます。
```
% sudo nvme set-feature /dev/nvme0 -f 0x10 -v 0x01630166
set-feature:10 (Host Controlled Thermal Management), value:0x1630166
```
　こんな感じで表示されれば成功です。再度``get-feature``サブコマンドを発行すれば変更された値を確認できます。なお、この設定を不揮発化する場合は``set-feature``サブコマンド発行時に``-s``オプションを付与します。

# サーマルスロットリングの無効化と有効化
　HCTMの設定値が変更可能であれば、HCTM無効と有効の切り替えもこのコマンドを使用して実行可能です。

　NVMe仕様によれば、HTCMをサポートするSSDに対して、TMT1とTMT2に0を設定すると機能は無効になります。またTMT1とTMT2に正しい値を設定することで機能が有効になります。

::: note warn
この方法で無効化できるのはHTCMによるサーマルスロットリングであり、SSDが自身を保護するために実行するサーマルスロットリングなどの高温対策機能は無効化できません。
:::

　例えば無効化する場合は以下のようにします。
```
% sudo nvme set-feature /dev/nvme0 -f 0x10 -v 0
set-feature:10 (Host Controlled Thermal Management), value:00000000
```
　一方、前記「サーマルスロットリング関連温度の設定」で示したようにTMT1とTMT2に非ゼロで適切な値を設定すれば機能が有効になります。
 
# おわりに
　この記事では、NVMe SSDに対してLinux用のNVMe SSD操作ツール（コマンド）を使用して所望の操作を行う方法、いわゆる「逆引きマニュアル」をまとめました。

　なおここに記載した操作は私が独断で選んだ「使う機会が多い・ありそう」な例であり、他にも様々な処理の実行や設定変更が可能です。

　NVMeは既に巨大な仕様であり、良く使う機能や設定もそれらの中に埋もれて探すのに苦労することが多いと思われます。そのよう際の助けになれば幸いです。Windowsではなかなかできない操作でもLinux上でこのnvmeコマンドを使えば実現可能であることが多いのも特徴です。

　ただし記事の中でも触れましたが、設定内容の中にはメーカーが製品の設計や特徴を踏まえて設定しているものが多く、それらを変更することは副作用を招く可能性が高いです。このため、そのような操作を行う際はデータのバックアップはもちろん、十分に注意して実施してください。
 
# ライセンス表記
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="クリエイティブ・コモンズ・ライセンス" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />この記事は<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンス</a>の下に提供されています。