[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.31

1.31    ! bouyer      1: /*     $NetBSD: siop.c,v 1.30 2000/10/06 20:07:10 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 <dev/microcode/siop/siop.out>
                     46:
                     47: #include <dev/scsipi/scsi_all.h>
                     48: #include <dev/scsipi/scsi_message.h>
                     49: #include <dev/scsipi/scsipi_all.h>
                     50:
                     51: #include <dev/scsipi/scsiconf.h>
                     52:
                     53: #include <dev/ic/siopreg.h>
                     54: #include <dev/ic/siopvar.h>
1.14      bouyer     55: #include <dev/ic/siopvar_common.h>
1.1       bouyer     56:
1.30      bouyer     57: #undef DEBUG
1.8       bouyer     58: #undef DEBUG_DR
1.2       bouyer     59: #undef DEBUG_INTR
1.31    ! bouyer     60: #undef DEBUG_SCHED
1.2       bouyer     61: #undef DUMP_SCRIPT
                     62:
                     63: #define SIOP_STATS
                     64:
1.1       bouyer     65: #ifndef SIOP_DEFAULT_TARGET
                     66: #define SIOP_DEFAULT_TARGET 7
                     67: #endif
                     68:
1.16      bouyer     69: /* number of cmd descriptors per block */
                     70: #define SIOP_NCMDPB (NBPG / sizeof(struct siop_xfer))
1.1       bouyer     71:
                     72: void   siop_reset __P((struct siop_softc *));
1.2       bouyer     73: void   siop_handle_reset __P((struct siop_softc *));
1.31    ! bouyer     74: int    siop_handle_qtag_reject __P((struct siop_cmd *));
1.2       bouyer     75: void   siop_scsicmd_end __P((struct siop_cmd *));
1.1       bouyer     76: void   siop_start __P((struct siop_softc *));
                     77: void   siop_timeout __P((void *));
                     78: int    siop_scsicmd __P((struct scsipi_xfer *));
1.2       bouyer     79: void   siop_dump_script __P((struct siop_softc *));
1.16      bouyer     80: int    siop_morecbd __P((struct siop_softc *));
1.31    ! bouyer     81: struct siop_lunsw *siop_get_lunsw __P((struct siop_softc *));
        !            82: void   siop_add_reselsw __P((struct siop_softc *, int));
        !            83: void   siop_update_scntl3 __P((struct siop_softc *, struct siop_target *));
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_xferdisc = 0;
                    107: void siop_printstats __P((void));
                    108: #define INCSTAT(x) x++
                    109: #else
                    110: #define INCSTAT(x)
                    111: #endif
                    112:
                    113: static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
                    114: static __inline__ void
                    115: siop_table_sync(siop_cmd, ops)
                    116:        struct siop_cmd *siop_cmd;
                    117:        int ops;
                    118: {
1.31    ! bouyer    119:        struct siop_softc *sc  = siop_cmd->siop_sc;
1.2       bouyer    120:        bus_addr_t offset;
                    121:
1.16      bouyer    122:        offset = siop_cmd->dsa -
                    123:            siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr;
                    124:        bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset,
1.2       bouyer    125:            sizeof(struct siop_xfer), ops);
                    126: }
                    127:
1.29      bouyer    128: static __inline__ void siop_sched_sync __P((struct siop_softc *, int));
1.2       bouyer    129: static __inline__ void
1.29      bouyer    130: siop_sched_sync(sc, ops)
1.2       bouyer    131:        struct siop_softc *sc;
                    132:        int ops;
                    133: {
1.31    ! bouyer    134:        bus_dmamap_sync(sc->sc_dmat, sc->sc_scheddma, 0, NBPG, ops);
1.28      bouyer    135: }
                    136:
1.31    ! bouyer    137: static __inline__ u_int32_t siop_script_read __P((struct siop_softc *, int));
        !           138: static __inline__ u_int32_t
        !           139: siop_script_read(sc, offset)
        !           140:        struct siop_softc *sc;
        !           141:        int offset;
        !           142: {
        !           143:        if (sc->features & SF_CHIP_RAM) {
        !           144:                return bus_space_read_4(sc->sc_ramt, sc->sc_ramh, offset * 4);
        !           145:        } else {
        !           146:                return le32toh(sc->sc_script[offset]);
        !           147:        }
        !           148: }
        !           149:
        !           150: static __inline__ void siop_script_write __P((struct siop_softc *, int,
        !           151:        u_int32_t));
1.28      bouyer    152: static __inline__ void
1.31    ! bouyer    153: siop_script_write(sc, offset, val)
1.28      bouyer    154:        struct siop_softc *sc;
1.31    ! bouyer    155:        int offset;
        !           156:        u_int32_t val;
1.28      bouyer    157: {
1.31    ! bouyer    158:        if (sc->features & SF_CHIP_RAM) {
        !           159:                bus_space_write_4(sc->sc_ramt, sc->sc_ramh, offset * 4, val);
        !           160:        } else {
        !           161:                sc->sc_script[offset] = htole32(val);
        !           162:        }
1.2       bouyer    163: }
                    164:
1.31    ! bouyer    165:
1.1       bouyer    166: void
                    167: siop_attach(sc)
                    168:        struct siop_softc *sc;
                    169: {
                    170:        int error, i;
                    171:        bus_dma_segment_t seg;
                    172:        int rseg;
                    173:
                    174:        /*
1.21      bouyer    175:         * Allocate DMA-safe memory for the script and script scheduler
1.17      bouyer    176:         * and map it.
1.1       bouyer    177:         */
1.17      bouyer    178:        if ((sc->features & SF_CHIP_RAM) == 0) {
                    179:                error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
                    180:                    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
                    181:                if (error) {
                    182:                        printf("%s: unable to allocate script DMA memory, "
                    183:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    184:                        return;
                    185:                }
                    186:                error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
                    187:                    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
                    188:                if (error) {
                    189:                        printf("%s: unable to map script DMA memory, "
                    190:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    191:                        return;
                    192:                }
                    193:                error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
                    194:                    NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
                    195:                if (error) {
                    196:                        printf("%s: unable to create script DMA map, "
                    197:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    198:                        return;
                    199:                }
                    200:                error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
1.31    ! bouyer    201:                    sc->sc_script, NBPG, NULL, BUS_DMA_NOWAIT);
1.17      bouyer    202:                if (error) {
                    203:                        printf("%s: unable to load script DMA map, "
                    204:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                    205:                        return;
                    206:                }
                    207:                sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr;
                    208:        }
1.31    ! bouyer    209:        error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
        !           210:            NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
1.1       bouyer    211:        if (error) {
1.21      bouyer    212:                printf("%s: unable to allocate scheduler DMA memory, "
1.17      bouyer    213:                    "error = %d\n", sc->sc_dev.dv_xname, error);
1.1       bouyer    214:                return;
                    215:        }
1.31    ! bouyer    216:        error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
1.29      bouyer    217:            (caddr_t *)&sc->sc_sched, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1.1       bouyer    218:        if (error) {
1.21      bouyer    219:                printf("%s: unable to map scheduler DMA memory, error = %d\n",
1.1       bouyer    220:                    sc->sc_dev.dv_xname, error);
                    221:                return;
                    222:        }
1.31    ! bouyer    223:        error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
        !           224:            NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scheddma);
1.1       bouyer    225:        if (error) {
1.21      bouyer    226:                printf("%s: unable to create scheduler DMA map, error = %d\n",
1.1       bouyer    227:                    sc->sc_dev.dv_xname, error);
                    228:                return;
                    229:        }
1.29      bouyer    230:        error = bus_dmamap_load(sc->sc_dmat, sc->sc_scheddma, sc->sc_sched,
1.31    ! bouyer    231:            NBPG, NULL, BUS_DMA_NOWAIT);
1.1       bouyer    232:        if (error) {
1.21      bouyer    233:                printf("%s: unable to load scheduler DMA map, error = %d\n",
1.1       bouyer    234:                    sc->sc_dev.dv_xname, error);
                    235:                return;
                    236:        }
                    237:        TAILQ_INIT(&sc->free_list);
1.31    ! bouyer    238:        TAILQ_INIT(&sc->ready_list);
1.16      bouyer    239:        TAILQ_INIT(&sc->cmds);
1.31    ! bouyer    240:        TAILQ_INIT(&sc->lunsw_list);
1.21      bouyer    241:        /* compute number of scheduler slots */
1.29      bouyer    242:        sc->sc_nschedslots = (
1.21      bouyer    243:            NBPG /* memory size allocated for scheduler */
                    244:            - sizeof(endslot_script) /* memory needed at end of scheduler */
1.2       bouyer    245:            ) / (sizeof(slot_script) - 8);
1.29      bouyer    246:        sc->sc_currschedslot = 0;
1.1       bouyer    247: #ifdef DEBUG
1.31    ! bouyer    248:        printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
1.2       bouyer    249:            sc->sc_dev.dv_xname, (int)sizeof(siop_script),
1.31    ! bouyer    250:            (u_int32_t)sc->sc_scriptaddr, sc->sc_script, sc->sc_nschedslots);
1.1       bouyer    251: #endif
                    252:
                    253:        sc->sc_link.adapter_softc = sc;
                    254:        sc->sc_link.openings = 1;
                    255:        sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
                    256:        sc->sc_link.scsipi_scsi.max_target  =
                    257:            (sc->features & SF_BUS_WIDE) ? 15 : 7;
                    258:        sc->sc_link.scsipi_scsi.max_lun = 7;
                    259:        sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
                    260:            sc->sc_rh, SIOP_SCID);
1.2       bouyer    261:        if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
                    262:            sc->sc_link.scsipi_scsi.adapter_target >
1.1       bouyer    263:            sc->sc_link.scsipi_scsi.max_target)
                    264:                sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
                    265:        sc->sc_link.type = BUS_SCSI;
                    266:        sc->sc_link.adapter = &siop_adapter;
                    267:        sc->sc_link.device = &siop_dev;
                    268:        sc->sc_link.flags  = 0;
                    269:
1.7       bouyer    270:        for (i = 0; i < 16; i++)
                    271:                sc->targets[i] = NULL;
                    272:
                    273:        /* find min/max sync period for this chip */
                    274:        sc->maxsync = 0;
                    275:        sc->minsync = 255;
                    276:        for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
                    277:                if (sc->clock_period != scf_period[i].clock)
                    278:                        continue;
                    279:                if (sc->maxsync < scf_period[i].period)
                    280:                        sc->maxsync = scf_period[i].period;
                    281:                if (sc->minsync > scf_period[i].period)
                    282:                        sc->minsync = scf_period[i].period;
                    283:        }
                    284:        if (sc->maxsync == 255 || sc->minsync == 0)
                    285:                panic("siop: can't find my sync parameters\n");
1.26      bouyer    286:        /* Do a bus reset, so that devices fall back to narrow/async */
                    287:        siop_resetbus(sc);
                    288:        /*
                    289:         * siop_reset() will reset the chip, thus clearing pending interrupts
                    290:         */
1.1       bouyer    291:        siop_reset(sc);
1.2       bouyer    292: #ifdef DUMP_SCRIPT
                    293:        siop_dump_script(sc);
                    294: #endif
1.1       bouyer    295:
                    296:        config_found((struct device*)sc, &sc->sc_link, scsiprint);
                    297: }
                    298:
                    299: void
                    300: siop_reset(sc)
                    301:        struct siop_softc *sc;
                    302: {
1.4       bouyer    303:        int i, j;
1.2       bouyer    304:        u_int32_t *scr;
                    305:        bus_addr_t physaddr;
1.31    ! bouyer    306:        struct siop_lunsw *lunsw;
1.4       bouyer    307:
1.14      bouyer    308:        siop_common_reset(sc);
1.1       bouyer    309:
                    310:        /* copy and patch the script */
1.17      bouyer    311:        if (sc->features & SF_CHIP_RAM) {
                    312:                bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0,
                    313:                    siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
                    314:                for (j = 0; j <
1.29      bouyer    315:                    (sizeof(E_script_abs_sched_Used) /
                    316:                    sizeof(E_script_abs_sched_Used[0]));
1.17      bouyer    317:                    j++) {
                    318:                        bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
1.29      bouyer    319:                            E_script_abs_sched_Used[j] * 4,
                    320:                            sc->sc_scheddma->dm_segs[0].ds_addr);
1.17      bouyer    321:                }
1.28      bouyer    322:                for (j = 0; j <
1.31    ! bouyer    323:                    (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
1.28      bouyer    324:                    j++) {
                    325:                        bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
1.31    ! bouyer    326:                            E_abs_msgin_Used[j] * 4,
        !           327:                            sc->sc_scriptaddr + Ent_msgin_space);
1.28      bouyer    328:                }
1.17      bouyer    329:        } else {
                    330:                for (j = 0;
                    331:                    j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
                    332:                        sc->sc_script[j] = htole32(siop_script[j]);
                    333:                }
                    334:                for (j = 0; j <
1.29      bouyer    335:                    (sizeof(E_script_abs_sched_Used) /
                    336:                    sizeof(E_script_abs_sched_Used[0]));
1.17      bouyer    337:                    j++) {
1.29      bouyer    338:                        sc->sc_script[E_script_abs_sched_Used[j]] =
                    339:                            htole32(sc->sc_scheddma->dm_segs[0].ds_addr);
1.28      bouyer    340:                }
                    341:                for (j = 0; j <
1.31    ! bouyer    342:                    (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
1.28      bouyer    343:                    j++) {
1.31    ! bouyer    344:                        sc->sc_script[E_abs_msgin_Used[j]] =
        !           345:                            htole32(sc->sc_scriptaddr + Ent_msgin_space);
1.17      bouyer    346:                }
1.4       bouyer    347:        }
1.31    ! bouyer    348:        sc->ram_free = sizeof(siop_script) / sizeof(siop_script[0]);
1.21      bouyer    349:        /* copy and init the scheduler slots script */
1.29      bouyer    350:        for (i = 0; i < sc->sc_nschedslots; i++) {
                    351:                scr = &sc->sc_sched[(Ent_nextslot / 4) * i];
                    352:                physaddr = sc->sc_scheddma->dm_segs[0].ds_addr +
1.17      bouyer    353:                    Ent_nextslot * i;
1.31    ! bouyer    354:                for (j = 0; j < (Ent_nextslot / 4); j++) {
1.4       bouyer    355:                        scr[j] = htole32(slot_script[j]);
                    356:                }
1.2       bouyer    357:                /*
                    358:                 * save current jump offset and patch MOVE MEMORY operands
                    359:                 * to restore it.
                    360:                 */
1.31    ! bouyer    361:                scr[(Ent_slotdata/4) + 1] = scr[(Ent_slot/4) + 1];
1.2       bouyer    362:                scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
1.29      bouyer    363:                scr[E_slot_sched_addrsrc_Used[0]] = htole32(physaddr +
1.2       bouyer    364:                    Ent_slotdata + 4);
                    365:                /* JUMP selected, in main script */
                    366:                scr[E_slot_abs_selected_Used[0]] =
1.17      bouyer    367:                   htole32(sc->sc_scriptaddr + Ent_selected);
1.2       bouyer    368:                /* JUMP addr if SELECT fail */
                    369:                scr[E_slot_abs_reselect_Used[0]] =
1.17      bouyer    370:                   htole32(sc->sc_scriptaddr + Ent_reselect);
1.2       bouyer    371:        }
                    372:        /* Now the final JUMP */
1.29      bouyer    373:        scr = &sc->sc_sched[(Ent_nextslot / 4) * sc->sc_nschedslots];
1.4       bouyer    374:        for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0]));
                    375:            j++) {
                    376:                scr[j] = htole32(endslot_script[j]);
                    377:        }
1.2       bouyer    378:        scr[E_endslot_abs_reselect_Used[0]] =
1.17      bouyer    379:            htole32(sc->sc_scriptaddr + Ent_reselect);
1.1       bouyer    380:
1.31    ! bouyer    381:        /* free used and unused lun switches */
        !           382:        while((lunsw = TAILQ_FIRST(&sc->lunsw_list)) != NULL) {
        !           383: #ifdef DEBUG
        !           384:                printf("%s: free lunsw at offset %d\n",
        !           385:                                sc->sc_dev.dv_xname, lunsw->lunsw_off);
        !           386: #endif
        !           387:                TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
        !           388:                free(lunsw, M_DEVBUF);
        !           389:        }
        !           390:        TAILQ_INIT(&sc->lunsw_list);
        !           391:        /* restore reselect switch */
        !           392:        for (i = 0; i < sc->sc_link.scsipi_scsi.max_target; i++) {
        !           393:                if (sc->targets[i] == NULL)
        !           394:                        continue;
        !           395: #ifdef DEBUG
        !           396:                printf("%s: restore sw for target %d\n",
        !           397:                                sc->sc_dev.dv_xname, i);
        !           398: #endif
        !           399:                free(sc->targets[i]->lunsw, M_DEVBUF);
        !           400:                sc->targets[i]->lunsw = siop_get_lunsw(sc);
        !           401:                if (sc->targets[i]->lunsw == NULL) {
        !           402:                        printf("%s: can't alloc lunsw for target %d\n",
        !           403:                            sc->sc_dev.dv_xname, i);
        !           404:                        break;
1.28      bouyer    405:                }
1.31    ! bouyer    406:                siop_add_reselsw(sc, i);
1.28      bouyer    407:        }
                    408:
1.2       bouyer    409:        /* start script */
1.22      bouyer    410:        if ((sc->features & SF_CHIP_RAM) == 0) {
                    411:                bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG,
                    412:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    413:        }
1.29      bouyer    414:        siop_sched_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.2       bouyer    415:        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
1.17      bouyer    416:            sc->sc_scriptaddr + Ent_reselect);
1.1       bouyer    417: }
                    418:
                    419: #if 0
                    420: #define CALL_SCRIPT(ent) do {\
                    421:        printf ("start script DSA 0x%lx DSP 0x%lx\n", \
1.4       bouyer    422:            siop_cmd->dsa, \
1.17      bouyer    423:            sc->sc_scriptaddr + ent); \
                    424: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
1.1       bouyer    425: } while (0)
                    426: #else
                    427: #define CALL_SCRIPT(ent) do {\
1.17      bouyer    428: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
1.1       bouyer    429: } while (0)
                    430: #endif
                    431:
                    432: int
                    433: siop_intr(v)
                    434:        void *v;
                    435: {
                    436:        struct siop_softc *sc = v;
1.7       bouyer    437:        struct siop_target *siop_target;
1.1       bouyer    438:        struct siop_cmd *siop_cmd;
1.31    ! bouyer    439:        struct siop_lun *siop_lun;
1.1       bouyer    440:        struct scsipi_xfer *xs;
1.26      bouyer    441:        int istat, sist0, sist1, sstat1, dstat;
1.1       bouyer    442:        u_int32_t irqcode;
                    443:        int need_reset = 0;
1.31    ! bouyer    444:        int freetarget = 0;
        !           445:        int offset, lun;
1.2       bouyer    446:        bus_addr_t dsa;
1.16      bouyer    447:        struct siop_cbd *cbdp;
1.1       bouyer    448:
                    449:        istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
1.2       bouyer    450:        if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
                    451:                return 0;
                    452:        INCSTAT(siop_stat_intr);
1.1       bouyer    453:        if (istat & ISTAT_INTF) {
                    454:                printf("INTRF\n");
                    455:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
                    456:        }
1.2       bouyer    457:        /* use DSA to find the current siop_cmd */
                    458:        dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
1.16      bouyer    459:        for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL;
                    460:            cbdp = TAILQ_NEXT(cbdp, next)) {
                    461:                if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&
                    462:                    dsa < cbdp->xferdma->dm_segs[0].ds_addr + NBPG) {
                    463:                        dsa -= cbdp->xferdma->dm_segs[0].ds_addr;
                    464:                        siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
                    465:                        siop_table_sync(siop_cmd,
                    466:                            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
                    467:                        break;
                    468:                }
                    469:        }
                    470:        if (cbdp == NULL) {
1.2       bouyer    471:                siop_cmd = NULL;
                    472:        }
1.31    ! bouyer    473:        if (siop_cmd) {
        !           474:                xs = siop_cmd->xs;
        !           475:                siop_target = siop_cmd->siop_target;
        !           476:                lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
        !           477:                siop_lun = &(siop_target->siop_lun[lun]);
        !           478: #ifdef DIAGNOSTIC
        !           479:                if (siop_cmd->status != CMDST_ACTIVE &&
        !           480:                    siop_cmd->status != CMDST_SENSE_ACTIVE) {
        !           481:                        printf("siop_cmd (lun %d) not active (%d)\n",
        !           482:                                lun, siop_cmd->status);
        !           483:                        xs = NULL;
        !           484:                        siop_target = NULL;
        !           485:                        lun = -1;
        !           486:                        siop_lun = NULL;
        !           487:                        siop_cmd = NULL;
        !           488:                } else if (siop_lun->active != siop_cmd) {
        !           489:                        printf("siop_cmd (lun %d) not in siop_lun active "
        !           490:                            "(%p != %p)\n", lun, siop_cmd, siop_lun->active);
        !           491:                }
        !           492: #endif
        !           493:        } else {
        !           494:                xs = NULL;
        !           495:                siop_target = NULL;
        !           496:                lun = -1;
        !           497:                siop_lun = NULL;
        !           498:        }
1.1       bouyer    499:        if (istat & ISTAT_DIP) {
                    500:                u_int32_t *p;
                    501:                dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
1.2       bouyer    502:                if (dstat & DSTAT_SSI) {
                    503:                        printf("single step dsp 0x%08x dsa 0x08%x\n",
1.7       bouyer    504:                            (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    505:                            sc->sc_scriptaddr),
1.2       bouyer    506:                            bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
                    507:                        if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
                    508:                            (istat & ISTAT_SIP) == 0) {
                    509:                                bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    510:                                    SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
                    511:                                    sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
                    512:                        }
                    513:                        return 1;
                    514:                }
                    515:                if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
1.1       bouyer    516:                printf("DMA IRQ:");
                    517:                if (dstat & DSTAT_IID)
                    518:                        printf(" Illegal instruction");
                    519:                if (dstat & DSTAT_ABRT)
                    520:                        printf(" abort");
                    521:                if (dstat & DSTAT_BF)
                    522:                        printf(" bus fault");
                    523:                if (dstat & DSTAT_MDPE)
                    524:                        printf(" parity");
                    525:                if (dstat & DSTAT_DFE)
                    526:                        printf(" dma fifo empty");
                    527:                printf(", DSP=0x%x DSA=0x%x: ",
1.7       bouyer    528:                    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    529:                    sc->sc_scriptaddr),
1.1       bouyer    530:                    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
1.2       bouyer    531:                p = sc->sc_script +
1.1       bouyer    532:                    (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    533:                    sc->sc_scriptaddr - 8) / 4;
1.4       bouyer    534:                printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]),
                    535:                    le32toh(p[2]), le32toh(p[3]));
1.2       bouyer    536:                if (siop_cmd)
1.1       bouyer    537:                        printf("last msg_in=0x%x status=0x%x\n",
1.31    ! bouyer    538:                            siop_cmd->siop_tables.msg_in[0],
        !           539:                            le32toh(siop_cmd->siop_tables.status));
1.20      bouyer    540:                else
                    541:                        printf("%s: current DSA invalid\n",
                    542:                            sc->sc_dev.dv_xname);
