直接向Windows中的设备发送ATA命令?

时间:2011-02-21 20:36:39

标签: windows device trim ioctl ata

我正在尝试将ATA命令发送到Windows中的物理磁盘,并从设备获取响应。

  

注意:在这种情况下,我想发送IDENTIFY DEVICE(0xEC)   命令。设备将响应   一个512字节的数据块。 (在   特别是我对第0位感兴趣   字119 - 设备的support for the TRIM command)。

我知道我需要使用CreateFile来打开设备:

handle = CreateFile(
    "\\.\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ, 
    nil,            // no security attributes
    OPEN_EXISTING,
    0,              // flags and attributes
    nil             // no template file
);

但在此之后,我被阻止该做什么。

我考虑过使用0xEC发送[DeviceIoControl][4]

// const ATACommand_IdentifyDevice = 0xEC;
uint bytesReturned = 0;

DeviceIoControl(handle, 
    0xEC,               // IO Control Code
    nil,                // input buffer not needed
    0,                  // input buffer is zero bytes
    @buffer,            // output buffer to store the returned 512-bytes
    512,                // output buffer is 512 bytes long
    out bytesReturned, 
    nil                 // not an overlapped operation
);

但这是完全错误的。发送到DeviceIoControl的IoControlCode必须是有效的IO_CTL,built using the macro

#define CTL_CODE(DeviceType, Function, Method, Access) (
   ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)
)

查看SDK,有许多有效的Disk Management Control Codes,例如:

  • IOCTL_DISK_CREATE_DISK
  • IOCTL_DISK_GET_DRIVE_GEOMETRY
  • IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
  • IOCTL_DISK_GET_PARTITION_INFO
  • IOCTL_STORAGE_QUERY_PROPERTY

但它们都不是IDENTIFY DEVICE命令,或返回它返回的任何内容。

所以我相信我必须使用一些发送命令的“原始”方法。


搜索周围,我遇到了无证件的IOCTL

#define  DFP_RECEIVE_DRIVE_DATA   0x0007c088   

当你分解IOCTL片段时,意味着:

Custom: (0)
Device Type: (7) FILE_DEVICE_DISK
Required Access: (3) METHOD_NEITHER
Custom: (0)
Function Code: (34)
Transfer Type: (0)

但是,inputBuffer必须包含的内容,大小以及outputBuffer将包含的内容或其必需内容均无文档。我也无法弄清楚functionCode 34(0x22)是什么。


我的问题:如何将原始ATA命令(例如0xEC)发送到ATA设备,并阅读其响应?

另见


答案

使用ReadWrite访问权限打开驱动器:

handle = CreateFile(
    "\\.\PhysicalDrive0", 
    GENERIC_READ or GENERIC_WRITE, // IOCTL_ATA_PASS_THROUGH requires read-write
    FILE_SHARE_READ, 
    nil,            // no security attributes
    OPEN_EXISTING,
    0,              // flags and attributes
    nil             // no template file
);

ATA_PASS_THROUGH_EX结构设置为我们的输入缓冲区,以与IOCTL_ATA_PASS_THROUGH IO控制代码一起使用:

ATA_PASS_THROUGH_EX inputBuffer;
inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
inputBuffer.DataTransferLength = 0;
inputBuffer.DataBufferOffset = 0;
// todo: put the ATA command (e.g. 0xEC) somewhere

uint inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);

设置输出缓冲区以保持驱动器的预期512字节响应:

Byte[] outputBuffer = new Byte[512];
uint outputBufferSize = 512;

致电DeviceIoControl

int ioControlCode = IOCTL_ATA_PASS_THROUGH; // or maybe IOCTL_ATA_PASS_THROUGH_DIRECT
uint bytesReturned = 0;

DeviceIoControl(handle, ioControlCode,
    inputBuffer, inputBufferSize,
    outputBuffer, outputBufferSize,
    out bytesReturned,
    nil      // not an overlapped operation    
);

关闭文件句柄:

handle.Close();

3 个答案:

答案 0 :(得分:11)

您需要使用IOCTL_ATA_PASS_THROUGH / IOCTL_ATA_PASS_THROUGH_DIRECT,这些都有很好的文档记录。此外,您还需要对CreateFile进行GENERIC_READ | GENERIC_WRITE访问。

请注意,XP SP2之前的版本不支持这些。此外,如果你有一个基于nForce的MB与nvidia驱动程序,你的SATA驱动器将显示为SCSI,你不能使用这个passthrough。

在某些情况下,SMART IOCTL(例如SMART_RCV_DRIVE_DATA)将适用于nForce驱动程序。您可以使用它们来获取IDENTIFY和SMART数据,但不是很多。

开源smartmontools是开始寻找示例代码的好地方。

编辑:来自应用与ATA设备通话的示例。

EResult DeviceOperationManagerWin::executeATACommandIndirect(ATACommand & Cmd) {
    const uint32 FillerSize = 0;
    Utils::ByteBuffer B;
    B.reserve(sizeof(ATA_PASS_THROUGH_EX) + 4 + Cmd.bufferSize());
    ATA_PASS_THROUGH_EX & PTE = * (ATA_PASS_THROUGH_EX *) B.appendPointer(sizeof(ATA_PASS_THROUGH_EX) + FillerSize + Cmd.bufferSize());
    uint8 * DataPtr = ((uint8 *) &PTE) + sizeof(ATA_PASS_THROUGH_EX) + FillerSize;

    memset(&PTE, 0, sizeof(ATA_PASS_THROUGH_EX) + FillerSize);
    PTE.Length = sizeof(PTE);
    PTE.AtaFlags = 0;
    PTE.AtaFlags |= Cmd.requiresDRDY() ? ATA_FLAGS_DRDY_REQUIRED : 0;
    switch (Cmd.dataDirection()) {
    case ddFromDevice: 
        PTE.AtaFlags |= ATA_FLAGS_DATA_IN; 
        break;
    case ddToDevice:
        PTE.AtaFlags |= ATA_FLAGS_DATA_OUT;
        memcpy(DataPtr, Cmd.buffer(), Cmd.bufferSize());
        break;
    default:
        break;
    }
    PTE.AtaFlags |= Cmd.is48Bit() ? ATA_FLAGS_48BIT_COMMAND : 0;
    PTE.AtaFlags |= Cmd.isDMA() ? ATA_FLAGS_USE_DMA : 0;
    PTE.DataTransferLength = Cmd.bufferSize();
    PTE.TimeOutValue = Cmd.timeout();
    PTE.DataBufferOffset = sizeof(PTE) + FillerSize;
    PTE.DataTransferLength = Cmd.bufferSize();
    PTE.CurrentTaskFile[0] = Cmd.taskFileIn0().Features;
    PTE.CurrentTaskFile[1] = Cmd.taskFileIn0().Count;
    PTE.CurrentTaskFile[2] = Cmd.taskFileIn0().LBALow;
    PTE.CurrentTaskFile[3] = Cmd.taskFileIn0().LBAMid;
    PTE.CurrentTaskFile[4] = Cmd.taskFileIn0().LBAHigh;
    PTE.CurrentTaskFile[5] = Cmd.taskFileIn0().Device;
    PTE.CurrentTaskFile[6] = Cmd.taskFileIn0().Command;
    PTE.CurrentTaskFile[7] = 0;
    if (Cmd.is48Bit()) {
        PTE.PreviousTaskFile[0] = Cmd.taskFileIn1().Features;
        PTE.PreviousTaskFile[1] = Cmd.taskFileIn1().Count;
        PTE.PreviousTaskFile[2] = Cmd.taskFileIn1().LBALow;
        PTE.PreviousTaskFile[3] = Cmd.taskFileIn1().LBAMid;
        PTE.PreviousTaskFile[4] = Cmd.taskFileIn1().LBAHigh;
        PTE.PreviousTaskFile[5] = Cmd.taskFileIn1().Device;
        PTE.PreviousTaskFile[6] = 0;
        PTE.PreviousTaskFile[7] = 0;
    }

    DWORD BR; 
    if (!DeviceIoControl(FHandle, IOCTL_ATA_PASS_THROUGH, &PTE, B.size(), &PTE, B.size(), &BR, 0)) {
        FLastOSError = GetLastError();
        LOG_W << "ioctl ATA_PT failed for " << Cmd << ": " << FLastOSError << " (" << Utils::describeOSError(FLastOSError) << ")";
        return Utils::mapOSError(FLastOSError);
    }
    Cmd.taskFileOut0().Error = PTE.CurrentTaskFile[0];
    Cmd.taskFileOut0().Count = PTE.CurrentTaskFile[1];
    Cmd.taskFileOut0().LBALow = PTE.CurrentTaskFile[2];
    Cmd.taskFileOut0().LBAMid = PTE.CurrentTaskFile[3];
    Cmd.taskFileOut0().LBAHigh = PTE.CurrentTaskFile[4];
    Cmd.taskFileOut0().Device = PTE.CurrentTaskFile[5];
    Cmd.taskFileOut0().Status = PTE.CurrentTaskFile[6];
    Cmd.taskFileOut1().Error = PTE.PreviousTaskFile[0];
    Cmd.taskFileOut1().Count = PTE.PreviousTaskFile[1];
    Cmd.taskFileOut1().LBALow = PTE.PreviousTaskFile[2];
    Cmd.taskFileOut1().LBAMid = PTE.PreviousTaskFile[3];
    Cmd.taskFileOut1().LBAHigh = PTE.PreviousTaskFile[4];
    Cmd.taskFileOut1().Device = PTE.PreviousTaskFile[5];
    Cmd.taskFileOut1().Status = PTE.PreviousTaskFile[6];
    if (Cmd.dataDirection() == ddFromDevice) {
        memcpy(Cmd.buffer(), DataPtr, Cmd.bufferSize());
    }
    return resOK;
    }

