SATADRIVER SPECIFICATION

Low-level interface

AHCI controllers may be attached via the PCI bus as was anticipated by the
AHCI standard. In this case, the SATADriver would scan the PCI bus for devices
of the appropriate class. It should be noted however that at the present time
there are no RISC OS platforms with such an architecture, so this is considered
a future enhancement.

Host controllers with alternate attachments are discovered via the HAL Device
API. This potentially includes hot-pluggable host controllers, as is true of all
HAL Devices. The HAL Device looks like this:

type        bits 15-8 = 5 (controllers of peripheral buses)
            bits 7-0 = 2 for AHCI controller
id          bits 15-0 varies
location    bits 31-28 varies (e.g. 1 for main system bus)
            bits 27-24 varies (e.g. 5 for network-on-chip)
            bits 23-16 varies (e.g. 0)
            bits 15-8 varies (e.g. 0)
            bits 7-0 varies (e.g. 0)
version     This document describes major version 1. The only minor version
            number at the time of writing is 0.
description, address, reserved1, Activate, Deactivate, Reset, Sleep,
devicenumber, TestIRQ, ClearIRQ, reserved2 are standard device fields and
require no further description
flags       bits 31-0 = reserved, 0


High-level interface

At the high level, a design goal has been to permit the insertion of a switching
module, similar in operation to SCSISwitch, to permit multiple ATA-type drivers
to run simultaneously on the same hardware (for example an Iyonix PC with
motherboard PATA and expansion card SATA). Initially, however, only SATADriver
is being developed, but using the SWI allocation for the ATASwitch module. Once
switching is in place, the only practical difference is that the 8-bit IDs used
to reference controllers and ports in the SWI API will be allocated from a
common pool across all ATA-type drivers, and these may differ from the numbers
used internally to each driver.

For example, within SATADriver, the controller/port ID is interpreted such that
the lower 5 bits are a port number and the upper 3 bits are a controller index
(assigned in order of controller discovery). Within PATADriver, typically you'd
only expect IDs of 0 and 1 to be used (or just 0 for single-controller
hardware). The ATASwitch module would, however, merely allocate blocks of IDs
on a first-come-first-served basis, so software above this level must only
treat the ID as an opaque number.

The device ID is a way of distinguishing between drives that share the same
controller/port (and therefore the same ATA bus bandwidth, the same interrupt
and so on). Unless indicated otherwise (typically due to the use of an AHCI
controller that supports FIS-based switching) operations can only be ongoing
for a single drive attached to the same controller/port - this is true of both
PATA and SATA. For compatibility with old ADFS APIs, PATADriver uses device IDs
of 0 and 8 for master and slave drives. SATADriver uses the PMP (port multiplier
port) as the device ID. High-level software should not need to worry about this
distinction, however - both schemes are discoverable using SWI ATA_Enumerate.

SATADriver does not initially support hot-plugging of drives, so unlike
SDIODriver, it does not use service calls to announce drive discovery.

The driver's main API is in the form of SWIs.


SWI ATA_Initialise 0 (SWI &59780)

On entry
R0 = 0 (reason code: reset controller/port)
R1 bits 0-7 = controller/port ID

Not reentrant

This call resets the specified host controller/port. This is accomplished on
AHCI controllers by use of a COMRESET.


SWI ATA_Control 0 (SWI &59781)

On entry
R0 = 0 (reason code: acquire exclusive access to drive, non-blocking)
R1  bits 0-3 = device ID
    bits 4-11 = controller/port ID

On exit
Error &820502 ("Device in use") is returned if exclusive access cannot be acquired
at the present time.

Reentrant

This call is one of a group that must be used around every call to SWI ATA_Op
or ATA_PacketOp. The reason for this is that sometimes (such as during reset)
ATA or ATAPI commands need to be issued in groups of two or more. If another
ATA command is queued in the middle of such a group, it may find that the device
is not in a receptive state for that command, and the operation of the command
group that was interrupted may also be disrupted.

This version of the acquire-drive SWI is suitable for use from the background,
but the caller must be prepared for it to fail and reschedule the command at a
later time.


SWI ATA_Control 1 (SWI &59781)

On entry
R0 = 1 (reason code: acquire exclusive access to drive, blocking)
R1  bits 0-3 = device ID
    bits 4-11 = controller/port ID

