[BACK]Return to vs.c CVS log [TXT][DIR] Up to [local] / sys / arch / mvme88k / dev

Annotation of sys/arch/mvme88k/dev/vs.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: vs.c,v 1.64 2006/12/01 19:36:09 miod Exp $    */
                      2:
                      3: /*
                      4:  * Copyright (c) 2004, Miodrag Vallat.
                      5:  * Copyright (c) 1999 Steve Murphree, Jr.
                      6:  * Copyright (c) 1990 The Regents of the University of California.
                      7:  * All rights reserved.
                      8:  *
                      9:  * This code is derived from software contributed to Berkeley by
                     10:  * Van Jacobson of Lawrence Berkeley Laboratory.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: /*
                     38:  * MVME328S SCSI adaptor driver
                     39:  */
                     40:
                     41: /* This card lives in D16 space */
                     42: #define        __BUS_SPACE_RESTRICT_D16__
                     43:
                     44: #include <sys/param.h>
                     45: #include <sys/systm.h>
                     46: #include <sys/device.h>
                     47: #include <sys/disklabel.h>
                     48: #include <sys/dkstat.h>
                     49: #include <sys/buf.h>
                     50: #include <sys/malloc.h>
                     51:
                     52: #include <uvm/uvm_extern.h>
                     53:
                     54: #include <scsi/scsi_all.h>
                     55: #include <scsi/scsiconf.h>
                     56:
                     57: #include <machine/autoconf.h>
                     58: #include <machine/cmmu.h>
                     59: #include <machine/cpu.h>
                     60:
                     61: #include <mvme88k/dev/vsreg.h>
                     62: #include <mvme88k/dev/vsvar.h>
                     63: #include <mvme88k/dev/vme.h>
                     64:
                     65: int    vsmatch(struct device *, void *, void *);
                     66: void   vsattach(struct device *, struct device *, void *);
                     67: int    vs_scsicmd(struct scsi_xfer *);
                     68:
                     69: struct scsi_adapter vs_scsiswitch = {
                     70:        vs_scsicmd,
                     71:        minphys,
                     72:        0,                      /* no lun support */
                     73:        0,                      /* no lun support */
                     74: };
                     75:
                     76: struct scsi_device vs_scsidev = {
                     77:        NULL,           /* use default error handler */
                     78:        NULL,           /* do not have a start function */
                     79:        NULL,           /* have no async handler */
                     80:        NULL,           /* Use default done routine */
                     81: };
                     82:
                     83: struct cfattach vs_ca = {
                     84:        sizeof(struct vs_softc), vsmatch, vsattach,
                     85: };
                     86:
                     87: struct cfdriver vs_cd = {
                     88:        NULL, "vs", DV_DULL,
                     89: };
                     90:
                     91: int    do_vspoll(struct vs_softc *, struct scsi_xfer *, int);
                     92: void   thaw_queue(struct vs_softc *, int);
                     93: void   thaw_all_queues(struct vs_softc *);
                     94: M328_SG        vs_alloc_scatter_gather(void);
                     95: M328_SG        vs_build_memory_structure(struct vs_softc *, struct scsi_xfer *,
                     96:            bus_addr_t);
                     97: void   vs_chksense(struct scsi_xfer *);
                     98: void   vs_dealloc_scatter_gather(M328_SG);
                     99: int    vs_eintr(void *);
                    100: bus_addr_t vs_getcqe(struct vs_softc *);
                    101: bus_addr_t vs_getiopb(struct vs_softc *);
                    102: int    vs_initialize(struct vs_softc *);
                    103: int    vs_intr(struct vs_softc *);
                    104: void   vs_link_sg_element(sg_list_element_t *, vaddr_t, int);
                    105: void   vs_link_sg_list(sg_list_element_t *, vaddr_t, int);
                    106: int    vs_nintr(void *);
                    107: int    vs_poll(struct vs_softc *, struct vs_cb *);
                    108: void   vs_print_addr(struct vs_softc *, struct scsi_xfer *);
                    109: struct vs_cb *vs_find_queue(struct scsi_link *, struct vs_softc *);
                    110: void   vs_reset(struct vs_softc *, int);
                    111: void   vs_resync(struct vs_softc *);
                    112: void   vs_scsidone(struct vs_softc *, struct vs_cb *);
                    113:
                    114: static __inline__ void vs_free(struct vs_cb *);
                    115: static __inline__ void vs_clear_return_info(struct vs_softc *);
                    116: static __inline__ paddr_t kvtop(vaddr_t);
                    117:
                    118: int
                    119: vsmatch(struct device *device, void *cf, void *args)
                    120: {
                    121:        struct confargs *ca = args;
                    122:        bus_space_tag_t iot = ca->ca_iot;
                    123:        bus_space_handle_t ioh;
                    124:        int rc;
                    125:
                    126:        if (bus_space_map(iot, ca->ca_paddr, S_SHORTIO, 0, &ioh) != 0)
                    127:                return 0;
                    128:        rc = badaddr((vaddr_t)bus_space_vaddr(iot, ioh), 1);
                    129:        bus_space_unmap(iot, ioh, S_SHORTIO);
                    130:
                    131:        return rc == 0;
                    132: }
                    133:
                    134: void
                    135: vsattach(struct device *parent, struct device *self, void *args)
                    136: {
                    137:        struct vs_softc *sc = (struct vs_softc *)self;
                    138:        struct confargs *ca = args;
                    139:        struct scsi_link *sc_link;
                    140:        struct scsibus_attach_args saa;
                    141:        int evec, bus;
                    142:        int tmp;
                    143:
                    144:        /* get the next available vector for the error interrupt */
                    145:        evec = vme_findvec(ca->ca_vec);
                    146:
                    147:        if (ca->ca_vec < 0 || evec < 0) {
                    148:                printf(": no more interrupts!\n");
                    149:                return;
                    150:        }
                    151:        if (ca->ca_ipl < 0)
                    152:                ca->ca_ipl = IPL_BIO;
                    153:
                    154:        printf(" vec 0x%x: ", evec);
                    155:
                    156:        sc->sc_paddr = ca->ca_paddr;
                    157:        sc->sc_iot = ca->ca_iot;
                    158:        if (bus_space_map(sc->sc_iot, sc->sc_paddr, S_SHORTIO, 0,
                    159:            &sc->sc_ioh) != 0) {
                    160:                printf("can't map registers!\n");
                    161:                return;
                    162:        }
                    163:
                    164:        sc->sc_ipl = ca->ca_ipl;
                    165:        sc->sc_nvec = ca->ca_vec;
                    166:        sc->sc_evec = evec;
                    167:
                    168:        if (vs_initialize(sc))
                    169:                return;
                    170:
                    171:        sc->sc_ih_n.ih_fn = vs_nintr;
                    172:        sc->sc_ih_n.ih_arg = sc;
                    173:        sc->sc_ih_n.ih_wantframe = 0;
                    174:        sc->sc_ih_n.ih_ipl = ca->ca_ipl;
                    175:
                    176:        sc->sc_ih_e.ih_fn = vs_eintr;
                    177:        sc->sc_ih_e.ih_arg = sc;
                    178:        sc->sc_ih_e.ih_wantframe = 0;
                    179:        sc->sc_ih_e.ih_ipl = ca->ca_ipl;
                    180:
                    181:        vmeintr_establish(sc->sc_nvec, &sc->sc_ih_n, self->dv_xname);
                    182:        snprintf(sc->sc_intrname_e, sizeof sc->sc_intrname_e,
                    183:            "%s_err", self->dv_xname);
                    184:        vmeintr_establish(sc->sc_evec, &sc->sc_ih_e, sc->sc_intrname_e);
                    185:
                    186:        printf("SCSI ID");
                    187:
                    188:        for (bus = 0; bus < 2; bus++) {
                    189:                if (sc->sc_id[bus] < 0)
                    190:                        continue;
                    191:
                    192:                sc_link = &sc->sc_link[bus];
                    193:                sc_link->adapter = &vs_scsiswitch;
                    194:                sc_link->adapter_buswidth = 8;
                    195:                sc_link->adapter_softc = sc;
                    196:                sc_link->adapter_target = sc->sc_id[bus];
                    197:                sc_link->device = &vs_scsidev;
                    198: #if 0
                    199:                sc_link->luns = 1;
                    200: #endif
                    201:                sc_link->openings = NUM_IOPB / 8;
                    202:                if (bus != 0)
                    203:                        sc_link->flags = SDEV_2NDBUS;
                    204:
                    205:                printf("%c%d", bus == 0 ? ' ' : '/', sc->sc_id[bus]);
                    206:        }
                    207:
                    208:        printf("\n");
                    209:
                    210:        /*
                    211:         * Attach all scsi units on us, watching for boot device
                    212:         * (see device_register).
                    213:         */
                    214:        tmp = bootpart;
                    215:        if (sc->sc_paddr != bootaddr)
                    216:                bootpart = -1;          /* invalid flag to device_register */
                    217:
                    218:        for (bus = 0; bus < 2; bus++) {
                    219:                if (sc->sc_id[bus] < 0)
                    220:                        continue;
                    221:
                    222:                bzero(&saa, sizeof(saa));
                    223:                saa.saa_sc_link = &sc->sc_link[bus];
                    224:
                    225:                bootbus = bus;
                    226:                config_found(self, &saa, scsiprint);
                    227:        }
                    228:
                    229:        bootpart = tmp;             /* restore old values */
                    230:        bootbus = 0;
                    231: }
                    232:
                    233: void
                    234: vs_print_addr(struct vs_softc *sc, struct scsi_xfer *xs)
                    235: {
                    236:        if (xs == NULL)
                    237:                printf("%s: ", sc->sc_dev.dv_xname);
                    238:        else {
                    239:                sc_print_addr(xs->sc_link);
                    240:
                    241:                /* print bus number too if appropriate */
                    242:                if (sc->sc_id[1] >= 0)
                    243:                        printf("(bus %d) ",
                    244:                            !!(xs->sc_link->flags & SDEV_2NDBUS));
                    245:        }
                    246: }
                    247:
                    248: int
                    249: do_vspoll(struct vs_softc *sc, struct scsi_xfer *xs, int canreset)
                    250: {
                    251:        int to;
                    252:        int crsw, bus;
                    253:
                    254:        if (xs != NULL) {
                    255:                bus = !!(xs->sc_link->flags & SDEV_2NDBUS);
                    256:                to = xs->timeout;
                    257:                if (to == 0)
                    258:                        to = 2000;
                    259:        } else {
                    260:                bus = -1;
                    261:                to = 2000;
                    262:        }
                    263:
                    264:        while (((crsw = CRSW) & (M_CRSW_CRBV | M_CRSW_CC)) == 0) {
                    265:                if (to-- <= 0) {
                    266:                        vs_print_addr(sc, xs);
                    267:                        printf("command timeout, crsw 0x%x\n", crsw);
                    268:
                    269:                        if (canreset) {
                    270:                                vs_reset(sc, bus);
                    271:                                vs_resync(sc);
                    272:                        }
                    273:                        return 1;
                    274:                }
                    275:                delay(1000);
                    276:        }
                    277:        return 0;
                    278: }
                    279:
                    280: int
                    281: vs_poll(struct vs_softc *sc, struct vs_cb *cb)
                    282: {
                    283:        struct scsi_xfer *xs;
                    284:        int s;
                    285:        int rc;
                    286:
                    287:        xs = cb->cb_xs;
                    288:        rc = do_vspoll(sc, xs, 1);
                    289:
                    290:        s = splbio();
                    291:        if (rc != 0) {
                    292:                xs->error = XS_SELTIMEOUT;
                    293:                xs->status = -1;
                    294:                xs->flags |= ITSDONE;
                    295: #if 0
                    296:                scsi_done(xs);
                    297: #endif
                    298:                vs_free(cb);
                    299:        } else
                    300:                vs_scsidone(sc, cb);
                    301:        splx(s);
                    302:
                    303:        if (CRSW & M_CRSW_ER)
                    304:                CRB_CLR_ER;
                    305:        CRB_CLR_DONE;
                    306:
                    307:        vs_clear_return_info(sc);
                    308:        return (COMPLETE);
                    309: }
                    310:
                    311: void
                    312: thaw_queue(struct vs_softc *sc, int target)
                    313: {
                    314:        THAW(target);
                    315:
                    316:        /* loop until thawed */
                    317:        while (THAW_REG & M_THAW_TWQE)
                    318:                ;
                    319: }
                    320:
                    321: void
                    322: thaw_all_queues(struct vs_softc *sc)
                    323: {
                    324:        int i;
                    325:
                    326:        for (i = 1; i < NUM_WQ; i++)
                    327:                thaw_queue(sc, i);
                    328: }
                    329:
                    330: void
                    331: vs_scsidone(struct vs_softc *sc, struct vs_cb *cb)
                    332: {
                    333:        struct scsi_xfer *xs = cb->cb_xs;
                    334:        u_int32_t len;
                    335:        int error;
                    336:
                    337:        len = vs_read(4, sh_RET_IOPB + IOPB_LENGTH);
                    338:        xs->resid = xs->datalen - len;
                    339:
                    340:        error = vs_read(2, sh_RET_IOPB + IOPB_STATUS);
                    341:        if ((error & 0xff) == SCSI_SELECTION_TO) {
                    342:                xs->error = XS_SELTIMEOUT;
                    343:                xs->status = -1;
                    344:        } else
                    345:                xs->status = error >> 8;
                    346:
                    347:        while (xs->status == SCSI_CHECK) {
                    348:                vs_chksense(xs);
                    349:        }
                    350:
                    351:        xs->flags |= ITSDONE;
                    352:        thaw_queue(sc, cb->cb_q);
                    353:
                    354:        scsi_done(xs);
                    355:
                    356:        vs_free(cb);
                    357: }
                    358:
                    359: int
                    360: vs_scsicmd(struct scsi_xfer *xs)
                    361: {
                    362:        struct scsi_link *slp = xs->sc_link;
                    363:        struct vs_softc *sc = slp->adapter_softc;
                    364:        int flags, option;
                    365:        unsigned int iopb_len;
                    366:        bus_addr_t cqep, iopb;
                    367:        struct vs_cb *cb;
                    368:        u_int queue;
                    369:        int s;
                    370:
                    371:        flags = xs->flags;
                    372:        if (flags & SCSI_POLL) {
                    373:                cb = &sc->sc_cb[0];
                    374:                cqep = sh_MCE;
                    375:                iopb = sh_MCE_IOPB;
                    376:
                    377: #ifdef VS_DEBUG
                    378:                if (mce_read(2, CQE_QECR) & M_QECR_GO)
                    379:                        printf("%s: master command queue busy\n",
                    380:                            sc->sc_dev.dv_xname);
                    381: #endif
                    382:                /* Wait until we can use the command queue entry. */
                    383:                while (mce_read(2, CQE_QECR) & M_QECR_GO)
                    384:                        ;
                    385: #ifdef VS_DEBUG
                    386:                if (cb->cb_xs != NULL) {
                    387:                        printf("%s: master command not idle\n",
                    388:                            sc->sc_dev.dv_xname);
                    389:                        return (TRY_AGAIN_LATER);
                    390:                }
                    391: #endif
                    392:                s = splbio();
                    393:        } else {
                    394:                s = splbio();
                    395:                cb = vs_find_queue(slp, sc);
                    396:                if (cb == NULL) {
                    397:                        splx(s);
                    398: #ifdef VS_DEBUG
                    399:                        printf("%s: no free queues\n", sc->sc_dev.dv_xname);
                    400: #endif
                    401:                        return (TRY_AGAIN_LATER);
                    402:                }
                    403:                cqep = vs_getcqe(sc);
                    404:                if (cqep == 0) {
                    405:                        splx(s);
                    406:                        return (TRY_AGAIN_LATER);
                    407:                }
                    408:                iopb = vs_getiopb(sc);
                    409:        }
                    410:
                    411:        queue = cb->cb_q;
                    412:
                    413:        vs_bzero(iopb, IOPB_LONG_SIZE);
                    414:
                    415:        /*
                    416:         * We should only provide the iopb len if the controller is not
                    417:         * able to compute it from the SCSI command group.
                    418:         * Note that it has no knowledge of group 2.
                    419:         */
                    420:        switch ((xs->cmd->opcode) >> 5) {
                    421:        case 0:
                    422:        case 1:
                    423:        case 5:
                    424:                iopb_len = 0;
                    425:                break;
                    426:        default:
                    427:                iopb_len = IOPB_SHORT_SIZE + xs->cmdlen;
                    428:                break;
                    429:        }
                    430:
                    431:        bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, iopb + IOPB_SCSI_DATA,
                    432:            (u_int8_t *)xs->cmd, xs->cmdlen);
                    433:
                    434:        vs_write(2, iopb + IOPB_CMD, IOPB_PASSTHROUGH);
                    435:        vs_write(2, iopb + IOPB_UNIT,
                    436:          IOPB_UNIT_VALUE(!!(slp->flags & SDEV_2NDBUS), slp->target, slp->lun));
                    437:        vs_write(1, iopb + IOPB_NVCT, sc->sc_nvec);
                    438:        vs_write(1, iopb + IOPB_EVCT, sc->sc_evec);
                    439:
                    440:        /*
                    441:         * Since the 88k doesn't support cache snooping, we have
                    442:         * to flush the cache for a write and flush with inval for
                    443:         * a read, prior to starting the IO.
                    444:         */
                    445:        dma_cachectl(pmap_kernel(), (vaddr_t)xs->data, xs->datalen,
                    446:            flags & SCSI_DATA_IN ? DMA_CACHE_SYNC_INVAL : DMA_CACHE_SYNC);
                    447:
                    448:        option = 0;
                    449:        if (flags & SCSI_DATA_OUT)
                    450:                option |= M_OPT_DIR;
                    451:
                    452:        if (flags & SCSI_POLL) {
                    453:                vs_write(2, iopb + IOPB_OPTION, option);
                    454:                vs_write(2, iopb + IOPB_LEVEL, 0);
                    455:        } else {
                    456:                vs_write(2, iopb + IOPB_OPTION, option | M_OPT_IE);
                    457:                vs_write(2, iopb + IOPB_LEVEL, sc->sc_ipl);
                    458:        }
                    459:        vs_write(2, iopb + IOPB_ADDR, ADDR_MOD);
                    460:
                    461:        vs_write(2, cqep + CQE_IOPB_ADDR, iopb);
                    462:        vs_write(1, cqep + CQE_IOPB_LENGTH, iopb_len);
                    463:        vs_write(1, cqep + CQE_WORK_QUEUE, queue);
                    464:
                    465:        cb->cb_xs = xs;
                    466:        splx(s);
                    467:
                    468:        if (xs->datalen != 0)
                    469:                cb->cb_sg = vs_build_memory_structure(sc, xs, iopb);
                    470:        else
                    471:                cb->cb_sg = NULL;
                    472:
                    473:        vs_write(4, cqep + CQE_CTAG, (u_int32_t)cb);
                    474:
                    475:        if (crb_read(2, CRB_CRSW) & M_CRSW_AQ)
                    476:                vs_write(2, cqep + CQE_QECR, M_QECR_AA | M_QECR_GO);
                    477:        else
                    478:                vs_write(2, cqep + CQE_QECR, M_QECR_GO);
                    479:
                    480:        if (flags & SCSI_POLL) {
                    481:                /* poll for the command to complete */
                    482:                return vs_poll(sc, cb);
                    483:        }
                    484:
                    485:        return (SUCCESSFULLY_QUEUED);
                    486: }
                    487:
                    488: void
                    489: vs_chksense(struct scsi_xfer *xs)
                    490: {
                    491:        int s;
                    492:        struct scsi_link *slp = xs->sc_link;
                    493:        struct vs_softc *sc = slp->adapter_softc;
                    494:        struct scsi_sense *ss;
                    495:
                    496:        /* ack and clear the error */
                    497:        if (CRSW & M_CRSW_ER)
                    498:                CRB_CLR_ER;
                    499:        CRB_CLR_DONE;
                    500:        xs->status = 0;
                    501:
                    502:        /* Wait until we can use the command queue entry. */
                    503:        while (mce_read(2, CQE_QECR) & M_QECR_GO)
                    504:                ;
                    505:
                    506:        vs_bzero(sh_MCE_IOPB, IOPB_LONG_SIZE);
                    507:        /* This is a command, so point to it */
                    508:        ss = (void *)(bus_space_vaddr(sc->sc_iot, sc->sc_ioh) +
                    509:            sh_MCE_IOPB + IOPB_SCSI_DATA);
                    510:        ss->opcode = REQUEST_SENSE;
                    511:        ss->byte2 = slp->lun << 5;
                    512:        ss->length = sizeof(struct scsi_sense_data);
                    513:
                    514:        mce_iopb_write(2, IOPB_CMD, IOPB_PASSTHROUGH);
                    515:        mce_iopb_write(2, IOPB_OPTION, 0);
                    516:        mce_iopb_write(1, IOPB_NVCT, sc->sc_nvec);
                    517:        mce_iopb_write(1, IOPB_EVCT, sc->sc_evec);
                    518:        mce_iopb_write(2, IOPB_LEVEL, 0 /* sc->sc_ipl */);
                    519:        mce_iopb_write(2, IOPB_ADDR, ADDR_MOD);
                    520:        mce_iopb_write(4, IOPB_BUFF, kvtop((vaddr_t)&xs->sense));
                    521:        mce_iopb_write(4, IOPB_LENGTH, sizeof(struct scsi_sense_data));
                    522:        mce_iopb_write(2, IOPB_UNIT,
                    523:          IOPB_UNIT_VALUE(!!(slp->flags & SDEV_2NDBUS), slp->target, slp->lun));
                    524:
                    525:        vs_bzero(sh_MCE, CQE_SIZE);
                    526:        mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB);
                    527:        mce_write(1, CQE_IOPB_LENGTH, 0);
                    528:        mce_write(1, CQE_WORK_QUEUE, 0);
                    529:        mce_write(2, CQE_QECR, M_QECR_GO);
                    530:
                    531:        /* poll for the command to complete */
                    532:        s = splbio();
                    533:        do_vspoll(sc, xs, 1);
                    534:        xs->status = vs_read(2, sh_RET_IOPB + IOPB_STATUS) >> 8;
                    535:        splx(s);
                    536: }
                    537:
                    538: bus_addr_t
                    539: vs_getcqe(struct vs_softc *sc)
                    540: {
                    541:        bus_addr_t cqep;
                    542:        int qhdp;
                    543:
                    544:        qhdp = mcsb_read(2, MCSB_QHDP);
                    545:        cqep = sh_CQE(qhdp);
                    546:
                    547:        if (vs_read(2, cqep + CQE_QECR) & M_QECR_GO) {
                    548:                /* should never happen */
                    549:                return 0;
                    550:        }
                    551:
                    552:        if (++qhdp == NUM_CQE)
                    553:                qhdp = 0;
                    554:        mcsb_write(2, MCSB_QHDP, qhdp);
                    555:
                    556:        vs_bzero(cqep, CQE_SIZE);
                    557:        return cqep;
                    558: }
                    559:
                    560: bus_addr_t
                    561: vs_getiopb(struct vs_softc *sc)
                    562: {
                    563:        bus_addr_t iopb;
                    564:        int qhdp;
                    565:
                    566:        /*
                    567:         * Since we are always invoked after vs_getcqe(), qhdp has already
                    568:         * been incremented...
                    569:         */
                    570:        qhdp = mcsb_read(2, MCSB_QHDP);
                    571:        if (--qhdp < 0)
                    572:                qhdp = NUM_CQE - 1;
                    573:
                    574:        iopb = sh_IOPB(qhdp);
                    575:        return iopb;
                    576: }
                    577:
                    578: int
                    579: vs_initialize(struct vs_softc *sc)
                    580: {
                    581:        int i, msr, dbid;
                    582:
                    583:        for (i = 0; i < NUM_WQ; i++)
                    584:                sc->sc_cb[i].cb_q = i;
                    585:
                    586:        /*
                    587:         * Reset the board, and wait for it to get ready.
                    588:         * The reset signal is applied for 70 usec, and the board status
                    589:         * is not tested until 100 usec after the reset signal has been
                    590:         * cleared, per the manual (MVME328/D1) pages 4-6 and 4-9.
                    591:         */
                    592:
                    593:        mcsb_write(2, MCSB_MCR, M_MCR_RES | M_MCR_SFEN);
                    594:        delay(70);
                    595:        mcsb_write(2, MCSB_MCR, M_MCR_SFEN);
                    596:
                    597:        delay(100);
                    598:        i = 0;
                    599:        for (;;) {
                    600:                msr = mcsb_read(2, MCSB_MSR);
                    601:                if ((msr & (M_MSR_BOK | M_MSR_CNA)) == M_MSR_BOK)
                    602:                        break;
                    603:                if (++i > 5000) {
                    604:                        printf("board reset failed, status %x\n", msr);
                    605:                        return 1;
                    606:                }
                    607:                delay(1000);
                    608:        }
                    609:
                    610:        /* initialize channels id */
                    611:        sc->sc_id[0] = csb_read(1, CSB_PID);
                    612:        sc->sc_id[1] = -1;
                    613:        switch (dbid = csb_read(1, CSB_DBID)) {
                    614:        case DBID_SCSI2:
                    615:        case DBID_SCSI:
                    616: #if 0
                    617:                printf("daughter board, ");
                    618: #endif
                    619:                sc->sc_id[1] = csb_read(1, CSB_SID);
                    620:                break;
                    621:        case DBID_PRINTER:
                    622:                printf("printer port, ");
                    623:                break;
                    624:        case DBID_NONE:
                    625:                break;
                    626:        default:
                    627:                printf("unknown daughterboard id %x, ", dbid);
                    628:                break;
                    629:        }
                    630:
                    631:        CRB_CLR_DONE;
                    632:        mcsb_write(2, MCSB_QHDP, 0);
                    633:
                    634:        vs_bzero(sh_CIB, CIB_SIZE);
                    635:        cib_write(2, CIB_NCQE, NUM_CQE);
                    636:        cib_write(2, CIB_BURST, 0);
                    637:        cib_write(2, CIB_NVECT, (sc->sc_ipl << 8) | sc->sc_nvec);
                    638:        cib_write(2, CIB_EVECT, (sc->sc_ipl << 8) | sc->sc_evec);
                    639:        cib_write(2, CIB_PID, 0x08);    /* XXX default */
                    640:        cib_write(2, CIB_SID, 0x08);
                    641:        cib_write(2, CIB_CRBO, sh_CRB);
                    642:        cib_write(4, CIB_SELECT, SELECTION_TIMEOUT);
                    643:        cib_write(4, CIB_WQTIMO, 4);
                    644:        cib_write(4, CIB_VMETIMO, 0 /* VME_BUS_TIMEOUT */);
                    645:        cib_write(2, CIB_ERR_FLGS, M_ERRFLGS_RIN | M_ERRFLGS_RSE);
                    646:        cib_write(2, CIB_SBRIV, (sc->sc_ipl << 8) | sc->sc_evec);
                    647:        cib_write(1, CIB_SOF0, 0x15);
                    648:        cib_write(1, CIB_SRATE0, 100 / 4);
                    649:        cib_write(1, CIB_SOF1, 0);
                    650:        cib_write(1, CIB_SRATE1, 0);
                    651:
                    652:        vs_bzero(sh_MCE_IOPB, IOPB_LONG_SIZE);
                    653:        mce_iopb_write(2, IOPB_CMD, CNTR_INIT);
                    654:        mce_iopb_write(2, IOPB_OPTION, 0);
                    655:        mce_iopb_write(1, IOPB_NVCT, sc->sc_nvec);
                    656:        mce_iopb_write(1, IOPB_EVCT, sc->sc_evec);
                    657:        mce_iopb_write(2, IOPB_LEVEL, 0 /* sc->sc_ipl */);
                    658:        mce_iopb_write(2, IOPB_ADDR, SHIO_MOD);
                    659:        mce_iopb_write(4, IOPB_BUFF, sh_CIB);
                    660:        mce_iopb_write(4, IOPB_LENGTH, CIB_SIZE);
                    661:
                    662:        vs_bzero(sh_MCE, CQE_SIZE);
                    663:        mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB);
                    664:        mce_write(1, CQE_IOPB_LENGTH, 0);
                    665:        mce_write(1, CQE_WORK_QUEUE, 0);
                    666:        mce_write(2, CQE_QECR, M_QECR_GO);
                    667:
                    668:        /* poll for the command to complete */
                    669:        do_vspoll(sc, NULL, 1);
                    670:
                    671:        /* initialize work queues */
                    672:        for (i = 1; i < NUM_WQ; i++) {
                    673:                /* Wait until we can use the command queue entry. */
                    674:                while (mce_read(2, CQE_QECR) & M_QECR_GO)
                    675:                        ;
                    676:
                    677:                vs_bzero(sh_MCE_IOPB, IOPB_LONG_SIZE);
                    678:                mce_iopb_write(2, WQCF_CMD, CNTR_INIT_WORKQ);
                    679:                mce_iopb_write(2, WQCF_OPTION, 0);
                    680:                mce_iopb_write(1, WQCF_NVCT, sc->sc_nvec);
                    681:                mce_iopb_write(1, WQCF_EVCT, sc->sc_evec);
                    682:                mce_iopb_write(2, WQCF_ILVL, 0 /* sc->sc_ipl */);
                    683:                mce_iopb_write(2, WQCF_WORKQ, i);
                    684:                mce_iopb_write(2, WQCF_WOPT, M_WOPT_FE | M_WOPT_IWQ);
                    685:                mce_iopb_write(2, WQCF_SLOTS, JAGUAR_MAX_Q_SIZ);
                    686:                mce_iopb_write(4, WQCF_CMDTO, 4);       /* 1 second */
                    687:
                    688:                vs_bzero(sh_MCE, CQE_SIZE);
                    689:                mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB);
                    690:                mce_write(1, CQE_IOPB_LENGTH, 0);
                    691:                mce_write(1, CQE_WORK_QUEUE, 0);
                    692:                mce_write(2, CQE_QECR, M_QECR_GO);
                    693:
                    694:                /* poll for the command to complete */
                    695:                do_vspoll(sc, NULL, 1);
                    696:                if (CRSW & M_CRSW_ER) {
                    697:                        printf("work queue %d initialization error 0x%x\n",
                    698:                            i, vs_read(2, sh_RET_IOPB + IOPB_STATUS));
                    699:                        return 1;
                    700:                }
                    701:                CRB_CLR_DONE;
                    702:        }
                    703:
                    704:        /* start queue mode */
                    705:        mcsb_write(2, MCSB_MCR, mcsb_read(2, MCSB_MCR) | M_MCR_SQM);
                    706:
                    707:        /* reset all SCSI buses */
                    708:        vs_reset(sc, -1);
                    709:        /* sync all devices */
                    710:        vs_resync(sc);
                    711:
                    712:        return 0;
                    713: }
                    714:
                    715: void
                    716: vs_resync(struct vs_softc *sc)
                    717: {
                    718:        int bus, target;
                    719:
                    720:        for (bus = 0; bus < 2; bus++) {
                    721:                if (sc->sc_id[bus] < 0)
                    722:                        break;
                    723:
                    724:                for (target = 0; target < 8; target++) {
                    725:                        if (target == sc->sc_id[bus])
                    726:                                continue;
                    727:
                    728:                        /* Wait until we can use the command queue entry. */
                    729:                        while (mce_read(2, CQE_QECR) & M_QECR_GO)
                    730:                                ;
                    731:
                    732:                        vs_bzero(sh_MCE_IOPB, IOPB_SHORT_SIZE);
                    733:                        mce_iopb_write(2, DRCF_CMD, CNTR_DEV_REINIT);
                    734:                        mce_iopb_write(2, DRCF_OPTION, 0); /* prefer polling */
                    735:                        mce_iopb_write(1, DRCF_NVCT, sc->sc_nvec);
                    736:                        mce_iopb_write(1, DRCF_EVCT, sc->sc_evec);
                    737:                        mce_iopb_write(2, DRCF_ILVL, 0);
                    738:                        mce_iopb_write(2, DRCF_UNIT,
                    739:                            IOPB_UNIT_VALUE(bus, target, 0));
                    740:
                    741:                        vs_bzero(sh_MCE, CQE_SIZE);
                    742:                        mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB);
                    743:                        mce_write(1, CQE_IOPB_LENGTH, 0);
                    744:                        mce_write(1, CQE_WORK_QUEUE, 0);
                    745:                        mce_write(2, CQE_QECR, M_QECR_GO);
                    746:
                    747:                        /* poll for the command to complete */
                    748:                        do_vspoll(sc, NULL, 0);
                    749:                        if (CRSW & M_CRSW_ER)
                    750:                                CRB_CLR_ER;
                    751:                        CRB_CLR_DONE;
                    752:                }
                    753:        }
                    754: }
                    755:
                    756: void
                    757: vs_reset(struct vs_softc *sc, int bus)
                    758: {
                    759:        int b, s;
                    760:
                    761:        s = splbio();
                    762:
                    763:        for (b = 0; b < 2; b++) {
                    764:                if (bus >= 0 && b != bus)
                    765:                        continue;
                    766:
                    767:                /* Wait until we can use the command queue entry. */
                    768:                while (mce_read(2, CQE_QECR) & M_QECR_GO)
                    769:                        ;
                    770:
                    771:                vs_bzero(sh_MCE_IOPB, IOPB_SHORT_SIZE);
                    772:                mce_iopb_write(2, SRCF_CMD, IOPB_RESET);
                    773:                mce_iopb_write(2, SRCF_OPTION, 0);      /* prefer polling */
                    774:                mce_iopb_write(1, SRCF_NVCT, sc->sc_nvec);
                    775:                mce_iopb_write(1, SRCF_EVCT, sc->sc_evec);
                    776:                mce_iopb_write(2, SRCF_ILVL, 0);
                    777:                mce_iopb_write(2, SRCF_BUSID, b << 15);
                    778:
                    779:                vs_bzero(sh_MCE, CQE_SIZE);
                    780:                mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB);
                    781:                mce_write(1, CQE_IOPB_LENGTH, 0);
                    782:                mce_write(1, CQE_WORK_QUEUE, 0);
                    783:                mce_write(2, CQE_QECR, M_QECR_GO);
                    784:
                    785:                /* poll for the command to complete */
                    786:                for (;;) {
                    787:                        do_vspoll(sc, NULL, 0);
                    788:                        /* ack & clear scsi error condition cause by reset */
                    789:                        if (CRSW & M_CRSW_ER) {
                    790:                                CRB_CLR_DONE;
                    791:                                vs_write(2, sh_RET_IOPB + IOPB_STATUS, 0);
                    792:                                break;
                    793:                        }
                    794:                        CRB_CLR_DONE;
                    795:                }
                    796:        }
                    797:
                    798:        thaw_all_queues(sc);
                    799:
                    800:        splx(s);
                    801: }
                    802:
                    803: /* free a cb; invoked at splbio */
                    804: static __inline__ void
                    805: vs_free(struct vs_cb *cb)
                    806: {
                    807:        if (cb->cb_sg != NULL) {
                    808:                vs_dealloc_scatter_gather(cb->cb_sg);
                    809:                cb->cb_sg = NULL;
                    810:        }
                    811:        cb->cb_xs = NULL;
                    812: }
                    813:
                    814: /* normal interrupt routine */
                    815: int
                    816: vs_nintr(void *vsc)
                    817: {
                    818:        struct vs_softc *sc = (struct vs_softc *)vsc;
                    819:        struct vs_cb *cb;
                    820:        int s;
                    821:
                    822:        if ((CRSW & CONTROLLER_ERROR) == CONTROLLER_ERROR)
                    823:                return vs_eintr(sc);
                    824:
                    825:        /* Got a valid interrupt on this device */
                    826:        s = splbio();
                    827:        cb = (struct vs_cb *)crb_read(4, CRB_CTAG);
                    828:
                    829:        /*
                    830:         * If this is a controller error, there won't be a cb
                    831:         * pointer in the CTAG field.  Bad things happen if you try
                    832:         * to point to address 0.  But then, we should have caught
                    833:         * the controller error above.
                    834:         */
                    835:        if (cb != NULL)
                    836:                vs_scsidone(sc, cb);
                    837:
                    838:        /* ack the interrupt */
                    839:        if (CRSW & M_CRSW_ER)
                    840:                CRB_CLR_ER;
                    841:        CRB_CLR_DONE;
                    842:
                    843:        vs_clear_return_info(sc);
                    844:        splx(s);
                    845:
                    846:        return 1;
                    847: }
                    848:
                    849: /* error interrupts */
                    850: int
                    851: vs_eintr(void *vsc)
                    852: {
                    853:        struct vs_softc *sc = (struct vs_softc *)vsc;
                    854:        struct vs_cb *cb;
                    855:        struct scsi_xfer *xs;
                    856:        int crsw, ecode;
                    857:        int s;
                    858:
                    859:        /* Got a valid interrupt on this device */
                    860:        s = splbio();
                    861:
                    862:        crsw = vs_read(2, sh_CEVSB + CEVSB_CRSW);
                    863:        ecode = vs_read(1, sh_CEVSB + CEVSB_ERROR);
                    864:        cb = (struct vs_cb *)crb_read(4, CRB_CTAG);
                    865:        xs = cb != NULL ? cb->cb_xs : NULL;
                    866:
                    867:        vs_print_addr(sc, xs);
                    868:
                    869:        if (crsw & M_CRSW_RST) {
                    870:                printf("bus reset\n");
                    871:        } else {
                    872:                switch (ecode) {
                    873:                case CEVSB_ERR_TYPE:
                    874:                        printf("IOPB type error\n");
                    875:                        break;
                    876:                case CEVSB_ERR_TO:
                    877:                        printf("timeout\n");
                    878:                        break;
                    879:                case CEVSB_ERR_TR:
                    880:                        printf("reconnect error\n");
                    881:                        break;
                    882:                case CEVSB_ERR_OF:
                    883:                        printf("overflow\n");
                    884:                        break;
                    885:                case CEVSB_ERR_BD:
                    886:                        printf("bad direction\n");
                    887:                        break;
                    888:                case CEVSB_ERR_NR:
                    889:                        printf("non-recoverable error\n");
                    890:                        break;
                    891:                case CEVSB_ERR_PANIC:
                    892:                        printf("board panic\n");
                    893:                        break;
                    894:                default:
                    895:                        printf("unexpected error %x\n", ecode);
                    896:                        break;
                    897:                }
                    898:        }
                    899:
                    900:        if (xs != NULL) {
                    901:                xs->error = XS_SELTIMEOUT;
                    902:                xs->status = -1;
                    903:                xs->flags |= ITSDONE;
                    904:                scsi_done(xs);
                    905:        }
                    906:
                    907:        if (CRSW & M_CRSW_ER)
                    908:                CRB_CLR_ER;
                    909:        CRB_CLR_DONE;
                    910:
                    911:        thaw_all_queues(sc);
                    912:        vs_clear_return_info(sc);
                    913:        splx(s);
                    914:
                    915:        return 1;
                    916: }
                    917:
                    918: static void
                    919: vs_clear_return_info(struct vs_softc *sc)
                    920: {
                    921:        vs_bzero(sh_RET_IOPB, CRB_SIZE + IOPB_LONG_SIZE);
                    922: }
                    923:
                    924: /*
                    925:  * Choose the first available work queue (invoked at splbio).
                    926:  * We used a simple round-robin mechanism which is faster than rescanning
                    927:  * from the beginning if we have more than one target on the bus.
                    928:  */
                    929: struct vs_cb *
                    930: vs_find_queue(struct scsi_link *sl, struct vs_softc *sc)
                    931: {
                    932:        struct vs_cb *cb;
                    933:        static u_int last = 0;
                    934:        u_int q;
                    935:
                    936:        q = last;
                    937:        for (;;) {
                    938:                if (++q == NUM_WQ)
                    939:                        q = 1;
                    940:                if (q == last)
                    941:                        break;
                    942:
                    943:                if ((cb = &sc->sc_cb[q])->cb_xs == NULL) {
                    944:                        last = q;
                    945:                        return (cb);
                    946:                }
                    947:        }
                    948:
                    949:        return (NULL);
                    950: }
                    951:
                    952: /*
                    953:  * Useful functions for scatter/gather list
                    954:  */
                    955:
                    956: M328_SG
                    957: vs_alloc_scatter_gather(void)
                    958: {
                    959:        M328_SG sg;
                    960:
                    961:        MALLOC(sg, M328_SG, sizeof(struct m328_sg), M_DEVBUF, M_WAITOK);
                    962:        bzero(sg, sizeof(struct m328_sg));
                    963:
                    964:        return (sg);
                    965: }
                    966:
                    967: void
                    968: vs_dealloc_scatter_gather(M328_SG sg)
                    969: {
                    970:        int i;
                    971:
                    972:        if (sg->level > 0) {
                    973:                for (i = 0; sg->down[i] && i < MAX_SG_ELEMENTS; i++) {
                    974:                        vs_dealloc_scatter_gather(sg->down[i]);
                    975:                }
                    976:        }
                    977:        FREE(sg, M_DEVBUF);
                    978: }
                    979:
                    980: void
                    981: vs_link_sg_element(sg_list_element_t *element, vaddr_t phys_add, int len)
                    982: {
                    983:        element->count.bytes = len;
                    984:        element->addrlo = phys_add;
                    985:        element->addrhi = phys_add >> 16;
                    986:        element->link = 0; /* FALSE */
                    987:        element->transfer_type = NORMAL_TYPE;
                    988:        element->memory_type = LONG_TRANSFER;
                    989:        element->address_modifier = ADRM_EXT_S_D;
                    990: }
                    991:
                    992: void
                    993: vs_link_sg_list(sg_list_element_t *list, vaddr_t phys_add, int elements)
                    994: {
                    995:        list->count.scatter.gather = elements;
                    996:        list->addrlo = phys_add;
                    997:        list->addrhi = phys_add >> 16;
                    998:        list->link = 1;    /* TRUE */
                    999:        list->transfer_type = NORMAL_TYPE;
                   1000:        list->memory_type = LONG_TRANSFER;
                   1001:        list->address_modifier = ADRM_EXT_S_D;
                   1002: }
                   1003:
                   1004: M328_SG
                   1005: vs_build_memory_structure(struct vs_softc *sc, struct scsi_xfer *xs,
                   1006:      bus_addr_t iopb)
                   1007: {
                   1008:        M328_SG sg;
                   1009:        vaddr_t starting_point_virt, starting_point_phys, point_virt,
                   1010:        point1_phys, point2_phys, virt;
                   1011:        unsigned int len;
                   1012:        int level;
                   1013:
                   1014:        sg = NULL;      /* Hopefully we need no scatter/gather list */
                   1015:
                   1016:        /*
                   1017:         * We have the following things:
                   1018:         *      virt                    va of the virtual memory block
                   1019:         *      len                     length of the virtual memory block
                   1020:         *      starting_point_virt     va of the physical memory block
                   1021:         *      starting_point_phys     pa of the physical memory block
                   1022:         *      point_virt              va of the virtual memory
                   1023:         *                                  we are checking at the moment
                   1024:         *      point1_phys             pa of the physical memory
                   1025:         *                                  we are checking at the moment
                   1026:         *      point2_phys             pa of another physical memory
                   1027:         *                                  we are checking at the moment
                   1028:         */
                   1029:
                   1030:        level = 0;
                   1031:        virt = starting_point_virt = (vaddr_t)xs->data;
                   1032:        point1_phys = starting_point_phys = kvtop((vaddr_t)xs->data);
                   1033:        len = xs->datalen;
                   1034:
                   1035:        /*
                   1036:         * Check if we need scatter/gather
                   1037:         */
                   1038:        if (trunc_page(virt + len - 1) != trunc_page(virt)) {
                   1039:                for (point_virt = round_page(starting_point_virt + 1);
                   1040:                    /* if we do already scatter/gather we have to stay in the loop and jump */
                   1041:                    point_virt < virt + len || sg != NULL;
                   1042:                    point_virt += PAGE_SIZE) {             /* out later */
                   1043:
                   1044:                        point2_phys = kvtop(point_virt);
                   1045:
                   1046:                        if ((point2_phys != trunc_page(point1_phys) + PAGE_SIZE) ||                /* physical memory is not contiguous */
                   1047:                            (point_virt - starting_point_virt >= MAX_SG_BLOCK_SIZE && sg)) {   /* we only can access (1<<16)-1 bytes in scatter/gather_mode */
                   1048:                                if (point_virt - starting_point_virt >= MAX_SG_BLOCK_SIZE) {           /* We were walking too far for one scatter/gather block ... */
                   1049:                                        point_virt = trunc_page(starting_point_virt+MAX_SG_BLOCK_SIZE-1);    /* So go back to the beginning of the last matching page */
                   1050:                                        /* and generate the physical address of
                   1051:                                         * this location for the next time. */
                   1052:                                        point2_phys = kvtop(point_virt);
                   1053:                                }
                   1054:
                   1055:                                if (sg == NULL)
                   1056:                                        sg = vs_alloc_scatter_gather();
                   1057:
                   1058: #if 1 /* broken firmware */
                   1059:                                if (sg->elements >= MAX_SG_ELEMENTS) {
                   1060:                                        vs_dealloc_scatter_gather(sg);
                   1061:                                        printf("%s: scatter/gather list too large\n",
                   1062:                                            sc->sc_dev.dv_xname);
                   1063:                                        return (NULL);
                   1064:                                }
                   1065: #else /* if the firmware will ever get fixed */
                   1066:                                while (sg->elements >= MAX_SG_ELEMENTS) {
                   1067:                                        if (!sg->up) { /* If the list full in this layer ? */
                   1068:                                                sg->up = vs_alloc_scatter_gather();
                   1069:                                                sg->up->level = sg->level+1;
                   1070:                                                sg->up->down[0] = sg;
                   1071:                                                sg->up->elements = 1;
                   1072:                                        }
                   1073:                                        /* link this full list also in physical memory */
                   1074:                                        vs_link_sg_list(&(sg->up->list[sg->up->elements-1]),
                   1075:                                                        kvtop((vaddr_t)sg->list),
                   1076:                                                        sg->elements);
                   1077:                                        sg = sg->up;      /* Climb up */
                   1078:                                }
                   1079:                                while (sg->level) {  /* As long as we are not a the base level */
                   1080:                                        int i;
                   1081:
                   1082:                                        i = sg->elements;
                   1083:                                        /* We need a new element */
                   1084:                                        sg->down[i] = vs_alloc_scatter_gather();
                   1085:                                        sg->down[i]->level = sg->level - 1;
                   1086:                                        sg->down[i]->up = sg;
                   1087:                                        sg->elements++;
                   1088:                                        sg = sg->down[i]; /* Climb down */
                   1089:                                }
                   1090: #endif /* 1 */
                   1091:                                if (point_virt < virt + len) {
                   1092:                                        /* linking element */
                   1093:                                        vs_link_sg_element(&(sg->list[sg->elements]),
                   1094:                                                           starting_point_phys,
                   1095:                                                           point_virt - starting_point_virt);
                   1096:                                        sg->elements++;
                   1097:                                } else {
                   1098:                                        /* linking last element */
                   1099:                                        vs_link_sg_element(&(sg->list[sg->elements]),
                   1100:                                                           starting_point_phys,
                   1101:                                                           virt + len - starting_point_virt);
                   1102:                                        sg->elements++;
                   1103:                                        break;                         /* We have now collected all blocks */
                   1104:                                }
                   1105:                                starting_point_virt = point_virt;
                   1106:                                starting_point_phys = point2_phys;
                   1107:                        }
                   1108:                        point1_phys = point2_phys;
                   1109:                }
                   1110:        }
                   1111:
                   1112:        /*
                   1113:         * Climb up along the right side of the tree until we reach the top.
                   1114:         */
                   1115:
                   1116:        if (sg != NULL) {
                   1117:                while (sg->up) {
                   1118:                        /* link this list also in physical memory */
                   1119:                        vs_link_sg_list(&(sg->up->list[sg->up->elements-1]),
                   1120:                                        kvtop((vaddr_t)sg->list),
                   1121:                                        sg->elements);
                   1122:                        sg = sg->up;                   /* Climb up */
                   1123:                }
                   1124:
                   1125:                vs_write(2, iopb + IOPB_OPTION,
                   1126:                    vs_read(2, iopb + IOPB_OPTION) | M_OPT_SG);
                   1127:                vs_write(2, iopb + IOPB_ADDR,
                   1128:                    vs_read(2, iopb + IOPB_ADDR) | M_ADR_SG_LINK);
                   1129:                vs_write(4, iopb + IOPB_BUFF, kvtop((vaddr_t)sg->list));
                   1130:                vs_write(4, iopb + IOPB_LENGTH, sg->elements);
                   1131:                vs_write(4, iopb + IOPB_SGTTL, len);
                   1132:        } else {
                   1133:                /* no scatter/gather necessary */
                   1134:                vs_write(4, iopb + IOPB_BUFF, starting_point_phys);
                   1135:                vs_write(4, iopb + IOPB_LENGTH, len);
                   1136:        }
                   1137:        return sg;
                   1138: }
                   1139:
                   1140: static paddr_t
                   1141: kvtop(vaddr_t va)
                   1142: {
                   1143:        paddr_t pa;
                   1144:
                   1145:        pmap_extract(pmap_kernel(), va, &pa);
                   1146:        /* XXX check for failure */
                   1147:        return pa;
                   1148: }

CVSweb