⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libata.tmpl

📁 linux 内核源代码
💻 TMPL
📖 第 1 页 / 共 4 页
字号:
	<para>Either 'softreset' (may be NULL) or 'hardreset' (may be NULL) will becalled to perform the low-level EH reset.	</para>	<programlisting>void (*post_internal_cmd) (struct ata_queued_cmd *qc);	</programlisting>	<para>Perform any hardware-specific actions necessary to finish processingafter executing a probe-time or EH-time command via ata_exec_internal().	</para>	</sect2>	<sect2><title>Hardware interrupt handling</title>	<programlisting>irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);void (*irq_clear) (struct ata_port *);	</programlisting>	<para>	->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.	</para>	<para>	The second argument, dev_instance, should be cast to a pointer	to struct ata_host_set.	</para>	<para>	Most legacy IDE drivers use ata_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_host_intr(ap,qc).	</para>	<para>	Most legacy IDE drivers use ata_bmdma_irq_clear() for the	irq_clear() hook, which simply clears the interrupt and error	flags in the DMA status register.	</para>	</sect2>	<sect2><title>SATA phy read/write</title>	<programlisting>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);	</programlisting>	<para>	Read and write standard SATA phy registers.  Currently only used	if ->phy_reset hook called the sata_phy_reset() helper function.	sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE.	</para>	</sect2>	<sect2><title>Init and shutdown</title>	<programlisting>int (*port_start) (struct ata_port *ap);void (*port_stop) (struct ata_port *ap);void (*host_stop) (struct ata_host_set *host_set);	</programlisting>	<para>	->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.	</para>	<para>	Many drivers use ata_port_start() as this hook or call	it from their own port_start() hooks.  ata_port_start()	allocates space for a legacy IDE PRD table and returns.	</para>	<para>	->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.  Many drivers also free driver-private	data from port at this time.	</para>	<para>	Many drivers use ata_port_stop() as this hook, which frees the	PRD table.	</para>	<para>	->host_stop() is called after all ->port_stop() callshave completed.  The hook must finalize hardware shutdown, release DMAand other resources, etc.	This hook may be specified as NULL, in which case it is not called.	</para>	</sect2>     </sect1>  </chapter>  <chapter id="libataEH">        <title>Error handling</title>	<para>	This chapter describes how errors are handled under libata.	Readers are advised to read SCSI EH	(Documentation/scsi/scsi_eh.txt) and ATA exceptions doc first.	</para>	<sect1><title>Origins of commands</title>	<para>	In libata, a command is represented with struct 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.	</para>	<para>	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.	</para>	</sect1>	<sect1><title>How commands are issued</title>	<variablelist>	<varlistentry><term>Internal commands</term>	<listitem>	<para>	First, qc is allocated and initialized using	ata_qc_new_init().  Although ata_qc_new_init() doesn't	implement any wait or retry mechanism when qc is not	available, internal commands are currently issued only during	initialization and error recovery, so no other command is	active and allocation is guaranteed to succeed.	</para>	<para>	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.	</para>	<para>	Once initialization is complete, host_set lock is acquired	and the qc is issued.	</para>	</listitem>	</varlistentry>	<varlistentry><term>SCSI commands</term>	<listitem>	<para>	All libata drivers use 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.	</para>	<para>	For a translated scmd, ata_qc_new_init() is invoked to	allocate a qc and the scmd is translated into the qc.  SCSI	midlayer's completion notification function pointer is stored	into qc->scsidone.	</para>	<para>	qc->complete_fn() callback is used for completion	notification.  ATA commands use ata_scsi_qc_complete() while	ATAPI commands use 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 ata_qc_issue().	</para>	<para>	Note that SCSI midlayer invokes hostt->queuecommand while	holding host_set lock, so all above occur while holding	host_set lock.	</para>	</listitem>	</varlistentry>	</variablelist>	</sect1>	<sect1><title>How commands are processed</title>	<para>	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.	</para>	<para>	Currently 6 ATA command protocols are used.  They can be	sorted into the following four categories according to how	they are processed.	</para>	<variablelist>	   <varlistentry><term>ATA NO DATA or DMA</term>	   <listitem>	   <para>	   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.	   </para>	   </listitem>	   </varlistentry>	   <varlistentry><term>ATA PIO</term>	   <listitem>	   <para>	   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.	   </para>	   </listitem>	   </varlistentry>	   <varlistentry><term>ATAPI NODATA or DMA</term>	   <listitem>	   <para>	   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.	   </para>	   </listitem>	   </varlistentry>	   <varlistentry><term>ATAPI PIO</term>	   <listitem>	   <para>	   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.	   </para>	   </listitem>	   </varlistentry>	</variablelist>        </sect1>	<sect1><title>How commands are completed</title>	<para>	Once issued, all qc's are either completed with	ata_qc_complete() or time out.  For commands which are handled	by interrupts, ata_host_intr() invokes ata_qc_complete(), and,	for PIO tasks, pio_task invokes ata_qc_complete().  In error	cases, packet_task may also complete commands.	</para>	<para>	ata_qc_complete() does the following.	</para>	<orderedlist>	<listitem>	<para>	DMA memory is unmapped.	</para>	</listitem>	<listitem>	<para>	ATA_QCFLAG_ACTIVE is clared from qc->flags.	</para>	</listitem>	<listitem>	<para>	qc->complete_fn() callback is invoked.  If the return value of	the callback is not zero.  Completion is short circuited and	ata_qc_complete() returns.	</para>	</listitem>	<listitem>	<para>	__ata_qc_complete() is called, which does	   <orderedlist>	   <listitem>	   <para>	   qc->flags is cleared to zero.	   </para>	   </listitem>	   <listitem>	   <para>	   ap->active_tag and qc->tag are poisoned.	   </para>	   </listitem>	   <listitem>	   <para>	   qc->waiting is claread &amp; completed (in that order).	   </para>	   </listitem>	   <listitem>	   <para>	   qc is deallocated by clearing appropriate bit in ap->qactive.	   </para>	   </listitem>	   </orderedlist>	</para>	</listitem>	</orderedlist>	<para>	So, it basically notifies upper layer and deallocates qc.  One	exception is short-circuit path in #3 which is used by	atapi_qc_complete().	</para>	<para>	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.	</para>	<para>	However, failed ATAPI commands require more handling as	REQUEST SENSE is needed to acquire sense data.  If an ATAPI	command fails, ata_qc_complete() is invoked with error status,	which in turn invokes atapi_qc_complete() via	qc->complete_fn() callback.	</para>	<para>	This makes 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 ata_qc_complete() to return without deallocating the qc.	This leads us to ata_scsi_error() with partially completed qc.	</para>	</sect1>	<sect1><title>ata_scsi_error()</title>	<para>	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	calls low level libata driver's eng_timeout() callback, the	standard callback for which is ata_eng_timeout().  It checks	if a qc is active and calls ata_qc_timeout() on the qc if so.	Actual error handling occurs in ata_qc_timeout().	</para>	<para>	If EH is invoked for timeout, ata_qc_timeout() 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	scsi_queue_insert() or finished with scsi_finish_command().	Here, we override qc->scsidone with scsi_finish_command() and	calls ata_qc_complete().	</para>	<para>	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.	</para>	<para>	Once control reaches here, the qc is deallocated by invoking	__ata_qc_complete() explicitly.  Then, internal qc for REQUEST	SENSE is issued.  Once sense data is acquired, scmd is	finished by directly invoking 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 ata_qc_complete() again.	</para>	</sect1>	<sect1><title>Problems with the current EH</title>	<itemizedlist>	<listitem>	<para>	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.	</para>	</listitem>	<listitem>	<para>	When handling timeouts, no action is taken to make device	forget about the timed out command and ready for new commands.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -