Sending ATA commands on Linux

written on Fri 12 September 2014

It appears that any user can send an ATA message on Linux. The function that allows this is called ioctl, by using message identifier 0x31F (HDIO_DRIVE_CMD).

It is possible to send, i.e. ATA IDENTIFY message by using 0xEC message. This command should return a device identification information. Other status indication message is implemented by the 0xA1 message, but the device needs to properly implement PACKET extensions, so it needs to be an ATAPI device.

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/ioctl.h>

using namespace std;

int main(void) {
    int fd = ::open("/dev/sda", O_RDONLY | O_DIRECT);
    if(fd != -1) {
        uint8_t buf[512] = { 0xEC, 0, 0, 1, 0 };
        int ret = ::ioctl(fd, 0x31F, buf);

        for(int i = 0; i < 512; ++i) {
            ::putchar(buf[i]);
        }
    } else {
        ::perror("open");
    }

    ::close(fd);
    return 0;
}

The data you'll get will be encoded in big endian notation, so you need to fix this by using necessary shifts and bswaps.

ATA Identify example

This entry was tagged on #c++, #hardware and #linux