编辑:没有外部依赖的示例。

IDENTIFY需要一个512字节的数据缓冲区:

unsigned char Buffer[512 + sizeof(ATA_PASS_THROUGH_EX)] = { 0 };
ATA_PASS_THROUGH_EX & PTE = *(ATA_PASS_THROUGH_EX *) Buffer;
PTE.Length = sizeof(PTE);
PTE.TimeOutValue = 10;
PTE.DataTransferLength = 512;
PTE.DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);

按照ATA规范中的规定设置IDE寄存器。

IDEREGS * ir = (IDEREGS *) PTE.CurrentTaskFile;
ir->bCommandReg = 0xEC;
ir->bSectorCountReg = 1;

IDENTIFY既不是48位也不是DMA,它从设备读取:

PTE.AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED;

做ioctl:

DeviceIOControl(Handle, IOCTL_ATA_PASS_THROUGH, &PTE, sizeof(Buffer), &PTE, sizeof(Buffer), &BR, 0);

在这里,您应该从DeviceIOControl插入错误检查,并查看IDEREGS以查找设备报告的错误。

获取IDENTIFY数据,假设您已定义结构IdentifyData

IdentifyData * IDData = (IdentifyData *) (Buffer + sizeof(ATA_PASS_THROUGH_EX));

答案 1 :(得分:5)

根据https://stackoverflow.com/a/5071027/15485的答案Erik,我编写了以下自包含代码。我在带有SSD磁盘和运行Windows 7的DELL笔记本电脑上进行了测试。

// Sending ATA commands directly to device in Windows?
// https://stackoverflow.com/questions/5070987/sending-ata-commands-directly-to-device-in-windows

#include <Windows.h>
#include <ntddscsi.h> // for ATA_PASS_THROUGH_EX
#include <iostream>

