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

Annotation of sys/dev/ic/oosiop.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: oosiop.c,v 1.5 2006/11/28 23:59:45 dlg Exp $  */
                      2: /*     $NetBSD: oosiop.c,v 1.4 2003/10/29 17:45:55 tsutsui Exp $       */
                      3:
                      4: /*
                      5:  * Copyright (c) 2001 Shuichiro URATA.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. The name of the author may not be used to endorse or promote products
                     16:  *    derived from this software without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     28:  */
                     29:
                     30: /*
                     31:  * NCR53C700 SCSI I/O processor (OOSIOP) driver
                     32:  *
                     33:  * TODO:
                     34:  *   - Better error handling.
                     35:  *   - Implement tagged queuing.
                     36:  */
                     37:
                     38: #include <sys/param.h>
                     39: #include <sys/systm.h>
                     40: #include <sys/timeout.h>
                     41: #include <sys/kernel.h>
                     42: #include <sys/device.h>
                     43: #include <sys/buf.h>
                     44: #include <sys/malloc.h>
                     45: #include <sys/queue.h>
                     46:
                     47: #include <uvm/uvm_extern.h>
                     48:
                     49: #include <scsi/scsi_all.h>
                     50: #include <scsi/scsiconf.h>
                     51: #include <scsi/scsi_message.h>
                     52:
                     53: #include <machine/cpu.h>
                     54: #include <machine/bus.h>
                     55:
                     56: #include <dev/ic/oosiopreg.h>
                     57: #include <dev/ic/oosiopvar.h>
                     58:
                     59: /* 53C700 script */
                     60: #include <dev/microcode/siop/oosiop.out>
                     61:
                     62: int    oosiop_alloc_cb(struct oosiop_softc *, int);
                     63:
                     64: static __inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t);
                     65: static __inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t);
                     66: static __inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t,
                     67:                         int);
                     68: static __inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t,
                     69:                         bus_addr_t);
                     70: static __inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t,
                     71:                         bus_size_t, bus_addr_t);
                     72:
                     73: void   oosiop_load_script(struct oosiop_softc *);
                     74: void   oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *);
                     75: void   oosiop_setup_dma(struct oosiop_softc *);
                     76: void   oosiop_flush_fifo(struct oosiop_softc *);
                     77: void   oosiop_clear_fifo(struct oosiop_softc *);
                     78: void   oosiop_phasemismatch(struct oosiop_softc *);
                     79: void   oosiop_setup_syncxfer(struct oosiop_softc *);
                     80: void   oosiop_set_syncparam(struct oosiop_softc *, int, int, int);
                     81: void   oosiop_minphys(struct buf *);
                     82: int    oosiop_scsicmd(struct scsi_xfer *);
                     83: void   oosiop_done(struct oosiop_softc *, struct oosiop_cb *);
                     84: void   oosiop_timeout(void *);
                     85: void   oosiop_reset(struct oosiop_softc *);
                     86: void   oosiop_reset_bus(struct oosiop_softc *);
                     87: void   oosiop_scriptintr(struct oosiop_softc *);
                     88: void   oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *);
                     89: void   oosiop_setup(struct oosiop_softc *, struct oosiop_cb *);
                     90: void   oosiop_poll(struct oosiop_softc *, struct oosiop_cb *);
                     91: void   oosiop_processintr(struct oosiop_softc *, u_int8_t);
                     92:
                     93: /* Trap interrupt code for unexpected data I/O */
                     94: #define        DATAIN_TRAP     0xdead0001
                     95: #define        DATAOUT_TRAP    0xdead0002
                     96:
                     97: /* Possible TP and SCF conbination */
                     98: static const struct {
                     99:        u_int8_t        tp;
                    100:        u_int8_t        scf;
                    101: } synctbl[] = {
                    102:        {0, 1},         /* SCLK /  4.0 */
                    103:        {1, 1},         /* SCLK /  5.0 */
                    104:        {2, 1},         /* SCLK /  6.0 */
                    105:        {3, 1},         /* SCLK /  7.0 */
                    106:        {1, 2},         /* SCLK /  7.5 */
                    107:        {4, 1},         /* SCLK /  8.0 */
                    108:        {5, 1},         /* SCLK /  9.0 */
                    109:        {6, 1},         /* SCLK / 10.0 */
                    110:        {3, 2},         /* SCLK / 10.5 */
                    111:        {7, 1},         /* SCLK / 11.0 */
                    112:        {4, 2},         /* SCLK / 12.0 */
                    113:        {5, 2},         /* SCLK / 13.5 */
                    114:        {3, 3},         /* SCLK / 14.0 */
                    115:        {6, 2},         /* SCLK / 15.0 */
                    116:        {4, 3},         /* SCLK / 16.0 */
                    117:        {7, 2},         /* SCLK / 16.5 */
                    118:        {5, 3},         /* SCLK / 18.0 */
                    119:        {6, 3},         /* SCLK / 20.0 */
                    120:        {7, 3}          /* SCLK / 22.0 */
                    121: };
                    122: #define        NSYNCTBL        (sizeof(synctbl) / sizeof(synctbl[0]))
                    123:
                    124: #define        oosiop_period(sc, tp, scf)                                      \
                    125:            (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40)
                    126:
                    127: struct cfdriver oosiop_cd = {
                    128:        NULL, "oosiop", DV_DULL
                    129: };
                    130:
                    131: struct scsi_adapter oosiop_adapter = {
                    132:        oosiop_scsicmd,
                    133:        oosiop_minphys,
                    134:        NULL,
                    135:        NULL
                    136: };
                    137:
                    138: struct scsi_device oosiop_dev = {
                    139:        NULL,
                    140:        NULL,
                    141:        NULL,
                    142:        NULL
                    143: };
                    144:
                    145: void
                    146: oosiop_attach(struct oosiop_softc *sc)
                    147: {
                    148:        struct scsibus_attach_args saa;
                    149:        bus_size_t scrsize;
                    150:        bus_dma_segment_t seg;
                    151:        struct oosiop_cb *cb;
                    152:        int err, i, nseg;
                    153:
                    154:        /*
                    155:         * Allocate DMA-safe memory for the script and map it.
                    156:         */
                    157:        scrsize = round_page(sizeof(oosiop_script));
                    158:        err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1,
                    159:            &nseg, BUS_DMA_NOWAIT);
                    160:        if (err) {
                    161:                printf(": failed to allocate script memory, err=%d\n", err);
                    162:                return;
                    163:        }
                    164:        err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize,
                    165:            (caddr_t *)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
                    166:        if (err) {
                    167:                printf(": failed to map script memory, err=%d\n", err);
                    168:                return;
                    169:        }
                    170:        err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0,
                    171:            BUS_DMA_NOWAIT, &sc->sc_scrdma);
                    172:        if (err) {
                    173:                printf(": failed to create script map, err=%d\n", err);
                    174:                return;
                    175:        }
                    176:        err = bus_dmamap_load_raw(sc->sc_dmat, sc->sc_scrdma,
                    177:            &seg, nseg, scrsize, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
                    178:        if (err) {
                    179:                printf(": failed to load script map, err=%d\n", err);
                    180:                return;
                    181:        }
                    182:        bzero(sc->sc_scr, scrsize);
                    183:        sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr;
                    184:
                    185:        /* Initialize command block array */
                    186:        TAILQ_INIT(&sc->sc_free_cb);
                    187:        TAILQ_INIT(&sc->sc_cbq);
                    188:        if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0)
                    189:                return;
                    190:
                    191:        /* Use first cb to reselection msgin buffer */
                    192:        cb = TAILQ_FIRST(&sc->sc_free_cb);
                    193:        sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr +
                    194:            offsetof(struct oosiop_xfer, msgin[0]);
                    195:
                    196:        for (i = 0; i < OOSIOP_NTGT; i++) {
                    197:                sc->sc_tgt[i].nexus = NULL;
                    198:                sc->sc_tgt[i].flags = 0;
                    199:        }
                    200:
                    201:        /* Setup asynchronous clock divisor parameters */
                    202:        if (sc->sc_freq <= 25000000) {
                    203:                sc->sc_ccf = 10;
                    204:                sc->sc_dcntl = OOSIOP_DCNTL_CF_1;
                    205:        } else if (sc->sc_freq <= 37500000) {
                    206:                sc->sc_ccf = 15;
                    207:                sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5;
                    208:        } else if (sc->sc_freq <= 50000000) {
                    209:                sc->sc_ccf = 20;
                    210:                sc->sc_dcntl = OOSIOP_DCNTL_CF_2;
                    211:        } else {
                    212:                sc->sc_ccf = 30;
                    213:                sc->sc_dcntl = OOSIOP_DCNTL_CF_3;
                    214:        }
                    215:
                    216:        if (sc->sc_chip == OOSIOP_700)
                    217:                sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf);
                    218:        else
                    219:                sc->sc_minperiod = oosiop_period(sc, 4, 10);
                    220:
                    221:        if (sc->sc_minperiod < 25)
                    222:                sc->sc_minperiod = 25;  /* limit to 10MB/s */
                    223:
                    224:        printf(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n",
                    225:            sc->sc_chip == OOSIOP_700_66 ? "-66" : "",
                    226:            oosiop_read_1(sc, OOSIOP_CTEST7) >> 4,
                    227:            sc->sc_freq / 1000000, sc->sc_id);
                    228:        /*
                    229:         * Reset all
                    230:         */
                    231:        oosiop_reset(sc);
                    232:        oosiop_reset_bus(sc);
                    233:
                    234:        /*
                    235:         * Start SCRIPTS processor
                    236:         */
                    237:        oosiop_load_script(sc);
                    238:        sc->sc_active = 0;
                    239:        oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect);
                    240:
                    241:        /*
                    242:         * Fill in the sc_link.
                    243:         */
                    244:        sc->sc_link.adapter = &oosiop_adapter;
                    245:        sc->sc_link.adapter_softc = sc;
                    246:        sc->sc_link.device = &oosiop_dev;
                    247:        sc->sc_link.openings = 1;       /* XXX */
                    248:        sc->sc_link.adapter_buswidth = OOSIOP_NTGT;
                    249:        sc->sc_link.adapter_target = sc->sc_id;
                    250:        sc->sc_link.quirks = ADEV_NODOORLOCK;
                    251:
                    252:        bzero(&saa, sizeof(saa));
                    253:        saa.saa_sc_link = &sc->sc_link;
                    254:
                    255:        /*
                    256:         * Now try to attach all the sub devices.
                    257:         */
                    258:        config_found(&sc->sc_dev, &saa, scsiprint);
                    259: }
                    260:
                    261: int
                    262: oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
                    263: {
                    264:        struct oosiop_cb *cb;
                    265:        struct oosiop_xfer *xfer;
                    266:        bus_size_t xfersize;
                    267:        bus_dma_segment_t seg;
                    268:        int i, s, err, nseg;
                    269:
                    270:        /*
                    271:         * Allocate oosiop_cb.
                    272:         */
                    273:        cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT);
                    274:        if (cb == NULL) {
                    275:                printf(": failed to allocate cb memory\n");
                    276:                return (ENOMEM);
                    277:        }
                    278:        bzero(cb, sizeof(struct oosiop_cb) * ncb);
                    279:
                    280:        /*
                    281:         * Allocate DMA-safe memory for the oosiop_xfer and map it.
                    282:         */
                    283:        xfersize = sizeof(struct oosiop_xfer) * ncb;
                    284:        err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1,
                    285:            &nseg, BUS_DMA_NOWAIT);
                    286:        if (err) {
                    287:                printf(": failed to allocate xfer block memory, err=%d\n", err);
                    288:                return (err);
                    289:        }
                    290:        err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
                    291:            (caddr_t *)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
                    292:        if (err) {
                    293:                printf(": failed to map xfer block memory, err=%d\n", err);
                    294:                return (err);
                    295:        }
                    296:
                    297:        /* Initialize each command block */
                    298:        for (i = 0; i < ncb; i++) {
                    299:                err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
                    300:                    0, BUS_DMA_NOWAIT, &cb->cmddma);
                    301:                if (err) {
                    302:                        printf(": failed to create cmddma map, err=%d\n", err);
                    303:                        return (err);
                    304:                }
                    305:
                    306:                err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
                    307:                    OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
                    308:                    &cb->datadma);
                    309:                if (err) {
                    310:                        printf(": failed to create datadma map, err=%d\n", err);
                    311:                        return (err);
                    312:                }
                    313:
                    314:                err = bus_dmamap_create(sc->sc_dmat,
                    315:                    sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
                    316:                    0, BUS_DMA_NOWAIT, &cb->xferdma);
                    317:                if (err) {
                    318:                        printf(": failed to create xfer block map, err=%d\n",
                    319:                            err);
                    320:                        return (err);
                    321:                }
                    322:                err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
                    323:                    sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
                    324:                if (err) {
                    325:                        printf(": failed to load xfer block, err=%d\n", err);
                    326:                        return (err);
                    327:                }
                    328:
                    329:                cb->xfer = xfer;
                    330:
                    331:                s = splbio();
                    332:                TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
                    333:                splx(s);
                    334:
                    335:                cb++;
                    336:                xfer++;
                    337:        }
                    338:
                    339:        return (0);
                    340: }
                    341:
                    342: static __inline void
                    343: oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr)
                    344: {
                    345:        u_int32_t dcmd;
                    346:        int32_t dsps;
                    347:
                    348:        dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
                    349:        dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
                    350:
                    351:        /* convert relative to absolute */
                    352:        if (dcmd & 0x04000000) {
                    353:                dcmd &= ~0x04000000;
                    354: #if 0
                    355:                /*
                    356:                 * sign extension isn't needed here because
                    357:                 * ncr53cxxx.c generates 32 bit dsps.
                    358:                 */
                    359:                dsps <<= 8;
                    360:                dsps >>= 8;
                    361: #endif
                    362:                sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
                    363:                dsps += addr + 8;
                    364:        }
                    365:
                    366:        sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
                    367: }
                    368:
                    369: static __inline void
                    370: oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr)
                    371: {
                    372:        u_int32_t dcmd;
                    373:        int32_t dsps;
                    374:
                    375:        dcmd = letoh32(sc->sc_scr[addr / 4 + 0]);
                    376:        dsps = letoh32(sc->sc_scr[addr / 4 + 1]);
                    377:
                    378:        /* convert relative to absolute */
                    379:        if (dcmd & 0x00800000) {
                    380:                dcmd &= ~0x00800000;
                    381:                sc->sc_scr[addr / 4] = htole32(dcmd);
                    382: #if 0
                    383:                /*
                    384:                 * sign extension isn't needed here because
                    385:                 * ncr53cxxx.c generates 32 bit dsps.
                    386:                 */
                    387:                dsps <<= 8;
                    388:                dsps >>= 8;
                    389: #endif
                    390:                dsps += addr + 8;
                    391:        }
                    392:
                    393:        sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase);
                    394: }
                    395:
                    396: static __inline void
                    397: oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id)
                    398: {
                    399:        u_int32_t dcmd;
                    400:
                    401:        dcmd = letoh32(sc->sc_scr[addr / 4]);
                    402:        dcmd &= 0xff00ffff;
                    403:        dcmd |= 0x00010000 << id;
                    404:        sc->sc_scr[addr / 4] = htole32(dcmd);
                    405: }
                    406:
                    407: static __inline void
                    408: oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst)
                    409: {
                    410:
                    411:        sc->sc_scr[addr / 4 + 1] = htole32(dst);
                    412: }
                    413:
                    414: static __inline void
                    415: oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc,
                    416:     bus_addr_t dsps)
                    417: {
                    418:        u_int32_t dcmd;
                    419:
                    420:        dcmd = letoh32(sc->sc_scr[addr / 4]);
                    421:        dcmd &= 0xff000000;
                    422:        dcmd |= dbc & 0x00ffffff;
                    423:        sc->sc_scr[addr / 4 + 0] = htole32(dcmd);
                    424:        sc->sc_scr[addr / 4 + 1] = htole32(dsps);
                    425: }
                    426:
                    427: void
                    428: oosiop_load_script(struct oosiop_softc *sc)
                    429: {
                    430:        int i;
                    431:
                    432:        /* load script */
                    433:        for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++)
                    434:                sc->sc_scr[i] = htole32(oosiop_script[i]);
                    435:
                    436:        /* relocate script */
                    437:        for (i = 0; i < (sizeof(oosiop_script) / 8); i++) {
                    438:                switch (oosiop_script[i * 2] >> 27) {
                    439:                case 0x08:      /* select */
                    440:                case 0x0a:      /* wait reselect */
                    441:                        oosiop_relocate_io(sc, i * 8);
                    442:                        break;
                    443:                case 0x10:      /* jump */
                    444:                case 0x11:      /* call */
                    445:                        oosiop_relocate_tc(sc, i * 8);
                    446:                        break;
                    447:                }
                    448:        }
                    449:
                    450:        oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf);
                    451:        OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
                    452: }
                    453:
                    454: void
                    455: oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb)
                    456: {
                    457:        struct oosiop_xfer *xfer = cb->xfer;
                    458:        struct scsi_xfer *xs = cb->xs;
                    459:        int i, n, off;
                    460:
                    461:        OOSIOP_XFERSCR_SYNC(sc, cb,
                    462:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    463:
                    464:        off = cb->curdp;
                    465:
                    466:        if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
                    467:                /* Find start segment */
                    468:                for (i = 0; i < cb->datadma->dm_nsegs; i++) {
                    469:                        if (off < cb->datadma->dm_segs[i].ds_len)
                    470:                                break;
                    471:                        off -= cb->datadma->dm_segs[i].ds_len;
                    472:                }
                    473:
                    474:                /* build MOVE block */
                    475:                if (xs->flags & SCSI_DATA_IN) {
                    476:                        n = 0;
                    477:                        while (i < cb->datadma->dm_nsegs) {
                    478:                                xfer->datain_scr[n * 2 + 0] =
                    479:                                    htole32(0x09000000 |
                    480:                                    (cb->datadma->dm_segs[i].ds_len - off));
                    481:                                xfer->datain_scr[n * 2 + 1] =
                    482:                                    htole32(cb->datadma->dm_segs[i].ds_addr +
                    483:                                    off);
                    484:                                n++;
                    485:                                i++;
                    486:                                off = 0;
                    487:                        }
                    488:                        xfer->datain_scr[n * 2 + 0] = htole32(0x80080000);
                    489:                        xfer->datain_scr[n * 2 + 1] =
                    490:                            htole32(sc->sc_scrbase + Ent_phasedispatch);
                    491:                }
                    492:                if (xs->flags & SCSI_DATA_OUT) {
                    493:                        n = 0;
                    494:                        while (i < cb->datadma->dm_nsegs) {
                    495:                                xfer->dataout_scr[n * 2 + 0] =
                    496:                                    htole32(0x08000000 |
                    497:                                    (cb->datadma->dm_segs[i].ds_len - off));
                    498:                                xfer->dataout_scr[n * 2 + 1] =
                    499:                                    htole32(cb->datadma->dm_segs[i].ds_addr +
                    500:                                    off);
                    501:                                n++;
                    502:                                i++;
                    503:                                off = 0;
                    504:                        }
                    505:                        xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000);
                    506:                        xfer->dataout_scr[n * 2 + 1] =
                    507:                            htole32(sc->sc_scrbase + Ent_phasedispatch);
                    508:                }
                    509:        }
                    510:        if ((xs->flags & SCSI_DATA_IN) == 0) {
                    511:                xfer->datain_scr[0] = htole32(0x98080000);
                    512:                xfer->datain_scr[1] = htole32(DATAIN_TRAP);
                    513:        }
                    514:        if ((xs->flags & SCSI_DATA_OUT) == 0) {
                    515:                xfer->dataout_scr[0] = htole32(0x98080000);
                    516:                xfer->dataout_scr[1] = htole32(DATAOUT_TRAP);
                    517:        }
                    518:        OOSIOP_XFERSCR_SYNC(sc, cb,
                    519:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    520: }
                    521:
                    522: /*
                    523:  * Setup DMA pointer into script.
                    524:  */
                    525: void
                    526: oosiop_setup_dma(struct oosiop_softc *sc)
                    527: {
                    528:        struct oosiop_cb *cb;
                    529:        bus_addr_t xferbase;
                    530:
                    531:        cb = sc->sc_curcb;
                    532:        xferbase = cb->xferdma->dm_segs[0].ds_addr;
                    533:
                    534:        OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
                    535:
                    536:        oosiop_fixup_select(sc, Ent_p_select, cb->id);
                    537:        oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase +
                    538:            offsetof(struct oosiop_xfer, datain_scr[0]));
                    539:        oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase +
                    540:            offsetof(struct oosiop_xfer, dataout_scr[0]));
                    541:        oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase +
                    542:            offsetof(struct oosiop_xfer, msgin[0]));
                    543:        oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase +
                    544:            offsetof(struct oosiop_xfer, msgin[1]));
                    545:        oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase +
                    546:            offsetof(struct oosiop_xfer, msgout[0]));
                    547:        oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase +
                    548:            offsetof(struct oosiop_xfer, status));
                    549:        oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->cmdlen,
                    550:            cb->cmddma->dm_segs[0].ds_addr);
                    551:
                    552:        OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
                    553: }
                    554:
                    555: void
                    556: oosiop_flush_fifo(struct oosiop_softc *sc)
                    557: {
                    558:
                    559:        oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
                    560:            OOSIOP_DFIFO_FLF);
                    561:        while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
                    562:            OOSIOP_CTEST1_FMT)
                    563:                ;
                    564:        oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
                    565:            ~OOSIOP_DFIFO_FLF);
                    566: }
                    567:
                    568: void
                    569: oosiop_clear_fifo(struct oosiop_softc *sc)
                    570: {
                    571:
                    572:        oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) |
                    573:            OOSIOP_DFIFO_CLF);
                    574:        while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) !=
                    575:            OOSIOP_CTEST1_FMT)
                    576:                ;
                    577:        oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) &
                    578:            ~OOSIOP_DFIFO_CLF);
                    579: }
                    580:
                    581: void
                    582: oosiop_phasemismatch(struct oosiop_softc *sc)
                    583: {
                    584:        struct oosiop_cb *cb;
                    585:        u_int32_t dsp, dbc, n, i, len;
                    586:        u_int8_t dfifo, sstat1;
                    587:
                    588:        cb = sc->sc_curcb;
                    589:        if (cb == NULL)
                    590:                return;
                    591:
                    592:        dsp = oosiop_read_4(sc, OOSIOP_DSP);
                    593:        dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX;
                    594:        len = 0;
                    595:
                    596:        n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8;
                    597:        if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) &&
                    598:            n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) {
                    599:                n -= offsetof(struct oosiop_xfer, datain_scr[0]);
                    600:                n >>= 3;
                    601:                OOSIOP_DINSCR_SYNC(sc, cb,
                    602:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    603:                for (i = 0; i <= n; i++)
                    604:                        len += letoh32(cb->xfer->datain_scr[i * 2]) &
                    605:                            0x00ffffff;
                    606:                OOSIOP_DINSCR_SYNC(sc, cb,
                    607:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    608:                /* All data in the chip are already flushed */
                    609:        } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) &&
                    610:            n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) {
                    611:                n -= offsetof(struct oosiop_xfer, dataout_scr[0]);
                    612:                n >>= 3;
                    613:                OOSIOP_DOUTSCR_SYNC(sc, cb,
                    614:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    615:                for (i = 0; i <= n; i++)
                    616:                        len += letoh32(cb->xfer->dataout_scr[i * 2]) &
                    617:                            0x00ffffff;
                    618:                OOSIOP_DOUTSCR_SYNC(sc, cb,
                    619:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    620:
                    621:                dfifo = oosiop_read_1(sc, OOSIOP_DFIFO);
                    622:                dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) &
                    623:                    OOSIOP_DFIFO_BO;
                    624:
                    625:                sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1);
                    626:                if (sstat1 & OOSIOP_SSTAT1_OLF)
                    627:                        dbc++;
                    628:                if ((sc->sc_tgt[cb->id].sxfer != 0) &&
                    629:                    (sstat1 & OOSIOP_SSTAT1_ORF) != 0)
                    630:                        dbc++;
                    631:
                    632:                oosiop_clear_fifo(sc);
                    633:        } else {
                    634:                printf("%s: phase mismatch addr=%08x\n", sc->sc_dev.dv_xname,
                    635:                    oosiop_read_4(sc, OOSIOP_DSP) - 8);
                    636:                oosiop_clear_fifo(sc);
                    637:                return;
                    638:        }
                    639:
                    640:        len -= dbc;
                    641:        if (len) {
                    642:                cb->curdp += len;
                    643:                oosiop_setup_sgdma(sc, cb);
                    644:        }
                    645: }
                    646:
                    647: void
                    648: oosiop_setup_syncxfer(struct oosiop_softc *sc)
                    649: {
                    650:        int id;
                    651:
                    652:        id = sc->sc_curcb->id;
                    653:        if (sc->sc_chip != OOSIOP_700)
                    654:                oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf);
                    655:
                    656:        oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer);
                    657: }
                    658:
                    659: void
                    660: oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset)
                    661: {
                    662:        int i, p;
                    663:
                    664:        printf("%s: target %d now using 8 bit ", sc->sc_dev.dv_xname, id);
                    665:
                    666:        if (offset == 0) {
                    667:                /* Asynchronous */
                    668:                sc->sc_tgt[id].scf = 0;
                    669:                sc->sc_tgt[id].sxfer = 0;
                    670:                printf("asynchronous");
                    671:        } else {
                    672:                /* Synchronous */
                    673:                if (sc->sc_chip == OOSIOP_700) {
                    674:                        for (i = 4; i < 12; i++) {
                    675:                                p = oosiop_period(sc, i, sc->sc_ccf);
                    676:                                if (p >= period)
                    677:                                        break;
                    678:                        }
                    679:                        if (i == 12) {
                    680:                                printf("%s: target %d period too large\n",
                    681:                                    sc->sc_dev.dv_xname, id);
                    682:                                i = 11; /* XXX */
                    683:                        }
                    684:                        sc->sc_tgt[id].scf = 0;
                    685:                        sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset;
                    686:                } else {
                    687:                        for (i = 0; i < NSYNCTBL; i++) {
                    688:                                p = oosiop_period(sc, synctbl[i].tp + 4,
                    689:                                    (synctbl[i].scf + 1) * 5);
                    690:                                if (p >= period)
                    691:                                        break;
                    692:                        }
                    693:                        if (i == NSYNCTBL) {
                    694:                                printf("%s: target %d period too large\n",
                    695:                                    sc->sc_dev.dv_xname, id);
                    696:                                i = NSYNCTBL - 1;       /* XXX */
                    697:                        }
                    698:                        sc->sc_tgt[id].scf = synctbl[i].scf;
                    699:                        sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset;
                    700:                }
                    701:                /* XXX print actual ns period... */
                    702:                printf(" synchronous");
                    703:        }
                    704:        printf(" xfers\n");
                    705: }
                    706:
                    707: void
                    708: oosiop_minphys(struct buf *bp)
                    709: {
                    710:
                    711:        if (bp->b_bcount > OOSIOP_MAX_XFER)
                    712:                bp->b_bcount = OOSIOP_MAX_XFER;
                    713:        minphys(bp);
                    714: }
                    715:
                    716: int
                    717: oosiop_scsicmd(struct scsi_xfer *xs)
                    718: {
                    719:        struct oosiop_softc *sc;
                    720:        struct oosiop_cb *cb;
                    721:        struct oosiop_xfer *xfer;
                    722:        int s, err;
                    723:
                    724:        sc = (struct oosiop_softc *)xs->sc_link->adapter_softc;
                    725:
                    726:        s = splbio();
                    727:        cb = TAILQ_FIRST(&sc->sc_free_cb);
                    728:        TAILQ_REMOVE(&sc->sc_free_cb, cb, chain);
                    729:        splx(s);
                    730:
                    731:        cb->xs = xs;
                    732:        cb->xsflags = xs->flags;
                    733:        cb->cmdlen = xs->cmdlen;
                    734:        cb->datalen = 0;
                    735:        cb->flags = 0;
                    736:        cb->id = xs->sc_link->target;
                    737:        cb->lun = xs->sc_link->lun;
                    738:        xfer = cb->xfer;
                    739:
                    740:        /* Setup SCSI command buffer DMA */
                    741:        err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd,
                    742:            xs->cmdlen, NULL, ((xs->flags & SCSI_NOSLEEP) ?
                    743:            BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
                    744:            BUS_DMA_STREAMING | BUS_DMA_WRITE);
                    745:        if (err) {
                    746:                printf("%s: unable to load cmd DMA map: %d",
                    747:                    sc->sc_dev.dv_xname, err);
                    748:                xs->error = XS_DRIVER_STUFFUP;
                    749:                scsi_done(xs);
                    750:                TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
                    751:                return (COMPLETE);
                    752:        }
                    753:        bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen,
                    754:            BUS_DMASYNC_PREWRITE);
                    755:
                    756:        /* Setup data buffer DMA */
                    757:        if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
                    758:                cb->datalen = xs->datalen;
                    759:                err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
                    760:                    xs->data, xs->datalen, NULL,
                    761:                    ((xs->flags & SCSI_NOSLEEP) ?
                    762:                    BUS_DMA_NOWAIT : BUS_DMA_WAITOK) |
                    763:                    BUS_DMA_STREAMING |
                    764:                    ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ :
                    765:                    BUS_DMA_WRITE));
                    766:                if (err) {
                    767:                        printf("%s: unable to load data DMA map: %d",
                    768:                            sc->sc_dev.dv_xname, err);
                    769:                        xs->error = XS_DRIVER_STUFFUP;
                    770:                        bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
                    771:                        scsi_done(xs);
                    772:                        TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
                    773:                        return (COMPLETE);
                    774:                }
                    775:                bus_dmamap_sync(sc->sc_dmat, cb->datadma,
                    776:                    0, xs->datalen,
                    777:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    778:        }
                    779:
                    780:        xfer->status = SCSI_OOSIOP_NOSTATUS;
                    781:
                    782:        oosiop_setup(sc, cb);
                    783:
                    784:        s = splbio();
                    785:
                    786:        /*
                    787:         * Always initialize timeout so it does not contain trash
                    788:         * that could confuse timeout_del().
                    789:         */
                    790:        timeout_set(&xs->stimeout, oosiop_timeout, cb);
                    791:
                    792:        TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain);
                    793:
                    794:        if (!sc->sc_active) {
                    795:                /* Abort script to start selection */
                    796:                oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
                    797:        }
                    798:        if (xs->flags & SCSI_POLL)
                    799:                oosiop_poll(sc, cb);
                    800:        else {
                    801:                /* start expire timer */
                    802:                timeout_add(&xs->stimeout, (xs->timeout / 1000) * hz);
                    803:        }
                    804:
                    805:        splx(s);
                    806:
                    807:        if ((xs->flags & ITSDONE) == 0)
                    808:                return (SUCCESSFULLY_QUEUED);
                    809:        else
                    810:                return (COMPLETE);
                    811: }
                    812:
                    813: void
                    814: oosiop_poll(struct oosiop_softc *sc, struct oosiop_cb *cb)
                    815: {
                    816:        struct scsi_xfer *xs = cb->xs;
                    817:        int i, s, to;
                    818:        u_int8_t istat;
                    819:
                    820:        s = splbio();
                    821:        to = xs->timeout / 1000;
                    822:        for (;;) {
                    823:                i = 1000;
                    824:                while (((istat = oosiop_read_1(sc, OOSIOP_ISTAT)) &
                    825:                    (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) {
                    826:                        if (i <= 0) {
                    827:                                i = 1000;
                    828:                                to--;
                    829:                                if (to <= 0) {
                    830:                                        oosiop_reset(sc);
                    831:                                        splx(s);
                    832:                                        return;
                    833:                                }
                    834:                        }
                    835:                        delay(1000);
                    836:                        i--;
                    837:                }
                    838:                oosiop_processintr(sc, istat);
                    839:
                    840:                if (xs->flags & ITSDONE)
                    841:                        break;
                    842:        }
                    843:
                    844:        splx(s);
                    845: }
                    846:
                    847: void
                    848: oosiop_setup(struct oosiop_softc *sc, struct oosiop_cb *cb)
                    849: {
                    850:        struct oosiop_xfer *xfer = cb->xfer;
                    851:
                    852:        cb->curdp = 0;
                    853:        cb->savedp = 0;
                    854:
                    855:        oosiop_setup_sgdma(sc, cb);
                    856:
                    857:        /* Setup msgout buffer */
                    858:        OOSIOP_XFERMSG_SYNC(sc, cb,
                    859:           BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    860:        xfer->msgout[0] = MSG_IDENTIFY(cb->lun,
                    861:            (cb->xs->cmd->opcode != REQUEST_SENSE));
                    862:        cb->msgoutlen = 1;
                    863:
                    864:        if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) {
                    865:                /* Send SDTR */
                    866:                xfer->msgout[1] = MSG_EXTENDED;
                    867:                xfer->msgout[2] = MSG_EXT_SDTR_LEN;
                    868:                xfer->msgout[3] = MSG_EXT_SDTR;
                    869:                xfer->msgout[4] = sc->sc_minperiod;
                    870:                xfer->msgout[5] = OOSIOP_MAX_OFFSET;
                    871:                cb->msgoutlen = 6;
                    872:                sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG;
                    873:                sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR;
                    874:        }
                    875:
                    876:        OOSIOP_XFERMSG_SYNC(sc, cb,
                    877:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    878: }
                    879:
                    880: void
                    881: oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb)
                    882: {
                    883:        struct scsi_xfer *xs;
                    884:        struct scsi_link *periph;
                    885:        int autosense;
                    886:
                    887:        xs = cb->xs;
                    888:        periph = xs->sc_link;
                    889:
                    890:        /*
                    891:         * Record if this is the completion of an auto sense
                    892:         * scsi command, and then reset the flag so we don't loop
                    893:         * when such a command fails or times out.
                    894:         */
                    895:        autosense = cb->flags & CBF_AUTOSENSE;
                    896:        cb->flags &= ~CBF_AUTOSENSE;
                    897:
                    898:        bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
                    899:            BUS_DMASYNC_POSTWRITE);
                    900:        bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
                    901:
                    902:        if (cb->xsflags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
                    903:                bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, cb->datalen,
                    904:                    (cb->xsflags & SCSI_DATA_IN) ?
                    905:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
                    906:                bus_dmamap_unload(sc->sc_dmat, cb->datadma);
                    907:        }
                    908:
                    909:        timeout_del(&xs->stimeout);
                    910:
                    911:        xs->status = cb->xfer->status;
                    912:
                    913:        if (cb->flags & CBF_SELTOUT)
                    914:                xs->error = XS_SELTIMEOUT;
                    915:        else if (cb->flags & CBF_TIMEOUT)
                    916:                xs->error = XS_TIMEOUT;
                    917:        else switch (xs->status) {
                    918:        case SCSI_OK:
                    919:                if (autosense == 0)
                    920:                        xs->error = XS_NOERROR;
                    921:                else
                    922:                        xs->error = XS_SENSE;
                    923:                break;
                    924:
                    925:        case SCSI_BUSY:
                    926:                xs->error = XS_BUSY;
                    927:                break;
                    928:        case SCSI_CHECK:
                    929: #ifdef notyet
                    930:                if (autosense == 0)
                    931:                        cb->flags |= CBF_AUTOSENSE;
                    932:                else
                    933: #endif
                    934:                        xs->error = XS_DRIVER_STUFFUP;
                    935:                break;
                    936:        case SCSI_OOSIOP_NOSTATUS:
                    937:                /* the status byte was not updated, cmd was aborted. */
                    938:                xs->error = XS_SELTIMEOUT;
                    939:                break;
                    940:
                    941:        default:
                    942:                xs->error = XS_RESET;
                    943:                break;
                    944:        }
                    945:
                    946:        if ((cb->flags & CBF_AUTOSENSE) == 0) {
                    947:                /* Put it on the free list. */
                    948: FREE:
                    949:                xs->resid = 0;
                    950:                xs->flags |= ITSDONE;
                    951:                scsi_done(xs);
                    952:                TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
                    953:
                    954:                if (cb == sc->sc_curcb)
                    955:                        sc->sc_curcb = NULL;
                    956:                if (cb == sc->sc_lastcb)
                    957:                        sc->sc_lastcb = NULL;
                    958:                sc->sc_tgt[cb->id].nexus = NULL;
                    959:        } else {
                    960:                /* Set up REQUEST_SENSE command */
                    961:                struct scsi_sense *cmd = (struct scsi_sense *)xs->cmd;
                    962:                int err;
                    963:
                    964:                bzero(cmd, sizeof(*cmd));
                    965:                cmd->opcode = REQUEST_SENSE;
                    966:                cmd->byte2 = xs->sc_link->lun << 5;
                    967:                cb->cmdlen = cmd->length = sizeof(xs->sense);
                    968:
                    969:                cb->xsflags &= SCSI_POLL | SCSI_NOSLEEP;
                    970:                cb->xsflags |= SCSI_DATA_IN;
                    971:                cb->datalen = sizeof xs->sense;
                    972:
                    973:                /* Setup SCSI command buffer DMA */
                    974:                err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, cmd,
                    975:                    cb->cmdlen, NULL,
                    976:                    BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE);
                    977:                if (err) {
                    978:                        printf("%s: unable to load REQUEST_SENSE cmd DMA map: %d",
                    979:                            sc->sc_dev.dv_xname, err);
                    980:                        xs->error = XS_DRIVER_STUFFUP;
                    981:                        goto FREE;
                    982:                }
                    983:                bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, cb->cmdlen,
                    984:                    BUS_DMASYNC_PREWRITE);
                    985:
                    986:                /* Setup data buffer DMA */
                    987:                err = bus_dmamap_load(sc->sc_dmat, cb->datadma,
                    988:                    &xs->sense, sizeof(xs->sense), NULL,
                    989:                    BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_READ);
                    990:                if (err) {
                    991:                        printf("%s: unable to load REQUEST_SENSE data DMA map: %d",
                    992:                            sc->sc_dev.dv_xname, err);
                    993:                        xs->error = XS_DRIVER_STUFFUP;
                    994:                        bus_dmamap_unload(sc->sc_dmat, cb->cmddma);
                    995:                        goto FREE;
                    996:                }
                    997:                bus_dmamap_sync(sc->sc_dmat, cb->datadma,
                    998:                    0, sizeof(xs->sense), BUS_DMASYNC_PREREAD);
                    999:
                   1000:                oosiop_setup(sc, cb);
                   1001:
                   1002:                TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
                   1003:                if ((cb->xs->flags & SCSI_POLL) == 0) {
                   1004:                        /* start expire timer */
                   1005:                        timeout_add(&xs->stimeout, (xs->timeout / 1000) * hz);
                   1006:                }
                   1007:        }
                   1008: }
                   1009:
                   1010: void
                   1011: oosiop_timeout(void *arg)
                   1012: {
                   1013:        struct oosiop_cb *cb = arg;
                   1014:        struct scsi_xfer *xs = cb->xs;
                   1015:        struct oosiop_softc *sc = xs->sc_link->adapter_softc;
                   1016:        int s;
                   1017:
                   1018:        sc_print_addr(xs->sc_link);
                   1019:        printf("command 0x%02x timeout on xs %p\n", xs->cmd->opcode, xs);
                   1020:
                   1021:        s = splbio();
                   1022:
                   1023:        oosiop_reset_bus(sc);
                   1024:
                   1025:        cb->flags |= CBF_TIMEOUT;
                   1026:        oosiop_done(sc, cb);
                   1027:
                   1028:        splx(s);
                   1029: }
                   1030:
                   1031: void
                   1032: oosiop_reset(struct oosiop_softc *sc)
                   1033: {
                   1034:        int i, s;
                   1035:
                   1036:        s = splbio();
                   1037:
                   1038:        /* Stop SCRIPTS processor */
                   1039:        oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT);
                   1040:        delay(100);
                   1041:        oosiop_write_1(sc, OOSIOP_ISTAT, 0);
                   1042:
                   1043:        /* Reset the chip */
                   1044:        oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST);
                   1045:        delay(100);
                   1046:        oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
                   1047:        delay(10000);
                   1048:
                   1049:        /* Set up various chip parameters */
                   1050:        oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG);
                   1051:        oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR);
                   1052:        oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl);
                   1053:        oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8);
                   1054:        oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id));
                   1055:        oosiop_write_1(sc, OOSIOP_DWT, 0xff);   /* Enable DMA timeout */
                   1056:        oosiop_write_1(sc, OOSIOP_CTEST7, 0);
                   1057:        oosiop_write_1(sc, OOSIOP_SXFER, 0);
                   1058:
                   1059:        /* Clear all interrupts */
                   1060:        (void)oosiop_read_1(sc, OOSIOP_SSTAT0);
                   1061:        (void)oosiop_read_1(sc, OOSIOP_SSTAT1);
                   1062:        (void)oosiop_read_1(sc, OOSIOP_DSTAT);
                   1063:
                   1064:        /* Enable interrupts */
                   1065:        oosiop_write_1(sc, OOSIOP_SIEN,
                   1066:            OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE |
                   1067:            OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR);
                   1068:        oosiop_write_1(sc, OOSIOP_DIEN,
                   1069:            OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR |
                   1070:            OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID);
                   1071:
                   1072:        /* Set target state to asynchronous */
                   1073:        for (i = 0; i < OOSIOP_NTGT; i++) {
                   1074:                sc->sc_tgt[i].flags = 0;
                   1075:                sc->sc_tgt[i].scf = 0;
                   1076:                sc->sc_tgt[i].sxfer = 0;
                   1077:        }
                   1078:
                   1079:        splx(s);
                   1080: }
                   1081:
                   1082: void
                   1083: oosiop_reset_bus(struct oosiop_softc *sc)
                   1084: {
                   1085:        int s, i;
                   1086:
                   1087:        s = splbio();
                   1088:
                   1089:        /* Assert SCSI RST */
                   1090:        oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST);
                   1091:        delay(25);      /* Reset hold time (25us) */
                   1092:        oosiop_write_1(sc, OOSIOP_SCNTL1, 0);
                   1093:
                   1094:        /* Remove all nexuses */
                   1095:        for (i = 0; i < OOSIOP_NTGT; i++) {
                   1096:                if (sc->sc_tgt[i].nexus) {
                   1097:                        sc->sc_tgt[i].nexus->xfer->status =
                   1098:                            SCSI_OOSIOP_NOSTATUS; /* XXX */
                   1099:                        oosiop_done(sc, sc->sc_tgt[i].nexus);
                   1100:                }
                   1101:        }
                   1102:
                   1103:        sc->sc_curcb = NULL;
                   1104:
                   1105:        delay(250000);  /* Reset to selection (250ms) */
                   1106:
                   1107:        splx(s);
                   1108: }
                   1109:
                   1110: /*
                   1111:  * interrupt handler
                   1112:  */
                   1113: int
                   1114: oosiop_intr(struct oosiop_softc *sc)
                   1115: {
                   1116:        u_int8_t istat;
                   1117:
                   1118:        istat = oosiop_read_1(sc, OOSIOP_ISTAT);
                   1119:
                   1120:        if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0)
                   1121:                return (0);
                   1122:
                   1123:        oosiop_processintr(sc, istat);
                   1124:        return (1);
                   1125: }
                   1126:
                   1127: void
                   1128: oosiop_processintr(struct oosiop_softc *sc, u_int8_t istat)
                   1129: {
                   1130:        struct oosiop_cb *cb;
                   1131:        u_int32_t dcmd;
                   1132:        u_int8_t dstat, sstat0;
                   1133:
                   1134:        sc->sc_nextdsp = Ent_wait_reselect;
                   1135:
                   1136:        /* DMA interrupts */
                   1137:        if (istat & OOSIOP_ISTAT_DIP) {
                   1138:                oosiop_write_1(sc, OOSIOP_ISTAT, 0);
                   1139:
                   1140:                dstat = oosiop_read_1(sc, OOSIOP_DSTAT);
                   1141:
                   1142:                if (dstat & OOSIOP_DSTAT_ABRT) {
                   1143:                        sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
                   1144:                            sc->sc_scrbase - 8;
                   1145:
                   1146:                        if (sc->sc_nextdsp == Ent_p_resel_msgin_move &&
                   1147:                            (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) {
                   1148:                                if ((dstat & OOSIOP_DSTAT_DFE) == 0)
                   1149:                                        oosiop_flush_fifo(sc);
                   1150:                                sc->sc_nextdsp += 8;
                   1151:                        }
                   1152:                }
                   1153:
                   1154:                if (dstat & OOSIOP_DSTAT_SSI) {
                   1155:                        sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) -
                   1156:                            sc->sc_scrbase;
                   1157:                        printf("%s: single step %08x\n", sc->sc_dev.dv_xname,
                   1158:                            sc->sc_nextdsp);
                   1159:                }
                   1160:
                   1161:                if (dstat & OOSIOP_DSTAT_SIR) {
                   1162:                        if ((dstat & OOSIOP_DSTAT_DFE) == 0)
                   1163:                                oosiop_flush_fifo(sc);
                   1164:                        oosiop_scriptintr(sc);
                   1165:                }
                   1166:
                   1167:                if (dstat & OOSIOP_DSTAT_WTD) {
                   1168:                        printf("%s: DMA time out\n", sc->sc_dev.dv_xname);
                   1169:                        oosiop_reset(sc);
                   1170:                }
                   1171:
                   1172:                if (dstat & OOSIOP_DSTAT_IID) {
                   1173:                        dcmd = oosiop_read_4(sc, OOSIOP_DBC);
                   1174:                        if ((dcmd & 0xf8000000) == 0x48000000) {
                   1175:                                printf("%s: REQ asserted on WAIT DISCONNECT\n",
                   1176:                                    sc->sc_dev.dv_xname);
                   1177:                                sc->sc_nextdsp = Ent_phasedispatch; /* XXX */
                   1178:                        } else {
                   1179:                                printf("%s: invalid SCRIPTS instruction "
                   1180:                                    "addr=%08x dcmd=%08x dsps=%08x\n",
                   1181:                                    sc->sc_dev.dv_xname,
                   1182:                                    oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd,
                   1183:                                    oosiop_read_4(sc, OOSIOP_DSPS));
                   1184:                                oosiop_reset(sc);
                   1185:                                OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
                   1186:                                oosiop_load_script(sc);
                   1187:                        }
                   1188:                }
                   1189:
                   1190:                if ((dstat & OOSIOP_DSTAT_DFE) == 0)
                   1191:                        oosiop_clear_fifo(sc);
                   1192:        }
                   1193:
                   1194:        /* SCSI interrupts */
                   1195:        if (istat & OOSIOP_ISTAT_SIP) {
                   1196:                if (istat & OOSIOP_ISTAT_DIP)
                   1197:                        delay(1);
                   1198:                sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0);
                   1199:
                   1200:                if (sstat0 & OOSIOP_SSTAT0_M_A) {
                   1201:                        /* SCSI phase mismatch during MOVE operation */
                   1202:                        oosiop_phasemismatch(sc);
                   1203:                        sc->sc_nextdsp = Ent_phasedispatch;
                   1204:                }
                   1205:
                   1206:                if (sstat0 & OOSIOP_SSTAT0_STO) {
                   1207:                        if (sc->sc_curcb) {
                   1208:                                sc->sc_curcb->flags |= CBF_SELTOUT;
                   1209:                                oosiop_done(sc, sc->sc_curcb);
                   1210:                        }
                   1211:                }
                   1212:
                   1213:                if (sstat0 & OOSIOP_SSTAT0_SGE) {
                   1214:                        printf("%s: SCSI gross error\n", sc->sc_dev.dv_xname);
                   1215:                        oosiop_reset(sc);
                   1216:                }
                   1217:
                   1218:                if (sstat0 & OOSIOP_SSTAT0_UDC) {
                   1219:                        /* XXX */
                   1220:                        if (sc->sc_curcb) {
                   1221:                                printf("%s: unexpected disconnect\n",
                   1222:                                    sc->sc_dev.dv_xname);
                   1223:                                oosiop_done(sc, sc->sc_curcb);
                   1224:                        }
                   1225:                }
                   1226:
                   1227:                if (sstat0 & OOSIOP_SSTAT0_RST)
                   1228:                        oosiop_reset(sc);
                   1229:
                   1230:                if (sstat0 & OOSIOP_SSTAT0_PAR)
                   1231:                        printf("%s: parity error\n", sc->sc_dev.dv_xname);
                   1232:        }
                   1233:
                   1234:        /* Start next command if available */
                   1235:        if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) {
                   1236:                cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq);
                   1237:                TAILQ_REMOVE(&sc->sc_cbq, cb, chain);
                   1238:                sc->sc_tgt[cb->id].nexus = cb;
                   1239:
                   1240:                oosiop_setup_dma(sc);
                   1241:                oosiop_setup_syncxfer(sc);
                   1242:                sc->sc_lastcb = cb;
                   1243:                sc->sc_nextdsp = Ent_start_select;
                   1244:
                   1245:                /* Schedule timeout */
                   1246:                if ((cb->xs->flags & SCSI_POLL) == 0) {
                   1247:                        /* start expire timer */
                   1248:                        timeout_add(&cb->xs->stimeout,
                   1249:                            (cb->xs->timeout / 1000) * hz);
                   1250:                }
                   1251:        }
                   1252:
                   1253:        sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect);
                   1254:
                   1255:        /* Restart script */
                   1256:        oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase);
                   1257: }
                   1258:
                   1259: void
                   1260: oosiop_scriptintr(struct oosiop_softc *sc)
                   1261: {
                   1262:        struct oosiop_cb *cb;
                   1263:        u_int32_t icode;
                   1264:        u_int32_t dsp;
                   1265:        int i;
                   1266:        u_int8_t sfbr, resid, resmsg;
                   1267:
                   1268:        cb = sc->sc_curcb;
                   1269:        icode = oosiop_read_4(sc, OOSIOP_DSPS);
                   1270:
                   1271:        switch (icode) {
                   1272:        case A_int_done:
                   1273:                if (cb)
                   1274:                        oosiop_done(sc, cb);
                   1275:                break;
                   1276:
                   1277:        case A_int_msgin:
                   1278:                if (cb)
                   1279:                        oosiop_msgin(sc, cb);
                   1280:                break;
                   1281:
                   1282:        case A_int_extmsg:
                   1283:                /* extended message in DMA setup request */
                   1284:                sfbr = oosiop_read_1(sc, OOSIOP_SFBR);
                   1285:                OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
                   1286:                oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr,
                   1287:                    cb->xferdma->dm_segs[0].ds_addr +
                   1288:                    offsetof(struct oosiop_xfer, msgin[2]));
                   1289:                OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
                   1290:                sc->sc_nextdsp = Ent_rcv_extmsg;
                   1291:                break;
                   1292:
                   1293:        case A_int_resel:
                   1294:                /* reselected */
                   1295:                resid = oosiop_read_1(sc, OOSIOP_SFBR);
                   1296:                for (i = 0; i < OOSIOP_NTGT; i++)
                   1297:                        if (resid & (1 << i))
                   1298:                                break;
                   1299:                if (i == OOSIOP_NTGT) {
                   1300:                        printf("%s: missing reselection target id\n",
                   1301:                            sc->sc_dev.dv_xname);
                   1302:                        break;
                   1303:                }
                   1304:                sc->sc_resid = i;
                   1305:                sc->sc_nextdsp = Ent_wait_resel_identify;
                   1306:
                   1307:                if (cb) {
                   1308:                        /* Current command was lost arbitration */
                   1309:                        sc->sc_tgt[cb->id].nexus = NULL;
                   1310:                        TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain);
                   1311:                        sc->sc_curcb = NULL;
                   1312:                }
                   1313:
                   1314:                break;
                   1315:
                   1316:        case A_int_res_id:
                   1317:                cb = sc->sc_tgt[sc->sc_resid].nexus;
                   1318:                resmsg = oosiop_read_1(sc, OOSIOP_SFBR);
                   1319:                if (MSG_ISIDENTIFY(resmsg) && cb &&
                   1320:                    (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) {
                   1321:                        sc->sc_curcb = cb;
                   1322:                        if (cb != sc->sc_lastcb) {
                   1323:                                oosiop_setup_dma(sc);
                   1324:                                oosiop_setup_syncxfer(sc);
                   1325:                                sc->sc_lastcb = cb;
                   1326:                        }
                   1327:                        if (cb->curdp != cb->savedp) {
                   1328:                                cb->curdp = cb->savedp;
                   1329:                                oosiop_setup_sgdma(sc, cb);
                   1330:                        }
                   1331:                        sc->sc_nextdsp = Ent_ack_msgin;
                   1332:                } else {
                   1333:                        /* Reselection from invalid target */
                   1334:                        oosiop_reset_bus(sc);
                   1335:                }
                   1336:                break;
                   1337:
                   1338:        case A_int_resfail:
                   1339:                /* reselect failed */
                   1340:                break;
                   1341:
                   1342:        case A_int_disc:
                   1343:                /* disconnected */
                   1344:                sc->sc_curcb = NULL;
                   1345:                break;
                   1346:
                   1347:        case A_int_err:
                   1348:                /* generic error */
                   1349:                dsp = oosiop_read_4(sc, OOSIOP_DSP);
                   1350:                printf("%s: script error at 0x%08x\n", sc->sc_dev.dv_xname,
                   1351:                    dsp - 8);
                   1352:                sc->sc_curcb = NULL;
                   1353:                break;
                   1354:
                   1355:        case DATAIN_TRAP:
                   1356:                printf("%s: unexpected datain\n", sc->sc_dev.dv_xname);
                   1357:                /* XXX: need to reset? */
                   1358:                break;
                   1359:
                   1360:        case DATAOUT_TRAP:
                   1361:                printf("%s: unexpected dataout\n", sc->sc_dev.dv_xname);
                   1362:                /* XXX: need to reset? */
                   1363:                break;
                   1364:
                   1365:        default:
                   1366:                printf("%s: unknown intr code %08x\n", sc->sc_dev.dv_xname,
                   1367:                    icode);
                   1368:                break;
                   1369:        }
                   1370: }
                   1371:
                   1372: void
                   1373: oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb)
                   1374: {
                   1375:        struct oosiop_xfer *xfer;
                   1376:        int msgout;
                   1377:
                   1378:        xfer = cb->xfer;
                   1379:        sc->sc_nextdsp = Ent_ack_msgin;
                   1380:        msgout = 0;
                   1381:
                   1382:        OOSIOP_XFERMSG_SYNC(sc, cb,
                   1383:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                   1384:
                   1385:        switch (xfer->msgin[0]) {
                   1386:        case MSG_EXTENDED:
                   1387:                switch (xfer->msgin[2]) {
                   1388:                case MSG_EXT_SDTR:
                   1389:                        if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
                   1390:                                /* Host initiated SDTR */
                   1391:                                sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
                   1392:                        } else {
                   1393:                                /* Target initiated SDTR */
                   1394:                                if (xfer->msgin[3] < sc->sc_minperiod)
                   1395:                                        xfer->msgin[3] = sc->sc_minperiod;
                   1396:                                if (xfer->msgin[4] > OOSIOP_MAX_OFFSET)
                   1397:                                        xfer->msgin[4] = OOSIOP_MAX_OFFSET;
                   1398:                                xfer->msgout[0] = MSG_EXTENDED;
                   1399:                                xfer->msgout[1] = MSG_EXT_SDTR_LEN;
                   1400:                                xfer->msgout[2] = MSG_EXT_SDTR;
                   1401:                                xfer->msgout[3] = xfer->msgin[3];
                   1402:                                xfer->msgout[4] = xfer->msgin[4];
                   1403:                                cb->msgoutlen = 5;
                   1404:                                msgout = 1;
                   1405:                        }
                   1406:                        oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3],
                   1407:                            (int)xfer->msgin[4]);
                   1408:                        oosiop_setup_syncxfer(sc);
                   1409:                        break;
                   1410:
                   1411:                default:
                   1412:                        /* Reject message */
                   1413:                        xfer->msgout[0] = MSG_MESSAGE_REJECT;
                   1414:                        cb->msgoutlen = 1;
                   1415:                        msgout = 1;
                   1416:                        break;
                   1417:                }
                   1418:                break;
                   1419:
                   1420:        case MSG_SAVEDATAPOINTER:
                   1421:                cb->savedp = cb->curdp;
                   1422:                break;
                   1423:
                   1424:        case MSG_RESTOREPOINTERS:
                   1425:                if (cb->curdp != cb->savedp) {
                   1426:                        cb->curdp = cb->savedp;
                   1427:                        oosiop_setup_sgdma(sc, cb);
                   1428:                }
                   1429:                break;
                   1430:
                   1431:        case MSG_MESSAGE_REJECT:
                   1432:                if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) {
                   1433:                        /* SDTR rejected */
                   1434:                        sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR;
                   1435:                        oosiop_set_syncparam(sc, cb->id, 0, 0);
                   1436:                        oosiop_setup_syncxfer(sc);
                   1437:                }
                   1438:                break;
                   1439:
                   1440:        default:
                   1441:                /* Reject message */
                   1442:                xfer->msgout[0] = MSG_MESSAGE_REJECT;
                   1443:                cb->msgoutlen = 1;
                   1444:                msgout = 1;
                   1445:        }
                   1446:
                   1447:        OOSIOP_XFERMSG_SYNC(sc, cb,
                   1448:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                   1449:
                   1450:        if (msgout) {
                   1451:                OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE);
                   1452:                oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen,
                   1453:                    cb->xferdma->dm_segs[0].ds_addr +
                   1454:                    offsetof(struct oosiop_xfer, msgout[0]));
                   1455:                OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE);
                   1456:                sc->sc_nextdsp = Ent_sendmsg;
                   1457:        }
                   1458: }

CVSweb