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