[BACK]Return to siop.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / ic

Annotation of src/sys/dev/ic/siop.c, Revision 1.21

1.21    ! bouyer      1: /*     $NetBSD: siop.c,v 1.20 2000/06/12 20:13:41 bouyer Exp $ */
1.1       bouyer      2:
                      3: /*
                      4:  * Copyright (c) 2000 Manuel Bouyer.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. All advertising materials mentioning features or use of this software
                     15:  *    must display the following acknowledgement:
1.5       bouyer     16:  *     This product includes software developed by Manuel Bouyer
                     17:  * 4. The name of the author may not be used to endorse or promote products
                     18:  *    derived from this software without specific prior written permission.
1.1       bouyer     19:  *
1.14      bouyer     20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     21:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     22:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     23:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     24:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     25:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     26:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     27:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     29:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       bouyer     30:  *
                     31:  */
                     32:
                     33: /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
                     34:
                     35: #include <sys/param.h>
                     36: #include <sys/systm.h>
                     37: #include <sys/device.h>
                     38: #include <sys/malloc.h>
                     39: #include <sys/buf.h>
                     40: #include <sys/kernel.h>
                     41:
                     42: #include <machine/endian.h>
                     43: #include <machine/bus.h>
                     44:
                     45: #include <vm/vm.h>
                     46: #include <vm/vm_param.h>
                     47: #include <vm/vm_kern.h>
                     48:
                     49: #include <dev/microcode/siop/siop.out>
                     50:
                     51: #include <dev/scsipi/scsi_all.h>
                     52: #include <dev/scsipi/scsi_message.h>
                     53: #include <dev/scsipi/scsipi_all.h>
                     54:
                     55: #include <dev/scsipi/scsiconf.h>
                     56:
                     57: #include <dev/ic/siopreg.h>
                     58: #include <dev/ic/siopvar.h>
1.14      bouyer     59: #include <dev/ic/siopvar_common.h>
1.1       bouyer     60:
1.15      bouyer     61: #undef DEBUG
1.8       bouyer     62: #undef DEBUG_DR
1.2       bouyer     63: #undef DEBUG_INTR
                     64: #undef DEBUG_SHED
                     65: #undef DUMP_SCRIPT
                     66:
                     67: #define SIOP_STATS
                     68:
1.1       bouyer     69: #ifndef SIOP_DEFAULT_TARGET
                     70: #define SIOP_DEFAULT_TARGET 7
                     71: #endif
                     72:
1.16      bouyer     73: /* number of cmd descriptors per block */
                     74: #define SIOP_NCMDPB (NBPG / sizeof(struct siop_xfer))
1.1       bouyer     75:
                     76: void   siop_reset __P((struct siop_softc *));
1.2       bouyer     77: void   siop_handle_reset __P((struct siop_softc *));
                     78: void   siop_scsicmd_end __P((struct siop_cmd *));
1.1       bouyer     79: void   siop_start __P((struct siop_softc *));
                     80: void   siop_timeout __P((void *));
                     81: int    siop_scsicmd __P((struct scsipi_xfer *));
1.2       bouyer     82: void   siop_dump_script __P((struct siop_softc *));
1.16      bouyer     83: int    siop_morecbd __P((struct siop_softc *));
1.1       bouyer     84:
                     85: struct scsipi_adapter siop_adapter = {
                     86:        0,
                     87:        siop_scsicmd,
                     88:        siop_minphys,
1.2       bouyer     89:        siop_ioctl,
1.19      tsutsui    90:        NULL,
1.1       bouyer     91:        NULL,
                     92: };
                     93:
                     94: struct scsipi_device siop_dev = {
                     95:        NULL,
                     96:        NULL,
                     97:        NULL,
                     98:        NULL,
                     99: };
                    100:
1.2       bouyer    101: #ifdef SIOP_STATS
                    102: static int siop_stat_intr = 0;
                    103: static int siop_stat_intr_shortxfer = 0;
                    104: static int siop_stat_intr_sdp = 0;
                    105: static int siop_stat_intr_done = 0;
                    106: static int siop_stat_intr_reselect = 0;
                    107: static int siop_stat_intr_xferdisc = 0;
                    108: void siop_printstats __P((void));
                    109: #define INCSTAT(x) x++
                    110: #else
                    111: #define INCSTAT(x)
                    112: #endif
                    113:
                    114: static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
                    115: static __inline__ void
                    116: siop_table_sync(siop_cmd, ops)
                    117:        struct siop_cmd *siop_cmd;
                    118:        int ops;
                    119: {
1.7       bouyer    120:        struct siop_softc *sc  = siop_cmd->siop_target->siop_sc;
1.2       bouyer    121:        bus_addr_t offset;
                    122:
1.16      bouyer    123:        offset = siop_cmd->dsa -
                    124:            siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr;
                    125:        bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset,
1.2       bouyer    126:            sizeof(struct siop_xfer), ops);
                    127: }
                    128:
1.17      bouyer    129: static __inline__ void siop_shed_sync __P((struct siop_softc *, int));
1.2       bouyer    130: static __inline__ void
1.17      bouyer    131: siop_shed_sync(sc, ops)
1.2       bouyer    132:        struct siop_softc *sc;
                    133:        int ops;
                    134: {
1.17      bouyer    135:        bus_dmamap_sync(sc->sc_dmat, sc->sc_sheddma, 0, NBPG, ops);
1.2       bouyer    136: }
                    137:
1.1       bouyer    138: void
                    139: siop_attach(sc)
                    140:        struct siop_softc *sc;
                    141: {
                    142:        int error, i;
                    143:        bus_dma_segment_t seg;
                    144:        int rseg;
                    145:
                    146:        /*
1.21    ! bouyer    147:         * Allocate DMA-safe memory for the script and script scheduler
1.17      bouyer    148:         * and map it.
1.1       bouyer    149:         */
1.17      bouyer    150:        if ((sc->features & SF_CHIP_RAM) == 0) {
                    151:                error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
                    152:                    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
                    153:                if (error) {
                    154:                        printf("%s: unable to allocate script DMA memory, "
                    155:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    156:                        return;
                    157:                }
                    158:                error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
                    159:                    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
                    160:                if (error) {
                    161:                        printf("%s: unable to map script DMA memory, "
                    162:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    163:                        return;
                    164:                }
                    165:                error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
                    166:                    NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
                    167:                if (error) {
                    168:                        printf("%s: unable to create script DMA map, "
                    169:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    170:                        return;
                    171:                }
                    172:                error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
                    173:                    sc->sc_script,
                    174:                    NBPG, NULL, BUS_DMA_NOWAIT);
                    175:                if (error) {
                    176:                        printf("%s: unable to load script DMA map, "
                    177:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    178:                        return;
                    179:                }
                    180:                sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr;
                    181:        }
1.16      bouyer    182:        error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
1.1       bouyer    183:            NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
                    184:        if (error) {
1.21    ! bouyer    185:                printf("%s: unable to allocate scheduler DMA memory, "
1.17      bouyer    186:                    "error = %d\n", sc->sc_dev.dv_xname, error);
1.1       bouyer    187:                return;
                    188:        }
1.16      bouyer    189:        error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
1.17      bouyer    190:            (caddr_t *)&sc->sc_shed, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1.1       bouyer    191:        if (error) {
1.21    ! bouyer    192:                printf("%s: unable to map scheduler DMA memory, error = %d\n",
1.1       bouyer    193:                    sc->sc_dev.dv_xname, error);
                    194:                return;
                    195:        }
1.16      bouyer    196:        error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
1.17      bouyer    197:            NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_sheddma);
1.1       bouyer    198:        if (error) {
1.21    ! bouyer    199:                printf("%s: unable to create scheduler DMA map, error = %d\n",
1.1       bouyer    200:                    sc->sc_dev.dv_xname, error);
                    201:                return;
                    202:        }
1.17      bouyer    203:        error = bus_dmamap_load(sc->sc_dmat, sc->sc_sheddma, sc->sc_shed,
1.16      bouyer    204:            NBPG, NULL, BUS_DMA_NOWAIT);
1.1       bouyer    205:        if (error) {
1.21    ! bouyer    206:                printf("%s: unable to load scheduler DMA map, error = %d\n",
1.1       bouyer    207:                    sc->sc_dev.dv_xname, error);
                    208:                return;
                    209:        }
                    210:        TAILQ_INIT(&sc->free_list);
1.16      bouyer    211:        TAILQ_INIT(&sc->cmds);
1.21    ! bouyer    212:        /* compute number of scheduler slots */
1.2       bouyer    213:        sc->sc_nshedslots = (
1.21    ! bouyer    214:            NBPG /* memory size allocated for scheduler */
        !           215:            - sizeof(endslot_script) /* memory needed at end of scheduler */
1.2       bouyer    216:            ) / (sizeof(slot_script) - 8);
1.7       bouyer    217:        sc->sc_currshedslot = 0;
1.1       bouyer    218: #ifdef DEBUG
1.2       bouyer    219:        printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
                    220:            sc->sc_dev.dv_xname, (int)sizeof(siop_script),
1.18      bouyer    221:            sc->sc_scriptaddr, sc->sc_script, sc->sc_nshedslots);
1.1       bouyer    222: #endif
                    223:
                    224:        sc->sc_link.adapter_softc = sc;
                    225:        sc->sc_link.openings = 1;
                    226:        sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
                    227:        sc->sc_link.scsipi_scsi.max_target  =
                    228:            (sc->features & SF_BUS_WIDE) ? 15 : 7;
                    229:        sc->sc_link.scsipi_scsi.max_lun = 7;
                    230:        sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
                    231:            sc->sc_rh, SIOP_SCID);
1.2       bouyer    232:        if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
                    233:            sc->sc_link.scsipi_scsi.adapter_target >
1.1       bouyer    234:            sc->sc_link.scsipi_scsi.max_target)
                    235:                sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
                    236:        sc->sc_link.type = BUS_SCSI;
                    237:        sc->sc_link.adapter = &siop_adapter;
                    238:        sc->sc_link.device = &siop_dev;
                    239:        sc->sc_link.flags  = 0;
                    240:
1.7       bouyer    241:        for (i = 0; i < 16; i++)
                    242:                sc->targets[i] = NULL;
                    243:
                    244:        /* find min/max sync period for this chip */
                    245:        sc->maxsync = 0;
                    246:        sc->minsync = 255;
                    247:        for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
                    248:                if (sc->clock_period != scf_period[i].clock)
                    249:                        continue;
                    250:                if (sc->maxsync < scf_period[i].period)
                    251:                        sc->maxsync = scf_period[i].period;
                    252:                if (sc->minsync > scf_period[i].period)
                    253:                        sc->minsync = scf_period[i].period;
                    254:        }
                    255:        if (sc->maxsync == 255 || sc->minsync == 0)
                    256:                panic("siop: can't find my sync parameters\n");
1.1       bouyer    257:        siop_reset(sc);
1.2       bouyer    258: #ifdef DUMP_SCRIPT
                    259:        siop_dump_script(sc);
                    260: #endif
1.1       bouyer    261:
                    262:        config_found((struct device*)sc, &sc->sc_link, scsiprint);
                    263: }
                    264:
                    265: void
                    266: siop_reset(sc)
                    267:        struct siop_softc *sc;
                    268: {
1.4       bouyer    269:        int i, j;
1.2       bouyer    270:        u_int32_t *scr;
                    271:        bus_addr_t physaddr;
1.4       bouyer    272:
1.14      bouyer    273:        siop_common_reset(sc);
1.1       bouyer    274:
                    275:        /* copy and patch the script */
1.17      bouyer    276:        if (sc->features & SF_CHIP_RAM) {
                    277:                bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0,
                    278:                    siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
                    279:                for (j = 0; j <
                    280:                    (sizeof(E_script_abs_shed_Used) /
                    281:                    sizeof(E_script_abs_shed_Used[0]));
                    282:                    j++) {
                    283:                        bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
                    284:                            E_script_abs_shed_Used[j] * 4,
                    285:                            sc->sc_sheddma->dm_segs[0].ds_addr);
                    286:                }
                    287:        } else {
                    288:                for (j = 0;
                    289:                    j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
                    290:                        sc->sc_script[j] = htole32(siop_script[j]);
                    291:                }
                    292:                for (j = 0; j <
                    293:                    (sizeof(E_script_abs_shed_Used) /
                    294:                    sizeof(E_script_abs_shed_Used[0]));
                    295:                    j++) {
                    296:                        sc->sc_script[E_script_abs_shed_Used[j]] =
                    297:                                htole32(sc->sc_sheddma->dm_segs[0].ds_addr);
                    298:                }
1.4       bouyer    299:        }
1.21    ! bouyer    300:        /* copy and init the scheduler slots script */
1.2       bouyer    301:        for (i = 0; i < sc->sc_nshedslots; i++) {
1.17      bouyer    302:                scr = &sc->sc_shed[(Ent_nextslot / 4) * i];
                    303:                physaddr = sc->sc_sheddma->dm_segs[0].ds_addr +
                    304:                    Ent_nextslot * i;
1.4       bouyer    305:                for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0]));
                    306:                    j++) {
                    307:                        scr[j] = htole32(slot_script[j]);
                    308:                }
1.2       bouyer    309:                /*
                    310:                 * save current jump offset and patch MOVE MEMORY operands
                    311:                 * to restore it.
                    312:                 */
                    313:                scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
                    314:                scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
                    315:                scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
                    316:                    Ent_slotdata + 4);
                    317:                /* JUMP selected, in main script */
                    318:                scr[E_slot_abs_selected_Used[0]] =
1.17      bouyer    319:                   htole32(sc->sc_scriptaddr + Ent_selected);
1.2       bouyer    320:                /* JUMP addr if SELECT fail */
                    321:                scr[E_slot_abs_reselect_Used[0]] =
1.17      bouyer    322:                   htole32(sc->sc_scriptaddr + Ent_reselect);
1.2       bouyer    323:        }
                    324:        /* Now the final JUMP */
1.17      bouyer    325:        scr = &sc->sc_shed[(Ent_nextslot / 4) * sc->sc_nshedslots];
1.4       bouyer    326:        for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0]));
                    327:            j++) {
                    328:                scr[j] = htole32(endslot_script[j]);
                    329:        }
1.2       bouyer    330:        scr[E_endslot_abs_reselect_Used[0]] =
1.17      bouyer    331:            htole32(sc->sc_scriptaddr + Ent_reselect);
1.1       bouyer    332:
1.2       bouyer    333:        /* start script */
1.17      bouyer    334:        bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG,
                    335:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    336:        siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.2       bouyer    337:        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
1.17      bouyer    338:            sc->sc_scriptaddr + Ent_reselect);
1.1       bouyer    339: }
                    340:
                    341: #if 0
                    342: #define CALL_SCRIPT(ent) do {\
                    343:        printf ("start script DSA 0x%lx DSP 0x%lx\n", \
1.4       bouyer    344:            siop_cmd->dsa, \
1.17      bouyer    345:            sc->sc_scriptaddr + ent); \
                    346: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
1.1       bouyer    347: } while (0)
                    348: #else
                    349: #define CALL_SCRIPT(ent) do {\
1.17      bouyer    350: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
1.1       bouyer    351: } while (0)
                    352: #endif
                    353:
                    354: int
                    355: siop_intr(v)
                    356:        void *v;
                    357: {
                    358:        struct siop_softc *sc = v;
1.7       bouyer    359:        struct siop_target *siop_target;
1.1       bouyer    360:        struct siop_cmd *siop_cmd;
                    361:        struct scsipi_xfer *xs;
1.8       bouyer    362:        int istat, sist0, sist1, sstat1, dstat, scntl1;
1.1       bouyer    363:        u_int32_t irqcode;
                    364:        int need_reset = 0;
1.7       bouyer    365:        int offset, target, lun;
1.2       bouyer    366:        bus_addr_t dsa;
1.16      bouyer    367:        struct siop_cbd *cbdp;
1.1       bouyer    368:
                    369:        istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
1.2       bouyer    370:        if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
                    371:                return 0;
                    372:        INCSTAT(siop_stat_intr);
1.1       bouyer    373:        if (istat & ISTAT_INTF) {
                    374:                printf("INTRF\n");
                    375:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
                    376:        }
1.2       bouyer    377:        /* use DSA to find the current siop_cmd */
                    378:        dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
1.16      bouyer    379:        for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL;
                    380:            cbdp = TAILQ_NEXT(cbdp, next)) {
                    381:                if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&
                    382:                    dsa < cbdp->xferdma->dm_segs[0].ds_addr + NBPG) {
                    383:                        dsa -= cbdp->xferdma->dm_segs[0].ds_addr;
                    384:                        siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
                    385:                        siop_table_sync(siop_cmd,
                    386:                            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    387:                        break;
                    388:                }
                    389:        }
                    390:        if (cbdp == NULL) {
1.2       bouyer    391:                siop_cmd = NULL;
                    392:        }
1.1       bouyer    393:        if (istat & ISTAT_DIP) {
                    394:                u_int32_t *p;
                    395:                dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
1.2       bouyer    396:                if (dstat & DSTAT_SSI) {
                    397:                        printf("single step dsp 0x%08x dsa 0x08%x\n",
1.7       bouyer    398:                            (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    399:                            sc->sc_scriptaddr),
1.2       bouyer    400:                            bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
                    401:                        if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
                    402:                            (istat & ISTAT_SIP) == 0) {
                    403:                                bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    404:                                    SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
                    405:                                    sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
                    406:                        }
                    407:                        return 1;
                    408:                }
                    409:                if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
1.1       bouyer    410:                printf("DMA IRQ:");
                    411:                if (dstat & DSTAT_IID)
                    412:                        printf(" Illegal instruction");
                    413:                if (dstat & DSTAT_ABRT)
                    414:                        printf(" abort");
                    415:                if (dstat & DSTAT_BF)
                    416:                        printf(" bus fault");
                    417:                if (dstat & DSTAT_MDPE)
                    418:                        printf(" parity");
                    419:                if (dstat & DSTAT_DFE)
                    420:                        printf(" dma fifo empty");
                    421:                printf(", DSP=0x%x DSA=0x%x: ",
1.7       bouyer    422:                    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    423:                    sc->sc_scriptaddr),
1.1       bouyer    424:                    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
1.2       bouyer    425:                p = sc->sc_script +
1.1       bouyer    426:                    (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    427:                    sc->sc_scriptaddr - 8) / 4;
1.4       bouyer    428:                printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]),
                    429:                    le32toh(p[2]), le32toh(p[3]));
1.2       bouyer    430:                if (siop_cmd)
1.1       bouyer    431:                        printf("last msg_in=0x%x status=0x%x\n",
1.2       bouyer    432:                            siop_cmd->siop_table->msg_in[0],
1.6       bouyer    433:                            le32toh(siop_cmd->siop_table->status));
1.20      bouyer    434:                else
                    435:                        printf("%s: current DSA invalid\n",
                    436:                            sc->sc_dev.dv_xname);
1.1       bouyer    437:                need_reset = 1;
                    438:                }
                    439:        }
                    440:        if (istat & ISTAT_SIP) {
1.2       bouyer    441:                /*
                    442:                 * SCSI interrupt. If current command is not active,
                    443:                 * we don't need siop_cmd
                    444:                 */
1.17      bouyer    445:                if (siop_cmd && siop_cmd->status != CMDST_ACTIVE &&
1.2       bouyer    446:                    siop_cmd->status != CMDST_SENSE_ACTIVE) {
                    447:                        siop_cmd = NULL;
                    448:                }
1.1       bouyer    449:                if (istat & ISTAT_DIP)
1.8       bouyer    450:                        delay(10);
1.1       bouyer    451:                sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
1.8       bouyer    452:                        delay(10);
1.1       bouyer    453:                sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
                    454:                sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
1.8       bouyer    455: #ifdef DEBUG_INTR
1.1       bouyer    456:                printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
1.8       bouyer    457:                    "DSA=0x%x DSP=0x%lx\n", sist0, sist1,
1.1       bouyer    458:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
                    459:                    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
1.8       bouyer    460:                    (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    461:                    sc->sc_scriptaddr));
1.1       bouyer    462: #endif
1.7       bouyer    463:                if (siop_cmd) {
1.1       bouyer    464:                        xs = siop_cmd->xs;
1.7       bouyer    465:                        siop_target = siop_cmd->siop_target;
                    466:                }
1.1       bouyer    467:                if (sist0 & SIST0_RST) {
1.2       bouyer    468:                        siop_handle_reset(sc);
1.1       bouyer    469:                        siop_start(sc);
1.2       bouyer    470:                        /* no table to flush here */
1.1       bouyer    471:                        return 1;
                    472:                }
                    473:                if (sist0 & SIST0_SGE) {
                    474:                        if (siop_cmd)
                    475:                                scsi_print_addr(xs->sc_link);
                    476:                        else
                    477:                                printf("%s:", sc->sc_dev.dv_xname);
                    478:                        printf("scsi gross error\n");
                    479:                        goto reset;
                    480:                }
                    481:                if ((sist0 & SIST0_MA) && need_reset == 0) {
                    482:                        if (siop_cmd) {
1.8       bouyer    483:                                int scratcha0;
                    484:                                dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    485:                                    SIOP_DSTAT);
1.3       bouyer    486:                                /*
                    487:                                 * first restore DSA, in case we were in a S/G
                    488:                                 * operation.
                    489:                                 */
                    490:                                bus_space_write_4(sc->sc_rt, sc->sc_rh,
1.4       bouyer    491:                                    SIOP_DSA, siop_cmd->dsa);
1.8       bouyer    492:                                scratcha0 = bus_space_read_1(sc->sc_rt,
                    493:                                    sc->sc_rh, SIOP_SCRATCHA);
1.1       bouyer    494:                                switch (sstat1 & SSTAT1_PHASE_MASK) {
                    495:                                case SSTAT1_PHASE_STATUS:
                    496:                                /*
                    497:                                 * previous phase may be aborted for any reason
                    498:                                 * ( for example, the target has less data to
                    499:                                 * transfer than requested). Just go to status
                    500:                                 * and the command should terminate.
                    501:                                 */
1.2       bouyer    502:                                        INCSTAT(siop_stat_intr_shortxfer);
1.1       bouyer    503:                                        CALL_SCRIPT(Ent_status);
1.8       bouyer    504:                                        if ((dstat & DSTAT_DFE) == 0)
                    505:                                                siop_clearfifo(sc);
1.2       bouyer    506:                                        /* no table to flush here */
1.1       bouyer    507:                                        return 1;
                    508:                                case SSTAT1_PHASE_MSGIN:
                    509:                                        /*
                    510:                                         * target may be ready to disconnect
                    511:                                         * Save data pointers just in case.
                    512:                                         */
1.2       bouyer    513:                                        INCSTAT(siop_stat_intr_xferdisc);
1.8       bouyer    514:                                        if (scratcha0 & A_flag_data)
                    515:                                                siop_sdp(siop_cmd);
                    516:                                        else if ((dstat & DSTAT_DFE) == 0)
                    517:                                                siop_clearfifo(sc);
                    518:                                        bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    519:                                            SIOP_SCRATCHA,
                    520:                                            scratcha0 & ~A_flag_data);
1.2       bouyer    521:                                        siop_table_sync(siop_cmd,
                    522:                                            BUS_DMASYNC_PREREAD |
                    523:                                            BUS_DMASYNC_PREWRITE);
1.1       bouyer    524:                                        CALL_SCRIPT(Ent_msgin);
                    525:                                        return 1;
                    526:                                }
                    527:                                printf("%s: unexpected phase mismatch %d\n",
                    528:                                    sc->sc_dev.dv_xname,
                    529:                                    sstat1 & SSTAT1_PHASE_MASK);
                    530:                        } else {
                    531:                                printf("%s: phase mismatch without command\n",
                    532:                                    sc->sc_dev.dv_xname);
                    533:                        }
                    534:                        need_reset = 1;
                    535:                }
                    536:                if (sist0 & SIST0_PAR) {
                    537:                        /* parity error, reset */
                    538:                        if (siop_cmd)
                    539:                                scsi_print_addr(xs->sc_link);
                    540:                        else
                    541:                                printf("%s:", sc->sc_dev.dv_xname);
                    542:                        printf("parity error\n");
1.11      bouyer    543:                        goto reset;
1.1       bouyer    544:                }
                    545:                if ((sist1 & SIST1_STO) && need_reset == 0) {
                    546:                        /* selection time out, assume there's no device here */
                    547:                        if (siop_cmd) {
                    548:                                siop_cmd->status = CMDST_DONE;
                    549:                                xs->error = XS_SELTIMEOUT;
                    550:                                goto end;
                    551:                        } else {
                    552:                                printf("%s: selection timeout without "
                    553:                                    "command\n", sc->sc_dev.dv_xname);
                    554:                                need_reset = 1;
                    555:                        }
                    556:                }
                    557:                if (sist0 & SIST0_UDC) {
                    558:                        /*
                    559:                         * unexpected disconnect. Usually the target signals
                    560:                         * a fatal condition this way. Attempt to get sense.
                    561:                         */
                    562:                         if (siop_cmd)
1.7       bouyer    563:                                goto check_sense;
1.1       bouyer    564:                        printf("%s: unexpected disconnect without "
                    565:                            "command\n", sc->sc_dev.dv_xname);
1.2       bouyer    566:                        goto reset;
1.1       bouyer    567:                }
1.20      bouyer    568:                if (sist1 & SIST1_SBMC) {
                    569:                        /* SCSI bus mode change */
                    570:                        if (siop_modechange(sc) == 0 || need_reset == 1)
                    571:                                goto reset;
                    572:                        if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
                    573:                                /*
                    574:                                 * we have a script interrupt, it will
                    575:                                 * restart the script.
                    576:                                 */
                    577:                                goto scintr;
                    578:                        }
                    579:                        /*
                    580:                         * else we have to restart it ourselve, at the
                    581:                         * interrupted instruction.
                    582:                         */
                    583:                        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
                    584:                            bus_space_read_4(sc->sc_rt, sc->sc_rh,
                    585:                            SIOP_DSP) - 8);
                    586:                        return 1;
                    587:                }
1.1       bouyer    588:                /* Else it's an unhandled exeption (for now). */
                    589:                printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
                    590:                    "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
                    591:                    sist0, sist1,
                    592:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
                    593:                    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
1.7       bouyer    594:                    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    595:                    sc->sc_scriptaddr));
1.1       bouyer    596:                if (siop_cmd) {
                    597:                        siop_cmd->status = CMDST_DONE;
                    598:                        xs->error = XS_SELTIMEOUT;
                    599:                        goto end;
                    600:                }
                    601:                need_reset = 1;
                    602:        }
                    603:        if (need_reset) {
                    604: reset:
                    605:                /* fatal error, reset the bus */
                    606:                scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
                    607:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
                    608:                    scntl1 | SCNTL1_RST);
                    609:                /* minimum 25 us, more time won't hurt */
                    610:                delay(100);
                    611:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1.2       bouyer    612:                /* no table to flush here */
1.1       bouyer    613:                return 1;
                    614:        }
                    615:
1.20      bouyer    616: scintr:
1.1       bouyer    617:        if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
                    618:                irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
                    619:                    SIOP_DSPS);
1.2       bouyer    620: #ifdef DEBUG_INTR
                    621:                printf("script interrupt 0x%x\n", irqcode);
                    622: #endif
1.16      bouyer    623:                if (siop_cmd == NULL) {
                    624:                        printf("%s: script interrupt (0x%x) with invalid "
                    625:                            "DSA !!!\n", sc->sc_dev.dv_xname, irqcode);
                    626:                        goto reset;
                    627:                }
1.2       bouyer    628:                /*
                    629:                 * an inactive command is only valid if it's a reselect
                    630:                 * interrupt: we'll change siop_cmd to point to the rigth one
                    631:                 * just here
                    632:                 */
1.14      bouyer    633:                if (irqcode != A_int_resel && irqcode != A_int_reseltag &&
1.2       bouyer    634:                    siop_cmd->status != CMDST_ACTIVE &&
                    635:                    siop_cmd->status != CMDST_SENSE_ACTIVE) {
                    636:                        printf("%s: Aie, no command (IRQ code 0x%x current "
                    637:                            "status %d) !\n", sc->sc_dev.dv_xname,
                    638:                            irqcode, siop_cmd->status);
                    639:                        xs = NULL;
1.7       bouyer    640:                } else {
1.2       bouyer    641:                        xs = siop_cmd->xs;
1.7       bouyer    642:                        siop_target = siop_cmd->siop_target;
                    643:                }
1.1       bouyer    644:                switch(irqcode) {
                    645:                case A_int_err:
1.2       bouyer    646:                        printf("error, DSP=0x%x\n",
1.17      bouyer    647:                            (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh,
                    648:                            SIOP_DSP) - sc->sc_scriptaddr));
1.2       bouyer    649:                        if (xs) {
                    650:                                xs->error = XS_SELTIMEOUT;
                    651:                                goto end;
                    652:                        } else {
                    653:                                goto reset;
                    654:                        }
1.1       bouyer    655:                case A_int_msgin:
1.2       bouyer    656:                        if (siop_cmd->siop_table->msg_in[0] ==
                    657:                            MSG_MESSAGE_REJECT) {
1.8       bouyer    658:                                int msg, extmsg;
                    659:                                if (siop_cmd->siop_table->msg_out[0] & 0x80) {
                    660:                                        /*
                    661:                                         * message was part of a identify +
                    662:                                         * something else. Identify shoudl't
                    663:                                         * have been rejected.
                    664:                                         */
                    665:                                        msg = siop_cmd->siop_table->msg_out[1];
                    666:                                        extmsg =
                    667:                                            siop_cmd->siop_table->msg_out[3];
                    668:                                } else {
                    669:                                        msg = siop_cmd->siop_table->msg_out[0];
                    670:                                        extmsg =
                    671:                                            siop_cmd->siop_table->msg_out[2];
                    672:                                }
                    673:                                if (msg == MSG_MESSAGE_REJECT) {
1.2       bouyer    674:                                        /* MSG_REJECT  for a MSG_REJECT  !*/
1.9       bouyer    675:                                        if (xs)
                    676:                                                scsi_print_addr(xs->sc_link);
                    677:                                        else
                    678:                                                printf("%s: ",
                    679:                                                   sc->sc_dev.dv_xname);
                    680:                                        printf("our reject message was "
                    681:                                            "rejected\n");
1.2       bouyer    682:                                        goto reset;
                    683:                                }
1.8       bouyer    684:                                if (msg == MSG_EXTENDED &&
                    685:                                    extmsg == MSG_EXT_WDTR) {
1.9       bouyer    686:                                        /* WDTR rejected, initiate sync */
                    687:                                        printf("%s: target %d using 8bit "
                    688:                                            "transfers\n", sc->sc_dev.dv_xname,
                    689:                                            xs->sc_link->scsipi_scsi.target);
                    690:                                        siop_target->status = TARST_SYNC_NEG;
                    691:                                        siop_cmd->siop_table->msg_out[0] =
                    692:                                            MSG_EXTENDED;
                    693:                                        siop_cmd->siop_table->msg_out[1] =
                    694:                                            MSG_EXT_SDTR_LEN;
                    695:                                        siop_cmd->siop_table->msg_out[2] =
                    696:                                            MSG_EXT_SDTR;
                    697:                                        siop_cmd->siop_table->msg_out[3] =
                    698:                                            sc->minsync;
                    699:                                        siop_cmd->siop_table->msg_out[4] =
                    700:                                            sc->maxoff;
                    701:                                        siop_cmd->siop_table->t_msgout.count =
                    702:                                            htole32(MSG_EXT_SDTR_LEN + 2);
                    703:                                        siop_cmd->siop_table->t_msgout.addr =
                    704:                                            htole32(siop_cmd->dsa);
                    705:                                        siop_table_sync(siop_cmd,
                    706:                                            BUS_DMASYNC_PREREAD |
                    707:                                            BUS_DMASYNC_PREWRITE);
                    708:                                        CALL_SCRIPT(Ent_send_msgout);
                    709:                                        return 1;
1.8       bouyer    710:                                } else if (msg == MSG_EXTENDED &&
                    711:                                    extmsg == MSG_EXT_SDTR) {
1.7       bouyer    712:                                        /* sync rejected */
1.9       bouyer    713:                                        printf("%s: target %d asynchronous\n",
                    714:                                            sc->sc_dev.dv_xname,
                    715:                                            xs->sc_link->scsipi_scsi.target);
1.7       bouyer    716:                                        siop_cmd->siop_target->status =
                    717:                                            TARST_OK;
1.9       bouyer    718:                                        /* no table to flush here */
                    719:                                        CALL_SCRIPT(Ent_msgin_ack);
                    720:                                        return 1;
                    721:                                }
                    722:                                if (xs)
                    723:                                        scsi_print_addr(xs->sc_link);
                    724:                                else
                    725:                                        printf("%s: ", sc->sc_dev.dv_xname);
                    726:                                if (msg == MSG_EXTENDED) {
                    727:                                        printf("scsi message reject, extended "
                    728:                                            "message sent was 0x%x\n", extmsg);
                    729:                                } else {
                    730:                                        printf("scsi message reject, message "
                    731:                                            "sent was 0x%x\n", msg);
1.7       bouyer    732:                                }
1.2       bouyer    733:                                /* no table to flush here */
                    734:                                CALL_SCRIPT(Ent_msgin_ack);
                    735:                                return 1;
                    736:                        }
1.9       bouyer    737:                        if (xs)
                    738:                                scsi_print_addr(xs->sc_link);
                    739:                        else
                    740:                                printf("%s: ", sc->sc_dev.dv_xname);
1.8       bouyer    741:                        printf("unhandled message 0x%x\n",
                    742:                            siop_cmd->siop_table->msg_in[0]);
1.2       bouyer    743:                        siop_cmd->siop_table->t_msgout.count= htole32(1);
                    744:                        siop_cmd->siop_table->t_msgout.addr =
                    745:                            htole32(siop_cmd->dsa);
                    746:                        siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
                    747:                        siop_table_sync(siop_cmd,
                    748:                            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    749:                        CALL_SCRIPT(Ent_send_msgout);
                    750:                        return 1;
                    751:                case A_int_extmsgin:
                    752: #ifdef DEBUG_INTR
                    753:                        printf("extended message: msg 0x%x len %d\n",
                    754:                            siop_cmd->siop_table->msg_in[2],
                    755:                            siop_cmd->siop_table->msg_in[1]);
                    756: #endif
1.8       bouyer    757:                        if (siop_cmd->siop_table->msg_in[1] > 6)
                    758:                                printf("%s: extended message too big (%d)\n",
                    759:                                    sc->sc_dev.dv_xname,
                    760:                                    siop_cmd->siop_table->msg_in[1]);
1.2       bouyer    761:                        siop_cmd->siop_table->t_extmsgdata.count =
                    762:                            htole32(siop_cmd->siop_table->msg_in[1] - 1);
                    763:                        siop_cmd->siop_table->t_extmsgdata.addr =
                    764:                            htole32(
1.4       bouyer    765:                            le32toh(siop_cmd->siop_table->t_extmsgin.addr)
1.2       bouyer    766:                            + 2);
                    767:                        siop_table_sync(siop_cmd,
                    768:                            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    769:                        CALL_SCRIPT(Ent_get_extmsgdata);
                    770:                        return 1;
                    771:                case A_int_extmsgdata:
                    772: #ifdef DEBUG_INTR
                    773:                        {
                    774:                        int i;
                    775:                        printf("extended message: 0x%x, data:",
                    776:                            siop_cmd->siop_table->msg_in[2]);
                    777:                        for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
                    778:                            i++)
                    779:                                printf(" 0x%x",
                    780:                                    siop_cmd->siop_table->msg_in[i]);
                    781:                        printf("\n");
                    782:                        }
                    783: #endif
1.7       bouyer    784:                        if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_WDTR) {
1.14      bouyer    785:                                switch (siop_wdtr_neg(siop_cmd)) {
                    786:                                case SIOP_NEG_NOP:
                    787:                                        break;
                    788:                                case SIOP_NEG_MSGOUT:
                    789:                                        siop_table_sync(siop_cmd,
                    790:                                            BUS_DMASYNC_PREREAD |
                    791:                                            BUS_DMASYNC_PREWRITE);
                    792:                                        CALL_SCRIPT(Ent_send_msgout);
                    793:                                        break;
                    794:                                default:
                    795:                                        panic("invalid retval from "
                    796:                                            "siop_wdtr_neg()");
                    797:                                }
1.7       bouyer    798:                                return(1);
                    799:                        }
1.2       bouyer    800:                        if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
1.14      bouyer    801:                                switch (siop_sdtr_neg(siop_cmd)) {
                    802:                                case SIOP_NEG_NOP:
                    803:                                        break;
                    804:                                case SIOP_NEG_MSGOUT:
                    805:                                        siop_table_sync(siop_cmd,
                    806:                                            BUS_DMASYNC_PREREAD |
                    807:                                            BUS_DMASYNC_PREWRITE);
                    808:                                        CALL_SCRIPT(Ent_send_msgout);
                    809:                                        break;
                    810:                                case SIOP_NEG_ACK:
                    811:                                        CALL_SCRIPT(Ent_msgin_ack);
                    812:                                        break;
                    813:                                default:
                    814:                                        panic("invalid retval from "
                    815:                                            "siop_wdtr_neg()");
                    816:                                }
1.7       bouyer    817:                                return(1);
1.2       bouyer    818:                        }
1.7       bouyer    819:                        /* send a message reject */
                    820:                        siop_cmd->siop_table->t_msgout.count =
                    821:                            htole32(1);
                    822:                        siop_cmd->siop_table->t_msgout.addr =
                    823:                            htole32(siop_cmd->dsa);
                    824:                        siop_cmd->siop_table->msg_out[0] =
                    825:                            MSG_MESSAGE_REJECT;
1.2       bouyer    826:                        siop_table_sync(siop_cmd,
                    827:                            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    828:                        CALL_SCRIPT(Ent_send_msgout);
                    829:                        return 1;
1.1       bouyer    830:                case A_int_resel: /* reselected */
1.14      bouyer    831:                case A_int_reseltag: /* reselected  with tag */
1.2       bouyer    832:                        INCSTAT(siop_stat_intr_reselect);
                    833:                        if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
1.1       bouyer    834:                                printf("%s: reselect without identify (%d)\n",
                    835:                                    sc->sc_dev.dv_xname,
1.2       bouyer    836:                                    siop_cmd->siop_table->msg_in[0]);
1.1       bouyer    837:                                goto reset;
                    838:                        }
1.2       bouyer    839:                        target = bus_space_read_1(sc->sc_rt,
1.1       bouyer    840:                            sc->sc_rh, SIOP_SCRATCHA);
1.2       bouyer    841:                        if ((target & 0x80) == 0) {
                    842:                                printf("reselect without id (%d)\n", target);
1.1       bouyer    843:                                goto reset;
                    844:                        }
1.2       bouyer    845:                        target &= 0x0f;
1.7       bouyer    846:                        lun = siop_cmd->siop_table->msg_in[0] & 0x07;
1.1       bouyer    847: #ifdef DEBUG_DR
                    848:                        printf("reselected by target %d lun %d\n",
1.7       bouyer    849:                            target, lun);
1.1       bouyer    850: #endif
                    851:                        siop_cmd =
1.7       bouyer    852:                            sc->targets[target]->active_list[lun].tqh_first;
1.1       bouyer    853:                        if (siop_cmd == NULL) {
                    854:                                printf("%s: reselected without cmd\n",
                    855:                                    sc->sc_dev.dv_xname);
                    856:                                goto reset;
                    857:                        }
1.4       bouyer    858:                        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
                    859:                            siop_cmd->dsa);
1.11      bouyer    860:                        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
                    861:                            (sc->targets[target]->id >> 24) & 0xff);
                    862:                        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER,
                    863:                            (sc->targets[target]->id >> 8) & 0xff);
1.2       bouyer    864:                        /* no table to flush */
                    865:                        CALL_SCRIPT(Ent_selected);
1.1       bouyer    866:                        return 1;
                    867:                case A_int_disc:
1.2       bouyer    868:                        INCSTAT(siop_stat_intr_sdp);
1.1       bouyer    869:                        offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    870:                            SIOP_SCRATCHA + 1);
                    871: #ifdef DEBUG_DR
                    872:                        printf("disconnect offset %d\n", offset);
                    873: #endif
                    874:                        if (offset > SIOP_NSG) {
                    875:                                printf("%s: bad offset for disconnect (%d)\n",
                    876:                                    sc->sc_dev.dv_xname, offset);
                    877:                                goto reset;
                    878:                        }
                    879:                        /*
                    880:                         * offset == SIOP_NSG may be a valid condition if
                    881:                         * we get a sdp when the xfer is done.
                    882:                         * Don't call memmove in this case.
                    883:                         */
                    884:                        if (offset < SIOP_NSG) {
                    885:                                memmove(&siop_cmd->siop_table->data[0],
                    886:                                    &siop_cmd->siop_table->data[offset],
                    887:                                    (SIOP_NSG - offset) * sizeof(scr_table_t));
1.2       bouyer    888:                                siop_table_sync(siop_cmd,
                    889:                                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer    890:                        }
1.17      bouyer    891:                        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
                    892:                            sc->sc_sheddma->dm_segs[0].ds_addr);
1.1       bouyer    893:                        return 1;
                    894:                case A_int_resfail:
                    895:                        printf("reselect failed\n");
1.17      bouyer    896:                        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
                    897:                            sc->sc_sheddma->dm_segs[0].ds_addr);
1.1       bouyer    898:                        return  1;
                    899:                case A_int_done:
1.2       bouyer    900:                        if (xs == NULL) {
1.8       bouyer    901:                                printf("%s: done without command, DSA=0x%lx\n",
                    902:                                    sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);
                    903:                                siop_cmd->status = CMDST_FREE;
1.17      bouyer    904:                                bus_space_write_4(sc->sc_rt, sc->sc_rh,
                    905:                                    SIOP_DSP,
                    906:                                    sc->sc_sheddma->dm_segs[0].ds_addr);
1.2       bouyer    907:                                siop_start(sc);
                    908:                                return 1;
                    909:                        }
1.7       bouyer    910:                        if (siop_target->status == TARST_PROBING)
                    911:                                siop_target->status = TARST_ASYNC;
1.8       bouyer    912: #ifdef DEBUG_INTR
                    913:                        printf("done, DSA=0x%lx target id 0x%x last msg "
                    914:                            "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,
1.4       bouyer    915:                            le32toh(siop_cmd->siop_table->id),
1.2       bouyer    916:                            siop_cmd->siop_table->msg_in[0],
1.4       bouyer    917:                            le32toh(siop_cmd->siop_table->status));
1.1       bouyer    918: #endif
1.2       bouyer    919:                        INCSTAT(siop_stat_intr_done);
                    920:                        if (siop_cmd->status == CMDST_SENSE_ACTIVE)
1.1       bouyer    921:                                siop_cmd->status = CMDST_SENSE_DONE;
                    922:                        else
                    923:                                siop_cmd->status = CMDST_DONE;
1.4       bouyer    924:                        switch(le32toh(siop_cmd->siop_table->status)) {
1.1       bouyer    925:                        case SCSI_OK:
                    926:                                xs->error = (siop_cmd->status == CMDST_DONE) ?
                    927:                                    XS_NOERROR : XS_SENSE;
                    928:                                break;
                    929:                        case SCSI_BUSY:
                    930:                                xs->error = XS_BUSY;
                    931:                                break;
                    932:                        case SCSI_CHECK:
                    933: check_sense:
                    934:                                if (siop_cmd->status == CMDST_SENSE_DONE) {
1.2       bouyer    935:                                        /* request sense on a request sense ? */
                    936:                                        printf("request sense failed\n");
1.1       bouyer    937:                                        xs->error = XS_DRIVER_STUFFUP;
                    938:                                } else {
                    939:                                        siop_cmd->status = CMDST_SENSE;
                    940:                                }
                    941:                                break;
                    942:                        case 0xff:
                    943:                                /*
                    944:                                 * the status byte was not updated, cmd was
                    945:                                 * aborted
                    946:                                 */
                    947:                                xs->error = XS_SELTIMEOUT;
1.2       bouyer    948:                                break;
1.1       bouyer    949:                        default:
                    950:                                xs->error = XS_DRIVER_STUFFUP;
                    951:                        }
                    952:                        goto end;
                    953:                default:
                    954:                        printf("unknown irqcode %x\n", irqcode);
                    955:                        xs->error = XS_SELTIMEOUT;
                    956:                        goto end;
                    957:                }
                    958:                return 1;
                    959:        }
1.2       bouyer    960:        /* We just should't get there */
                    961:        panic("siop_intr: I shouldn't be there !");
                    962:        return 1;
