How to Read particular sector of a disk using ATA command?

ata trim command
serial ata revision 3.4 specification download
sata set feature command
download microcode ata
sata identify device data
sata specification t13

I want to read a particular sector(MBR Sector) of a disk using ATA commands in vc++. I am new to VC++ so i am facing a problem when sending command to disk using DeviceIoControl. I am providing a code that i am using to read out a sector using command Read Sector(s)(0x20).

  BOOL status = FALSE;
 PATA_PASS_THROUGH_EX pATAData;
DWORD dataSize = sizeof(ATA_PASS_THROUGH_EX) + 512;
BYTE Buffer[sizeof(ATA_PASS_THROUGH_EX) + 512];
DWORD bytescopied = 0;

    pATAData = (ATA_PASS_THROUGH_EX*)Buffer;

    ZeroMemory(pATAData,dataSize); // clears the buffer

    pATAData->Length = sizeof(ATA_PASS_THROUGH_EX);
    pATAData->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
    pATAData->DataTransferLength = 512;
    pATAData->TimeOutValue = 2;

    pATAData->CurrentTaskFile[1] = 0x01;
    pATAData->CurrentTaskFile[2] = 0x00;
    pATAData->CurrentTaskFile[3] = 0x00;
    pATAData->CurrentTaskFile[4] = 0x00;
    pATAData->AtaFlags =ATA_FLAGS_DATA_IN;

    pATAData->CurrentTaskFile[6] = 0x20; // command Read Sector(s)(0x20)
    /* sends the command to the device, **hDevice** is device handle*/
    status = DeviceIoControl(hDevice, IOCTL_ATA_PASS_THROUGH, pATAData, dataSize,Buffer, dataSize, &bytescopied, NULL );

I can't undersatnd that what's wrong in this code and what i am missing here, but it is not working. What i am missing here ? If there is a problem with parametres of PATA_PASS_THROUGH_EX structure than tell how to read first sector(MBR).

Thankyou everyone for your help. I got the solution. A little bit thing that i have not noticed. That is Ata Flags. I have to send multiple flags. Eg.

pATAData->ataFlags = ATA_FLAGS_48BIT_COMMAND | ATA_FLAGS_DRDY_REQUIRED | ATA_FLAGS_DATA_IN

and also send the ATA command Opcode in PreviousTaskFile[6] also. And the few things to be noticed is What is the block size of the HDD? It could be more than 512 bytes, especially if it is a large disk like(1TB...4TB). As such, you'll need to adjust the sizes accordingly. You can see what the size is by doing the EC identify ATA command, and then look at the resulting data structure.

Is there way to read sectors from SATA drive without ECC correction , I know, there was such possibility like that in old ATA standards: "READ LONG" command produced LBA sector + ECC payload. sg_read_long supports in in� ;=====; ATA read sectors (LBA mode) ;; @param EAX Logical Block Address of sector; @param CL Number of sectors to read; @param RDI The address of buffer to put data obtained from disk;; @return None;===== ata_lba_read: pushfq and rax, 0x0FFFFFFF push rax push rbx push rcx push rdx push rdi mov rbx, rax; Save LBA in RBX mov edx, 0x01F6; Port to send drive and bit 24 - 27 of LBA shr eax, 24; Get bit 24 - 27 in al or al, 11100000b; Set bit 6 in al for LBA mode out dx, al mov edx, 0x01F2; Port

Thanks for your help guys. I got the solution. I was not assigning the Device Handle in CurrentTaskFile.

pATAData->CurrentTaskFile[5] = (UCHAR)hDevice;

But IDENTIFY_DEVICE(ECh) command was sending succesfully without this. I don't know it's right or wrong but this is working.

Disk Drive I/O Commands and Write Blocking, write blockers that use the ATA interface. 3. BIOS-Based Write Blockers specific and undocumented, but in practice they may not make any changes to the drive. sector then tried the Read Long command to read the simulated bad sector. A given disk drive supports either the ATA command set or the SCSI command set. The SCSI command set does include the ability to send ATA pass commands, but not vice versa. Tim Roberts, [email protected]

Thanks guys for your help. After a long discussion i find that i have to send extended commands for large disk. But now i am sending Read Sector(s) Ext(0x24 oppcode) command.

BOOL status = FALSE;
PATA_PASS_THROUGH_EX pATAData;
DWORD dataSize = sizeof(ATA_PASS_THROUGH_EX) + 512;
BYTE Buffer[sizeof(ATA_PASS_THROUGH_EX) + 512];
DWORD bytescopied = 0;

pATAData = (ATA_PASS_THROUGH_EX*)Buffer;

ZeroMemory(pATAData,dataSize); // clears the buffer

pATAData->Length = sizeof(ATA_PASS_THROUGH_EX);
pATAData->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
pATAData->DataTransferLength = 512;
pATAData->TimeOutValue = 2;

pATAData->CurrentTaskFile[0] = 0x00;
pATAData->CurrentTaskFile[1] = 0x01;
pATAData->CurrentTaskFile[2] = 0x01;
pATAData->CurrentTaskFile[3] = 0x00;
pATAData->CurrentTaskFile[4] = 0x00;
pATAData->CurrentTaskFile[5] = 0x40;
pATAData->CurrentTaskFile[7]=  0x00;
pATAData->AtaFlags =ATA_FLAGS_48BIT_COMMAND;