// I have copied the struct declaration from 
// "IDENTIFY_DEVICE_DATA structure" http://msdn.microsoft.com/en-us/library/windows/hardware/ff559006(v=vs.85).aspx
// I think it is better to include the suitable header (MSDN says the header is Ata.h and suggests to include Irb.h)
typedef struct _IDENTIFY_DEVICE_DATA {
   struct {
      USHORT Reserved1  :1;
      USHORT Retired3  :1;
      USHORT ResponseIncomplete  :1;
      USHORT Retired2  :3;
      USHORT FixedDevice  :1;
      USHORT RemovableMedia  :1;
      USHORT Retired1  :7;
      USHORT DeviceType  :1;
   } GeneralConfiguration;
   USHORT NumCylinders;
   USHORT ReservedWord2;
   USHORT NumHeads;
   USHORT Retired1[2];
   USHORT NumSectorsPerTrack;
   USHORT VendorUnique1[3];
   UCHAR  SerialNumber[20];
   USHORT Retired2[2];
   USHORT Obsolete1;
   UCHAR  FirmwareRevision[8];
   UCHAR  ModelNumber[40];
   UCHAR  MaximumBlockTransfer;
   UCHAR  VendorUnique2;
   USHORT ReservedWord48;
   struct {
      UCHAR  ReservedByte49;
      UCHAR  DmaSupported  :1;
      UCHAR  LbaSupported  :1;
      UCHAR  IordyDisable  :1;
      UCHAR  IordySupported  :1;
      UCHAR  Reserved1  :1;
      UCHAR  StandybyTimerSupport  :1;
      UCHAR  Reserved2  :2;
      USHORT ReservedWord50;
   } Capabilities;
   USHORT ObsoleteWords51[2];
   USHORT TranslationFieldsValid  :3;
   USHORT Reserved3  :13;
   USHORT NumberOfCurrentCylinders;
   USHORT NumberOfCurrentHeads;
   USHORT CurrentSectorsPerTrack;
   ULONG  CurrentSectorCapacity;
   UCHAR  CurrentMultiSectorSetting;
   UCHAR  MultiSectorSettingValid  :1;
   UCHAR  ReservedByte59  :7;
   ULONG  UserAddressableSectors;
   USHORT ObsoleteWord62;
   USHORT MultiWordDMASupport  :8;
   USHORT MultiWordDMAActive  :8;
   USHORT AdvancedPIOModes  :8;
   USHORT ReservedByte64  :8;
   USHORT MinimumMWXferCycleTime;
   USHORT RecommendedMWXferCycleTime;
   USHORT MinimumPIOCycleTime;
   USHORT MinimumPIOCycleTimeIORDY;
   USHORT ReservedWords69[6];
   USHORT QueueDepth  :5;
   USHORT ReservedWord75  :11;
   USHORT ReservedWords76[4];
   USHORT MajorRevision;
   USHORT MinorRevision;
   struct {
      USHORT SmartCommands  :1;
      USHORT SecurityMode  :1;
      USHORT RemovableMediaFeature  :1;
      USHORT PowerManagement  :1;
      USHORT Reserved1  :1;
      USHORT WriteCache  :1;
      USHORT LookAhead  :1;
      USHORT ReleaseInterrupt  :1;
      USHORT ServiceInterrupt  :1;
      USHORT DeviceReset  :1;
      USHORT HostProtectedArea  :1;
      USHORT Obsolete1  :1;
      USHORT WriteBuffer  :1;
      USHORT ReadBuffer  :1;
      USHORT Nop  :1;
      USHORT Obsolete2  :1;
      USHORT DownloadMicrocode  :1;
      USHORT DmaQueued  :1;
      USHORT Cfa  :1;
      USHORT AdvancedPm  :1;
      USHORT Msn  :1;
      USHORT PowerUpInStandby  :1;
      USHORT ManualPowerUp  :1;
      USHORT Reserved2  :1;
      USHORT SetMax  :1;
      USHORT Acoustics  :1;
      USHORT BigLba  :1;
      USHORT DeviceConfigOverlay  :1;
      USHORT FlushCache  :1;
      USHORT FlushCacheExt  :1;
      USHORT Resrved3  :2;
      USHORT SmartErrorLog  :1;
      USHORT SmartSelfTest  :1;
      USHORT MediaSerialNumber  :1;
      USHORT MediaCardPassThrough  :1;
      USHORT StreamingFeature  :1;
      USHORT GpLogging  :1;
      USHORT WriteFua  :1;
      USHORT WriteQueuedFua  :1;
      USHORT WWN64Bit  :1;
      USHORT URGReadStream  :1;
      USHORT URGWriteStream  :1;
      USHORT ReservedForTechReport  :2;
      USHORT IdleWithUnloadFeature  :1;
      USHORT Reserved4  :2;
   } CommandSetSupport;
   struct {
      USHORT SmartCommands  :1;
      USHORT SecurityMode  :1;
      USHORT RemovableMediaFeature  :1;
      USHORT PowerManagement  :1;
      USHORT Reserved1  :1;
      USHORT WriteCache  :1;
      USHORT LookAhead  :1;
      USHORT ReleaseInterrupt  :1;
      USHORT ServiceInterrupt  :1;
      USHORT DeviceReset  :1;
      USHORT HostProtectedArea  :1;
      USHORT Obsolete1  :1;
      USHORT WriteBuffer  :1;
      USHORT ReadBuffer  :1;
      USHORT Nop  :1;
      USHORT Obsolete2  :1;
      USHORT DownloadMicrocode  :1;
      USHORT DmaQueued  :1;
      USHORT Cfa  :1;
      USHORT AdvancedPm  :1;
      USHORT Msn  :1;
      USHORT PowerUpInStandby  :1;
      USHORT ManualPowerUp  :1;
      USHORT Reserved2  :1;
      USHORT SetMax  :1;
      USHORT Acoustics  :1;
      USHORT BigLba  :1;
      USHORT DeviceConfigOverlay  :1;
      USHORT FlushCache  :1;
      USHORT FlushCacheExt  :1;
      USHORT Resrved3  :2;
      USHORT SmartErrorLog  :1;
      USHORT SmartSelfTest  :1;
      USHORT MediaSerialNumber  :1;
      USHORT MediaCardPassThrough  :1;
      USHORT StreamingFeature  :1;
      USHORT GpLogging  :1;
      USHORT WriteFua  :1;
      USHORT WriteQueuedFua  :1;
      USHORT WWN64Bit  :1;
      USHORT URGReadStream  :1;
      USHORT URGWriteStream  :1;
      USHORT ReservedForTechReport  :2;
      USHORT IdleWithUnloadFeature  :1;
      USHORT Reserved4  :2;
   } CommandSetActive;
   USHORT UltraDMASupport  :8;
   USHORT UltraDMAActive  :8;
   USHORT ReservedWord89[4];
   USHORT HardwareResetResult;
   USHORT CurrentAcousticValue  :8;
   USHORT RecommendedAcousticValue  :8;
   USHORT ReservedWord95[5];
   ULONG  Max48BitLBA[2];
   USHORT StreamingTransferTime;
   USHORT ReservedWord105;
   struct {
      USHORT LogicalSectorsPerPhysicalSector  :4;
      USHORT Reserved0  :8;
      USHORT LogicalSectorLongerThan256Words  :1;
      USHORT MultipleLogicalSectorsPerPhysicalSector  :1;
      USHORT Reserved1  :2;
   } PhysicalLogicalSectorSize;
   USHORT InterSeekDelay;
   USHORT WorldWideName[4];
   USHORT ReservedForWorldWideName128[4];
   USHORT ReservedForTlcTechnicalReport;
   USHORT WordsPerLogicalSector[2];
   struct {
      USHORT ReservedForDrqTechnicalReport  :1;
      USHORT WriteReadVerifySupported  :1;
      USHORT Reserved01  :11;
      USHORT Reserved1  :2;
   } CommandSetSupportExt;
   struct {
      USHORT ReservedForDrqTechnicalReport  :1;
      USHORT WriteReadVerifyEnabled  :1;
      USHORT Reserved01  :11;
      USHORT Reserved1  :2;
   } CommandSetActiveExt;
   USHORT ReservedForExpandedSupportandActive[6];
   USHORT MsnSupport  :2;
   USHORT ReservedWord1274  :14;
   struct {
      USHORT SecuritySupported  :1;
      USHORT SecurityEnabled  :1;
      USHORT SecurityLocked  :1;
      USHORT SecurityFrozen  :1;
      USHORT SecurityCountExpired  :1;
      USHORT EnhancedSecurityEraseSupported  :1;
      USHORT Reserved0  :2;
      USHORT SecurityLevel  :1;
      USHORT Reserved1  :7;
   } SecurityStatus;
   USHORT ReservedWord129[31];
   struct {
      USHORT MaximumCurrentInMA2  :12;
      USHORT CfaPowerMode1Disabled  :1;
      USHORT CfaPowerMode1Required  :1;
      USHORT Reserved0  :1;
      USHORT Word160Supported  :1;
   } CfaPowerModel;
   USHORT ReservedForCfaWord161[8];
   struct {
      USHORT SupportsTrim  :1;
      USHORT Reserved0  :15;
   } DataSetManagementFeature;
   USHORT ReservedForCfaWord170[6];
   USHORT CurrentMediaSerialNumber[30];
   USHORT ReservedWord206;
   USHORT ReservedWord207[2];
   struct {
      USHORT AlignmentOfLogicalWithinPhysical  :14;
      USHORT Word209Supported  :1;
      USHORT Reserved0  :1;
   } BlockAlignment;
   USHORT WriteReadVerifySectorCountMode3Only[2];
   USHORT WriteReadVerifySectorCountMode2Only[2];
   struct {
      USHORT NVCachePowerModeEnabled  :1;
      USHORT Reserved0  :3;
      USHORT NVCacheFeatureSetEnabled  :1;
      USHORT Reserved1  :3;
      USHORT NVCachePowerModeVersion  :4;
      USHORT NVCacheFeatureSetVersion  :4;
   } NVCacheCapabilities;
   USHORT NVCacheSizeLSW;
   USHORT NVCacheSizeMSW;
   USHORT NominalMediaRotationRate;
   USHORT ReservedWord218;
   struct {
      UCHAR NVCacheEstimatedTimeToSpinUpInSeconds;
      UCHAR Reserved;
   } NVCacheOptions;
   USHORT ReservedWord220[35];
   USHORT Signature  :8;
   USHORT CheckSum  :8;
} IDENTIFY_DEVICE_DATA, *PIDENTIFY_DEVICE_DATA;

// Taken from smartmontools
// Copies n bytes (or n-1 if n is odd) from in to out, but swaps adjacents
// bytes.
static void swapbytes(char * out, const char * in, size_t n)
{
   for (size_t i = 0; i < n; i += 2) {
      out[i]   = in[i+1];
      out[i+1] = in[i];
   }
}

// Taken from smartmontools
// Copies in to out, but removes leading and trailing whitespace.
static void trim(char * out, const char * in)
{
   // Find the first non-space character (maybe none).
   int first = -1;
   int i;
   for (i = 0; in[i]; i++)
      if (!isspace((int)in[i])) {
         first = i;
         break;
      }

      if (first == -1) {
         // There are no non-space characters.
         out[0] = '\0';
         return;
      }

      // Find the last non-space character.
      for (i = strlen(in)-1; i >= first && isspace((int)in[i]); i--)
         ;
      int last = i;

      strncpy(out, in+first, last-first+1);
      out[last-first+1] = '\0';
}

// Taken from smartmontools
// Convenience function for formatting strings from ata_identify_device
void ata_format_id_string(char * out, const unsigned char * in, int n)
{
   bool must_swap = true;
#ifdef __NetBSD__
   /* NetBSD kernel delivers IDENTIFY data in host byte order (but all else is LE) */
   // TODO: Handle NetBSD case in os_netbsd.cpp
   if (isbigendian())
      must_swap = !must_swap;
#endif

   char tmp[65];
   n = n > 64 ? 64 : n;
   if (!must_swap)
      strncpy(tmp, (const char *)in, n);
   else
      swapbytes(tmp, (const char *)in, n);
   tmp[n] = '\0';
   trim(out, tmp);
}

