LoginSignup
1
1

More than 3 years have passed since last update.

Windowsの標準NVMeドライバでNVMe SSDにアクセスする(Get Features)

Posted at

はじめに

 これまで、Windows 10(以降Windowsと記載します)の標準NVMeデバイスドライバを使用して、ユーザ空間で動作するプログラムからNVMe SSDに対していくつかのコマンドを発行する方法を紹介しました(その1その2その3)。

 この記事では、NVMeが規定する機能の設定内容を取得するGet Featuresというコマンドを、Windowsの標準NVMeデバイスドライバを使用して発行する方法を説明します。

 Get Featuresコマンドと対を成す、「機能の設定」を行うSet Featuresコマンドも説明できればよかったのですが、Windowsの標準NVMeデバイスドライバを使う限りSet Featuresコマンドを使うことで設定内容を変更可能な機能がほとんどないようですので、ここではGet Featuresコマンドのみ説明します。

 なお、この記事でまとめた内容の動作確認環境は、以前の記事の動作確認環境とほぼ同一ですので、そちらを参照してください。また、完全なコードはGithubに置いてありますのでそちらをご覧ください。

まとめ

  • Get Featuresコマンドを使用すると、NVMe SSDの機能の「現在の設定」を取得できる
  • ただし、Windowsの標準NVMeデバイスドライバを使う場合、取得が可能な機能は限られる

NVMe仕様における"Feature"とは

 NVMe仕様[1]におけるGet Featuresコマンドは、NVMeデバイス(面倒なので、以降「デバイス」=「SSD」として"SSD"と記載します)の各種機能に関する、現時点での設定内容を取得するためのコマンドです。

 NVMe仕様は、Get Featuresコマンドの対象となる機能(Feature)として、以下のものを定義しています。

表1:NVMe仕様で定義されている機能(NVMe仕様書から抜粋)
NVMe仕様で定義されている機能(NVMe仕様書から抜粋)

 表1内の機能のうち、例えば、Feature Identifier (FID) = 06hのVolatile Write Cacheは揮発性ライトキャッシュ、FID = 02hのPower Managementは省電力機能、そしてFID = 04hのTemperature Thresholdは温度閾値に関する設定となります。

"Feature"の仕組み

 Get Featuresコマンドの説明に入る前に、NVMe仕様が定義する「機能」の仕組みについて説明します。

 NVMe仕様における「機能(Feature)」は、下記のような特徴を持ち、それらの設定内容をGet Featuresコマンドで取得できます。

  • 機能の設定内容(値)には、「現在の値(Current)」と「デフォルト値(Default)」と「保存された値(Saved)」の3種類がある
  • 各機能に下記の「属性(Supported Capabilities)」が存在する
    • 設定を変更できるかどうか(Changeable)
    • 設定を保存できるかどうか(Saveable)
    • Namespace毎に適用される設定なのかコントローラ全体に適用される設定なのか

 これらの仕様は、仕様書5.13節"Get Features command"および5.21節"Set Features command"に記載されています。

 Get Featuresコマンドでどの内容を取得するかは、以下の部分で設定します(青四角で囲った部分)。

Get Featuresコマンドで取得する値の設定方法(NVMe仕様書より抜粋)
図1:Get Featuresコマンドで取得する値の設定方法(NVMe仕様書より抜粋)

Get Featuresコマンドの発行

 それでは、具体的にGet Featuresコマンドを発行する手順を見ていきます。

 以下のフローチャートは、Windowsの標準NVMeデバイスドライバを使用してNVMe SSDにGet Featuresコマンドを発行する手順です。

 といっても、これまでに説明した他のコマンドの発行手順と大差はありません。

Get Featuresコマンド発行手順
図2:Get Featuresコマンド発行手順

 デバイスハンドルを取得する方法は、以前の別記事で説明した通りですので、説明は省略します。

 この記事では、機能(Feature)の例としてVolatile Write Cacheを取り上げます。

 「コマンド発行用構造体作成」以降の処理について、以下にコード片を示します。行頭の行番号は、説明のために付与したものです。エラー処理に関するコードは省略しています。

 このコードは、Microsoftの説明[2]にしたがって書き起こしたものです。

 1: int     iResult = -1;
 2: PVOID   buffer = NULL;
 3: ULONG   bufferLength = 0;
 4: ULONG   returnedLength = 0;
 5: uint32_t resultData = 0;

 6: PSTORAGE_PROPERTY_QUERY query = NULL;
 7: PSTORAGE_PROTOCOL_SPECIFIC_DATA protocolData = NULL;
 8: PSTORAGE_PROTOCOL_DATA_DESCRIPTOR protocolDataDescr = NULL;
 9: NVME_CDW10_GET_FEATURES cdw10 = { 0 };

    // Allocate buffer for use.
10: bufferLength = offsetof(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
11: buffer = malloc(bufferLength);
12: ZeroMemory(buffer, bufferLength);

13: query = (PSTORAGE_PROPERTY_QUERY)buffer;
14: protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
15: protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;

16: query->PropertyId = StorageDeviceProtocolSpecificProperty;
17: query->QueryType = PropertyStandardQuery;

18: cdw10.FID = NVME_FEATURE_VOLATILE_WRITE_CACHE;
19: cdw10.SEL = NVME_FEATURE_VALUE_CURRENT;

20: protocolData->ProtocolType = ProtocolTypeNvme;
21: protocolData->DataType = NVMeDataTypeFeature;
22: protocolData->ProtocolDataRequestValue = (DWORD)(cdw10.AsUlong);
23: protocolData->ProtocolDataRequestSubValue = 0;
24: protocolData->ProtocolDataOffset = 0;
25: protocolData->ProtocolDataLength = 0;

    // Send request down.  
26: iResult = DeviceIoControl(_hDevice,
                              IOCTL_STORAGE_QUERY_PROPERTY,
                              buffer,
                              bufferLength,
                              buffer,
                              bufferLength,
                              &returnedLength,
                              NULL);

27: resultData = (uint32_t)(protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData);

 6行目に登場する構造体STORAGE_PROPERTY_QUERYは、ストレージに問い合わせ(クエリ)をするようなコマンドを発行する際に使用するデータ構造です。

 これはGet Log Pageコマンドの発行時にも使ったもので、クエリタイプの設定(17行目)が必要です。

 9行目で定義している変数の型は、Get Featuresコマンド用にnvme.hで定義されている構造体です。

 Get Featuresコマンドでは、Feature IDなどをCommand DWord 10 (CDW10)に設定します。このCDW10の設定内容はGet Featuresコマンド専用ですので、nvme.hに構造体が定義されています。

 具体的なFeature IDと図1で示した取得内容は、18行目と19行目で設定して、22行目でコマンド発行用構造体に設定しています。

 サンプルコードでは、19行目にNVME_FEATURE_VALUE_CURRENTを指定しています。これは「現在の値(Current)」の取得を要求するための値です。「デフォルト値(Default)」や「保存された値(Saved)」そして「属性」に対しても、同様にnvme.hに定数が定義されていますので、それを指定します。

 今回はVolatile Write Cacheですので、FIDにはNVME_FEATURE_VOLATILE_WRITE_CACHE (06h)を設定します。

 順序が逆になってしまいましたが、10行目でバッファサイズを計算して11行目でメモリを確保しているのが、コマンド発行用構造体です。

 Volatile Write Cache機能の場合、Get Featuresコマンドの結果としてSSDから受け取るデータはDWord(32ビット)のデータひとつだけですので、SSDから受け取るデータのためのメモリ領域を改めて確保する必要はありません。

 そして、21行目でGet Featuresコマンドであることを設定した上で、26行目でDeviceIoControl()を呼び出して、コマンド発行を要求します。

 DeviceIoControl()が成功すると、コマンド発行用構造体の中に、SSDから受け取ったデータが格納されますので、27行目のように参照します。

 受信したデータは、NVMe仕様書5.21.1節"Feature Specific Information"に記載されている各機能に関するデータ構造にしたがって解析します。

 以下に、とあるNVMe SSDから取得したVolatile Write Cacheの設定内容を示します。なお、フィールド名や説明文の付与や出力の整形はプログラム中で行ったものです。

 解釈はNVMe仕様書の5.21.1.6節に従って行います。

[I] Volatile Write Cache:
        bit [      0] Volatile Write Cache Enable (WCE), (0) disabled, (1) enabled
                Current = 1
                Default = 1
                Saved   = 1
        Capabilities: this feature is
                bit [      2] 1 = (1) changeable, (0) not changeable
                bit [      1] 0 = (1) namespace specific, (0) for entire controller
                bit [      0] 0 = (1) saveable, (0) not saveable

 この結果から、このNVMe SSDのVolatile Write Cache機能は以下のようになっていることがわかります。

  • 現在の設定値は「有効(Current = 1)」
  • デフォルトの設定値は「有効(Default = 1)」
  • 保存されている値は「有効(Saved = 1)」
  • 設定値の変更は「可能(changeable)」
  • この設定値は「コントローラ全体に適用される設定(for entire controller)」
  • この設定値は「保存できない(not saveable)」

 わかりにくいですが、実際には、CurrentDefaultSavedの設定値を取得するためにそれぞれGet Featuresコマンドを発行する必要があります。

 つまり、上記の結果を取得するために、属性(Capability)を取得するためのコマンド発行分と合わせて合計4回Get Featuresコマンドを発行しています。

まとめ

 この記事では、NVMe仕様が定める「機能(Feature)」について説明し、Windowsの標準NVMeデバイスドライバを使って、Get Featuresコマンドでその機能の設定内容を取得する方法をまとめました。

 NVMe仕様が定める機能(Feature)は仕様が新しくなるにつれてどんどん数が増えているのですが、Windowsの標準NVMeデバイスドライバを使う方法では、Set Featuresコマンドによる設定内容の変更はもちろん、Get Featuresコマンドによる設定内容の取得ができない機能も多いです。

 とはいえ、この記事で紹介した方法は、Windowsの標準NVMeデバイスドライバを使用していますので、とても手軽に試せることが特徴です。

 なお、Windowsの標準NVMeデバイスドライバを使用した場合の、各機能についての設定取得可否については、Githubにまとめてあります。

参考文献

[1] NVM Express, "NVM ExpressTM Base Specification", Revision 1.3d, March 20, 2019
[2] Microsoft, "Working with NVMe drives", 最終閲覧日2020年9月16日

ライセンス表記

クリエイティブ・コモンズ・ライセンス
この記事はクリエイティブ・コモンズ 表示 - 継承 4.0 国際ライセンスの下に提供されています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1