pATAData->PreviousTaskFile[0] = 0x00;
pATAData->PreviousTaskFile[1] = 0x00;
pATAData->PreviousTaskFile[2] = 0x00;
pATAData->PreviousTaskFile[3] = 0x00;
pATAData->PreviousTaskFile[4] = 0x00;
pATAData->PreviousTaskFile[5] = 0x04;
pATAData->PreviousTaskFile[7]=  0x00;

pATAData->CurrentTaskFile[6] = 0x24; // command Read Sector(s) Ext(0x24)
/* sends the command to the device, **hDevice** is device handle*/
status = DeviceIoControl(hDevice, IOCTL_ATA_PASS_THROUGH, pATAData, dataSize,Buffer, dataSize, &bytescopied, NULL );

But here is the same problem. command executed successfully but it does not read any sector. I am unable to find any error.

How to Read particular sector of a disk using ATA command?, I want to read a particular sector(MBR Sector) of a disk using ATA commands in vc++. I am new to VC++ so i am facing a problem when sending command to� I am using extended ATA commands to read Disk drive(SSD or HDD both). I have been read out many document based on ATA commands and finaly write a code to send extended commands to my disk. I am using extended because i have to read out large disk like upto 4 TB using LBA addressing.

[PDF] ATA Command Set - 4 (ACS-4), 10) Added cross references where possible in SMART Read Data table. 11) Added a Incorporated f14176r0 Other Subcommand Specific Bits;. 3). Incorporated Incorporated f14181r5 – Set Sector Configuration (heavily edited during Note 1 to entry: An example of a device is a disk drive. Note 2 to� Until an OS (or bootloader) has a disk driver loaded, these BIOS functions are the only way to access disks. There are two basic INT0x13 calls to use for ATA disk access. One uses Cylinder, Head, Sector addressing, and the other uses LBA addressing. There is a third command to access ATAPI drives using the PACKET command set.

ATA PIO Mode, The method suggested in the ATA specs for sending ATA commands tells you to modes to select particular sectors to read or write on a disk. Reading/Writing disk sectors is done differently in win 9x and win NT/2K/XP. Windows 9x. Windows 9x provides a vxd called vwin32.vxd using which msdos functions including absolute disk read/write can be performed. A handle to vwin32.vxd must be first created using the CreateFile function.

hdparm(8) - Linux manual page - Michael Kerrisk, hdparm provides a command line interface to various kernel interfaces supported by the -a Get/set sector count for filesystem (software) read-ahead. Many IDE drives also have a separate built-in read-ahead function, which augments this Overlay, a way for vendors to selectively disable certain features of a drive. More Info on Driver Writing and Debugging. The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters.

Comments
  • Did you call GetLastError to see why it failed?
  • Not sure if this applies since you don't show the code for opening the device, but you might take a look anyway. stackoverflow.com/questions/3362037/…
  • Why does this have the qt tag? You may get better help with other tags such as: device, hard-drive or sata. Also, what is the error you get?
  • Yes i call GetLastError. It give an error ERROR_INVALID_PARAMETER (0x57). But i can't understand which parameter is wrong. Actually I am new to windows progarmming.
  • Tags fixed to match code.
  • Now i can read sectors, but now i have to read large storage disk(upto 4 TB). Can anyone help me how to send details in CurrentTaskFile[] to read a large space disk. Because CurrentTaskFile[] is UCHAR type array. If i want to read last sector from a 1 TB disk .
  • You need to use the extended commands (EXT) along with the PreviousTaskFile[]
  • Regarding the CurrentTaskFile[5] aka the "Device" register. The old ATA spec reserved bit 6 of this register for "LBA mode". This means you should set this bit to enable "LBA mode", and clear it to use "CHS mode". To keep things simple, just always use LBA mode by setting this register to 0x40. The reason why the IDENTIFY_DEVICE command works is because it doesn't access any sectors, so it doesn't care about LBA or CHS mode.
  • THanks @tchau.dev . Your last two comments is very helpfull to me. Yes i have to use the extended commands (EXT) along with the PreviousTaskFile[] for large disk.
  • There are 2 types of errors you need to take into consideration when using DeviceIoControl. (1) The first is from DeviceIoControl telling you if the command was sent successfully to the device. (2) The second is from the device it self. In this case, a SATA or PATA drive. Every command will return a status indicating if the command is successful or not. This will be in the "Status" register (CurrentTaskFile[7]) and the "Error" register (CurrentTaskFile[0]). The "Status" register tells you if there is an error, and the "Error" register will tell you the type of error.
  • I got none of the above errors. Everything looks like ok but no buffer is read from drive. The "Status" register (CurrentTaskFile[7] and "Error" register (CurrentTaskFile[0]) both are zero. GetLastError() retruns code(0x57)(ERROR_INVALID_PARAMETER). DeviceIoControl returns TRUE but output buffer is empty. The lpBytesReturned parameter's value is 40(exactly the size of PATA_PASS_THROUGH_EX structure) it means no data is read from the drive.
  • Error register can be zero, but the Status register should at least have the "Device Ready" bit set to one (bit 6). Don't trust the DeviceIoControl() return status. It looks like GetLastError() is telling the truth.
  • Correction on my part, the "Status" register should be the same as the "Command" register, which is CurrentTaskFile[6].
  • No error no result, what should i do. The "Status" register (CurrentTaskFile[7] and "Error" register (CurrentTaskFile[0]) both are zero. Only two registers "Command" register is 0x58, and "Device" register is 0xE0 has any returned value that is not helping. What should i do.