diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-06-22 02:25:27 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-07-20 03:58:45 -0400 |
commit | e4a9c3732cea3e3c8c704aad86636090ffe6b25f (patch) | |
tree | faea8e91b3d917dcdb4c89adbb021ac737a6cb35 /drivers/ata/libata-eh.c | |
parent | 3b661a92e869ebe2358de8f4b3230ad84f7fce51 (diff) |
[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 <jacek.danecki@intel.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 57 |
1 files changed, 46 insertions, 11 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 6d53cf9b3b6e..77fc80640e26 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -793,12 +793,12 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) | |||
793 | ata_for_each_link(link, ap, HOST_FIRST) | 793 | ata_for_each_link(link, ap, HOST_FIRST) |
794 | memset(&link->eh_info, 0, sizeof(link->eh_info)); | 794 | memset(&link->eh_info, 0, sizeof(link->eh_info)); |
795 | 795 | ||
796 | /* Clear host_eh_scheduled while holding ap->lock such | 796 | /* end eh (clear host_eh_scheduled) while holding |
797 | * that if exception occurs after this point but | 797 | * ap->lock such that if exception occurs after this |
798 | * before EH completion, SCSI midlayer will | 798 | * point but before EH completion, SCSI midlayer will |
799 | * re-initiate EH. | 799 | * re-initiate EH. |
800 | */ | 800 | */ |
801 | host->host_eh_scheduled = 0; | 801 | ap->ops->end_eh(ap); |
802 | 802 | ||
803 | spin_unlock_irqrestore(ap->lock, flags); | 803 | spin_unlock_irqrestore(ap->lock, flags); |
804 | ata_eh_release(ap); | 804 | ata_eh_release(ap); |
@@ -986,16 +986,13 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) | |||
986 | } | 986 | } |
987 | 987 | ||
988 | /** | 988 | /** |
989 | * ata_port_schedule_eh - schedule error handling without a qc | 989 | * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine |
990 | * @ap: ATA port to schedule EH for | 990 | * @ap: ATA port to schedule EH for |
991 | * | ||
992 | * Schedule error handling for @ap. EH will kick in as soon as | ||
993 | * all commands are drained. | ||
994 | * | 991 | * |
995 | * LOCKING: | 992 | * LOCKING: inherited from ata_port_schedule_eh |
996 | * spin_lock_irqsave(host lock) | 993 | * spin_lock_irqsave(host lock) |
997 | */ | 994 | */ |
998 | void ata_port_schedule_eh(struct ata_port *ap) | 995 | void ata_std_sched_eh(struct ata_port *ap) |
999 | { | 996 | { |
1000 | WARN_ON(!ap->ops->error_handler); | 997 | WARN_ON(!ap->ops->error_handler); |
1001 | 998 | ||
@@ -1007,6 +1004,44 @@ void ata_port_schedule_eh(struct ata_port *ap) | |||
1007 | 1004 | ||
1008 | DPRINTK("port EH scheduled\n"); | 1005 | DPRINTK("port EH scheduled\n"); |
1009 | } | 1006 | } |
1007 | EXPORT_SYMBOL_GPL(ata_std_sched_eh); | ||
1008 | |||
1009 | /** | ||
1010 | * ata_std_end_eh - non-libsas ata_ports complete eh with this common routine | ||
1011 | * @ap: ATA port to end EH for | ||
1012 | * | ||
1013 | * In the libata object model there is a 1:1 mapping of ata_port to | ||
1014 | * shost, so host fields can be directly manipulated under ap->lock, in | ||
1015 | * the libsas case we need to hold a lock at the ha->level to coordinate | ||
1016 | * these events. | ||
1017 | * | ||
1018 | * LOCKING: | ||
1019 | * spin_lock_irqsave(host lock) | ||
1020 | */ | ||
1021 | void ata_std_end_eh(struct ata_port *ap) | ||
1022 | { | ||
1023 | struct Scsi_Host *host = ap->scsi_host; | ||
1024 | |||
1025 | host->host_eh_scheduled = 0; | ||
1026 | } | ||
1027 | EXPORT_SYMBOL(ata_std_end_eh); | ||
1028 | |||
1029 | |||
1030 | /** | ||
1031 | * ata_port_schedule_eh - schedule error handling without a qc | ||
1032 | * @ap: ATA port to schedule EH for | ||
1033 | * | ||
1034 | * Schedule error handling for @ap. EH will kick in as soon as | ||
1035 | * all commands are drained. | ||
1036 | * | ||
1037 | * LOCKING: | ||
1038 | * spin_lock_irqsave(host lock) | ||
1039 | */ | ||
1040 | void ata_port_schedule_eh(struct ata_port *ap) | ||
1041 | { | ||
1042 | /* see: ata_std_sched_eh, unless you know better */ | ||
1043 | ap->ops->sched_eh(ap); | ||
1044 | } | ||
1010 | 1045 | ||
1011 | static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) | 1046 | static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) |
1012 | { | 1047 | { |