How ATA registers work
This article explains how ATA registers are used in hard drives and SSDs
How do hard drives work?
Hard drives and SATA SSDs contains a set of registers (or ports) that are used to communicate with the computer. For an end user, these ports are immaterial, but when it comes to hard disk firmware programming and direct drive access, knowledge of these ports and how to use them analytically and programmatically is essential in data recovery work. Below, we take a look at how ATA registers work.
Firstly, there are two main modes of port access. Data functions and Non-data functions. Data functions are split into two sub-categories; Read and Write for performing data access commands.
Non-data commands tell the drive to do something or stop doing something. For example, send the drive to sleep, wake it up, perform a soft reset, etc. Non data commands do not manipulate the user data on the drive.
The process of working with ports is;
First, load in the values into the registers, and then load the command register with the byte value to perform the required function. It is also possible to read a port value, by querying the register directly.
Here is a list of ports available on a modern drives.
Port ID | Reading | Writing | Value type |
---|---|---|---|
P0 | Data register | Word | |
P1 | Error register | Feature register | Byte |
P2 | Sector count | Byte | |
P3 | Sector number register | Byte | |
P4 | Cylinder low register | Byte | |
P5 | Cylinder high register | Byte | |
P6 | Device register * | Byte | |
P7 | Status register | Command register | Byte |
Control block registers | |||
P8 | Alternative Status register | Device control | Byte |
* The device register is used for old PATA/IDE hard drives, where more than one drive can be on a cable, for example Master and Slave, where 0 would be Master and 1 Slave. The device would need to be entered as a separate port. For example, the old PATA computers had preset base port values for each hard drive connector. If the hard drive base port you are working with is 1F0h. The values for the ports would be as follows.
When you read or write to a register (P0 – P9) value, you use the port address. For example, if you want to load 0xECh into the command register, you would write the value in address 1F7h. Then, If you need to read the status register, you read address 0×1F7 (or 0×3F6). You can get the base value by looking at the reserved port list for the storage controller on the resources tab for the storage controller.
Port | Address |
---|---|
Base drive port | 0x1F0h |
P0 | 0x1F0h |
P1 | 0x1F1h |
P2 | 0x1F2h |
P3 | 0x1F3h |
P4 | 0x1F4h |
P5 | 0x1F5h |
P6 | 0x1F6h |
P7 | 0x1F7h |
P8 | 0x3F6h |
It is important to differentiate between reading and writing data to reading and writing to registers. When writing to a register, you are just setting the register with a single value. If the intention is to read data from the drive, you would enter the details about the location of the read, by loading ports P2 to P6, then load the read command into register P7. The drive will then fetch the data, one word at a time, and load it into the P0 register.
When each word (two bytes) of the data is read, it is stored in P0. The DRQ flag is set in the Status register, notifying the application that the data needs to be read from P0. Once it is read from P0, the DRQ flag is unset, and the next word is loaded into Po, and so on until all the requested data is read.
When reading or writing with drives that support 48 bit LBA values, the process is slightly different. If for example you were making a 48 bit read you would load P3 – P5 with the first set of values, then again with the second set and finally send the command to perform the function.
When reading the Alt-Status register (P8), it is a copy of the normal Status register (P7). Where this is useful is, on faulty drives we find it better to use the Alt Status register, as this will always contain the last status value returned by the drive.
The Device Control port is used for sending commands such as a Soft Reset. A soft reset is needed to reset the status register to 0×50h (idle) when an error occurs, or the drive BSY or DRQ flags remain set after a command is not completed correctly.
What happens if there is an error during a command?
When an error happens, it will fall into a specific category. First, the ATA status register will return a byte value with bit 1 set. Once this happens, you can read the error code in P1 register. This is a short error code that describes why the error occurs. For example, if the drive does not recognise a command, the error flag is set, and the ABORT flag is set to 1.
Features register
This register acts as a Sub-command register, for example if we wanted to turn SMART off we would load P1 with 0xD9h and P7 with 0xB0h.
Port ID | Reading | Writing | Value type |
---|---|---|---|
P0 | Data register = empty | Word | |
P1 | Error register | Feature register = 0xD9 | Byte |
P2 | Sector count = empty | Byte | |
P3 | Sector number register = empty | Byte | |
P4 | Cylinder low register = empty | Byte | |
P5 | Cylinder high register = empty | Byte | |
P6 | Device = 0x0 | Byte | |
P7 | Status register | Command register = 0xB0 | Byte |
Control block registers | |||
P8 | Alternative Status register | Device control | Byte |