1.1       bouyer    543:                need_reset = 1;
                    544:                }
                    545:        }
                    546:        if (istat & ISTAT_SIP) {
                    547:                if (istat & ISTAT_DIP)
1.8       bouyer    548:                        delay(10);
1.1       bouyer    549:                sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
1.8       bouyer    550:                        delay(10);
1.1       bouyer    551:                sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
                    552:                sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
1.8       bouyer    553: #ifdef DEBUG_INTR
1.1       bouyer    554:                printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
1.8       bouyer    555:                    "DSA=0x%x DSP=0x%lx\n", sist0, sist1,
1.1       bouyer    556:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
                    557:                    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
1.8       bouyer    558:                    (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    559:                    sc->sc_scriptaddr));
1.1       bouyer    560: #endif
                    561:                if (sist0 & SIST0_RST) {
1.2       bouyer    562:                        siop_handle_reset(sc);
1.1       bouyer    563:                        siop_start(sc);
1.2       bouyer    564:                        /* no table to flush here */
1.1       bouyer    565:                        return 1;
                    566:                }
                    567:                if (sist0 & SIST0_SGE) {
                    568:                        if (siop_cmd)
                    569:                                scsi_print_addr(xs->sc_link);
                    570:                        else
                    571:                                printf("%s:", sc->sc_dev.dv_xname);
                    572:                        printf("scsi gross error\n");
                    573:                        goto reset;
                    574:                }
                    575:                if ((sist0 & SIST0_MA) && need_reset == 0) {
                    576:                        if (siop_cmd) {
1.8       bouyer    577:                                int scratcha0;
                    578:                                dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    579:                                    SIOP_DSTAT);
1.3       bouyer    580:                                /*
                    581:                                 * first restore DSA, in case we were in a S/G
                    582:                                 * operation.
                    583:                                 */
                    584:                                bus_space_write_4(sc->sc_rt, sc->sc_rh,
1.4       bouyer    585:                                    SIOP_DSA, siop_cmd->dsa);
1.8       bouyer    586:                                scratcha0 = bus_space_read_1(sc->sc_rt,
                    587:                                    sc->sc_rh, SIOP_SCRATCHA);
1.1       bouyer    588:                                switch (sstat1 & SSTAT1_PHASE_MASK) {
                    589:                                case SSTAT1_PHASE_STATUS:
                    590:                                /*
                    591:                                 * previous phase may be aborted for any reason
                    592:                                 * ( for example, the target has less data to
                    593:                                 * transfer than requested). Just go to status
                    594:                                 * and the command should terminate.
                    595:                                 */
1.2       bouyer    596:                                        INCSTAT(siop_stat_intr_shortxfer);
1.8       bouyer    597:                                        if ((dstat & DSTAT_DFE) == 0)
                    598:                                                siop_clearfifo(sc);
1.2       bouyer    599:                                        /* no table to flush here */
1.31    ! bouyer    600:                                        CALL_SCRIPT(Ent_status);
1.1       bouyer    601:                                        return 1;
                    602:                                case SSTAT1_PHASE_MSGIN:
                    603:                                        /*
                    604:                                         * target may be ready to disconnect
                    605:                                         * Save data pointers just in case.
                    606:                                         */
1.2       bouyer    607:                                        INCSTAT(siop_stat_intr_xferdisc);
1.8       bouyer    608:                                        if (scratcha0 & A_flag_data)
                    609:                                                siop_sdp(siop_cmd);
                    610:                                        else if ((dstat & DSTAT_DFE) == 0)
                    611:                                                siop_clearfifo(sc);
                    612:                                        bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    613:                                            SIOP_SCRATCHA,
                    614:                                            scratcha0 & ~A_flag_data);
1.2       bouyer    615:                                        siop_table_sync(siop_cmd,
                    616:                                            BUS_DMASYNC_PREREAD |
                    617:                                            BUS_DMASYNC_PREWRITE);
1.1       bouyer    618:                                        CALL_SCRIPT(Ent_msgin);
                    619:                                        return 1;
                    620:                                }
                    621:                                printf("%s: unexpected phase mismatch %d\n",
                    622:                                    sc->sc_dev.dv_xname,
                    623:                                    sstat1 & SSTAT1_PHASE_MASK);
                    624:                        } else {
                    625:                                printf("%s: phase mismatch without command\n",
                    626:                                    sc->sc_dev.dv_xname);
                    627:                        }
                    628:                        need_reset = 1;
                    629:                }
                    630:                if (sist0 & SIST0_PAR) {
                    631:                        /* parity error, reset */
                    632:                        if (siop_cmd)
                    633:                                scsi_print_addr(xs->sc_link);
                    634:                        else
                    635:                                printf("%s:", sc->sc_dev.dv_xname);
                    636:                        printf("parity error\n");
1.11      bouyer    637:                        goto reset;
1.1       bouyer    638:                }
                    639:                if ((sist1 & SIST1_STO) && need_reset == 0) {
                    640:                        /* selection time out, assume there's no device here */
                    641:                        if (siop_cmd) {
                    642:                                siop_cmd->status = CMDST_DONE;
                    643:                                xs->error = XS_SELTIMEOUT;
1.31    ! bouyer    644:                                freetarget = 1;
1.1       bouyer    645:                                goto end;
                    646:                        } else {
                    647:                                printf("%s: selection timeout without "
                    648:                                    "command\n", sc->sc_dev.dv_xname);
                    649:                                need_reset = 1;
                    650:                        }
                    651:                }
                    652:                if (sist0 & SIST0_UDC) {
                    653:                        /*
                    654:                         * unexpected disconnect. Usually the target signals
                    655:                         * a fatal condition this way. Attempt to get sense.
                    656:                         */
                    657:                         if (siop_cmd)
1.7       bouyer    658:                                goto check_sense;
1.1       bouyer    659:                        printf("%s: unexpected disconnect without "
                    660:                            "command\n", sc->sc_dev.dv_xname);
1.2       bouyer    661:                        goto reset;
1.1       bouyer    662:                }
1.20      bouyer    663:                if (sist1 & SIST1_SBMC) {
                    664:                        /* SCSI bus mode change */
                    665:                        if (siop_modechange(sc) == 0 || need_reset == 1)
                    666:                                goto reset;
                    667:                        if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
                    668:                                /*
                    669:                                 * we have a script interrupt, it will
                    670:                                 * restart the script.
                    671:                                 */
                    672:                                goto scintr;
                    673:                        }
                    674:                        /*
                    675:                         * else we have to restart it ourselve, at the
                    676:                         * interrupted instruction.
                    677:                         */
                    678:                        bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
                    679:                            bus_space_read_4(sc->sc_rt, sc->sc_rh,
                    680:                            SIOP_DSP) - 8);
                    681:                        return 1;
                    682:                }
1.1       bouyer    683:                /* Else it's an unhandled exeption (for now). */
                    684:                printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
                    685:                    "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
                    686:                    sist0, sist1,
                    687:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
                    688:                    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
1.7       bouyer    689:                    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17      bouyer    690:                    sc->sc_scriptaddr));
1.1       bouyer    691:                if (siop_cmd) {
                    692:                        siop_cmd->status = CMDST_DONE;
                    693:                        xs->error = XS_SELTIMEOUT;
                    694:                        goto end;
                    695:                }
                    696:                need_reset = 1;
                    697:        }
                    698:        if (need_reset) {
                    699: reset:
                    700:                /* fatal error, reset the bus */
1.26      bouyer    701:                siop_resetbus(sc);
1.2       bouyer    702:                /* no table to flush here */
1.1       bouyer    703:                return 1;
                    704:        }
                    705:
1.20      bouyer    706: scintr:
1.1       bouyer    707:        if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
                    708:                irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
                    709:                    SIOP_DSPS);
1.2       bouyer    710: #ifdef DEBUG_INTR
                    711:                printf("script interrupt 0x%x\n", irqcode);
                    712: #endif
                    713:                /*
1.31    ! bouyer    714:                 * no command, or an inactive command is only valid for a
        !           715:                 * reselect interrupt
1.2       bouyer    716:                 */
1.31    ! bouyer    717:                if ((irqcode & 0x80) == 0) {
        !           718:                        if (siop_cmd == NULL) {
        !           719:                                printf("%s: script interrupt (0x%x) with
        !           720:                                    invalid DSA !!!\n", sc->sc_dev.dv_xname,
        !           721:                                    irqcode);
        !           722:                                goto reset;
        !           723:                        }
        !           724:                        if (siop_cmd->status != CMDST_ACTIVE &&
        !           725:                            siop_cmd->status != CMDST_SENSE_ACTIVE) {
        !           726:                                printf("%s: command with invalid status "
        !           727:                                    "(IRQ code 0x%x current status %d) !\n",
        !           728:                                    sc->sc_dev.dv_xname,
        !           729:                                    irqcode, siop_cmd->status);
        !           730:                                xs = NULL;
        !           731:                        }
1.7       bouyer    732:                }
1.1       bouyer    733:                switch(irqcode) {
                    734:                case A_int_err:
1.2       bouyer    735:                        printf("error, DSP=0x%x\n",
1.17      bouyer    736:                            (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh,
                    737:                            SIOP_DSP) - sc->sc_scriptaddr));
1.2       bouyer    738:                        if (xs) {
                    739:                                xs->error = XS_SELTIMEOUT;
                    740:                                goto end;
                    741:                        } else {
                    742:                                goto reset;
                    743:                        }
1.31    ! bouyer    744:                case A_int_reseltarg:
        !           745:                        printf("%s: reselect with invalid target\n",
        !           746:                                    sc->sc_dev.dv_xname);
        !           747:                        goto reset;
        !           748:                case A_int_resellun:
        !           749:                        printf("%s: reselect with invalid lun\n",
        !           750:                                    sc->sc_dev.dv_xname);
        !           751:                        goto reset;
        !           752:                case A_int_reseltag:
        !           753:                        printf("%s: reselect with invalid tag\n",
        !           754:                                    sc->sc_dev.dv_xname);
        !           755:                        goto reset;
1.1       bouyer    756:                case A_int_msgin:
1.31    ! bouyer    757:                {
        !           758:                        int msgin = bus_space_read_1(sc->sc_rt, sc->sc_rh,
        !           759:                            SIOP_SFBR);
        !           760:                        if (msgin == MSG_MESSAGE_REJECT) {
1.8       bouyer    761:                                int msg, extmsg;
1.31    ! bouyer    762:                                if (siop_cmd->siop_tables.msg_out[0] & 0x80) {
1.8       bouyer    763:                                        /*
                    764:                                         * message was part of a identify +
                    765:                                         * something else. Identify shoudl't
                    766:                                         * have been rejected.
                    767:                                         */
1.31    ! bouyer    768:                                        msg = siop_cmd->siop_tables.msg_out[1];
1.8       bouyer    769:                                        extmsg =
1.31    ! bouyer    770:                                            siop_cmd->siop_tables.msg_out[3];
1.8       bouyer    771:                                } else {
1.31    ! bouyer    772:                                        msg = siop_cmd->siop_tables.msg_out[0];
1.8       bouyer    773:                                        extmsg =
1.31    ! bouyer    774:                                            siop_cmd->siop_tables.msg_out[2];
1.8       bouyer    775:                                }
                    776:                                if (msg == MSG_MESSAGE_REJECT) {
1.2       bouyer    777:                                        /* MSG_REJECT  for a MSG_REJECT  !*/
1.9       bouyer    778:                                        if (xs)
                    779:                                                scsi_print_addr(xs->sc_link);
                    780:                                        else
                    781:                                                printf("%s: ",
                    782:                                                   sc->sc_dev.dv_xname);
                    783:                                        printf("our reject message was "
                    784:                                            "rejected\n");
1.2       bouyer    785:                                        goto reset;
                    786:                                }
1.8       bouyer    787:                                if (msg == MSG_EXTENDED &&
                    788:                                    extmsg == MSG_EXT_WDTR) {
1.9       bouyer    789:                                        /* WDTR rejected, initiate sync */
                    790:                                        printf("%s: target %d using 8bit "
                    791:                                            "transfers\n", sc->sc_dev.dv_xname,
                    792:                                            xs->sc_link->scsipi_scsi.target);
1.31    ! bouyer    793:                                        if ((siop_target->flags & TARF_SYNC)
        !           794:                                            == 0) {
        !           795:                                                siop_target->status = TARST_OK;
1.26      bouyer    796:                                                /* no table to flush here */
                    797:                                                CALL_SCRIPT(Ent_msgin_ack);
                    798:                                                return 1;
                    799:                                        }
1.9       bouyer    800:                                        siop_target->status = TARST_SYNC_NEG;
1.31    ! bouyer    801:                                        siop_cmd->siop_tables.msg_out[0] =
1.9       bouyer    802:                                            MSG_EXTENDED;
1.31    ! bouyer    803:                                        siop_cmd->siop_tables.msg_out[1] =
1.9       bouyer    804:                                            MSG_EXT_SDTR_LEN;
1.31    ! bouyer    805:                                        siop_cmd->siop_tables.msg_out[2] =
1.9       bouyer    806:                                            MSG_EXT_SDTR;
1.31    ! bouyer    807:                                        siop_cmd->siop_tables.msg_out[3] =
1.9       bouyer    808:                                            sc->minsync;
1.31    ! bouyer    809:                                        siop_cmd->siop_tables.msg_out[4] =
1.9       bouyer    810:                                            sc->maxoff;
1.31    ! bouyer    811:                                        siop_cmd->siop_tables.t_msgout.count =
1.9       bouyer    812:                                            htole32(MSG_EXT_SDTR_LEN + 2);
1.31    ! bouyer    813:                                        siop_cmd->siop_tables.t_msgout.addr =
1.9       bouyer    814:                                            htole32(siop_cmd->dsa);
                    815:                                        siop_table_sync(siop_cmd,
                    816:                                            BUS_DMASYNC_PREREAD |
                    817:                                            BUS_DMASYNC_PREWRITE);
                    818:                                        CALL_SCRIPT(Ent_send_msgout);
                    819:                                        return 1;
1.8       bouyer    820:                                } else if (msg == MSG_EXTENDED &&
                    821:                                    extmsg == MSG_EXT_SDTR) {
1.7       bouyer    822:                                        /* sync rejected */
1.9       bouyer    823:                                        printf("%s: target %d asynchronous\n",
                    824:                                            sc->sc_dev.dv_xname,
                    825:                                            xs->sc_link->scsipi_scsi.target);
1.31    ! bouyer    826:                                        siop_target->status = TARST_OK;
1.9       bouyer    827:                                        /* no table to flush here */
                    828:                                        CALL_SCRIPT(Ent_msgin_ack);
                    829:                                        return 1;
                    830:                                }
                    831:                                if (xs)
                    832:                                        scsi_print_addr(xs->sc_link);
                    833:                                else
                    834:                                        printf("%s: ", sc->sc_dev.dv_xname);
                    835:                                if (msg == MSG_EXTENDED) {
                    836:                                        printf("scsi message reject, extended "
                    837:                                            "message sent was 0x%x\n", extmsg);
                    838:                                } else {
                    839:                                        printf("scsi message reject, message "
                    840:                                            "sent was 0x%x\n", msg);
1.31    ! bouyer    841:                                        if (msg == MSG_SIMPLE_Q_TAG ||
        !           842:                                            msg == MSG_HEAD_OF_Q_TAG ||
        !           843:                                            msg == MSG_ORDERED_Q_TAG)
        !           844:                                                if (siop_handle_qtag_reject(
        !           845:                                                    siop_cmd) == -1)
        !           846:                                                        goto reset;
1.7       bouyer    847:                                }
1.2       bouyer    848:                                /* no table to flush here */
                    849:                                CALL_SCRIPT(Ent_msgin_ack);
                    850:                                return 1;
                    851:                        }
1.9       bouyer    852:                        if (xs)
                    853:                                scsi_print_addr(xs->sc_link);
                    854:                        else
                    855:                                printf("%s: ", sc->sc_dev.dv_xname);
1.8       bouyer    856:                        printf("unhandled message 0x%x\n",
1.31    ! bouyer    857:                            siop_cmd->siop_tables.msg_in[0]);
        !           858:                        siop_cmd->siop_tables.t_msgout.count= htole32(1);
        !           859:                        siop_cmd->siop_tables.t_msgout.addr =
1.2       bouyer    860:                            htole32(siop_cmd->dsa);
1.31    ! bouyer    861:                        siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT;
1.2       bouyer    862:                        siop_table_sync(siop_cmd,
                    863:                            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    864:                        CALL_SCRIPT(Ent_send_msgout);
                    865:                        return 1;
1.31    ! bouyer    866:                }
1.2       bouyer    867:                case A_int_extmsgin:
                    868: #ifdef DEBUG_INTR
                    869:                        printf("extended message: msg 0x%x len %d\n",
1.31    ! bouyer    870:                            siop_cmd->siop_tables.msg_in[2],
        !           871:                            siop_cmd->siop_tables.msg_in[1]);
1.2       bouyer    872: #endif
1.31    ! bouyer    873:                        if (siop_cmd->siop_tables.msg_in[1] > 6)
1.8       bouyer    874:                                printf("%s: extended message too big (%d)\n",
                    875:                                    sc->sc_dev.dv_xname,
1.31    ! bouyer    876:                                    siop_cmd->siop_tables.msg_in[1]);
        !           877:                        siop_cmd->siop_tables.t_extmsgdata.count =
        !           878:                            htole32(siop_cmd->siop_tables.msg_in[1] - 1);
        !           879:                        siop_cmd->siop_tables.t_extmsgdata.addr =
1.2       bouyer    880:                            htole32(
1.31    ! bouyer    881:                            le32toh(siop_cmd->siop_tables.t_extmsgin.addr)
1.2       bouyer    882:                            + 2);
                    883:                        siop_table_sync(siop_cmd,
                    884:                            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    885:                        CALL_SCRIPT(Ent_get_extmsgdata);
                    886:                        return 1;
                    887:                case A_int_extmsgdata:
                    888: #ifdef DEBUG_INTR
                    889:                        {
                    890:                        int i;
                    891:                        printf("extended message: 0x%x, data:",
1.31    ! bouyer    892:                            siop_cmd->siop_tables.msg_in[2]);
        !           893:                        for (i = 3; i < 2 + siop_cmd->siop_tables.msg_in[1];
1.2       bouyer    894:                            i++)
                    895:                                printf(" 0x%x",
1.31    ! bouyer    896:                                    siop_cmd->siop_tables.msg_in[i]);
1.2       bouyer    897:                        printf("\n");
                    898:                        }
                    899: #endif
1.31    ! bouyer    900:                        if (siop_cmd->siop_tables.msg_in[2] == MSG_EXT_WDTR) {
1.14      bouyer    901:                                switch (siop_wdtr_neg(siop_cmd)) {
                    902:                                case SIOP_NEG_MSGOUT:
1.31    ! bouyer    903:                                        siop_update_scntl3(sc,
        !           904:                                            siop_cmd->siop_target);
1.14      bouyer    905:                                        siop_table_sync(siop_cmd,
                    906:                                            BUS_DMASYNC_PREREAD |
                    907:                                            BUS_DMASYNC_PREWRITE);
                    908:                                        CALL_SCRIPT(Ent_send_msgout);
1.31    ! bouyer    909:                                        return(1);
1.26      bouyer    910:                                case SIOP_NEG_ACK:
1.31    ! bouyer    911:                                        siop_update_scntl3(sc,
        !           912:                                            siop_cmd->siop_target);
1.26      bouyer    913:                                        CALL_SCRIPT(Ent_msgin_ack);
1.31    ! bouyer    914:                                        return(1);
1.14      bouyer    915:                                default:
                    916:                                        panic("invalid retval from "
                    917:                                            "siop_wdtr_neg()");
                    918:                                }
1.7       bouyer    919:                                return(1);
                    920:                        }
1.31    ! bouyer    921:                        if (siop_cmd->siop_tables.msg_in[2] == MSG_EXT_SDTR) {
1.14      bouyer    922:                                switch (siop_sdtr_neg(siop_cmd)) {
                    923:                                case SIOP_NEG_MSGOUT:
1.31    ! bouyer    924:                                        siop_update_scntl3(sc,
        !           925:                                            siop_cmd->siop_target);
1.14      bouyer    926:                                        siop_table_sync(siop_cmd,
                    927:                                            BUS_DMASYNC_PREREAD |
                    928:                                            BUS_DMASYNC_PREWRITE);
                    929:                                        CALL_SCRIPT(Ent_send_msgout);
1.31    ! bouyer    930:                                        return(1);
1.14      bouyer    931:                                case SIOP_NEG_ACK:
1.31    ! bouyer    932:                                        siop_update_scntl3(sc,
        !           933:                                            siop_cmd->siop_target);
1.14      bouyer    934:                                        CALL_SCRIPT(Ent_msgin_ack);
1.31    ! bouyer    935:                                        return(1);
1.14      bouyer    936:                                default:
                    937:                                        panic("invalid retval from "
                    938:                                            "siop_wdtr_neg()");
                    939:                                }
1.7       bouyer    940:                                return(1);
1.2       bouyer    941:                        }
1.7       bouyer    942:                        /* send a message reject */
1.31    ! bouyer    943:                        siop_cmd->siop_tables.t_msgout.count = htole32(1);
        !           944:                        siop_cmd->siop_tables.t_msgout.addr =
1.7       bouyer    945:                            htole32(siop_cmd->dsa);
1.31    ! bouyer    946:                        siop_cmd->siop_tables.msg_out[0] =
1.7       bouyer    947:                            MSG_MESSAGE_REJECT;
1.2       bouyer    948:                        siop_table_sync(siop_cmd,
                    949:                            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
                    950:                        CALL_SCRIPT(Ent_send_msgout);
                    951:                        return 1;
1.1       bouyer    952:                case A_int_disc:
1.2       bouyer    953:                        INCSTAT(siop_stat_intr_sdp);
1.1       bouyer    954:                        offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    955:                            SIOP_SCRATCHA + 1);
                    956: #ifdef DEBUG_DR
                    957:                        printf("disconnect offset %d\n", offset);
                    958: #endif
                    959:                        if (offset > SIOP_NSG) {
                    960:                                printf("%s: bad offset for disconnect (%d)\n",
                    961:                                    sc->sc_dev.dv_xname, offset);
                    962:                                goto reset;
                    963:                        }
                    964:                        /*
                    965:                         * offset == SIOP_NSG may be a valid condition if
                    966:                         * we get a sdp when the xfer is done.
                    967:                         * Don't call memmove in this case.
                    968:                         */
                    969:                        if (offset < SIOP_NSG) {
1.31    ! bouyer    970:                                memmove(&siop_cmd->siop_tables.data[0],
        !           971:                                    &siop_cmd->siop_tables.data[offset],
1.1       bouyer    972:                                    (SIOP_NSG - offset) * sizeof(scr_table_t));
1.2       bouyer    973:                                siop_table_sync(siop_cmd,
                    974:                                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer    975:                        }
1.31    ! bouyer    976:                        CALL_SCRIPT(Ent_script_sched);
1.1       bouyer    977:                        return 1;
                    978:                case A_int_resfail:
                    979:                        printf("reselect failed\n");
1.31    ! bouyer    980:                        CALL_SCRIPT(Ent_script_sched);
1.1       bouyer    981:                        return  1;
                    982:                case A_int_done:
1.2       bouyer    983:                        if (xs == NULL) {
1.8       bouyer    984:                                printf("%s: done without command, DSA=0x%lx\n",
                    985:                                    sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);
                    986:                                siop_cmd->status = CMDST_FREE;
1.2       bouyer    987:                                siop_start(sc);
1.31    ! bouyer    988:                                CALL_SCRIPT(Ent_script_sched);
1.2       bouyer    989:                                return 1;
                    990:                        }
1.26      bouyer    991:                        if (siop_target->status == TARST_PROBING &&
1.31    ! bouyer    992:                            xs->sc_link->device_softc != NULL) {
1.7       bouyer    993:                                siop_target->status = TARST_ASYNC;
1.31    ! bouyer    994:                        }
1.8       bouyer    995: #ifdef DEBUG_INTR
                    996:                        printf("done, DSA=0x%lx target id 0x%x last msg "
                    997:                            "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,
1.31    ! bouyer    998:                            le32toh(siop_cmd->siop_tables.id),
        !           999:                            siop_cmd->siop_tables.msg_in[0],
        !          1000:                            le32toh(siop_cmd->siop_tables.status));
1.1       bouyer   1001: #endif
1.2       bouyer   1002:                        INCSTAT(siop_stat_intr_done);
                   1003:                        if (siop_cmd->status == CMDST_SENSE_ACTIVE)
1.1       bouyer   1004:                                siop_cmd->status = CMDST_SENSE_DONE;
                   1005:                        else
                   1006:                                siop_cmd->status = CMDST_DONE;
1.31    ! bouyer   1007:                        switch(le32toh(siop_cmd->siop_tables.status)) {
1.1       bouyer   1008:                        case SCSI_OK:
                   1009:                                xs->error = (siop_cmd->status == CMDST_DONE) ?
                   1010:                                    XS_NOERROR : XS_SENSE;
                   1011:                                break;
                   1012:                        case SCSI_BUSY:
                   1013:                                xs->error = XS_BUSY;
                   1014:                                break;
                   1015:                        case SCSI_CHECK:
                   1016: check_sense:
                   1017:                                if (siop_cmd->status == CMDST_SENSE_DONE) {
1.2       bouyer   1018:                                        /* request sense on a request sense ? */
                   1019:                                        printf("request sense failed\n");
1.1       bouyer   1020:                                        xs->error = XS_DRIVER_STUFFUP;
                   1021:                                } else {
                   1022:                                        siop_cmd->status = CMDST_SENSE;
                   1023:                                }
                   1024:                                break;
                   1025:                        case 0xff:
                   1026:                                /*
                   1027:                                 * the status byte was not updated, cmd was
                   1028:                                 * aborted
                   1029:                                 */
                   1030:                                xs->error = XS_SELTIMEOUT;
1.2       bouyer   1031:                                break;
1.1       bouyer   1032:                        default:
                   1033:                                xs->error = XS_DRIVER_STUFFUP;
                   1034:                        }
                   1035:                        goto end;
                   1036:                default:
                   1037:                        printf("unknown irqcode %x\n", irqcode);
                   1038:                        xs->error = XS_SELTIMEOUT;
                   1039:                        goto end;
                   1040:                }
                   1041:                return 1;
                   1042:        }
1.2       bouyer   1043:        /* We just should't get there */
                   1044:        panic("siop_intr: I shouldn't be there !");
                   1045:        return 1;
1.1       bouyer   1046: end:
1.31    ! bouyer   1047:        CALL_SCRIPT(Ent_script_sched);
1.2       bouyer   1048:        siop_scsicmd_end(siop_cmd);
1.31    ! bouyer   1049:        siop_lun->active = NULL;
1.2       bouyer   1050:        if (siop_cmd->status == CMDST_FREE) {
1.31    ! bouyer   1051:                if (freetarget) {
        !          1052: #ifdef DEBUG
        !          1053:                        printf("%s: free siop_target for target %d lun %d "
        !          1054:                            "lunsw offset %d\n",
        !          1055:                            sc->sc_dev.dv_xname,
        !          1056:                            xs->sc_link->scsipi_scsi.target, lun,
        !          1057:                            sc->targets[xs->sc_link->scsipi_scsi.target]->lunsw->lunsw_off);
        !          1058: #endif
        !          1059:                        /*
        !          1060:                         * nothing here, free the target struct and resel
        !          1061:                         * switch entry
        !          1062:                         */
        !          1063:                        siop_script_write(sc, siop_cmd->siop_target->reseloff,
        !          1064:                            0x800c00ff);
        !          1065:                        TAILQ_INSERT_TAIL(&sc->lunsw_list,
        !          1066:                            sc->targets[xs->sc_link->scsipi_scsi.target]->lunsw,
        !          1067:                            next);
        !          1068:                        free(sc->targets[xs->sc_link->scsipi_scsi.target],
        !          1069:                            M_DEVBUF);
        !          1070:                        sc->targets[xs->sc_link->scsipi_scsi.target] = NULL;
        !          1071:                        siop_cmd->siop_target = NULL;
        !          1072:                }
1.2       bouyer   1073:                TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
                   1074:        }
                   1075:        siop_start(sc);
                   1076:        return 1;
                   1077: }
                   1078:
                   1079: void
                   1080: siop_scsicmd_end(siop_cmd)
                   1081:        struct siop_cmd *siop_cmd;
                   1082: {
                   1083:        struct scsipi_xfer *xs = siop_cmd->xs;
1.31    ! bouyer   1084:        struct siop_softc *sc = siop_cmd->siop_sc;
1.2       bouyer   1085:
1.1       bouyer   1086:        if (siop_cmd->status != CMDST_SENSE_DONE &&
                   1087:            xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
                   1088:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1089:                    siop_cmd->dmamap_data->dm_mapsize,
                   1090:                    (xs->xs_control & XS_CTL_DATA_IN) ?
                   1091:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
                   1092:                bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
                   1093:        }
                   1094:        bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
                   1095:        if (siop_cmd->status == CMDST_SENSE) {
                   1096:                /* issue a request sense for this target */
                   1097:                int error, i;
                   1098:                siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
                   1099:                siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
                   1100:                siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
                   1101:                siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
                   1102:                siop_cmd->rs_cmd.control = 0;
1.31    ! bouyer   1103:                siop_cmd->siop_tables.status = htole32(0xff);/*invalid status*/
        !          1104:                siop_cmd->siop_tables.t_msgout.count= htole32(1);
        !          1105:                siop_cmd->siop_tables.t_msgout.addr = htole32(siop_cmd->dsa);
        !          1106:                siop_cmd->siop_tables.msg_out[0] =
1.2       bouyer   1107:                    MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1.1       bouyer   1108:                error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
                   1109:                    &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
                   1110:                    NULL, BUS_DMA_NOWAIT);
                   1111:                if (error) {
                   1112:                        printf("%s: unable to load cmd DMA map: %d",
                   1113:                            sc->sc_dev.dv_xname, error);
                   1114:                        xs->error = XS_DRIVER_STUFFUP;
                   1115:                        goto out;
                   1116:                }
1.31    ! bouyer   1117:                siop_cmd->siop_tables.cmd.count =
1.1       bouyer   1118:                    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1.31    ! bouyer   1119:                siop_cmd->siop_tables.cmd.addr =
1.1       bouyer   1120:                    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
                   1121:                error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
                   1122:                    &xs->sense.scsi_sense, sizeof(struct  scsipi_sense_data),
                   1123:                    NULL, BUS_DMA_NOWAIT);
                   1124:                if (error) {
                   1125:                        printf("%s: unable to load sense DMA map: %d",
                   1126:                            sc->sc_dev.dv_xname, error);
                   1127:                        xs->error = XS_DRIVER_STUFFUP;
                   1128:                        bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
                   1129:                        goto out;
                   1130:                }
                   1131:                for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1.31    ! bouyer   1132:                        siop_cmd->siop_tables.data[i].count =
