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)
* the driver to resolve the problem, if a DMA transfer is still
* in progress we continue to wait (arguably we need to add a
* secondary 'I don't care what the drive thinks' timeout here)
* Finally if we have an interrupt but for some reason got the
* timeout first we complete the I/O. This can occur if an
* interrupt is lost or due to bugs.
* Finally if we have an interrupt we let it complete the I/O.
* But only one time - we clear expiry and if it's still not
* 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)
......@@ -461,19 +462,16 @@ static int dma_timer_expiry (ide_drive_t *drive)
HWGROUP(drive)->expiry = NULL; /* one free ride for now */
/* 1 dmaing, 2 error, 4 intr */
if (dma_stat & 2) { /* ERROR */
(void) hwif->ide_dma_end(drive);
return DRIVER(drive)->error(drive,
"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));
}
if (dma_stat & 2) /* ERROR */
return -1;
if (dma_stat & 1) /* DMAing */
return WAIT_CMD;
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)
* retry the current request in pio mode instead of risking tossing it
* 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);
struct request *rq;
ide_startstop_t ret = ide_stopped;
/*
* end current dma transaction
*/
(void) hwif->ide_dma_end(drive);
/*
* complain a little, later we might remove some of this verbosity
*/
printk(KERN_WARNING "%s: timeout waiting for DMA\n", drive->name);
(void) hwif->ide_dma_timeout(drive);
if (error < 0) {
printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
(void)HWIF(drive)->ide_dma_end(drive);
ret = DRIVER(drive)->error(drive, "dma timeout error",
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
......@@ -1018,9 +1022,9 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
rq->hard_cur_sectors = rq->current_nr_sectors;
if (rq->bio)
rq->buffer = NULL;
}
EXPORT_SYMBOL(ide_dma_timeout_retry);
return ret;
}
/**
* ide_timer_expiry - handle lack of an IDE interrupt
......@@ -1041,11 +1045,10 @@ void ide_timer_expiry (unsigned long data)
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
ide_handler_t *handler;
ide_expiry_t *expiry;
unsigned long flags;
unsigned long wait;
unsigned long flags;
unsigned long wait = -1;
spin_lock_irqsave(&ide_lock, flags);
del_timer(&hwgroup->timer);
if ((handler = hwgroup->handler) == NULL) {
/*
......@@ -1072,7 +1075,7 @@ void ide_timer_expiry (unsigned long data)
}
if ((expiry = hwgroup->expiry) != NULL) {
/* continue */
if ((wait = expiry(drive)) != 0) {
if ((wait = expiry(drive)) > 0) {
/* reset timer */
hwgroup->timer.expires = jiffies + wait;
add_timer(&hwgroup->timer);
......@@ -1107,15 +1110,15 @@ void ide_timer_expiry (unsigned long data)
startstop = handler(drive);
} else {
if (drive->waiting_for_dma) {
startstop = ide_stopped;
ide_dma_timeout_retry(drive);
startstop = ide_dma_timeout_retry(drive, wait);
} 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);
drive->service_time = jiffies - drive->service_start;
enable_irq(hwif->irq);
spin_lock_irq(&ide_lock);
enable_irq(hwif->irq);
if (startstop == ide_stopped)
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