Apply by doing: cd /usr/src patch -p0 < 009_atapi.patch And then rebuild your kernel. Index: sys/dev/ata/ata.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata.c,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- sys/dev/ata/ata.c 1999/08/05 00:12:09 1.2 +++ sys/dev/ata/ata.c 1999/11/17 01:22:55 1.4 @@ -1,4 +1,4 @@ -/* $OpenBSD: ata.c,v 1.2 1999/08/05 00:12:09 niklas Exp $ */ +/* $OpenBSD: ata.c,v 1.4 1999/11/17 01:22: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. @@ -29,10 +29,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WDCDEBUG -#define WDCDEBUG -#endif /* WDCDEBUG */ - #include #include #include @@ -57,6 +53,8 @@ #define WDCDEBUG_PRINT(args, level) #endif +#define ATAPARAMS_SIZE 512 + /* Get the disk's parameters */ int ata_get_params(drvp, flags, prms) @@ -64,17 +62,15 @@ u_int8_t flags; struct ataparams *prms; { - char tb[DEV_BSIZE]; + char tb[ATAPARAMS_SIZE]; struct wdc_command wdc_c; -#if BYTE_ORDER == LITTLE_ENDIAN int i; u_int16_t *p; -#endif WDCDEBUG_PRINT(("wdc_ata_get_parms\n"), DEBUG_FUNCS); - bzero(tb, DEV_BSIZE); + bzero(tb, sizeof(tb)); bzero(prms, sizeof(struct ataparams)); bzero(&wdc_c, sizeof(struct wdc_command)); @@ -93,7 +89,7 @@ } wdc_c.flags = AT_READ | flags; wdc_c.data = tb; - wdc_c.bcount = DEV_BSIZE; + wdc_c.bcount = ATAPARAMS_SIZE; { int ret; @@ -106,9 +102,24 @@ if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { return CMD_ERR; } else { +#if BYTE_ORDER == BIG_ENDIAN + /* All the fields in the params structure are 16-bit + integers except for the ID strings which are char + strings. The 16-bit integers are currently in + memory in little-endian, regardless of architecture. + So, they need to be swapped on big-endian architectures + before they are accessed through the ataparams structure. + + The swaps below avoid touching the char strings. + */ + + swap16_multi((u_int16_t *)tb, 10); + swap16_multi((u_int16_t *)tb + 20, 3); + swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47); +#endif /* Read in parameter block. */ bcopy(tb, prms, sizeof(struct ataparams)); -#if BYTE_ORDER == LITTLE_ENDIAN + /* * Shuffle string byte order. * ATAPI Mitsumi and NEC drives don't need this. @@ -122,17 +133,17 @@ return 0; for (i = 0; i < sizeof(prms->atap_model); i += 2) { p = (u_short *)(prms->atap_model + i); - *p = ntohs(*p); + *p = swap16(*p); } for (i = 0; i < sizeof(prms->atap_serial); i += 2) { p = (u_short *)(prms->atap_serial + i); - *p = ntohs(*p); + *p = swap16(*p); } for (i = 0; i < sizeof(prms->atap_revision); i += 2) { p = (u_short *)(prms->atap_revision + i); - *p = ntohs(*p); + *p = swap16(*p); } -#endif + return CMD_OK; } } Index: sys/dev/ata/ata_wdc.c =================================================================== RCS file: /cvs/src/sys/dev/ata/ata_wdc.c,v retrieving revision 1.1 retrieving revision 1.4 diff -u -r1.1 -r1.4 --- sys/dev/ata/ata_wdc.c 1999/07/18 21:25:17 1.1 +++ sys/dev/ata/ata_wdc.c 1999/11/17 01:22:55 1.4 @@ -1,5 +1,4 @@ -/* $OpenBSD: ata_wdc.c,v 1.1 1999/07/18 21:25:17 csapuntz Exp $ */ -/* $NetBSD: ata_wdc.c,v 1.19 1999/04/01 21:46:28 bouyer Exp $ */ +/* $NetBSD: ata_wdc.c,v 1.21 1999/08/09 09:43:11 bouyer Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. @@ -70,10 +69,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WDCDEBUG -#define WDCDEBUG -#endif /* WDCDEBUG */ - #include #include #include @@ -88,12 +83,6 @@ #include #include -#ifndef __BUS_SPACE_HAS_STREAM_METHODS -#define bus_space_write_multi_stream_2 bus_space_write_multi_2 -#define bus_space_write_multi_stream_4 bus_space_write_multi_4 -#define bus_space_read_multi_stream_2 bus_space_read_multi_2 -#define bus_space_read_multi_stream_4 bus_space_read_multi_4 -#endif /* __BUS_SPACE_HAS_STREAM_METHODS */ #include #include @@ -124,6 +113,7 @@ #endif void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); +void _wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *)); int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *, int)); void wdc_ata_bio_done __P((struct channel_softc *, struct wdc_xfer *)); int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *, int)); @@ -168,6 +158,22 @@ struct wdc_xfer *xfer; { struct ata_bio *ata_bio = xfer->cmd; + WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n", + chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), + DEBUG_XFERS); + + /* start timeout machinery */ + if ((ata_bio->flags & ATA_POLL) == 0) + timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz); + _wdc_ata_bio_start(chp, xfer); +} + +void +_wdc_ata_bio_start(chp, xfer) + struct channel_softc *chp; + struct wdc_xfer *xfer; +{ + struct ata_bio *ata_bio = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; u_int16_t cyl; u_int8_t head, sect, cmd = 0; @@ -175,10 +181,9 @@ int ata_delay; int dma_flags = 0; - WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n", + WDCDEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), - DEBUG_XFERS); - + DEBUG_INTR | DEBUG_XFERS); /* Do control operations specially. */ if (drvp->state < READY) { /* @@ -188,22 +193,19 @@ */ /* at this point, we should only be in RECAL state */ if (drvp->state != RECAL) { - printf("%s:%d:%d: bad state %d in wdc_ata_bio_start\n", + printf("%s:%d:%d: bad state %d in _wdc_ata_bio_start\n", chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, drvp->state); - panic("wdc_ata_bio_start: bad state"); + panic("_wdc_ata_bio_start: bad state"); } xfer->c_intr = wdc_ata_ctrl_intr; - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (xfer->drive << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4)); if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY) != 0) goto timeout; wdccommandshort(chp, xfer->drive, WDCC_RECAL); drvp->state = RECAL_WAIT; if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, - ATA_DELAY / 1000 * hz); } else { /* Wait for at last 400ns for status bit to be valid */ DELAY(1); @@ -287,7 +289,7 @@ return; } /* Initiate command */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4)); if (wait_for_ready(chp, ata_delay) < 0) goto timeout; @@ -309,8 +311,7 @@ WDCC_READ : WDCC_WRITE; } /* Initiate command! */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (xfer->drive << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4)); if (wait_for_ready(chp, ata_delay) < 0) goto timeout; wdccommand(chp, xfer->drive, cmd, cyl, @@ -341,41 +342,13 @@ wdc_ata_bio_done(chp, xfer); return; } - if ((chp->wdc->cap & WDC_CAPABILITY_ATA_NOSTREAM)) { - if (drvp->drive_flags & DRIVE_CAP32) { - bus_space_write_multi_4(chp->data32iot, - chp->data32ioh, 0, - (u_int32_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 2); - } else { - bus_space_write_multi_2(chp->cmd_iot, - chp->cmd_ioh, wd_data, - (u_int16_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 1); - } - } else { - if (drvp->drive_flags & DRIVE_CAP32) { - bus_space_write_multi_stream_4(chp->data32iot, - chp->data32ioh, 0, - (u_int32_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 2); - } else { - bus_space_write_multi_stream_2(chp->cmd_iot, - chp->cmd_ioh, wd_data, - (u_int16_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 1); - } - } + wdc_output_bytes(drvp, (char *)xfer->databuf + xfer->c_skip, + ata_bio->nbytes); } intr: /* Wait for IRQ (either real or polled) */ if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, ata_delay / 1000 * hz); } else { /* Wait for at last 400ns for status bit to be valid */ delay(1); @@ -423,6 +396,16 @@ 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. + */ + if ((xfer->c_flags & (C_TIMEOU | C_DMA)) == C_TIMEOU) { + ata_bio->error = TIMEOUT; + wdc_ata_bio_done(chp, xfer); + return 1; + } + /* Ack interrupt done by wait_for_unbusy */ if (wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0) < 0) { @@ -498,38 +481,10 @@ ata_bio->error = TIMEOUT; wdc_ata_bio_done(chp, xfer); return 1; - } - if ((chp->wdc->cap & WDC_CAPABILITY_ATA_NOSTREAM)) { - if (drvp->drive_flags & DRIVE_CAP32) { - bus_space_read_multi_4(chp->data32iot, - chp->data32ioh, 0, - (u_int32_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 2); - } else { - bus_space_read_multi_2(chp->cmd_iot, - chp->cmd_ioh, wd_data, - (u_int16_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 1); - } - } else { - if (drvp->drive_flags & DRIVE_CAP32) { - bus_space_read_multi_stream_4(chp->data32iot, - chp->data32ioh, 0, - (u_int32_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 2); - } else { - bus_space_read_multi_stream_2(chp->cmd_iot, - chp->cmd_ioh, wd_data, - (u_int16_t *)((char *)xfer->databuf + - xfer->c_skip), - ata_bio->nbytes >> 1); - } } + wdc_input_bytes(drvp, (char *)xfer->databuf + xfer->c_skip, + ata_bio->nbytes); } - end: ata_bio->blkno += ata_bio->nblks; ata_bio->blkdone += ata_bio->nblks; @@ -539,9 +494,9 @@ if (xfer->c_bcount > 0) { if ((ata_bio->flags & ATA_POLL) == 0) { /* Start the next operation */ - wdc_ata_bio_start(chp, xfer); + _wdc_ata_bio_start(chp, xfer); } else { - /* Let wdc_ata_bio_start do the loop */ + /* Let _wdc_ata_bio_start do the loop */ return 1; } } else { /* Done with this transfer */ @@ -557,7 +512,6 @@ struct wdc_xfer *xfer; { struct ata_bio *ata_bio = xfer->cmd; - int need_done = xfer->c_flags & C_NEEDDONE; int drive = xfer->drive; struct ata_drive_datas *drvp = &chp->ch_drive[drive]; @@ -566,6 +520,7 @@ (u_int)xfer->c_flags), DEBUG_XFERS); + untimeout(wdctimeout, chp); if (ata_bio->error == NOERROR) drvp->n_dmaerrs = 0; else if (drvp->n_dmaerrs >= NERRS_MAX) { @@ -579,7 +534,7 @@ wdc_free_xfer(chp, xfer); ata_bio->flags |= ATA_ITSDONE; - if (need_done) { + if ((ata_bio->flags & ATA_POLL) == 0) { WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS); wddone(chp->ch_drive[drive].drv_softc); } @@ -703,13 +658,12 @@ * The drive is usable now */ xfer->c_intr = wdc_ata_bio_intr; - wdc_ata_bio_start(chp, xfer); + _wdc_ata_bio_start(chp, xfer); return 1; } if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz); } else { goto again; } Index: sys/dev/ata/wd.c =================================================================== RCS file: /cvs/src/sys/dev/ata/wd.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- sys/dev/ata/wd.c 1999/10/09 07:14:00 1.9 +++ sys/dev/ata/wd.c 1999/11/17 01:22:55 1.10 @@ -1,4 +1,4 @@ -/* $OpenBSD: wd.c,v 1.9 1999/10/09 07:14:00 csapuntz Exp $ */ +/* $OpenBSD: wd.c,v 1.10 1999/11/17 01:22:55 csapuntz Exp $ */ /* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */ /* @@ -65,10 +65,6 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef WDCDEBUG -#define WDCDEBUG -#endif /* WDCDEBUG */ #if 0 #include "rnd.h" Index: sys/dev/pci/pciide.c =================================================================== RCS file: /cvs/src/sys/dev/pci/pciide.c,v retrieving revision 1.11 retrieving revision 1.15 diff -u -r1.11 -r1.15 --- sys/dev/pci/pciide.c 1999/10/09 03:42:04 1.11 +++ sys/dev/pci/pciide.c 1999/11/23 20:48:35 1.15 @@ -1,4 +1,4 @@ -/* $OpenBSD: pciide.c,v 1.11 1999/10/09 03:42:04 csapuntz Exp $ */ +/* $OpenBSD: pciide.c,v 1.15 1999/11/23 20:48:35 chris Exp $ */ /* $NetBSD: pciide.c,v 1.40 1999/07/12 13:49:38 bouyer Exp $ */ /* @@ -43,10 +43,6 @@ * */ -#ifndef WDCDEBUG -#define WDCDEBUG -#endif - #define DEBUG_DMA 0x01 #define DEBUG_XFERS 0x02 #define DEBUG_FUNCS 0x08 @@ -230,11 +226,11 @@ 0, piix_chip_map }, - { PCI_PRODUCT_INTEL_82801AA_IDE, + { PCI_PRODUCT_INTEL_82801AA_IDE, /* Intel 82801AA IDE (ICH) */ 0, piix_chip_map, }, - { PCI_PRODUCT_INTEL_82801AB_IDE, + { PCI_PRODUCT_INTEL_82801AB_IDE, /* Intel 82801AB IDE (ICH0) */ 0, piix_chip_map, }, @@ -274,7 +270,7 @@ }; const struct pciide_product_desc pciide_sis_products[] = { - { PCI_PRODUCT_SIS_5597, /* SIS 5597/5598 IDE */ + { PCI_PRODUCT_SIS_5513, /* SIS 5513 EIDE */ 0, sis_chip_map } @@ -1113,7 +1109,7 @@ } else { pciide_mapreg_dma(sc, pa); if (sc->sc_dma_ok != 0) - printf(", (partial support) "); + printf(", (partial support)"); } } else { printf(": no DMA"); @@ -1297,7 +1293,7 @@ PIIX_IDETIM_IDE) == 0) { printf("%s: %s ignored (disabled)\n", sc->sc_wdcdev.sc_dev.dv_xname, cp->name); - return; + continue; } /* PIIX are compat-only pciide devices */ pciide_mapchan(pa, cp, 0, &cmdsize, &ctlsize, pciide_pci_intr); @@ -1689,7 +1685,7 @@ if ((ideconf & APO_IDECONF_EN(channel)) == 0) { printf("%s: %s ignored (disabled)\n", sc->sc_wdcdev.sc_dev.dv_xname, cp->name); - return; + continue; } pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, pciide_pci_intr); @@ -2192,7 +2188,7 @@ (channel == 1 && (sis_ctr0 & SIS_CTRL0_CHAN1_EN) == 0)) { printf("%s: %s ignored (disabled)\n", sc->sc_wdcdev.sc_dev.dv_xname, cp->name); - return; + continue; } pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, pciide_pci_intr); @@ -2574,7 +2570,7 @@ WDCDEBUG_PRINT(("pdc202xx_setup_chip: new controller state 0x%x\n", st), DEBUG_PROBE); pci_conf_write(sc->sc_pc, sc->sc_tag, PDC2xx_STATE, st); -return; + return; } void Index: sys/dev/atapiscsi/atapiscsi.c =================================================================== RCS file: /cvs/src/sys/dev/atapiscsi/atapiscsi.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- sys/dev/atapiscsi/atapiscsi.c 1999/11/02 01:43:40 1.18 +++ sys/dev/atapiscsi/atapiscsi.c 1999/11/17 01:22:55 1.19 @@ -1,4 +1,4 @@ -/* $OpenBSD: atapiscsi.c,v 1.18 1999/11/02 01:43:40 deraadt Exp $ */ +/* $OpenBSD: atapiscsi.c,v 1.19 1999/11/17 01:22:55 csapuntz Exp $ */ /* * This code is derived from code with the copyright below. @@ -68,7 +68,6 @@ #include -#define WDCDEBUG #define DEBUG_INTR 0x01 #define DEBUG_XFERS 0x02 #define DEBUG_STATUS 0x04 @@ -124,6 +123,7 @@ struct channel_softc *chp; enum atapi_state { as_none, as_cmdout, as_data } protocol_phase; + int retries; int diagnostics_printed; #define ATAPI_DIAG_UNEXP_CMD 0x01 #define ATAPI_DIAG_POLARITY 0x02 @@ -335,7 +335,7 @@ } drvp->state = 0; - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); + CHP_READ_REG(chp, wdr_status); /* Some ATAPI devices need a bit more time after software reset. */ delay(5000); @@ -357,7 +357,6 @@ int drive = sc_xfer->sc_link->target; struct channel_softc *chp = as->chp; struct ata_drive_datas *drvp = &chp->ch_drive[drive]; - struct wdc_softc *wdc = chp->wdc; struct wdc_xfer *xfer; int flags = sc_xfer->flags; int s, ret, saved_datalen; @@ -367,7 +366,7 @@ saved_datalen = 0; WDCDEBUG_PRINT(("wdc_atapi_send_cmd %s:%d:%d\n", - wdc->sc_dev.dv_xname, chp->channel, drive), DEBUG_XFERS); + chp->wdc->sc_dev.dv_xname, chp->channel, drive), DEBUG_XFERS); if (drive > 1 || !(drvp->drive_flags & DRIVE_ATAPI)) { sc_xfer->error = XS_DRIVER_STUFFUP; @@ -568,6 +567,7 @@ (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0); as->protocol_phase = as_cmdout; + as->retries = 0; /* * If there is no interrupt for CMD input, busy-wait for it (done in @@ -616,106 +616,105 @@ /* We should really wait_for_unbusy here too before switching drives. */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (drvp->drive << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drvp->drive << 4)); return (wait_for_unbusy(chp, 0) == 0); } + +int wdc_atapi_intr_command __P((struct channel_softc *, struct wdc_xfer *, int)); +int wdc_atapi_intr_data __P((struct channel_softc *, struct wdc_xfer *, int)); +int wdc_atapi_intr_complete __P((struct channel_softc *, struct wdc_xfer *, int)); -int wdc_atapi_intr_drq __P((struct channel_softc *, struct wdc_xfer *, int)); int -wdc_atapi_intr_drq(chp, xfer, irq) +wdc_atapi_intr_command(chp, xfer, dma_flags) struct channel_softc *chp; struct wdc_xfer *xfer; - int irq; - + int dma_flags; { struct scsi_xfer *sc_xfer = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; - int len, phase, i; - int ire; - int dma_flags = 0; + int i; u_int8_t cmd[16]; struct scsi_sense *cmd_reqsense; int cmdlen = (drvp->atapi_cap & ACAP_LEN) ? 16 : 12; - if (xfer->c_flags & C_DMA) { - dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) || - (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0; - dma_flags |= ((sc_xfer->flags & SCSI_POLL) || - (drvp->atapi_cap & ACAP_DSC)) ? WDC_DMA_POLL : 0; - } + bzero(cmd, sizeof(cmd)); - - if (as->protocol_phase == as_cmdout) { - bzero(cmd, sizeof(cmd)); + if (xfer->c_flags & C_SENSE) { + cmd_reqsense = (struct scsi_sense *)&cmd[0]; + cmd_reqsense->opcode = REQUEST_SENSE; + cmd_reqsense->length = xfer->c_bcount; + } else + bcopy(sc_xfer->cmd, cmd, sc_xfer->cmdlen); + + for (i = 0; i < 12; i++) + WDCDEBUG_PRINT(("%02x ", cmd[i]), DEBUG_INTR); + WDCDEBUG_PRINT((": PHASE_CMDOUT\n"), DEBUG_INTR); - if (xfer->c_flags & C_SENSE) { - cmd_reqsense = (struct scsi_sense *)&cmd[0]; - cmd_reqsense->opcode = REQUEST_SENSE; - cmd_reqsense->length = xfer->c_bcount; - } else - bcopy(sc_xfer->cmd, cmd, sc_xfer->cmdlen); - - for (i = 0; i < 12; i++) - WDCDEBUG_PRINT(("%02x ", cmd[i]), DEBUG_INTR); - WDCDEBUG_PRINT((": PHASE_CMDOUT\n"), DEBUG_INTR); - - /* Init the DMA channel if necessary */ - if (xfer->c_flags & C_DMA) { - if ((*chp->wdc->dma_init)(chp->wdc->dma_arg, - chp->channel, xfer->drive, xfer->databuf, - xfer->c_bcount, dma_flags) != 0) { - sc_xfer->error = XS_DRIVER_STUFFUP; - wdc_atapi_done(chp, xfer); - return (1); - } + /* Init the DMA channel if necessary */ + if (xfer->c_flags & C_DMA) { + if ((*chp->wdc->dma_init)(chp->wdc->dma_arg, + chp->channel, xfer->drive, xfer->databuf, + xfer->c_bcount, dma_flags) != 0) { + sc_xfer->error = XS_DRIVER_STUFFUP; + wdc_atapi_done(chp, xfer); + return (1); } - + } - wdc_output_bytes(drvp, cmd, cmdlen); + wdc_output_bytes(drvp, cmd, cmdlen); - as->protocol_phase = as_data; + as->protocol_phase = as_data; - /* Start the DMA channel if necessary */ - if (xfer->c_flags & C_DMA) { - (*chp->wdc->dma_start)(chp->wdc->dma_arg, - chp->channel, xfer->drive, - dma_flags); - } + /* Start the DMA channel if necessary */ + if (xfer->c_flags & C_DMA) { + (*chp->wdc->dma_start)(chp->wdc->dma_arg, + chp->channel, xfer->drive, + dma_flags); + } - if ((sc_xfer->flags & SCSI_POLL) == 0 && - (drvp->atapi_cap & ACAP_DSC) == 0) { - chp->ch_flags |= WDCF_IRQ_WAIT; - timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); - } + if ((sc_xfer->flags & SCSI_POLL) == 0 && + (drvp->atapi_cap & ACAP_DSC) == 0) { + chp->ch_flags |= WDCF_IRQ_WAIT; + timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000); + } - /* If we read/write to a tape we will get into buffer - availability mode. */ - if (drvp->atapi_cap & ACAP_DSC) { - if (!(drvp->drive_flags & DRIVE_DSCBA) && - (sc_xfer->cmd->opcode == READ || - sc_xfer->cmd->opcode == WRITE)) { - drvp->drive_flags |= DRIVE_DSCBA; - WDCDEBUG_PRINT(("set DSCBA\n"), DEBUG_DSC); - } - if (sc_xfer->cmd->opcode == READ) - drvp->drive_flags |= DRIVE_DSCWAIT; + /* If we read/write to a tape we will get into buffer + availability mode. */ + if (drvp->atapi_cap & ACAP_DSC) { + if (!(drvp->drive_flags & DRIVE_DSCBA) && + (sc_xfer->cmd->opcode == READ || + sc_xfer->cmd->opcode == WRITE)) { + drvp->drive_flags |= DRIVE_DSCBA; + WDCDEBUG_PRINT(("set DSCBA\n"), DEBUG_DSC); } - return (1); + if (sc_xfer->cmd->opcode == READ) + drvp->drive_flags |= DRIVE_DSCWAIT; } + return (1); - if (as->protocol_phase != as_data) { - panic ("wdc_atapi_intr_drq: bad protocol phase"); - } +} + +int +wdc_atapi_intr_data(chp, xfer, dma_flags) + struct channel_softc *chp; + struct wdc_xfer *xfer; + int dma_flags; + +{ + struct scsi_xfer *sc_xfer = xfer->cmd; + struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; + struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; + int len, ire; + char *message = 0; - len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo) + - 256 * bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi); - ire = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_ireason); - phase = (ire & (WDCI_CMD | WDCI_IN)) | (chp->ch_status & WDCS_DRQ); + len = (CHP_READ_REG(chp, wdr_cyl_hi) << 8) | + CHP_READ_REG(chp, wdr_cyl_lo); + ire = CHP_READ_REG(chp, wdr_ireason); + WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x " "ire 0x%x :", xfer->c_bcount, len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR); @@ -723,42 +722,41 @@ /* Possibility to explore; what if we get an interrupt during DMA ? */ if ((xfer->c_flags & C_DMA) != 0) { - printf("wdc_atapi_intr_drq: Unexpected " - "interrupt during DMA mode"); + if ((xfer->c_flags & C_TIMEOU) == 0) + message = "unexpected interrupt during DMA mode"; - goto abort_data; + goto unexpected_state; } - if (ire & WDCI_CMD) { - /* Something messed up */ - if (!(as->diagnostics_printed & ATAPI_DIAG_UNEXP_CMD)) { - printf ("wdc_atapi_intr_drq: Unexpectedly " - "in the command phase. Please report this.\n"); - as->diagnostics_printed |= ATAPI_DIAG_UNEXP_CMD; - } - goto abort_data; + message = "unexpectedly in command phase"; + goto unexpected_state; } + + if (!(xfer->c_flags & C_SENSE)) { + if (!(sc_xfer->flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) { + message = "data phase where none expected"; + goto unexpected_state; + } - /* Make sure polarities match */ - if (((ire & WDCI_IN) == WDCI_IN) == - ((sc_xfer->flags & SCSI_DATA_OUT) == SCSI_DATA_OUT)) { - if (!(as->diagnostics_printed & ATAPI_DIAG_POLARITY)) { - printf ("wdc_atapi_intr_drq: Polarity problem " - "in transfer. Please report this.\n"); - as->diagnostics_printed |= ATAPI_DIAG_POLARITY; + /* Make sure polarities match */ + if (((ire & WDCI_IN) == WDCI_IN) == + ((sc_xfer->flags & SCSI_DATA_OUT) == SCSI_DATA_OUT)) { + message = "data transfer direction disagreement"; + goto unexpected_state; } - goto abort_data; + } else { + if (!(ire & WDCI_IN)) { + message = "data transfer direction disagreement during sense"; + goto unexpected_state; + } } - WDCDEBUG_PRINT(("PHASE_DATA\n"), DEBUG_INTR); - if (len == 0) { - printf("wdc_atapi_intr_drq: length 0 transfer in " - "data phase\n"); - goto abort_data; + message = "zero length transfer requested in data phase"; + goto unexpected_state; } - + if (xfer->c_bcount >= len) { /* Common case */ if (sc_xfer->flags & SCSI_DATA_OUT) @@ -779,9 +777,8 @@ wdc_output_bytes(drvp, (u_int8_t *)xfer->databuf + xfer->c_skip, xfer->c_bcount); - for (i = xfer->c_bcount; i < len; i += 2) - bus_space_write_2(chp->cmd_iot, chp->cmd_ioh, - wd_data, 0); + CHP_WRITE_RAW_MULTI_2(chp, NULL, + len - xfer->c_bcount); } else { printf("wdc_atapi_intr: warning: reading only " "%d of %d bytes\n", xfer->c_bcount, len); @@ -803,8 +800,29 @@ } else if (drvp->atapi_cap & ACAP_DSC) drvp->drive_flags |= DRIVE_DSCWAIT; return (1); + + unexpected_state: - abort_data: + /* If we're in polling mode, then it's possible we caught + a drive in some awkward, intermediate state. Of course, + the drive should have BSY set while it's transitioning + through awkward states, but this may not always + be the case. */ + + /* Spurious interrupts can cause us pain too and we don't deal + with those nearly as well. We assume the spurious + interrupts are random and won't affect us on retry */ + if (xfer->c_flags & C_POLL) { + DELAY(1000); + as->retries++; + /* Give the drive up to 2 seconds to fix itself */ + if (as->retries <= 2000) + return (1); + } + + if (message) + printf ("wdc_atapi_intr_drq: %s\n", message); + if (xfer->c_flags & C_DMA) { (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel, xfer->drive, dma_flags); @@ -819,63 +837,16 @@ int -wdc_atapi_intr(chp, xfer, irq) +wdc_atapi_intr_complete(chp, xfer, dma_flags) struct channel_softc *chp; struct wdc_xfer *xfer; - int irq; + int dma_flags; + { struct scsi_xfer *sc_xfer = xfer->cmd; struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; int dma_err = 0; - int dma_flags = 0; - - WDCDEBUG_PRINT(("wdc_atapi_intr %s:%d:%d\n", - chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive), - DEBUG_INTR); - - /* Is it not a transfer, but a control operation? */ - if (drvp->state < READY) { - printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n", - chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, - drvp->state); - panic("wdc_atapi_intr: bad state\n"); - } - - /* We should really wait_for_unbusy here too before - switching drives. */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (xfer->drive << 4)); - - /* Ack interrupt done in wait_for_unbusy */ - if (wait_for_unbusy(chp, - (irq == 0) ? sc_xfer->timeout : 0) != 0) { - if (irq && (xfer->c_flags & C_TIMEOU) == 0) - return (0); /* IRQ was not for us */ - 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 (xfer->c_flags & C_DMA) - drvp->n_dmaerrs++; - sc_xfer->error = XS_TIMEOUT; - wdc_atapi_reset(chp, xfer); - return (1); - } - /* If we missed an IRQ and were using DMA, flag it as a DMA error */ - if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) - drvp->n_dmaerrs++; - - if (chp->ch_status & WDCS_DRQ) - return (wdc_atapi_intr_drq(chp, xfer, irq)); - - /* DRQ was dropped. This means the command is over. - Do cleanup, check for errors, etc. */ - if (xfer->c_flags & C_DMA) { - dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) || - (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0; - dma_flags |= ((sc_xfer->flags & SCSI_POLL) || - (drvp->atapi_cap & ACAP_DSC)) ? WDC_DMA_POLL : 0; - } WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR); @@ -885,7 +856,8 @@ dma_err = (*chp->wdc->dma_finish)(chp->wdc->dma_arg, chp->channel, xfer->drive, dma_flags); - /* Assume everything was transferred */ + /* Assume everything was transferred + XXX - maybe we want to check the error register here */ if (xfer->c_flags & C_SENSE) xfer->c_bcount -= sizeof(sc_xfer->sense); else @@ -972,6 +944,69 @@ } int +wdc_atapi_intr(chp, xfer, irq) + struct channel_softc *chp; + struct wdc_xfer *xfer; + int irq; +{ + struct scsi_xfer *sc_xfer = xfer->cmd; + struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive]; + struct atapiscsi_softc *as = sc_xfer->sc_link->adapter_softc; + int dma_flags = 0; + + WDCDEBUG_PRINT(("wdc_atapi_intr %s:%d:%d\n", + chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive), + DEBUG_INTR); + + /* Is it not a transfer, but a control operation? */ + if (drvp->state < READY) { + printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n", + chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, + drvp->state); + panic("wdc_atapi_intr: bad state\n"); + } + + /* We should really wait_for_unbusy here too before + switching drives. */ + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (xfer->drive << 4)); + + /* Ack interrupt done in wait_for_unbusy */ + if (wait_for_unbusy(chp, + (irq == 0) ? sc_xfer->timeout : 0) != 0) { + if (irq && (xfer->c_flags & C_TIMEOU) == 0) + return (0); /* IRQ was not for us */ + 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 (xfer->c_flags & C_DMA) + drvp->n_dmaerrs++; + sc_xfer->error = XS_TIMEOUT; + wdc_atapi_reset(chp, xfer); + return (1); + } + /* If we missed an IRQ and were using DMA, flag it as a DMA error */ + if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) + drvp->n_dmaerrs++; + + /* DRQ was dropped. This means the command is over. + Do cleanup, check for errors, etc. */ + if (xfer->c_flags & C_DMA) { + dma_flags = ((sc_xfer->flags & SCSI_DATA_IN) || + (xfer->c_flags & C_SENSE)) ? WDC_DMA_READ : 0; + dma_flags |= ((sc_xfer->flags & SCSI_POLL) || + (drvp->atapi_cap & ACAP_DSC)) ? WDC_DMA_POLL : 0; + } + + if (chp->ch_status & WDCS_DRQ) { + if (as->protocol_phase == as_cmdout) + return (wdc_atapi_intr_command(chp, xfer, dma_flags)); + else + return (wdc_atapi_intr_data(chp, xfer, dma_flags)); + } else + return (wdc_atapi_intr_complete(chp, xfer, dma_flags)); +} + +int wdc_atapi_ctrl(chp, xfer, irq) struct channel_softc *chp; struct wdc_xfer *xfer; @@ -1005,7 +1040,6 @@ is about the most innocuous thing you can do that's guaranteed to be there */ case IDENTIFY: -#if 1 wdccommandshort(chp, drvp->drive, ATAPI_IDENTIFY_DEVICE); drvp->state = IDENTIFY_WAIT; break; @@ -1026,14 +1060,11 @@ errstring = "Post IDENTIFY"; - delay = ATAPI_DELAY; + if (wdcwait(chp, WDCS_DRQ, 0, 100)) + goto timeout; } drvp->state = PIOMODE; - goto again; -#else - drvp->state = PIOMODE; -#endif case PIOMODE: piomode: /* Don't try to set mode if controller can't be adjusted */ @@ -1182,8 +1213,7 @@ if (chp->ch_flags & WDCF_ACTIVE) return (0); wdc_select_drive(chp, drvp->drive, 0); - chp->ch_status = - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); + chp->ch_status = CHP_READ_REG(chp, wdr_status); return ((chp->ch_status & (WDCS_BSY | WDCS_DSC)) == WDCS_DSC); } Index: sys/dev/ic/wdc.c =================================================================== RCS file: /cvs/src/sys/dev/ic/wdc.c,v retrieving revision 1.12 retrieving revision 1.14 diff -u -r1.12 -r1.14 --- sys/dev/ic/wdc.c 1999/10/29 01:15:15 1.12 +++ sys/dev/ic/wdc.c 1999/11/17 01:22:56 1.14 @@ -1,4 +1,4 @@ -/* $OpenBSD: wdc.c,v 1.12 1999/10/29 01:15:15 deraadt Exp $ */ +/* $OpenBSD: wdc.c,v 1.14 1999/11/17 01:22:56 csapuntz Exp $ */ /* $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */ @@ -72,10 +72,6 @@ * */ -#ifndef WDCDEBUG -#define WDCDEBUG -#endif /* WDCDEBUG */ - #include #include #include @@ -91,13 +87,6 @@ #include #include -#ifndef __BUS_SPACE_HAS_STREAM_METHODS -#define bus_space_write_multi_stream_2 bus_space_write_multi_2 -#define bus_space_write_multi_stream_4 bus_space_write_multi_4 -#define bus_space_read_multi_stream_2 bus_space_read_multi_2 -#define bus_space_read_multi_stream_4 bus_space_read_multi_4 -#endif /* __BUS_SPACE_HAS_STREAM_METHODS */ - #include #include #include @@ -138,6 +127,155 @@ #define WDCDEBUG_PRINT(args, level) #endif + +u_int8_t wdc_default_read_reg __P((struct channel_softc *, enum wdc_regs)); +void wdc_default_write_reg __P((struct channel_softc *, enum wdc_regs, u_int8_t)); +void wdc_default_read_raw_multi_2 __P((struct channel_softc *, + void *, unsigned int)); +void wdc_default_write_raw_multi_2 __P((struct channel_softc *, + void *, unsigned int)); +void wdc_default_read_raw_multi_4 __P((struct channel_softc *, + void *, unsigned int)); +void wdc_default_write_raw_multi_4 __P((struct channel_softc *, + void *, unsigned int)); + +struct channel_softc_vtbl wdc_default_vtbl = { + wdc_default_read_reg, + wdc_default_write_reg, + wdc_default_read_raw_multi_2, + wdc_default_write_raw_multi_2, + wdc_default_read_raw_multi_4, + wdc_default_write_raw_multi_4 +}; + +u_int8_t +wdc_default_read_reg(chp, reg) + struct channel_softc *chp; + enum wdc_regs reg; +{ +#ifdef DIAGNOSTIC + if (reg & _WDC_WRONLY) { + printf ("wdc_default_read_reg: reading from a write-only register %d\n", reg); + } +#endif + + if (reg & _WDC_AUX) + return (bus_space_read_1(chp->ctl_iot, chp->ctl_ioh, + reg & _WDC_REGMASK)); + else + return (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, + reg & _WDC_REGMASK)); +} + +void +wdc_default_write_reg(chp, reg, val) + struct channel_softc *chp; + enum wdc_regs reg; + u_int8_t val; +{ +#ifdef DIAGNOSTIC + if (reg & _WDC_RDONLY) { + printf ("wdc_default_write_reg: writing to a read-only register %d\n", reg); + } +#endif + + if (reg & _WDC_AUX) + bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, + reg & _WDC_REGMASK, val); + else + bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, + reg & _WDC_REGMASK, val); +} + + +void +wdc_default_read_raw_multi_2(chp, data, nbytes) + struct channel_softc *chp; + void *data; + unsigned int nbytes; +{ + if (data == NULL) { + int i; + + for (i = 0; i < nbytes; i += 2) { + bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, 0); + } + + return; + } + + bus_space_read_raw_multi_2(chp->cmd_iot, chp->cmd_ioh, 0, + data, nbytes); + return; +} + + +void +wdc_default_write_raw_multi_2(chp, data, nbytes) + struct channel_softc *chp; + void *data; + unsigned int nbytes; +{ + if (data == NULL) { + int i; + + for (i = 0; i < nbytes; i += 2) { + bus_space_write_2(chp->cmd_iot, chp->cmd_ioh, 0, 0); + } + + return; + } + + bus_space_write_raw_multi_2(chp->cmd_iot, chp->cmd_ioh, 0, + data, nbytes); + return; +} + + +void +wdc_default_write_raw_multi_4(chp, data, nbytes) + struct channel_softc *chp; + void *data; + unsigned int nbytes; +{ + if (data == NULL) { + int i; + + for (i = 0; i < nbytes; i += 4) { + bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, 0, 0); + } + + return; + } + + bus_space_write_raw_multi_4(chp->cmd_iot, chp->cmd_ioh, 0, + data, nbytes); + return; +} + + +void +wdc_default_read_raw_multi_4(chp, data, nbytes) + struct channel_softc *chp; + void *data; + unsigned int nbytes; +{ + if (data == NULL) { + int i; + + for (i = 0; i < nbytes; i += 4) { + bus_space_read_4(chp->cmd_iot, chp->cmd_ioh, 0); + } + + return; + } + + bus_space_read_raw_multi_4(chp->cmd_iot, chp->cmd_ioh, 0, + data, nbytes); + return; +} + + int wdprint(aux, pnp) void *aux; @@ -167,16 +305,14 @@ wdc_disable_intr(chp) struct channel_softc *chp; { - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_IDS); + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS); } void wdc_enable_intr(chp) struct channel_softc *chp; { - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_4BIT); + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT); } int @@ -185,8 +321,7 @@ int drive; int howlong; { - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (drive << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4)); delay(1); @@ -225,20 +360,21 @@ u_int8_t ret_value = 0x03; u_int8_t drive; + if (!chp->_vtbl) + chp->_vtbl = &wdc_default_vtbl; + /* * Sanity check to see if the wdc channel responds at all. */ if (chp->wdc == NULL || (chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) { - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); delay(10); - st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | 0x10); + st0 = CHP_READ_REG(chp, wdr_status); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10); delay(10); - st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); + st1 = CHP_READ_REG(chp, wdr_status); WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n", chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", @@ -253,17 +389,14 @@ } /* assert SRST, wait for reset to complete */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); delay(10); - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_RST | WDCTL_IDS); + CHP_WRITE_REG(chp,wdr_ctlr, WDCTL_RST | WDCTL_IDS); DELAY(1000); - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_IDS); + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS); delay(1000); - (void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error); - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT); + (void) CHP_READ_REG(chp, wdr_error); + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT); delay(10); ret_value = __wdcwait_reset(chp, ret_value); @@ -284,14 +417,13 @@ for (drive = 0; drive < 2; drive++) { if ((ret_value & (0x01 << drive)) == 0) continue; - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (drive << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4)); delay(10); /* Save registers contents */ - sc = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt); - sn = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector); - cl = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo); - ch = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi); + sc = CHP_READ_REG(chp, wdr_seccnt); + sn = CHP_READ_REG(chp, wdr_sector); + cl = CHP_READ_REG(chp, wdr_cyl_lo); + ch = CHP_READ_REG(chp, wdr_cyl_hi); WDCDEBUG_PRINT(("%s:%d:%d: after reset, sc=0x%x sn=0x%x " "cl=0x%x ch=0x%x\n", @@ -333,6 +465,8 @@ return; } #endif + if (!chp->_vtbl) + chp->_vtbl = &wdc_default_vtbl; if (wdcprobe(chp) == 0) { /* If no drives, abort attach here. */ @@ -382,25 +516,19 @@ * Test registers writability (Error register not * writable, but cyllo is), then try an ATA command. */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (i << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (i << 4)); delay(10); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, - wd_error, 0x58); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, - wd_cyl_lo, 0xa5); - if (bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_error == 0x58) || - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_cyl_lo) != 0xa5) { + CHP_WRITE_REG(chp, wdr_features, 0x58); + CHP_WRITE_REG(chp, wdr_cyl_lo, 0xa5); + if ((CHP_READ_REG(chp, wdr_error) == 0x58) || + (CHP_READ_REG(chp, wdr_cyl_lo) != 0xa5)) { WDCDEBUG_PRINT(("%s:%d:%d: register " "writability failed\n", chp->wdc->sc_dev.dv_xname, chp->channel, i), DEBUG_PROBE); chp->ch_drive[i].drive_flags &= ~DRIVE_OLD; } - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (i << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (i << 4)); delay(100); if (wait_for_ready(chp, 10000) != 0) { WDCDEBUG_PRINT(("%s:%d:%d: not ready\n", @@ -409,8 +537,7 @@ chp->ch_drive[i].drive_flags &= ~DRIVE_OLD; continue; } - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, - wd_command, WDCC_RECAL); + CHP_WRITE_REG(chp, wdr_command, WDCC_RECAL); if (wait_for_ready(chp, 10000) != 0) { WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n", chp->wdc->sc_dev.dv_xname, @@ -491,8 +618,8 @@ */ for (i = 1; i >= 0; i--) { if (chp->ch_drive[i].drive_flags & DRIVE) { - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, - wd_sdh, WDSD_IBM | (i << 4)); + CHP_WRITE_REG(chp, + wdr_sdh, WDSD_IBM | (i << 4)); if (wait_for_unbusy(chp, 10000) < 0) printf("%s:%d:%d: device busy\n", chp->wdc->sc_dev.dv_xname, @@ -545,7 +672,7 @@ panic("wdcstart: channel waiting for irq\n"); #endif if (chp->wdc->cap & WDC_CAPABILITY_HWLOCK) - if (!(*chp->wdc->claim_hw)(chp, 0)) + if (!(chp->wdc->claim_hw)(chp, 0)) return; WDCDEBUG_PRINT(("wdcstart: xfer %p channel %d drive %d\n", xfer, @@ -619,17 +746,13 @@ { int drv_mask1, drv_mask2; - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM); /* master */ - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_RST | WDCTL_IDS); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */ + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_RST | WDCTL_IDS); delay(1000); - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_IDS); + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS); delay(2000); - (void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error); - bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, - WDCTL_4BIT); + (void) CHP_READ_REG(chp,wdr_error); + CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT); drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00; drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00; @@ -660,14 +783,12 @@ /* wait for BSY to deassert */ for (timeout = 0; timeout < WDCNDELAY_RST;timeout++) { - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM); /* master */ + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */ delay(10); - st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | 0x10); /* slave */ + st0 = CHP_READ_REG(chp, wdr_status); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10); /* slave */ delay(10); - st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); + st1 = CHP_READ_REG(chp, wdr_status); if ((drv_mask & 0x01) == 0) { /* no master */ @@ -726,25 +847,18 @@ for (;;) { #ifdef TEST_ALTSTS - chp->ch_status = status = - bus_space_read_1(chp->ctl_iot, chp->ctl_ioh, - wd_aux_altsts); + chp->ch_status = status = CHP_READ_REG(chp, wdr_altsts); #else - chp->ch_status = status = - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_status); + chp->ch_status = status = CHP_READ_REG(chp, wdr_status); #endif if (status == 0xff && (chp->ch_flags & WDCF_ONESLAVE)) { - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | 0x10); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10); #ifdef TEST_ALTSTS chp->ch_status = status = - bus_space_read_1(chp->ctl_iot, chp->ctl_ioh, - wd_aux_altsts); + CHP_READ_REG(chp, wdr_altsts); #else chp->ch_status = status = - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_status); + CHP_READ_REG(chp, wdr_status); #endif } if ((status & WDCS_BSY) == 0 && (status & mask) == bits) @@ -752,8 +866,7 @@ if (++time > timeout) { WDCDEBUG_PRINT(("wdcwait: timeout, status %x " "error %x\n", status, - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_error)), + CHP_READ_REG(chp, wdr_error)), DEBUG_STATUSX | DEBUG_STATUS); return -1; } @@ -761,11 +874,10 @@ } #ifdef TEST_ALTSTS /* Acknowledge any pending interrupts */ - bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status); + CHP_READ_REG(chp, wdr_status); #endif if (status & WDCS_ERR) { - chp->ch_error = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_error); + chp->ch_error = CHP_READ_REG(chp, wdr_error); WDCDEBUG_PRINT(("wdcwait: error %x\n", chp->ch_error), DEBUG_STATUSX | DEBUG_STATUS); } @@ -1010,23 +1122,23 @@ { struct channel_softc *chp = drvp->chnl_softc; unsigned int off = 0; - unsigned int len = buflen; + unsigned int len = buflen, roundlen; if (drvp->drive_flags & DRIVE_CAP32) { - bus_space_write_multi_4(chp->data32iot, - chp->data32ioh, wd_data, - (void *)((u_int8_t *)bytes + off), - len >> 2); + roundlen = len & ~3; - off += ((len >> 2) << 2); - len = len & 0x03; + CHP_WRITE_RAW_MULTI_4(chp, + (void *)((u_int8_t *)bytes + off), roundlen); + + off += roundlen; + len -= roundlen; } if (len > 0) { - bus_space_write_multi_2(chp->cmd_iot, - chp->cmd_ioh, wd_data, - (void *)((u_int8_t *)bytes + off), - (len + 1) >> 1); + roundlen = (len + 1) & ~0x1; + + CHP_WRITE_RAW_MULTI_2(chp, + (void *)((u_int8_t *)bytes + off), roundlen); } return; @@ -1040,22 +1152,23 @@ { struct channel_softc *chp = drvp->chnl_softc; unsigned int off = 0; - unsigned int len = buflen; + unsigned int len = buflen, roundlen; if (drvp->drive_flags & DRIVE_CAP32) { - bus_space_read_multi_4(chp->data32iot, - chp->data32ioh, wd_data, - (void *)((u_int8_t *)bytes + off), - len >> 2); - off += ((len >> 2) << 2); - len = len & 0x03; + roundlen = len & ~3; + + CHP_READ_RAW_MULTI_4(chp, + (void *)((u_int8_t *)bytes + off), roundlen); + + off += roundlen; + len -= roundlen; } if (len > 0) { - bus_space_read_multi_2(chp->cmd_iot, - chp->cmd_ioh, wd_data, - (void *)((u_int8_t *)bytes + off), - (len + 1) >> 1); + roundlen = (len + 1) & ~0x1; + + CHP_READ_RAW_MULTI_2(chp, + (void *)((u_int8_t *)bytes + off), roundlen); } return; @@ -1236,8 +1349,7 @@ * For resets, we don't really care to make sure that * the bus is free */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (drive << 4)); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4)); if (wdc_c->r_command != ATAPI_SOFT_RESET) { if (wdcwait(chp, wdc_c->r_st_bmask, wdc_c->r_st_bmask, @@ -1315,20 +1427,15 @@ wdc_c->flags |= AT_DONE; if (wdc_c->flags & AT_READREG && (wdc_c->flags & (AT_ERROR | AT_DF)) == 0) { - wdc_c->r_head = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_sdh); - wdc_c->r_cyl = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_cyl_hi) << 8; - wdc_c->r_cyl |= bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_cyl_lo); - wdc_c->r_sector = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_sector); - wdc_c->r_count = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_seccnt); - wdc_c->r_error = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_error); - wdc_c->r_precomp = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, - wd_precomp); + wdc_c->r_head = CHP_READ_REG(chp, wdr_sdh); + wdc_c->r_cyl = CHP_READ_REG(chp, wdr_cyl_hi) << 8; + wdc_c->r_cyl |= CHP_READ_REG(chp, wdr_cyl_lo); + wdc_c->r_sector = CHP_READ_REG(chp, wdr_sector); + wdc_c->r_count = CHP_READ_REG(chp, wdr_seccnt); + wdc_c->r_error = CHP_READ_REG(chp, wdr_error); + wdc_c->r_precomp = wdc_c->r_error; + /* XXX CHP_READ_REG(chp, wdr_precomp); - precomp + isn't a readable register */ } if (xfer->c_flags & C_POLL) { wdc_enable_intr(chp); @@ -1364,19 +1471,17 @@ DEBUG_FUNCS); /* Select drive, head, and addressing mode. */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (drive << 4) | head); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4) | head); - /* Load parameters. wd_features(ATA/ATAPI) = wd_precomp(ST506) */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_precomp, - precomp); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo, cylin); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi, cylin >> 8); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sector, sector); - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt, count); + /* Load parameters. wdr_features(ATA/ATAPI) = wdr_precomp(ST506) */ + CHP_WRITE_REG(chp, wdr_precomp, precomp); + CHP_WRITE_REG(chp, wdr_cyl_lo, cylin); + CHP_WRITE_REG(chp, wdr_cyl_hi, cylin >> 8); + CHP_WRITE_REG(chp, wdr_sector, sector); + CHP_WRITE_REG(chp, wdr_seccnt, count); /* Send command. */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_command, command); + CHP_WRITE_REG(chp, wdr_command, command); return; } @@ -1396,10 +1501,8 @@ DEBUG_FUNCS); /* Select drive. */ - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh, - WDSD_IBM | (drive << 4)); - - bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_command, command); + CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4)); + CHP_WRITE_REG(chp, wdr_command, command); } /* Add a command to the queue and start controller. Must be called at splbio */ @@ -1519,11 +1622,7 @@ struct channel_softc *chp; int size; { - - for (; size >= 2; size -= 2) - (void)bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, wd_data); - if (size) - (void)bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_data); + CHP_READ_RAW_MULTI_2(chp, NULL, size); } #ifndef __OpenBSD__ Index: sys/dev/ic/wdcreg.h =================================================================== RCS file: /cvs/src/sys/dev/ic/wdcreg.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- sys/dev/ic/wdcreg.h 1999/07/18 21:25:16 1.1 +++ sys/dev/ic/wdcreg.h 1999/11/17 01:22:56 1.2 @@ -1,4 +1,4 @@ -/* $OpenBSD: wdcreg.h,v 1.1 1999/07/18 21:25:16 csapuntz Exp $ */ +/* $OpenBSD: wdcreg.h,v 1.2 1999/11/17 01:22:56 csapuntz Exp $ */ /* $NetBSD: wdcreg.h,v 1.22 1999/03/07 14:02:54 bouyer Exp $ */ /*- @@ -39,27 +39,9 @@ * @(#)wdreg.h 7.1 (Berkeley) 5/9/91 */ -/* - * Disk Controller register definitions. - */ - -/* offsets of registers in the 'regular' register region */ -#define wd_data 0 /* data register (R/W - 16 bits) */ -#define wd_error 1 /* error register (R) */ -#define wd_precomp 1 /* write precompensation (W) */ -#define wd_features 1 /* features (W), same as wd_precomp */ -#define wd_seccnt 2 /* sector count (R/W) */ -#define wd_ireason 2 /* interrupt reason (R/W) (for atapi) */ -#define wd_sector 3 /* first sector number (R/W) */ -#define wd_cyl_lo 4 /* cylinder address, low byte (R/W) */ -#define wd_cyl_hi 5 /* cylinder address, high byte (R/W) */ -#define wd_sdh 6 /* sector size/drive/head (R/W) */ -#define wd_command 7 /* command register (W) */ -#define wd_status 7 /* immediate status (R) */ - -/* offsets of registers in the auxiliary register region */ -#define wd_aux_altsts 0 /* alternate fixed disk status (R) */ -#define wd_aux_ctlr 0 /* fixed disk controller control (W) */ +/* + * Controller register (wdr_ctlr) + */ #define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */ #define WDCTL_RST 0x04 /* reset the controller */ #define WDCTL_IDS 0x02 /* disable controller interrupts */ @@ -178,4 +160,5 @@ #define PHASE_DATAOUT WDCS_DRQ #define PHASE_COMPLETED (WDCI_IN | WDCI_CMD) #define PHASE_ABORTED 0 + Index: sys/dev/ic/wdcvar.h =================================================================== RCS file: /cvs/src/sys/dev/ic/wdcvar.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- sys/dev/ic/wdcvar.h 1999/10/29 01:15:15 1.4 +++ sys/dev/ic/wdcvar.h 1999/11/17 01:22:56 1.5 @@ -1,4 +1,4 @@ -/* $OpenBSD: wdcvar.h,v 1.4 1999/10/29 01:15:15 deraadt Exp $ */ +/* $OpenBSD: wdcvar.h,v 1.5 1999/11/17 01:22:56 csapuntz Exp $ */ /* $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $ */ /*- @@ -44,7 +44,11 @@ TAILQ_HEAD(xferhead, wdc_xfer) sc_xfer; }; +struct channel_softc_vtbl; + struct channel_softc { /* Per channel data */ + struct channel_softc_vtbl *_vtbl; + /* Our location */ int channel; /* Our controller's softc */ @@ -73,6 +77,57 @@ */ struct channel_queue *ch_queue; }; + +/* + * Disk Controller register definitions. + */ +#define _WDC_REGMASK 7 +#define _WDC_AUX 8 +#define _WDC_RDONLY 16 +#define _WDC_WRONLY 32 +enum wdc_regs { + wdr_error = _WDC_RDONLY | 1, + wdr_precomp = _WDC_WRONLY | 1, + wdr_features = _WDC_WRONLY | 1, + wdr_seccnt = 2, + wdr_ireason = 2, + wdr_sector = 3, + wdr_cyl_lo = 4, + wdr_cyl_hi = 5, + wdr_sdh = 6, + wdr_status = _WDC_RDONLY | 7, + wdr_command = _WDC_WRONLY | 7, + wdr_altsts = _WDC_RDONLY | _WDC_AUX, + wdr_ctlr = _WDC_WRONLY | _WDC_AUX +}; + +struct channel_softc_vtbl { + u_int8_t (*read_reg)(struct channel_softc *, enum wdc_regs reg); + void (*write_reg)(struct channel_softc *, enum wdc_regs reg, + u_int8_t var); + + void (*read_raw_multi_2)(struct channel_softc *, + void *data, unsigned int nbytes); + void (*write_raw_multi_2)(struct channel_softc *, + void *data, unsigned int nbytes); + + void (*read_raw_multi_4)(struct channel_softc *, + void *data, unsigned int nbytes); + void (*write_raw_multi_4)(struct channel_softc *, + void *data, unsigned int nbytes); +}; + + +#define CHP_READ_REG(chp, a) ((chp)->_vtbl->read_reg)(chp, a) +#define CHP_WRITE_REG(chp, a, b) ((chp)->_vtbl->write_reg)(chp, a, b) +#define CHP_READ_RAW_MULTI_2(chp, a, b) \ + ((chp)->_vtbl->read_raw_multi_2)(chp, a, b) +#define CHP_WRITE_RAW_MULTI_2(chp, a, b) \ + ((chp)->_vtbl->write_raw_multi_2)(chp, a, b) +#define CHP_READ_RAW_MULTI_4(chp, a, b) \ + ((chp)->_vtbl->read_raw_multi_4)(chp, a, b) +#define CHP_WRITE_RAW_MULTI_4(chp, a, b) \ + ((chp)->_vtbl->write_raw_multi_4)(chp, a, b) struct wdc_softc { /* Per controller state */ struct device sc_dev;