Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Şunlar için geçerlidir:
- Windows 10
- Windows Server 2016
Windows uygulamanızdan yüksek hızlı NVMe cihazlarıyla çalışmayı öğrenin. Cihaz erişimi, ilk olarak Windows Server 2012 R2 ve Windows 8.1'de kullanıma sunulan yerleşik sürücü StorNVMe.sysaracılığıyla etkinleştirilir. Ayrıca, bir KB düzeltme eki aracılığıyla Windows 7 cihazlarında da kullanılabilir. Windows 10'da, satıcıya özgü NVMe komutları ve mevcut IOCTL'lere yönelik güncelleştirmeler için geçiş mekanizması da dahil olmak üzere birkaç yeni özellik kullanıma sunulmuştur.
Bu konu, Windows 10'da NVMe sürücülerine erişmek için kullanabileceğiniz genel kullanım API'lerine genel bir bakış sağlar. Ayrıca şunları da açıklar:
- Nasıl geçiş ile satıcıya özgü NVMe komutu gönderilir?
- NVMe sürücüsüne Bir Tanımla, Özellik Al veya Günlük Sayfalarını Al komutunu gönderme
- NVMe sürücüsünden sıcaklık bilgilerini alma
- Sıcaklık eşiklerini ayarlama gibi davranış değiştirme komutlarını gerçekleştirme
NVMe sürücüleriyle çalışmak için API'ler
Windows 10'da NVMe sürücülerine erişmek için aşağıdaki genel kullanım API'lerini kullanabilirsiniz. Bu API'ler kullanıcı modu uygulamaları için winioctl.h ve çekirdek modu sürücüleri için ntddstor.h bulunabilir. Üst bilgi dosyaları hakkında daha fazla bilgi için bkz. Üst bilgi dosyaları.
IOCTL_STORAGE_PROTOCOL_COMMAND : NVMe komutları vermek için bu IOCTL'yi STORAGE_PROTOCOL_COMMAND yapısıyla kullanın. Bu IOCTL, NVMe iletimini etkinleştirir ve NVMe'de Komut Etkileri günlüğünü destekler. Satıcıya özgü komutlarla kullanabilirsiniz. Daha fazla bilgi için bakınız Geçiş mekanizması.
STORAGE_PROTOCOL_COMMAND : Bu giriş-arabellek yapısı, aşağıdaki durum değerlerini raporlayan kullanılabilecek bir ReturnStatus alanı içerir.
- DEPOLAMA_PROTOKOLU_DURUMU_BEKLEMEDE
- STORAGE_PROTOCOL_STATUS_SUCCESS
- STORAGE_PROTOCOL_STATUS_ERROR
- DEPOLAMA_PROTOKOL_DURUMU_GEÇERSİZ_İSTEK
- STORAGE_PROTOCOL_STATUS_NO_DEVICE
- DEPOLAMA_PROTOKOL_DURUMU_MEŞGUL
- STORAGE_PROTOCOL_STATUS_DATA_OVERRUN
- DEPOLAMA_PROTOKOL_DURUM_YETERSİZ_KAYNAKLAR
- DEPOLAMA_PROTOKOL_DURUMU_DESTEKLENMİYOR
IOCTL_STORAGE_QUERY_PROPERTY : Cihaz bilgilerini almak için bu IOCTL'yi STORAGE_PROPERTY_QUERY yapısıyla kullanın. Daha fazla bilgi için bkz. Protokole özgü sorgular ve Sıcaklık sorguları.
STORAGE_PROPERTY_QUERY : Bu yapı sorgulanacak verileri belirtmek için PropertyId ve AdditionalParameters alanlarını içerir. Dosyalanan PropertyId veri türünü belirtmek için STORAGE_PROPERTY_ID numaralandırmasını kullanın. Veri türüne bağlı olarak daha fazla ayrıntı belirtmek için AdditionalParameters alanını kullanın. Protokole özgü veriler için AdditionalParameters alanındaki STORAGE_PROTOCOL_SPECIFIC_DATA yapısını kullanın. Sıcaklık verileri için AdditionalParameters alanındaki STORAGE_TEMPERATURE_INFO yapısını kullanın.
STORAGE_PROPERTY_ID : Bu numaralandırma, IOCTL_STORAGE_QUERY_PROPERTY protokole özgü ve sıcaklık bilgilerini almasını sağlayan yeni değerler içerir.
StorageAdapterProtocolSpecificProperty: If
ProtocolType=ProtocolTypeNvmeveDataType=NVMeDataTypeLogPage, çağıranların 512 bayt veri öbekleri istemesi gerekir.DepolamaCihazıProtokolÖzelÖzelliği
STORAGE_PROTOCOL_DATA_DESCRIPTOR yapısındaki protokole özgü verileri almak için STORAGE_PROTOCOL_SPECIFIC_DATA ile birlikte bu protokole özgü özellik kimliklerinden birini kullanın.
- DepolamaAdaptörüSıcaklıkÖzelliği
- Depolama Cihazı Sıcaklık Özelliği
STORAGE_TEMPERATURE_DATA_DESCRIPTOR yapısındaki sıcaklık verilerini almak için bu sıcaklık özelliği kimliklerinden birini kullanın.
STORAGE_PROTOCOL_SPECIFIC_DATA : Bu yapı STORAGE_PROPERTY_QUERY'ın AdditionalParameters alanı için kullanıldığında ve STORAGE_PROTOCOL_NVME_DATA_TYPEsabit listesi değeri belirtildiğinde NVMe'e özgü verileri alın. STORAGE_PROTOCOL_SPECIFIC_DATA yapısının DataType alanında aşağıdaki STORAGE_PROTOCOL_NVME_DATA_TYPE değerlerinden birini kullanın:
- NVMeDataTypeIdentify kullanarak Denetleyici Verilerini Tanımla veya Ad Alanı Verilerini Tanımla'ya tıklayın.
- Günlük sayfalarını (SMART/sağlık verileri dahil) almak için NVMeDataTypeLogPage kullanın.
- NVMe sürücüsünün özelliklerini almak için NVMeDataTypeFeature kullanın.
STORAGE_TEMPERATURE_INFO : Bu yapı belirli sıcaklık verilerini tutmak için kullanılır. Sıcaklık sorgusunun sonuçlarını döndürmek için STORAGE_TEMERATURE_DATA_DESCRIPTOR kullanılır.
IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD : Sıcaklık eşiklerini ayarlamak için bu IOCTL'yi STORAGE_TEMPERATURE_THRESHOLD yapısıyla kullanın. Daha fazla bilgi için bkz. Davranış değiştirme komutları.
STORAGE_TEMPERATURE_THRESHOLD : Bu yapı, sıcaklık eşiğini belirtmek için giriş arabelleği olarak kullanılır. OverThreshold alanı (boolean), Eşik alanının değeri eşik değerinin üzerinde mi yoksa altında mı olduğunu belirtir (aksi takdirde eşik değerinin altındadır).
Geçiş mekanizması
NVMe belirtiminde tanımlanmayan komutlar, konak işletim sisteminin işleyebileceği en zor komutlardır. Konağın komutların hedef cihaz üzerindeki etkileri, kullanıma sunulan altyapı (ad alanları/blok boyutları) ve davranışı hakkında hiçbir içgörü yoktur.
Bu tür cihaza özgü komutları Windows depolama yığını üzerinden daha iyi taşımak için, yeni bir geçiş mekanizması satıcıya özgü komutların iletilmesine olanak tanır. Bu geçiş boru, yönetim ve test araçlarının geliştirilmesine de yardımcı olacaktır. Ancak, bu geçiş mekanizması Komut Efektleri Günlüğünün kullanılmasını gerektirir. Ayrıca, StoreNVMe.sys yalnızca geçiş komutlarının değil tüm komutların Komut Efektleri Günlüğü'nde açıklanması gerekir.
Önemli
StorNVMe.sys ve Storport.sys Komut Efektleri Günlüğü'nde açıklanmadıysa cihaza gelen tüm komutları engeller.
Komut Efektleri Günlüğünü Destekleme
Komut Efektleri Günlüğü (Desteklenen Komutlar ve Efektler bölümünde açıklandığı gibi, NVMe Belirtimi 1.2bölüm 5.10.1.5), belirtim tanımlı komutlarla birlikte satıcıya özgü komutların etkilerinin açıklamasına izin verir. Bu, hem komut desteği doğrulamasını hem de komut davranışını iyileştirmeyi kolaylaştırır ve bu nedenle cihazın desteklediği tüm komut kümesi için uygulanmalıdır. Aşağıdaki koşullar, komutun Komut Efektleri Günlüğü girdisine göre nasıl gönderildiğine ilişkin sonucu açıklar.
Komut Efektleri Günlüğü'nde açıklanan belirli komutlar için...
sırasında:
Komut Desteği (CSUPP), komutun denetleyici tarafından desteklendiğini belirten '1' olarak ayarlanmıştır (Bit 01)
Not
CSUPP '0' olarak ayarlandığında (komutun desteklenmediğini belirten) komut engellenir
Ve aşağıdakilerden biri ayarlandıysa:
- Denetleyici Yetenek Değişikliği (CCC), komutun denetleyici özelliklerini değiştirebileceğini belirten '1' olarak ayarlandı (Bit 04)
- Ad Alanı Envanter Değişikliği (NIC), komutun birden çok ad alanının sayısını veya özelliklerini değiştirebileceğini belirten '1' olarak ayarlandı (Bit 03)
- Ad Alanı Yetenek Değişikliği (NCC), komutun tek bir ad alanının özelliklerini değiştirebileceğini belirten '1' olarak ayarlanmıştır (Bit 02)
- Komut Gönderme ve Yürütme (CSE) 001b veya 010b olarak ayarlanmıştır. Bu, komutun aynı veya herhangi bir ad alanında bekleyen başka bir komut olmadığında gönderilebileceğini ve bu komut tamamlanana kadar başka bir komutun aynı veya herhangi bir ad alanına gönderilmemesi gerektiğini ifade eder (Bit 18:16)
Ardından komutu bağdaştırıcıya kalan tek komut olarak gönderilir.
Değilse:
- Komut Gönderme ve Yürütme (CSE) 001b olarak ayarlanır; bu, komutun aynı ad alanında bekleyen başka bir komut olmadığında gönderilebileceğini ve bu komut tamamlanana kadar başka bir komutun aynı ad alanına gönderilmemesi gerektiğini ifade eder (Bits 18:16)
Ardından komut, Mantıksal Birim Numarası nesnesine (LUN) kalan tek komut olarak gönderilir.
Aksi takdirdekomutu, engelleme olmadan diğer beklemede olan komutlarla birlikte gönderilir. Örneğin, belirtim tanımlanmamış istatistiksel bilgileri almak için cihaza satıcıya özgü bir komut gönderilirse, cihazın G/Ç komutlarını yürütme davranışını veya özelliğini değiştirme riski olmamalıdır. Bu tür istekler G/Ç işlemleriyle paralel olarak karşılanabilir ve duraklatma-sürdürme gerekmez.
Komutları göndermek için IOCTL_STORAGE_PROTOCOL_COMMAND kullanma
Geçiş, Windows 10'da tanıtılan IOCTL_STORAGE_PROTOCOL_COMMAND kullanılarak yapılabilir. Bu IOCTL, hedef cihaza ekli bir komut göndermek için mevcut SCSI ve ATA doğrudan IOCTL'lerle benzer bir davranışa sahip olacak şekilde tasarlanmıştır. Bu IOCTL aracılığıyla, NVMe sürücüsü de dahil olmak üzere bir depolama cihazına geçiş gönderebilirsiniz.
Örneğin, NVMe'de IOCTL aşağıdaki komut kodlarının gönderilmesine izin verir.
- Satıcıya Özgü Yönetici Komutları (C0h – FFh)
- Satıcıya Özgü NVMe Komutları (80h – FFh)
Diğer tüm IOCTL'lerde olduğu gibi, geçiş IOCTL'yi aşağı göndermek için DeviceIoControl kullanın. IOCTL, ntddstor.h dosyasında bulunan STORAGE_PROTOCOL_COMMAND input-buffer yapısı kullanılarak doldurulur. Command alanını satıcıya özgü komutla doldurun.
typedef struct _STORAGE_PROTOCOL_COMMAND {
ULONG Version; // STORAGE_PROTOCOL_STRUCTURE_VERSION
ULONG Length; // sizeof(STORAGE_PROTOCOL_COMMAND)
STORAGE_PROTOCOL_TYPE ProtocolType;
ULONG Flags; // Flags for the request
ULONG ReturnStatus; // return value
ULONG ErrorCode; // return value, optional
ULONG CommandLength; // non-zero value should be set by caller
ULONG ErrorInfoLength; // optional, can be zero
ULONG DataToDeviceTransferLength; // optional, can be zero. Used by WRITE type of request.
ULONG DataFromDeviceTransferLength; // optional, can be zero. Used by READ type of request.
ULONG TimeOutValue; // in unit of seconds
ULONG ErrorInfoOffset; // offsets need to be pointer aligned
ULONG DataToDeviceBufferOffset; // offsets need to be pointer aligned
ULONG DataFromDeviceBufferOffset; // offsets need to be pointer aligned
ULONG CommandSpecific; // optional information passed along with Command.
ULONG Reserved0;
ULONG FixedProtocolReturnData; // return data, optional. Some protocol, such as NVMe, may return a small amount data (DWORD0 from completion queue entry) without the need of separate device data transfer.
ULONG Reserved1[3];
_Field_size_bytes_full_(CommandLength) UCHAR Command[ANYSIZE_ARRAY];
} STORAGE_PROTOCOL_COMMAND, *PSTORAGE_PROTOCOL_COMMAND;
Gönderilmesi istenen satıcıya özgü komut, yukarıdaki vurgulanan alana doldurulmalıdır. Geçiş komutları için Komut Efektleri Günlüğünün uygulanması gerektiğini tekrar unutmayın. Özellikle, bu komutların Komut Efektleri Günlüğü'nde desteklendiği bildirilmelidir (daha fazla bilgi için önceki bölüme bakın). Ayrıca, PRP alanlarının sürücüye özgü olduğunu ve bu nedenle komut gönderen uygulamaların bunları olarak 0bırakabileceğini unutmayın.
Son olarak, bu geçiş IOCTL satıcıya özel komutları göndermeye yöneliktir. Yöneticilere veya satıcıya özgü olmayan Tanımla gibi diğer NVMe komutlarını göndermek için bu geçiş IOCTL kullanılmamalıdır. Örneğin, IOCTL_STORAGE_QUERY_PROPERTY Tanımlama veya Günlük Sayfalarını Alma için kullanılmalıdır. Daha fazla bilgi için, Protokole özgü sorgularsonraki bölüme bakın.
Geçiş mekanizması üzerinden üretici yazılımını güncellemeyin.
Üretici yazılımı indirme ve etkinleştirme komutları geçiş kullanılarak gönderilmemelidir. IOCTL_STORAGE_PROTOCOL_COMMAND yalnızca satıcıya özgü komutlar için kullanılmalıdır.
Bunun yerine, uygulamaların doğrudan Üretici Yazılımı IOCTL'sinin SCSI_miniport sürümünü kullanmasını önlemek için aşağıdaki genel depolama IOCTL'lerini (Windows 10'da kullanıma sunulmuştur) kullanın. Depolama sürücüleri, IOCTL'yi ya bir SCSI komutuna ya da IOCTL'nin SCSI_miniport versiyonuna çevirerek miniport'a iletir.
Bu IOCTL (Giriş/Çıkış Kontrol Kodu) komutları, Windows 10 ve Windows Server 2016'da donanım yazılımı yükseltme araçları geliştirmek için önerilir:
Windows, depolama bilgilerini almak ve üretici yazılımını güncelleştirmek için bunu hızlı bir şekilde yapmak için PowerShell cmdlet'lerini de destekler:
Get-StorageFirmwareInfoUpdate-StorageFirmware
Aktarım mekanizması aracılığıyla hataları döndürme
SCSI ve ATA geçişli GÇTL'lere benzer şekilde, bir komut/istek miniport'a veya cihaza gönderildiğinde, IOCTL işlemin başarılı olup olmadığını bildirir. STORAGE_PROTOCOL_COMMAND yapısında IOCTL, ReturnStatus alanı aracılığıyla durumu döndürür.
Örnek: Satıcıya özgü komut gönderme
Bu örnekte, bir NVMe sürücüsüne geçiş yoluyla rastgele satıcıya özgü bir komut (0xFF) gönderilir. Aşağıdaki kod bir arabellek ayırır, bir sorgu başlatır ve ardından deviceIoControl aracılığıyla komutu cihaza gönderir.
ZeroMemory(buffer, bufferLength);
protocolCommand = (PSTORAGE_PROTOCOL_COMMAND)buffer;
protocolCommand->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION;
protocolCommand->Length = sizeof(STORAGE_PROTOCOL_COMMAND);
protocolCommand->ProtocolType = ProtocolTypeNvme;
protocolCommand->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST;
protocolCommand->CommandLength = STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
protocolCommand->ErrorInfoLength = sizeof(NVME_ERROR_INFO_LOG);
protocolCommand->DataFromDeviceTransferLength = 4096;
protocolCommand->TimeOutValue = 10;
protocolCommand->ErrorInfoOffset = FIELD_OFFSET(STORAGE_PROTOCOL_COMMAND, Command) + STORAGE_PROTOCOL_COMMAND_LENGTH_NVME;
protocolCommand->DataFromDeviceBufferOffset = protocolCommand->ErrorInfoOffset + protocolCommand->ErrorInfoLength;
protocolCommand->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND;
command = (PNVME_COMMAND)protocolCommand->Command;
command->CDW0.OPC = 0xFF;
command->u.GENERAL.CDW10 = 0xto_fill_in;
command->u.GENERAL.CDW12 = 0xto_fill_in;
command->u.GENERAL.CDW13 = 0xto_fill_in;
//
// Send request down.
//
result = DeviceIoControl(DeviceList[DeviceIndex].Handle,
IOCTL_STORAGE_PROTOCOL_COMMAND,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
Bu örnekte, komutun cihaza başarılı iletildiğinde protocolCommand->ReturnStatus == STORAGE_PROTOCOL_STATUS_SUCCESS bekliyoruz.
Protokole özgü sorgular
Windows 8.1, veri alma için IOCTL_STORAGE_QUERY_PROPERTY'yi tanıttı. Windows 10'da IOCTL, Günlük Sayfalarını Al, Özellikleri Alve Tanımla gibi yaygın olarak istenen NVMe özelliklerini destekleyecek şekilde geliştirilmiştir. Bu, izleme ve envanter amacıyla NVMe'ye özgü bilgilerin alınmasına olanak tanır.
IOCTL, STORAGE_PROPERTY_QUERY (Windows 10 ve sonrasındaki sürümler) için giriş tamponu burada gösterilmiştir:
typedef struct _STORAGE_PROPERTY_QUERY {
STORAGE_PROPERTY_ID PropertyId;
STORAGE_QUERY_TYPE QueryType;
UCHAR AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
STORAGE_PROTOCOL_DATA_DESCRIPTOR NVMe protokolüne özgü bilgileri almak için IOCTL_STORAGE_QUERY_PROPERTY kullanırken, STORAGE_PROPERTY_QUERY yapısını aşağıdaki gibi yapılandırın:
- Bir STORAGE_PROPERTY_QUERY ve STORAGE_PROTOCOL_SPECIFIC_DATA yapısını aynı anda içerebilen bir arabellek ayırın.
- Denetleyici veya cihaz/ad alanı isteği için PropertyID alanını, sırasıyla StorageAdapterProtocolSpecificProperty veya StorageDeviceProtocolSpecificProperty olarak ayarlayın.
- QueryType alanını PropertyStandardQueryolarak ayarlayın.
- STORAGE_PROTOCOL_SPECIFIC_DATA yapısını istenen değerlerle doldurun. STORAGE_PROTOCOL_SPECIFIC_DATA'nın başlangıcı, STORAGE_PROPERTY_QUERY'nin AdditionalParameters alanıdır.
STORAGE_PROTOCOL_SPECIFIC_DATA yapısı (Windows 10 ve sonraki sürümlerden) burada gösterilmiştir:
typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA {
STORAGE_PROTOCOL_TYPE ProtocolType;
ULONG DataType;
ULONG ProtocolDataRequestValue;
ULONG ProtocolDataRequestSubValue;
ULONG ProtocolDataOffset;
ULONG ProtocolDataLength;
ULONG FixedProtocolReturnData;
ULONG Reserved[3];
} STORAGE_PROTOCOL_SPECIFIC_DATA, *PSTORAGE_PROTOCOL_SPECIFIC_DATA;
NVMe protokolüne özgü bir bilgi türü belirtmek için STORAGE_PROTOCOL_SPECIFIC_DATA yapısını aşağıdaki gibi yapılandırın:
- ProtocolType alanını ProtocolTypeNVMe olarak ayarlayın.
-
DataType alanını STORAGE_PROTOCOL_NVME_DATA_TYPE tarafından tanımlanan bir numaralandırma değerine ayarlayın:
- NVMeDataTypeIdentify kullanarak Denetleyici Verilerini Tanımla veya Ad Alanı Verilerini Tanımla'ya tıklayın.
- Günlük sayfalarını (SMART/sağlık verileri dahil) almak için NVMeDataTypeLogPage kullanın.
- NVMe sürücüsünün özelliklerini almak için NVMeDataTypeFeature kullanın.
ProtocolTypeNVMeProtocolTypeolarak kullanıldığında, protokole özgü bilgilerle ilgili sorgular NVMe sürücüsündeki diğer G/Ç ile paralel olarak alınabilir.
Önemli
IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_ID olarak StorageAdapterProtocolSpecificProperty kullanıldığında ve STORAGE_PROTOCOL_SPECIFIC_DATA veya STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısı ProtocolType=ProtocolTypeNvme ve DataType=NVMeDataTypeLogPage olarak ayarlandığında, aynı yapının ProtocolDataLength üyesini en az 512 (bayt) olacak şekilde ayarlayın.
Aşağıdaki örneklerde NVMe protokolüne özgü sorgular gösterilmektedir.
Örnek: NVMe Tanımlama sorgusu
Bu örnekte Belirleme isteği bir NVMe sürücüsüne gönderilir. Aşağıdaki kod sorgu veri yapısını başlatır ve ardından DeviceIoControl aracılığıyla komutu cihaza gönderir.
BOOL result;
PVOID buffer = NULL;
ULONG bufferLength = 0;
ULONG returnedLength = 0;
PSTORAGE_PROPERTY_QUERY query = NULL;
PSTORAGE_PROTOCOL_SPECIFIC_DATA protocolData = NULL;
PSTORAGE_PROTOCOL_DATA_DESCRIPTOR protocolDataDescr = NULL;
//
// Allocate buffer for use.
//
bufferLength = FIELD_OFFSET(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + NVME_MAX_LOG_SIZE;
buffer = malloc(bufferLength);
if (buffer == NULL) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: allocate buffer failed, exit.\n"));
goto exit;
}
//
// Initialize query data structure to get Identify Controller Data.
//
ZeroMemory(buffer, bufferLength);
query = (PSTORAGE_PROPERTY_QUERY)buffer;
protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
query->PropertyId = StorageAdapterProtocolSpecificProperty;
query->QueryType = PropertyStandardQuery;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeIdentify;
protocolData->ProtocolDataRequestValue = NVME_IDENTIFY_CNS_CONTROLLER;
protocolData->ProtocolDataRequestSubValue = 0;
protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
protocolData->ProtocolDataLength = NVME_MAX_LOG_SIZE;
//
// Send request down.
//
result = DeviceIoControl(DeviceList[Index].Handle,
IOCTL_STORAGE_QUERY_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
ZeroMemory(buffer, bufferLength);
query = (PSTORAGE_PROPERTY_QUERY)buffer;
protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
query->PropertyId = StorageDeviceProtocolSpecificProperty;
query->QueryType = PropertyStandardQuery;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeLogPage;
protocolData->ProtocolDataRequestValue = NVME_LOG_PAGE_HEALTH_INFO;
protocolData->ProtocolDataRequestSubValue = 0;
protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
protocolData->ProtocolDataLength = sizeof(NVME_HEALTH_INFO_LOG);
//
// Send request down.
//
result = DeviceIoControl(DeviceList[Index].Handle,
IOCTL_STORAGE_QUERY_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
//
// Validate the returned data.
//
if ((protocolDataDescr->Version != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR)) ||
(protocolDataDescr->Size != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: Get Identify Controller Data - data descriptor header not valid.\n"));
return;
}
protocolData = &protocolDataDescr->ProtocolSpecificData;
if ((protocolData->ProtocolDataOffset < sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA)) ||
(protocolData->ProtocolDataLength < NVME_MAX_LOG_SIZE)) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: Get Identify Controller Data - ProtocolData Offset/Length not valid.\n"));
goto exit;
}
//
// Identify Controller Data
//
{
PNVME_IDENTIFY_CONTROLLER_DATA identifyControllerData = (PNVME_IDENTIFY_CONTROLLER_DATA)((PCHAR)protocolData + protocolData->ProtocolDataOffset);
if ((identifyControllerData->VID == 0) ||
(identifyControllerData->NN == 0)) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: Identify Controller Data not valid.\n"));
goto exit;
} else {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: ***Identify Controller Data succeeded***.\n"));
}
}
Önemli
IOCTL_STORAGE_QUERY_PROPERTY, STORAGE_PROPERTY_ID olarak StorageAdapterProtocolSpecificProperty kullanıldığında ve STORAGE_PROTOCOL_SPECIFIC_DATA veya STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısı ProtocolType=ProtocolTypeNvme ve DataType=NVMeDataTypeLogPage olarak ayarlandığında, aynı yapının ProtocolDataLength üyesini en az 512 (bayt) olacak şekilde ayarlayın.
Çağıranın, STORAGE_PROPERTY_QUERY ve STORAGE_PROTOCOL_SPECIFIC_DATA boyutunu da içeren tek bir arabellek ayırması gerektiğini unutmayın. Bu örnekte, özellik sorgusundan gelen giriş ve çıkış için aynı arabelleği kullanıyor. Bu nedenle ayrılan arabellek "FIELD_OFFSET(STORAGE_PROPERTY_QUERY, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA) + NVME_MAX_LOG_SIZE" boyutundadır. Hem giriş hem de çıkış için ayrı arabellekler ayrılabilse de NVMe ile ilgili bilgileri sorgulamak için tek bir arabellek kullanmanızı öneririz.
identifyControllerData->NN, Ad Alanı Sayısıdır (NN). Windows, bir ad alanını fiziksel sürücü olarak algılar.
Örnek: NVMe Günlük Sayfalarını Al sorgusu
Bu örnekte, öncekine dayanarak Günlük Sayfalarını Al isteği bir NVMe sürücüsüne gönderilir. Aşağıdaki kod sorgu veri yapısını hazırlar ve ardından DeviceIoControl aracılığıyla komutu cihaza gönderir.
ZeroMemory(buffer, bufferLength);
query = (PSTORAGE_PROPERTY_QUERY)buffer;
protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
query->PropertyId = StorageDeviceProtocolSpecificProperty;
query->QueryType = PropertyStandardQuery;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeLogPage;
protocolData->ProtocolDataRequestValue = NVME_LOG_PAGE_HEALTH_INFO;
protocolData->ProtocolDataRequestSubValue = 0; // This will be passed as the lower 32 bit of log page offset if controller supports extended data for the Get Log Page.
protocolData->ProtocolDataRequestSubValue2 = 0; // This will be passed as the higher 32 bit of log page offset if controller supports extended data for the Get Log Page.
protocolData->ProtocolDataRequestSubValue3 = 0; // This will be passed as Log Specific Identifier in CDW11.
protocolData->ProtocolDataRequestSubValue4 = 0; // This will map to STORAGE_PROTOCOL_DATA_SUBVALUE_GET_LOG_PAGE definition, then user can pass Retain Asynchronous Event, Log Specific Field.
protocolData->ProtocolDataOffset = sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA);
protocolData->ProtocolDataLength = sizeof(NVME_HEALTH_INFO_LOG);
//
// Send request down.
//
result = DeviceIoControl(DeviceList[Index].Handle,
IOCTL_STORAGE_QUERY_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
if (!result || (returnedLength == 0)) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log failed. Error Code %d.\n"), GetLastError());
goto exit;
}
//
// Validate the returned data.
//
if ((protocolDataDescr->Version != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR)) ||
(protocolDataDescr->Size != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log - data descriptor header not valid.\n"));
return;
}
protocolData = &protocolDataDescr->ProtocolSpecificData;
if ((protocolData->ProtocolDataOffset < sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA)) ||
(protocolData->ProtocolDataLength < sizeof(NVME_HEALTH_INFO_LOG))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log - ProtocolData Offset/Length not valid.\n"));
goto exit;
}
//
// SMART/Health Information Log Data
//
{
PNVME_HEALTH_INFO_LOG smartInfo = (PNVME_HEALTH_INFO_LOG)((PCHAR)protocolData + protocolData->ProtocolDataOffset);
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: SMART/Health Information Log Data - Temperature %d.\n"), ((ULONG)smartInfo->Temperature[1] << 8 | smartInfo->Temperature[0]) - 273);
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: ***SMART/Health Information Log succeeded***.\n"));
}
Çağrılar, STORAGE_PROPERTY_ID olarak StorageAdapterProtocolSpecificProperty kullanabilir ve STORAGE_PROTOCOL_SPECIFIC_DATA veya STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısı, satıcıya özgü verilerin 512 baytlık bloklarını istemek üzere ProtocolDataRequestValue=VENDOR_SPECIFIC_LOG_PAGE_IDENTIFIER olarak ayarlanır.
Örnek: NVMe Get Features sorgusu
Önceki örneğe dayanarak, bu örnekte, Özellik Al isteği bir NVMe sürücüsüne gönderilir. Aşağıdaki kod sorgu veri yapısını hazırlar ve ardından DeviceIoControl aracılığıyla komutu cihaza gönderir.
//
// Initialize query data structure to Volatile Cache feature.
//
ZeroMemory(buffer, bufferLength);
query = (PSTORAGE_PROPERTY_QUERY)buffer;
protocolDataDescr = (PSTORAGE_PROTOCOL_DATA_DESCRIPTOR)buffer;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA)query->AdditionalParameters;
query->PropertyId = StorageDeviceProtocolSpecificProperty;
query->QueryType = PropertyStandardQuery;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeFeature;
protocolData->ProtocolDataRequestValue = NVME_FEATURE_VOLATILE_WRITE_CACHE;
protocolData->ProtocolDataRequestSubValue = 0;
protocolData->ProtocolDataOffset = 0;
protocolData->ProtocolDataLength = 0;
//
// Send request down.
//
result = DeviceIoControl(DeviceList[Index].Handle,
IOCTL_STORAGE_QUERY_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
if (!result || (returnedLength == 0)) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: Get Feature - Volatile Cache failed. Error Code %d.\n"), GetLastError());
goto exit;
}
//
// Validate the returned data.
//
if ((protocolDataDescr->Version != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR)) ||
(protocolDataDescr->Size != sizeof(STORAGE_PROTOCOL_DATA_DESCRIPTOR))) {
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: Get Feature - Volatile Cache - data descriptor header not valid.\n"));
return;
}
//
// Volatile Cache
//
{
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: Get Feature - Volatile Cache - %x.\n"), protocolDataDescr->ProtocolSpecificData.FixedProtocolReturnData);
_tprintf(_T("DeviceNVMeQueryProtocolDataTest: ***Get Feature - Volatile Cache succeeded***.\n"));
}
Protokole özgü küme
Windows 10 19H1 ve sonraki sürümlerde IOCTL_STORAGE_SET_PROPERTY NVMe Kümesi Özelliklerini destekleyecek şekilde geliştirilmiştir.
IOCTL_STORAGE_SET_PROPERTY giriş tamponu burada gösterilmiştir:
typedef struct _STORAGE_PROPERTY_SET {
//
// ID of the property being retrieved
//
STORAGE_PROPERTY_ID PropertyId;
//
// Flags indicating the type of set property being performed
//
STORAGE_SET_TYPE SetType;
//
// Space for additional parameters if necessary
//
UCHAR AdditionalParameters[1];
} STORAGE_PROPERTY_SET, *PSTORAGE_PROPERTY_SET;
NVMe özelliğini ayarlamak için IOCTL_STORAGE_SET_PROPERTY kullanırken STORAGE_PROPERTY_SET yapısını aşağıdaki gibi yapılandırın:
- STORAGE_PROPERTY_SET ve STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısını içerebilecek bir arabellek ayırın;
- Denetleyici veya cihaz/ad alanı isteği için PropertyID alanını, sırasıyla StorageAdapterProtocolSpecificProperty veya StorageDeviceProtocolSpecificProperty olarak ayarlayın.
- STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısını istenen değerlerle doldurun. STORAGE_PROTOCOL_SPECIFIC_DATA_EXT başlangıcı, AdditionalParameters alanı ile STORAGE_PROPERTY_SET'dir.
STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısı burada gösterilmiştir.
typedef struct _STORAGE_PROTOCOL_SPECIFIC_DATA_EXT {
STORAGE_PROTOCOL_TYPE ProtocolType;
ULONG DataType; // The value will be protocol specific, as defined in STORAGE_PROTOCOL_NVME_DATA_TYPE or STORAGE_PROTOCOL_ATA_DATA_TYPE.
ULONG ProtocolDataValue;
ULONG ProtocolDataSubValue; // Data sub request value
ULONG ProtocolDataOffset; // The offset of data buffer is from beginning of this data structure.
ULONG ProtocolDataLength;
ULONG FixedProtocolReturnData;
ULONG ProtocolDataSubValue2; // First additional data sub request value
ULONG ProtocolDataSubValue3; // Second additional data sub request value
ULONG ProtocolDataSubValue4; // Third additional data sub request value
ULONG ProtocolDataSubValue5; // Fourth additional data sub request value
ULONG Reserved[5];
} STORAGE_PROTOCOL_SPECIFIC_DATA_EXT, *PSTORAGE_PROTOCOL_SPECIFIC_DATA_EXT;
Ayarlanacağı NVMe özelliğinin türünü belirtmek için STORAGE_PROTOCOL_SPECIFIC_DATA_EXT yapısını aşağıdaki gibi yapılandırın:
- ProtocolType alanını ProtocolTypeNvme olarak ayarlayın;
- DataType alanını STORAGE_PROTOCOL_NVME_DATA_TYPE tarafından tanımlanan NVMeDataTypeFeature numaralandırma değerine ayarlayın;
Aşağıdaki örneklerde NVMe özellik kümesi gösterilmektedir.
Örnek: NVMe Özellikleri Ayarla
Bu örnekte Özellikleri Ayarla isteği bir NVMe sürücüsüne gönderilir. Aşağıdaki kod, küme veri yapısını hazırlar ve ardından deviceIoControl aracılığıyla komutu cihaza gönderir.
PSTORAGE_PROPERTY_SET setProperty = NULL;
PSTORAGE_PROTOCOL_SPECIFIC_DATA_EXT protocolData = NULL;
PSTORAGE_PROTOCOL_DATA_DESCRIPTOR_EXT protocolDataDescr = NULL;
//
// Allocate buffer for use.
//
bufferLength = FIELD_OFFSET(STORAGE_PROPERTY_SET, AdditionalParameters) + sizeof(STORAGE_PROTOCOL_SPECIFIC_DATA_EXT);
bufferLength += NVME_MAX_LOG_SIZE;
buffer = new UCHAR[bufferLength];
//
// Initialize query data structure to get the desired log page.
//
ZeroMemory(buffer, bufferLength);
setProperty = (PSTORAGE_PROPERTY_SET)buffer;
setProperty->PropertyId = StorageAdapterProtocolSpecificProperty;
setProperty->SetType = PropertyStandardSet;
protocolData = (PSTORAGE_PROTOCOL_SPECIFIC_DATA_EXT)setProperty->AdditionalParameters;
protocolData->ProtocolType = ProtocolTypeNvme;
protocolData->DataType = NVMeDataTypeFeature;
protocolData->ProtocolDataValue = NVME_FEATURE_HOST_CONTROLLED_THERMAL_MANAGEMENT;
protocolData->ProtocolDataSubValue = 0; // This will pass to CDW11.
protocolData->ProtocolDataSubValue2 = 0; // This will pass to CDW12.
protocolData->ProtocolDataSubValue3 = 0; // This will pass to CDW13.
protocolData->ProtocolDataSubValue4 = 0; // This will pass to CDW14.
protocolData->ProtocolDataSubValue5 = 0; // This will pass to CDW15.
protocolData->ProtocolDataOffset = 0;
protocolData->ProtocolDataLength = 0;
//
// Send request down.
//
result = DeviceIoControl(m_deviceHandle,
IOCTL_STORAGE_SET_PROPERTY,
buffer,
bufferLength,
buffer,
bufferLength,
&returnedLength,
NULL
);
Sıcaklık sorguları
Windows 10 ve sonraki sürümlerde IOCTL_STORAGE_QUERY_PROPERTY , NVMe cihazlarından sıcaklık verilerini sorgulamak için de kullanılabilir.
STORAGE_TEMPERATURE_DATA_DESCRIPTOR bir NVMe sürücüsünden sıcaklık bilgilerini almak için STORAGE_PROPERTY_QUERY yapısını aşağıdaki gibi yapılandırın:
- STORAGE_PROPERTY_QUERY yapısı içerebilen bir arabellek tahsis edin.
- Bir denetleyici veya cihaz/ad alanı isteği için, PropertyID alanını StorageAdapterTemperatureProperty ya da StorageDeviceTemperatureProperty olarak ayarlayın.
- QueryType alanını PropertyStandardQueryolarak ayarlayın.
STORAGE_TEMPERATURE_INFO yapısı (Windows 10 ve sonraki sürümlerde kullanılabilir) burada gösterilmiştir:
typedef struct _STORAGE_TEMPERATURE_INFO {
USHORT Index; // Starts from 0. Index 0 may indicate a composite value.
SHORT Temperature; // Signed value; in Celsius.
SHORT OverThreshold; // Signed value; in Celsius.
SHORT UnderThreshold; // Signed value; in Celsius.
BOOLEAN OverThresholdChangable; // Can the threshold value being changed by using IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD.
BOOLEAN UnderThresholdChangable; // Can the threshold value being changed by using IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD.
BOOLEAN EventGenerated; // Indicates that notification will be generated when temperature cross threshold.
UCHAR Reserved0;
ULONG Reserved1;
} STORAGE_TEMPERATURE_INFO, *PSTORAGE_TEMPERATURE_INFO;
Davranış değiştirme komutları
Cihaz özniteliklerini işleyen veya cihaz davranışını etkileyebilecek komutlar, işletim sisteminin ilgilenmesi daha zordur. G/Ç işlenirken cihaz öznitelikleri çalışma zamanında değişirse, düzgün işlenmediği takdirde eşitleme veya veri bütünlüğü sorunları ortaya çıkabilir.
NVMe Set-Features komutu, komutu değiştirme davranışına iyi bir örnektir. Tahkim mekanizmasının değiştirilmesine ve sıcaklık eşiklerinin ayarlanmasına izin verir. Uçuş esnasındaki veri akışının davranış etkileyen ayar komutları gönderildiğinde risk altında olmadığından emin olmak için, Windows NVMe cihazındaki tüm G/Ç işlemlerini duraklatır, kuyrukları temizler ve arabellekleri boşaltır. Set komutu başarıyla yürütüldükten sonra G/Ç sürdürülür (mümkünse). Giriş/Çıkış sürdürülemezse, cihazın sıfırlanması gerekebilir.
Sıcaklık eşiklerini ayarlama
Windows 10, sıcaklık eşiklerini almaya ve ayarlamaya yönelik bir IOCTL olan IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD'yi kullanıma sunar. Cihazın geçerli sıcaklığını almak için de kullanabilirsiniz. Bu IOCTL için giriş/çıkış arabelleği, önceki kod bölümünde yer alan STORAGE_TEMPERATURE_INFO yapısıdır.
Örnek: Aşırı eşik sıcaklığını ayarlama
Bu örnekte NVMe sürücüsünün eşik üzerindeki sıcaklığı ayarlanır. Aşağıdaki kod komutu hazırlar ve ardından DeviceIoControl aracılığıyla cihaza gönderir.
BOOL result;
ULONG returnedLength = 0;
STORAGE_TEMPERATURE_THRESHOLD setThreshold = {0};
setThreshold.Version = sizeof(STORAGE_TEMPERATURE_THRESHOLD);
setThreshold.Size = sizeof(STORAGE_TEMPERATURE_THRESHOLD);
setThreshold.Flags = STORAGE_TEMPERATURE_THRESHOLD_FLAG_ADAPTER_REQUEST;
setThreshold.Index = SensorIndex;
setThreshold.Threshold = Threshold;
setThreshold.OverThreshold = UpdateOverThreshold;
//
// Send request down.
//
result = DeviceIoControl(DeviceList[DeviceIndex].Handle,
IOCTL_STORAGE_SET_TEMPERATURE_THRESHOLD,
&setThreshold,
sizeof(STORAGE_TEMPERATURE_THRESHOLD),
NULL,
0,
&returnedLength,
NULL
);
Satıcıya özgü özellikleri ayarlama
Komut Efektleri Günlüğü olmadan, sürücünün komutun sonuçları hakkında hiçbir bilgisi yoktur. Bu nedenle Komut Efektleri Günlüğü gereklidir. İşletim sisteminin bir komutun yüksek etkiye sahip olup olmadığını ve sürücüye diğer komutlarla paralel olarak gönderilip gönderilemediğini belirlemesine yardımcı olur.
Komut Efektleri Günlüğü henüz satıcıya özgü Set-Features komutlarını kapsayacak kadar ayrıntılı değil. Bu nedenle, satıcıya özgü Set-Features komutları göndermek henüz mümkün değildir. Ancak, satıcıya özgü komutları göndermek için daha önce ele alınan geçiş mekanizmasını kullanmak mümkündür. Daha fazla bilgi için bakınız Geçiş mekanizması.
Başlık dosyaları
Aşağıdaki dosyalar NVMe geliştirmeyle ilgilidir. Bu dosyalar Microsoft Windows Yazılım Geliştirme Seti (SDK)ile birlikte sunulur.
| Başlık dosyası | Açıklama |
|---|---|
| ntddstor.h | Çekirdek modundan depolama sınıfı sürücülerine erişmek için sabitleri ve türleri tanımlar. |
| nvme.h | NVMe ile ilgili diğer veri yapıları için. |
| winioctl.h | Kullanıcı modu uygulamaları için depolama API'leri de dahil olmak üzere genel Win32 IOCTL tanımları için. |