1.1       bouyer   1133:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1.31    ! bouyer   1134:                        siop_cmd->siop_tables.data[i].addr =
1.1       bouyer   1135:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
                   1136:                }
                   1137:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1138:                    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
                   1139:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
                   1140:                    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1.2       bouyer   1141:                siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
1.31    ! bouyer   1142:                /* arrange for the cmd to be handled now */
        !          1143:                TAILQ_INSERT_HEAD(&sc->ready_list, siop_cmd, next);
1.2       bouyer   1144:                return;
1.1       bouyer   1145:        } else if (siop_cmd->status == CMDST_SENSE_DONE) {
                   1146:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1147:                    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
                   1148:                bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
                   1149:        }
                   1150: out:
                   1151:        callout_stop(&siop_cmd->xs->xs_callout);
                   1152:        siop_cmd->status = CMDST_FREE;
                   1153:        xs->xs_status |= XS_STS_DONE;
                   1154:        xs->resid = 0;
1.14      bouyer   1155:        if ((xs->xs_control & XS_CTL_POLL) == 0)
                   1156:                scsipi_done (xs);
1.7       bouyer   1157: }
                   1158:
1.2       bouyer   1159: /*
1.31    ! bouyer   1160:  * handle a rejected queue tag message: the command will run untagged,
        !          1161:  * has to adjust the reselect script.
        !          1162:  */
        !          1163: int
        !          1164: siop_handle_qtag_reject(siop_cmd)
        !          1165:        struct siop_cmd *siop_cmd;
        !          1166: {
        !          1167: #if 0
        !          1168:        struct siop_softc *sc = siop_cmd->siop_sc;
        !          1169:        int target = siop_cmd->xs->sc_link->scsipi_scsi.target;
        !          1170:        int lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
        !          1171:        int tag = siop_cmd->siop_tables.msg_out[2];
        !          1172:        int resel;
        !          1173:        u_int32_t *rscr;
        !          1174:
        !          1175:        for (resel = 0; resel < sc->sc_nreselslots; resel++) {
        !          1176:                rscr = &sc->sc_resel[
        !          1177:                        (Ent_res_nextld / 4) * resel];
        !          1178:                if ((htole32(rscr[Ent_rtarget / 4]) & 0x0f) == target &&
        !          1179:                    (htole32(rscr[Ent_rlun / 4]) & 0x0f) == lun &&
        !          1180:                    (htole32(rscr[Ent_rtag / 4]) & 0xff) == tag) {
        !          1181:                        rscr[Ent_rtag / 4] = htole32(0x808400ff);
        !          1182:                        return 0;
        !          1183:                }
        !          1184:        }
        !          1185:        printf("%s: reselect entry not found for target %d lun %d tag %d\n",
        !          1186:            sc->sc_dev.dv_xname, target, lun, tag);
        !          1187:        return -1;
        !          1188: #endif
        !          1189:        return 0;
        !          1190: }
        !          1191:
        !          1192: /*
        !          1193:  * handle a bus reset: reset chip, unqueue all active commands, free all
        !          1194:  * target struct and report loosage to upper layer.
1.2       bouyer   1195:  * As the upper layer may requeue immediatly we have to first store
                   1196:  * all active commands in a temporary queue.
                   1197:  */
                   1198: void
                   1199: siop_handle_reset(sc)
                   1200:        struct siop_softc *sc;
                   1201: {
                   1202:        struct cmd_list reset_list;
                   1203:        struct siop_cmd *siop_cmd, *next_siop_cmd;
1.31    ! bouyer   1204:        struct siop_lun *siop_lun;
1.7       bouyer   1205:        int target, lun;
1.2       bouyer   1206:        /*
                   1207:         * scsi bus reset. reset the chip and restart
                   1208:         * the queue. Need to clean up all active commands
                   1209:         */
                   1210:        printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
                   1211:        /* stop, reset and restart the chip */
                   1212:        siop_reset(sc);
                   1213:        TAILQ_INIT(&reset_list);
                   1214:        /* find all active commands */
1.25      pk       1215:        for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target;
1.7       bouyer   1216:            target++) {
                   1217:                if (sc->targets[target] == NULL)
                   1218:                        continue;
                   1219:                for (lun = 0; lun < 8; lun++) {
1.31    ! bouyer   1220:                        siop_lun = &(sc->targets[target]->siop_lun[lun]);
        !          1221:                        if (siop_lun == NULL)
        !          1222:                                continue;
        !          1223:                        siop_cmd = siop_lun->active;
        !          1224:                        if (siop_cmd == NULL)
        !          1225:                                continue;
        !          1226:                        printf("cmd %p (target %d:%d) in reset list\n",
        !          1227:                            siop_cmd, target, lun);
        !          1228:                        TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
        !          1229:                        siop_lun->active = NULL;
1.2       bouyer   1230:                }
1.7       bouyer   1231:                sc->targets[target]->status = TARST_ASYNC;
1.31    ! bouyer   1232:                sc->targets[target]->flags &= ~TARF_ISWIDE;
        !          1233:        }
        !          1234:        for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL;
        !          1235:            siop_cmd = next_siop_cmd) {
        !          1236:                next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
        !          1237:                if (siop_cmd->status != CMDST_SENSE)
        !          1238:                        continue;
        !          1239:                printf("cmd %p (target %d:%d) in reset list (sense)\n",
        !          1240:                    siop_cmd, siop_cmd->xs->sc_link->scsipi_scsi.target,
        !          1241:                    siop_cmd->xs->sc_link->scsipi_scsi.lun);
        !          1242:                TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
        !          1243:                TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1.2       bouyer   1244:        }
