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

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

1.1       nbrk        1: /*     $OpenBSD: siop_common.c,v 1.30 2007/08/05 19:05:09 kettenis Exp $ */
                      2: /*     $NetBSD: siop_common.c,v 1.37 2005/02/27 00:27:02 perry Exp $   */
                      3:
                      4: /*
                      5:  * Copyright (c) 2000, 2002 Manuel Bouyer.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by Manuel Bouyer.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  *
                     32:  */
                     33:
                     34: /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
                     35:
                     36: #include <sys/param.h>
                     37: #include <sys/systm.h>
                     38: #include <sys/device.h>
                     39: #include <sys/malloc.h>
                     40: #include <sys/buf.h>
                     41: #include <sys/kernel.h>
                     42: #include <sys/scsiio.h>
                     43:
                     44: #include <machine/endian.h>
                     45: #include <machine/bus.h>
                     46:
                     47: #include <scsi/scsi_all.h>
                     48: #include <scsi/scsi_message.h>
                     49: #include <scsi/scsiconf.h>
                     50:
                     51: #define SIOP_NEEDS_PERIOD_TABLES
                     52: #include <dev/ic/siopreg.h>
                     53: #include <dev/ic/siopvar_common.h>
                     54: #include <dev/ic/siopvar.h>
                     55:
                     56: #undef DEBUG
                     57: #undef DEBUG_DR
                     58: #undef DEBUG_NEG
                     59:
                     60: int
                     61: siop_common_attach(sc)
                     62:        struct siop_common_softc *sc;
                     63: {
                     64:        int error, i;
                     65:        bus_dma_segment_t seg;
                     66:        int rseg;
                     67:
                     68:        /*
                     69:         * Allocate DMA-safe memory for the script and map it.
                     70:         */
                     71:        if ((sc->features & SF_CHIP_RAM) == 0) {
                     72:                error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE,
                     73:                    PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
                     74:                if (error) {
                     75:                        printf("%s: unable to allocate script DMA memory, "
                     76:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                     77:                        return error;
                     78:                }
                     79:                error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE,
                     80:                    (caddr_t *)&sc->sc_script,
                     81:                    BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
                     82:                if (error) {
                     83:                        printf("%s: unable to map script DMA memory, "
                     84:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                     85:                        return error;
                     86:                }
                     87:                error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
                     88:                    PAGE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
                     89:                if (error) {
                     90:                        printf("%s: unable to create script DMA map, "
                     91:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                     92:                        return error;
                     93:                }
                     94:                error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
                     95:                    sc->sc_script, PAGE_SIZE, NULL, BUS_DMA_NOWAIT);
                     96:                if (error) {
                     97:                        printf("%s: unable to load script DMA map, "
                     98:                            "error = %d\n", sc->sc_dev.dv_xname, error);
                     99:                        return error;
                    100:                }
                    101:                sc->sc_scriptaddr =
                    102:                    sc->sc_scriptdma->dm_segs[0].ds_addr;
                    103:                sc->ram_size = PAGE_SIZE;
                    104:        }
                    105:
                    106:        /*
                    107:         * sc->sc_link is the template for all device sc_link's
                    108:         * for devices attached to this adapter. It is passed to
                    109:         * the upper layers in config_found().
                    110:         */
                    111:        sc->sc_link.adapter_softc = sc;
                    112:        sc->sc_link.adapter_buswidth =
                    113:            (sc->features & SF_BUS_WIDE) ? 16 : 8;
                    114:        sc->sc_link.adapter_target =
                    115:            bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCID);
                    116:        if (sc->sc_link.adapter_target == 0 ||
                    117:            sc->sc_link.adapter_target >=
                    118:            sc->sc_link.adapter_buswidth)
                    119:                sc->sc_link.adapter_target = SIOP_DEFAULT_TARGET;
                    120:
                    121:        for (i = 0; i < 16; i++)
                    122:                sc->targets[i] = NULL;
                    123:
                    124:        /* find min/max sync period for this chip */
                    125:        sc->st_maxsync = 0;
                    126:        sc->dt_maxsync = 0;
                    127:        sc->st_minsync = 255;
                    128:        sc->dt_minsync = 255;
                    129:        for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
                    130:                if (sc->clock_period != scf_period[i].clock)
                    131:                        continue;
                    132:                if (sc->st_maxsync < scf_period[i].period)
                    133:                        sc->st_maxsync = scf_period[i].period;
                    134:                if (sc->st_minsync > scf_period[i].period)
                    135:                        sc->st_minsync = scf_period[i].period;
                    136:        }
                    137:        if (sc->st_maxsync == 255 || sc->st_minsync == 0)
                    138:                panic("siop: can't find my sync parameters");
                    139:        for (i = 0; i < sizeof(dt_scf_period) / sizeof(dt_scf_period[0]); i++) {
                    140:                if (sc->clock_period != dt_scf_period[i].clock)
                    141:                        continue;
                    142:                if (sc->dt_maxsync < dt_scf_period[i].period)
                    143:                        sc->dt_maxsync = dt_scf_period[i].period;
                    144:                if (sc->dt_minsync > dt_scf_period[i].period)
                    145:                        sc->dt_minsync = dt_scf_period[i].period;
                    146:        }
                    147:        if (sc->dt_maxsync == 255 || sc->dt_minsync == 0)
                    148:                panic("siop: can't find my sync parameters");
                    149:        return 0;
                    150: }
                    151:
                    152: void
                    153: siop_common_reset(sc)
                    154:        struct siop_common_softc *sc;
                    155: {
                    156:        u_int32_t stest3;
                    157:
                    158:        /* reset the chip */
                    159:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
                    160:        delay(1000);
                    161:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
                    162:
                    163:        /* init registers */
                    164:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
                    165:            SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
                    166:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
                    167:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
                    168:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER, 0);
                    169:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
                    170:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
                    171:            0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
                    172:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
                    173:            0xff & ~(SIEN1_HTH | SIEN1_GEN));
                    174:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, 0);
                    175:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
                    176:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
                    177:            (0xb << STIME0_SEL_SHIFT));
                    178:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
                    179:            sc->sc_link.adapter_target | SCID_RRE);
                    180:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
                    181:            1 << sc->sc_link.adapter_target);
                    182:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL,
                    183:            (sc->features & SF_CHIP_PF) ? DCNTL_COM | DCNTL_PFEN : DCNTL_COM);
                    184:        if (sc->features & SF_CHIP_AAIP)
                    185:                bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    186:                    SIOP_AIPCNTL1, AIPCNTL1_DIS);
                    187:
                    188:        /* enable clock doubler or quadrupler if appropriate */
                    189:        if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
                    190:                stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
                    191:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
                    192:                    STEST1_DBLEN);
                    193:                if (sc->features & SF_CHIP_QUAD) {
                    194:                        /* wait for PPL to lock */
                    195:                        while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    196:                            SIOP_STEST4) & STEST4_LOCK) == 0)
                    197:                                delay(10);
                    198:                } else {
                    199:                        /* data sheet says 20us - more won't hurt */
                    200:                        delay(100);
                    201:                }
                    202:                /* halt scsi clock, select doubler/quad, restart clock */
                    203:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
                    204:                    stest3 | STEST3_HSC);
                    205:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
                    206:                    STEST1_DBLEN | STEST1_DBLSEL);
                    207:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
                    208:        } else {
                    209:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
                    210:        }
                    211:        if (sc->features & SF_CHIP_FIFO)
                    212:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5,
                    213:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST5) |
                    214:                    CTEST5_DFS);
                    215:        if (sc->features & SF_CHIP_LED0) {
                    216:                /* Set GPIO0 as output if software LED control is required */
                    217:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL,
                    218:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_GPCNTL) & 0xfe);
                    219:        }
                    220:        if (sc->features & SF_BUS_ULTRA3) {
                    221:                /* reset SCNTL4 */
                    222:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4, 0);
                    223:        }
                    224:        sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
                    225:            STEST4_MODE_MASK;
                    226:
                    227:        /*
                    228:         * initialise the RAM. Without this we may get scsi gross errors on
                    229:         * the 1010
                    230:         */
                    231:        if (sc->features & SF_CHIP_RAM)
                    232:                bus_space_set_region_4(sc->sc_ramt, sc->sc_ramh,
                    233:                        0, 0, sc->ram_size / 4);
                    234:        sc->sc_reset(sc);
                    235: }
                    236:
                    237: /* prepare tables before sending a cmd */
                    238: void
                    239: siop_setuptables(siop_cmd)
                    240:        struct siop_common_cmd *siop_cmd;
                    241: {
                    242:        int i;
                    243:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    244:        struct scsi_xfer *xs = siop_cmd->xs;
                    245:        int target = xs->sc_link->target;
                    246:        int lun = xs->sc_link->lun;
                    247:        int msgoffset = 1;
                    248:        int *targ_flags = &sc->targets[target]->flags;
                    249:        int quirks;
                    250:
                    251:        siop_cmd->siop_tables->id = siop_htoc32(sc, sc->targets[target]->id);
                    252:        memset(siop_cmd->siop_tables->msg_out, 0,
                    253:            sizeof(siop_cmd->siop_tables->msg_out));
                    254:        /* request sense doesn't disconnect */
                    255:        if (siop_cmd->status == CMDST_SENSE)
                    256:                siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
                    257:        else if ((sc->features & SF_CHIP_GEBUG) &&
                    258:            (sc->targets[target]->flags & TARF_ISWIDE) == 0)
                    259:                /*
                    260:                 * 1010 bug: it seems that the 1010 has problems with reselect
                    261:                 * when not in wide mode (generate false SCSI gross error).
                    262:                 * The FreeBSD sym driver has comments about it but their
                    263:                 * workaround (disable SCSI gross error reporting) doesn't
                    264:                 * work with my adapter. So disable disconnect when not
                    265:                 * wide.
                    266:                 */
                    267:                siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 0);
                    268:        else
                    269:                siop_cmd->siop_tables->msg_out[0] = MSG_IDENTIFY(lun, 1);
                    270:        siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, msgoffset);
                    271:        if (sc->targets[target]->status == TARST_ASYNC) {
                    272:                *targ_flags &= TARF_DT; /* Save TARF_DT 'cuz we don't set it here */
                    273:                quirks = xs->sc_link->quirks;
                    274:
                    275:                if ((quirks & SDEV_NOTAGS) == 0)
                    276:                        *targ_flags |= TARF_TAG;
                    277:                if (((quirks & SDEV_NOWIDE) == 0) &&
                    278:                    (sc->features & SF_BUS_WIDE))
                    279:                        *targ_flags |= TARF_WIDE;
                    280:                if ((quirks & SDEV_NOSYNC) == 0)
                    281:                        *targ_flags |= TARF_SYNC;
                    282:
                    283:                if ((sc->features & SF_CHIP_GEBUG) &&
                    284:                    (*targ_flags & TARF_WIDE) == 0)
                    285:                        /*
                    286:                         * 1010 workaround: can't do disconnect if not wide,
                    287:                         * so can't do tag
                    288:                         */
                    289:                        *targ_flags &= ~TARF_TAG;
                    290:
                    291:                /* Safe to call siop_add_dev() multiple times */
                    292:                siop_add_dev((struct siop_softc *)sc, target, lun);
                    293:
                    294:                if ((*targ_flags & TARF_DT) &&
                    295:                    (sc->mode == STEST4_MODE_LVD)) {
                    296:                        sc->targets[target]->status = TARST_PPR_NEG;
                    297:                         siop_ppr_msg(siop_cmd, msgoffset, sc->dt_minsync,
                    298:                            sc->maxoff);
                    299:                } else if (*targ_flags & TARF_WIDE) {
                    300:                        sc->targets[target]->status = TARST_WIDE_NEG;
                    301:                        siop_wdtr_msg(siop_cmd, msgoffset,
                    302:                            MSG_EXT_WDTR_BUS_16_BIT);
                    303:                } else if (*targ_flags & TARF_SYNC) {
                    304:                        sc->targets[target]->status = TARST_SYNC_NEG;
                    305:                        siop_sdtr_msg(siop_cmd, msgoffset, sc->st_minsync,
                    306:                        (sc->maxoff > 31) ? 31 :  sc->maxoff);
                    307:                } else {
                    308:                        sc->targets[target]->status = TARST_OK;
                    309:                        siop_update_xfer_mode(sc, target);
                    310:                }
                    311:        } else if (sc->targets[target]->status == TARST_OK &&
                    312:            (*targ_flags & TARF_TAG) &&
                    313:            siop_cmd->status != CMDST_SENSE) {
                    314:                siop_cmd->flags |= CMDFL_TAG;
                    315:        }
                    316:        siop_cmd->siop_tables->status =
                    317:            siop_htoc32(sc, SCSI_SIOP_NOSTATUS); /* set invalid status */
                    318:
                    319:        if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) ||
                    320:            siop_cmd->status == CMDST_SENSE) {
                    321:                bzero(siop_cmd->siop_tables->data,
                    322:                    sizeof(siop_cmd->siop_tables->data));
                    323:                for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
                    324:                        siop_cmd->siop_tables->data[i].count =
                    325:                            siop_htoc32(sc,
                    326:                                siop_cmd->dmamap_data->dm_segs[i].ds_len);
                    327:                        siop_cmd->siop_tables->data[i].addr =
                    328:                            siop_htoc32(sc,
                    329:                                siop_cmd->dmamap_data->dm_segs[i].ds_addr);
                    330:                }
                    331:        }
                    332: }
                    333:
                    334: int
                    335: siop_wdtr_neg(siop_cmd)
                    336:        struct siop_common_cmd *siop_cmd;
                    337: {
                    338:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    339:        struct siop_common_target *siop_target = siop_cmd->siop_target;
                    340:        int target = siop_cmd->xs->sc_link->target;
                    341:        struct siop_common_xfer *tables = siop_cmd->siop_tables;
                    342:
                    343:        if (siop_target->status == TARST_WIDE_NEG) {
                    344:                /* we initiated wide negotiation */
                    345:                switch (tables->msg_in[3]) {
                    346:                case MSG_EXT_WDTR_BUS_8_BIT:
                    347:                        siop_target->flags &= ~TARF_ISWIDE;
                    348:                        sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
                    349:                        break;
                    350:                case MSG_EXT_WDTR_BUS_16_BIT:
                    351:                        if (siop_target->flags & TARF_WIDE) {
                    352:                                siop_target->flags |= TARF_ISWIDE;
                    353:                                sc->targets[target]->id |= (SCNTL3_EWS << 24);
                    354:                                break;
                    355:                        }
                    356:                /* FALLTHROUGH */
                    357:                default:
                    358:                        /*
                    359:                         * hum, we got more than what we can handle, shouldn't
                    360:                         * happen. Reject, and stay async
                    361:                         */
                    362:                        siop_target->flags &= ~TARF_ISWIDE;
                    363:                        siop_target->status = TARST_OK;
                    364:                        siop_target->offset = siop_target->period = 0;
                    365:                        siop_update_xfer_mode(sc, target);
                    366:                        printf("%s: rejecting invalid wide negotiation from "
                    367:                            "target %d (%d)\n", sc->sc_dev.dv_xname, target,
                    368:                            tables->msg_in[3]);
                    369:                        tables->t_msgout.count = siop_htoc32(sc, 1);
                    370:                        tables->msg_out[0] = MSG_MESSAGE_REJECT;
                    371:                        return SIOP_NEG_MSGOUT;
                    372:                }
                    373:                tables->id = siop_htoc32(sc, sc->targets[target]->id);
                    374:                bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    375:                    SIOP_SCNTL3,
                    376:                    (sc->targets[target]->id >> 24) & 0xff);
                    377:                /* we now need to do sync */
                    378:                if (siop_target->flags & TARF_SYNC) {
                    379:                        siop_target->status = TARST_SYNC_NEG;
                    380:                        siop_sdtr_msg(siop_cmd, 0, sc->st_minsync,
                    381:                            (sc->maxoff > 31) ? 31 : sc->maxoff);
                    382:                        return SIOP_NEG_MSGOUT;
                    383:                } else {
                    384:                        siop_target->status = TARST_OK;
                    385:                        siop_update_xfer_mode(sc, target);
                    386:                        return SIOP_NEG_ACK;
                    387:                }
                    388:        } else {
                    389:                /* target initiated wide negotiation */
                    390:                if (tables->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
                    391:                    && (siop_target->flags & TARF_WIDE)) {
                    392:                        siop_target->flags |= TARF_ISWIDE;
                    393:                        sc->targets[target]->id |= SCNTL3_EWS << 24;
                    394:                } else {
                    395:                        siop_target->flags &= ~TARF_ISWIDE;
                    396:                        sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
                    397:                }
                    398:                tables->id = siop_htoc32(sc, sc->targets[target]->id);
                    399:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
                    400:                    (sc->targets[target]->id >> 24) & 0xff);
                    401:                /*
                    402:                 * we did reset wide parameters, so fall back to async,
                    403:                 * but don't schedule a sync neg, target should initiate it
                    404:                 */
                    405:                siop_target->status = TARST_OK;
                    406:                siop_target->offset = siop_target->period = 0;
                    407:                siop_update_xfer_mode(sc, target);
                    408:                siop_wdtr_msg(siop_cmd, 0, (siop_target->flags & TARF_ISWIDE) ?
                    409:                    MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT);
                    410:                return SIOP_NEG_MSGOUT;
                    411:        }
                    412: }
                    413:
                    414: int
                    415: siop_ppr_neg(siop_cmd)
                    416:        struct siop_common_cmd *siop_cmd;
                    417: {
                    418:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    419:        struct siop_common_target *siop_target = siop_cmd->siop_target;
                    420:        int target = siop_cmd->xs->sc_link->target;
                    421:        struct siop_common_xfer *tables = siop_cmd->siop_tables;
                    422:        int sync, offset, options, scf = 0;
                    423:        int i;
                    424:
                    425: #ifdef DEBUG_NEG
                    426:        printf("%s: answer on ppr negotiation:", sc->sc_dev.dv_xname);
                    427:        for (i = 0; i < 8; i++)
                    428:                printf(" 0x%x", tables->msg_in[i]);
                    429:        printf("\n");
                    430: #endif
                    431:
                    432:        if (siop_target->status == TARST_PPR_NEG) {
                    433:                /* we initiated PPR negotiation */
                    434:                sync = tables->msg_in[3];
                    435:                offset = tables->msg_in[5];
                    436:                options = tables->msg_in[7];
                    437:                if (options != MSG_EXT_PPR_PROT_DT) {
                    438:                        /* should't happen */
                    439:                        printf("%s: ppr negotiation for target %d: "
                    440:                            "no DT option\n", sc->sc_dev.dv_xname, target);
                    441:                        siop_target->status = TARST_ASYNC;
                    442:                        siop_target->flags &= ~(TARF_DT | TARF_ISDT);
                    443:                        siop_target->offset = 0;
                    444:                        siop_target->period = 0;
                    445:                        goto reject;
                    446:                }
                    447:
                    448:                if (offset > sc->maxoff || sync < sc->dt_minsync ||
                    449:                    sync > sc->dt_maxsync) {
                    450:                        printf("%s: ppr negotiation for target %d: "
                    451:                            "offset (%d) or sync (%d) out of range\n",
                    452:                            sc->sc_dev.dv_xname, target, offset, sync);
                    453:                        /* should not happen */
                    454:                        siop_target->status = TARST_ASYNC;
                    455:                        siop_target->flags &= ~(TARF_DT | TARF_ISDT);
                    456:                        siop_target->offset = 0;
                    457:                        siop_target->period = 0;
                    458:                        goto reject;
                    459:                } else {
                    460:                        for (i = 0; i <
                    461:                            sizeof(dt_scf_period) / sizeof(dt_scf_period[0]);
                    462:                            i++) {
                    463:                                if (sc->clock_period != dt_scf_period[i].clock)
                    464:                                        continue;
                    465:                                if (dt_scf_period[i].period == sync) {
                    466:                                        /* ok, found it. we now are sync. */
                    467:                                        siop_target->offset = offset;
                    468:                                        siop_target->period = sync;
                    469:                                        scf = dt_scf_period[i].scf;
                    470:                                        siop_target->flags |= TARF_ISDT;
                    471:                                }
                    472:                        }
                    473:                        if ((siop_target->flags & TARF_ISDT) == 0) {
                    474:                                printf("%s: ppr negotiation for target %d: "
                    475:                                    "sync (%d) incompatible with adapter\n",
                    476:                                    sc->sc_dev.dv_xname, target, sync);
                    477:                                /*
                    478:                                 * we didn't find it in our table, do async
                    479:                                 * send reject msg, start SDTR/WDTR neg
                    480:                                 */
                    481:                                siop_target->status = TARST_ASYNC;
                    482:                                siop_target->flags &= ~(TARF_DT | TARF_ISDT);
                    483:                                siop_target->offset = 0;
                    484:                                siop_target->period = 0;
                    485:                                goto reject;
                    486:                        }
                    487:                }
                    488:                if (tables->msg_in[6] != 1) {
                    489:                        printf("%s: ppr negotiation for target %d: "
                    490:                            "transfer width (%d) incompatible with dt\n",
                    491:                            sc->sc_dev.dv_xname, target, tables->msg_in[6]);
                    492:                        /* DT mode can only be done with wide transfers */
                    493:                        siop_target->status = TARST_ASYNC;
                    494:                        siop_target->flags &= ~(TARF_DT | TARF_ISDT);
                    495:                        siop_target->offset = 0;
                    496:                        siop_target->period = 0;
                    497:                        goto reject;
                    498:                }
                    499:                siop_target->flags |= TARF_ISWIDE;
                    500:                sc->targets[target]->id |= (SCNTL3_EWS << 24);
                    501:                sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
                    502:                sc->targets[target]->id |= scf << (24 + SCNTL3_SCF_SHIFT);
                    503:                sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
                    504:                sc->targets[target]->id |=
                    505:                    (siop_target->offset & SXFER_MO_MASK) << 8;
                    506:                sc->targets[target]->id &= ~0xff;
                    507:                sc->targets[target]->id |= SCNTL4_U3EN;
                    508:                siop_target->status = TARST_OK;
                    509:                siop_update_xfer_mode(sc, target);
                    510:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
                    511:                    (sc->targets[target]->id >> 24) & 0xff);
                    512:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
                    513:                    (sc->targets[target]->id >> 8) & 0xff);
                    514:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL4,
                    515:                    sc->targets[target]->id & 0xff);
                    516:                return SIOP_NEG_ACK;
                    517:        } else {
                    518:                /* target initiated PPR negotiation, shouldn't happen */
                    519:                printf("%s: rejecting invalid PPR negotiation from "
                    520:                    "target %d\n", sc->sc_dev.dv_xname, target);
                    521: reject:
                    522:                tables->t_msgout.count = siop_htoc32(sc, 1);
                    523:                tables->msg_out[0] = MSG_MESSAGE_REJECT;
                    524:                return SIOP_NEG_MSGOUT;
                    525:        }
                    526: }
                    527:
                    528: int
                    529: siop_sdtr_neg(siop_cmd)
                    530:        struct siop_common_cmd *siop_cmd;
                    531: {
                    532:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    533:        struct siop_common_target *siop_target = siop_cmd->siop_target;
                    534:        int target = siop_cmd->xs->sc_link->target;
                    535:        int sync, maxoffset, offset, i;
                    536:        int send_msgout = 0;
                    537:        struct siop_common_xfer *tables = siop_cmd->siop_tables;
                    538:
                    539:        /* limit to Ultra/2 parameters, need PPR for Ultra/3 */
                    540:        maxoffset = (sc->maxoff > 31) ? 31 : sc->maxoff;
                    541:
                    542:        sync = tables->msg_in[3];
                    543:        offset = tables->msg_in[4];
                    544:
                    545:        if (siop_target->status == TARST_SYNC_NEG) {
                    546:                /* we initiated sync negotiation */
                    547:                siop_target->status = TARST_OK;
                    548: #ifdef DEBUG
                    549:                printf("sdtr: sync %d offset %d\n", sync, offset);
                    550: #endif
                    551:                if (offset > maxoffset || sync < sc->st_minsync ||
                    552:                        sync > sc->st_maxsync)
                    553:                        goto reject;
                    554:                for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
                    555:                    i++) {
                    556:                        if (sc->clock_period != scf_period[i].clock)
                    557:                                continue;
                    558:                        if (scf_period[i].period == sync) {
                    559:                                /* ok, found it. we now are sync. */
                    560:                                siop_target->offset = offset;
                    561:                                siop_target->period = sync;
                    562:                                sc->targets[target]->id &=
                    563:                                    ~(SCNTL3_SCF_MASK << 24);
                    564:                                sc->targets[target]->id |= scf_period[i].scf
                    565:                                    << (24 + SCNTL3_SCF_SHIFT);
                    566:                                if (sync < 25 && /* Ultra */
                    567:                                    (sc->features & SF_BUS_ULTRA3) == 0)
                    568:                                        sc->targets[target]->id |=
                    569:                                            SCNTL3_ULTRA << 24;
                    570:                                else
                    571:                                        sc->targets[target]->id &=
                    572:                                            ~(SCNTL3_ULTRA << 24);
                    573:                                sc->targets[target]->id &=
                    574:                                    ~(SXFER_MO_MASK << 8);
                    575:                                sc->targets[target]->id |=
                    576:                                    (offset & SXFER_MO_MASK) << 8;
                    577:                                sc->targets[target]->id &= ~0xff; /* scntl4 */
                    578:                                goto end;
                    579:                        }
                    580:                }
                    581:                /*
                    582:                 * we didn't find it in our table, do async and send reject
                    583:                 * msg
                    584:                 */
                    585: reject:
                    586:                send_msgout = 1;
                    587:                tables->t_msgout.count = siop_htoc32(sc, 1);
                    588:                tables->msg_out[0] = MSG_MESSAGE_REJECT;
                    589:                sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
                    590:                sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
                    591:                sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
                    592:                sc->targets[target]->id &= ~0xff; /* scntl4 */
                    593:                siop_target->offset = siop_target->period = 0;
                    594:        } else { /* target initiated sync neg */
                    595: #ifdef DEBUG
                    596:                printf("sdtr (target): sync %d offset %d\n", sync, offset);
                    597: #endif
                    598:                if (offset == 0 || sync > sc->st_maxsync) { /* async */
                    599:                        goto async;
                    600:                }
                    601:                if (offset > maxoffset)
                    602:                        offset = maxoffset;
                    603:                if (sync < sc->st_minsync)
                    604:                        sync = sc->st_minsync;
                    605:                /* look for sync period */
                    606:                for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
                    607:                    i++) {
                    608:                        if (sc->clock_period != scf_period[i].clock)
                    609:                                continue;
                    610:                        if (scf_period[i].period == sync) {
                    611:                                /* ok, found it. we now are sync. */
                    612:                                siop_target->offset = offset;
                    613:                                siop_target->period = sync;
                    614:                                sc->targets[target]->id &=
                    615:                                    ~(SCNTL3_SCF_MASK << 24);
                    616:                                sc->targets[target]->id |= scf_period[i].scf
                    617:                                    << (24 + SCNTL3_SCF_SHIFT);
                    618:                                if (sync < 25 && /* Ultra */
                    619:                                    (sc->features & SF_BUS_ULTRA3) == 0)
                    620:                                        sc->targets[target]->id |=
                    621:                                            SCNTL3_ULTRA << 24;
                    622:                                else
                    623:                                        sc->targets[target]->id &=
                    624:                                            ~(SCNTL3_ULTRA << 24);
                    625:                                sc->targets[target]->id &=
                    626:                                    ~(SXFER_MO_MASK << 8);
                    627:                                sc->targets[target]->id |=
                    628:                                    (offset & SXFER_MO_MASK) << 8;
                    629:                                sc->targets[target]->id &= ~0xff; /* scntl4 */
                    630:                                siop_sdtr_msg(siop_cmd, 0, sync, offset);
                    631:                                send_msgout = 1;
                    632:                                goto end;
                    633:                        }
                    634:                }
                    635: async:
                    636:                siop_target->offset = siop_target->period = 0;
                    637:                sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
                    638:                sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
                    639:                sc->targets[target]->id &= ~(SXFER_MO_MASK << 8);
                    640:                sc->targets[target]->id &= ~0xff; /* scntl4 */
                    641:                siop_sdtr_msg(siop_cmd, 0, 0, 0);
                    642:                send_msgout = 1;
                    643:        }
                    644: end:
                    645:        if (siop_target->status == TARST_OK)
                    646:                siop_update_xfer_mode(sc, target);
                    647: #ifdef DEBUG
                    648:        printf("id now 0x%x\n", sc->targets[target]->id);
                    649: #endif
                    650:        tables->id = siop_htoc32(sc, sc->targets[target]->id);
                    651:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
                    652:            (sc->targets[target]->id >> 24) & 0xff);
                    653:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SXFER,
                    654:            (sc->targets[target]->id >> 8) & 0xff);
                    655:        if (send_msgout) {
                    656:                return SIOP_NEG_MSGOUT;
                    657:        } else {
                    658:                return SIOP_NEG_ACK;
                    659:        }
                    660: }
                    661:
                    662: void
                    663: siop_sdtr_msg(siop_cmd, offset, ssync, soff)
                    664:        struct siop_common_cmd *siop_cmd;
                    665:        int offset;
                    666:        int ssync, soff;
                    667: {
                    668:        siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
                    669:        siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_SDTR_LEN;
                    670:        siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_SDTR;
                    671:        siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
                    672:        siop_cmd->siop_tables->msg_out[offset + 4] = soff;
                    673:        siop_cmd->siop_tables->t_msgout.count =
                    674:            siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_SDTR_LEN + 2);
                    675: }
                    676:
                    677: void
                    678: siop_wdtr_msg(siop_cmd, offset, wide)
                    679:        struct siop_common_cmd *siop_cmd;
                    680:        int offset;
                    681:        int wide;
                    682: {
                    683:        siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
                    684:        siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_WDTR_LEN;
                    685:        siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_WDTR;
                    686:        siop_cmd->siop_tables->msg_out[offset + 3] = wide;
                    687:        siop_cmd->siop_tables->t_msgout.count =
                    688:            siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_WDTR_LEN + 2);
                    689: }
                    690:
                    691: void
                    692: siop_ppr_msg(siop_cmd, offset, ssync, soff)
                    693:        struct siop_common_cmd *siop_cmd;
                    694:        int offset;
                    695:        int ssync, soff;
                    696: {
                    697:        siop_cmd->siop_tables->msg_out[offset + 0] = MSG_EXTENDED;
                    698:        siop_cmd->siop_tables->msg_out[offset + 1] = MSG_EXT_PPR_LEN;
                    699:        siop_cmd->siop_tables->msg_out[offset + 2] = MSG_EXT_PPR;
                    700:        siop_cmd->siop_tables->msg_out[offset + 3] = ssync;
                    701:        siop_cmd->siop_tables->msg_out[offset + 4] = 0; /* reserved */
                    702:        siop_cmd->siop_tables->msg_out[offset + 5] = soff;
                    703:        siop_cmd->siop_tables->msg_out[offset + 6] = 1; /* wide */
                    704:        siop_cmd->siop_tables->msg_out[offset + 7] = MSG_EXT_PPR_PROT_DT;
                    705:        siop_cmd->siop_tables->t_msgout.count =
                    706:            siop_htoc32(siop_cmd->siop_sc, offset + MSG_EXT_PPR_LEN + 2);
                    707: }
                    708:
                    709: void
                    710: siop_minphys(bp)
                    711:        struct buf *bp;
                    712: {
                    713:        if (bp->b_bcount > SIOP_MAXFER)
                    714:                bp->b_bcount = SIOP_MAXFER;
                    715:
                    716:        minphys(bp);
                    717: }
                    718:
                    719: void
                    720: siop_ma(siop_cmd)
                    721:        struct siop_common_cmd *siop_cmd;
                    722: {
                    723:        int offset, dbc, sstat;
                    724:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    725:        scr_table_t *table; /* table with partial xfer */
                    726:
                    727:        /*
                    728:         * compute how much of the current table didn't get handled when
                    729:         * a phase mismatch occurs
                    730:         */
                    731:        if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
                    732:            == 0)
                    733:            return; /* no valid data transfer */
                    734:
                    735:        offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
                    736:        if (offset >= SIOP_NSG) {
                    737:                printf("%s: bad offset in siop_sdp (%d)\n",
                    738:                    sc->sc_dev.dv_xname, offset);
                    739:                return;
                    740:        }
                    741:        table = &siop_cmd->siop_tables->data[offset];
                    742: #ifdef DEBUG_DR
                    743:        printf("siop_ma: offset %d count=%d addr=0x%x ", offset,
                    744:            table->count, table->addr);
                    745: #endif
                    746:        dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
                    747:        if (siop_cmd->xs->flags & SCSI_DATA_OUT) {
                    748:                if (sc->features & SF_CHIP_DFBC) {
                    749:                        dbc +=
                    750:                            bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_DFBC);
                    751:                } else {
                    752:                        /* need to account stale data in FIFO */
                    753:                        int dfifo =
                    754:                            bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO);
                    755:                        if (sc->features & SF_CHIP_FIFO) {
                    756:                                dfifo |= (bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    757:                                    SIOP_CTEST5) & CTEST5_BOMASK) << 8;
                    758:                                dbc += (dfifo - (dbc & 0x3ff)) & 0x3ff;
                    759:                        } else {
                    760:                                dbc += (dfifo - (dbc & 0x7f)) & 0x7f;
                    761:                        }
                    762:                }
                    763:                sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
                    764:                if (sstat & SSTAT0_OLF)
                    765:                        dbc++;
                    766:                if ((sstat & SSTAT0_ORF) && (sc->features & SF_CHIP_DFBC) == 0)
                    767:                        dbc++;
                    768:                if (siop_cmd->siop_target->flags & TARF_ISWIDE) {
                    769:                        sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    770:                            SIOP_SSTAT2);
                    771:                        if (sstat & SSTAT2_OLF1)
                    772:                                dbc++;
                    773:                        if ((sstat & SSTAT2_ORF1) &&
                    774:                            (sc->features & SF_CHIP_DFBC) == 0)
                    775:                                dbc++;
                    776:                }
                    777:                /* clear the FIFO */
                    778:                bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
                    779:                    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
                    780:                    CTEST3_CLF);
                    781:        }
                    782:        siop_cmd->flags |= CMDFL_RESID;
                    783:        siop_cmd->resid = dbc;
                    784: }
                    785:
                    786: void
                    787: siop_sdp(siop_cmd, offset)
                    788:        struct siop_common_cmd *siop_cmd;
                    789:        int offset;
                    790: {
                    791:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    792:        scr_table_t *table;
                    793:
                    794:        if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
                    795:            == 0)
                    796:            return; /* no data pointers to save */
                    797:
                    798:        /*
                    799:         * offset == SIOP_NSG may be a valid condition if we get a Save data
                    800:         * pointer when the xfer is done. Just ignore the Save data pointer
                    801:         * in this case
                    802:         */
                    803:        if (offset == SIOP_NSG)
                    804:                return;
                    805: #ifdef DIAGNOSTIC
                    806:        if (offset > SIOP_NSG) {
                    807:                sc_print_addr(siop_cmd->xs->sc_link);
                    808:                printf(": offset %d > %d\n", offset, SIOP_NSG);
                    809:                panic("siop_sdp: offset");
                    810:        }
                    811: #endif
                    812:        /*
                    813:         * Save data pointer. We do this by adjusting the tables to point
                    814:         * at the begginning of the data not yet transfered.
                    815:         * offset points to the first table with untransfered data.
                    816:         */
                    817:
                    818:        /*
                    819:         * before doing that we decrease resid from the amount of data which
                    820:         * has been transfered.
                    821:         */
                    822:        siop_update_resid(siop_cmd, offset);
                    823:
                    824:        /*
                    825:         * First let see if we have a resid from a phase mismatch. If so,
                    826:         * we have to adjst the table at offset to remove transfered data.
                    827:         */
                    828:        if (siop_cmd->flags & CMDFL_RESID) {
                    829:                siop_cmd->flags &= ~CMDFL_RESID;
                    830:                table = &siop_cmd->siop_tables->data[offset];
                    831:                /* "cut" already transfered data from this table */
                    832:                table->addr =
                    833:                    siop_htoc32(sc, siop_ctoh32(sc, table->addr) +
                    834:                    siop_ctoh32(sc, table->count) - siop_cmd->resid);
                    835:                table->count = siop_htoc32(sc, siop_cmd->resid);
                    836:        }
                    837:
                    838:        /*
                    839:         * now we can remove entries which have been transfered.
                    840:         * We just move the entries with data left at the beggining of the
                    841:         * tables
                    842:         */
                    843:        bcopy(&siop_cmd->siop_tables->data[offset],
                    844:            &siop_cmd->siop_tables->data[0],
                    845:            (SIOP_NSG - offset) * sizeof(scr_table_t));
                    846: }
                    847:
                    848: void
                    849: siop_update_resid(siop_cmd, offset)
                    850:        struct siop_common_cmd *siop_cmd;
                    851:        int offset;
                    852: {
                    853:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    854:        scr_table_t *table;
                    855:        int i;
                    856:
                    857:        if ((siop_cmd->xs->flags & (SCSI_DATA_OUT | SCSI_DATA_IN))
                    858:            == 0)
                    859:            return; /* no data to transfer */
                    860:
                    861:        /*
                    862:         * update resid. First account for the table entries which have
                    863:         * been fully completed.
                    864:         */
                    865:        for (i = 0; i < offset; i++)
                    866:                siop_cmd->xs->resid -=
                    867:                    siop_ctoh32(sc, siop_cmd->siop_tables->data[i].count);
                    868:        /*
                    869:         * if CMDFL_RESID is set, the last table (pointed by offset) is a
                    870:         * partial transfers. If not, offset points to the entry folloing
                    871:         * the last full transfer.
                    872:         */
                    873:        if (siop_cmd->flags & CMDFL_RESID) {
                    874:                table = &siop_cmd->siop_tables->data[offset];
                    875:                siop_cmd->xs->resid -=
                    876:                    siop_ctoh32(sc, table->count) - siop_cmd->resid;
                    877:        }
                    878: }
                    879:
                    880: int
                    881: siop_iwr(siop_cmd)
                    882:        struct siop_common_cmd *siop_cmd;
                    883: {
                    884:        int offset;
                    885:        scr_table_t *table; /* table with IWR */
                    886:        struct siop_common_softc *sc = siop_cmd->siop_sc;
                    887:        /* handle ignore wide residue messages */
                    888:
                    889:        /* if target isn't wide, reject */
                    890:        if ((siop_cmd->siop_target->flags & TARF_ISWIDE) == 0) {
                    891:                siop_cmd->siop_tables->t_msgout.count = siop_htoc32(sc, 1);
                    892:                siop_cmd->siop_tables->msg_out[0] = MSG_MESSAGE_REJECT;
                    893:                return SIOP_NEG_MSGOUT;
                    894:        }
                    895:        /* get index of current command in table */
                    896:        offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
                    897:        /*
                    898:         * if the current table did complete, we're now pointing at the
                    899:         * next one. Go back one if we didn't see a phase mismatch.
                    900:         */
                    901:        if ((siop_cmd->flags & CMDFL_RESID) == 0)
                    902:                offset--;
                    903:        table = &siop_cmd->siop_tables->data[offset];
                    904:
                    905:        if ((siop_cmd->flags & CMDFL_RESID) == 0) {
                    906:                if (siop_ctoh32(sc, table->count) & 1) {
                    907:                        /* we really got the number of bytes we expected */
                    908:                        return SIOP_NEG_ACK;
                    909:                } else {
                    910:                        /*
                    911:                         * now we really had a short xfer, by one byte.
                    912:                         * handle it just as if we had a phase mistmatch
                    913:                         * (there is a resid of one for this table).
                    914:                         * Update scratcha1 to reflect the fact that
                    915:                         * this xfer isn't complete.
                    916:                         */
                    917:                         siop_cmd->flags |= CMDFL_RESID;
                    918:                         siop_cmd->resid = 1;
                    919:                         bus_space_write_1(sc->sc_rt, sc->sc_rh,
                    920:                             SIOP_SCRATCHA + 1, offset);
                    921:                         return SIOP_NEG_ACK;
                    922:                }
                    923:        } else {
                    924:                /*
                    925:                 * we already have a short xfer for this table; it's
                    926:                 * just one byte less than we though it was
                    927:                 */
                    928:                siop_cmd->resid--;
                    929:                return SIOP_NEG_ACK;
                    930:        }
                    931: }
                    932:
                    933: void
                    934: siop_clearfifo(sc)
                    935:        struct siop_common_softc *sc;
                    936: {
                    937:        int timeout = 0;
                    938:        int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
                    939:
                    940: #ifdef DEBUG_INTR
                    941:        printf("DMA fifo not empty !\n");
                    942: #endif
                    943:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
                    944:            ctest3 | CTEST3_CLF);
                    945:        while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
                    946:            CTEST3_CLF) != 0) {
                    947:                delay(1);
                    948:                if (++timeout > 1000) {
                    949:                        printf("clear fifo failed\n");
                    950:                        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
                    951:                            bus_space_read_1(sc->sc_rt, sc->sc_rh,
                    952:                            SIOP_CTEST3) & ~CTEST3_CLF);
                    953:                        return;
                    954:                }
                    955:        }
                    956: }
                    957:
                    958: int
                    959: siop_modechange(sc)
                    960:        struct siop_common_softc *sc;
                    961: {
                    962:        int retry;
                    963:        int sist0, sist1, stest2;
                    964:        for (retry = 0; retry < 5; retry++) {
                    965:                /*
                    966:                 * datasheet says to wait 100ms and re-read SIST1,
                    967:                 * to check that DIFFSENSE is stable.
                    968:                 * We may delay() 5 times for  100ms at interrupt time;
                    969:                 * hopefully this will not happen often.
                    970:                 */
                    971:                delay(100000);
                    972:                sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
                    973:                sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
                    974:                if (sist1 & SIEN1_SBMC)
                    975:                        continue; /* we got an irq again */
                    976:                sc->mode = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST4) &
                    977:                    STEST4_MODE_MASK;
                    978:                stest2 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2);
                    979:                switch(sc->mode) {
                    980:                case STEST4_MODE_DIF:
                    981:                        printf("%s: switching to differential mode\n",
                    982:                            sc->sc_dev.dv_xname);
                    983:                        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
                    984:                            stest2 | STEST2_DIF);
                    985:                        break;
                    986:                case STEST4_MODE_SE:
                    987:                        printf("%s: switching to single-ended mode\n",
                    988:                            sc->sc_dev.dv_xname);
                    989:                        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
                    990:                            stest2 & ~STEST2_DIF);
                    991:                        break;
                    992:                case STEST4_MODE_LVD:
                    993:                        printf("%s: switching to LVD mode\n",
                    994:                            sc->sc_dev.dv_xname);
                    995:                        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2,
                    996:                            stest2 & ~STEST2_DIF);
                    997:                        break;
                    998:                default:
                    999:                        printf("%s: invalid SCSI mode 0x%x\n",
                   1000:                            sc->sc_dev.dv_xname, sc->mode);
                   1001:                        return 0;
                   1002:                }
                   1003:                return 1;
                   1004:        }
                   1005:        printf("%s: timeout waiting for DIFFSENSE to stabilise\n",
                   1006:            sc->sc_dev.dv_xname);
                   1007:        return 0;
                   1008: }
                   1009:
                   1010: void
                   1011: siop_resetbus(sc)
                   1012:        struct siop_common_softc *sc;
                   1013: {
                   1014:        int scntl1;
                   1015:        scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
                   1016:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
                   1017:            scntl1 | SCNTL1_RST);
                   1018:        /* minimum 25 us, more time won't hurt */
                   1019:        delay(100);
                   1020:        bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
                   1021: }
                   1022:
                   1023: void
                   1024: siop_update_xfer_mode(sc, target)
                   1025:         struct siop_common_softc *sc;
                   1026:         int target;
                   1027: {
                   1028:        struct siop_common_target *siop_target;
                   1029:
                   1030:        siop_target = sc->targets[target];
                   1031:
                   1032:        printf("%s: target %d now using %s%s%d bit ",
                   1033:             sc->sc_dev.dv_xname, target,
                   1034:            (siop_target->flags & TARF_TAG) ? "tagged " : "",
                   1035:            (siop_target->flags & TARF_ISDT) ? "DT " : "",
                   1036:            (siop_target->flags & TARF_ISWIDE) ? 16 : 8);
                   1037:
                   1038:        if (siop_target->offset == 0)
                   1039:                printf("async ");
                   1040:        else {
                   1041:                switch (siop_target->period) {
                   1042:                case 9: /*   12.5ns cycle */
                   1043:                        printf("80.0");
                   1044:                        break;
                   1045:                case 10: /*  25  ns cycle */
                   1046:                        printf("40.0");
                   1047:                        break;
                   1048:                case 12: /*  48  ns cycle */
                   1049:                        printf("20.0");
                   1050:                        break;
                   1051:                case 18: /*  72  ns cycle */
                   1052:                        printf("13.3");
                   1053:                        break;
                   1054:                case 25: /* 100  ns cycle */
                   1055:                        printf("10.0");
                   1056:                        break;
                   1057:                case 37: /* 118  ns cycle */
                   1058:                        printf("6.67");
                   1059:                        break;
                   1060:                case 50: /* 200  ns cycle */
                   1061:                        printf("5.0");
                   1062:                        break;
                   1063:                case 75: /* 300  ns cycle */
                   1064:                        printf("3.33");
                   1065:                        break;
                   1066:                default:
                   1067:                        printf("??");
                   1068:                        break;
                   1069:                }
                   1070:                printf(" MHz %d REQ/ACK offset ", siop_target->offset);
                   1071:        }
                   1072:
                   1073:        printf("xfers\n");
                   1074:
                   1075:        if ((sc->features & SF_CHIP_GEBUG) &&
                   1076:            (siop_target->flags & TARF_ISWIDE) == 0)
                   1077:                /* 1010 workaround: can't do disconnect if not wide, so can't do tag */
                   1078:                siop_target->flags &= ~TARF_TAG;
                   1079: }

CVSweb