nvmeコマンド逆引きマニュアル(3)

# はじめに
　以前2回にわたり、NVMe SSDに対してLinux用のNVMe SSD操作ツール（コマンド）を使用して所望の操作を行う方法、いわゆる「逆引きマニュアル」をまとめました（[こちら](https://qiita.com/ken-yossy/items/7d20929ce2de0edd2190)と[こちら](https://qiita.com/ken-yossy/items/443d5c8768347ca7488f)）。

　その後、質問をいただいたり記事の間違いを見つけたりしましたので、その内容を含めて第3弾をまとめました。

# 記載内容
* Power State手動変更
* Sanitizeログ取得方法（以前書いた内容の訂正）
* Error Information取得

# 準備（再掲）
　ここではnvme-cliパッケージをLinux (Ubuntu)上で使用することを前提とします。また、操作対象のNVMe SSDは/dev/nvme0とします。お使いの環境に合わせて適宜読みかえてください。

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

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

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

# Power State手動変更
　まず質問をいただいた件です。

　以前の記事で「SSDの低消費電力状態」や「低消費電力状態への自動遷移」について説明しましたが、その後「特定の電力状態(Power State)に遷移させるにはどうしたらよいか」という質問をいただきました。

　そこで実験してみましたのでその結果を交えながら説明します。

　基本的には、以下の手順で実行できます。

1. `Get Features`コマンドで`Power Management`機能が変更可能かどうかを確認する
1. 変更可能であれば`Set Features`コマンドで所望のPower Stateに設定する
1. `Get Features`コマンドで所望のPower Stateに変更されているかどうかを確認する

　ただ、「低消費電力状態への自動遷移」機能(Autonomous Power State Transition: APST)が有効である場合、手動でPower Stateを変化させてもこの機能によりすぐに（人間が観測するより早く）別のPower Stateに遷移してしまう可能性が高いです。

　それでは意図通りに設定できたのかどうかが確認できずつまらないので、今回は以下の手順で実行します。

1. `Get Features`コマンドでPower Stateが変更可能かどうかを確認する
1. APSTが有効であれば無効化する
1. `Set Features`コマンドで所望のPower Stateに設定する
1. `Get Features`コマンドで所望のPower Stateに変更されているかどうかを確認する

## Power Stateが変更可能かどうかを確認する
　これは`Get Features`コマンドを使用します。
```
% sudo nvme get-feature /dev/nvme0n1 --feature-id=2 --sel=3
get-feature:0x2 (Power Management), Supported capabilities value:0x000004
  Feature is changeable
```
　このSSDはPower Stateを変更できるようです。ちなみに、このコマンドを実行した時点でのPower Stateは4 (PS4)のようです。

## APSTが有効であれば無効化する
　先ほど説明した通り、Power Stateを変更してもAPSTが有効では変更結果の観測が難しくなるため、APSTが有効化どうかを確認して有効であれば無効にします。

　APSTが有効かどうかも`Get Features`コマンドで調べます。
```
% sudo nvme get-feature /dev/nvme0n1 --feature-id=0xc --sel=0
get-feature:0xc (Autonomous Power State Transition), Current value:0x000001
       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
0000: 18 64 00 00 00 00 00 00 18 64 00 00 00 00 00 00 ".d.......d......"
(snip)
```
　現在の値が1ですので、このSSDのAPSTは有効のようです。そこでAPSTを無効化したいのですが、APSTの設定を変更できるとは限りませんので、念のため確認します。
```
% sudo nvme get-feature /dev/nvme0n1 --feature-id=0xc --sel=3
get-feature:0xc (Autonomous Power State Transition), Supported capabilities value:0x000004
  Feature is changeable
```
　このSSDのAPSTは設定変更可能であることがわかりましたので無効化します。無効化には`Set Features`コマンドを使用します。なお、APSTの設定は最後に有効に戻しますので、APSTの現在の設定値を保存（退避）してから無効化します。
```
% sudo nvme get-feature /dev/nvme0 -f 0xc -b > apst.dat

% hexdump apst.dat 
0000000 6418 0000 0000 0000 6418 0000 0000 0000
0000010 6418 0000 0000 0000 d020 0007 0000 0000
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
0000100

% dd bs=256 count=1 if=/dev/zero | sudo nvme set-feature /dev/nvme0 -f 0xc -v 0 -l 256
set-feature:0c (Autonomous Power State Transition), value:00000000
```
　これでAPSTの無効化が完了しました。

## 所望のPower Stateに設定する
　これで漸くPower Stateの変更を試すことができます。

　まず、変更前のPower Stateを確認します。
```
% sudo nvme get-feature -f 0x2 /dev/nvme0
get-feature:0x2 (Power Management), Current value:00000000
```
　APSTを無効化したためか、Power Stateは0 (PS0)に変更されていました。それではPower StateをPS1に変更してみます。
```
% sudo nvme set-feature -f 0x2 -v 1 /dev/nvme0
set-feature:02 (Power Management), value:0x000001
```
　これで変更できたはずです。再度`Get Features`コマンドで確認します。
```
% sudo nvme get-feature -f 0x2 /dev/nvme0
get-feature:0x2 (Power Management), Current value:0x000001
```
　現在値として1 (PS1)が取得できました。変更が成功したようです。

## APSTを有効に戻す
　最後に無効化したAPSTを有効に戻します。先ほど退避したAPSTの設定値を使用します。
```
% cat apst.dat | sudo nvme set-feature /dev/nvme0 -f 0xc -v 1 -l 256
set-feature:0c (Autonomous Power State Transition), value:0x000001
       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
0000: 18 64 00 00 00 00 00 00 18 64 00 00 00 00 00 00 ".d.......d......"
0010: 18 64 00 00 00 00 00 00 20 d0 07 00 00 00 00 00 ".d.............."
(snip)
```
　APSTが有効になるとすぐにPower Stateが変わるはずです。実際変更後にPower Stateを取得すると、
```
% sudo nvme get-feature -f 0x2 /dev/nvme0
get-feature:0x2 (Power Management), Current value:0x000004
```
　この通りPS4に遷移したことがわかります。

# Sanitizeログ取得方法（以前書いた内容の訂正）
　以前の記事で「廃棄や譲渡を前提としたデータの難読化」として`Sanitize`コマンドの実行方法をご説明しました。その際コマンドの進捗についてhuman friendlyではない方法をご紹介しましたが、nvmeコマンドはきちんとhuman friendlyなSanitizeコマンドの進捗状況表示機能を備えていますのでそちらをご紹介します。

　具体的には`sanitize-log`サブコマンドを使用します。こんな感じです。
```
% sudo nvme sanitize-log -H /dev/nvme0n1
```
　Sanitize処理実行中であれば以下のような出力を得られます。これはBlock Erase処理を実行している最中の出力です。
```
Sanitize Progress                      (SPROG) :  39321	(59.999084%)
Sanitize Status                        (SSTAT) :  0x102
	[2:0]	Sanitize in Progress.
	[7:3]	Number of completed passes if most recent operation was overwrite:	0
	  [8]	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
Sanitize Command Dword 10 Information (SCDW10) :  0x2
Estimated Time For Overwrite                   :  0xffffffff (No time period reported)
Estimated Time For Block Erase                 :  60
Estimated Time For Crypto Erase                :  0xffffffff (No time period reported)
Estimated Time For Overwrite (No-Deallocate)   :  0xffffffff (No time period reported)
Estimated Time For Block Erase (No-Deallocate) :  0xffffffff (No time period reported)
Estimated Time For Crypto Erase (No-Deallocate):  0xffffffff (No time period reported)
```
　Sanitize Progressとして59%と進捗が表示されていることがわかります。

　Sanitize処理が完了した（実行中でない）時は以下のような出力になります。
```
Sanitize Progress                      (SPROG) :  65535
Sanitize Status                        (SSTAT) :  0x101
	[2:0]	Most Recent Sanitize Command Completed Successfully.
	[7:3]	Number of completed passes if most recent operation was overwrite:	0
	  [8]	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
Sanitize Command Dword 10 Information (SCDW10) :  0x2
Estimated Time For Overwrite                   :  0xffffffff (No time period reported)
Estimated Time For Block Erase                 :  60
Estimated Time For Crypto Erase                :  0xffffffff (No time period reported)
Estimated Time For Overwrite (No-Deallocate)   :  0xffffffff (No time period reported)
Estimated Time For Block Erase (No-Deallocate) :  0xffffffff (No time period reported)
Estimated Time For Crypto Erase (No-Deallocate):  0xffffffff (No time period reported)
```
　これならわかりやすいですね。

# Error Information取得
　NVMe仕様にはError Informationという情報が定義されています。何かエラーと呼べるような事象が発生した際に、その事象がホストから受領したコマンドに起因するものであればそのコマンドやLBAの情報も含めて記録されるものです。

　このError Informationはオプション機能ですが、`Get Log Page`コマンドで取得できるため比較的取得が簡単です。そこで試してみます。

　なお、このError InformationはSSDをリセット（例えばPCを再起動する、など）してしまうと内容が消えてしまいますので注意が必要です。

　まず、これまでにError Informationとして記録された情報の数（累積数）を、SMART情報を取得して調べます。

```
% sudo nvme smart-log -H /dev/nvme0

Smart Log for NVME device:nvme0 namespace-id:ffffffff
critical_warning                    : 0
temperature                         : 31 C
available_spare                     : 100%
available_spare_threshold           : 10%
percentage_used                     : 0%
data_units_read                     : 63,606
data_units_written                  : 868,052
host_read_commands                  : 789,555
host_write_commands                 : 1,649,951
controller_busy_time                : 35
power_cycles                        : 59
power_on_hours                      : 155
unsafe_shutdowns                    : 20
media_errors                        : 0
num_err_log_entries                 : 12 ★ ココ
Warning Temperature Time            : 0
Critical Composite Temperature Time : 0
Thermal Management T1 Trans Count   : 0
Thermal Management T2 Trans Count   : 0
Thermal Management T1 Total Time    : 0
Thermal Management T2 Total Time    : 0
```

　取得した12という数はドライブの生涯における通算Error Information記録数であり、12個のError Informationが取得可能というわけではないことに注意が必要です。

　実際、Error Informationを先頭の1エントリだけ取得しようとコマンドを発行してみると、

```
% sudo nvme error-log /dev/nvme0 -e 1

Error Log Entries for device:nvme0 entries:1
.................
 Entry[ 0]   
.................
error_count  : 0
sqid         : 0
cmdid        : 0
status_field : 0(SUCCESS: The command completed successfully)
parm_err_loc : 0
lba          : 0
nsid         : 0
vs           : 0
cs           : 0
.................
```

 　このように先頭のエントリが無効でありひとつも記録されていませんでした。エントリ先頭の`error_count`というフィールドがError InformationのIDであり、有効なエントリであればこの値が非ゼロになります。

　つまり、有効なError Informationを取得するには、SMART情報にあるError Information数が増えたらすぐに取得しなければならない、ということになります。
 
# おわりに
　この記事では、NVMe SSDに対してLinux用のNVMe SSD操作ツール（コマンド）を使用して所望の操作を行う方法、いわゆる「逆引きマニュアル」について、これまでの記事の補足をしました。

　これまでに説明した内容と合わせて、NVMe SSDを操作する際の助けになれば幸いです。

　ただし、一部の設定はメーカーが製品の設計や特徴を踏まえて設定しているものが多く、それらを変更することは副作用を伴う可能性が高いです。このため、操作を行う際はデータのバックアップはもちろん、十分に注意して実施してください。

# ライセンス表記
<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>の下に提供されています。