1.1       bouyer    963: end:
1.7       bouyer    964:        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
1.17      bouyer    965:            sc->sc_sheddma->dm_segs[0].ds_addr);
1.7       bouyer    966:        lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
1.2       bouyer    967:        siop_scsicmd_end(siop_cmd);
                    968:        if (siop_cmd->status == CMDST_FREE) {
1.7       bouyer    969:                TAILQ_REMOVE(&siop_target->active_list[lun],
1.2       bouyer    970:                    siop_cmd, next);
                    971:                TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
                    972:        }
                    973:        siop_start(sc);
                    974:        return 1;
                    975: }
                    976:
                    977: void
                    978: siop_scsicmd_end(siop_cmd)
                    979:        struct siop_cmd *siop_cmd;
                    980: {
                    981:        struct scsipi_xfer *xs = siop_cmd->xs;
1.7       bouyer    982:        struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1.2       bouyer    983:
1.1       bouyer    984:        if (siop_cmd->status != CMDST_SENSE_DONE &&
                    985:            xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
                    986:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                    987:                    siop_cmd->dmamap_data->dm_mapsize,
                    988:                    (xs->xs_control & XS_CTL_DATA_IN) ?
                    989:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
                    990:                bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
                    991:        }
                    992:        bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
                    993:        if (siop_cmd->status == CMDST_SENSE) {
                    994:                /* issue a request sense for this target */
                    995:                int error, i;
                    996:                siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
                    997:                siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
                    998:                siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
                    999:                siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
                   1000:                siop_cmd->rs_cmd.control = 0;
1.2       bouyer   1001:                siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
                   1002:                siop_cmd->siop_table->t_msgout.count= htole32(1);
                   1003:                siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
                   1004:                siop_cmd->siop_table->msg_out[0] =
                   1005:                    MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1.1       bouyer   1006:                error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
                   1007:                    &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
                   1008:                    NULL, BUS_DMA_NOWAIT);
                   1009:                if (error) {
                   1010:                        printf("%s: unable to load cmd DMA map: %d",
                   1011:                            sc->sc_dev.dv_xname, error);
                   1012:                        xs->error = XS_DRIVER_STUFFUP;
                   1013:                        goto out;
                   1014:                }
                   1015:                siop_cmd->siop_table->cmd.count =
                   1016:                    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
                   1017:                siop_cmd->siop_table->cmd.addr =
                   1018:                    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
                   1019:                error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
                   1020:                    &xs->sense.scsi_sense, sizeof(struct  scsipi_sense_data),
                   1021:                    NULL, BUS_DMA_NOWAIT);
                   1022:                if (error) {
                   1023:                        printf("%s: unable to load sense DMA map: %d",
                   1024:                            sc->sc_dev.dv_xname, error);
                   1025:                        xs->error = XS_DRIVER_STUFFUP;
                   1026:                        bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
                   1027:                        goto out;
                   1028:                }
                   1029:                for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
                   1030:                        siop_cmd->siop_table->data[i].count =
                   1031:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
                   1032:                        siop_cmd->siop_table->data[i].addr =
                   1033:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
                   1034:                }
                   1035:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1036:                    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
                   1037:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
                   1038:                    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1.2       bouyer   1039:                siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
                   1040:                return;
1.1       bouyer   1041:        } else if (siop_cmd->status == CMDST_SENSE_DONE) {
                   1042:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1043:                    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
                   1044:                bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
                   1045:        }
                   1046: out:
                   1047:        callout_stop(&siop_cmd->xs->xs_callout);
                   1048:        siop_cmd->status = CMDST_FREE;
                   1049:        xs->xs_status |= XS_STS_DONE;
                   1050:        xs->resid = 0;
1.14      bouyer   1051:        if ((xs->xs_control & XS_CTL_POLL) == 0)
                   1052:                scsipi_done (xs);
1.7       bouyer   1053: }
                   1054:
1.2       bouyer   1055: /*
                   1056:  * handle a bus reset: reset chip, unqueue all active commands and report
                   1057:  * loosage to upper layer.
                   1058:  * As the upper layer may requeue immediatly we have to first store
                   1059:  * all active commands in a temporary queue.
                   1060:  */
                   1061: void
                   1062: siop_handle_reset(sc)
                   1063:        struct siop_softc *sc;
                   1064: {
                   1065:        struct cmd_list reset_list;
                   1066:        struct siop_cmd *siop_cmd, *next_siop_cmd;
1.7       bouyer   1067:        int target, lun;
1.2       bouyer   1068:        /*
                   1069:         * scsi bus reset. reset the chip and restart
                   1070:         * the queue. Need to clean up all active commands
                   1071:         */
                   1072:        printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
                   1073:        /* stop, reset and restart the chip */
                   1074:        siop_reset(sc);
                   1075:        TAILQ_INIT(&reset_list);
                   1076:        /* find all active commands */
1.7       bouyer   1077:        for (target = 0; target < sc->sc_link.scsipi_scsi.max_target;
                   1078:            target++) {
                   1079:                if (sc->targets[target] == NULL)
                   1080:                        continue;
                   1081:                for (lun = 0; lun < 8; lun++) {
                   1082:                        for (siop_cmd =
                   1083:                            TAILQ_FIRST(&sc->targets[target]->active_list[lun]);
                   1084:                            siop_cmd != NULL; siop_cmd = next_siop_cmd) {
                   1085:                                next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
                   1086:                                if (siop_cmd->status < CMDST_ACTIVE)
                   1087:                                        continue;
                   1088:                                printf("cmd %p (target %d) in reset list\n",
                   1089:                                    siop_cmd, target);
                   1090:                                TAILQ_REMOVE(
                   1091:                                    &sc->targets[target]->active_list[lun],
                   1092:                                    siop_cmd, next);
                   1093:                                TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
                   1094:                        }
1.2       bouyer   1095:                }
1.7       bouyer   1096:                sc->targets[target]->status = TARST_ASYNC;
                   1097:                sc->targets[target]->flags = ~(TARF_SYNC | TARF_WIDE);
1.2       bouyer   1098:        }
                   1099:        for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
                   1100:            siop_cmd = next_siop_cmd) {
                   1101:                next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
                   1102:                siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
                   1103:                    XS_TIMEOUT : XS_RESET;
                   1104:                printf("cmd %p about to be processed\n", siop_cmd);
1.16      bouyer   1105:                if (siop_cmd->status == CMDST_SENSE ||
                   1106:                    siop_cmd->status == CMDST_SENSE_ACTIVE)
                   1107:                        siop_cmd->status = CMDST_SENSE_DONE;
                   1108:                else
                   1109:                        siop_cmd->status = CMDST_DONE;
1.2       bouyer   1110:                TAILQ_REMOVE(&reset_list, siop_cmd, next);
                   1111:                siop_scsicmd_end(siop_cmd);
                   1112:                TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
                   1113:        }
1.1       bouyer   1114: }
                   1115:
1.2       bouyer   1116: int
1.1       bouyer   1117: siop_scsicmd(xs)
                   1118:        struct scsipi_xfer *xs;
                   1119: {
                   1120:        struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
                   1121:        struct siop_cmd *siop_cmd;
                   1122:        int s, error, i;
1.7       bouyer   1123:        int target = xs->sc_link->scsipi_scsi.target;
                   1124:        int lun = xs->sc_link->scsipi_scsi.lun;
1.1       bouyer   1125:
                   1126:        s = splbio();
1.7       bouyer   1127: #ifdef DEBUG_SHED
                   1128:        printf("starting cmd for %d:%d\n", target, lun);
1.1       bouyer   1129: #endif
                   1130:        siop_cmd = sc->free_list.tqh_first;
                   1131:        if (siop_cmd) {
                   1132:                TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1.16      bouyer   1133:        } else {
                   1134:                if (siop_morecbd(sc) == 0) {
                   1135:                        siop_cmd = sc->free_list.tqh_first;
                   1136: #ifdef DIAGNOSTIC
                   1137:                        if (siop_cmd == NULL)
                   1138:                                panic("siop_morecbd succeed and does nothing");
                   1139: #endif
                   1140:                        TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
                   1141:                }
1.1       bouyer   1142:        }
                   1143:        splx(s);
                   1144:        if (siop_cmd == NULL) {
                   1145:                xs->error = XS_DRIVER_STUFFUP;
                   1146:                return(TRY_AGAIN_LATER);
                   1147:        }
                   1148: #ifdef DIAGNOSTIC
                   1149:        if (siop_cmd->status != CMDST_FREE)
                   1150:                panic("siop_scsicmd: new cmd not free");
                   1151: #endif
1.7       bouyer   1152:        if (sc->targets[target] == NULL) {
                   1153:                sc->targets[target] =
                   1154:                    malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT);
                   1155:                if (sc->targets[target] == NULL) {
                   1156:                        printf("%s: can't malloc memory for target %d\n",
                   1157:                            sc->sc_dev.dv_xname, target);
                   1158:                        xs->error = XS_DRIVER_STUFFUP;
                   1159:                        return(TRY_AGAIN_LATER);
                   1160:                }
                   1161:                sc->targets[target]->siop_sc = sc;
                   1162:                sc->targets[target]->status = TARST_PROBING;
                   1163:                sc->targets[target]->flags = 0;
                   1164:                sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */
                   1165:                sc->targets[target]->id |=  target << 16; /* id */
1.14      bouyer   1166:                /* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */
1.7       bouyer   1167:                for (i = 0; i < 8; i++)
                   1168:                        TAILQ_INIT(&sc->targets[target]->active_list[i]);
                   1169:        }
                   1170:        siop_cmd->siop_target = sc->targets[target];
1.1       bouyer   1171:        siop_cmd->xs = xs;
1.7       bouyer   1172:        siop_cmd->siop_table->id = htole32(sc->targets[target]->id);
1.2       bouyer   1173:        siop_cmd->siop_table->t_msgout.count= htole32(1);
                   1174:        siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1.8       bouyer   1175:        memset(siop_cmd->siop_table->msg_out, 0, 8);
1.7       bouyer   1176:        siop_cmd->siop_table->msg_out[0] = MSG_IDENTIFY(lun, 1);
1.14      bouyer   1177: #if 0
                   1178:        siop_cmd->siop_table->msg_out[1] = MSG_SIMPLE_Q_TAG;
                   1179:        siop_cmd->siop_table->msg_out[2] = 0;
                   1180: #endif
1.7       bouyer   1181:        if (sc->targets[target]->status == TARST_ASYNC) {
                   1182:                if (sc->features & SF_BUS_WIDE) {
                   1183:                        sc->targets[target]->status = TARST_WIDE_NEG;
                   1184:                        siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
                   1185:                        siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR_LEN;
                   1186:                        siop_cmd->siop_table->msg_out[3] = MSG_EXT_WDTR;
                   1187:                        siop_cmd->siop_table->msg_out[4] =
                   1188:                            MSG_EXT_WDTR_BUS_16_BIT;
1.8       bouyer   1189:                        siop_cmd->siop_table->t_msgout.count=
                   1190:                            htole32(MSG_EXT_WDTR_LEN + 2 + 1);
1.7       bouyer   1191:                } else {
                   1192:                        sc->targets[target]->status = TARST_SYNC_NEG;
                   1193:                        siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
                   1194:                        siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR_LEN;
                   1195:                        siop_cmd->siop_table->msg_out[3] = MSG_EXT_SDTR;
                   1196:                        siop_cmd->siop_table->msg_out[4] = sc->minsync;
                   1197:                        siop_cmd->siop_table->msg_out[5] = sc->maxoff;
1.8       bouyer   1198:                        siop_cmd->siop_table->t_msgout.count=
                   1199:                            htole32(MSG_EXT_SDTR_LEN + 2 +1);
1.7       bouyer   1200:                }
                   1201:        }
1.2       bouyer   1202:        siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
1.1       bouyer   1203:
                   1204:        /* load the DMA maps */
                   1205:        error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
                   1206:            xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
                   1207:        if (error) {
                   1208:                printf("%s: unable to load cmd DMA map: %d",
                   1209:                    sc->sc_dev.dv_xname, error);
                   1210:                xs->error = XS_DRIVER_STUFFUP;
                   1211:                return(TRY_AGAIN_LATER);
                   1212:        }
                   1213:        siop_cmd->siop_table->cmd.count =
                   1214:            htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
                   1215:        siop_cmd->siop_table->cmd.addr =
                   1216:            htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
                   1217:        if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
                   1218:                error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
                   1219:                    xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
                   1220:                if (error) {
                   1221:                        printf("%s: unable to load cmd DMA map: %d",
                   1222:                            sc->sc_dev.dv_xname, error);
                   1223:                        xs->error = XS_DRIVER_STUFFUP;
                   1224:                        return(TRY_AGAIN_LATER);
                   1225:                        bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
                   1226:                }
                   1227:                for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
                   1228:                        siop_cmd->siop_table->data[i].count =
                   1229:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
                   1230:                        siop_cmd->siop_table->data[i].addr =
                   1231:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
                   1232:                }
                   1233:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1234:                    siop_cmd->dmamap_data->dm_mapsize,
                   1235:                    (xs->xs_control & XS_CTL_DATA_IN) ?
                   1236:                    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
                   1237:        }
                   1238:        bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
                   1239:            siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1.2       bouyer   1240:        siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer   1241:
                   1242:        siop_cmd->status = CMDST_READY;
                   1243:        s = splbio();
1.7       bouyer   1244:        TAILQ_INSERT_TAIL(&sc->targets[target]->active_list[lun],
1.1       bouyer   1245:            siop_cmd, next);
1.2       bouyer   1246:        siop_start(sc);
1.14      bouyer   1247:        if (xs->xs_control & XS_CTL_POLL) {
                   1248:                /* poll for command completion */
                   1249:                while ((xs->xs_status & XS_STS_DONE) == 0)
                   1250:                        siop_intr(sc);
                   1251:                splx(s);
                   1252:                return (COMPLETE);
                   1253:        }
1.1       bouyer   1254:        splx(s);
                   1255:        return (SUCCESSFULLY_QUEUED);
                   1256: }
                   1257:
                   1258: void
                   1259: siop_start(sc)
                   1260:        struct siop_softc *sc;
                   1261: {
                   1262:        struct siop_cmd *siop_cmd;
1.2       bouyer   1263:        u_int32_t *scr;
                   1264:        u_int32_t dsa;
1.1       bouyer   1265:        int timeout;
1.10      bouyer   1266:        int target, lun, slot;
1.2       bouyer   1267:        int newcmd = 0;
                   1268:
                   1269:        /*
                   1270:         * first make sure to read valid data
                   1271:         */
1.17      bouyer   1272:        siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.1       bouyer   1273:
1.2       bouyer   1274:        /*
1.10      bouyer   1275:         * The queue management here is a bit tricky: the script always looks
                   1276:         * at the slot from first to last, so if we always use the first
                   1277:         * free slot commands can stay at the tail of the queue ~forever.
                   1278:         * The algorithm used here is to restart from the head when we know
                   1279:         * that the queue is empty, and only add commands after the last one.
                   1280:         * When we're at the end of the queue wait for the script to clear it.
                   1281:         * The best thing to do here would be to implement a circular queue,
                   1282:         * but using only 53c720 features this can be "interesting".
                   1283:         * A mid-way solution could be to implement 2 queues and swap orders.
1.2       bouyer   1284:         */
1.10      bouyer   1285:        slot = sc->sc_currshedslot;
1.17      bouyer   1286:        scr = &sc->sc_shed[(Ent_nextslot / 4) * slot];
1.10      bouyer   1287:        /*
                   1288:         * if relative addr of first jump is not 0 the slot is free. As this is
                   1289:         * the last used slot, all previous slots are free, we can restart
                   1290:         * from 0.
                   1291:         */
                   1292:        if (scr[Ent_slot / 4 + 1] != 0) {
                   1293:                slot = sc->sc_currshedslot = 0;
                   1294:        } else {
                   1295:                slot++;
                   1296:        }
                   1297:
1.7       bouyer   1298:        for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target;
                   1299:            target++) {
                   1300:                if (sc->targets[target] == NULL)
1.2       bouyer   1301:                        continue;
1.7       bouyer   1302:                for (lun = 0; lun < 8; lun++) {
                   1303:                        siop_cmd =
                   1304:                            sc->targets[target]->active_list[lun].tqh_first;
                   1305:                        if (siop_cmd == NULL)
                   1306:                                continue;
                   1307:                        if (siop_cmd->status != CMDST_READY &&
                   1308:                            siop_cmd->status != CMDST_SENSE)
1.2       bouyer   1309:                                continue;
1.21    ! bouyer   1310:                        /* find a free scheduler slot and load it */
1.10      bouyer   1311:                        for (; slot < sc->sc_nshedslots; slot++) {
1.17      bouyer   1312:                                scr = &sc->sc_shed[(Ent_nextslot / 4) * slot];
1.7       bouyer   1313:                                /*
                   1314:                                 * if relative addr of first jump is 0 the
                   1315:                                 * slot isn't free
                   1316:                                 */
                   1317:                                if (scr[Ent_slot / 4 + 1] == 0)
                   1318:                                        continue;
1.2       bouyer   1319: #ifdef DEBUG_SHED
1.8       bouyer   1320:                                printf("using slot %d for DSA 0x%lx\n", slot,
                   1321:                                    (u_long)siop_cmd->dsa);
1.2       bouyer   1322: #endif
1.7       bouyer   1323:                                /* note that we started a new command */
                   1324:                                newcmd = 1;
                   1325:                                /* mark command as active */
                   1326:                                if (siop_cmd->status == CMDST_READY)
                   1327:                                        siop_cmd->status = CMDST_ACTIVE;
                   1328:                                else if (siop_cmd->status == CMDST_SENSE)
                   1329:                                        siop_cmd->status = CMDST_SENSE_ACTIVE;
                   1330:                                else
                   1331:                                        panic("siop_start: bad status");
                   1332:                                /* patch script with DSA addr */
                   1333:                                dsa = siop_cmd->dsa;
                   1334:                                /*
                   1335:                                 * 0x78000000 is a 'move data8 to reg'. data8
                   1336:                                 * is the second octet, reg offset is the third.
                   1337:                                 */
                   1338:                                scr[Ent_idsa0 / 4] =
                   1339:                                    htole32(0x78100000 |
                   1340:                                    ((dsa & 0x000000ff) <<  8));
                   1341:                                scr[Ent_idsa1 / 4] =
                   1342:                                    htole32(0x78110000 |
                   1343:                                    ( dsa & 0x0000ff00       ));
                   1344:                                scr[Ent_idsa2 / 4] =
                   1345:                                    htole32(0x78120000 |
                   1346:                                    ((dsa & 0x00ff0000) >>  8));
                   1347:                                scr[Ent_idsa3 / 4] =
                   1348:                                    htole32(0x78130000 |
                   1349:                                    ((dsa & 0xff000000) >> 16));
                   1350:                                /* handle timeout */
                   1351:                                if (siop_cmd->status == CMDST_ACTIVE) {
                   1352:                                        if ((siop_cmd->xs->xs_control &
                   1353:                                            XS_CTL_POLL) == 0) {
                   1354:                                                /* start exire timer */
                   1355:                                                timeout =
                   1356:                                                    siop_cmd->xs->timeout *
                   1357:                                                    hz / 1000;
                   1358:                                                if (timeout == 0)
                   1359:                                                        timeout = 1;
                   1360:                                                callout_reset(
                   1361:                                                    &siop_cmd->xs->xs_callout,
                   1362:                                                    timeout, siop_timeout,
                   1363:                                                    siop_cmd);
                   1364:                                        }
1.2       bouyer   1365:                                }
1.7       bouyer   1366:                                /*
                   1367:                                 * Change jump offset so that this slot will be
                   1368:                                 * handled
                   1369:                                 */
                   1370:                                scr[Ent_slot / 4 + 1] = 0;
                   1371:                                break;
                   1372:                        }
1.10      bouyer   1373:                        /* no more free slot, no need to continue */
1.7       bouyer   1374:                        if (slot == sc->sc_nshedslots) {
1.10      bouyer   1375:                                goto end;
1.2       bouyer   1376:                        }
1.7       bouyer   1377:                        sc->sc_currshedslot = slot;
1.1       bouyer   1378:                }
                   1379:        }
