diff options
author | Tejun Heo <htejun@gmail.com> | 2006-02-01 10:56:10 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-02-09 01:18:38 -0500 |
commit | c18d06f89fd09ee0059c4899e615c471d59af66a (patch) | |
tree | 445617ceee37299d0856e54a945957102728cb0b | |
parent | dde44589bf9fac0168c6ce6d097c99c33b18074f (diff) |
[PATCH] libata: EH / pio tasks synchronization
This patch makes sure that pio tasks are flushed before proceeding
with EH.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/scsi/libata-core.c | 56 | ||||
-rw-r--r-- | include/linux/libata.h | 3 |
2 files changed, 55 insertions, 4 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 249e67fab81f..9a785cf0c5b1 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -1074,19 +1074,66 @@ static unsigned int ata_pio_modes(const struct ata_device *adev) | |||
1074 | static inline void | 1074 | static inline void |
1075 | ata_queue_packet_task(struct ata_port *ap) | 1075 | ata_queue_packet_task(struct ata_port *ap) |
1076 | { | 1076 | { |
1077 | queue_work(ata_wq, &ap->packet_task); | 1077 | if (!(ap->flags & ATA_FLAG_FLUSH_PIO_TASK)) |
1078 | queue_work(ata_wq, &ap->packet_task); | ||
1078 | } | 1079 | } |
1079 | 1080 | ||
1080 | static inline void | 1081 | static inline void |
1081 | ata_queue_pio_task(struct ata_port *ap) | 1082 | ata_queue_pio_task(struct ata_port *ap) |
1082 | { | 1083 | { |
1083 | queue_work(ata_wq, &ap->pio_task); | 1084 | if (!(ap->flags & ATA_FLAG_FLUSH_PIO_TASK)) |
1085 | queue_work(ata_wq, &ap->pio_task); | ||
1084 | } | 1086 | } |
1085 | 1087 | ||
1086 | static inline void | 1088 | static inline void |
1087 | ata_queue_delayed_pio_task(struct ata_port *ap, unsigned long delay) | 1089 | ata_queue_delayed_pio_task(struct ata_port *ap, unsigned long delay) |
1088 | { | 1090 | { |
1089 | queue_delayed_work(ata_wq, &ap->pio_task, delay); | 1091 | if (!(ap->flags & ATA_FLAG_FLUSH_PIO_TASK)) |
1092 | queue_delayed_work(ata_wq, &ap->pio_task, delay); | ||
1093 | } | ||
1094 | |||
1095 | /** | ||
1096 | * ata_flush_pio_tasks - Flush pio_task and packet_task | ||
1097 | * @ap: the target ata_port | ||
1098 | * | ||
1099 | * After this function completes, pio_task and packet_task are | ||
1100 | * guranteed not to be running or scheduled. | ||
1101 | * | ||
1102 | * LOCKING: | ||
1103 | * Kernel thread context (may sleep) | ||
1104 | */ | ||
1105 | |||
1106 | static void ata_flush_pio_tasks(struct ata_port *ap) | ||
1107 | { | ||
1108 | int tmp = 0; | ||
1109 | unsigned long flags; | ||
1110 | |||
1111 | DPRINTK("ENTER\n"); | ||
1112 | |||
1113 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
1114 | ap->flags |= ATA_FLAG_FLUSH_PIO_TASK; | ||
1115 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
1116 | |||
1117 | DPRINTK("flush #1\n"); | ||
1118 | flush_workqueue(ata_wq); | ||
1119 | |||
1120 | /* | ||
1121 | * At this point, if a task is running, it's guaranteed to see | ||
1122 | * the FLUSH flag; thus, it will never queue pio tasks again. | ||
1123 | * Cancel and flush. | ||
1124 | */ | ||
1125 | tmp |= cancel_delayed_work(&ap->pio_task); | ||
1126 | tmp |= cancel_delayed_work(&ap->packet_task); | ||
1127 | if (!tmp) { | ||
1128 | DPRINTK("flush #2\n"); | ||
1129 | flush_workqueue(ata_wq); | ||
1130 | } | ||
1131 | |||
1132 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
1133 | ap->flags &= ~ATA_FLAG_FLUSH_PIO_TASK; | ||
1134 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
1135 | |||
1136 | DPRINTK("EXIT\n"); | ||
1090 | } | 1137 | } |
1091 | 1138 | ||
1092 | void ata_qc_complete_internal(struct ata_queued_cmd *qc) | 1139 | void ata_qc_complete_internal(struct ata_queued_cmd *qc) |
@@ -3767,6 +3814,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) | |||
3767 | 3814 | ||
3768 | DPRINTK("ENTER\n"); | 3815 | DPRINTK("ENTER\n"); |
3769 | 3816 | ||
3817 | ata_flush_pio_tasks(ap); | ||
3818 | ap->hsm_task_state = HSM_ST_IDLE; | ||
3819 | |||
3770 | spin_lock_irqsave(&host_set->lock, flags); | 3820 | spin_lock_irqsave(&host_set->lock, flags); |
3771 | 3821 | ||
3772 | switch (qc->tf.protocol) { | 3822 | switch (qc->tf.protocol) { |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 55176df403a5..f4cd1eb734a0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -162,7 +162,8 @@ enum { | |||
162 | ATA_FLAG_PIO_LBA48 = (1 << 13), /* Host DMA engine is LBA28 only */ | 162 | ATA_FLAG_PIO_LBA48 = (1 << 13), /* Host DMA engine is LBA28 only */ |
163 | ATA_FLAG_IRQ_MASK = (1 << 14), /* Mask IRQ in PIO xfers */ | 163 | ATA_FLAG_IRQ_MASK = (1 << 14), /* Mask IRQ in PIO xfers */ |
164 | 164 | ||
165 | ATA_FLAG_IN_EH = (1 << 15), /* EH in progress */ | 165 | ATA_FLAG_FLUSH_PIO_TASK = (1 << 15), /* Flush PIO task */ |
166 | ATA_FLAG_IN_EH = (1 << 16), /* EH in progress */ | ||
166 | 167 | ||
167 | ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ | 168 | ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ |
168 | ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ | 169 | ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ |