int pcscp_dma_isactive(struct ncr53c9x_softc *sc) { struct pcscp_softc *esc = (struct pcscp_softc *)sc; /* XXX should check esc->sc_active? */ if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE) return 1; return 0; }
static int esp_pci_dma_isactive(struct ncr53c9x_softc *sc) { struct esp_pci_softc *esc = (struct esp_pci_softc *)sc; /* XXX should we check esc->sc_active? */ if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE) return (1); return (0); }
int pcscp_dma_intr(struct ncr53c9x_softc *sc) { struct pcscp_softc *esc = (struct pcscp_softc *)sc; int trans, resid, i; bus_dmamap_t dmap = esc->sc_xfermap; int datain = esc->sc_datain; u_int32_t dmastat; char *p = NULL; dmastat = READ_DMAREG(esc, DMA_STAT); if (dmastat & DMASTAT_ERR) { /* XXX not tested... */ WRITE_DMAREG(esc, DMA_CMD, DMACMD_ABORT | (datain ? DMACMD_DIR : 0)); printf("%s: error: DMA error detected; Aborting.\n", sc->sc_dev.dv_xname); bus_dmamap_unload(esc->sc_dmat, dmap); return -1; } if (dmastat & DMASTAT_ABT) { /* XXX What should be done? */ printf("%s: dma_intr: DMA aborted.\n", sc->sc_dev.dv_xname); WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0)); esc->sc_active = 0; return 0; } #ifdef DIAGNOSTIC /* This is an "assertion" :) */ if (esc->sc_active == 0) panic("pcscp dmaintr: DMA wasn't active"); #endif /* DMA has stopped */ esc->sc_active = 0; if (esc->sc_dmasize == 0) { /* A "Transfer Pad" operation completed */ NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n", PCSCP_READ_REG(esc, NCR_TCL) | (PCSCP_READ_REG(esc, NCR_TCM) << 8), PCSCP_READ_REG(esc, NCR_TCL), PCSCP_READ_REG(esc, NCR_TCM))); return 0; } resid = 0; /* * If a transfer onto the SCSI bus gets interrupted by the device * (e.g. for a SAVEPOINTER message), the data in the FIFO counts * as residual since the ESP counter registers get decremented as * bytes are clocked into the FIFO. */ if (!datain && (resid = (PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { NCR_DMA(("pcscp_dma_intr: empty esp FIFO of %d ", resid)); } if ((sc->sc_espstat & NCRSTAT_TC) == 0) { /* * `Terminal count' is off, so read the residue * out of the ESP counter registers. */ if (datain) { resid = PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF; while (resid > 1) resid = PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF; WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_MDL | (datain ? DMACMD_DIR : 0)); for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */ if (READ_DMAREG(esc, DMA_STAT) & DMASTAT_BCMP) break; /* See the below comments... */ if (resid) p = *esc->sc_dmaaddr; } resid += PCSCP_READ_REG(esc, NCR_TCL) | (PCSCP_READ_REG(esc, NCR_TCM) << 8) | (PCSCP_READ_REG(esc, NCR_TCH) << 16); } else { while ((dmastat & DMASTAT_DONE) == 0) dmastat = READ_DMAREG(esc, DMA_STAT); } WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0)); /* sync MDL */ bus_dmamap_sync(esc->sc_dmat, esc->sc_mdldmap, 0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_POSTWRITE); /* sync transfer buffer */ bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize, datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(esc->sc_dmat, dmap); trans = esc->sc_dmasize - resid; /* * From the technical manual notes: * * `In some odd byte conditions, one residual byte will be left * in the SCSI FIFO, and the FIFO flags will never count to 0. * When this happens, the residual byte should be retrieved * via PIO following completion of the BLAST operation.' */ if (p) { p += trans; *p = PCSCP_READ_REG(esc, NCR_FIFO); trans++; } if (trans < 0) { /* transferred < 0 ? */ #if 0 /* * This situation can happen in perfectly normal operation * if the ESP is reselected while using DMA to select * another target. As such, don't print the warning. */ printf("%s: xfer (%d) > req (%d)\n", sc->sc_dev.dv_xname, trans, esc->sc_dmasize); #endif trans = esc->sc_dmasize; } NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", PCSCP_READ_REG(esc, NCR_TCL), PCSCP_READ_REG(esc, NCR_TCM), PCSCP_READ_REG(esc, NCR_TCH), trans, resid)); *esc->sc_dmalen -= trans; *esc->sc_dmaaddr += trans; return 0; }
static int esp_pci_dma_intr(struct ncr53c9x_softc *sc) { struct esp_pci_softc *esc = (struct esp_pci_softc *)sc; bus_dma_tag_t xferdmat; bus_dmamap_t xferdmam; size_t dmasize; int datain, i, resid, trans; uint32_t dmastat; char *p = NULL; xferdmat = esc->sc_xferdmat; xferdmam = esc->sc_xferdmam; datain = esc->sc_datain; dmastat = READ_DMAREG(esc, DMA_STAT); if ((dmastat & DMASTAT_ERR) != 0) { /* XXX not tested... */ WRITE_DMAREG(esc, DMA_CMD, DMACMD_ABORT | (datain != 0 ? DMACMD_DIR : 0)); device_printf(esc->sc_dev, "DMA error detected; Aborting.\n"); bus_dmamap_sync(xferdmat, xferdmam, datain != 0 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(xferdmat, xferdmam); return (-1); } if ((dmastat & DMASTAT_ABT) != 0) { /* XXX what should be done? */ device_printf(esc->sc_dev, "DMA aborted.\n"); WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain != 0 ? DMACMD_DIR : 0)); esc->sc_active = 0; return (0); } KASSERT(esc->sc_active != 0, ("%s: DMA wasn't active", __func__)); /* DMA has stopped. */ esc->sc_active = 0; dmasize = esc->sc_dmasize; if (dmasize == 0) { /* A "Transfer Pad" operation completed. */ NCR_DMA(("%s: discarded %d bytes (tcl=%d, tcm=%d)\n", __func__, READ_ESPREG(esc, NCR_TCL) | (READ_ESPREG(esc, NCR_TCM) << 8), READ_ESPREG(esc, NCR_TCL), READ_ESPREG(esc, NCR_TCM))); return (0); } resid = 0; /* * If a transfer onto the SCSI bus gets interrupted by the device * (e.g. for a SAVEPOINTER message), the data in the FIFO counts * as residual since the ESP counter registers get decremented as * bytes are clocked into the FIFO. */ if (datain == 0 && (resid = (READ_ESPREG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0) NCR_DMA(("%s: empty esp FIFO of %d ", __func__, resid)); if ((sc->sc_espstat & NCRSTAT_TC) == 0) { /* * "Terminal count" is off, so read the residue * out of the ESP counter registers. */ if (datain != 0) { resid = READ_ESPREG(esc, NCR_FFLAG) & NCRFIFO_FF; while (resid > 1) resid = READ_ESPREG(esc, NCR_FFLAG) & NCRFIFO_FF; WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_DIR); for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */ if ((READ_DMAREG(esc, DMA_STAT) & DMASTAT_BCMP) != 0) break; /* See the below comments... */ if (resid != 0) p = *esc->sc_dmaaddr; } resid += READ_ESPREG(esc, NCR_TCL) | (READ_ESPREG(esc, NCR_TCM) << 8) | (READ_ESPREG(esc, NCR_TCH) << 16); } else while ((dmastat & DMASTAT_DONE) == 0) dmastat = READ_DMAREG(esc, DMA_STAT); WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain != 0 ? DMACMD_DIR : 0)); /* Sync the transfer buffer. */ bus_dmamap_sync(xferdmat, xferdmam, datain != 0 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(xferdmat, xferdmam); trans = dmasize - resid; /* * From the technical manual notes: * * "In some odd byte conditions, one residual byte will be left * in the SCSI FIFO, and the FIFO flags will never count to 0. * When this happens, the residual byte should be retrieved * via PIO following completion of the BLAST operation." */ if (p != NULL) { p += trans; *p = READ_ESPREG(esc, NCR_FIFO); trans++; } if (trans < 0) { /* transferred < 0 ? */ #if 0 /* * This situation can happen in perfectly normal operation * if the ESP is reselected while using DMA to select * another target. As such, don't print the warning. */ device_printf(dev, "xfer (%d) > req (%d)\n", trans, dmasize); #endif trans = dmasize; } NCR_DMA(("%s: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", __func__, READ_ESPREG(esc, NCR_TCL), READ_ESPREG(esc, NCR_TCM), READ_ESPREG(esc, NCR_TCH), trans, resid)); *esc->sc_dmalen -= trans; *esc->sc_dmaaddr = (char *)*esc->sc_dmaaddr + trans; return (0); }