요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
========================
libATA Developer's Guide
========================
:Author: Jeff Garzik
Introduction
============
libATA is a library used inside the Linux kernel to support ATA host
controllers and devices. libATA provides an ATA driver API, class
transports for ATA and ATAPI devices, and SCSI<->ATA translation for ATA
devices according to the T10 SAT specification.
This Guide documents the libATA driver API, library functions, library
internals, and a couple sample ATA low-level drivers.
libata Driver API
=================
:c:type:`struct ata_port_operations <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.
:c:type:`struct ata_port_operations <ata_port_operations>`
----------------------------------------------------------
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.
This entry may be specified as NULL in ata_port_operations.
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 *);
unsigned int (*mode_filter) (struct ata_port *, struct ata_device *, unsigned int);
Hooks called prior to the issue of SET FEATURES - XFER MODE command. The
optional ``->mode_filter()`` hook is called when libata has built a mask of
the possible modes. This is passed to the ``->mode_filter()`` function
which should return a mask of valid modes after filtering those
unsuitable due to hardware limits. It is not valid to use this interface
to add modes.
``dev->pio_mode`` and ``dev->dma_mode`` are guaranteed to be valid when
``->set_piomode()`` and when ``->set_dmamode()`` is called. The timings for
any other drive sharing the cable will also be valid at this point. That
is the library records the decisions for the modes of each drive on a
channel before it attempts to set any of them.
``->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 (*sff_tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
void (*sff_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. Most drivers for taskfile-based hardware (PIO or MMIO) use
:c:func:`ata_sff_tf_load` and :c:func:`ata_sff_tf_read` for these hooks.
PIO data read/write
~~~~~~~~~~~~~~~~~~~
::
void (*sff_data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
All bmdma-style drivers must implement this hook. This is the low-level
operation that actually copies the data bytes during a PIO data
transfer. Typically the driver will choose one of
:c:func:`ata_sff_data_xfer`, or :c:func:`ata_sff_data_xfer32`.
ATA command execute
~~~~~~~~~~~~~~~~~~~
::
void (*sff_exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
causes an ATA command, previously loaded with ``->tf_load()``, to be
initiated in hardware. Most drivers for taskfile-based hardware use
:c:func:`ata_sff_exec_command` for this hook.
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.
This hook may be specified as NULL, in which case libata will assume
that atapi dma can be supported.
Read specific ATA shadow registers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
u8 (*sff_check_status)(struct ata_port *ap);
u8 (*sff_check_altstatus)(struct ata_port *ap);
Reads the Status/AltStatus ATA shadow register from hardware. On some
hardware, reading the Status register has the side effect of clearing
the interrupt condition. Most drivers for taskfile-based hardware use
:c:func:`ata_sff_check_status` for this hook.
Write specific ATA shadow register
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
void (*sff_set_devctl)(struct ata_port *ap, u8 ctl);
Write the device control ATA shadow register to the hardware. Most
drivers don't need to define this.
Select ATA device on bus
~~~~~~~~~~~~~~~~~~~~~~~~
::
void (*sff_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.
Most drivers for taskfile-based hardware use :c:func:`ata_sff_dev_select` for
this hook.
Private tuning method
~~~~~~~~~~~~~~~~~~~~~
::
void (*set_mode) (struct ata_port *ap);
By default libata performs drive and controller tuning in accordance
with the ATA timing rules and also applies blacklists and cable limits.
Some controllers need special handling and have custom tuning rules,
typically raid controllers that use ATA commands but do not actually do
drive timing.
**Warning**
This hook should not be used to replace the standard controller
tuning logic when a controller has quirks. Replacing the default
tuning logic in that case would bypass handling for drive and bridge
quirks that may be important to data reliability. If a controller
needs to filter the mode selection it should use the mode_filter
hook instead.
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.
Most legacy IDE drivers use :c:func:`ata_bmdma_setup` for the
:c:func:`bmdma_setup` hook. :c:func:`ata_bmdma_setup` will write the pointer
to the PRD table to the IDE PRD Table Address register, enable DMA in the DMA
Command register, and call :c:func:`exec_command` to begin the transfer.
Most legacy IDE drivers use :c:func:`ata_bmdma_start` for the
:c:func:`bmdma_start` hook. :c:func:`ata_bmdma_start` will write the
ATA_DMA_START flag to the DMA Command register.
Many legacy IDE drivers use :c:func:`ata_bmdma_stop` for the
:c:func:`bmdma_stop` hook. :c:func:`ata_bmdma_stop` clears the ATA_DMA_START
flag in the DMA command register.
Many legacy IDE drivers use :c:func:`ata_bmdma_status` as the
:c:func:`bmdma_status` hook.
High-level taskfile hooks
~~~~~~~~~~~~~~~~~~~~~~~~~
::
enum ata_completion_errors (*qc_prep) (struct ata_queued_cmd *qc);
int (*qc_issue) (struct ata_queued_cmd *qc);
Higher-level hooks, these two hooks can potentially supersede 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. Some drivers use the standard
:c:func:`ata_bmdma_qc_prep` and :c:func:`ata_bmdma_dumb_qc_prep` helper
functions, 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
:c:func:`ata_sff_qc_issue` for taskfile protocol-based dispatch. More
advanced drivers implement their own ``->qc_issue``.
:c:func:`ata_sff_qc_issue` calls ``->sff_tf_load()``, ``->bmdma_setup()``, and
``->bmdma_start()`` as necessary to initiate a transfer.
Exception and probe handling (EH)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
void (*freeze) (struct ata_port *ap);
void (*thaw) (struct ata_port *ap);
:c:func:`ata_port_freeze` is called when HSM violations or some other
condition disrupts normal operation of the port. A frozen port is not
allowed to perform any operation until the port is thawed, which usually
follows a successful reset.
The optional ``->freeze()`` callback can be used for freezing the port
hardware-wise (e.g. mask interrupt and stop DMA engine). If a port
cannot be frozen hardware-wise, the interrupt handler must ack and clear
interrupts unconditionally while the port is frozen.
The optional ``->thaw()`` callback is called to perform the opposite of
``->freeze()``: prepare the port for normal operation once again. Unmask
interrupts, start DMA engine, etc.
::
void (*error_handler) (struct ata_port *ap);
``->error_handler()`` is a driver's hook into probe, hotplug, and recovery
and other exceptional conditions. The primary responsibility of an
implementation is to call :c:func:`ata_std_error_handler`.
:c:func:`ata_std_error_handler` will perform a standard error handling sequence
to resurect failed devices, detach lost devices and add new devices (if any).
This function will call the various reset operations for a port, as needed.
These operations are as follows.
* The 'prereset' operation (which may be NULL) is called during an EH reset,
before any other action is taken.
* The 'postreset' hook (which may be NULL) is called after the EH reset is
performed. Based on existing conditions, severity of the problem, and hardware
capabilities,
* Either the 'softreset' operation or the 'hardreset' operation will be called
to perform the low-level EH reset. If both operations are defined,
'hardreset' is preferred and used. If both are not defined, no low-level reset
is performed and EH assumes that an ATA class device is connected through the
link.
::
void (*post_internal_cmd) (struct ata_queued_cmd *qc);
Perform any hardware-specific actions necessary to finish processing
after executing a probe-time or EH-time command via
:c:func:`ata_exec_internal`.
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.
The second argument, dev_instance, should be cast to a pointer to
:c:type:`struct ata_host_set <ata_host_set>`.
Most legacy IDE drivers use :c:func:`ata_sff_interrupt` for the irq_handler
hook, which scans all ports in the host_set, determines which queued
command was active (if any), and calls ata_sff_host_intr(ap,qc).
Most legacy IDE drivers use :c:func:`ata_sff_irq_clear` for the
:c:func:`irq_clear` hook, which simply clears the interrupt and error flags
in the DMA status register.
SATA phy read/write
~~~~~~~~~~~~~~~~~~~
::
int (*scr_read) (struct ata_port *ap, unsigned int sc_reg,
u32 *val);
int (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
Read and write standard SATA phy registers.
sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE.
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. Some drivers also
use this entry point as a chance to allocate driver-private memory for
``ap->private_data``.
Many drivers use :c:func:`ata_port_start` as this hook or call it from their
own :c:func:`port_start` hooks. :c:func:`ata_port_start` allocates space for
a legacy IDE PRD table and returns.
``->port_stop()`` is called after ``->host_stop()``. Its sole function is to
release DMA/memory resources, now that they are no longer actively being
used. Many drivers also free driver-private data from port at this time.
``->host_stop()`` is called after all ``->port_stop()`` calls have completed.
The hook must finalize hardware shutdown, release DMA and other
resources, etc. This hook may be specified as NULL, in which case it is
not called.
Error handling
==============
This chapter describes how errors are handled under libata. Readers are
advised to read SCSI EH (Documentation/scsi/scsi_eh.rst) and ATA
exceptions doc first.
Origins of commands
-------------------
In libata, a command is represented with
:c:type:`struct ata_queued_cmd <ata_queued_cmd>` or qc.
qc's are preallocated during port initialization and repetitively used
for command executions. Currently only one qc is allocated per port but
yet-to-be-merged NCQ branch allocates one for each tag and maps each qc
to NCQ tag 1-to-1.
libata commands can originate from two sources - libata itself and SCSI
midlayer. libata internal commands are used for initialization and error
handling. All normal blk requests and commands for SCSI emulation are
passed as SCSI commands through queuecommand callback of SCSI host
template.
How commands are issued
-----------------------
Internal commands
Once allocated qc's taskfile is initialized for the command to be
executed. qc currently has two mechanisms to notify completion. One
is via ``qc->complete_fn()`` callback and the other is completion
``qc->waiting``. ``qc->complete_fn()`` callback is the asynchronous path
used by normal SCSI translated commands and ``qc->waiting`` is the
synchronous (issuer sleeps in process context) path used by internal
commands.
Once initialization is complete, host_set lock is acquired and the
qc is issued.
SCSI commands
All libata drivers use :c:func:`ata_scsi_queuecmd` as
``hostt->queuecommand`` callback. scmds can either be simulated or
translated. No qc is involved in processing a simulated scmd. The
result is computed right away and the scmd is completed.
``qc->complete_fn()`` callback is used for completion notification. ATA
commands use :c:func:`ata_scsi_qc_complete` while ATAPI commands use
:c:func:`atapi_qc_complete`. Both functions end up calling ``qc->scsidone``
to notify upper layer when the qc is finished. After translation is
completed, the qc is issued with :c:func:`ata_qc_issue`.
Note that SCSI midlayer invokes hostt->queuecommand while holding
host_set lock, so all above occur while holding host_set lock.
How commands are processed
--------------------------
Depending on which protocol and which controller are used, commands are
processed differently. For the purpose of discussion, a controller which
uses taskfile interface and all standard callbacks is assumed.
Currently 6 ATA command protocols are used. They can be sorted into the
following four categories according to how they are processed.
ATA NO DATA or DMA
ATA_PROT_NODATA and ATA_PROT_DMA fall into this category. These
types of commands don't require any software intervention once
issued. Device will raise interrupt on completion.
ATA PIO
ATA_PROT_PIO is in this category. libata currently implements PIO
with polling. ATA_NIEN bit is set to turn off interrupt and
pio_task on ata_wq performs polling and IO.
ATAPI NODATA or DMA
ATA_PROT_ATAPI_NODATA and ATA_PROT_ATAPI_DMA are in this
category. packet_task is used to poll BSY bit after issuing PACKET
command. Once BSY is turned off by the device, packet_task
transfers CDB and hands off processing to interrupt handler.
ATAPI PIO
ATA_PROT_ATAPI is in this category. ATA_NIEN bit is set and, as
in ATAPI NODATA or DMA, packet_task submits cdb. However, after
submitting cdb, further processing (data transfer) is handed off to
pio_task.
How commands are completed
--------------------------
Once issued, all qc's are either completed with :c:func:`ata_qc_complete` or
time out. For commands which are handled by interrupts,
:c:func:`ata_host_intr` invokes :c:func:`ata_qc_complete`, and, for PIO tasks,
pio_task invokes :c:func:`ata_qc_complete`. In error cases, packet_task may
also complete commands.
:c:func:`ata_qc_complete` does the following.
1. DMA memory is unmapped.
2. ATA_QCFLAG_ACTIVE is cleared from qc->flags.
3. :c:expr:`qc->complete_fn` callback is invoked. If the return value of the
callback is not zero. Completion is short circuited and
:c:func:`ata_qc_complete` returns.
4. :c:func:`__ata_qc_complete` is called, which does
1. ``qc->flags`` is cleared to zero.
2. ``ap->active_tag`` and ``qc->tag`` are poisoned.
3. ``qc->waiting`` is cleared & completed (in that order).
4. qc is deallocated by clearing appropriate bit in ``ap->qactive``.
So, it basically notifies upper layer and deallocates qc. One exception
is short-circuit path in #3 which is used by :c:func:`atapi_qc_complete`.
For all non-ATAPI commands, whether it fails or not, almost the same
code path is taken and very little error handling takes place. A qc is
completed with success status if it succeeded, with failed status
otherwise.
However, failed ATAPI commands require more handling as REQUEST SENSE is
needed to acquire sense data. If an ATAPI command fails,
:c:func:`ata_qc_complete` is invoked with error status, which in turn invokes
:c:func:`atapi_qc_complete` via ``qc->complete_fn()`` callback.
This makes :c:func:`atapi_qc_complete` set ``scmd->result`` to
SAM_STAT_CHECK_CONDITION, complete the scmd and return 1. As the
sense data is empty but ``scmd->result`` is CHECK CONDITION, SCSI midlayer
will invoke EH for the scmd, and returning 1 makes :c:func:`ata_qc_complete`
to return without deallocating the qc. This leads us to
:c:func:`ata_scsi_error` with partially completed qc.
:c:func:`ata_scsi_error`
------------------------
:c:func:`ata_scsi_error` is the current ``transportt->eh_strategy_handler()``
for libata. As discussed above, this will be entered in two cases -
timeout and ATAPI error completion. This function will check if a qc is active
and has not failed yet. Such a qc will be marked with AC_ERR_TIMEOUT such that
EH will know to handle it later. Then it calls low level libata driver's
:c:func:`error_handler` callback.
When the :c:func:`error_handler` callback is invoked it stops BMDMA and
completes the qc. Note that as we're currently in EH, we cannot call
scsi_done. As described in SCSI EH doc, a recovered scmd should be
either retried with :c:func:`scsi_queue_insert` or finished with
:c:func:`scsi_finish_command`. Here, we override ``qc->scsidone`` with
:c:func:`scsi_finish_command` and calls :c:func:`ata_qc_complete`.
If EH is invoked due to a failed ATAPI qc, the qc here is completed but
not deallocated. The purpose of this half-completion is to use the qc as
place holder to make EH code reach this place. This is a bit hackish,
but it works.
Once control reaches here, the qc is deallocated by invoking
:c:func:`__ata_qc_complete` explicitly. Then, internal qc for REQUEST SENSE
is issued. Once sense data is acquired, scmd is finished by directly
invoking :c:func:`scsi_finish_command` on the scmd. Note that as we already
have completed and deallocated the qc which was associated with the
scmd, we don't need to/cannot call :c:func:`ata_qc_complete` again.
Problems with the current EH
----------------------------
- Error representation is too crude. Currently any and all error
conditions are represented with ATA STATUS and ERROR registers.
Errors which aren't ATA device errors are treated as ATA device
errors by setting ATA_ERR bit. Better error descriptor which can
properly represent ATA and other errors/exceptions is needed.
- When handling timeouts, no action is taken to make device forget
about the timed out command and ready for new commands.
- EH handling via :c:func:`ata_scsi_error` is not properly protected from
usual command processing. On EH entrance, the device is not in
quiescent state. Timed out commands may succeed or fail any time.
pio_task and atapi_task may still be running.
- Too weak error recovery. Devices / controllers causing HSM mismatch
errors and other errors quite often require reset to return to known
state. Also, advanced error handling is necessary to support features
like NCQ and hotplug.
- ATA errors are directly handled in the interrupt handler and PIO
errors in pio_task. This is problematic for advanced error handling
for the following reasons.
First, advanced error handling often requires context and internal qc
execution.
Second, even a simple failure (say, CRC error) needs information
gathering and could trigger complex error handling (say, resetting &
reconfiguring). Having multiple code paths to gather information,
enter EH and trigger actions makes life painful.
Third, scattered EH code makes implementing low level drivers
difficult. Low level drivers override libata callbacks. If EH is
scattered over several places, each affected callbacks should perform
its part of error handling. This can be error prone and painful.
libata Library
==============
.. kernel-doc:: drivers/ata/libata-core.c
:export:
libata Core Internals
=====================
.. kernel-doc:: drivers/ata/libata-core.c
:internal:
.. kernel-doc:: drivers/ata/libata-eh.c
libata SCSI translation/emulation
=================================
.. kernel-doc:: drivers/ata/libata-scsi.c
:export:
.. kernel-doc:: drivers/ata/libata-scsi.c
:internal:
ATA errors and exceptions
=========================
This chapter tries to identify what error/exception conditions exist for
ATA/ATAPI devices and describe how they should be handled in
implementation-neutral way.
The term 'error' is used to describe conditions where either an explicit
error condition is reported from device or a command has timed out.
The term 'exception' is either used to describe exceptional conditions
which are not errors (say, power or hotplug events), or to describe both
errors and non-error exceptional conditions. Where explicit distinction
between error and exception is necessary, the term 'non-error exception'
is used.
Exception categories
--------------------
Exceptions are described primarily with respect to legacy taskfile + bus
master IDE interface. If a controller provides other better mechanism
for error reporting, mapping those into categories described below
shouldn't be difficult.
In the following sections, two recovery actions - reset and
reconfiguring transport - are mentioned. These are described further in
`EH recovery actions <#exrec>`__.
HSM violation
~~~~~~~~~~~~~
This error is indicated when STATUS value doesn't match HSM requirement
during issuing or execution any ATA/ATAPI command.
- ATA_STATUS doesn't contain !BSY && DRDY && !DRQ while trying to
issue a command.
- !BSY && !DRQ during PIO data transfer.
- DRQ on command completion.
- !BSY && ERR after CDB transfer starts but before the last byte of CDB
is transferred. ATA/ATAPI standard states that "The device shall not
terminate the PACKET command with an error before the last byte of
the command packet has been written" in the error outputs description
of PACKET command and the state diagram doesn't include such
transitions.
In these cases, HSM is violated and not much information regarding the
error can be acquired from STATUS or ERROR register. IOW, this error can
be anything - driver bug, faulty device, controller and/or cable.
As HSM is violated, reset is necessary to restore known state.
Reconfiguring transport for lower speed might be helpful too as
transmission errors sometimes cause this kind of errors.
ATA/ATAPI device error (non-NCQ / non-CHECK CONDITION)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These are errors detected and reported by ATA/ATAPI devices indicating
device problems. For this type of errors, STATUS and ERROR register
values are valid and describe error condition. Note that some of ATA bus
errors are detected by ATA/ATAPI devices and reported using the same
mechanism as device errors. Those cases are described later in this
section.
For ATA commands, this type of errors are indicated by !BSY && ERR
during command execution and on completion.
For ATAPI commands,
- !BSY && ERR && ABRT right after issuing PACKET indicates that PACKET
command is not supported and falls in this category.
- !BSY && ERR(==CHK) && !ABRT after the last byte of CDB is transferred
indicates CHECK CONDITION and doesn't fall in this category.
- !BSY && ERR(==CHK) && ABRT after the last byte of CDB is transferred
\*probably\* indicates CHECK CONDITION and doesn't fall in this
category.
Of errors detected as above, the following are not ATA/ATAPI device
errors but ATA bus errors and should be handled according to
`ATA bus error <#excatATAbusErr>`__.
CRC error during data transfer
This is indicated by ICRC bit in the ERROR register and means that
corruption occurred during data transfer. Up to ATA/ATAPI-7, the
standard specifies that this bit is only applicable to UDMA
transfers but ATA/ATAPI-8 draft revision 1f says that the bit may be
applicable to multiword DMA and PIO.
ABRT error during data transfer or on completion
Up to ATA/ATAPI-7, the standard specifies that ABRT could be set on
ICRC errors and on cases where a device is not able to complete a
command. Combined with the fact that MWDMA and PIO transfer errors
aren't allowed to use ICRC bit up to ATA/ATAPI-7, it seems to imply
that ABRT bit alone could indicate transfer errors.
However, ATA/ATAPI-8 draft revision 1f removes the part that ICRC
errors can turn on ABRT. So, this is kind of gray area. Some
heuristics are needed here.
ATA/ATAPI device errors can be further categorized as follows.
Media errors
This is indicated by UNC bit in the ERROR register. ATA devices
reports UNC error only after certain number of retries cannot
recover the data, so there's nothing much else to do other than
notifying upper layer.
READ and WRITE commands report CHS or LBA of the first failed sector
but ATA/ATAPI standard specifies that the amount of transferred data
on error completion is indeterminate, so we cannot assume that
sectors preceding the failed sector have been transferred and thus
cannot complete those sectors successfully as SCSI does.
Media changed / media change requested error
<<TODO: fill here>>
Address error
This is indicated by IDNF bit in the ERROR register. Report to upper
layer.
Other errors
This can be invalid command or parameter indicated by ABRT ERROR bit
or some other error condition. Note that ABRT bit can indicate a lot
of things including ICRC and Address errors. Heuristics needed.
Depending on commands, not all STATUS/ERROR bits are applicable. These
non-applicable bits are marked with "na" in the output descriptions but
up to ATA/ATAPI-7 no definition of "na" can be found. However,
ATA/ATAPI-8 draft revision 1f describes "N/A" as follows.
3.2.3.3a N/A
A keyword the indicates a field has no defined value in this
standard and should not be checked by the host or device. N/A
fields should be cleared to zero.
So, it seems reasonable to assume that "na" bits are cleared to zero by
devices and thus need no explicit masking.
ATAPI device CHECK CONDITION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ATAPI device CHECK CONDITION error is indicated by set CHK bit (ERR bit)
in the STATUS register after the last byte of CDB is transferred for a
PACKET command. For this kind of errors, sense data should be acquired
to gather information regarding the errors. REQUEST SENSE packet command
should be used to acquire sense data.
Once sense data is acquired, this type of errors can be handled
similarly to other SCSI errors. Note that sense data may indicate ATA
bus error (e.g. Sense Key 04h HARDWARE ERROR && ASC/ASCQ 47h/00h SCSI
PARITY ERROR). In such cases, the error should be considered as an ATA
bus error and handled according to `ATA bus error <#excatATAbusErr>`__.
ATA device error (NCQ)
~~~~~~~~~~~~~~~~~~~~~~
NCQ command error is indicated by cleared BSY and set ERR bit during NCQ
command phase (one or more NCQ commands outstanding). Although STATUS
and ERROR registers will contain valid values describing the error, READ
LOG EXT is required to clear the error condition, determine which
command has failed and acquire more information.
READ LOG EXT Log Page 10h reports which tag has failed and taskfile
register values describing the error. With this information the failed
command can be handled as a normal ATA command error as in
`ATA/ATAPI device error (non-NCQ / non-CHECK CONDITION) <#excatDevErr>`__
and all other in-flight commands must be retried. Note that this retry
should not be counted - it's likely that commands retried this way would
have completed normally if it were not for the failed command.
Note that ATA bus errors can be reported as ATA device NCQ errors. This
should be handled as described in `ATA bus error <#excatATAbusErr>`__.
If READ LOG EXT Log Page 10h fails or reports NQ, we're thoroughly
screwed. This condition should be treated according to
`HSM violation <#excatHSMviolation>`__.
ATA bus error
~~~~~~~~~~~~~
ATA bus error means that data corruption occurred during transmission
over ATA bus (SATA or PATA). This type of errors can be indicated by
- ICRC or ABRT error as described in
`ATA/ATAPI device error (non-NCQ / non-CHECK CONDITION) <#excatDevErr>`__.
- Controller-specific error completion with error information
indicating transmission error.
- On some controllers, command timeout. In this case, there may be a
mechanism to determine that the timeout is due to transmission error.
- Unknown/random errors, timeouts and all sorts of weirdities.
As described above, transmission errors can cause wide variety of
symptoms ranging from device ICRC error to random device lockup, and,
for many cases, there is no way to tell if an error condition is due to
transmission error or not; therefore, it's necessary to employ some kind
of heuristic when dealing with errors and timeouts. For example,
encountering repetitive ABRT errors for known supported command is
likely to indicate ATA bus error.
Once it's determined that ATA bus errors have possibly occurred,
lowering ATA bus transmission speed is one of actions which may
alleviate the problem. See `Reconfigure transport <#exrecReconf>`__ for
more information.
PCI bus error
~~~~~~~~~~~~~
Data corruption or other failures during transmission over PCI (or other
system bus). For standard BMDMA, this is indicated by Error bit in the
BMDMA Status register. This type of errors must be logged as it
indicates something is very wrong with the system. Resetting host
controller is recommended.
Late completion
~~~~~~~~~~~~~~~
This occurs when timeout occurs and the timeout handler finds out that
the timed out command has completed successfully or with error. This is
usually caused by lost interrupts. This type of errors must be logged.
Resetting host controller is recommended.
Unknown error (timeout)
~~~~~~~~~~~~~~~~~~~~~~~
This is when timeout occurs and the command is still processing or the
host and device are in unknown state. When this occurs, HSM could be in
any valid or invalid state. To bring the device to known state and make
it forget about the timed out command, resetting is necessary. The timed
out command may be retried.
Timeouts can also be caused by transmission errors. Refer to
`ATA bus error <#excatATAbusErr>`__ for more details.
Hotplug and power management exceptions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<<TODO: fill here>>
EH recovery actions
-------------------
This section discusses several important recovery actions.
Clearing error condition
~~~~~~~~~~~~~~~~~~~~~~~~
Many controllers require its error registers to be cleared by error
handler. Different controllers may have different requirements.
For SATA, it's strongly recommended to clear at least SError register
during error handling.
Reset
~~~~~
During EH, resetting is necessary in the following cases.
- HSM is in unknown or invalid state
- HBA is in unknown or invalid state
- EH needs to make HBA/device forget about in-flight commands
- HBA/device behaves weirdly
Resetting during EH might be a good idea regardless of error condition
to improve EH robustness. Whether to reset both or either one of HBA and
device depends on situation but the following scheme is recommended.
- When it's known that HBA is in ready state but ATA/ATAPI device is in
unknown state, reset only device.
- If HBA is in unknown state, reset both HBA and device.
HBA resetting is implementation specific. For a controller complying to
taskfile/BMDMA PCI IDE, stopping active DMA transaction may be
sufficient iff BMDMA state is the only HBA context. But even mostly
taskfile/BMDMA PCI IDE complying controllers may have implementation
specific requirements and mechanism to reset themselves. This must be
addressed by specific drivers.
OTOH, ATA/ATAPI standard describes in detail ways to reset ATA/ATAPI
devices.
PATA hardware reset
This is hardware initiated device reset signalled with asserted PATA
RESET- signal. There is no standard way to initiate hardware reset
from software although some hardware provides registers that allow
driver to directly tweak the RESET- signal.
Software reset
This is achieved by turning CONTROL SRST bit on for at least 5us.
Both PATA and SATA support it but, in case of SATA, this may require
controller-specific support as the second Register FIS to clear SRST
should be transmitted while BSY bit is still set. Note that on PATA,
this resets both master and slave devices on a channel.
EXECUTE DEVICE DIAGNOSTIC command
Although ATA/ATAPI standard doesn't describe exactly, EDD implies
some level of resetting, possibly similar level with software reset.
Host-side EDD protocol can be handled with normal command processing
and most SATA controllers should be able to handle EDD's just like
other commands. As in software reset, EDD affects both devices on a
PATA bus.
Although EDD does reset devices, this doesn't suit error handling as
EDD cannot be issued while BSY is set and it's unclear how it will
act when device is in unknown/weird state.
ATAPI DEVICE RESET command
This is very similar to software reset except that reset can be
restricted to the selected device without affecting the other device
sharing the cable.
SATA phy reset
This is the preferred way of resetting a SATA device. In effect,
it's identical to PATA hardware reset. Note that this can be done
with the standard SCR Control register. As such, it's usually easier
to implement than software reset.
One more thing to consider when resetting devices is that resetting
clears certain configuration parameters and they need to be set to their
previous or newly adjusted values after reset.
Parameters affected are.
- CHS set up with INITIALIZE DEVICE PARAMETERS (seldom used)
- Parameters set with SET FEATURES including transfer mode setting
- Block count set with SET MULTIPLE MODE
- Other parameters (SET MAX, MEDIA LOCK...)
ATA/ATAPI standard specifies that some parameters must be maintained
across hardware or software reset, but doesn't strictly specify all of
them. Always reconfiguring needed parameters after reset is required for
robustness. Note that this also applies when resuming from deep sleep
(power-off).
Also, ATA/ATAPI standard requires that IDENTIFY DEVICE / IDENTIFY PACKET
DEVICE is issued after any configuration parameter is updated or a
hardware reset and the result used for further operation. OS driver is
required to implement revalidation mechanism to support this.
Reconfigure transport
~~~~~~~~~~~~~~~~~~~~~
For both PATA and SATA, a lot of corners are cut for cheap connectors,
cables or controllers and it's quite common to see high transmission
error rate. This can be mitigated by lowering transmission speed.
The following is a possible scheme Jeff Garzik suggested.
If more than $N (3?) transmission errors happen in 15 minutes,
- if SATA, decrease SATA PHY speed. if speed cannot be decreased,
- decrease UDMA xfer speed. if at UDMA0, switch to PIO4,
- decrease PIO xfer speed. if at PIO3, complain, but continue
ata_piix Internals
===================
.. kernel-doc:: drivers/ata/ata_piix.c
:internal:
sata_sil Internals
===================
.. kernel-doc:: drivers/ata/sata_sil.c
:internal:
Thanks
======
The bulk of the ATA knowledge comes thanks to long conversations with
Andre Hedrick (www.linux-ide.org), and long hours pondering the ATA and
SCSI specifications.
Thanks to Alan Cox for pointing out similarities between SATA and SCSI,
and in general for motivation to hack on libata.
libata's device detection method, ata_pio_devchk, and in general all
the early probing was based on extensive study of Hale Landis's
probe/reset code in his ATADRVR driver (www.ata-atapi.com).
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
libATA Developer's Guide 소개
1-17문서 제목은 `libATA Developer's Guide`이며 저자는 Jeff Garzik입니다. libATA는 Linux kernel 안에서 ATA host controller와 device를 지원하는 library입니다.
libATA는 ATA driver API, ATA·ATAPI device용 class transport, T10 SAT specification에 따른 SCSI와 ATA 사이 translation을 제공합니다. 이 guide는 driver API, library function과 내부 구조, 두 low-level ATA driver example을 설명합니다.
SCSI request와 ATA hardware 사이의 주요 계층입니다.
ata_port_operations 개요
18-34모든 low-level libATA hardware driver는 `struct ata_port_operations`를 정의합니다. 이 structure가 low-level driver와 ATA·SCSI layer의 연결 방식을 제어합니다.
FIS 기반 driver는 high-level `->qc_prep()`과 `->qc_issue()` hook으로 system에 연결합니다. PCI IDE와 비슷한 hardware는 여러 generic helper를 사용할 수 있으며 최소한 ATA shadow register block의 bus I/O address를 정의합니다.
Controller model에 따른 최소 hook 집합입니다.
Post-IDENTIFY device configuration
35-48void (*dev_config) (struct ata_port *, struct ata_device *);
`->dev_config()`는 발견한 각 device에 `IDENTIFY DEVICE` 또는 `IDENTIFY PACKET DEVICE`를 보낸 뒤 호출합니다. 일반적으로 `SET FEATURES - XFER MODE`를 보내기 전, 실제 operation을 시작하기 전에 device-specific fixup을 적용합니다. `ata_port_operations`에서 `NULL`로 둘 수 있습니다.
IDENTIFY 이후 transfer mode 설정 전의 fixup 단계입니다.
PIO·DMA mode 설정
49-78void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (struct ata_port *, struct ata_device *);
void (*post_set_mode) (struct ata_port *);
unsigned int (*mode_filter) (struct ata_port *, struct ata_device *, unsigned int);
이 hook들은 `SET FEATURES - XFER MODE` command를 보내기 전에 호출됩니다. Optional `->mode_filter()`는 libATA가 만든 가능한 mode mask를 받아 hardware limit에 맞지 않는 mode를 제거한 valid mask를 반환합니다. 이 interface로 mode를 추가하는 것은 허용되지 않습니다.
`->set_piomode()`와 `->set_dmamode()` 호출 시 `dev->pio_mode`와 `dev->dma_mode`는 valid합니다. 같은 cable을 공유하는 다른 drive의 timing도 valid합니다. Library가 channel의 모든 drive에 대한 mode 결정을 기록한 뒤 실제 설정을 시작하기 때문입니다.
`->post_set_mode()`는 `SET FEATURES - XFER MODE`가 성공한 뒤 조건 없이 호출됩니다. `->set_piomode()`는 hook이 있으면 항상 호출하지만 `->set_dmamode()`는 DMA가 가능할 때만 호출합니다.
가능 mode를 줄인 뒤 channel 전체 timing을 확정합니다.
각 callback의 호출 조건입니다.
Taskfile·PIO data·command 실행
79-118void (*sff_tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
void (*sff_tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
`->sff_tf_load()`는 taskfile을 hardware register 또는 DMA buffer에 넣고 `->sff_tf_read()`는 현재 taskfile register 값을 읽습니다. PIO·MMIO taskfile hardware driver 대부분은 `ata_sff_tf_load()`와 `ata_sff_tf_read()`를 사용합니다.
void (*sff_data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
모든 BMDMA-style driver는 `->sff_data_xfer()`를 구현해야 합니다. PIO data transfer 중 실제 data byte를 copy하는 low-level operation이며 보통 `ata_sff_data_xfer()` 또는 `ata_sff_data_xfer32()`를 선택합니다.
void (*sff_exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
`->sff_exec_command()`는 앞서 `->tf_load()`한 ATA command를 hardware에서 시작합니다. Taskfile 기반 driver 대부분은 `ata_sff_exec_command()` helper를 사용합니다.
Taskfile 준비에서 PIO data transfer까지의 low-level 순서입니다.
ATAPI DMA·shadow register·device select
119-173int (*check_atapi_dma) (struct ata_queued_cmd *qc);
`->check_atapi_dma()`는 개별 ATA PACKET command가 DMA를 사용해도 되는지 low-level driver가 filter하게 합니다. `NULL`이면 libATA는 ATAPI DMA를 지원할 수 있다고 가정합니다.
u8 (*sff_check_status)(struct ata_port *ap);
u8 (*sff_check_altstatus)(struct ata_port *ap);
`->sff_check_status()`와 `->sff_check_altstatus()`는 hardware의 Status·AltStatus shadow register를 읽습니다. 일부 hardware에서는 Status read가 interrupt condition을 clear하는 side effect가 있습니다. Taskfile driver 대부분은 `ata_sff_check_status()`를 사용합니다.
void (*sff_set_devctl)(struct ata_port *ap, u8 ctl);
`->sff_set_devctl()`은 Device Control ATA shadow register를 씁니다. Driver 대부분은 별도 구현이 필요 없습니다.
void (*sff_dev_select)(struct ata_port *ap, unsigned int device);
`->sff_dev_select()`는 ATA bus에서 N개 hardware device 중 하나를 active device로 선택하는 low-level command를 냅니다. FIS 기반 device에는 일반적으로 의미가 없고 taskfile driver는 보통 `ata_sff_dev_select()`를 사용합니다.
Optional filtering과 register side effect를 정리했습니다.
Command별 DMA capability를 결정합니다.
Private tuning method
174-196void (*set_mode) (struct ata_port *ap);
기본적으로 libATA는 ATA timing rule에 따라 drive와 controller를 tuning하고 blacklist와 cable limit도 적용합니다. 실제 drive timing을 다루지 않는 일부 RAID controller처럼 custom rule이 필요한 controller는 `->set_mode()`를 사용할 수 있습니다.
Controller quirk 때문에 standard tuning logic 전체를 이 hook으로 대체하면 안 됩니다. 그렇게 하면 data reliability에 중요한 drive·bridge quirk 처리를 우회합니다. Mode selection을 제한해야 한다면 `mode_filter` hook을 사용해야 합니다.
Standard logic 보존이 필요한 이유입니다.
PCI IDE BMDMA engine 제어
197-231void (*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);
IDE BMDMA transaction에서 `->bmdma_setup()`은 DMA engine을 arm하고 `->bmdma_start()`는 시작하며 `->bmdma_stop()`은 멈춥니다. `->bmdma_status()`는 standard PCI IDE DMA Status register를 읽습니다. FIS driver에서는 대개 no-op이거나 구현하지 않습니다.
Legacy IDE driver의 `ata_bmdma_setup()`은 PRD table pointer를 IDE PRD Table Address register에 쓰고 DMA Command register에서 DMA를 enable한 뒤 `exec_command()`를 호출합니다. `ata_bmdma_start()`는 `ATA_DMA_START`를 set하고 `ata_bmdma_stop()`은 clear합니다. Status hook에는 `ata_bmdma_status()`를 흔히 사용합니다.
PRD 준비에서 engine stop까지의 generic helper 동작입니다.
High-level queued-command hook
232-255enum ata_completion_errors (*qc_prep) (struct ata_queued_cmd *qc);
int (*qc_issue) (struct ata_queued_cmd *qc);
`->qc_prep()`과 `->qc_issue()`는 여러 taskfile·DMA engine hook을 대체할 수 있는 high-level hook입니다. DMA mapping 뒤 호출되는 `->qc_prep()`은 hardware scatter-gather table을 채우는 데 주로 쓰입니다. 일부 driver는 `ata_bmdma_qc_prep()` 또는 `ata_bmdma_dumb_qc_prep()`을 쓰고 advanced driver는 자체 구현합니다.
Hardware와 S/G table 준비가 끝나면 `->qc_issue()`가 command를 active로 만듭니다. IDE BMDMA driver는 taskfile protocol dispatch에 `ata_sff_qc_issue()`를 사용하며 이 helper가 필요에 따라 `->sff_tf_load()`, `->bmdma_setup()`, `->bmdma_start()`를 호출합니다.
High-level hook과 generic SFF helper의 관계입니다.
Exception·probe handling
256-314void (*freeze) (struct ata_port *ap);
void (*thaw) (struct ata_port *ap);
HSM violation 등으로 port normal operation이 깨지면 `ata_port_freeze()`가 port를 freeze합니다. Frozen port는 보통 successful reset 뒤 thaw될 때까지 operation을 수행할 수 없습니다. Optional `->freeze()`는 interrupt masking·DMA stop 같은 hardware freeze를 수행합니다. Hardware freeze가 불가능하면 frozen 동안 interrupt handler가 interrupt를 무조건 ack·clear해야 합니다. `->thaw()`는 interrupt unmask와 DMA restart로 normal operation을 복구합니다.
void (*error_handler) (struct ata_port *ap);
`->error_handler()`는 probe, hotplug, recovery와 다른 exceptional condition에 대한 driver hook이며 구현의 핵심 책임은 `ata_std_error_handler()` 호출입니다. Standard handler는 failed device를 되살리고 lost device를 detach하며 new device를 추가하고 필요에 따라 reset operation을 호출합니다.
Reset sequence에서 optional `prereset`은 다른 action 전에, optional `postreset`은 reset 뒤 호출됩니다. Severity와 hardware capability에 따라 `softreset` 또는 `hardreset`을 호출하며 둘 다 있으면 `hardreset`을 선호합니다. 둘 다 없으면 low-level reset 없이 ATA class device가 link에 연결된 것으로 가정합니다.
void (*post_internal_cmd) (struct ata_queued_cmd *qc);
`->post_internal_cmd()`는 probe-time 또는 EH-time에 `ata_exec_internal()`로 command를 실행한 뒤 필요한 hardware-specific 마무리를 수행합니다.
Disruption에서 standard EH를 거쳐 thaw하기까지입니다.
Optional callback과 reset 우선순위입니다.
Interrupt·SATA PHY·lifecycle
315-381irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
void (*irq_clear) (struct ata_port *);
`->irq_handler`는 libATA가 system에 등록하는 interrupt routine이고 `->irq_clear`는 handler 등록 직전 probe 중 hardware를 quiet하게 만들기 위해 호출합니다. 두 번째 argument `dev_instance`는 `struct ata_host_set *`로 cast합니다.
Legacy IDE driver는 보통 `ata_sff_interrupt()`로 host_set의 모든 port를 scan해 active qc를 찾고 `ata_sff_host_intr(ap, qc)`를 호출합니다. `ata_sff_irq_clear()`는 DMA status register의 interrupt와 error flag를 clear합니다.
int (*scr_read) (struct ata_port *ap, unsigned int sc_reg,
u32 *val);
int (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
`->scr_read()`와 `->scr_write()`는 `SCR_STATUS`, `SCR_CONTROL`, `SCR_ERROR`, `SCR_ACTIVE` 같은 standard SATA PHY register를 읽고 씁니다.
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()`는 port data structure 초기화 직후 호출되어 per-port DMA buffer·table·ring을 allocate하고 DMA engine을 enable합니다. `ap->private_data`용 memory도 이때 allocate할 수 있습니다. `ata_port_start()`는 legacy IDE PRD table 공간을 allocate합니다.
Shutdown 때 모든 `->port_stop()` 뒤 `->host_stop()`이 호출된다고 적힌 원문과 callback 설명의 ordering을 함께 따라야 합니다. `->port_stop()`은 active use가 끝난 DMA·memory와 private data를 release하고, `->host_stop()`은 hardware shutdown과 host-level DMA resource release를 마무리하며 `NULL`일 수 있습니다.
Interrupt와 SATA PHY register 역할입니다.
Initialization과 shutdown의 resource ownership입니다.
Error handling과 command origin
382-404이 장은 libATA error handling을 설명합니다. 먼저 `Documentation/scsi/scsi_eh.rst`의 SCSI EH와 ATA exception 문서를 읽는 것이 권장됩니다.
libATA command는 `struct ata_queued_cmd`, 줄여서 qc로 표현합니다. Qc는 port initialization 때 미리 allocate되어 반복 사용됩니다. 원문 작성 당시 port당 하나였고 향후 NCQ branch는 tag마다 하나를 allocate해 qc와 NCQ tag를 1:1로 mapping하는 model을 설명합니다.
Command source는 libATA 자체와 SCSI midlayer 두 가지입니다. Internal command는 initialization과 error handling에 쓰고, normal block request와 SCSI emulation command는 SCSI host template의 `queuecommand` callback을 통해 SCSI command로 전달됩니다.
Internal command와 SCSI request가 qc execution으로 모입니다.
Command 발행
405-434Internal command는 allocate한 qc의 taskfile을 초기화합니다. Completion notification은 asynchronous `qc->complete_fn()` callback과 issuer가 process context에서 sleep하는 synchronous completion `qc->waiting` 두 방식입니다. 초기화 뒤 `host_set` lock을 잡고 qc를 발행합니다.
모든 libATA driver는 `ata_scsi_queuecmd()`를 `hostt->queuecommand` callback으로 사용합니다. Simulated SCSI command는 qc 없이 즉시 result를 계산해 완료하고, translated command는 qc를 사용합니다.
ATA command completion에는 `ata_scsi_qc_complete()`, ATAPI에는 `atapi_qc_complete()`를 `qc->complete_fn()`으로 사용합니다. 둘 다 끝에서 `qc->scsidone`을 호출해 upper layer에 알립니다. Translation이 끝나면 `ata_qc_issue()`로 qc를 발행합니다. SCSI midlayer가 `hostt->queuecommand` 호출 때 `host_set` lock을 잡고 있으므로 이 과정 전체가 lock 안에서 일어납니다.
Source와 protocol에 따른 callback입니다.
Command protocol 처리
435-466Protocol과 controller에 따라 처리 방식이 다릅니다. 문서는 taskfile interface와 standard callback을 사용하는 controller를 가정하고 6개 ATA protocol을 네 category로 묶습니다.
`ATA_PROT_NODATA`와 `ATA_PROT_DMA`는 issue 뒤 software intervention이 필요 없고 완료 시 device가 interrupt를 올립니다. `ATA_PROT_PIO`는 `ATA_NIEN`으로 interrupt를 끄고 `ata_wq`의 `pio_task`가 polling과 I/O를 수행합니다.
`ATA_PROT_ATAPI_NODATA`와 `ATA_PROT_ATAPI_DMA`는 PACKET command 뒤 `packet_task`가 BSY를 poll합니다. BSY가 clear되면 CDB를 전송하고 interrupt handler에 넘깁니다. `ATA_PROT_ATAPI` PIO도 `packet_task`가 CDB를 보내지만 이후 data transfer는 `pio_task`가 맡습니다.
여섯 protocol을 software 개입 방식으로 분류했습니다.
Command 완료
467-515발행된 qc는 `ata_qc_complete()`로 완료되거나 timeout됩니다. Interrupt command는 `ata_host_intr()`, PIO는 `pio_task`, error case 일부는 `packet_task`가 completion을 호출합니다.
`ata_qc_complete()`는 DMA mapping을 해제하고 `qc->flags`의 `ATA_QCFLAG_ACTIVE`를 clear한 뒤 `qc->complete_fn`을 호출합니다. Callback이 0이 아닌 값을 반환하면 short-circuit하고 qc를 deallocate하지 않습니다.
Normal path의 `__ata_qc_complete()`는 flags를 0으로 clear하고 `ap->active_tag`와 `qc->tag`를 poison하며 `qc->waiting`을 clear한 뒤 complete하고, `ap->qactive` bit를 clear해 qc를 deallocate합니다. 즉 upper layer에 알리고 qc를 반환합니다.
Non-ATAPI command는 성공·실패 모두 거의 같은 path로 완료합니다. Failed ATAPI command는 REQUEST SENSE가 필요합니다. Error status로 `ata_qc_complete()`를 부르면 `atapi_qc_complete()`가 `scmd->result`를 `SAM_STAT_CHECK_CONDITION`으로 설정하고 scmd를 완료한 뒤 1을 반환합니다.
Sense data는 비어 있지만 result가 CHECK CONDITION이므로 SCSI midlayer가 EH를 호출합니다. Return 1은 qc deallocation을 막아 partially completed qc를 `ata_scsi_error()`까지 운반합니다.
DMA unmap에서 qc deallocation까지의 순서입니다.
REQUEST SENSE를 위해 qc를 반완료 상태로 유지합니다.
ata_scsi_error
516-544`ata_scsi_error()`는 당시 libATA의 `transportt->eh_strategy_handler()`이며 timeout과 ATAPI error completion 두 경우에 진입합니다. 아직 active이고 failed로 표시되지 않은 qc에는 `AC_ERR_TIMEOUT`을 set한 뒤 low-level driver의 `error_handler`를 호출합니다.
Error handler는 BMDMA를 stop하고 qc를 완료합니다. EH context에서는 `scsi_done`을 부를 수 없으므로 `qc->scsidone`을 `scsi_finish_command()`로 바꾸고 `ata_qc_complete()`를 호출합니다.
Failed ATAPI qc는 완료됐지만 deallocate되지 않은 placeholder로 EH code를 이 지점까지 오게 합니다. 여기서 `__ata_qc_complete()`로 명시적으로 deallocate하고 REQUEST SENSE용 internal qc를 발행합니다. Sense data를 얻으면 scmd에 `scsi_finish_command()`를 직접 호출합니다. 기존 qc는 이미 완료·해제됐으므로 `ata_qc_complete()`를 다시 호출할 수 없습니다.
Timeout 또는 failed ATAPI qc에서 sense completion까지입니다.
기존 EH 문제와 library 문서
545-606기존 EH는 error 표현이 지나치게 단순해 ATA device error가 아닌 condition도 ATA STATUS·ERROR register와 `ATA_ERR`로 표현합니다. Timeout command를 device가 잊고 새 command를 받을 상태로 만드는 action도 없습니다.
`ata_scsi_error()` 진입 시 device가 quiescent하지 않아 timed-out command가 언제든 성공·실패할 수 있고 `pio_task`·`atapi_task`가 계속 실행될 수 있습니다. HSM mismatch, NCQ, hotplug에는 reset을 포함한 더 강한 recovery가 필요합니다.
ATA error는 interrupt handler, PIO error는 `pio_task`에서 직접 처리되어 advanced EH가 여러 path로 흩어집니다. Context와 internal qc가 필요한 recovery, CRC 뒤 정보 수집·reset·reconfiguration 같은 복잡한 action, low-level callback별 분산 구현을 어렵고 error-prone하게 만듭니다.
Library API와 내부 문서는 kernel-doc directive로 `drivers/ata/libata-core.c`, `drivers/ata/libata-eh.c`, `drivers/ata/libata-scsi.c`에서 가져옵니다.
.. kernel-doc:: drivers/ata/libata-core.c
:export:
.. kernel-doc:: drivers/ata/libata-core.c
:internal:
.. kernel-doc:: drivers/ata/libata-eh.c
.. kernel-doc:: drivers/ata/libata-scsi.c
:export:
.. kernel-doc:: drivers/ata/libata-scsi.c
:internal:
문서가 지적한 구조적 문제입니다.
Generated API·internal documentation source path입니다.
ATA error·exception 정의
607-634이 장은 ATA·ATAPI device의 error와 exception condition을 구현과 무관한 방식으로 분류하고 처리 원칙을 설명합니다.
`error`는 device가 명시적 error를 보고하거나 command가 timeout된 condition입니다. `exception`은 power·hotplug처럼 error가 아닌 exceptional condition 또는 error와 non-error exception 전체를 뜻할 수 있습니다. 구분이 필요하면 `non-error exception`이라고 합니다.
Category는 주로 legacy taskfile + bus-master IDE interface를 기준으로 설명하지만 더 나은 controller error-reporting mechanism도 이 category로 mapping할 수 있습니다. Recovery action인 reset과 transport reconfiguration은 뒤의 EH recovery section에서 설명합니다.
libATA 문서의 error·exception 구분입니다.
HSM violation
635-662ATA·ATAPI command 발행 또는 실행 중 STATUS가 HSM requirement와 맞지 않으면 HSM violation입니다. Command issue 때 `!BSY && DRDY && !DRQ`가 아니거나, PIO data transfer 중 `!BSY && !DRQ`, completion 때 DRQ set, CDB 마지막 byte 전송 전 `!BSY && ERR`인 경우가 포함됩니다.
PACKET command는 command packet 마지막 byte를 쓰기 전에 error로 끝나면 안 된다고 standard가 규정하며 state diagram에도 그런 transition이 없습니다. HSM이 깨지면 STATUS·ERROR에서 유용한 정보를 거의 얻지 못해 driver bug, device, controller, cable 어느 쪽도 원인일 수 있습니다.
Known state 복구에는 reset이 필요합니다. Transmission error가 이런 증상을 만들 수 있으므로 transport speed를 낮추는 것도 도움이 될 수 있습니다.
Protocol state와 어긋나는 대표 STATUS 조합입니다.
Non-NCQ ATA·ATAPI device error
663-748이 category는 ATA·ATAPI device가 감지·보고한 문제로 STATUS와 ERROR register가 valid합니다. 일부 ATA bus error도 같은 mechanism으로 보고됩니다. ATA command는 실행·완료 중 `!BSY && ERR`로 나타납니다.
ATAPI에서 PACKET 직후 `!BSY && ERR && ABRT`는 PACKET 미지원으로 이 category입니다. CDB 마지막 byte 뒤 `ERR(CHK) && !ABRT` 또는 `ERR(CHK) && ABRT`는 CHECK CONDITION으로 이 category가 아닙니다.
Data transfer의 ICRC는 corruption을 뜻합니다. ATA/ATAPI-7까지는 UDMA에만 적용됐지만 ATA/ATAPI-8 draft 1f는 MWDMA·PIO에도 적용 가능하다고 합니다. ABRT만으로도 transfer error일 수 있으나 revision에 따라 의미가 달라 heuristic이 필요합니다.
Media error는 ERROR의 `UNC` bit이며 device가 자체 retry 뒤에도 복구하지 못한 상태라 upper layer에 알리는 것 외에 할 일이 적습니다. READ·WRITE가 첫 failed sector CHS/LBA를 주어도 error completion 전 transfer amount가 indeterminate이므로 앞 sector가 성공했다고 가정할 수 없습니다.
Media changed·change requested 부분은 원문에 TODO로 남아 있습니다. Address error는 `IDNF` bit로 upper layer에 보고합니다. Invalid command·parameter 등의 other error는 ABRT로 표시될 수 있지만 ABRT가 ICRC·address error도 뜻해 heuristic이 필요합니다.
Command별로 적용되지 않는 STATUS·ERROR bit는 output description에서 `na`로 표시됩니다. ATA/ATAPI-8 draft 1f의 `N/A` 정의는 standard상 defined value가 없고 host·device가 검사하지 않으며 0으로 clear해야 한다는 뜻입니다. 따라서 device가 `na` bit를 0으로 clear한다고 보고 별도 masking이 필요 없다고 판단할 수 있습니다.
ERROR bit와 처리 방향입니다.
Reported LBA 앞 sector를 성공 처리할 수 없는 이유입니다.
ATAPI CHECK CONDITION과 NCQ error
749-787PACKET command의 CDB 마지막 byte를 전송한 뒤 STATUS의 CHK, 즉 ERR bit가 set되면 ATAPI CHECK CONDITION입니다. Error 정보를 얻기 위해 `REQUEST SENSE` packet command로 sense data를 수집합니다.
Sense data를 얻으면 다른 SCSI error처럼 처리합니다. Sense Key `04h HARDWARE ERROR`와 ASC/ASCQ `47h/00h SCSI PARITY ERROR`처럼 ATA bus error를 나타낼 수도 있으며 이 경우 ATA bus error recovery를 적용합니다.
NCQ command phase에 one or more command가 outstanding인 상태에서 BSY clear와 ERR set이면 NCQ error입니다. STATUS·ERROR도 valid하지만 error condition clear, failed command 식별과 추가 정보 수집에 `READ LOG EXT`가 필요합니다.
Log Page `10h`는 failed tag와 taskfile register 값을 보고합니다. Failed command는 normal ATA error처럼 처리하고 다른 in-flight command는 모두 retry합니다. 이 retry는 failed command가 없었다면 정상 완료됐을 가능성이 크므로 retry count에 포함하지 않습니다.
ATA bus error도 NCQ device error처럼 보고될 수 있습니다. Log Page 10h read가 실패하거나 NQ를 보고하면 상태를 복구하기 어려우므로 HSM violation으로 처리합니다.
PACKET failure에서 SCSI sense handling까지입니다.
Failed tag를 찾고 다른 command를 재시도합니다.
Bus error·late completion·timeout
788-851ATA bus error는 SATA 또는 PATA 전송 중 data corruption입니다. ICRC·ABRT, controller-specific transmission error, 일부 controller의 timeout 진단, random error·timeout 등 다양한 증상으로 나타납니다.
Transmission error인지 판별할 수 없는 경우가 많아 heuristic이 필요합니다. 지원된 command에서 ABRT가 반복되는 경우가 예입니다. ATA bus error 가능성이 있으면 transmission speed를 낮춰 완화할 수 있습니다.
PCI 또는 다른 system bus 전송 중 corruption은 standard BMDMA에서 BMDMA Status의 Error bit로 나타납니다. System에 심각한 문제가 있음을 뜻하므로 반드시 log하고 host controller reset을 권장합니다.
Late completion은 timeout handler가 timed-out command가 이미 성공 또는 error로 완료됐음을 발견하는 경우이며 보통 lost interrupt가 원인입니다. Log와 host reset이 권장됩니다.
Unknown timeout은 command가 여전히 processing 중이거나 host·device가 unknown state인 경우입니다. HSM은 valid·invalid 어느 state일 수도 있으므로 reset해 known state로 만들고 timed-out command를 잊게 해야 합니다. Command는 retry할 수 있으며 transmission error 가능성도 고려합니다. Hotplug·power-management exception 절은 원문에 TODO로 남아 있습니다.
증상과 권장 recovery를 비교했습니다.
명확하지 않은 error를 반복 pattern으로 판단합니다.
EH recovery와 reset 정책
852-897EH recovery에서 controller error register를 clear해야 하며 요구사항은 controller마다 다릅니다. SATA에서는 최소한 SError register를 clear하는 것이 강하게 권장됩니다.
HSM 또는 HBA state가 unknown·invalid이거나, HBA·device가 in-flight command를 잊어야 하거나, 이상 동작할 때 reset이 필요합니다. Robustness를 위해 error 종류와 무관하게 reset하는 것도 유용할 수 있습니다.
HBA가 ready이고 device만 unknown이면 device만 reset합니다. HBA도 unknown이면 HBA와 device 모두 reset합니다. HBA reset은 implementation-specific입니다. Taskfile/BMDMA PCI IDE는 active DMA stop만으로 충분할 수 있지만 controller별 context·reset requirement는 specific driver가 처리해야 합니다.
Known state에 따라 device-only 또는 full reset을 선택합니다.
ATA·ATAPI reset 방식
898-958PATA hardware reset은 PATA `RESET-` signal을 assert하는 hardware-initiated reset입니다. Software에서 시작하는 standard 방법은 없지만 일부 hardware는 signal을 직접 제어하는 register를 제공합니다.
Software reset은 CONTROL의 `SRST` bit를 최소 5us 동안 set합니다. PATA와 SATA 모두 지원하지만 SATA에서는 BSY가 set된 동안 SRST를 clear하는 두 번째 Register FIS를 보내야 해 controller-specific support가 필요할 수 있습니다. PATA에서는 channel의 master와 slave를 모두 reset합니다.
`EXECUTE DEVICE DIAGNOSTIC`(EDD)은 정확한 reset level이 명시되지 않았지만 software reset과 비슷한 reset을 암시합니다. Normal command path로 처리할 수 있고 SATA controller도 보통 지원하지만 BSY 중 발행할 수 없고 unknown state 동작이 불명확해 EH에는 적합하지 않습니다. PATA에서는 두 device 모두에 영향이 있습니다.
`ATAPI DEVICE RESET`은 software reset과 비슷하지만 cable의 다른 device에 영향 없이 selected device만 reset할 수 있습니다. SATA PHY reset은 SATA device의 권장 방식으로 PATA hardware reset과 사실상 같고 standard SCR Control register로 구현해 software reset보다 쉬운 경우가 많습니다.
Reset은 `INITIALIZE DEVICE PARAMETERS`의 CHS, `SET FEATURES`의 transfer mode, `SET MULTIPLE MODE`의 block count, `SET MAX`·`MEDIA LOCK` 같은 parameter를 clear할 수 있습니다. Standard가 일부 parameter 유지 여부만 규정하므로 robust driver는 reset 뒤 필요한 값을 항상 재설정해야 하며 deep sleep power-off resume에도 적용됩니다.
Configuration parameter update 또는 hardware reset 뒤에는 `IDENTIFY DEVICE` 또는 `IDENTIFY PACKET DEVICE`를 다시 실행하고 그 결과로 이후 operation을 해야 합니다. OS driver가 revalidation mechanism을 구현해야 합니다.
범위와 EH 적합성을 비교했습니다.
Reset이 지운 configuration을 복원하는 순서입니다.
Transport 재설정·driver internals·감사
959-1000저가 connector·cable·controller 때문에 PATA와 SATA 모두 transmission error가 흔하며 speed를 낮춰 완화할 수 있습니다. Jeff Garzik이 제안한 scheme은 15분 안에 3회 정도보다 많은 error가 발생하면 SATA PHY speed를 먼저 낮추고, 더 낮출 수 없으면 UDMA speed를 낮추며 UDMA0에서는 PIO4로 전환합니다. 이후 PIO speed를 낮추고 PIO3에서도 계속 오류가 나면 경고하되 동작을 계속합니다.
`ata_piix`와 `sata_sil` 내부 문서는 각 driver source의 kernel-doc internal directive에서 생성됩니다.
.. kernel-doc:: drivers/ata/ata_piix.c
:internal:
.. kernel-doc:: drivers/ata/sata_sil.c
:internal:
ATA 지식은 Andre Hedrick과의 논의, ATA·SCSI specification 연구에서 왔습니다. Alan Cox는 SATA와 SCSI의 유사성을 지적하고 libATA 개발 동기를 제공했습니다. `ata_pio_devchk`와 초기 probing은 Hale Landis의 ATADRVR probe/reset code 연구를 기반으로 했습니다.
반복 error에서 단계적으로 link mode를 낮춥니다.
Example driver internal documentation source입니다.
요약과 해설
libata.rst:1-1000libATA는 SCSI midlayer request를 ATA·ATAPI protocol로 변환하고 `ata_port_operations`로 controller-specific 작업을 분리합니다. 안정적인 driver는 qc ownership과 completion short-circuit, port freeze·thaw, HSM·NCQ·bus error 분류, reset 뒤 IDENTIFY revalidation과 단계적 link-speed 강등을 일관된 EH path에서 처리해야 합니다.