Not reentrant

This call is similar to ATA_Control 0, but waits (forever if necessary) for the
drive to become available.


SWI ATA_Control 2 (SWI &59781)

On entry
R0 = 2 (reason code: acquire exclusive access to drive, blocking with sleep)
R1  bits 0-3 = device ID
    bits 4-11 = controller/port ID

Not reentrant

This call is similar to ATA_Control 1, but calls OS_UpCall 6 while the drive is
not available, in order to yield the current application.


SWI ATA_Control 3 (SWI &59781)

On entry
R0 = 3 (reason code: release exclusive access to drive)
R1  bits 0-3 = device ID
    bits 4-11 = controller/port ID

Reentrant

This call makes the specified drive available for others to use. It should be
used routinely as soon as a group of related ATA or ATAPI commands has been
issued, to avoid locking other routines out.


SWI ATA_Control 4 (SWI &59781)

On entry
R0 = 4 (reason code: abort all operations on controller/port)
R1  bits 4-11 = controller/port ID

Reentrant

This call cancels all outstanding operations on a port. You should abort
individual operations instead wherever possible.


SWI ATA_Control 5 (SWI &59781)

On entry
R0 = 5 (reason code: abort ATA or ATAPI operation)
R1  bits 4-11 = controller/port ID
R2 = operation ID as returned by ATA_Op or ATA_PacketOp for background operations

Reentrant

This call cancels the specified background operation.


SWI ATA_Enumerate 0 (SWI &59782)

On entry
R0 = 0 (reason code: enumerate drives)
R1 = 0 on first call, or preserved on subsequent calls

On exit
R0 preserved
R1 = 0 if no more drives (R2 is not valid in this case), else the value to pass
     in R1 to next call
R2  bits 0-3 = device ID
    bits 4-11 = controller/port ID
    bit 12 set => device is a packet device

Reentrant

This call enables the caller to discover the set of controller/port and device
ID which are implemented and which have a drive connected. In the case of
SATA buses, port multipliers themselves are not reported.


SWI ATA_Op (SWI &59783)

On entry
R0  bit 1 set => don't wait for DRDY before issuing command
    bit 2 set => data transfer uses multiword DMA or UDMA from device's
                 perspective (note that the host controller may actually use
                 bus mastering even for PIO transfers)
    bits 12-15 = device ID
    bits 16-23 = controller/port ID
    bits 24-25 = transfer direction (0 = no data transfer, 1 = read, 2 = write)
    bit 26 set => scatter transfer
    bit 27 set => don't poll for escape during foreground transfers
    (bit 28 reserved - bits 26-29 are equivalent to bits 5-8 for FileCore DiscOps)
    bit 29 set => background transfer (not supported initially)
R1 = length of parameter block, must be 1 (for device control), 7 (for 28-bit
     LBA), 11 (for 48-bit LBA) or 12 (for wide features)
R2 = pointer to parameter block for command and results:
     Device control form  28-bit LBA form         48-bit LBA form          Wide features form
     R2+0 Device control  R2+0 Features/Error     R2+0 Features/Error      R2+0 Features 7..0 / Error
                          R2+1 Sector Count       R2+1 Sector Count 7..0   R2+1 Features 15..8
                          R2+2 LBA Low/Sector No  R2+2 Sector Count 15..8  R2+2 Sector Count 7..0
                          R2+3 LBA Mid/Cyl Low    R2+3 LBA 7..0            R2+3 Sector Count 15..8
                          R2+4 LBA High/Cyl High  R2+4 LBA 15..8           R2+4 LBA 7..0
                          R2+5 Device (+head)     R2+5 LBA 23..16          R2+5 LBA 15..8
                          R2+6 Command/Status     R2+6 LBA 31..24          R2+6 LBA 23..16
                                                  R2+7 LBA 39..32          R2+7 LBA 31..24
                                                  R2+8 LBA 47..40          R2+8 LBA 39..32
                                                  R2+9 Device              R2+9 LBA 47..40
                                                  R2+10 Command/Status     R2+10 Device
                                                                           R2+11 Command/Status
R3 = RAM ptr for start of transfer or pointer to scatter list of address length
     pairs if bit 26 of R0 is set
