mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
[SCSI] libata, libsas: introduce sched_eh and end_eh port ops
When managing shost->host_eh_scheduled libata assumes that there is a 1:1 shost-to-ata_port relationship. libsas creates a 1:N relationship so it needs to manage host_eh_scheduled cumulatively at the host level. The sched_eh and end_eh port port ops allow libsas to track when domain devices enter/leave the "eh-pending" state under ha->lock (previously named ha->state_lock, but it is no longer just a lock for ha->state changes). Since host_eh_scheduled indicates eh without backing commands pinning the device it can be deallocated at any time. Move the taking of the domain_device reference under the port_lock to guarantee that the ata_port stays around for the duration of eh. Reviewed-by: Jacek Danecki <[email protected]> Acked-by: Jeff Garzik <[email protected]> Signed-off-by: Dan Williams <[email protected]> Signed-off-by: James Bottomley <[email protected]>
This commit is contained in:
parent
3b661a92e8
commit
e4a9c3732c
10 changed files with 134 additions and 37 deletions
|
|
@ -80,6 +80,8 @@ const struct ata_port_operations ata_base_port_ops = {
|
|||
.prereset = ata_std_prereset,
|
||||
.postreset = ata_std_postreset,
|
||||
.error_handler = ata_std_error_handler,
|
||||
.sched_eh = ata_std_sched_eh,
|
||||
.end_eh = ata_std_end_eh,
|
||||
};
|
||||
|
||||
const struct ata_port_operations sata_port_ops = {
|
||||
|
|
@ -6642,6 +6644,8 @@ struct ata_port_operations ata_dummy_port_ops = {
|
|||
.qc_prep = ata_noop_qc_prep,
|
||||
.qc_issue = ata_dummy_qc_issue,
|
||||
.error_handler = ata_dummy_error_handler,
|
||||
.sched_eh = ata_std_sched_eh,
|
||||
.end_eh = ata_std_end_eh,
|
||||
};
|
||||
|
||||
const struct ata_port_info ata_dummy_port_info = {
|
||||
|
|
|
|||
|
|
@ -793,12 +793,12 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
|
|||
ata_for_each_link(link, ap, HOST_FIRST)
|
||||
memset(&link->eh_info, 0, sizeof(link->eh_info));
|
||||
|
||||
/* Clear host_eh_scheduled while holding ap->lock such
|
||||
* that if exception occurs after this point but
|
||||
* before EH completion, SCSI midlayer will
|
||||
/* end eh (clear host_eh_scheduled) while holding
|
||||
* ap->lock such that if exception occurs after this
|
||||
* point but before EH completion, SCSI midlayer will
|
||||
* re-initiate EH.
|
||||
*/
|
||||
host->host_eh_scheduled = 0;
|
||||
ap->ops->end_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
ata_eh_release(ap);
|
||||
|
|
@ -985,6 +985,48 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
|
|||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
|
||||
* @ap: ATA port to schedule EH for
|
||||
*
|
||||
* LOCKING: inherited from ata_port_schedule_eh
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_std_sched_eh(struct ata_port *ap)
|
||||
{
|
||||
WARN_ON(!ap->ops->error_handler);
|
||||
|
||||
if (ap->pflags & ATA_PFLAG_INITIALIZING)
|
||||
return;
|
||||
|
||||
ata_eh_set_pending(ap, 1);
|
||||
scsi_schedule_eh(ap->scsi_host);
|
||||
|
||||
DPRINTK("port EH scheduled\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_std_sched_eh);
|
||||
|
||||
/**
|
||||
* ata_std_end_eh - non-libsas ata_ports complete eh with this common routine
|
||||
* @ap: ATA port to end EH for
|
||||
*
|
||||
* In the libata object model there is a 1:1 mapping of ata_port to
|
||||
* shost, so host fields can be directly manipulated under ap->lock, in
|
||||
* the libsas case we need to hold a lock at the ha->level to coordinate
|
||||
* these events.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_std_end_eh(struct ata_port *ap)
|
||||
{
|
||||
struct Scsi_Host *host = ap->scsi_host;
|
||||
|
||||
host->host_eh_scheduled = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ata_std_end_eh);
|
||||
|
||||
|
||||
/**
|
||||
* ata_port_schedule_eh - schedule error handling without a qc
|
||||
* @ap: ATA port to schedule EH for
|
||||
|
|
@ -997,15 +1039,8 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
|
|||
*/
|
||||
void ata_port_schedule_eh(struct ata_port *ap)
|
||||
{
|
||||
WARN_ON(!ap->ops->error_handler);
|
||||
|
||||
if (ap->pflags & ATA_PFLAG_INITIALIZING)
|
||||
return;
|
||||
|
||||
ata_eh_set_pending(ap, 1);
|
||||
scsi_schedule_eh(ap->scsi_host);
|
||||
|
||||
DPRINTK("port EH scheduled\n");
|
||||
/* see: ata_std_sched_eh, unless you know better */
|
||||
ap->ops->sched_eh(ap);
|
||||
}
|
||||
|
||||
static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
|
||||
|
|
|
|||
Loading…
Reference in a new issue