1.31    ! bouyer   1245:
1.2       bouyer   1246:        for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
                   1247:            siop_cmd = next_siop_cmd) {
                   1248:                next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
                   1249:                siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
                   1250:                    XS_TIMEOUT : XS_RESET;
1.31    ! bouyer   1251:                printf("cmd %p (status %d) about to be processed\n", siop_cmd,
        !          1252:                    siop_cmd->status);
1.16      bouyer   1253:                if (siop_cmd->status == CMDST_SENSE ||
                   1254:                    siop_cmd->status == CMDST_SENSE_ACTIVE)
                   1255:                        siop_cmd->status = CMDST_SENSE_DONE;
                   1256:                else
                   1257:                        siop_cmd->status = CMDST_DONE;
1.2       bouyer   1258:                TAILQ_REMOVE(&reset_list, siop_cmd, next);
                   1259:                siop_scsicmd_end(siop_cmd);
                   1260:                TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
                   1261:        }
1.1       bouyer   1262: }
                   1263:
1.2       bouyer   1264: int
1.1       bouyer   1265: siop_scsicmd(xs)
                   1266:        struct scsipi_xfer *xs;
                   1267: {
                   1268:        struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
                   1269:        struct siop_cmd *siop_cmd;
                   1270:        int s, error, i;
1.31    ! bouyer   1271:        const int target = xs->sc_link->scsipi_scsi.target;
        !          1272:        const int lun = xs->sc_link->scsipi_scsi.lun;
1.1       bouyer   1273:
                   1274:        s = splbio();
1.31    ! bouyer   1275: #ifdef DEBUG_SCHED
1.7       bouyer   1276:        printf("starting cmd for %d:%d\n", target, lun);
1.1       bouyer   1277: #endif
1.31    ! bouyer   1278:        siop_cmd = TAILQ_FIRST(&sc->free_list);
1.1       bouyer   1279:        if (siop_cmd) {
                   1280:                TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1.16      bouyer   1281:        } else {
                   1282:                if (siop_morecbd(sc) == 0) {
1.31    ! bouyer   1283:                        siop_cmd = TAILQ_FIRST(&sc->free_list);
1.16      bouyer   1284: #ifdef DIAGNOSTIC
                   1285:                        if (siop_cmd == NULL)
                   1286:                                panic("siop_morecbd succeed and does nothing");
                   1287: #endif
                   1288:                        TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
                   1289:                }
1.1       bouyer   1290:        }
                   1291:        if (siop_cmd == NULL) {
                   1292:                xs->error = XS_DRIVER_STUFFUP;
1.31    ! bouyer   1293:                splx(s);
1.1       bouyer   1294:                return(TRY_AGAIN_LATER);
                   1295:        }
                   1296: #ifdef DIAGNOSTIC
                   1297:        if (siop_cmd->status != CMDST_FREE)
                   1298:                panic("siop_scsicmd: new cmd not free");
                   1299: #endif
1.7       bouyer   1300:        if (sc->targets[target] == NULL) {
1.31    ! bouyer   1301: #ifdef DEBUG
        !          1302:                printf("%s: alloc siop_target for target %d\n",
        !          1303:                        sc->sc_dev.dv_xname, target);
        !          1304: #endif
1.7       bouyer   1305:                sc->targets[target] =
                   1306:                    malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT);
                   1307:                if (sc->targets[target] == NULL) {
                   1308:                        printf("%s: can't malloc memory for target %d\n",
                   1309:                            sc->sc_dev.dv_xname, target);
                   1310:                        xs->error = XS_DRIVER_STUFFUP;
1.31    ! bouyer   1311:                        splx(s);
1.7       bouyer   1312:                        return(TRY_AGAIN_LATER);
                   1313:                }
                   1314:                sc->targets[target]->status = TARST_PROBING;
                   1315:                sc->targets[target]->flags = 0;
                   1316:                sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */
                   1317:                sc->targets[target]->id |=  target << 16; /* id */
1.14      bouyer   1318:                /* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */
1.31    ! bouyer   1319:
        !          1320:                /* get a lun switch script */
        !          1321:                sc->targets[target]->lunsw = siop_get_lunsw(sc);
        !          1322:                if (sc->targets[target]->lunsw == NULL) {
        !          1323:                        printf("%s: can't alloc lunsw for target %d\n",
        !          1324:                            sc->sc_dev.dv_xname, target);
        !          1325:                        xs->error = XS_DRIVER_STUFFUP;
        !          1326:                        splx(s);
        !          1327:                        return(TRY_AGAIN_LATER);
        !          1328:                }
        !          1329:                siop_add_reselsw(sc, target);
        !          1330:                for (i=0; i < 8; i++)
        !          1331:                        sc->targets[target]->siop_lun[i].active = NULL;
1.7       bouyer   1332:        }
                   1333:        siop_cmd->siop_target = sc->targets[target];
1.1       bouyer   1334:        siop_cmd->xs = xs;
1.31    ! bouyer   1335:        siop_cmd->flags = 0;
        !          1336:        siop_cmd->siop_tables.id = htole32(sc->targets[target]->id);
        !          1337:        siop_cmd->siop_tables.t_msgout.count= htole32(1);
        !          1338:        siop_cmd->siop_tables.t_msgout.addr = htole32(siop_cmd->dsa);
        !          1339:        memset(siop_cmd->siop_tables.msg_out, 0, 8);
        !          1340:        siop_cmd->siop_tables.msg_out[0] = MSG_IDENTIFY(lun, 1);
1.7       bouyer   1341:        if (sc->targets[target]->status == TARST_ASYNC) {
1.31    ! bouyer   1342:                if (sc->targets[target]->flags & TARF_WIDE) {
1.7       bouyer   1343:                        sc->targets[target]->status = TARST_WIDE_NEG;
1.31    ! bouyer   1344:                        siop_cmd->siop_tables.msg_out[1] = MSG_EXTENDED;
        !          1345:                        siop_cmd->siop_tables.msg_out[2] = MSG_EXT_WDTR_LEN;
        !          1346:                        siop_cmd->siop_tables.msg_out[3] = MSG_EXT_WDTR;
        !          1347:                        siop_cmd->siop_tables.msg_out[4] =
1.7       bouyer   1348:                            MSG_EXT_WDTR_BUS_16_BIT;
1.31    ! bouyer   1349:                        siop_cmd->siop_tables.t_msgout.count=
1.8       bouyer   1350:                            htole32(MSG_EXT_WDTR_LEN + 2 + 1);
1.31    ! bouyer   1351:                } else if (sc->targets[target]->flags & TARF_SYNC) {
1.7       bouyer   1352:                        sc->targets[target]->status = TARST_SYNC_NEG;
1.31    ! bouyer   1353:                        siop_cmd->siop_tables.msg_out[1] = MSG_EXTENDED;
        !          1354:                        siop_cmd->siop_tables.msg_out[2] = MSG_EXT_SDTR_LEN;
        !          1355:                        siop_cmd->siop_tables.msg_out[3] = MSG_EXT_SDTR;
        !          1356:                        siop_cmd->siop_tables.msg_out[4] = sc->minsync;
        !          1357:                        siop_cmd->siop_tables.msg_out[5] = sc->maxoff;
        !          1358:                        siop_cmd->siop_tables.t_msgout.count=
1.8       bouyer   1359:                            htole32(MSG_EXT_SDTR_LEN + 2 +1);
1.26      bouyer   1360:                } else {
                   1361:                        sc->targets[target]->status = TARST_OK;
1.7       bouyer   1362:                }
1.31    ! bouyer   1363:        } else if (sc->targets[target]->status == TARST_OK &&
        !          1364:            (sc->targets[target]->flags & TARF_TAG)) {
        !          1365:                siop_cmd->siop_tables.msg_out[1] = MSG_SIMPLE_Q_TAG;
        !          1366:                siop_cmd->siop_tables.msg_out[2] = 0;
        !          1367:                siop_cmd->siop_tables.t_msgout.count = htole32(3);
        !          1368:                siop_cmd->flags |= CMDFL_TAG;
1.7       bouyer   1369:        }
1.31    ! bouyer   1370:        siop_cmd->siop_tables.status = htole32(0xff); /* set invalid status */
1.1       bouyer   1371:
                   1372:        /* load the DMA maps */
                   1373:        error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
                   1374:            xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
                   1375:        if (error) {
                   1376:                printf("%s: unable to load cmd DMA map: %d",
                   1377:                    sc->sc_dev.dv_xname, error);
                   1378:                xs->error = XS_DRIVER_STUFFUP;
1.31    ! bouyer   1379:                splx(s);
1.1       bouyer   1380:                return(TRY_AGAIN_LATER);
                   1381:        }
1.31    ! bouyer   1382:        siop_cmd->siop_tables.cmd.count =
1.1       bouyer   1383:            htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1.31    ! bouyer   1384:        siop_cmd->siop_tables.cmd.addr =
1.1       bouyer   1385:            htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
                   1386:        if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
                   1387:                error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
                   1388:                    xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
                   1389:                if (error) {
                   1390:                        printf("%s: unable to load cmd DMA map: %d",
                   1391:                            sc->sc_dev.dv_xname, error);
                   1392:                        xs->error = XS_DRIVER_STUFFUP;
1.31    ! bouyer   1393:                        bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
        !          1394:                        splx(s);
1.1       bouyer   1395:                        return(TRY_AGAIN_LATER);
                   1396:                }
                   1397:                for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1.31    ! bouyer   1398:                        siop_cmd->siop_tables.data[i].count =
1.1       bouyer   1399:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1.31    ! bouyer   1400:                        siop_cmd->siop_tables.data[i].addr =
1.1       bouyer   1401:                            htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
                   1402:                }
                   1403:                bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
                   1404:                    siop_cmd->dmamap_data->dm_mapsize,
                   1405:                    (xs->xs_control & XS_CTL_DATA_IN) ?
                   1406:                    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
                   1407:        }
                   1408:        bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
                   1409:            siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1.2       bouyer   1410:        siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1       bouyer   1411:
                   1412:        siop_cmd->status = CMDST_READY;
1.31    ! bouyer   1413:        TAILQ_INSERT_TAIL(&sc->ready_list, siop_cmd, next);
1.2       bouyer   1414:        siop_start(sc);
1.14      bouyer   1415:        if (xs->xs_control & XS_CTL_POLL) {
                   1416:                /* poll for command completion */
1.31    ! bouyer   1417:                while ((xs->xs_status & XS_STS_DONE) == 0) {
        !          1418:                        delay(1000);
1.14      bouyer   1419:                        siop_intr(sc);
1.31    ! bouyer   1420:                }
1.14      bouyer   1421:                splx(s);
                   1422:                return (COMPLETE);
                   1423:        }
