Search code examples
windowssolid-state-driveata

ATA command device IDENTIFY


I am trying to identify a device using ATA_PASS_THROUGH_EX.

When I see the output buffer, it has all invalid data. Can someone help me what I am doing wrong?

#include <Windows.h>
#include <ntddscsi.h>
#include <iostream>

void main() {
    WCHAR *fileName = (WCHAR * ) "\\.\PhysicalDrive0";
    HANDLE handle = CreateFile(
       fileName, 
       GENERIC_READ | GENERIC_WRITE, //IOCTL_ATA_PASS_THROUGH requires read-write
       FILE_SHARE_READ, 
       NULL,            //no security attributes
       OPEN_EXISTING,
       0,              //flags and attributes
       NULL             //no template file
    );


    ATA_PASS_THROUGH_EX inputBuffer;
    inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
    inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
    inputBuffer.DataTransferLength = 0;
    inputBuffer.DataBufferOffset = 0;

    IDEREGS *ir  = (IDEREGS *) inputBuffer.CurrentTaskFile;
    ir->bCommandReg = 0xEC; //identify device
    ir->bSectorCountReg = 1;

    unsigned int inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);

    UINT8 outputBuffer[512];
    UINT32 outputBufferSize = 512;
    LPDWORD bytesReturned = 0;

    DeviceIoControl( handle, IOCTL_ATA_PASS_THROUGH_DIRECT, &inputBuffer,    inputBufferSize, &outputBuffer, outputBufferSize, bytesReturned, NULL);

    DWORD error = GetLastError();

    std::cout << outputBuffer << std::endl;
    system("pause");
}

update: When I check the error value, it is 5, which means it is an access violation. I am running in admin mode. Am I doing something wrong?

-Nick


Solution

  • I've done this using code that looks like this:

    int foo()
    {
        int iRet( 0 );
    
        // Open handle to disk.
        HANDLE hDevice( ::CreateFileW( L"\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ) );
        if( hDevice == INVALID_HANDLE_VALUE )
        {
            std::wcout << L"CreateFileW( " << sPath << L" ) failed.  LastError: " << GetLastError() << std::endl;
            return -1;
        }
    
        //
        // Use IOCTL_ATA_PASS_THROUGH
        //
        std::vector< UCHAR > vBuffer( sizeof( ATA_PASS_THROUGH_EX ) + sizeof( IDENTIFY_DEVICE_DATA ), 0 );
        PATA_PASS_THROUGH_EX pATARequest( reinterpret_cast< PATA_PASS_THROUGH_EX >( &vBuffer[0] ) );
        pATARequest->AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED;
        pATARequest->Length = sizeof( ATA_PASS_THROUGH_EX );
        pATARequest->DataBufferOffset = sizeof( ATA_PASS_THROUGH_EX );
        pATARequest->DataTransferLength = sizeof( IDENTIFY_DEVICE_DATA );
        pATARequest->TimeOutValue = 2;
        pATARequest->CurrentTaskFile[6] = ID_CMD;
    
        ULONG ulBytesRead;
        if( DeviceIoControl( hDevice, IOCTL_ATA_PASS_THROUGH, 
            &vBuffer[0], ULONG( vBuffer.size() ),
            &vBuffer[0], ULONG( vBuffer.size() ),
            &ulBytesRead, NULL ) == FALSE )
        {
            std::cout << "DeviceIoControl(IOCTL_ATA_PASS_THROUGH) failed.  LastError: " << GetLastError() << std::endl;
            iRet = -1;
        }
        else
        {
            // Fetch identity blob from output buffer.
            PIDENTIFY_DEVICE_DATA pIdentityBlob( reinterpret_cast< PIDENTIFY_DEVICE_DATA >( &vBuffer[ sizeof( ATA_PASS_THROUGH_EX ) ] ) );
        }
    
        CloseHandle( hDevice );
    
        return iRet;
    }
    

    Note that this must be run from an administrator account or elevated context.