libata-pmp-prep: implement ops->qc_defer()
Controllers which support PMP have various restrictions on which combinations of commands are allowed to what number of devices concurrently. This patch implements ops->qc_defer() which determines whether a qc can be issued at the moment or should be deferred. If the function returns ATA_DEFER_LINK, the qc will be deferred until a qc completes on the link. If ATA_DEFER_PORT, until a qc completes on any link. The defer conditions are advisory and in general ATA_DEFER_LINK can be considered as lower priority deferring than ATA_DEFER_PORT. ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and sata_sil24 are converted to use ata_std_qc_defer(). ops->qc_defer() is heavier than the original mechanism because full qc is prepped before determining to defer it, but various information is needed to determine defer conditinos and fully translating a qc is the only way to supply such information in generic manner. IMHO, this shouldn't cause any noticeable performance issues as * for most cases deferring occurs rarely (except for NCQ-aware cmd-switching PMP) * translation itself isn't that expensive * once deferred the command won't be repeated until another command completes which usually is a very long time cpu-wise. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
@@ -4345,6 +4345,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_std_qc_defer - Check whether a qc needs to be deferred
|
||||
* @qc: ATA command in question
|
||||
*
|
||||
* Non-NCQ commands cannot run with any other command, NCQ or
|
||||
* not. As upper layer only knows the queue depth, we are
|
||||
* responsible for maintaining exclusion. This function checks
|
||||
* whether a new command @qc can be issued.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*
|
||||
* RETURNS:
|
||||
* ATA_DEFER_* if deferring is needed, 0 otherwise.
|
||||
*/
|
||||
int ata_std_qc_defer(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_link *link = qc->dev->link;
|
||||
|
||||
if (qc->tf.protocol == ATA_PROT_NCQ) {
|
||||
if (!ata_tag_valid(link->active_tag))
|
||||
return 0;
|
||||
} else {
|
||||
if (!ata_tag_valid(link->active_tag) && !link->sactive)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ATA_DEFER_LINK;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_qc_prep - Prepare taskfile for submission
|
||||
* @qc: Metadata associated with taskfile to be prepared
|
||||
@@ -7111,6 +7141,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
|
||||
EXPORT_SYMBOL_GPL(ata_do_set_mode);
|
||||
EXPORT_SYMBOL_GPL(ata_data_xfer);
|
||||
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
|
||||
EXPORT_SYMBOL_GPL(ata_std_qc_defer);
|
||||
EXPORT_SYMBOL_GPL(ata_qc_prep);
|
||||
EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
|
||||
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
|
||||
|
Reference in New Issue
Block a user