1.1       bouyer   1424:        splx(s);
                   1425:        return (SUCCESSFULLY_QUEUED);
                   1426: }
                   1427:
                   1428: void
                   1429: siop_start(sc)
                   1430:        struct siop_softc *sc;
                   1431: {
1.31    ! bouyer   1432:        struct siop_cmd *siop_cmd, *next_siop_cmd;
        !          1433:        struct siop_lun *siop_lun;
        !          1434:        u_int32_t *scr;
1.2       bouyer   1435:        u_int32_t dsa;
1.1       bouyer   1436:        int timeout;
1.31    ! bouyer   1437:        int target, lun, tag, slot;
1.2       bouyer   1438:        int newcmd = 0;
                   1439:
                   1440:        /*
                   1441:         * first make sure to read valid data
                   1442:         */
1.29      bouyer   1443:        siop_sched_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.1       bouyer   1444:
1.2       bouyer   1445:        /*
1.10      bouyer   1446:         * The queue management here is a bit tricky: the script always looks
                   1447:         * at the slot from first to last, so if we always use the first
                   1448:         * free slot commands can stay at the tail of the queue ~forever.
                   1449:         * The algorithm used here is to restart from the head when we know
                   1450:         * that the queue is empty, and only add commands after the last one.
                   1451:         * When we're at the end of the queue wait for the script to clear it.
                   1452:         * The best thing to do here would be to implement a circular queue,
                   1453:         * but using only 53c720 features this can be "interesting".
                   1454:         * A mid-way solution could be to implement 2 queues and swap orders.
1.2       bouyer   1455:         */
1.29      bouyer   1456:        slot = sc->sc_currschedslot;
                   1457:        scr = &sc->sc_sched[(Ent_nextslot / 4) * slot];
1.10      bouyer   1458:        /*
                   1459:         * if relative addr of first jump is not 0 the slot is free. As this is
                   1460:         * the last used slot, all previous slots are free, we can restart
                   1461:         * from 0.
                   1462:         */
1.31    ! bouyer   1463:        if (scr[(Ent_slot / 4) + 1] != 0) {
1.29      bouyer   1464:                slot = sc->sc_currschedslot = 0;
1.10      bouyer   1465:        } else {
                   1466:                slot++;
                   1467:        }
1.31    ! bouyer   1468:
        !          1469:        for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL;
        !          1470:            siop_cmd = next_siop_cmd) {
        !          1471:                next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
        !          1472: #ifdef DIAGNOSTIC
        !          1473:                if (siop_cmd->status != CMDST_READY &&
        !          1474:                    siop_cmd->status != CMDST_SENSE)
        !          1475:                        panic("siop: non-ready cmd in ready list");
        !          1476: #endif
        !          1477:                target = siop_cmd->xs->sc_link->scsipi_scsi.target;
        !          1478:                lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
        !          1479:                siop_lun = &(sc->targets[target]->siop_lun[lun]);
        !          1480:                if (siop_lun->active != NULL)
1.2       bouyer   1481:                        continue;
1.31    ! bouyer   1482:                /* find a free scheduler slot and load it */
        !          1483:                for (; slot < sc->sc_nschedslots; slot++) {
        !          1484:                        scr = &sc->sc_sched[(Ent_nextslot / 4) * slot];
        !          1485:                        /*
        !          1486:                         * if relative addr of first jump is not 0 the
        !          1487:                         * slot is free
        !          1488:                         */
        !          1489:                        if (scr[(Ent_slot / 4) + 1] != 0)
        !          1490:                                break;
        !          1491:                }
        !          1492:                /* no more free slot, no need to continue */
        !          1493:                if (slot == sc->sc_nschedslots) {
        !          1494:                        printf("out of slot\n");
        !          1495:                        goto end;
        !          1496:                }
        !          1497: #ifdef DEBUG_SCHED
        !          1498:                printf("using slot %d for DSA 0x%lx\n", slot,
        !          1499:                    (u_long)siop_cmd->dsa);
        !          1500: #endif
        !          1501:                /* note that we started a new command */
        !          1502:                newcmd = 1;
        !          1503:                /* mark command as active */
        !          1504:                if (siop_cmd->status == CMDST_READY) {
        !          1505:                        siop_cmd->status = CMDST_ACTIVE;
        !          1506:                        tag = (siop_cmd->flags & CMDFL_TAG) ?
        !          1507:                            0x0 : 0xff;
        !          1508:                } else if (siop_cmd->status == CMDST_SENSE) {
        !          1509:                        siop_cmd->status = CMDST_SENSE_ACTIVE;
        !          1510:                        tag = 0xff;
        !          1511:                        siop_cmd->siop_tables.t_msgout.count = htole32(1);
        !          1512:                } else
        !          1513:                        panic("siop_start: bad status");
        !          1514:                TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
        !          1515:                siop_lun->active = siop_cmd;
        !          1516:                /* patch scripts with DSA addr */
        !          1517:                dsa = siop_cmd->dsa;
        !          1518:                /* first reselect switch */
        !          1519:                siop_script_write(sc, siop_lun->reseloff + 1,
        !          1520:                    dsa + sizeof(struct siop_xfer_common) + Ent_reload_dsa);
        !          1521:                /* then scheduler entry */
        !          1522:                scr[E_slot_abs_loaddsa_Used[0]] =
        !          1523:                    htole32(dsa + sizeof(struct siop_xfer_common));
        !          1524: #ifdef DEBUG_SCHED
        !          1525:                { int j;
        !          1526:                printf("dump of slot:\n");
        !          1527:                for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0]));
        !          1528:                    j +=2)
        !          1529:                        printf("0x%x 0x%x\n", scr[j], scr[j+1]);
        !          1530:                }
1.28      bouyer   1531: #endif
1.31    ! bouyer   1532:                /* handle timeout */
        !          1533:                if (siop_cmd->status == CMDST_ACTIVE) {
        !          1534:                        if ((siop_cmd->xs->xs_control &
        !          1535:                            XS_CTL_POLL) == 0) {
        !          1536:                                /* start exire timer */
        !          1537:                                timeout = (u_int64_t) siop_cmd->xs->timeout *
        !          1538:                                    (u_int64_t)hz / 1000;
        !          1539:                                if (timeout == 0)
        !          1540:                                        timeout = 1;
        !          1541:                                callout_reset( &siop_cmd->xs->xs_callout,
        !          1542:                                    timeout, siop_timeout, siop_cmd);
1.28      bouyer   1543:                        }
1.1       bouyer   1544:                }
1.31    ! bouyer   1545:                /*
        !          1546:                 * Change jump offset so that this slot will be
        !          1547:                 * handled
        !          1548:                 */
        !          1549:                scr[(Ent_slot / 4) + 1] = 0;
        !          1550:                sc->sc_currschedslot = slot;
        !          1551:                slot++;
1.1       bouyer   1552:        }
1.7       bouyer   1553: end:
1.2       bouyer   1554:        /* if nothing changed no need to flush cache and wakeup script */
                   1555:        if (newcmd == 0)
1.1       bouyer   1556:                return;
1.2       bouyer   1557:        /* make sure SCRIPT processor will read valid data */
1.29      bouyer   1558:        siop_sched_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.2       bouyer   1559:        /* Signal script it has some work to do */
                   1560:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
                   1561:        /* and wait for IRQ */
                   1562:        return;
1.1       bouyer   1563: }
                   1564:
                   1565: void
                   1566: siop_timeout(v)
                   1567:        void *v;
                   1568: {
                   1569:        struct siop_cmd *siop_cmd = v;
1.31    ! bouyer   1570:        struct siop_softc *sc = siop_cmd->siop_sc;
1.1       bouyer   1571:        int s;
                   1572:
                   1573:        scsi_print_addr(siop_cmd->xs->sc_link);
                   1574:        printf("command timeout\n");
                   1575:
                   1576:        s = splbio();
                   1577:        /* reset the scsi bus */
1.26      bouyer   1578:        siop_resetbus(sc);
1.1       bouyer   1579:
1.12      soren    1580:        /* deactivate callout */
1.1       bouyer   1581:        callout_stop(&siop_cmd->xs->xs_callout);
1.31    ! bouyer   1582:        /* mark command as being timed out; siop_intr will handle it */
1.1       bouyer   1583:        /*
                   1584:         * mark command has being timed out and just return;
                   1585:         * the bus reset will generate an interrupt,
                   1586:         * it will be handled in siop_intr()
                   1587:         */
                   1588:        siop_cmd->flags |= CMDFL_TIMEOUT;
                   1589:        splx(s);
                   1590:        return;
                   1591:
                   1592: }
1.2       bouyer   1593:
                   1594: void
                   1595: siop_dump_script(sc)
                   1596:        struct siop_softc *sc;
                   1597: {
                   1598:        int i;
1.29      bouyer   1599:        siop_sched_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.16      bouyer   1600:        for (i = 0; i < NBPG / 4; i += 2) {
1.4       bouyer   1601:                printf("0x%04x: 0x%08x 0x%08x", i * 4,
                   1602:                    le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
                   1603:                if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1.2       bouyer   1604:                        i++;
1.4       bouyer   1605:                        printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1.2       bouyer   1606:                }
                   1607:                printf("\n");
                   1608:        }
1.16      bouyer   1609: }
                   1610:
                   1611: int
                   1612: siop_morecbd(sc)
                   1613:        struct siop_softc *sc;
                   1614: {
1.31    ! bouyer   1615:        int error, i, j;
1.16      bouyer   1616:        bus_dma_segment_t seg;
                   1617:        int rseg;
                   1618:        struct siop_cbd *newcbd;
1.31    ! bouyer   1619:        bus_addr_t dsa;
        !          1620:        u_int32_t *scr;
1.16      bouyer   1621:
                   1622:        /* allocate a new list head */
                   1623:        newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT);
                   1624:        if (newcbd == NULL) {
                   1625:                printf("%s: can't allocate memory for command descriptors "
                   1626:                    "head\n", sc->sc_dev.dv_xname);
                   1627:                return ENOMEM;
                   1628:        }
1.31    ! bouyer   1629:        memset(newcbd, 0, sizeof(struct siop_cbd));
1.16      bouyer   1630:
                   1631:        /* allocate cmd list */
                   1632:        newcbd->cmds =
                   1633:            malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT);
                   1634:        if (newcbd->cmds == NULL) {
                   1635:                printf("%s: can't allocate memory for command descriptors\n",
                   1636:                    sc->sc_dev.dv_xname);
                   1637:                error = ENOMEM;
                   1638:                goto bad3;
                   1639:        }
1.31    ! bouyer   1640:        memset(newcbd->cmds, 0, sizeof(struct siop_cmd) * SIOP_NCMDPB);
1.16      bouyer   1641:        error = bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, &rseg,
                   1642:            BUS_DMA_NOWAIT);
                   1643:        if (error) {
                   1644:                printf("%s: unable to allocate cbd DMA memory, error = %d\n",
                   1645:                    sc->sc_dev.dv_xname, error);
                   1646:                goto bad2;
                   1647:        }
                   1648:        error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
                   1649:            (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
                   1650:        if (error) {
                   1651:                printf("%s: unable to map cbd DMA memory, error = %d\n",
                   1652:                    sc->sc_dev.dv_xname, error);
                   1653:                goto bad2;
                   1654:        }
                   1655:        error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, NBPG, 0,
                   1656:            BUS_DMA_NOWAIT, &newcbd->xferdma);
                   1657:        if (error) {
                   1658:                printf("%s: unable to create cbd DMA map, error = %d\n",
                   1659:                    sc->sc_dev.dv_xname, error);
                   1660:                goto bad1;
                   1661:        }
                   1662:        error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers,
                   1663:            NBPG, NULL, BUS_DMA_NOWAIT);
                   1664:        if (error) {
1.17      bouyer   1665:                printf("%s: unable to load cbd DMA map, error = %d\n",
1.16      bouyer   1666:                    sc->sc_dev.dv_xname, error);
                   1667:                goto bad0;
                   1668:        }
