はじめに
前回はSMART / Health Information Log を読めるようにしました。次に着手するのは、Error Information Log です。
この log page は、温度や使用率のような健康状態を見るものではなく、controller が保持している error 情報を並べたものです。
今回ここで整理したかったのは、主に次の 3 点でした。
Error Information LogはどういうデータフォーマットなのかELPEがなぜ必要になるのか
特に ELPE は、実装してみると必要だと分かるのですが、初期段階では少し分かりにくかった部分です。
理論: Error Information Log のデータ・フォーマット
Error Information Log は、SMART Log のように 1 ページを丸ごとひとつの構造体として見るというより、64 byte の entry が並んだ配列として見る方が分かりやすいです。
全体のデータ・フォーマットは以下のとおりです。
[07:00] Error Count (ECNT) 一意なエラー識別子
[09:08] Submission Queue ID (SQID) 該当SQ ID
[11:10] Command ID (CID) 該当Command ID
[13:12] Status Info (STS) 完了ステータス
[15:14] Parameter Error Location (PEL) パラメータ異常位置
[23:16] Logical Block address (LBA) 異常に関する先頭LBA
[27:24] Namespace Identifier (NSID) 関係するNamespace
[28] Vendor Specific Information Available (VSIA)
[29] Transport Type
[30] Command Set Indicator (CSI)
[31] Opcode (OPC) 関係するコマンド opcode
[39:32] Command Specific Information (CSINFO)
[41:40] Transport Type Specific Information (TTSI)
[62:42] reserved
[63] Log Page Version (LPVER)
これが読めると、「何か error があった」というだけでなく、
- どの command で起きたか
- どの queue / namespace に関係するか
- completion status は何か
を追えるようになります。
実際の出力はこうなる
mock では、次のような形で出力していました。
=== Error Log ===
--- count 0 ---
Error Count : 1
Submission Queue ID : 1
Command ID : 291
Status Info : 2
Parameter Error Location : 16
Logical Block Address : 4096
Namespace Identifier : 1
Vendor Specific Info Available : 0x00
Transport Type : 0x00
Command Set indicator : 0x00
Opcode : 0x02
Command Specific Information : 0
Transport Type Specific Information : 0
Log Page Version : 0x01
real device 側では、有効な error が無い場合に
=== Error Log ===
No Error Log in Nvme
と出るようにしています。
ここで分かるように、Error Information Log は「単一の status を返す」のではなく、entry を順に見ていく log です。
count はページ数ではなく entry 数
今回の実装では、引数に--countオプションを用意しています。これがエントリーをいくつ取るかを意味します。
1 entry は 64 byte なので、
count = 1なら 64 bytecount = 2なら 128 byte
の buffer を用意して Get Log Page を投げることになります。
この時点で、SMART Log とはかなり感覚が違います。
SMART Log
512 byte の 1 page をひとまとまりで読むError Information Log
64 byte entry をcount個ぶん読む
という差があるからです。
そのため実装側でも、Error Information Log は std::vector<LogErrorInfo> で受ける形にしました。
ELPE が必要になる
ここで必要になったのが Identify Controller の ELPE です。
ELPE は Error Log Page Entries を表す field で、controller が何件の error entry を保持できるかを示します。
ただし、その値は 0-based です。しかも field 自体は 8bit です。
つまり、
ELPE = 0x00なら最大 1 entryELPE = 0x0fなら最大 16 entryELPE = 0x3fなら最大 64 entryELPE = 0xffなら最大 256 entry- 実際の最大件数は常に
ELPE + 1
という解釈になります。
実際に自分の手元の device では ELPE = 0x0f でした。つまり最大 16 entry まで保持できることになります。
一方で mock では、少し大きめの値として 0x3f を入れていました。こちらは最大 64 entry です。
8bit なので理論上は最大 256 entry まで持てますが、そこまで error が積み上がる前に別の問題として気付くことの方が多そうです。実際の運用では、最大値そのものよりも「ELPE + 1 で上限が決まる」という考え方の方が重要ですね。
このことが分かると、--count は好きな値をそのまま受け取ればよいわけではなく、
- controller が保持できる最大件数を超えていないか
を見ておく必要があります。
ELPE を読むために Identify Controller も更新した
最初の Identify Controller 実装では、
VIDSSVIDserialmodelfirmware
のような、個体識別に必要な情報を優先して読んでいました。
Error Information Log を実装する段階で、そこへ ELPE を追加しました。
ここでいう ELPE は、Error Log Page Entries の略です。Identify Controller の中にあるこの 1 byte の field が、Error Information Log の最大 entry 数を決めています。
Identify Controllerで必要になる情報は、今後も必要になったタイミングで追加していきます。
Error Count == 0 は invalid entry とみなす
もうひとつ大きかったのが、Error Count == 0 の扱いです。
Error Information Log では、読み出した entry の先頭 8 byte に Error Count が入っています。
NVMe の仕様上、この値が 0 の時は invalid entry です。
実装としては、
- 64 byte ごとに
LogErrorInfoを組み立てる - 最初の
Error Countを見る 0なら vector に積まない
という流れです。
このおかげで、
countを多めに要求したが実際の error は少ない- そもそも error が無い
という時に、無効な entry までそのまま表示せずに済みます。
No Error Log in Nvme という表示も、この判断とつながっています。
実装の流れ
今回の実装でやっていること自体は、流れにするとかなりシンプルです。
Identify ControllerからELPEを読むELPE + 1を最大 entry 数として扱うcountがそれを超えるなら clamp する64 * countbyte の buffer を用意するGet Log Pageを投げる- 64 byte ごとに entry を decode する
Error Count == 0の entry は捨てる- vector に積んで表示する
SMART Log に比べると、decode する項目数はそこまで多くありません。
その代わり、
- entry 単位で読むこと
countをどう解釈するかELPEで上限を知ることError Count == 0を invalid とみなすこと
が実装上では重要です。
まとめ
Error Information Log を実装して分かったのは、ここで重要なのは field 数の多さではなく、entry の並び方と件数の扱い だということでした。
今回整理したポイントは次の通りです。
Error Information Logは 64 byte entry の配列として読むcountはページ数ではなく entry 数- 最大 entry 数は
ELPE + 1 ELPEを読むためにIdentify Controller側の実装も更新するError Count == 0の entry は invalid とみなす
SMART Log では単位の解釈が中心でしたが、Error Information Log ではフォーマットと件数の考え方を理解することが中心でした。