Chapter 2. libata Driver API

Table of Contents

struct ata_port_operations
Disable ATA port
Post-IDENTIFY device configuration
Set PIO/DMA mode
Taskfile read/write
ATA command execute
Per-cmd ATAPI DMA capabilities filter
Read specific ATA shadow registers
Select ATA device on bus
Reset ATA bus
Control PCI IDE BMDMA engine
High-level taskfile hooks
Timeout (error) handling
Hardware interrupt handling
SATA phy read/write
Init and shutdown

struct ata_port_operations is defined for every low-level libata hardware driver, and it controls how the low-level driver interfaces with the ATA and SCSI layers.

FIS-based drivers will hook into the system with ->qc_prep() and ->qc_issue() high-level hooks. Hardware which behaves in a manner similar to PCI IDE hardware may utilize several generic helpers, defining at a bare minimum the bus I/O addresses of the ATA shadow register blocks.

struct ata_port_operations

Disable ATA port

void (*port_disable) (struct ata_port *);
	

Called from ata_bus_probe() and ata_bus_reset() error paths, as well as when unregistering from the SCSI module (rmmod, hot unplug).

Post-IDENTIFY device configuration

void (*dev_config) (struct ata_port *, struct ata_device *);
	

Called after IDENTIFY [PACKET] DEVICE is issued to each device found. Typically used to apply device-specific fixups prior to issue of SET FEATURES - XFER MODE, and prior to operation.

Set PIO/DMA mode

void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (struct ata_port *, struct ata_device *);
void (*post_set_mode) (struct ata_port *ap);
	

Hooks called prior to the issue of SET FEATURES - XFER MODE command. dev->pio_mode is guaranteed to be valid when ->set_piomode() is called, and dev->dma_mode is guaranteed to be valid when ->set_dmamode() is called. ->post_set_mode() is called unconditionally, after the SET FEATURES - XFER MODE command completes successfully.

->set_piomode() is always called (if present), but ->set_dma_mode() is only called if DMA is possible.

Taskfile read/write

void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
	

->tf_load() is called to load the given taskfile into hardware registers / DMA buffers. ->tf_read() is called to read the hardware registers / DMA buffers, to obtain the current set of taskfile register values.

ATA command execute

void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
	

causes an ATA command, previously loaded with ->tf_load(), to be initiated in hardware.

Per-cmd ATAPI DMA capabilities filter

int (*check_atapi_dma) (struct ata_queued_cmd *qc);
	

Allow low-level driver to filter ATA PACKET commands, returning a status indicating whether or not it is OK to use DMA for the supplied PACKET command.

Read specific ATA shadow registers

u8   (*check_status)(struct ata_port *ap);
u8   (*check_altstatus)(struct ata_port *ap);
u8   (*check_err)(struct ata_port *ap);
	

Reads the Status/AltStatus/Error ATA shadow register from hardware. On some hardware, reading the Status register has the side effect of clearing the interrupt condition.

Select ATA device on bus

void (*dev_select)(struct ata_port *ap, unsigned int device);
	

Issues the low-level hardware command(s) that causes one of N hardware devices to be considered 'selected' (active and available for use) on the ATA bus. This generally has no meaning on FIS-based devices.

Reset ATA bus

void (*phy_reset) (struct ata_port *ap);
	

The very first step in the probe phase. Actions vary depending on the bus type, typically. After waking up the device and probing for device presence (PATA and SATA), typically a soft reset (SRST) will be performed. Drivers typically use the helper functions ata_bus_reset() or sata_phy_reset() for this hook.

Control PCI IDE BMDMA engine

void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (struct ata_queued_cmd *qc);
void (*bmdma_stop) (struct ata_port *ap);
u8   (*bmdma_status) (struct ata_port *ap);
	

When setting up an IDE BMDMA transaction, these hooks arm (->bmdma_setup), fire (->bmdma_start), and halt (->bmdma_stop) the hardware's DMA engine. ->bmdma_status is used to read the standard PCI IDE DMA Status register.

These hooks are typically either no-ops, or simply not implemented, in FIS-based drivers.

High-level taskfile hooks

void (*qc_prep) (struct ata_queued_cmd *qc);
int (*qc_issue) (struct ata_queued_cmd *qc);
	

Higher-level hooks, these two hooks can potentially supercede several of the above taskfile/DMA engine hooks. ->qc_prep is called after the buffers have been DMA-mapped, and is typically used to populate the hardware's DMA scatter-gather table. Most drivers use the standard ata_qc_prep() helper function, but more advanced drivers roll their own.

->qc_issue is used to make a command active, once the hardware and S/G tables have been prepared. IDE BMDMA drivers use the helper function ata_qc_issue_prot() for taskfile protocol-based dispatch. More advanced drivers implement their own ->qc_issue.

Timeout (error) handling

void (*eng_timeout) (struct ata_port *ap);
	

This is a high level error handling function, called from the error handling thread, when a command times out. Most newer hardware will implement its own error handling code here. IDE BMDMA drivers may use the helper function ata_eng_timeout().

Hardware interrupt handling

irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
void (*irq_clear) (struct ata_port *);
	

->irq_handler is the interrupt handling routine registered with the system, by libata. ->irq_clear is called during probe just before the interrupt handler is registered, to be sure hardware is quiet.

SATA phy read/write

u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
                   u32 val);
	

Read and write standard SATA phy registers. Currently only used if ->phy_reset hook called the sata_phy_reset() helper function.

Init and shutdown

int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap);
void (*host_stop) (struct ata_host_set *host_set);
	

->port_start() is called just after the data structures for each port are initialized. Typically this is used to alloc per-port DMA buffers / tables / rings, enable DMA engines, and similar tasks.

->port_stop() is called after ->host_stop(). It's sole function is to release DMA/memory resources, now that they are no longer actively being used.

->host_stop() is called after all ->port_stop() calls have completed. The hook must finalize hardware shutdown, release DMA and other resources, etc.