[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     ! 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