R4 = length of transfer (in bytes) - must be 0 if no data transfer is specified
     in R0 bits 24-25, and must be a non-0 multiple of 4 otherwise
R5 = if bit 29 of R0 is clear, this is timeout in centiseconds or 0 for
     no timeout
     if bit 29 of R0 is set, this is the value to pass in R5 to the callback
     routine
R6 = address of callback routine, if bit 26 of R0 is set
R7 = value to pass in R12 to the callback routine, if bit 26 of R0 is set

On exit
If error was detected,
  R0 -> error block
  R4 updated to number of bytes not transferred
  V set
If foreground transfer completed successfully,
  R0 = 0 (consider as a flags word with all bits reserved)
  R4 = 0
  V clear
If background transfer has started,
  R0 = 0 (consider as a flags word with all bits reserved)
  R1 = operation handle, can be used to cancel the operation using ATA_Control
  V clear

Reentrant when used to specify a background transfer, otherwise not reentrant.

The scatter list is not updated (in other words, it behaves more like the
low-level SCSISwitch API than the backward-compatible SCSIDriver API).
FileCore-style wrapping is accepted (ie if an address entry is between &FFFF0000
and &FFFFFFFF, and the length field is 0, then that should be treated as an
instruction to push the scatter list pointer backwards by an offset of up to
64K).

The callback operates as follows:
    The call is made in privileged mode. IRQs may be enabled or disabled.
    If the operation completed, V is clear & R0 is set to 0.
    If an error occurred, V is set and R0 is an error pointer.
    R4 holds the amount of data not transferred.
    R5 and R12 are set to the values passed in.
    All registers will be preserved.

Note that, unlike SWI ADFS_IDEUserOp, this SWI does not return disc error
numbers in R0 with V clear (the error translation is performed by ADFS 4).

Unlike FileCore_DiscOp, the total transfer length must be a whole number of
words. This is because the underlying hardware cannot be guaranteed to handle
smaller units, and SATADriver is at too low a level to be able to compensate
by converting the command into separate read-modify-write stages.

The caller must special-case error number &604, "Transfer too complex". This is
used when the data region specified by R3 and R4 are either too intricate or too
long to be achieved - typically due to limitations of the DMA hardware. R4 is
updated on exit to hold a shorter transfer length which *can* be achieved. The
caller should change the parameter block to reflect this length and retry the
operation. Typically, the caller will then want to issue one or more further
operations to complete the amount of data transfer originally requested.


SWI ATA_PacketOp (SWI &59784)

On entry
R0  bit 2 set => data transfer uses multiword DMA or UDMA from device's
                 perspective (note that the host controller may actually use
                 bus mastering even for PIO transfers)
    bit 3 set => device requires DMADIR indicator in Features task file register
                 (determine this using IDENTIFY PACKET DEVICE)
    bits 12-15 = device ID
    bits 16-23 = controller/port ID
    bits 24-25 = transfer direction (0 = no data transfer, 1 = read, 2 = write)
    bit 26 set => scatter transfer
    bit 27 set => don't poll for escape during foreground transfers
    (bit 28 reserved - bits 26-29 are equivalent to bits 5-8 for FileCore DiscOps)
    bit 29 set => background transfer (not supported initially)
R1 = length of control block, may be 12 or 16 bytes
R2 = pointer to control block:
     12-byte form
     R2+0 Operation code
     R2+1 Service action
     R2+2 LBA 31..24
     R2+3 LBA 23..16
     R2+4 LBA 15..8
     R2+5 LBA 7..0
     R2+6 Length 31..24
     R2+7 Length 23..16
     R2+8 Length 15..8
     R2+9 Length 7..0
     R2+10 Reserved
     R2+11 Control
R3 = RAM ptr for start of transfer or pointer to scatter list of address length
     pairs if bit 26 of R0 is set
R4 = length of transfer (in bytes) - must be 0 if no data transfer is specified
     in R0 bits 24-25, and must be a non-0 multiple of 4 otherwise
R5 = if bit 29 of R0 is clear, this is timeout in centiseconds or 0 for
     no timeout
     if bit 29 of R0 is set, this is the value to pass in R5 to the callback
     routine
R6 = address of callback routine, if bit 26 of R0 is set
R7 = value to pass in R12 to the callback routine, if bit 26 of R0 is set

On exit
Same as ATA_Op