1.31    ! bouyer   1669: #ifdef DEBUG
        !          1670:        printf("newcdb PHY addr: 0x%lx\n",
        !          1671:            (unsigned long)newcbd->xferdma->dm_segs[0].ds_addr);
        !          1672: #endif
1.16      bouyer   1673:
                   1674:        for (i = 0; i < SIOP_NCMDPB; i++) {
                   1675:                error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
                   1676:                    MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
                   1677:                    &newcbd->cmds[i].dmamap_data);
                   1678:                if (error) {
                   1679:                        printf("%s: unable to create data DMA map for cbd: "
                   1680:                            "error %d\n",
                   1681:                            sc->sc_dev.dv_xname, error);
                   1682:                        goto bad0;
                   1683:                }
                   1684:                error = bus_dmamap_create(sc->sc_dmat,
                   1685:                    sizeof(struct scsipi_generic), 1,
                   1686:                    sizeof(struct scsipi_generic), 0,
                   1687:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
                   1688:                    &newcbd->cmds[i].dmamap_cmd);
                   1689:                if (error) {
                   1690:                        printf("%s: unable to create cmd DMA map for cbd %d\n",
                   1691:                            sc->sc_dev.dv_xname, error);
                   1692:                        goto bad0;
                   1693:                }
1.31    ! bouyer   1694:                newcbd->cmds[i].siop_sc = sc;
1.16      bouyer   1695:                newcbd->cmds[i].siop_cbdp = newcbd;
1.31    ! bouyer   1696:                newcbd->cmds[i].siop_xfer = &newcbd->xfers[i];
        !          1697:                memset(newcbd->cmds[i].siop_xfer, 0,
        !          1698:                    sizeof(struct siop_xfer));
1.16      bouyer   1699:                newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr +
                   1700:                    i * sizeof(struct siop_xfer);
1.31    ! bouyer   1701:                dsa = newcbd->cmds[i].dsa;
1.16      bouyer   1702:                newcbd->cmds[i].status = CMDST_FREE;
1.31    ! bouyer   1703:                newcbd->cmds[i].siop_tables.t_msgout.count= htole32(1);
        !          1704:                newcbd->cmds[i].siop_tables.t_msgout.addr = htole32(dsa);
        !          1705:                newcbd->cmds[i].siop_tables.t_msgin.count= htole32(1);
        !          1706:                newcbd->cmds[i].siop_tables.t_msgin.addr = htole32(dsa + 8);
        !          1707:                newcbd->cmds[i].siop_tables.t_extmsgin.count= htole32(2);
        !          1708:                newcbd->cmds[i].siop_tables.t_extmsgin.addr = htole32(
        !          1709:                    le32toh(newcbd->cmds[i].siop_tables.t_msgin.addr) + 1);
        !          1710:                newcbd->cmds[i].siop_tables.t_msgtag.count= htole32(2);
        !          1711:                newcbd->cmds[i].siop_tables.t_msgtag.addr = htole32(
        !          1712:                    le32toh(newcbd->cmds[i].siop_tables.t_msgin.addr) + 1);
        !          1713:                newcbd->cmds[i].siop_tables.t_status.count= htole32(1);
        !          1714:                newcbd->cmds[i].siop_tables.t_status.addr = htole32(
        !          1715:                    le32toh(newcbd->cmds[i].siop_tables.t_msgin.addr) + 8);
        !          1716:
        !          1717:                /* The reselect script */
        !          1718:                scr = &newcbd->cmds[i].siop_xfer->resel[0];
        !          1719:                for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]); j++)
        !          1720:                        scr[j] = htole32(load_dsa[j]);
        !          1721:                /*
        !          1722:                 * 0x78000000 is a 'move data8 to reg'. data8 is the second
        !          1723:                 * octet, reg offset is the third.
        !          1724:                 */
        !          1725:                scr[Ent_rdsa0 / 4] =
        !          1726:                    htole32(0x78100000 | ((dsa & 0x000000ff) <<  8));
        !          1727:                scr[Ent_rdsa1 / 4] =
        !          1728:                    htole32(0x78110000 | ( dsa & 0x0000ff00       ));
        !          1729:                scr[Ent_rdsa2 / 4] =
        !          1730:                    htole32(0x78120000 | ((dsa & 0x00ff0000) >>  8));
        !          1731:                scr[Ent_rdsa3 / 4] =
        !          1732:                    htole32(0x78130000 | ((dsa & 0xff000000) >> 16));
        !          1733:                for (j = 0;
        !          1734:                    j < (sizeof(E_resel_abs_reselected_Used) /
        !          1735:                    sizeof(E_resel_abs_reselected_Used[0])); j++)
        !          1736:                        scr[E_resel_abs_reselected_Used[j]] =
        !          1737:                            htole32(sc->sc_scriptaddr + Ent_reselected);
1.16      bouyer   1738:                TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
                   1739: #ifdef DEBUG
1.31    ! bouyer   1740:                printf("tables[%d]: in=0x%x out=0x%x status=0x%x\n", i,
        !          1741:                    le32toh(newcbd->cmds[i].siop_tables.t_msgin.addr),
        !          1742:                    le32toh(newcbd->cmds[i].siop_tables.t_msgout.addr),
        !          1743:                    le32toh(newcbd->cmds[i].siop_tables.t_status.addr));
        !          1744:                for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]);
        !          1745:                    j += 2) {
        !          1746:                        printf("0x%x 0x%x\n", scr[j], scr[j+1]);
        !          1747:                }
1.16      bouyer   1748: #endif
                   1749:        }
                   1750:        TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
                   1751:        return 0;
                   1752: bad0:
                   1753:        bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma);
                   1754: bad1:
                   1755:        bus_dmamem_free(sc->sc_dmat, &seg, rseg);
                   1756: bad2:
                   1757:        free(newcbd->cmds, M_DEVBUF);
                   1758: bad3:
                   1759:        free(newcbd, M_DEVBUF);
                   1760:        return error;
1.2       bouyer   1761: }
                   1762:
1.31    ! bouyer   1763: struct siop_lunsw *
        !          1764: siop_get_lunsw(sc)
        !          1765:        struct siop_softc *sc;
        !          1766: {
        !          1767:        struct siop_lunsw *lunsw;
        !          1768:        int i;
        !          1769:
        !          1770:        lunsw = TAILQ_FIRST(&sc->lunsw_list);
        !          1771:        if (lunsw != NULL) {
        !          1772: #ifdef DEBUG
        !          1773:                printf("siop_get_lunsw got lunsw at offset %d\n",
        !          1774:                    lunsw->lunsw_off);
        !          1775: #endif
        !          1776:                TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
        !          1777:                return lunsw;
        !          1778:        }
        !          1779:        lunsw = malloc(sizeof(struct siop_lunsw), M_DEVBUF, M_NOWAIT);
        !          1780:        if (lunsw == NULL)
        !          1781:                return NULL;
        !          1782:        memset(lunsw, 0, sizeof(struct siop_lunsw));
        !          1783: #ifdef DEBUG
        !          1784:        printf("allocating lunsw at offset %d\n", sc->ram_free);
        !          1785: #endif
        !          1786:        if (sc->features & SF_CHIP_RAM) {
        !          1787:                bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh,
        !          1788:                    sc->ram_free * 4, lun_switch,
        !          1789:                    sizeof(lun_switch) / sizeof(lun_switch[0]));
        !          1790:                bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
        !          1791:                    (sc->ram_free + E_abs_lunsw_return_Used[0]) * 4,
        !          1792:                    sc->sc_scriptaddr + Ent_lunsw_return);
        !          1793:        } else {
        !          1794:                for (i = 0; i < sizeof(lun_switch) / sizeof(lun_switch[0]);
        !          1795:                    i++)
        !          1796:                        sc->sc_script[sc->ram_free + i] =
        !          1797:                            htole32(lun_switch[i]);
        !          1798:                sc->sc_script[sc->ram_free + E_abs_lunsw_return_Used[0]] =
        !          1799:                    htole32(sc->sc_scriptaddr + Ent_lunsw_return);
        !          1800:        }
        !          1801:        lunsw->lunsw_off = sc->ram_free;
        !          1802:        sc->ram_free += sizeof(lun_switch) / sizeof(lun_switch[0]);
        !          1803:        if (sc->ram_free > 1024)
        !          1804:                printf("%s: ram_free (%d) > 1024\n", sc->sc_dev.dv_xname,
        !          1805:                    sc->ram_free);
        !          1806:        return lunsw;
        !          1807: }
        !          1808:
        !          1809: void
        !          1810: siop_add_reselsw(sc, target)
        !          1811:        struct siop_softc *sc;
        !          1812:        int target;
        !          1813: {
        !          1814:        int i;
        !          1815:        struct siop_lun *siop_lun;
        !          1816:        /* add an entry to resel switch */
        !          1817:        for (i = 0; i < 15; i++) {
        !          1818:                sc->targets[target]->reseloff = Ent_resel_targ0 / 4 + i * 2;
        !          1819:                if ((siop_script_read(sc, sc->targets[target]->reseloff) & 0xff)
        !          1820:                    == 0xff) { /* it's free */
        !          1821: #ifdef DEBUG
        !          1822:                        printf("siop: target %d slot %d offset %d\n",
        !          1823:                            target, i, sc->targets[target]->reseloff);
        !          1824: #endif
        !          1825:                        /* JUMP abs_foo, IF target | 0x80; */
        !          1826:                        siop_script_write(sc, sc->targets[target]->reseloff,
        !          1827:                            0x800c0080 | target);
        !          1828:                        siop_script_write(sc, sc->targets[target]->reseloff + 1,
        !          1829:                            sc->sc_scriptaddr +
        !          1830:                            sc->targets[target]->lunsw->lunsw_off * 4);
        !          1831:                        break;
        !          1832:                }
        !          1833:        }
        !          1834:        if (i == 15) /* no free slot, shouldn't happen */
        !          1835:                panic("siop: resel switch full");
        !          1836:
        !          1837:        for (i = 0; i < 8; i++) {
        !          1838:                siop_lun = &(sc->targets[target]->siop_lun[i]);
        !          1839:                siop_lun->reseloff =
        !          1840:                    sc->targets[target]->lunsw->lunsw_off +
        !          1841:                        (Ent_resel_lun0 / 4) + (i * 2);
        !          1842:        }
        !          1843:        siop_update_scntl3(sc, sc->targets[target]);
        !          1844: }
        !          1845:
        !          1846: void
        !          1847: siop_update_scntl3(sc, siop_target)
        !          1848:        struct siop_softc *sc;
        !          1849:        struct siop_target *siop_target;
        !          1850: {
        !          1851:        /* MOVE target->id >> 24 TO SCNTL3 */
        !          1852:        siop_script_write(sc,
        !          1853:            siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4),
        !          1854:            0x78030000 | ((siop_target->id >> 16) & 0x0000ff00));
        !          1855:        /* MOVE target->id >> 8 TO SXFER */
        !          1856:        siop_script_write(sc,
        !          1857:            siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2,
        !          1858:            0x78050000 | (siop_target->id & 0x0000ff00));
        !          1859: }
        !          1860:
1.2       bouyer   1861: #ifdef SIOP_STATS
                   1862: void
                   1863: siop_printstats()
                   1864: {
                   1865:        printf("siop_stat_intr %d\n", siop_stat_intr);
                   1866:        printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
                   1867:        printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
                   1868:        printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
                   1869:        printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
                   1870: }
                   1871: #endif

CVSweb <webmaster@jp.NetBSD.org>