[BACK]Return to pcscp.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/pcscp.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: pcscp.c,v 1.14 2006/04/30 00:35:40 brad Exp $ */
                      2: /*     $NetBSD: pcscp.c,v 1.26 2003/10/19 10:25:42 tsutsui Exp $       */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
                     10:  * NASA Ames Research Center; Izumi Tsutsui.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *     This product includes software developed by the NetBSD
                     23:  *     Foundation, Inc. and its contributors.
                     24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     25:  *    contributors may be used to endorse or promote products derived
                     26:  *    from this software without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     38:  * POSSIBILITY OF SUCH DAMAGE.
                     39:  */
                     40:
                     41: /*
                     42:  * pcscp.c: device dependent code for AMD Am53c974 (PCscsi-PCI)
                     43:  * written by Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
                     44:  *
                     45:  * Technical manual available at
                     46:  * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/19113.pdf
                     47:  */
                     48:
                     49: #include <sys/param.h>
                     50: #include <sys/systm.h>
                     51: #include <sys/device.h>
                     52: #include <sys/buf.h>
                     53:
                     54: #include <machine/bus.h>
                     55: #include <machine/intr.h>
                     56:
                     57: #include <scsi/scsi_all.h>
                     58: #include <scsi/scsiconf.h>
                     59: #include <scsi/scsi_message.h>
                     60:
                     61: #include <dev/pci/pcireg.h>
                     62: #include <dev/pci/pcivar.h>
                     63: #include <dev/pci/pcidevs.h>
                     64:
                     65: #include <dev/ic/ncr53c9xreg.h>
                     66: #include <dev/ic/ncr53c9xvar.h>
                     67:
                     68: #include <dev/pci/pcscpreg.h>
                     69:
                     70: #define IO_MAP_REG     0x10
                     71:
                     72: struct pcscp_softc {
                     73:        struct ncr53c9x_softc sc_ncr53c9x;      /* glue to MI code */
                     74:
                     75:        bus_space_tag_t sc_st;          /* bus space tag */
                     76:        bus_space_handle_t sc_sh;       /* bus space handle */
                     77:        void *sc_ih;                    /* interrupt cookie */
                     78:
                     79:        bus_dma_tag_t sc_dmat;          /* DMA tag */
                     80:
                     81:        bus_dmamap_t sc_xfermap;        /* DMA map for transfers */
                     82:
                     83:        u_int32_t *sc_mdladdr;          /* MDL array */
                     84:        bus_dmamap_t sc_mdldmap;        /* MDL DMA map */
                     85:
                     86:        int     sc_active;              /* DMA state */
                     87:        int     sc_datain;              /* DMA Data Direction */
                     88:        size_t  sc_dmasize;             /* DMA size */
                     89:        char    **sc_dmaaddr;           /* DMA address */
                     90:        size_t  *sc_dmalen;             /* DMA length */
                     91: };
                     92:
                     93: #define        READ_DMAREG(sc, reg) \
                     94:        bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
                     95: #define        WRITE_DMAREG(sc, reg, var) \
                     96:        bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (var))
                     97:
                     98: #define        PCSCP_READ_REG(sc, reg) \
                     99:        bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg) << 2)
                    100: #define        PCSCP_WRITE_REG(sc, reg, val) \
                    101:        bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg) << 2, (val))
                    102:
                    103: int    pcscp_match(struct device *, void *, void *);
                    104: void   pcscp_attach(struct device *, struct device *, void *);
                    105:
                    106: struct cfattach pcscp_ca = {
                    107:        sizeof(struct pcscp_softc), pcscp_match, pcscp_attach
                    108: };
                    109:
                    110: struct cfdriver pcscp_cd = {
                    111:        NULL, "pcscp", DV_DULL
                    112: };
                    113:
                    114: /*
                    115:  * Functions and the switch for the MI code.
                    116:  */
                    117:
                    118: u_char pcscp_read_reg(struct ncr53c9x_softc *, int);
                    119: void   pcscp_write_reg(struct ncr53c9x_softc *, int, u_char);
                    120: int    pcscp_dma_isintr(struct ncr53c9x_softc *);
                    121: void   pcscp_dma_reset(struct ncr53c9x_softc *);
                    122: int    pcscp_dma_intr(struct ncr53c9x_softc *);
                    123: int    pcscp_dma_setup(struct ncr53c9x_softc *, caddr_t *,
                    124:                               size_t *, int, size_t *);
                    125: void   pcscp_dma_go(struct ncr53c9x_softc *);
                    126: void   pcscp_dma_stop(struct ncr53c9x_softc *);
                    127: int    pcscp_dma_isactive(struct ncr53c9x_softc *);
                    128:
                    129: struct scsi_adapter pcscp_adapter = {
                    130:        ncr53c9x_scsi_cmd,      /* cmd */
                    131:        minphys,                /* minphys */
                    132:        0,                      /* open */
                    133:        0,                      /* close */
                    134: };
                    135:
                    136: struct ncr53c9x_glue pcscp_glue = {
                    137:        pcscp_read_reg,
                    138:        pcscp_write_reg,
                    139:        pcscp_dma_isintr,
                    140:        pcscp_dma_reset,
                    141:        pcscp_dma_intr,
                    142:        pcscp_dma_setup,
                    143:        pcscp_dma_go,
                    144:        pcscp_dma_stop,
                    145:        pcscp_dma_isactive,
                    146:        NULL,                   /* gl_clear_latched_intr */
                    147: };
                    148:
                    149: int
                    150: pcscp_match(struct device *parent, void *match, void *aux)
                    151: {
                    152:        struct pci_attach_args *pa = aux;
                    153:
                    154:        if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
                    155:                return 0;
                    156:
                    157:        switch (PCI_PRODUCT(pa->pa_id)) {
                    158:        case PCI_PRODUCT_AMD_PCSCSI_PCI:
                    159:                return 1;
                    160:        }
                    161:        return 0;
                    162: }
                    163:
                    164: /*
                    165:  * Attach this instance, and then all the sub-devices
                    166:  */
                    167: void
                    168: pcscp_attach(struct device *parent, struct device *self, void *aux)
                    169: {
                    170:        struct pci_attach_args *pa = aux;
                    171:        struct pcscp_softc *esc = (void *)self;
                    172:        struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
                    173:        bus_space_tag_t iot;
                    174:        bus_space_handle_t ioh;
                    175:        pci_intr_handle_t ih;
                    176:        const char *intrstr;
                    177:        bus_dma_segment_t seg;
                    178:        int error, rseg;
                    179:
                    180:        if (pci_mapreg_map(pa, IO_MAP_REG, PCI_MAPREG_TYPE_IO, 0,
                    181:             &iot, &ioh, NULL, NULL, NULL)) {
                    182:                printf("%s: unable to map registers\n", sc->sc_dev.dv_xname);
                    183:                return;
                    184:        }
                    185:
                    186:        sc->sc_glue = &pcscp_glue;
                    187:
                    188:        esc->sc_st = iot;
                    189:        esc->sc_sh = ioh;
                    190:        esc->sc_dmat = pa->pa_dmat;
                    191:
                    192:        /*
                    193:         * XXX More of this should be in ncr53c9x_attach(), but
                    194:         * XXX should we really poke around the chip that much in
                    195:         * XXX the MI code?  Think about this more...
                    196:         */
                    197:
                    198:        /*
                    199:         * Set up static configuration info.
                    200:         */
                    201:
                    202:        /*
                    203:         * XXX should read configuration from EEPROM?
                    204:         *
                    205:         * MI ncr53c9x driver does not support configuration
                    206:         * per each target device, though...
                    207:         */
                    208:        sc->sc_id = 7;
                    209:        sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
                    210:        sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_FE;
                    211:        sc->sc_cfg3 = NCRAMDCFG3_IDM | NCRAMDCFG3_FCLK;
                    212:        sc->sc_cfg4 = NCRAMDCFG4_GE12NS | NCRAMDCFG4_RADE;
                    213:        sc->sc_rev = NCR_VARIANT_AM53C974;
                    214:        sc->sc_features = NCR_F_FASTSCSI;
                    215:        sc->sc_cfg3_fscsi = NCRAMDCFG3_FSCSI;
                    216:        sc->sc_freq = 40; /* MHz */
                    217:
                    218:        /*
                    219:         * XXX minsync and maxxfer _should_ be set up in MI code,
                    220:         * XXX but it appears to have some dependency on what sort
                    221:         * XXX of DMA we're hooked up to, etc.
                    222:         */
                    223:
                    224:        /*
                    225:         * This is the value used to start sync negotiations
                    226:         * Note that the NCR register "SYNCTP" is programmed
                    227:         * in "clocks per byte", and has a minimum value of 4.
                    228:         * The SCSI period used in negotiation is one-fourth
                    229:         * of the time (in nanoseconds) needed to transfer one byte.
                    230:         * Since the chip's clock is given in MHz, we have the following
                    231:         * formula: 4 * period = (1000 / freq) * 4
                    232:         */
                    233:
                    234:        sc->sc_minsync = 1000 / sc->sc_freq;
                    235:
                    236:        /* Really no limit, but since we want to fit into the TCR... */
                    237:        sc->sc_maxxfer = 16 * 1024 * 1024;
                    238:
                    239:        /*
                    240:         * Create the DMA maps for the data transfers.
                    241:          */
                    242:
                    243: #define MDL_SEG_SIZE   0x1000 /* 4kbyte per segment */
                    244: #define MDL_SEG_OFFSET 0x0FFF
                    245: #define MDL_SIZE       (MAXPHYS / MDL_SEG_SIZE + 1) /* no hardware limit? */
                    246:
                    247:        if (bus_dmamap_create(esc->sc_dmat, MAXPHYS, MDL_SIZE, MDL_SEG_SIZE,
                    248:            MDL_SEG_SIZE, BUS_DMA_NOWAIT, &esc->sc_xfermap)) {
                    249:                printf("%s: can't create dma maps\n", sc->sc_dev.dv_xname);
                    250:                return;
                    251:        }
                    252:
                    253:        /*
                    254:         * Allocate and map memory for the MDL.
                    255:         */
                    256:
                    257:        if ((error = bus_dmamem_alloc(esc->sc_dmat,
                    258:            sizeof(u_int32_t) * MDL_SIZE, PAGE_SIZE, 0, &seg, 1, &rseg,
                    259:            BUS_DMA_NOWAIT)) != 0) {
                    260:                printf("%s: unable to allocate memory for the MDL, "
                    261:                    "error = %d\n", sc->sc_dev.dv_xname, error);
                    262:                goto fail_0;
                    263:        }
                    264:        if ((error = bus_dmamem_map(esc->sc_dmat, &seg, rseg,
                    265:            sizeof(u_int32_t) * MDL_SIZE , (caddr_t *)&esc->sc_mdladdr,
                    266:            BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
                    267:                printf("%s: unable to map the MDL memory, error = %d\n",
                    268:                    sc->sc_dev.dv_xname, error);
                    269:                goto fail_1;
                    270:        }
                    271:        if ((error = bus_dmamap_create(esc->sc_dmat,
                    272:            sizeof(u_int32_t) * MDL_SIZE, 1, sizeof(u_int32_t) * MDL_SIZE,
                    273:            0, BUS_DMA_NOWAIT, &esc->sc_mdldmap)) != 0) {
                    274:                printf("%s: unable to map_create for the MDL, error = %d\n",
                    275:                    sc->sc_dev.dv_xname, error);
                    276:                goto fail_2;
                    277:        }
                    278:        if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_mdldmap,
                    279:             esc->sc_mdladdr, sizeof(u_int32_t) * MDL_SIZE,
                    280:             NULL, BUS_DMA_NOWAIT)) != 0) {
                    281:                printf("%s: unable to load for the MDL, error = %d\n",
                    282:                    sc->sc_dev.dv_xname, error);
                    283:                goto fail_3;
                    284:        }
                    285:
                    286:        /* map and establish interrupt */
                    287:        if (pci_intr_map(pa, &ih)) {
                    288:                printf(": couldn't map interrupt\n");
                    289:                goto fail_4;
                    290:        }
                    291:
                    292:        intrstr = pci_intr_string(pa->pa_pc, ih);
                    293:        esc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
                    294:            ncr53c9x_intr, esc, sc->sc_dev.dv_xname);
                    295:        if (esc->sc_ih == NULL) {
                    296:                printf(": couldn't establish interrupt");
                    297:                if (intrstr != NULL)
                    298:                        printf(" at %s", intrstr);
                    299:                printf("\n");
                    300:                goto fail_4;
                    301:        }
                    302:        if (intrstr != NULL)
                    303:                printf(": %s\n", intrstr);
                    304:
                    305:        /* Do the common parts of attachment. */
                    306:        printf("%s", sc->sc_dev.dv_xname);
                    307:
                    308:        ncr53c9x_attach(sc, &pcscp_adapter, NULL);
                    309:
                    310:        /* Turn on target selection using the `dma' method */
                    311:        sc->sc_features |= NCR_F_DMASELECT;
                    312:
                    313:        return;
                    314:
                    315: fail_4:
                    316:        bus_dmamap_unload(esc->sc_dmat, esc->sc_mdldmap);
                    317: fail_3:
                    318:        bus_dmamap_destroy(esc->sc_dmat, esc->sc_mdldmap);
                    319: fail_2:
                    320:        bus_dmamem_unmap(esc->sc_dmat, (caddr_t)esc->sc_mdldmap,
                    321:            sizeof(uint32_t) * MDL_SIZE);
                    322: fail_1:
                    323:        bus_dmamem_free(esc->sc_dmat, &seg, rseg);
                    324: fail_0:
                    325:        bus_dmamap_destroy(esc->sc_dmat, esc->sc_xfermap);
                    326: }
                    327:
                    328: /*
                    329:  * Glue functions.
                    330:  */
                    331:
                    332: u_char
                    333: pcscp_read_reg(struct ncr53c9x_softc *sc, int reg)
                    334: {
                    335:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    336:
                    337:        return PCSCP_READ_REG(esc, reg);
                    338: }
                    339:
                    340: void
                    341: pcscp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char v)
                    342: {
                    343:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    344:
                    345:        PCSCP_WRITE_REG(esc, reg, v);
                    346: }
                    347:
                    348: int
                    349: pcscp_dma_isintr(struct ncr53c9x_softc *sc)
                    350: {
                    351:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    352:
                    353:        return (PCSCP_READ_REG(esc, NCR_STAT) & NCRSTAT_INT) != 0;
                    354: }
                    355:
                    356: void
                    357: pcscp_dma_reset(struct ncr53c9x_softc *sc)
                    358: {
                    359:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    360:
                    361:        WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE);
                    362:
                    363:        esc->sc_active = 0;
                    364: }
                    365:
                    366: int
                    367: pcscp_dma_intr(struct ncr53c9x_softc *sc)
                    368: {
                    369:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    370:        int trans, resid, i;
                    371:        bus_dmamap_t dmap = esc->sc_xfermap;
                    372:        int datain = esc->sc_datain;
                    373:        u_int32_t dmastat;
                    374:        char *p = NULL;
                    375:
                    376:        dmastat = READ_DMAREG(esc, DMA_STAT);
                    377:
                    378:        if (dmastat & DMASTAT_ERR) {
                    379:                /* XXX not tested... */
                    380:                WRITE_DMAREG(esc, DMA_CMD,
                    381:                    DMACMD_ABORT | (datain ? DMACMD_DIR : 0));
                    382:
                    383:                printf("%s: error: DMA error detected; Aborting.\n",
                    384:                    sc->sc_dev.dv_xname);
                    385:                bus_dmamap_unload(esc->sc_dmat, dmap);
                    386:                return -1;
                    387:        }
                    388:
                    389:        if (dmastat & DMASTAT_ABT) {
                    390:                /* XXX What should be done? */
                    391:                printf("%s: dma_intr: DMA aborted.\n", sc->sc_dev.dv_xname);
                    392:                WRITE_DMAREG(esc, DMA_CMD,
                    393:                    DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
                    394:                esc->sc_active = 0;
                    395:                return 0;
                    396:        }
                    397:
                    398: #ifdef DIAGNOSTIC
                    399:        /* This is an "assertion" :) */
                    400:        if (esc->sc_active == 0)
                    401:                panic("pcscp dmaintr: DMA wasn't active");
                    402: #endif
                    403:
                    404:        /* DMA has stopped */
                    405:
                    406:        esc->sc_active = 0;
                    407:
                    408:        if (esc->sc_dmasize == 0) {
                    409:                /* A "Transfer Pad" operation completed */
                    410:                NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
                    411:                    PCSCP_READ_REG(esc, NCR_TCL) |
                    412:                    (PCSCP_READ_REG(esc, NCR_TCM) << 8),
                    413:                    PCSCP_READ_REG(esc, NCR_TCL),
                    414:                    PCSCP_READ_REG(esc, NCR_TCM)));
                    415:                return 0;
                    416:        }
                    417:
                    418:        resid = 0;
                    419:        /*
                    420:         * If a transfer onto the SCSI bus gets interrupted by the device
                    421:         * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
                    422:         * as residual since the ESP counter registers get decremented as
                    423:         * bytes are clocked into the FIFO.
                    424:         */
                    425:        if (!datain &&
                    426:            (resid = (PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
                    427:                NCR_DMA(("pcscp_dma_intr: empty esp FIFO of %d ", resid));
                    428:        }
                    429:
                    430:        if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
                    431:                /*
                    432:                 * `Terminal count' is off, so read the residue
                    433:                 * out of the ESP counter registers.
                    434:                 */
                    435:                if (datain) {
                    436:                        resid = PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF;
                    437:                        while (resid > 1)
                    438:                                resid =
                    439:                                    PCSCP_READ_REG(esc, NCR_FFLAG) & NCRFIFO_FF;
                    440:                        WRITE_DMAREG(esc, DMA_CMD, DMACMD_BLAST | DMACMD_MDL |
                    441:                            (datain ? DMACMD_DIR : 0));
                    442:
                    443:                        for (i = 0; i < 0x8000; i++) /* XXX 0x8000 ? */
                    444:                                if (READ_DMAREG(esc, DMA_STAT) & DMASTAT_BCMP)
                    445:                                        break;
                    446:
                    447:                        /* See the below comments... */
                    448:                        if (resid)
                    449:                                p = *esc->sc_dmaaddr;
                    450:                }
                    451:
                    452:                resid += PCSCP_READ_REG(esc, NCR_TCL) |
                    453:                    (PCSCP_READ_REG(esc, NCR_TCM) << 8) |
                    454:                    (PCSCP_READ_REG(esc, NCR_TCH) << 16);
                    455:        } else {
                    456:                while ((dmastat & DMASTAT_DONE) == 0)
                    457:                        dmastat = READ_DMAREG(esc, DMA_STAT);
                    458:        }
                    459:
                    460:        WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
                    461:
                    462:        /* sync MDL */
                    463:        bus_dmamap_sync(esc->sc_dmat, esc->sc_mdldmap,
                    464:            0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_POSTWRITE);
                    465:        /* sync transfer buffer */
                    466:        bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize,
                    467:            datain ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
                    468:        bus_dmamap_unload(esc->sc_dmat, dmap);
                    469:
                    470:        trans = esc->sc_dmasize - resid;
                    471:
                    472:        /*
                    473:         * From the technical manual notes:
                    474:         *
                    475:         * `In some odd byte conditions, one residual byte will be left
                    476:         *  in the SCSI FIFO, and the FIFO flags will never count to 0.
                    477:         *  When this happens, the residual byte should be retrieved
                    478:         *  via PIO following completion of the BLAST operation.'
                    479:         */
                    480:
                    481:        if (p) {
                    482:                p += trans;
                    483:                *p = PCSCP_READ_REG(esc, NCR_FIFO);
                    484:                trans++;
                    485:        }
                    486:
                    487:        if (trans < 0) {                        /* transferred < 0 ? */
                    488: #if 0
                    489:                /*
                    490:                 * This situation can happen in perfectly normal operation
                    491:                 * if the ESP is reselected while using DMA to select
                    492:                 * another target.  As such, don't print the warning.
                    493:                 */
                    494:                printf("%s: xfer (%d) > req (%d)\n",
                    495:                    sc->sc_dev.dv_xname, trans, esc->sc_dmasize);
                    496: #endif
                    497:                trans = esc->sc_dmasize;
                    498:        }
                    499:
                    500:        NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
                    501:            PCSCP_READ_REG(esc, NCR_TCL),
                    502:            PCSCP_READ_REG(esc, NCR_TCM),
                    503:            PCSCP_READ_REG(esc, NCR_TCH),
                    504:            trans, resid));
                    505:
                    506:        *esc->sc_dmalen -= trans;
                    507:        *esc->sc_dmaaddr += trans;
                    508:
                    509:        return 0;
                    510: }
                    511:
                    512: int
                    513: pcscp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
                    514:     int datain, size_t *dmasize)
                    515: {
                    516:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    517:        bus_dmamap_t dmap = esc->sc_xfermap;
                    518:        u_int32_t *mdl;
                    519:        int error, nseg, seg;
                    520:        bus_addr_t s_offset, s_addr;
                    521:
                    522:        WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | (datain ? DMACMD_DIR : 0));
                    523:
                    524:        esc->sc_dmaaddr = addr;
                    525:        esc->sc_dmalen = len;
                    526:        esc->sc_dmasize = *dmasize;
                    527:        esc->sc_datain = datain;
                    528:
                    529: #ifdef DIAGNOSTIC
                    530:        if ((*dmasize / MDL_SEG_SIZE) > MDL_SIZE)
                    531:                panic("pcscp: transfer size too large");
                    532: #endif
                    533:
                    534:        /*
                    535:         * No need to set up DMA in `Transfer Pad' operation.
                    536:         * (case of *dmasize == 0)
                    537:         */
                    538:        if (*dmasize == 0)
                    539:                return 0;
                    540:
                    541:        error = bus_dmamap_load(esc->sc_dmat, dmap, *esc->sc_dmaaddr,
                    542:            *esc->sc_dmalen, NULL,
                    543:            ((sc->sc_nexus->xs->flags & SCSI_NOSLEEP) ?
                    544:            BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_STREAMING |
                    545:            ((sc->sc_nexus->xs->flags & SCSI_DATA_IN) ?
                    546:             BUS_DMA_READ : BUS_DMA_WRITE));
                    547:        if (error) {
                    548:                printf("%s: unable to load dmamap, error = %d\n",
                    549:                    sc->sc_dev.dv_xname, error);
                    550:                return error;
                    551:        }
                    552:
                    553:        /* set transfer length */
                    554:        WRITE_DMAREG(esc, DMA_STC, *dmasize);
                    555:
                    556:        /* set up MDL */
                    557:        mdl = esc->sc_mdladdr;
                    558:        nseg = dmap->dm_nsegs;
                    559:
                    560:        /* the first segment is possibly not aligned with 4k MDL boundary */
                    561:        s_addr = dmap->dm_segs[0].ds_addr;
                    562:        s_offset = s_addr & MDL_SEG_OFFSET;
                    563:        s_addr -= s_offset;
                    564:
                    565:        /* set the first MDL and offset */
                    566:        WRITE_DMAREG(esc, DMA_SPA, s_offset);
                    567:        *mdl++ = htole32(s_addr);
                    568:
                    569:        /* the rest dmamap segments are aligned with 4k boundary */
                    570:        for (seg = 1; seg < nseg; seg++)
                    571:                *mdl++ = htole32(dmap->dm_segs[seg].ds_addr);
                    572:
                    573:        return 0;
                    574: }
                    575:
                    576: void
                    577: pcscp_dma_go(struct ncr53c9x_softc *sc)
                    578: {
                    579:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    580:        bus_dmamap_t dmap = esc->sc_xfermap, mdldmap = esc->sc_mdldmap;
                    581:        int datain = esc->sc_datain;
                    582:
                    583:        /* No DMA transfer in Transfer Pad operation */
                    584:        if (esc->sc_dmasize == 0)
                    585:                return;
                    586:
                    587:        /* sync transfer buffer */
                    588:        bus_dmamap_sync(esc->sc_dmat, dmap, 0, dmap->dm_mapsize,
                    589:            datain ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
                    590:
                    591:        /* sync MDL */
                    592:        bus_dmamap_sync(esc->sc_dmat, mdldmap,
                    593:            0, sizeof(u_int32_t) * dmap->dm_nsegs, BUS_DMASYNC_PREWRITE);
                    594:
                    595:        /* set Starting MDL Address */
                    596:        WRITE_DMAREG(esc, DMA_SMDLA, mdldmap->dm_segs[0].ds_addr);
                    597:
                    598:        /* set DMA command register bits */
                    599:        /* XXX DMA Transfer Interrupt Enable bit is broken? */
                    600:        WRITE_DMAREG(esc, DMA_CMD, DMACMD_IDLE | DMACMD_MDL |
                    601:            /* DMACMD_INTE | */
                    602:            (datain ? DMACMD_DIR : 0));
                    603:
                    604:        /* issue DMA start command */
                    605:        WRITE_DMAREG(esc, DMA_CMD, DMACMD_START | DMACMD_MDL |
                    606:            /* DMACMD_INTE | */
                    607:            (datain ? DMACMD_DIR : 0));
                    608:
                    609:        esc->sc_active = 1;
                    610: }
                    611:
                    612: void
                    613: pcscp_dma_stop(struct ncr53c9x_softc *sc)
                    614: {
                    615:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    616:
                    617:        /* dma stop */
                    618:        /* XXX What should we do here ? */
                    619:        WRITE_DMAREG(esc, DMA_CMD,
                    620:            DMACMD_ABORT | (esc->sc_datain ? DMACMD_DIR : 0));
                    621:        bus_dmamap_unload(esc->sc_dmat, esc->sc_xfermap);
                    622:
                    623:        esc->sc_active = 0;
                    624: }
                    625:
                    626: int
                    627: pcscp_dma_isactive(struct ncr53c9x_softc *sc)
                    628: {
                    629:        struct pcscp_softc *esc = (struct pcscp_softc *)sc;
                    630:
                    631:        /* XXX should check esc->sc_active? */
                    632:        if ((READ_DMAREG(esc, DMA_CMD) & DMACMD_CMD) != DMACMD_IDLE)
                    633:                return 1;
                    634:        return 0;
                    635: }

CVSweb