aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-sff.c
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2009-03-24 06:23:19 -0400
committerJeff Garzik <jgarzik@redhat.com>2009-03-24 22:48:26 -0400
commit3d47aa8e7e7b2aa09256590388aa8dddc79280f9 (patch)
tree82f4c85842e5e02489eb0533609dabb865e55198 /drivers/ata/libata-sff.c
parentc0f2ee34a5a0b79fd98d965ad8ae765d4639bfa5 (diff)
[libata] Drain data on errors
If the device is signalling that there is data to drain after an error we should read the bytes out and throw them away. Without this some devices and controllers get wedged and don't recover. Based on earlier work by Mark Lord Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-sff.c')
-rw-r--r--drivers/ata/libata-sff.c45
1 files changed, 43 insertions, 2 deletions
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index f93dc029dfd..9a10cb055ac 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -52,6 +52,7 @@ const struct ata_port_operations ata_sff_port_ops = {
52 .softreset = ata_sff_softreset, 52 .softreset = ata_sff_softreset,
53 .hardreset = sata_sff_hardreset, 53 .hardreset = sata_sff_hardreset,
54 .postreset = ata_sff_postreset, 54 .postreset = ata_sff_postreset,
55 .drain_fifo = ata_sff_drain_fifo,
55 .error_handler = ata_sff_error_handler, 56 .error_handler = ata_sff_error_handler,
56 .post_internal_cmd = ata_sff_post_internal_cmd, 57 .post_internal_cmd = ata_sff_post_internal_cmd,
57 58
@@ -2199,6 +2200,39 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
2199EXPORT_SYMBOL_GPL(ata_sff_postreset); 2200EXPORT_SYMBOL_GPL(ata_sff_postreset);
2200 2201
2201/** 2202/**
2203 * ata_sff_drain_fifo - Stock FIFO drain logic for SFF controllers
2204 * @qc: command
2205 *
2206 * Drain the FIFO and device of any stuck data following a command
2207 * failing to complete. In some cases this is neccessary before a
2208 * reset will recover the device.
2209 *
2210 */
2211
2212void ata_sff_drain_fifo(struct ata_queued_cmd *qc)
2213{
2214 int count;
2215 struct ata_port *ap;
2216
2217 /* We only need to flush incoming data when a command was running */
2218 if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
2219 return;
2220
2221 ap = qc->ap;
2222 /* Drain up to 64K of data before we give up this recovery method */
2223 for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
2224 && count < 32768; count++)
2225 ioread16(ap->ioaddr.data_addr);
2226
2227 /* Can become DEBUG later */
2228 if (count)
2229 ata_port_printk(ap, KERN_DEBUG,
2230 "drained %d bytes to clear DRQ.\n", count);
2231
2232}
2233EXPORT_SYMBOL_GPL(ata_sff_drain_fifo);
2234
2235/**
2202 * ata_sff_error_handler - Stock error handler for BMDMA controller 2236 * ata_sff_error_handler - Stock error handler for BMDMA controller
2203 * @ap: port to handle error for 2237 * @ap: port to handle error for
2204 * 2238 *
@@ -2239,7 +2273,8 @@ void ata_sff_error_handler(struct ata_port *ap)
2239 * really a timeout event, adjust error mask and 2273 * really a timeout event, adjust error mask and
2240 * cancel frozen state. 2274 * cancel frozen state.
2241 */ 2275 */
2242 if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) { 2276 if (qc->err_mask == AC_ERR_TIMEOUT
2277 && (host_stat & ATA_DMA_ERR)) {
2243 qc->err_mask = AC_ERR_HOST_BUS; 2278 qc->err_mask = AC_ERR_HOST_BUS;
2244 thaw = 1; 2279 thaw = 1;
2245 } 2280 }
@@ -2250,6 +2285,13 @@ void ata_sff_error_handler(struct ata_port *ap)
2250 ata_sff_sync(ap); /* FIXME: We don't need this */ 2285 ata_sff_sync(ap); /* FIXME: We don't need this */
2251 ap->ops->sff_check_status(ap); 2286 ap->ops->sff_check_status(ap);
2252 ap->ops->sff_irq_clear(ap); 2287 ap->ops->sff_irq_clear(ap);
2288 /* We *MUST* do FIFO draining before we issue a reset as several
2289 * devices helpfully clear their internal state and will lock solid
2290 * if we touch the data port post reset. Pass qc in case anyone wants
2291 * to do different PIO/DMA recovery or has per command fixups
2292 */
2293 if (ap->ops->drain_fifo)
2294 ap->ops->drain_fifo(qc);
2253 2295
2254 spin_unlock_irqrestore(ap->lock, flags); 2296 spin_unlock_irqrestore(ap->lock, flags);
2255 2297
@@ -2959,4 +3001,3 @@ out:
2959EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); 3001EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
2960 3002
2961#endif /* CONFIG_PCI */ 3003#endif /* CONFIG_PCI */
2962