diff options
author | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-03-25 13:11:59 +0000 |
---|---|---|
committer | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 2001-03-25 13:11:59 +0000 |
commit | e062b2ded8bea4b44e6b5782a79fabbebb2eb929 (patch) | |
tree | 2b254b38691ca1d18309eaf5b10ebcde5eb617ac /sys/dev/ata | |
parent | f8ee0399c6e8a97e07e33bfdd2cf4ed7bd611704 (diff) |
Minor mods to DMA interface - get rid of unnecessary args. Allow DMA functions to return status flags.
Note: Changing code to have DMA interface indicate when I/O is done (a la NetBSD) was considered. It was rejected due to questionable backward compatability
with ISA DMA and MAC obio DMA
Added irqack from NetBSD (though this feature should really be in the
PCI interrupt handlers)
Use pool
Diffstat (limited to 'sys/dev/ata')
-rw-r--r-- | sys/dev/ata/ata.c | 26 | ||||
-rw-r--r-- | sys/dev/ata/ata_wdc.c | 51 | ||||
-rw-r--r-- | sys/dev/ata/atavar.h | 10 |
3 files changed, 63 insertions, 24 deletions
diff --git a/sys/dev/ata/ata.c b/sys/dev/ata/ata.c index b9ce6f180b8..5a235e9102b 100644 --- a/sys/dev/ata/ata.c +++ b/sys/dev/ata/ata.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ata.c,v 1.9 2001/01/29 02:18:33 niklas Exp $ */ +/* $OpenBSD: ata.c,v 1.10 2001/03/25 13:11:55 csapuntz Exp $ */ /* $NetBSD: ata.c,v 1.9 1999/04/15 09:41:09 bouyer Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. All rights reserved. @@ -196,6 +196,30 @@ ata_set_mode(drvp, mode, flags) } void +ata_dmaerr(drvp) + struct ata_drive_datas *drvp; +{ + /* + * Downgrade decision: if we get NERRS_MAX in NXFER. + * We start with n_dmaerrs set to NERRS_MAX-1 so that the + * first error within the first NXFER ops will immediatly trigger + * a downgrade. + * If we got an error and n_xfers is bigger than NXFER reset counters. + */ + drvp->n_dmaerrs++; + if (drvp->n_dmaerrs >= NERRS_MAX && drvp->n_xfers <= NXFER) { + wdc_downgrade_mode(drvp); + drvp->n_dmaerrs = NERRS_MAX-1; + drvp->n_xfers = 0; + return; + } + if (drvp->n_xfers > NXFER) { + drvp->n_dmaerrs = 1; /* just got an error */ + drvp->n_xfers = 1; /* restart counting from this error */ + } +} + +void ata_perror(drvp, errno, buf) struct ata_drive_datas *drvp; int errno; diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c index dba5130af66..2b5101fd9c4 100644 --- a/sys/dev/ata/ata_wdc.c +++ b/sys/dev/ata/ata_wdc.c @@ -218,14 +218,15 @@ _wdc_ata_bio_start(chp, xfer) } if (xfer->c_flags & C_DMA) { + if (drvp->n_xfers <= NXFER) + drvp->n_xfers++; dma_flags = (ata_bio->flags & ATA_READ) ? WDC_DMA_READ : 0; - dma_flags |= (ata_bio->flags & ATA_POLL) ? WDC_DMA_POLL : 0; } if (ata_bio->flags & ATA_SINGLE) ata_delay = ATA_DELAY; else ata_delay = ATA_DELAY; - again: +again: /* * * When starting a multi-sector transfer, or doing single-sector @@ -300,7 +301,7 @@ _wdc_ata_bio_start(chp, xfer) head, sect, nblks, 0); /* start the DMA channel */ (*chp->wdc->dma_start)(chp->wdc->dma_arg, - chp->channel, xfer->drive, dma_flags); + chp->channel, xfer->drive); /* wait for irq */ goto intr; } /* else not DMA */ @@ -349,7 +350,7 @@ _wdc_ata_bio_start(chp, xfer) ata_bio->nbytes); } - intr: /* Wait for IRQ (either real or polled) */ +intr: /* Wait for IRQ (either real or polled) */ if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; } else { @@ -360,7 +361,7 @@ _wdc_ata_bio_start(chp, xfer) goto again; } return; - timeout: +timeout: printf("%s:%d:%d: not ready, st=0x%02x, err=0x%02x\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, chp->ch_status, chp->ch_error); @@ -379,7 +380,6 @@ wdc_ata_bio_intr(chp, xfer, irq) struct ata_bio *ata_bio = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; int drv_err; - int dma_flags = 0; WDCDEBUG_PRINT(("wdc_ata_bio_intr %s:%d:%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), @@ -394,11 +394,6 @@ wdc_ata_bio_intr(chp, xfer, irq) panic("wdc_ata_bio_intr: bad state\n"); } - if (xfer->c_flags & C_DMA) { - dma_flags = (ata_bio->flags & ATA_READ) ? WDC_DMA_READ : 0; - dma_flags |= (ata_bio->flags & ATA_POLL) ? WDC_DMA_POLL : 0; - } - /* * if we missed an interrupt in a PIO transfer, reset and restart. * Don't try to continue transfer, we may have missed cycles. @@ -417,17 +412,21 @@ wdc_ata_bio_intr(chp, xfer, irq) printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, xfer->c_bcount, xfer->c_skip); - /* if we were using DMA, turn off DMA channel */ + + /* if we were using DMA, stop channel and deal with error */ if (xfer->c_flags & C_DMA) { - (*chp->wdc->dma_finish)(chp->wdc->dma_arg, - chp->channel, xfer->drive, dma_flags); - drvp->n_dmaerrs++; + chp->wdc->dma_status = + (*chp->wdc->dma_finish)(chp->wdc->dma_arg, + chp->channel, + xfer->drive); + ata_dmaerr(drvp); } + ata_bio->error = TIMEOUT; wdc_ata_bio_done(chp, xfer); return 1; } - + drv_err = wdc_ata_err(drvp, ata_bio); /* If we were using DMA, Turn off the DMA channel and check for error */ @@ -448,8 +447,11 @@ wdc_ata_bio_intr(chp, xfer, irq) drv_err = WDC_ATA_ERR; } } - if ((*chp->wdc->dma_finish)(chp->wdc->dma_arg, - chp->channel, xfer->drive, dma_flags) != 0) { + + chp->wdc->dma_status = + (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel, + xfer->drive); + if (chp->wdc->dma_status != 0) { if (drv_err != WDC_ATA_ERR) { ata_bio->error = ERR_DMA; drv_err = WDC_ATA_ERR; @@ -466,9 +468,12 @@ wdc_ata_bio_intr(chp, xfer, irq) } if (drv_err != WDC_ATA_ERR) goto end; - drvp->n_dmaerrs++; + ata_dmaerr(drvp); } + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); + /* if we had an error, end */ if (drv_err == WDC_ATA_ERR) { wdc_ata_bio_done(chp, xfer); @@ -614,6 +619,8 @@ again: errstring = "piomode"; if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)) goto timeout; + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) goto error; /* fall through */ @@ -634,6 +641,8 @@ again: errstring = "dmamode"; if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)) goto timeout; + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) goto error; /* fall through */ @@ -654,6 +663,8 @@ again: errstring = "geometry"; if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)) goto timeout; + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) goto error; /* fall through */ @@ -671,6 +682,8 @@ again: errstring = "setmulti"; if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay)) goto timeout; + if (chp->wdc->cap & WDC_CAPABILITY_IRQACK) + chp->wdc->irqack(chp); if (chp->ch_status & (WDCS_ERR | WDCS_DWF)) goto error; /* fall through */ diff --git a/sys/dev/ata/atavar.h b/sys/dev/ata/atavar.h index 8448949adcd..0ba26ac2922 100644 --- a/sys/dev/ata/atavar.h +++ b/sys/dev/ata/atavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: atavar.h,v 1.5 2000/04/10 07:06:16 csapuntz Exp $ */ +/* $OpenBSD: atavar.h,v 1.6 2001/03/25 13:11:56 csapuntz Exp $ */ /* $NetBSD: atavar.h,v 1.13 1999/03/10 13:11:43 bouyer Exp $ */ /* @@ -79,10 +79,10 @@ struct ata_drive_datas { /* 0x20-0x40 reserved for ATAPI_CFG_DRQ_MASK */ u_int8_t atapi_cap; - /* Number of DMA errors. Reset to 0 after every successful transfers. */ u_int8_t n_dmaerrs; - /* downgrade mode after this many successive errors */ -#define NERRS_MAX 2 + u_int32_t n_xfers; +#define NERRS_MAX 4 +#define NXFER 1000 char drive_name[31]; int cf_flags; @@ -168,6 +168,7 @@ void wdc_reset_channel __P((struct ata_drive_datas *)); int wdc_ata_addref __P((struct ata_drive_datas *)); void wdc_ata_delref __P((struct ata_drive_datas *)); +void wdc_ata_kill_pending __P((struct ata_drive_datas *)); struct ataparams; int ata_get_params __P((struct ata_drive_datas*, u_int8_t, @@ -178,4 +179,5 @@ int ata_set_mode __P((struct ata_drive_datas*, u_int8_t, u_int8_t)); #define CMD_ERR 1 #define CMD_AGAIN 2 +void ata_dmaerr __P((struct ata_drive_datas *)); void ata_perror __P((struct ata_drive_datas *, int, char *)); |