--- ../linux-2.4.5-ac3-clean/drivers/ide/ide.c Mon May 28 20:28:05 2001 +++ drivers/ide/ide.c Mon May 28 20:21:48 2001 @@ -543,10 +543,20 @@ { struct request *rq; unsigned long flags; + ide_drive_t *drive = hwgroup->drive; spin_lock_irqsave(&io_request_lock, flags); rq = hwgroup->rq; + /* + * decide whether to reenable DMA -- 3 is a random magic for now, + * if we DMA timeout more than 3 times, just stay in PIO + */ + if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { + drive->state = 0; + hwgroup->hwif->dmaproc(ide_dma_on, drive); + } + if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) { add_blkdev_randomness(MAJOR(rq->rq_dev)); blkdev_dequeue_request(rq); @@ -1419,6 +1429,49 @@ } /* + * un-busy the hwgroup etc, and clear any pending DMA status. we want to + * retry the current request in pio mode instead of risking tossing it + * all away + */ +void ide_dma_timeout_retry(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct request *rq; + + /* + * end current dma transaction + */ + (void) hwif->dmaproc(ide_dma_end, drive); + + /* + * complain a little, later we might remove some of this verbosity + */ + printk("%s: timeout waiting for DMA\n", drive->name); + (void) hwif->dmaproc(ide_dma_timeout, drive); + + /* + * disable dma for now, but remember that we did so because of + * a timeout -- we'll reenable after we finish this next request + * (or rather the first chunk of it) in pio. + */ + drive->retry_pio++; + drive->state = DMA_PIO_RETRY; + (void) hwif->dmaproc(ide_dma_off_quietly, drive); + + /* + * un-busy drive etc (hwgroup->busy is cleared on return) and + * make sure request is sane + */ + rq = HWGROUP(drive)->rq; + HWGROUP(drive)->rq = NULL; + + rq->errors = 0; + rq->sector = rq->bh->b_rsector; + rq->current_nr_sectors = rq->bh->b_size >> 9; + rq->buffer = rq->bh->b_data; +} + +/* * ide_timer_expiry() is our timeout function for all drive operations. * But note that it can also be invoked as a result of a "sleep" operation * triggered by the mod_timer() call in ide_do_request. @@ -1491,11 +1544,10 @@ startstop = handler(drive); } else { if (drive->waiting_for_dma) { - (void) hwgroup->hwif->dmaproc(ide_dma_end, drive); - printk("%s: timeout waiting for DMA\n", drive->name); - (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive); - } - startstop = ide_error(drive, "irq timeout", GET_STAT()); + startstop = ide_stopped; + ide_dma_timeout_retry(drive); + } else + startstop = ide_error(drive, "irq timeout", GET_STAT()); } set_recovery_timer(hwif); drive->service_time = jiffies - drive->service_start; --- ../linux-2.4.5-ac3-clean/include/linux/ide.h Mon May 28 20:28:13 2001 +++ include/linux/ide.h Mon May 28 20:21:18 2001 @@ -87,6 +87,11 @@ #define ERROR_RECAL 1 /* Recalibrate every 2nd retry */ /* + * state flags + */ +#define DMA_PIO_RETRY 1 /* retrying in PIO */ + +/* * Ensure that various configuration flags have compatible settings */ #ifdef REALLY_SLOW_IO @@ -299,6 +304,8 @@ special_t special; /* special action flags */ byte keep_settings; /* restore settings after drive reset */ byte using_dma; /* disk is using dma for read/write */ + byte retry_pio; /* retrying dma capable host in pio */ + byte state; /* retry state */ byte waiting_for_dma; /* dma currently in progress */ byte unmask; /* flag: okay to unmask other irqs */ byte slow; /* flag: slow data port */