1.7       bouyer   1380: end:
1.2       bouyer   1381:        /* if nothing changed no need to flush cache and wakeup script */
                   1382:        if (newcmd == 0)
1.1       bouyer   1383:                return;
1.2       bouyer   1384:        /* make sure SCRIPT processor will read valid data */
1.17      bouyer   1385:        siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.2       bouyer   1386:        /* Signal script it has some work to do */
                   1387:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
                   1388:        /* and wait for IRQ */
                   1389:        return;
1.1       bouyer   1390: }
                   1391:
                   1392: void
                   1393: siop_timeout(v)
                   1394:        void *v;
                   1395: {
                   1396:        struct siop_cmd *siop_cmd = v;
1.7       bouyer   1397:        struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1.1       bouyer   1398:        int s;
                   1399:        u_int8_t scntl1;
                   1400:
                   1401:        scsi_print_addr(siop_cmd->xs->sc_link);
                   1402:        printf("command timeout\n");
                   1403:
                   1404:        s = splbio();
                   1405:        /* reset the scsi bus */
                   1406:        scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
                   1407:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
                   1408:            scntl1 | SCNTL1_RST);
                   1409:        /* minimum 25 us, more time won't hurt */
                   1410:        delay(100);
                   1411:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
                   1412:
1.12      soren    1413:        /* deactivate callout */
1.1       bouyer   1414:        callout_stop(&siop_cmd->xs->xs_callout);
                   1415:        /* mark command has being timed out; siop_intr will handle it */
                   1416:        /*
                   1417:         * mark command has being timed out and just return;
                   1418:         * the bus reset will generate an interrupt,
                   1419:         * it will be handled in siop_intr()
                   1420:         */
                   1421:        siop_cmd->flags |= CMDFL_TIMEOUT;
                   1422:        splx(s);
                   1423:        return;
                   1424:
                   1425: }
1.2       bouyer   1426:
                   1427: void
                   1428: siop_dump_script(sc)
                   1429:        struct siop_softc *sc;
                   1430: {
                   1431:        int i;
1.17      bouyer   1432:        siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.16      bouyer   1433:        for (i = 0; i < NBPG / 4; i += 2) {
1.4       bouyer   1434:                printf("0x%04x: 0x%08x 0x%08x", i * 4,
                   1435:                    le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
                   1436:                if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1.2       bouyer   1437:                        i++;
1.4       bouyer   1438:                        printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1.2       bouyer   1439:                }
                   1440:                printf("\n");
                   1441:        }
1.16      bouyer   1442: }
                   1443:
                   1444: int
                   1445: siop_morecbd(sc)
                   1446:        struct siop_softc *sc;
                   1447: {
                   1448:        int error, i;
                   1449:        bus_dma_segment_t seg;
                   1450:        int rseg;
                   1451:        struct siop_cbd *newcbd;
                   1452:
                   1453:        /* allocate a new list head */
                   1454:        newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT);
                   1455:        if (newcbd == NULL) {
                   1456:                printf("%s: can't allocate memory for command descriptors "
                   1457:                    "head\n", sc->sc_dev.dv_xname);
                   1458:                return ENOMEM;
                   1459:        }
                   1460:
                   1461:        /* allocate cmd list */
                   1462:        newcbd->cmds =
                   1463:            malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT);
                   1464:        if (newcbd->cmds == NULL) {
                   1465:                printf("%s: can't allocate memory for command descriptors\n",
                   1466:                    sc->sc_dev.dv_xname);
                   1467:                error = ENOMEM;
                   1468:                goto bad3;
                   1469:        }
                   1470:        error = bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, &rseg,
                   1471:            BUS_DMA_NOWAIT);
                   1472:        if (error) {
                   1473:                printf("%s: unable to allocate cbd DMA memory, error = %d\n",
                   1474:                    sc->sc_dev.dv_xname, error);
                   1475:                goto bad2;
                   1476:        }
                   1477:        error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
                   1478:            (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
                   1479:        if (error) {
                   1480:                printf("%s: unable to map cbd DMA memory, error = %d\n",
                   1481:                    sc->sc_dev.dv_xname, error);
                   1482:                goto bad2;
                   1483:        }
                   1484:        error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, NBPG, 0,
                   1485:            BUS_DMA_NOWAIT, &newcbd->xferdma);
                   1486:        if (error) {
                   1487:                printf("%s: unable to create cbd DMA map, error = %d\n",
                   1488:                    sc->sc_dev.dv_xname, error);
                   1489:                goto bad1;
                   1490:        }
                   1491:        error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers,
                   1492:            NBPG, NULL, BUS_DMA_NOWAIT);
                   1493:        if (error) {
1.17      bouyer   1494:                printf("%s: unable to load cbd DMA map, error = %d\n",
1.16      bouyer   1495:                    sc->sc_dev.dv_xname, error);
                   1496:                goto bad0;
                   1497:        }
                   1498:
                   1499:        for (i = 0; i < SIOP_NCMDPB; i++) {
                   1500:                error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
                   1501:                    MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
                   1502:                    &newcbd->cmds[i].dmamap_data);
                   1503:                if (error) {
                   1504:                        printf("%s: unable to create data DMA map for cbd: "
                   1505:                            "error %d\n",
                   1506:                            sc->sc_dev.dv_xname, error);
                   1507:                        goto bad0;
                   1508:                }
                   1509:                error = bus_dmamap_create(sc->sc_dmat,
                   1510:                    sizeof(struct scsipi_generic), 1,
                   1511:                    sizeof(struct scsipi_generic), 0,
                   1512:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
                   1513:                    &newcbd->cmds[i].dmamap_cmd);
                   1514:                if (error) {
                   1515:                        printf("%s: unable to create cmd DMA map for cbd %d\n",
                   1516:                            sc->sc_dev.dv_xname, error);
                   1517:                        goto bad0;
                   1518:                }
                   1519:                newcbd->cmds[i].siop_cbdp = newcbd;
                   1520:                newcbd->cmds[i].siop_table = &newcbd->xfers[i];
                   1521:                memset(newcbd->cmds[i].siop_table, 0, sizeof(struct siop_xfer));
                   1522:                newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr +
                   1523:                    i * sizeof(struct siop_xfer);
                   1524:                newcbd->cmds[i].status = CMDST_FREE;
                   1525:                newcbd->cmds[i].siop_table->t_msgout.count= htole32(1);
                   1526:                newcbd->cmds[i].siop_table->t_msgout.addr =
                   1527:                    htole32(newcbd->cmds[i].dsa);
                   1528:                newcbd->cmds[i].siop_table->t_msgin.count= htole32(1);
                   1529:                newcbd->cmds[i].siop_table->t_msgin.addr =
                   1530:                    htole32(newcbd->cmds[i].dsa + 8);
                   1531:                newcbd->cmds[i].siop_table->t_extmsgin.count= htole32(2);
                   1532:                newcbd->cmds[i].siop_table->t_extmsgin.addr = htole32(
                   1533:                    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1);
                   1534:                newcbd->cmds[i].siop_table->t_msgtag.count= htole32(2);
                   1535:                newcbd->cmds[i].siop_table->t_msgtag.addr = htole32(
                   1536:                    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1);
                   1537:                newcbd->cmds[i].siop_table->t_status.count= htole32(1);
                   1538:                newcbd->cmds[i].siop_table->t_status.addr = htole32(
                   1539:                    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 8);
                   1540:                TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
                   1541: #ifdef DEBUG
                   1542:                printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
                   1543:                    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr),
                   1544:                    le32toh(newcbd->cmds[i].siop_table->t_msgout.addr),
                   1545:                    le32toh(newcbd->cmds[i].siop_table->t_status.addr));
                   1546: #endif
                   1547:        }
                   1548:        TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
                   1549:        return 0;
                   1550: bad0:
                   1551:        bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma);
                   1552: bad1:
                   1553:        bus_dmamem_free(sc->sc_dmat, &seg, rseg);
                   1554: bad2:
                   1555:        free(newcbd->cmds, M_DEVBUF);
                   1556: bad3:
                   1557:        free(newcbd, M_DEVBUF);
                   1558:        return error;
1.2       bouyer   1559: }
                   1560:
                   1561: #ifdef SIOP_STATS
                   1562: void
                   1563: siop_printstats()
                   1564: {
                   1565:        printf("siop_stat_intr %d\n", siop_stat_intr);
                   1566:        printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
                   1567:        printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
                   1568:        printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
                   1569:        printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
                   1570:        printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
                   1571: }
                   1572: #endif

CVSweb <webmaster@jp.NetBSD.org>