int main(int argc, char* argv[])
{
   HANDLE handle = ::CreateFileA(
      "\\\\.\\PhysicalDrive0", 
      GENERIC_READ | GENERIC_WRITE, //IOCTL_ATA_PASS_THROUGH requires read-write
      FILE_SHARE_READ, 
      0,            //no security attributes
      OPEN_EXISTING,
      0,              //flags and attributes
      0             //no template file
      );

   if ( handle == INVALID_HANDLE_VALUE ) {
      std::cout << "Invalid handle\n";
   }

   // IDENTIFY command requires a 512 byte buffer for data:
   const unsigned int IDENTIFY_buffer_size = 512;
   const BYTE IDENTIFY_command_ID =  0xEC;
   unsigned char Buffer[IDENTIFY_buffer_size + sizeof(ATA_PASS_THROUGH_EX)] = { 0 };
   ATA_PASS_THROUGH_EX & PTE = *(ATA_PASS_THROUGH_EX *) Buffer;
   PTE.Length = sizeof(PTE);
   PTE.TimeOutValue = 10;
   PTE.DataTransferLength = 512;
   PTE.DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);

   // Set up the IDE registers as specified in ATA spec.
   IDEREGS * ir = (IDEREGS *) PTE.CurrentTaskFile;
   ir->bCommandReg = IDENTIFY_command_ID;
   ir->bSectorCountReg = 1;

   // IDENTIFY is neither 48-bit nor DMA, it reads from the device:
   PTE.AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED;

   DWORD BR = 0;
   BOOL b = ::DeviceIoControl(handle, IOCTL_ATA_PASS_THROUGH, &PTE, sizeof(Buffer), &PTE, sizeof(Buffer), &BR, 0);
   if ( b == 0 ) {
      std::cout << "Invalid call\n";
   }

   IDENTIFY_DEVICE_DATA * data = (IDENTIFY_DEVICE_DATA *) (Buffer + sizeof(ATA_PASS_THROUGH_EX));

   // Nota Bene: I think some endianness control is needed
   char model[40+1];
   ata_format_id_string(model, data->ModelNumber, sizeof(model)-1);

   char serial[20+1];
   ata_format_id_string(serial, data->SerialNumber, sizeof(serial)-1);

   char firmware[8+1];
   ata_format_id_string(firmware, data->FirmwareRevision, sizeof(firmware)-1);

   std::cout << "ModelNumber:      " << model << "\n";
   std::cout << "SerialNumber:     " << serial << "\n";
   std::cout << "FirmwareRevision: " << firmware << "\n";
   return 0;
}

答案 2 :(得分:1)