Commit f68f2fa3 authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz Committed by Linus Torvalds

[PATCH] Fix dma timeout bugs

From Alexander Atanasov <alex@ssi.bg>

Fix DMA I/O and state machine fixes, error recovery
parent 61666547
...@@ -442,9 +442,10 @@ static int config_drive_for_dma (ide_drive_t *drive) ...@@ -442,9 +442,10 @@ static int config_drive_for_dma (ide_drive_t *drive)
* the driver to resolve the problem, if a DMA transfer is still * the driver to resolve the problem, if a DMA transfer is still
* in progress we continue to wait (arguably we need to add a * in progress we continue to wait (arguably we need to add a
* secondary 'I don't care what the drive thinks' timeout here) * secondary 'I don't care what the drive thinks' timeout here)
* Finally if we have an interrupt but for some reason got the * Finally if we have an interrupt we let it complete the I/O.
* timeout first we complete the I/O. This can occur if an * But only one time - we clear expiry and if it's still not
* interrupt is lost or due to bugs. * completed after WAIT_CMD, we error and retry in PIO.
* This can occur if an interrupt is lost or due to hang or bugs.
*/ */
static int dma_timer_expiry (ide_drive_t *drive) static int dma_timer_expiry (ide_drive_t *drive)
...@@ -461,19 +462,16 @@ static int dma_timer_expiry (ide_drive_t *drive) ...@@ -461,19 +462,16 @@ static int dma_timer_expiry (ide_drive_t *drive)
HWGROUP(drive)->expiry = NULL; /* one free ride for now */ HWGROUP(drive)->expiry = NULL; /* one free ride for now */
/* 1 dmaing, 2 error, 4 intr */ /* 1 dmaing, 2 error, 4 intr */
if (dma_stat & 2) /* ERROR */
if (dma_stat & 2) { /* ERROR */ return -1;
(void) hwif->ide_dma_end(drive);
return DRIVER(drive)->error(drive,
"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));
}
if (dma_stat & 1) /* DMAing */ if (dma_stat & 1) /* DMAing */
return WAIT_CMD; return WAIT_CMD;
if (dma_stat & 4) /* Got an Interrupt */ if (dma_stat & 4) /* Got an Interrupt */
HWGROUP(drive)->handler(drive); return WAIT_CMD;
return 0; return 0; /* Status is unknown -- reset the bus */
} }
/** /**
......
...@@ -980,21 +980,25 @@ void do_ide_request(request_queue_t *q) ...@@ -980,21 +980,25 @@ void do_ide_request(request_queue_t *q)
* retry the current request in pio mode instead of risking tossing it * retry the current request in pio mode instead of risking tossing it
* all away * all away
*/ */
void ide_dma_timeout_retry(ide_drive_t *drive) static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
{ {
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
struct request *rq; struct request *rq;
ide_startstop_t ret = ide_stopped;
/* /*
* end current dma transaction * end current dma transaction
*/ */
(void) hwif->ide_dma_end(drive);
/* if (error < 0) {
* complain a little, later we might remove some of this verbosity printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
*/ (void)HWIF(drive)->ide_dma_end(drive);
printk(KERN_WARNING "%s: timeout waiting for DMA\n", drive->name); ret = DRIVER(drive)->error(drive, "dma timeout error",
(void) hwif->ide_dma_timeout(drive); hwif->INB(IDE_STATUS_REG));
} else {
printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
(void) hwif->ide_dma_timeout(drive);
}
/* /*
* disable dma for now, but remember that we did so because of * disable dma for now, but remember that we did so because of
...@@ -1018,9 +1022,9 @@ void ide_dma_timeout_retry(ide_drive_t *drive) ...@@ -1018,9 +1022,9 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
rq->hard_cur_sectors = rq->current_nr_sectors; rq->hard_cur_sectors = rq->current_nr_sectors;
if (rq->bio) if (rq->bio)
rq->buffer = NULL; rq->buffer = NULL;
}
EXPORT_SYMBOL(ide_dma_timeout_retry); return ret;
}
/** /**
* ide_timer_expiry - handle lack of an IDE interrupt * ide_timer_expiry - handle lack of an IDE interrupt
...@@ -1041,11 +1045,10 @@ void ide_timer_expiry (unsigned long data) ...@@ -1041,11 +1045,10 @@ void ide_timer_expiry (unsigned long data)
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
ide_handler_t *handler; ide_handler_t *handler;
ide_expiry_t *expiry; ide_expiry_t *expiry;
unsigned long flags; unsigned long flags;
unsigned long wait; unsigned long wait = -1;
spin_lock_irqsave(&ide_lock, flags); spin_lock_irqsave(&ide_lock, flags);
del_timer(&hwgroup->timer);
if ((handler = hwgroup->handler) == NULL) { if ((handler = hwgroup->handler) == NULL) {
/* /*
...@@ -1072,7 +1075,7 @@ void ide_timer_expiry (unsigned long data) ...@@ -1072,7 +1075,7 @@ void ide_timer_expiry (unsigned long data)
} }
if ((expiry = hwgroup->expiry) != NULL) { if ((expiry = hwgroup->expiry) != NULL) {
/* continue */ /* continue */
if ((wait = expiry(drive)) != 0) { if ((wait = expiry(drive)) > 0) {
/* reset timer */ /* reset timer */
hwgroup->timer.expires = jiffies + wait; hwgroup->timer.expires = jiffies + wait;
add_timer(&hwgroup->timer); add_timer(&hwgroup->timer);
...@@ -1107,15 +1110,15 @@ void ide_timer_expiry (unsigned long data) ...@@ -1107,15 +1110,15 @@ void ide_timer_expiry (unsigned long data)
startstop = handler(drive); startstop = handler(drive);
} else { } else {
if (drive->waiting_for_dma) { if (drive->waiting_for_dma) {
startstop = ide_stopped; startstop = ide_dma_timeout_retry(drive, wait);
ide_dma_timeout_retry(drive);
} else } else
startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); startstop =
DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
} }
set_recovery_timer(hwif); set_recovery_timer(hwif);
drive->service_time = jiffies - drive->service_start; drive->service_time = jiffies - drive->service_start;
enable_irq(hwif->irq);
spin_lock_irq(&ide_lock); spin_lock_irq(&ide_lock);
enable_irq(hwif->irq);
if (startstop == ide_stopped) if (startstop == ide_stopped)
hwgroup->busy = 0; hwgroup->busy = 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment