From f68f2fa3980f2c05d64bc890ac2d19b561b55ea0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 16 Jul 2003 19:03:48 -0700 Subject: [PATCH] [PATCH] Fix dma timeout bugs From Alexander Atanasov Fix DMA I/O and state machine fixes, error recovery --- drivers/ide/ide-dma.c | 20 +++++++++----------- drivers/ide/ide-io.c | 37 ++++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 70bb8d05c63..e507f9e6193 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -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 */ } /** diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 025cdc34d06..acac8e3dfee 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -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; } -- 2.11.4.GIT