ATA PIO Mode: Difference between revisions

Jump to navigation Jump to search
m
s/dword/uint32_t/g
[unchecked revision][unchecked revision]
(→‎See Also: Merged references from IDE)
m (s/dword/uint32_t/g)
Line 77:
Then read the Status port (0x1F7) again. If the value read is 0, the drive does not exist. For any other value: poll the Status port (0x1F7) until bit 7 (BSY, value = 0x80) clears. Because of some ATAPI drives that do not follow spec, at this point you need to check the LBAmid and LBAhi ports (0x1F4 and 0x1F5) to see if they are non-zero. If so, the drive is not ATA, and you should stop polling. Otherwise, continue polling one of the Status ports until bit 3 (DRQ, value = 8) sets, or until bit 0 (ERR, value = 1) sets.
 
At that point, if ERR is clear, the data is ready to read from the Data port (0x1F0). Read 256 words16-bit values, and store them.
 
===="Command Aborted"====
 
ATAPI or SATA devices are supposed to respond to an ATA IDENTIFY command by immediately reporting an error in the Status Register, rather than setting BSY, then DRQ, then sending 256 words16 bit values of PIO data. These devices will also write specific values to the IO ports, that can be read. Seeing ATAPI specific values on those ports after an IDENTIFY is definitive proof that the device is ATAPI -- on the Primary bus, IO port 0x1F4 will read as 0x14, and IO port 0x1F5 will read as 0xEB. If a normal ATA drive should ever happen to abort an IDENTIFY command, the values in those two ports will be 0. A SATA device will report 0x3c, and 0xc3 instead. See below for a code example.
 
'''However''', at least a few real ATAPI drives do not set the ERR flag after aborting an ATA IDENTIFY command. So do not depend completely on the ERR flag after an IDENTIFY.
Line 87:
====Interesting information returned by IDENTIFY====
 
* Worduint16_t 0: is useful if the device is not a hard disk.
 
* Worduint16_t 83: Bit 10 is set if the drive supports LBA48 mode.
 
* Worduint16_t 88: The bits in the low byte tell you the supported UDMA modes, the upper byte tells you which UDMA mode is active. If the active mode is not the highest supported mode, you may want to figure out why.
 
* Worduint16_t 93 from a master drive on the bus: Bit 12 is supposed to be set if the drive detects an 80 pin cable.
 
* Wordsuint16_t 60 & 61 taken as a DWORDuint32_t contain the total number of 28 bit LBA addressable sectors on the drive. (If non-zero, the drive supports LBA28.)
 
* Wordsuint16_t 100 through 103 taken as a QWORDuint64_t contain the total number of 48 bit addressable sectors on the drive. (Probably also proof that LBA48 is supported.)
 
==Addressing Modes==
Line 228:
 
In the early days, the only intent of an IRQ was to inform the IRQ handler that the drive was ready to send or accept data. The expectation was that the IRQ handler itself would perform a PIO based data transfer of the next data block, immediately.
Now things are not so simple. One or both of the drives on the bus may be in DMA mode, or have data block sizes other than 256 words16-bit values.
Also, there is more emphasis now on returning as quickly as possible out of the IRQ handler routine. So the question is: what is the minimal set of operations that an IRQ handler needs to do?
 
Line 263:
===Read/Write Multiple===
 
One way of trying to reduce the number of IRQs in <b>multitasking</b> PIO mode is to use the READ MULTIPLE (0xC4), and WRITE MULTIPLE (0xC5) commands. These commands make the drive buffer "blocks" of sectors, and only send one IRQ per block, rather than one IRQ per sector. See Wordsuint16_t 47 and 59 of the IDENTIFY command, to determine the number of sectors in a block. You can also try to use the SET MULTIPLE MODE (0xC6) command, to change the sectors per block.
 
<b>NOTE:</b> Overall, PIO mode is a slow transfer method. Under real working conditions, almost any drive should be controlled by a DMA driver, and should not be using PIO. Trying to speed up PIO mode by preempting IRQs (or any other method) is mostly a waste of time and effort. ATA drives that are 400MB or smaller may not support Multiword DMA mode 0, however. If you want to support drives that size, then perhaps a <i>little</i> effort spent on PIO mode drivers is worthwhile.
Line 283:
# Send the "READ SECTORS" command (0x20) to port 0x1F7: outb(0x1F7, 0x20)
# Wait for an IRQ or poll.
# Transfer 256 words16-bit values, a worduint16_t at a time, into your buffer from I/O port 0x1F0. (In assembler, REP INSW works well for this.)
# Then loop back to waiting for the next IRQ (or poll again -- see next note) for <i>each successive sector</i>.
 
Note for polling PIO drivers:
After transferring the last worduint16_t of a PIO data block to the data IO port, give the drive a 400ns delay to reset its DRQ bit (and possibly set BSY again, while emptying/filling its buffer to/from the drive).
 
Note on the "magic bits" sent to port 0x1f6: Bit 6 (value = 0x40) is the LBA bit. This must be set for either LBA28 or LBA48 transfers. It must be clear for CHS transfers. Bits 7 and 5 are obsolete for <b>current</b> ATA drives, but must be set for backwards compatibility with very old (ATA1) drives.
 
===Writing 28 bit LBA===
To write sectors in 28 bit PIO mode, send command "WRITE SECTORS" (0x30) to the Command port. Do <b>not</b> use <b>REP</b> OUTSW to transfer data. There must be a tiny delay between each OUTSW output worduint16_t. A jmp $+2 size of delay. Make sure to do a Cache Flush (ATA command 0xE7) after each write command completes.
 
===48 bit PIO===
Line 299:
(Notes: A sector count of 0 means 65536 sectors = 32MB. Try not to send bytes to the same IO port twice in a row. Doing so is <b>much</b> slower than doing two outb() commands to <b>different</b> IO ports. The important thing is that the high byte of the sector count, and LBA bytes 4, 5, & 6 go to their respective ports <b>before the low bytes</b>.)
 
Assume you have a sectorcount worduint16_t and a 6 byte LBA value. Mentally number the LBA bytes as 1 to 6, from low to high.
Send the 2 byte sector count to port 0x1F2 (high byte first), and the six LBA byte pairs to ports 0x1F3 through 0x1F5 in some appropriate order.
 
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu