[BACK]Return to esp.c CVS log [TXT][DIR] Up to [local] / sys / arch / macppc / dev

Annotation of sys/arch/macppc/dev/esp.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: esp.c,v 1.3 2007/04/22 22:31:14 deraadt Exp $ */
                      2:
                      3: /*-
                      4:  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
                      9:  * Simulation Facility, NASA Ames Research Center.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by the NetBSD
                     22:  *     Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * Copyright (c) 1994 Peter Galbavy
                     42:  * All rights reserved.
                     43:  *
                     44:  * Redistribution and use in source and binary forms, with or without
                     45:  * modification, are permitted provided that the following conditions
                     46:  * are met:
                     47:  * 1. Redistributions of source code must retain the above copyright
                     48:  *    notice, this list of conditions and the following disclaimer.
                     49:  * 2. Redistributions in binary form must reproduce the above copyright
                     50:  *    notice, this list of conditions and the following disclaimer in the
                     51:  *    documentation and/or other materials provided with the distribution.
                     52:  * 3. All advertising materials mentioning features or use of this software
                     53:  *    must display the following acknowledgement:
                     54:  *     This product includes software developed by Peter Galbavy
                     55:  * 4. The name of the author may not be used to endorse or promote products
                     56:  *    derived from this software without specific prior written permission.
                     57:  *
                     58:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     59:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     60:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     61:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     62:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     63:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     64:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     65:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     66:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     67:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     68:  * POSSIBILITY OF SUCH DAMAGE.
                     69:  */
                     70:
                     71: /*
                     72:  * Based on aic6360 by Jarle Greipsland
                     73:  *
                     74:  * Acknowledgements: Many of the algorithms used in this driver are
                     75:  * inspired by the work of Julian Elischer (julian@tfs.com) and
                     76:  * Charles Hannum (mycroft@duality.gnu.ai.mit.edu).  Thanks a million!
                     77:  */
                     78:
                     79: #include <sys/cdefs.h>
                     80:
                     81: #include <sys/types.h>
                     82: #include <sys/param.h>
                     83: #include <sys/systm.h>
                     84: #include <sys/kernel.h>
                     85: #include <sys/errno.h>
                     86: #include <sys/ioctl.h>
                     87: #include <sys/device.h>
                     88: #include <sys/buf.h>
                     89: #include <sys/proc.h>
                     90: #include <sys/user.h>
                     91: #include <sys/queue.h>
                     92: #include <sys/malloc.h>
                     93:
                     94: #include <uvm/uvm_extern.h>
                     95:
                     96: #include <scsi/scsi_all.h>
                     97: #include <scsi/scsiconf.h>
                     98: #include <scsi/scsi_message.h>
                     99:
                    100: #include <dev/ofw/openfirm.h>
                    101:
                    102: #include <machine/cpu.h>
                    103: #include <machine/autoconf.h>
                    104: #include <machine/pio.h>
                    105:
                    106: #include <dev/ic/ncr53c9xreg.h>
                    107: #include <dev/ic/ncr53c9xvar.h>
                    108:
                    109: #include <macppc/dev/dbdma.h>
                    110:
                    111: struct esp_softc {
                    112:        struct ncr53c9x_softc sc_ncr53c9x;      /* glue to MI code */
                    113:
                    114:        struct intrhand sc_ih;                  /* intr handler */
                    115:
                    116:        volatile u_char *sc_reg;                /* the registers */
                    117:
                    118:        bus_dmamap_t sc_dmamap;
                    119:        bus_dma_tag_t sc_dmat;
                    120:        dbdma_t sc_dbdma;
                    121:        dbdma_regmap_t *sc_dmareg;              /* DMA registers */
                    122:        dbdma_command_t *sc_dmacmd;             /* command area for DMA */
                    123:
                    124:        int sc_node;                            /* node ID */
                    125:        int sc_intr;
                    126:
                    127:        size_t  sc_dmasize;
                    128:        caddr_t *sc_dmaaddr;
                    129:        size_t  *sc_dmalen;
                    130:        int sc_dmaactive;
                    131:        int sc_dma_direction;
                    132: };
                    133:
                    134: #define D_WRITE 1
                    135: #define ESP_DMALIST_MAX        20
                    136:
                    137: void espattach(struct device *, struct device *, void *);
                    138: int espmatch(struct device *, void *, void *);
                    139:
                    140: /* Linkup to the rest of the kernel */
                    141: struct cfattach esp_ca = {
                    142:        sizeof(struct esp_softc), espmatch, espattach
                    143: };
                    144:
                    145: struct scsi_adapter esp_switch = {
                    146:        /* no max at this level; handled by DMA code */
                    147:        ncr53c9x_scsi_cmd, minphys, NULL, NULL,
                    148: };
                    149:
                    150: struct scsi_device esp_dev = {
                    151:        NULL, NULL, NULL, NULL,
                    152: };
                    153:
                    154: /*
                    155:  * Functions and the switch for the MI code.
                    156:  */
                    157: u_char esp_read_reg(struct ncr53c9x_softc *, int);
                    158: void   esp_write_reg(struct ncr53c9x_softc *, int, u_char);
                    159: int    esp_dma_isintr(struct ncr53c9x_softc *);
                    160: void   esp_dma_reset(struct ncr53c9x_softc *);
                    161: int    esp_dma_intr(struct ncr53c9x_softc *);
                    162: int    esp_dma_setup(struct ncr53c9x_softc *, caddr_t *,
                    163:     size_t *, int, size_t *);
                    164: void   esp_dma_go(struct ncr53c9x_softc *);
                    165: void   esp_dma_stop(struct ncr53c9x_softc *);
                    166: int    esp_dma_isactive(struct ncr53c9x_softc *);
                    167:
                    168: struct ncr53c9x_glue esp_glue = {
                    169:        esp_read_reg,
                    170:        esp_write_reg,
                    171:        esp_dma_isintr,
                    172:        esp_dma_reset,
                    173:        esp_dma_intr,
                    174:        esp_dma_setup,
                    175:        esp_dma_go,
                    176:        esp_dma_stop,
                    177:        esp_dma_isactive,
                    178:        NULL,                   /* gl_clear_latched_intr */
                    179: };
                    180:
                    181: static int espdmaintr(struct esp_softc *);
                    182: static void esp_shutdownhook(void *);
                    183:
                    184: int
                    185: espmatch(struct device *parent, void *cf, void *aux)
                    186: {
                    187:        struct confargs *ca = aux;
                    188:
                    189:        if (strcmp(ca->ca_name, "53c94") != 0)
                    190:                return 0;
                    191:
                    192:        if (ca->ca_nreg != 16)
                    193:                return 0;
                    194:        if (ca->ca_nintr != 8)
                    195:                return 0;
                    196:
                    197:        return 1;
                    198: }
                    199:
                    200: /*
                    201:  * Attach this instance, and then all the sub-devices
                    202:  */
                    203: void
                    204: espattach(struct device *parent, struct device *self, void *aux)
                    205: {
                    206:        struct confargs *ca = aux;
                    207:        struct esp_softc *esc = (void *)self;
                    208:        struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
                    209:        u_int *reg;
                    210:        int sz, error;
                    211:
                    212:        /*
                    213:         * Set up glue for MI code early; we use some of it here.
                    214:         */
                    215:        sc->sc_glue = &esp_glue;
                    216:
                    217:        esc->sc_node = ca->ca_node;
                    218:        esc->sc_intr = ca->ca_intr[0];
                    219:        printf(" irq %d", esc->sc_intr);
                    220:
                    221:        /*
                    222:         * Map my registers in.
                    223:         */
                    224:        reg = ca->ca_reg;
                    225:        esc->sc_reg = mapiodev(ca->ca_baseaddr + reg[0], reg[1]);
                    226:        esc->sc_dmareg = mapiodev(ca->ca_baseaddr + reg[2], reg[3]);
                    227:
                    228:        esc->sc_dmat = ca->ca_dmat;
                    229:        if ((error = bus_dmamap_create(esc->sc_dmat,
                    230:            ESP_DMALIST_MAX * DBDMA_COUNT_MAX, ESP_DMALIST_MAX,
                    231:            DBDMA_COUNT_MAX, NBPG, BUS_DMA_NOWAIT, &esc->sc_dmamap)) != 0) {
                    232:                printf(": cannot create dma map, error = %d\n", error);
                    233:                return;
                    234:        }
                    235:
                    236:        /* Allocate 16-byte aligned DMA command space */
                    237:        esc->sc_dbdma = dbdma_alloc(esc->sc_dmat, ESP_DMALIST_MAX);
                    238:        esc->sc_dmacmd = esc->sc_dbdma->d_addr;
                    239:
                    240:        /* Other settings */
                    241:        sc->sc_id = 7;
                    242:        sz = OF_getprop(ca->ca_node, "clock-frequency",
                    243:                &sc->sc_freq, sizeof(int));
                    244:        if (sz != sizeof(int))
                    245:                sc->sc_freq = 25000000;
                    246:
                    247:        /* gimme MHz */
                    248:        sc->sc_freq /= 1000000;
                    249:
                    250:        /*
                    251:         * Set up static configuration info.
                    252:         */
                    253:        sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
                    254:        sc->sc_cfg2 = NCRCFG2_SCSI2; /* | NCRCFG2_FE */
                    255:        sc->sc_cfg3 = NCRCFG3_CDB;
                    256:        sc->sc_rev = NCR_VARIANT_NCR53C94;
                    257:
                    258:        /*
                    259:         * This is the value used to start sync negotiations
                    260:         * Note that the NCR register "SYNCTP" is programmed
                    261:         * in "clocks per byte", and has a minimum value of 4.
                    262:         * The SCSI period used in negotiation is one-fourth
                    263:         * of the time (in nanoseconds) needed to transfer one byte.
                    264:         * Since the chip's clock is given in MHz, we have the following
                    265:         * formula: 4 * period = (1000 / freq) * 4
                    266:         */
                    267:        sc->sc_minsync = 1000 / sc->sc_freq;
                    268:
                    269:        sc->sc_maxxfer = 64 * 1024;
                    270:
                    271:        /* and the interuppts */
                    272:        mac_intr_establish(parent, esc->sc_intr, IST_LEVEL, IPL_BIO,
                    273:            ncr53c9x_intr, sc, sc->sc_dev.dv_xname);
                    274:
                    275:        /* Reset SCSI bus when halt. */
                    276:        shutdownhook_establish(esp_shutdownhook, sc);
                    277:
                    278:        /* Turn on target selection using the `DMA' method */
                    279:        sc->sc_features |= NCR_F_DMASELECT;
                    280:
                    281:        ncr53c9x_attach(sc, &esp_switch, &esp_dev);
                    282:
                    283: }
                    284:
                    285: /*
                    286:  * Glue functions.
                    287:  */
                    288:
                    289: u_char
                    290: esp_read_reg(struct ncr53c9x_softc *sc, int reg)
                    291: {
                    292:        struct esp_softc *esc = (struct esp_softc *)sc;
                    293:
                    294:        return in8(&esc->sc_reg[reg * 16]);
                    295: }
                    296:
                    297: void
                    298: esp_write_reg(struct ncr53c9x_softc *sc, int reg, u_char val)
                    299: {
                    300:        struct esp_softc *esc = (struct esp_softc *)sc;
                    301:        u_char v = val;
                    302:
                    303:        out8(&esc->sc_reg[reg * 16], v);
                    304: }
                    305:
                    306: int
                    307: esp_dma_isintr(struct ncr53c9x_softc *sc)
                    308: {
                    309:        return esp_read_reg(sc, NCR_STAT) & NCRSTAT_INT;
                    310: }
                    311:
                    312: void
                    313: esp_dma_reset(struct ncr53c9x_softc *sc)
                    314: {
                    315:        struct esp_softc *esc = (struct esp_softc *)sc;
                    316:
                    317:        dbdma_stop(esc->sc_dmareg);
                    318:        esc->sc_dmaactive = 0;
                    319: }
                    320:
                    321: int
                    322: esp_dma_intr(struct ncr53c9x_softc *sc)
                    323: {
                    324:        struct esp_softc *esc = (struct esp_softc *)sc;
                    325:
                    326:        return (espdmaintr(esc));
                    327: }
                    328:
                    329: int
                    330: esp_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
                    331:      int datain, size_t *dmasize)
                    332: {
                    333:        struct esp_softc *esc = (struct esp_softc *)sc;
                    334:        dbdma_command_t *cmdp;
                    335:        u_int cmd;
                    336:        int i, error;
                    337:
                    338:        cmdp = esc->sc_dmacmd;
                    339:        cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
                    340:
                    341:        esc->sc_dmaaddr = addr;
                    342:        esc->sc_dmalen = len;
                    343:        esc->sc_dmasize = *dmasize;
                    344:
                    345:        if ((error = bus_dmamap_load(esc->sc_dmat, esc->sc_dmamap, *addr,
                    346:            *dmasize, NULL, BUS_DMA_NOWAIT)) != 0)
                    347:                return (error);
                    348:
                    349:        for (i = 0; i < esc->sc_dmamap->dm_nsegs; i++, cmdp++) {
                    350:                if (i + 1 == esc->sc_dmamap->dm_nsegs)
                    351:                        cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST;
                    352:                DBDMA_BUILD(cmdp, cmd, 0, esc->sc_dmamap->dm_segs[i].ds_len,
                    353:                    esc->sc_dmamap->dm_segs[i].ds_addr, DBDMA_INT_NEVER,
                    354:                    DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                    355:        }
                    356:        DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
                    357:            DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                    358:
                    359:        esc->sc_dma_direction = datain ? D_WRITE : 0;
                    360:
                    361:        return 0;
                    362: }
                    363:
                    364: void
                    365: esp_dma_go(struct ncr53c9x_softc *sc)
                    366: {
                    367:        struct esp_softc *esc = (struct esp_softc *)sc;
                    368:
                    369:        dbdma_start(esc->sc_dmareg, esc->sc_dbdma);
                    370:        esc->sc_dmaactive = 1;
                    371: }
                    372:
                    373: void
                    374: esp_dma_stop(struct ncr53c9x_softc *sc)
                    375: {
                    376:        struct esp_softc *esc = (struct esp_softc *)sc;
                    377:
                    378:        dbdma_stop(esc->sc_dmareg);
                    379:        bus_dmamap_unload(esc->sc_dmat, esc->sc_dmamap);
                    380:        esc->sc_dmaactive = 0;
                    381: }
                    382:
                    383: int
                    384: esp_dma_isactive(struct ncr53c9x_softc *sc)
                    385: {
                    386:        struct esp_softc *esc = (struct esp_softc *)sc;
                    387:
                    388:        return (esc->sc_dmaactive);
                    389: }
                    390:
                    391:
                    392: /*
                    393:  * Pseudo (chained) interrupt from the esp driver to kick the
                    394:  * current running DMA transfer. I am replying on espintr() to
                    395:  * pickup and clean errors for now
                    396:  *
                    397:  * return 1 if it was a DMA continue.
                    398:  */
                    399: int
                    400: espdmaintr(struct esp_softc *sc)
                    401: {
                    402:        struct ncr53c9x_softc *nsc = (struct ncr53c9x_softc *)sc;
                    403:        int trans, resid;
                    404:        u_long csr = sc->sc_dma_direction;
                    405:
                    406:        /* This is an "assertion" :) */
                    407:        if (sc->sc_dmaactive == 0)
                    408:                panic("dmaintr: DMA wasn't active");
                    409:
                    410:        /* DMA has stopped */
                    411:        dbdma_stop(sc->sc_dmareg);
                    412:        bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
                    413:        sc->sc_dmaactive = 0;
                    414:
                    415:        if (sc->sc_dmasize == 0) {
                    416:                /* A "Transfer Pad" operation completed */
                    417:                NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
                    418:                    NCR_READ_REG(nsc, NCR_TCL) |
                    419:                    (NCR_READ_REG(nsc, NCR_TCM) << 8),
                    420:                    NCR_READ_REG(nsc, NCR_TCL),
                    421:                    NCR_READ_REG(nsc, NCR_TCM)));
                    422:                return 0;
                    423:        }
                    424:
                    425:        resid = 0;
                    426:        /*
                    427:         * If a transfer onto the SCSI bus gets interrupted by the device
                    428:         * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
                    429:         * as residual since the ESP counter registers get decremented as
                    430:         * bytes are clocked into the FIFO.
                    431:         */
                    432:        if (!(csr & D_WRITE) &&
                    433:            (resid = (NCR_READ_REG(nsc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
                    434:                NCR_DMA(("dmaintr: empty esp FIFO of %d ", resid));
                    435:        }
                    436:
                    437:        if ((nsc->sc_espstat & NCRSTAT_TC) == 0) {
                    438:                /*
                    439:                 * `Terminal count' is off, so read the residue
                    440:                 * out of the ESP counter registers.
                    441:                 */
                    442:                resid += (NCR_READ_REG(nsc, NCR_TCL) |
                    443:                    (NCR_READ_REG(nsc, NCR_TCM) << 8) |
                    444:                    ((nsc->sc_cfg2 & NCRCFG2_FE)
                    445:                    ? (NCR_READ_REG(nsc, NCR_TCH) << 16) : 0));
                    446:
                    447:                if (resid == 0 && sc->sc_dmasize == 65536 &&
                    448:                    (nsc->sc_cfg2 & NCRCFG2_FE) == 0)
                    449:                        /* A transfer of 64K is encoded as `TCL=TCM=0' */
                    450:                        resid = 65536;
                    451:        }
                    452:
                    453:        trans = sc->sc_dmasize - resid;
                    454:        if (trans < 0) {                        /* transferred < 0 ? */
                    455:                trans = sc->sc_dmasize;
                    456:        }
                    457:
                    458:        NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
                    459:            NCR_READ_REG(nsc, NCR_TCL), NCR_READ_REG(nsc, NCR_TCM),
                    460:            (nsc->sc_cfg2 & NCRCFG2_FE) ? NCR_READ_REG(nsc, NCR_TCH) : 0,
                    461:            trans, resid));
                    462:
                    463:
                    464:        *sc->sc_dmalen -= trans;
                    465:        *sc->sc_dmaaddr += trans;
                    466:
                    467:        return 0;
                    468: }
                    469:
                    470: void
                    471: esp_shutdownhook(void *arg)
                    472: {
                    473:        struct ncr53c9x_softc *sc = arg;
                    474:
                    475:        NCRCMD(sc, NCRCMD_RSTSCSI);
                    476: }

CVSweb