Windowsの標準NVMeドライバでNVMe SSDにアクセスする：更新情報

# はじめに
　以前、Windows 10（以降Windowsと記載します）の標準NVMeデバイスドライバを使用して、ユーザ空間で動作するプログラムからNVMe SSDに対して、以下のコマンドを発行する方法を紹介しました。

* `Read`、`Write`、`Dataset Management`(Deallocate)（[こちら](https://qiita.com/ken-yossy/items/30f0dd206713aba770f7)）
* `Identify`（[こちら](https://qiita.com/ken-yossy/items/d4cd6502fe475d78e872)）
* `Get Log Page`（[こちら](https://qiita.com/ken-yossy/items/ffecfd31d41d71f27dca)）

　その後Microsoftのドキュメントには特に更新がなかったのですが、先日（2020年5月）更新があり、Windowsの標準NVMeデバイスドライバを使用してできること（発行できるコマンドなど）についてまとめられた記事<sup>[1]</sup>が公開されました。

　今回公開された内容は、Windows 10 version 1903以降の標準NVMeデバイスドライバ(StorNVMe)に関する情報で、大きく分けて3つあります。

1. コマンドのサポート情報
2. 機能(Feature)のサポート情報
3. SCSIコマンドとNVMeコマンドの対応関係情報

　そこでこの記事では、コマンドのサポート情報についてその内容を見ていきたいと思います。

# まとめ
* これまで明らかにされていなかった、各コマンドのサポート状況が明らかにされた
* この情報に基づき、`Flush`コマンドと`Format NVM`コマンドを、Windowsの標準NVMeデバイスドライバを使用して発行できることを確認した

# コマンドサポート情報
　今回公開された記事には、以前（一年ほど前）記事を書いた際には記載されていなかった、コマンドのサポート状況をまとめた表が記載されています<sup>[2]</sup>。

　以下の表1は、その表の一部を引用したものです。この表1のように、AdminコマンドセットおよびNVMコマンドセットの各コマンドについて、そのサポート状況が記載されています。

表1：公開されたコマンドサポート表（一部）
![公開されたコマンドサポート表（一部）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/70f5b214-95ff-f453-b617-d7497fe0a606.png "公開されたコマンドサポート表（一部）")

　この表に書かれている内容にはいくつかのパターンがあります。

## "Internal Driver Usage"とだけ書かれたコマンド
　"Internal Driver Usage"という記載は、言葉の通り「このデバイスドライバ(StorNVMe)が、このコマンドを、内部で使用している」という意味だと思われます。ですので、"Internal Driver Usage"と書かれているコマンドは、「このデバイスドライバがこのコマンドを発行する（ことがある）」と解釈できます。

　一方で、"Internal Driver Usage"**とだけ**書かれているコマンドは、「外部からこのデバイスドライバを利用して発行することはできない」という意味だと解釈できます。

　例えば、表1にある`Delete I/O Submission Queue`コマンドや`Create I/O Submission Queue`コマンドは、"StorNVMe Support"の列に"Internal Driver Usage"とだけ書かれていますので、ユーザ空間のプログラムを含む外部から（`DeviceIoControl()`を使うなどして）このデバイスドライバを利用して発行することはできない、と思われます。

　上記2つのコマンドは、NVMeドライブとの間でのコマンド発行やレスポンス受信に用いるキューの作成や削除を行うコマンドですので、ユーザ空間から好き勝手に発行可能だと困るという理由からこのような扱いになっているのでしょう。

## "IOCTL_STORAGE_"から始まる識別子が書かれたコマンド
　表1では、`Get Log Page`コマンドについて、"StorNVMe Support"の列に"Internal Driver Usage"だけでなく、"IOCTL_STORAGE_QUERY_PROPERTY"と記載されています。

　`Get Log Page`コマンドは、S.M.A.R.T.属性などを取得するためのコマンドで、[以前の記事](https://qiita.com/ken-yossy/items/ffecfd31d41d71f27dca)で説明した通り、Windowsの標準NVMeデバイスドライバを使用して発行できることを確認済みです。

　したがって、"StorNVMe Support"の列に"IOCTL_STORAGE_"から始まる識別子が記載されているコマンドは、「ユーザ空間のプログラムを含む外部から、（`DeviceIoControl()`を使うなどして）このデバイスドライバを利用して発行することができる」ことを意味すると考えられます。

　ただし、"StorNVMe Support"の列に"IOCTL_STORAGE_"から始まる識別子が記載されていても、コメント欄に制約が書かれている場合があります。

表2：公開されたコマンドサポート表（一部、その2）
![公開されたコマンドサポート表（一部、その2）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/eca75b05-0f91-e88b-fed4-8f693d315dc3.png "公開されたコマンドサポート表（一部、その2）")

　表2に引用したサポート表には、"StorNVMe Support"の列に"IOCTL_STORAGE_"から始まる識別子が記載されているものの、コメント列に制約が書かれているコマンドがあります。

　例えば、`Set Features`コマンドはNVMeドライブが持つ様々な機能の設定を行うコマンドですが、コメント列には、ホスト制御によるサーマルスロットリング(Host Controlled Thermal Management; HCTM)に関する設定のみ可能であると記載されています。

　また、同じく表2にある`Namespace Management`コマンドについては、コメント列に「Win PEモードでのみ可能」と記載されています。

　"Win PE"とは"Windows Preinstallation Environment"<sup>[3]</sup>のことで、Windowsのインストールや企業・組織におけるWindows環境の展開、さらにはトラブルシューティングに使われる特殊な環境のことで、私たちが日頃使用するいわゆるフルセットのWindowsではありません。

　したがって、コメント列に「Win PEモードでのみ可能」と記載されているコマンドは、通常のWindows環境では「ユーザ空間のプログラムを含む外部から（`DeviceIoControl()`を使うなどして）このデバイスドライバを利用して発行することはできない」という意味だと解釈できます。

## "IOCTL_SCSI_PASS_THROUGH"と書かれたコマンド
　"StorNVMe Support"の列に"IOCTL_SCSI_PASS_THROUGH"と記載されているコマンドは、SCSI Pass-Through機構を用いて発行可能であることを示していると考えられます。

　表3は、`Flush`、`Write`、そして`Read`コマンドについての記述を抜粋したものです。

表3：公開されたコマンドサポート表（一部、その3）
![公開されたコマンドサポート表（一部、その3）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/5e63ad72-73ec-c9c1-d921-4ecf2f1572b5.png "公開されたコマンドサポート表（一部、その3）")

　表3の通り、これらのコマンドは"StorNVMe Support"の列に"IOCTL_SCSI_PASS_THROUGH"と記載されています。そして、コメント列にはそれぞれ対応するSCSIコマンドが記載されています。

　`Write`コマンドと`Read`コマンドについては、[以前の記事](https://qiita.com/ken-yossy/items/30f0dd206713aba770f7)で説明した通り、SCSI Pass-Through機構を用いることで、Windowsの標準NVMeデバイスドライバを使用して発行できることを確認済みです。

　したがって、"StorNVMe Support"の列に"IOCTL_SCSI_PASS_THROUGH"と記載されているコマンドは、SCSI Pass-Through機構を用いて発行可能であることを示していると推測できます。

## "Currently not supported"と書かれたコマンド
　これまでの解釈から総合すると、コメント列に"Currently not supported"と書かれたコマンドは、「このデバイスドライバ(StorNVMe)は内部で使用しない」かつ「外部からこのデバイスドライバを利用して発行することはできない」という意味だと推測できます。

　`Write Uncorrectable`コマンドが未サポートでかつ未使用となっているのは意外でした。HDDの時代から（SCSI Block CommandやATA Command Setに）存在するレガシーなコマンドとはいえ、RAID環境でのリカバリ処理などでは必要になると考えられるからです。SCSI Pass-Through機構を使って`WRITE LONG`コマンドにマッピングすればできそうに思えるのですが。

# 今回発行できることを確認したコマンド
　今回新しい情報が公開されたことを受けて、2つのコマンドが発行できることを追加で確認しました。

　ひとつは`Flush`コマンド、もう一つは`Format NVM`コマンドです。

## `Flush`コマンド
　`Flush`コマンドについては、表3の内容より、SCSI Pass-Through機構を用いて発行できそうなことがわかりました。

　そこで今回、SCSIの`SYNCHRONIZE CACHE`コマンドに相当する`SCSIOP_SYNCHRONIZE_CACHE`を指定してSCSI Pass-Through機構を用いることで、ユーザ空間のプログラムから発行できることを実際に確認しました<sup>[4]</sup>。

　なお、`Flush`コマンドが実際に発行されたこと（SSDが`Flush`コマンドを受信したこと）を、SSDの外部から、`Flush`コマンド実行前後の違いを観測することで確認するのは難しいです。

　このため、QemuでエミュレートされたNVMeドライブに対してこの方法で`Flush`コマンドを発行し、NVMeドライブのエミュレーションコード側で、実際に`Flush`コマンドを受信したことを確認しました。

## `Format NVM`コマンド
　今回公開された記事では、`Format NVM`コマンドのサポート状況については、以下の表4のように、いくつかの方法で発行できることが記載されています。

表4：Format NVMコマンドのサポート状況
![Format NVMコマンドのサポート状況](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/c82a7b5d-633a-9a3d-fd3a-27d7c9da9e5d.png "Format NVMコマンドのサポート状況")

　この"Comments"欄には以下の3つのことが記載されています。

1. `IOCTL_STORAGE_PROTOCOL_COMMAND`を使った（`Format NVM`コマンドの）発行は、WinPEモードでのみ可能
2. `IOCTL_SCSI_PASS_THROUGH`（SCSI Pass-Through機構）を使う場合は`SCSIOP_SANITIZE`を指定すること
3. `IOCTL_STORAGE_REINITIALIZE_MEDIA`を使う場合は、ドライブが暗号的消去(cryptographic erase)をサポートしていることが必要

　今回は上記3の方法（`IOCTL_STORAGE_REINITIALIZE_MEDIA`を指定する方法）で`Format NVM`コマンドの発行を試みて、成功しました。

　確認した方法は以下の2つです。

1. `Write`コマンドでセクタ0に書き込んで、セクタ0にデータが書けたことを`Read`コマンドで確認し、その後`Format NVM`コマンドを発行した後に、`Read`コマンドでセクタ0を読み出して先に書き込んだデータが読めないこと
2. QemuでエミュレートされたNVMeドライブに対してこの方法で`Format NVM`コマンドを発行し、NVMeドライブのエミュレーションコード側で実際に`Format NVM`コマンドを受信したこと

　2の確認時には、発行された`Format NVM`コマンドの、"Secure Erase Setting (SES)"フィールドの値が`2`となっていることを観測しました。

　NVMe仕様<sup>[5]</sup>によると、SESフィールドの内容は表5のようになっています。

表5：Format NVMコマンドのSESフィールドの内容（NVMe仕様のFigure 174から抜粋）
![Format NVMコマンドのSESフィールドの内容](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/74ba6782-8444-4b48-36ba-adead784353c.png "Format NVMコマンドのSESフィールドの内容")

　したがって、NVMeドライブが受信した`Format NVM`コマンドのSESフィールドが2だったということは、Windowsの標準デバイスドライバがNVMeドライブに対して暗号的消去(cryptographic erase)を要求した、ということになります。

　確かに、表4の"Comments"欄でも暗号的消去のサポートを求めています。

　実はこのことは、Microsoftが定めているWindows 10向けハードウェア互換性プログラム(Windows Hardware Compatibility Program, WHCP)仕様<sup>[6]</sup>に記載されています。

　WHCP仕様の仕様書の"Device.Storage.ControllerDrive.NVMe"節には、以下のような記述があります。

![WHCP仕様におけるFormat NVMコマンドに関する規定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/823377d6-e053-b402-4079-2106ed3f5d13.png "WHCP仕様におけるFormat NVMコマンドに関する規定")
図1：WHCP仕様における`Format NVM`コマンドに関する規定

　このように、表4に記載されている暗号的消去のサポート要求は、このWHCP仕様に基づいたものであると考えることができます。

　なお、図1に"If Implemented"と記載されているように、そもそも`Format NVM`コマンドのサポートはオプションです。

　SSDが`Format NVM`コマンドをサポートしているかどうかは、SSDコントローラに対する`Identify`コマンドの結果から確認できます。

　具体的には、表6の赤四角で囲ったフィールドとなります。

表6：`Format NVM`コマンドサポート有無表示フィールド（NVMe仕様書のFigure 112より抜粋）
![Format NVMコマンドサポート有無表示フィールド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/9f3fb410-76dc-ec86-9ff4-38570eee6ef0.png "Format NVMコマンドサポート有無表示フィールド")

　また、`Format NVM`コマンド実行時の暗号的消去サポート有無は、同じくSSDコントローラに対する`Identify`コマンドの結果から確認できます。

表7：`Format NVM`コマンドでの暗号的消去サポート有無表示フィールド（NVMe仕様書のFigure 112より抜粋）
![Format NVMコマンドでの暗号的消去サポート有無表示フィールド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/71e00e3c-2ce7-6ecf-fe89-14e050f4e15a.png "Format NVMコマンドでの暗号的消去サポート有無表示フィールド")

# まとめ

　この記事では、先日（2020年5月）に投稿されたWindows 10の標準NVMeデバイスドライバについての記事の内容から、コマンドのサポート情報を取り上げて説明しました。

　あわせて、`Flush`コマンドと`Format NVM`コマンドを、Windowsの標準NVMeデバイスドライバを使用して発行できたことをご紹介しました。

　今後Windowsの標準NVMeデバイスドライバでできることが増えていくのかどうかはわかりませんが、新しい情報が公開されたり新しいことができるようになったことがわかったら、随時ご紹介できればと思います。

# 参考文献
[1] Microsoft、_"[NVMe Features Supported by StorNVMe](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/storage/nvme-features-supported-by-stornvme)"_、2020年6月25日閲覧
[2] Microsoft、_"[StorNVMe Command Set Support](https://docs.microsoft.com/en-us/windows-hardware/drivers/storage/stornvme-command-set-support)"_、2020年6月25日閲覧
[3] Microsoft、_"[Windows PE (WinPE)](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-intro)"_、2020年6月25日閲覧
[4] _"[ken-yossy/nvmetool-win: Communicate with NVMe SSD using Windows' inbox device driver](https://github.com/ken-yossy/nvmetool-win)"_
[5] NVM Express, _"NVM Express<sup>TM</sup> Base Specification"_, Revision 1.3d, March, 2019
[6] Microsoft, _"Windows Hardware Compatibility Specifications for Windows 10, version 2004 – Components and Peripherals"_, 2020

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