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

Annotation of sys/dev/ic/twe.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: twe.c,v 1.27 2006/12/29 13:04:37 pedro Exp $  */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2000-2002 Michael Shalayeff.  All rights reserved.
        !             5:  *
        !             6:  * The SCSI emulation layer is derived from gdt(4) driver,
        !             7:  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            21:  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
        !            22:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            23:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            24:  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            26:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
        !            27:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            28:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            29:  */
        !            30:
        !            31: /* #define     TWE_DEBUG */
        !            32:
        !            33: #include <sys/param.h>
        !            34: #include <sys/systm.h>
        !            35: #include <sys/buf.h>
        !            36: #include <sys/device.h>
        !            37: #include <sys/kernel.h>
        !            38: #include <sys/malloc.h>
        !            39: #include <sys/proc.h>
        !            40: #include <sys/kthread.h>
        !            41:
        !            42: #include <machine/bus.h>
        !            43:
        !            44: #include <scsi/scsi_all.h>
        !            45: #include <scsi/scsi_disk.h>
        !            46: #include <scsi/scsiconf.h>
        !            47:
        !            48: #include <dev/ic/twereg.h>
        !            49: #include <dev/ic/twevar.h>
        !            50:
        !            51: #ifdef TWE_DEBUG
        !            52: #define        TWE_DPRINTF(m,a)        if (twe_debug & (m)) printf a
        !            53: #define        TWE_D_CMD       0x0001
        !            54: #define        TWE_D_INTR      0x0002
        !            55: #define        TWE_D_MISC      0x0004
        !            56: #define        TWE_D_DMA       0x0008
        !            57: #define        TWE_D_AEN       0x0010
        !            58: int twe_debug = 0;
        !            59: #else
        !            60: #define        TWE_DPRINTF(m,a)        /* m, a */
        !            61: #endif
        !            62:
        !            63: struct cfdriver twe_cd = {
        !            64:        NULL, "twe", DV_DULL
        !            65: };
        !            66:
        !            67: int    twe_scsi_cmd(struct scsi_xfer *);
        !            68:
        !            69: struct scsi_adapter twe_switch = {
        !            70:        twe_scsi_cmd, tweminphys, 0, 0,
        !            71: };
        !            72:
        !            73: struct scsi_device twe_dev = {
        !            74:        NULL, NULL, NULL, NULL
        !            75: };
        !            76:
        !            77: static __inline struct twe_ccb *twe_get_ccb(struct twe_softc *sc);
        !            78: static __inline void twe_put_ccb(struct twe_ccb *ccb);
        !            79: void twe_dispose(struct twe_softc *sc);
        !            80: int  twe_cmd(struct twe_ccb *ccb, int flags, int wait);
        !            81: int  twe_start(struct twe_ccb *ccb, int wait);
        !            82: int  twe_complete(struct twe_ccb *ccb);
        !            83: int  twe_done(struct twe_softc *sc, struct twe_ccb *ccb);
        !            84: void twe_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
        !            85: void twe_thread_create(void *v);
        !            86: void twe_thread(void *v);
        !            87:
        !            88:
        !            89: static __inline struct twe_ccb *
        !            90: twe_get_ccb(sc)
        !            91:        struct twe_softc *sc;
        !            92: {
        !            93:        struct twe_ccb *ccb;
        !            94:
        !            95:        ccb = TAILQ_LAST(&sc->sc_free_ccb, twe_queue_head);
        !            96:        if (ccb)
        !            97:                TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link);
        !            98:        return ccb;
        !            99: }
        !           100:
        !           101: static __inline void
        !           102: twe_put_ccb(ccb)
        !           103:        struct twe_ccb *ccb;
        !           104: {
        !           105:        struct twe_softc *sc = ccb->ccb_sc;
        !           106:
        !           107:        ccb->ccb_state = TWE_CCB_FREE;
        !           108:        TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);
        !           109: }
        !           110:
        !           111: void
        !           112: twe_dispose(sc)
        !           113:        struct twe_softc *sc;
        !           114: {
        !           115:        register struct twe_ccb *ccb;
        !           116:        if (sc->sc_cmdmap != NULL) {
        !           117:                bus_dmamap_destroy(sc->dmat, sc->sc_cmdmap);
        !           118:                /* traverse the ccbs and destroy the maps */
        !           119:                for (ccb = &sc->sc_ccbs[TWE_MAXCMDS - 1]; ccb >= sc->sc_ccbs; ccb--)
        !           120:                        if (ccb->ccb_dmamap)
        !           121:                                bus_dmamap_destroy(sc->dmat, ccb->ccb_dmamap);
        !           122:        }
        !           123:        bus_dmamem_unmap(sc->dmat, sc->sc_cmds,
        !           124:            sizeof(struct twe_cmd) * TWE_MAXCMDS);
        !           125:        bus_dmamem_free(sc->dmat, sc->sc_cmdseg, 1);
        !           126: }
        !           127:
        !           128: int
        !           129: twe_attach(sc)
        !           130:        struct twe_softc *sc;
        !           131: {
        !           132:        struct scsibus_attach_args saa;
        !           133:        /* this includes a buffer for drive config req, and a capacity req */
        !           134:        u_int8_t        param_buf[2 * TWE_SECTOR_SIZE + TWE_ALIGN - 1];
        !           135:        struct twe_param *pb = (void *)
        !           136:            (((u_long)param_buf + TWE_ALIGN - 1) & ~(TWE_ALIGN - 1));
        !           137:        struct twe_param *cap = (void *)((u_int8_t *)pb + TWE_SECTOR_SIZE);
        !           138:        struct twe_ccb  *ccb;
        !           139:        struct twe_cmd  *cmd;
        !           140:        u_int32_t       status;
        !           141:        int             error, i, retry, nunits, nseg;
        !           142:        const char      *errstr;
        !           143:        twe_lock_t      lock;
        !           144:        paddr_t         pa;
        !           145:
        !           146:        error = bus_dmamem_alloc(sc->dmat, sizeof(struct twe_cmd) * TWE_MAXCMDS,
        !           147:            PAGE_SIZE, 0, sc->sc_cmdseg, 1, &nseg, BUS_DMA_NOWAIT);
        !           148:        if (error) {
        !           149:                printf(": cannot allocate commands (%d)\n", error);
        !           150:                return (1);
        !           151:        }
        !           152:
        !           153:        error = bus_dmamem_map(sc->dmat, sc->sc_cmdseg, nseg,
        !           154:            sizeof(struct twe_cmd) * TWE_MAXCMDS,
        !           155:            (caddr_t *)&sc->sc_cmds, BUS_DMA_NOWAIT);
        !           156:        if (error) {
        !           157:                printf(": cannot map commands (%d)\n", error);
        !           158:                bus_dmamem_free(sc->dmat, sc->sc_cmdseg, 1);
        !           159:                return (1);
        !           160:        }
        !           161:
        !           162:        error = bus_dmamap_create(sc->dmat,
        !           163:            sizeof(struct twe_cmd) * TWE_MAXCMDS, TWE_MAXCMDS,
        !           164:            sizeof(struct twe_cmd) * TWE_MAXCMDS, 0,
        !           165:            BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_cmdmap);
        !           166:        if (error) {
        !           167:                printf(": cannot create ccb cmd dmamap (%d)\n", error);
        !           168:                twe_dispose(sc);
        !           169:                return (1);
        !           170:        }
        !           171:        error = bus_dmamap_load(sc->dmat, sc->sc_cmdmap, sc->sc_cmds,
        !           172:            sizeof(struct twe_cmd) * TWE_MAXCMDS, NULL, BUS_DMA_NOWAIT);
        !           173:        if (error) {
        !           174:                printf(": cannot load command dma map (%d)\n", error);
        !           175:                twe_dispose(sc);
        !           176:                return (1);
        !           177:        }
        !           178:
        !           179:        TAILQ_INIT(&sc->sc_ccb2q);
        !           180:        TAILQ_INIT(&sc->sc_ccbq);
        !           181:        TAILQ_INIT(&sc->sc_free_ccb);
        !           182:        TAILQ_INIT(&sc->sc_done_ccb);
        !           183:
        !           184:        lockinit(&sc->sc_lock, PWAIT, "twelk", 0, 0);
        !           185:
        !           186:        pa = sc->sc_cmdmap->dm_segs[0].ds_addr +
        !           187:            sizeof(struct twe_cmd) * (TWE_MAXCMDS - 1);
        !           188:        for (cmd = (struct twe_cmd *)sc->sc_cmds + TWE_MAXCMDS - 1;
        !           189:             cmd >= (struct twe_cmd *)sc->sc_cmds; cmd--, pa -= sizeof(*cmd)) {
        !           190:
        !           191:                cmd->cmd_index = cmd - (struct twe_cmd *)sc->sc_cmds;
        !           192:                ccb = &sc->sc_ccbs[cmd->cmd_index];
        !           193:                error = bus_dmamap_create(sc->dmat,
        !           194:                    TWE_MAXFER, TWE_MAXOFFSETS, TWE_MAXFER, 0,
        !           195:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
        !           196:                if (error) {
        !           197:                        printf(": cannot create ccb dmamap (%d)\n", error);
        !           198:                        twe_dispose(sc);
        !           199:                        return (1);
        !           200:                }
        !           201:                ccb->ccb_sc = sc;
        !           202:                ccb->ccb_cmd = cmd;
        !           203:                ccb->ccb_cmdpa = pa;
        !           204:                ccb->ccb_state = TWE_CCB_FREE;
        !           205:                TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);
        !           206:        }
        !           207:
        !           208:        for (errstr = NULL, retry = 3; retry--; ) {
        !           209:                int             veseen_srst;
        !           210:                u_int16_t       aen;
        !           211:
        !           212:                if (errstr)
        !           213:                        TWE_DPRINTF(TWE_D_MISC, ("%s ", errstr));
        !           214:
        !           215:                for (i = 350000; i--; DELAY(100)) {
        !           216:                        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           217:                        if (status & TWE_STAT_CPURDY)
        !           218:                                break;
        !           219:                }
        !           220:
        !           221:                if (!(status & TWE_STAT_CPURDY)) {
        !           222:                        errstr = ": card CPU is not ready\n";
        !           223:                        continue;
        !           224:                }
        !           225:
        !           226:                /* soft reset, disable ints */
        !           227:                bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !           228:                    TWE_CTRL_SRST |
        !           229:                    TWE_CTRL_CHOSTI | TWE_CTRL_CATTNI | TWE_CTRL_CERR |
        !           230:                    TWE_CTRL_MCMDI | TWE_CTRL_MRDYI |
        !           231:                    TWE_CTRL_MINT);
        !           232:
        !           233:                for (i = 350000; i--; DELAY(100)) {
        !           234:                        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           235:                        if (status & TWE_STAT_ATTNI)
        !           236:                                break;
        !           237:                }
        !           238:
        !           239:                if (!(status & TWE_STAT_ATTNI)) {
        !           240:                        errstr = ": cannot get card's attention\n";
        !           241:                        continue;
        !           242:                }
        !           243:
        !           244:                /* drain aen queue */
        !           245:                for (veseen_srst = 0, aen = -1; aen != TWE_AEN_QEMPTY; ) {
        !           246:
        !           247:                        if ((ccb = twe_get_ccb(sc)) == NULL) {
        !           248:                                errstr = ": out of ccbs\n";
        !           249:                                continue;
        !           250:                        }
        !           251:
        !           252:                        ccb->ccb_xs = NULL;
        !           253:                        ccb->ccb_data = pb;
        !           254:                        ccb->ccb_length = TWE_SECTOR_SIZE;
        !           255:                        ccb->ccb_state = TWE_CCB_READY;
        !           256:                        cmd = ccb->ccb_cmd;
        !           257:                        cmd->cmd_unit_host = TWE_UNITHOST(0, 0);
        !           258:                        cmd->cmd_op = TWE_CMD_GPARAM;
        !           259:                        cmd->cmd_param.count = 1;
        !           260:
        !           261:                        pb->table_id = TWE_PARAM_AEN;
        !           262:                        pb->param_id = 2;
        !           263:                        pb->param_size = 2;
        !           264:
        !           265:                        if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) {
        !           266:                                errstr = ": error draining attention queue\n";
        !           267:                                break;
        !           268:                        }
        !           269:                        aen = *(u_int16_t *)pb->data;
        !           270:                        TWE_DPRINTF(TWE_D_AEN, ("aen=%x ", aen));
        !           271:                        if (aen == TWE_AEN_SRST)
        !           272:                                veseen_srst++;
        !           273:                }
        !           274:
        !           275:                if (!veseen_srst) {
        !           276:                        errstr = ": we don't get it\n";
        !           277:                        continue;
        !           278:                }
        !           279:
        !           280:                if (status & TWE_STAT_CPUERR) {
        !           281:                        errstr = ": card CPU error detected\n";
        !           282:                        continue;
        !           283:                }
        !           284:
        !           285:                if (status & TWE_STAT_PCIPAR) {
        !           286:                        errstr = ": PCI parity error detected\n";
        !           287:                        continue;
        !           288:                }
        !           289:
        !           290:                if (status & TWE_STAT_QUEUEE ) {
        !           291:                        errstr = ": queuing error detected\n";
        !           292:                        continue;
        !           293:                }
        !           294:
        !           295:                if (status & TWE_STAT_PCIABR) {
        !           296:                        errstr = ": PCI abort\n";
        !           297:                        continue;
        !           298:                }
        !           299:
        !           300:                while (!(status & TWE_STAT_RQE)) {
        !           301:                        bus_space_read_4(sc->iot, sc->ioh, TWE_READYQUEUE);
        !           302:                        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           303:                }
        !           304:
        !           305:                break;
        !           306:        }
        !           307:
        !           308:        if (retry < 0) {
        !           309:                printf(errstr);
        !           310:                twe_dispose(sc);
        !           311:                return 1;
        !           312:        }
        !           313:
        !           314:        if ((ccb = twe_get_ccb(sc)) == NULL) {
        !           315:                printf(": out of ccbs\n");
        !           316:                twe_dispose(sc);
        !           317:                return 1;
        !           318:        }
        !           319:
        !           320:        ccb->ccb_xs = NULL;
        !           321:        ccb->ccb_data = pb;
        !           322:        ccb->ccb_length = TWE_SECTOR_SIZE;
        !           323:        ccb->ccb_state = TWE_CCB_READY;
        !           324:        cmd = ccb->ccb_cmd;
        !           325:        cmd->cmd_unit_host = TWE_UNITHOST(0, 0);
        !           326:        cmd->cmd_op = TWE_CMD_GPARAM;
        !           327:        cmd->cmd_param.count = 1;
        !           328:
        !           329:        pb->table_id = TWE_PARAM_UC;
        !           330:        pb->param_id = TWE_PARAM_UC;
        !           331:        pb->param_size = TWE_MAX_UNITS;
        !           332:        if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) {
        !           333:                printf(": failed to fetch unit parameters\n");
        !           334:                twe_dispose(sc);
        !           335:                return 1;
        !           336:        }
        !           337:
        !           338:        /* we are assuming last read status was good */
        !           339:        printf(": Escalade V%d.%d\n", TWE_MAJV(status), TWE_MINV(status));
        !           340:
        !           341:        for (nunits = i = 0; i < TWE_MAX_UNITS; i++) {
        !           342:                if (pb->data[i] == 0)
        !           343:                        continue;
        !           344:
        !           345:                if ((ccb = twe_get_ccb(sc)) == NULL) {
        !           346:                        printf(": out of ccbs\n");
        !           347:                        twe_dispose(sc);
        !           348:                        return 1;
        !           349:                }
        !           350:
        !           351:                ccb->ccb_xs = NULL;
        !           352:                ccb->ccb_data = cap;
        !           353:                ccb->ccb_length = TWE_SECTOR_SIZE;
        !           354:                ccb->ccb_state = TWE_CCB_READY;
        !           355:                cmd = ccb->ccb_cmd;
        !           356:                cmd->cmd_unit_host = TWE_UNITHOST(0, 0);
        !           357:                cmd->cmd_op = TWE_CMD_GPARAM;
        !           358:                cmd->cmd_param.count = 1;
        !           359:
        !           360:                cap->table_id = TWE_PARAM_UI + i;
        !           361:                cap->param_id = 4;
        !           362:                cap->param_size = 4;    /* 4 bytes */
        !           363:                lock = TWE_LOCK(sc);
        !           364:                if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) {
        !           365:                        TWE_UNLOCK(sc, lock);
        !           366:                        printf("%s: error fetching capacity for unit %d\n",
        !           367:                            sc->sc_dev.dv_xname, i);
        !           368:                        continue;
        !           369:                }
        !           370:                TWE_UNLOCK(sc, lock);
        !           371:
        !           372:                nunits++;
        !           373:                sc->sc_hdr[i].hd_present = 1;
        !           374:                sc->sc_hdr[i].hd_devtype = 0;
        !           375:                sc->sc_hdr[i].hd_size = letoh32(*(u_int32_t *)cap->data);
        !           376:                TWE_DPRINTF(TWE_D_MISC, ("twed%d: size=%d\n",
        !           377:                    i, sc->sc_hdr[i].hd_size));
        !           378:        }
        !           379:
        !           380:        if (!nunits)
        !           381:                nunits++;
        !           382:
        !           383:        /* TODO: fetch & print cache params? */
        !           384:
        !           385:        sc->sc_link.adapter_softc = sc;
        !           386:        sc->sc_link.adapter = &twe_switch;
        !           387:        sc->sc_link.adapter_target = TWE_MAX_UNITS;
        !           388:        sc->sc_link.device = &twe_dev;
        !           389:        sc->sc_link.openings = TWE_MAXCMDS / nunits;
        !           390:        sc->sc_link.adapter_buswidth = TWE_MAX_UNITS;
        !           391:
        !           392:        bzero(&saa, sizeof(saa));
        !           393:        saa.saa_sc_link = &sc->sc_link;
        !           394:
        !           395:        config_found(&sc->sc_dev, &saa, scsiprint);
        !           396:
        !           397:        kthread_create_deferred(twe_thread_create, sc);
        !           398:
        !           399:        return (0);
        !           400: }
        !           401:
        !           402: void
        !           403: twe_thread_create(void *v)
        !           404: {
        !           405:        struct twe_softc *sc = v;
        !           406:
        !           407:        if (kthread_create(twe_thread, sc, &sc->sc_thread,
        !           408:            "%s", sc->sc_dev.dv_xname)) {
        !           409:                /* TODO disable twe */
        !           410:                printf("%s: failed to create kernel thread, disabled\n",
        !           411:                    sc->sc_dev.dv_xname);
        !           412:                return;
        !           413:        }
        !           414:
        !           415:        TWE_DPRINTF(TWE_D_CMD, ("stat=%b ",
        !           416:            bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS), TWE_STAT_BITS));
        !           417:        /*
        !           418:         * ack all before enable, cannot be done in one
        !           419:         * operation as it seems clear is not processed
        !           420:         * if enable is specified.
        !           421:         */
        !           422:        bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !           423:            TWE_CTRL_CHOSTI | TWE_CTRL_CATTNI | TWE_CTRL_CERR);
        !           424:        TWE_DPRINTF(TWE_D_CMD, ("stat=%b ",
        !           425:            bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS), TWE_STAT_BITS));
        !           426:        /* enable interrupts */
        !           427:        bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !           428:            TWE_CTRL_EINT | TWE_CTRL_ERDYI |
        !           429:            /*TWE_CTRL_HOSTI |*/ TWE_CTRL_MCMDI);
        !           430: }
        !           431:
        !           432: void
        !           433: twe_thread(v)
        !           434:        void *v;
        !           435: {
        !           436:        struct twe_softc *sc = v;
        !           437:        struct twe_ccb *ccb;
        !           438:        twe_lock_t lock;
        !           439:        u_int32_t status;
        !           440:        int err;
        !           441:
        !           442:        splbio();
        !           443:        for (;;) {
        !           444:                lock = TWE_LOCK(sc);
        !           445:
        !           446:                while (!TAILQ_EMPTY(&sc->sc_done_ccb)) {
        !           447:                        ccb = TAILQ_FIRST(&sc->sc_done_ccb);
        !           448:                        TAILQ_REMOVE(&sc->sc_done_ccb, ccb, ccb_link);
        !           449:                        if ((err = twe_done(sc, ccb)))
        !           450:                                printf("%s: done failed (%d)\n",
        !           451:                                    sc->sc_dev.dv_xname, err);
        !           452:                }
        !           453:
        !           454:                status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           455:                TWE_DPRINTF(TWE_D_INTR, ("twe_thread stat=%b ",
        !           456:                    status & TWE_STAT_FLAGS, TWE_STAT_BITS));
        !           457:                while (!(status & TWE_STAT_CQF) &&
        !           458:                    !TAILQ_EMPTY(&sc->sc_ccb2q)) {
        !           459:
        !           460:                        ccb = TAILQ_LAST(&sc->sc_ccb2q, twe_queue_head);
        !           461:                        TAILQ_REMOVE(&sc->sc_ccb2q, ccb, ccb_link);
        !           462:
        !           463:                        ccb->ccb_state = TWE_CCB_QUEUED;
        !           464:                        TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link);
        !           465:                        bus_space_write_4(sc->iot, sc->ioh, TWE_COMMANDQUEUE,
        !           466:                            ccb->ccb_cmdpa);
        !           467:
        !           468:                        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           469:                        TWE_DPRINTF(TWE_D_INTR, ("twe_thread stat=%b ",
        !           470:                            status & TWE_STAT_FLAGS, TWE_STAT_BITS));
        !           471:                }
        !           472:
        !           473:                if (!TAILQ_EMPTY(&sc->sc_ccb2q))
        !           474:                        bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !           475:                            TWE_CTRL_ECMDI);
        !           476:
        !           477:                TWE_UNLOCK(sc, lock);
        !           478:                sc->sc_thread_on = 1;
        !           479:                tsleep(sc, PWAIT, "twespank", 0);
        !           480:        }
        !           481: }
        !           482:
        !           483: int
        !           484: twe_cmd(ccb, flags, wait)
        !           485:        struct twe_ccb *ccb;
        !           486:        int flags, wait;
        !           487: {
        !           488:        struct twe_softc *sc = ccb->ccb_sc;
        !           489:        bus_dmamap_t dmap;
        !           490:        struct twe_cmd *cmd;
        !           491:        struct twe_segs *sgp;
        !           492:        int error, i;
        !           493:
        !           494:        if (ccb->ccb_data && ((u_long)ccb->ccb_data & (TWE_ALIGN - 1))) {
        !           495:                TWE_DPRINTF(TWE_D_DMA, ("data=%p is unaligned ",ccb->ccb_data));
        !           496:                ccb->ccb_realdata = ccb->ccb_data;
        !           497:
        !           498:                error = bus_dmamem_alloc(sc->dmat, ccb->ccb_length, PAGE_SIZE,
        !           499:                    0, ccb->ccb_2bseg, TWE_MAXOFFSETS, &ccb->ccb_2nseg,
        !           500:                    BUS_DMA_NOWAIT);
        !           501:                if (error) {
        !           502:                        TWE_DPRINTF(TWE_D_DMA, ("2buf alloc failed(%d) ", error));
        !           503:                        twe_put_ccb(ccb);
        !           504:                        return (ENOMEM);
        !           505:                }
        !           506:
        !           507:                error = bus_dmamem_map(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg,
        !           508:                    ccb->ccb_length, (caddr_t *)&ccb->ccb_data, BUS_DMA_NOWAIT);
        !           509:                if (error) {
        !           510:                        TWE_DPRINTF(TWE_D_DMA, ("2buf map failed(%d) ", error));
        !           511:                        bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg);
        !           512:                        twe_put_ccb(ccb);
        !           513:                        return (ENOMEM);
        !           514:                }
        !           515:                bcopy(ccb->ccb_realdata, ccb->ccb_data, ccb->ccb_length);
        !           516:        } else
        !           517:                ccb->ccb_realdata = NULL;
        !           518:
        !           519:        dmap = ccb->ccb_dmamap;
        !           520:        cmd = ccb->ccb_cmd;
        !           521:        cmd->cmd_status = 0;
        !           522:
        !           523:        if (ccb->ccb_data) {
        !           524:                error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data,
        !           525:                    ccb->ccb_length, NULL, flags);
        !           526:                if (error) {
        !           527:                        if (error == EFBIG)
        !           528:                                printf("more than %d dma segs\n", TWE_MAXOFFSETS);
        !           529:                        else
        !           530:                                printf("error %d loading dma map\n", error);
        !           531:
        !           532:                        if (ccb->ccb_realdata) {
        !           533:                                bus_dmamem_unmap(sc->dmat, ccb->ccb_data,
        !           534:                                    ccb->ccb_length);
        !           535:                                bus_dmamem_free(sc->dmat, ccb->ccb_2bseg,
        !           536:                                    ccb->ccb_2nseg);
        !           537:                        }
        !           538:                        twe_put_ccb(ccb);
        !           539:                        return error;
        !           540:                }
        !           541:                /* load addresses into command */
        !           542:                switch (cmd->cmd_op) {
        !           543:                case TWE_CMD_GPARAM:
        !           544:                case TWE_CMD_SPARAM:
        !           545:                        sgp = cmd->cmd_param.segs;
        !           546:                        break;
        !           547:                case TWE_CMD_READ:
        !           548:                case TWE_CMD_WRITE:
        !           549:                        sgp = cmd->cmd_io.segs;
        !           550:                        break;
        !           551:                default:
        !           552:                        /* no data transfer */
        !           553:                        TWE_DPRINTF(TWE_D_DMA, ("twe_cmd: unknown sgp op=%x\n",
        !           554:                            cmd->cmd_op));
        !           555:                        sgp = NULL;
        !           556:                        break;
        !           557:                }
        !           558:                TWE_DPRINTF(TWE_D_DMA, ("data=%p<", ccb->ccb_data));
        !           559:                if (sgp) {
        !           560:                        /*
        !           561:                         * we know that size is in the upper byte,
        !           562:                         * and we do not worry about overflow
        !           563:                         */
        !           564:                        cmd->cmd_op += (2 * dmap->dm_nsegs) << 8;
        !           565:                        bzero (sgp, TWE_MAXOFFSETS * sizeof(*sgp));
        !           566:                        for (i = 0; i < dmap->dm_nsegs; i++, sgp++) {
        !           567:                                sgp->twes_addr = htole32(dmap->dm_segs[i].ds_addr);
        !           568:                                sgp->twes_len  = htole32(dmap->dm_segs[i].ds_len);
        !           569:                                TWE_DPRINTF(TWE_D_DMA, ("%x[%x] ",
        !           570:                                    dmap->dm_segs[i].ds_addr,
        !           571:                                    dmap->dm_segs[i].ds_len));
        !           572:                        }
        !           573:                }
        !           574:                TWE_DPRINTF(TWE_D_DMA, ("> "));
        !           575:                bus_dmamap_sync(sc->dmat, dmap, 0, dmap->dm_mapsize,
        !           576:                    BUS_DMASYNC_PREWRITE);
        !           577:        }
        !           578:        bus_dmamap_sync(sc->dmat, sc->sc_cmdmap, 0, sc->sc_cmdmap->dm_mapsize,
        !           579:            BUS_DMASYNC_PREWRITE);
        !           580:
        !           581:        if ((error = twe_start(ccb, wait))) {
        !           582:                bus_dmamap_unload(sc->dmat, dmap);
        !           583:                if (ccb->ccb_realdata) {
        !           584:                        bus_dmamem_unmap(sc->dmat, ccb->ccb_data,
        !           585:                            ccb->ccb_length);
        !           586:                        bus_dmamem_free(sc->dmat, ccb->ccb_2bseg,
        !           587:                            ccb->ccb_2nseg);
        !           588:                }
        !           589:                twe_put_ccb(ccb);
        !           590:                return (error);
        !           591:        }
        !           592:
        !           593:        return wait? twe_complete(ccb) : 0;
        !           594: }
        !           595:
        !           596: int
        !           597: twe_start(ccb, wait)
        !           598:        struct twe_ccb *ccb;
        !           599:        int wait;
        !           600: {
        !           601:        struct twe_softc*sc = ccb->ccb_sc;
        !           602:        struct twe_cmd  *cmd = ccb->ccb_cmd;
        !           603:        u_int32_t       status;
        !           604:        int i;
        !           605:
        !           606:        cmd->cmd_op = htole16(cmd->cmd_op);
        !           607:
        !           608:        if (!wait) {
        !           609:
        !           610:                TWE_DPRINTF(TWE_D_CMD, ("prequeue(%d) ", cmd->cmd_index));
        !           611:                ccb->ccb_state = TWE_CCB_PREQUEUED;
        !           612:                TAILQ_INSERT_TAIL(&sc->sc_ccb2q, ccb, ccb_link);
        !           613:                wakeup(sc);
        !           614:                return 0;
        !           615:        }
        !           616:
        !           617:        for (i = 1000; i--; DELAY(10)) {
        !           618:
        !           619:                status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           620:                if (!(status & TWE_STAT_CQF))
        !           621:                        break;
        !           622:                TWE_DPRINTF(TWE_D_CMD,  ("twe_start stat=%b ",
        !           623:                    status & TWE_STAT_FLAGS, TWE_STAT_BITS));
        !           624:        }
        !           625:
        !           626:        if (!(status & TWE_STAT_CQF)) {
        !           627:                bus_space_write_4(sc->iot, sc->ioh, TWE_COMMANDQUEUE,
        !           628:                    ccb->ccb_cmdpa);
        !           629:
        !           630:                TWE_DPRINTF(TWE_D_CMD, ("queue(%d) ", cmd->cmd_index));
        !           631:                ccb->ccb_state = TWE_CCB_QUEUED;
        !           632:                TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link);
        !           633:                return 0;
        !           634:
        !           635:        } else {
        !           636:
        !           637:                printf("%s: twe_start(%d) timed out\n",
        !           638:                    sc->sc_dev.dv_xname, cmd->cmd_index);
        !           639:
        !           640:                return 1;
        !           641:        }
        !           642: }
        !           643:
        !           644: int
        !           645: twe_complete(ccb)
        !           646:        struct twe_ccb *ccb;
        !           647: {
        !           648:        struct twe_softc *sc = ccb->ccb_sc;
        !           649:        struct scsi_xfer *xs = ccb->ccb_xs;
        !           650:        int i;
        !           651:
        !           652:        for (i = 100 * (xs? xs->timeout : 35000); i--; DELAY(10)) {
        !           653:                u_int32_t status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           654:
        !           655:                /* TWE_DPRINTF(TWE_D_CMD,  ("twe_intr stat=%b ",
        !           656:                    status & TWE_STAT_FLAGS, TWE_STAT_BITS)); */
        !           657:
        !           658:                while (!(status & TWE_STAT_RQE)) {
        !           659:                        struct twe_ccb *ccb1;
        !           660:                        u_int32_t ready;
        !           661:
        !           662:                        ready = bus_space_read_4(sc->iot, sc->ioh,
        !           663:                            TWE_READYQUEUE);
        !           664:
        !           665:                        TWE_DPRINTF(TWE_D_CMD, ("ready=%x ", ready));
        !           666:
        !           667:                        ccb1 = &sc->sc_ccbs[TWE_READYID(ready)];
        !           668:                        TAILQ_REMOVE(&sc->sc_ccbq, ccb1, ccb_link);
        !           669:                        ccb1->ccb_state = TWE_CCB_DONE;
        !           670:                        if (!twe_done(sc, ccb1) && ccb1 == ccb) {
        !           671:                                TWE_DPRINTF(TWE_D_CMD, ("complete\n"));
        !           672:                                return 0;
        !           673:                        }
        !           674:
        !           675:                        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           676:                        /* TWE_DPRINTF(TWE_D_CMD,  ("twe_intr stat=%b ",
        !           677:                            status & TWE_STAT_FLAGS, TWE_STAT_BITS)); */
        !           678:                }
        !           679:        }
        !           680:
        !           681:        return 1;
        !           682: }
        !           683:
        !           684: int
        !           685: twe_done(sc, ccb)
        !           686:        struct twe_softc *sc;
        !           687:        struct twe_ccb *ccb;
        !           688: {
        !           689:        struct twe_cmd *cmd = ccb->ccb_cmd;
        !           690:        struct scsi_xfer *xs = ccb->ccb_xs;
        !           691:        bus_dmamap_t    dmap;
        !           692:        twe_lock_t      lock;
        !           693:
        !           694:        TWE_DPRINTF(TWE_D_CMD, ("done(%d) ", cmd->cmd_index));
        !           695:
        !           696:        if (ccb->ccb_state != TWE_CCB_DONE) {
        !           697:                printf("%s: undone ccb %d ready\n",
        !           698:                     sc->sc_dev.dv_xname, cmd->cmd_index);
        !           699:                return 1;
        !           700:        }
        !           701:
        !           702:        dmap = ccb->ccb_dmamap;
        !           703:        if (xs) {
        !           704:                if (xs->cmd->opcode != PREVENT_ALLOW &&
        !           705:                    xs->cmd->opcode != SYNCHRONIZE_CACHE) {
        !           706:                        bus_dmamap_sync(sc->dmat, dmap, 0,
        !           707:                            dmap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?
        !           708:                            BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !           709:                        bus_dmamap_unload(sc->dmat, dmap);
        !           710:                }
        !           711:        } else {
        !           712:                switch (letoh16(cmd->cmd_op)) {
        !           713:                case TWE_CMD_GPARAM:
        !           714:                case TWE_CMD_READ:
        !           715:                        bus_dmamap_sync(sc->dmat, dmap, 0,
        !           716:                            dmap->dm_mapsize, BUS_DMASYNC_POSTREAD);
        !           717:                        bus_dmamap_unload(sc->dmat, dmap);
        !           718:                        break;
        !           719:                case TWE_CMD_SPARAM:
        !           720:                case TWE_CMD_WRITE:
        !           721:                        bus_dmamap_sync(sc->dmat, dmap, 0,
        !           722:                            dmap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
        !           723:                        bus_dmamap_unload(sc->dmat, dmap);
        !           724:                        break;
        !           725:                default:
        !           726:                        /* no data */
        !           727:                        break;
        !           728:                }
        !           729:        }
        !           730:
        !           731:        if (ccb->ccb_realdata) {
        !           732:                bcopy(ccb->ccb_data, ccb->ccb_realdata, ccb->ccb_length);
        !           733:                bus_dmamem_unmap(sc->dmat, ccb->ccb_data, ccb->ccb_length);
        !           734:                bus_dmamem_free(sc->dmat, ccb->ccb_2bseg, ccb->ccb_2nseg);
        !           735:        }
        !           736:
        !           737:        lock = TWE_LOCK(sc);
        !           738:        twe_put_ccb(ccb);
        !           739:
        !           740:        if (xs) {
        !           741:                xs->resid = 0;
        !           742:                xs->flags |= ITSDONE;
        !           743:                scsi_done(xs);
        !           744:        }
        !           745:        TWE_UNLOCK(sc, lock);
        !           746:
        !           747:        return 0;
        !           748: }
        !           749:
        !           750: void
        !           751: tweminphys(bp)
        !           752:        struct buf *bp;
        !           753: {
        !           754:        if (bp->b_bcount > TWE_MAXFER)
        !           755:                bp->b_bcount = TWE_MAXFER;
        !           756:        minphys(bp);
        !           757: }
        !           758:
        !           759: void
        !           760: twe_copy_internal_data(xs, v, size)
        !           761:        struct scsi_xfer *xs;
        !           762:        void *v;
        !           763:        size_t size;
        !           764: {
        !           765:        size_t copy_cnt;
        !           766:
        !           767:        TWE_DPRINTF(TWE_D_MISC, ("twe_copy_internal_data "));
        !           768:
        !           769:        if (!xs->datalen)
        !           770:                printf("uio move is not yet supported\n");
        !           771:        else {
        !           772:                copy_cnt = MIN(size, xs->datalen);
        !           773:                bcopy(v, xs->data, copy_cnt);
        !           774:        }
        !           775: }
        !           776:
        !           777: int
        !           778: twe_scsi_cmd(xs)
        !           779:        struct scsi_xfer *xs;
        !           780: {
        !           781:        struct scsi_link *link = xs->sc_link;
        !           782:        struct twe_softc *sc = link->adapter_softc;
        !           783:        struct twe_ccb *ccb;
        !           784:        struct twe_cmd *cmd;
        !           785:        struct scsi_inquiry_data inq;
        !           786:        struct scsi_sense_data sd;
        !           787:        struct scsi_read_cap_data rcd;
        !           788:        u_int8_t target = link->target;
        !           789:        u_int32_t blockno, blockcnt;
        !           790:        struct scsi_rw *rw;
        !           791:        struct scsi_rw_big *rwb;
        !           792:        int error, op, flags, wait;
        !           793:        twe_lock_t lock;
        !           794:
        !           795:
        !           796:        if (target >= TWE_MAX_UNITS || !sc->sc_hdr[target].hd_present ||
        !           797:            link->lun != 0) {
        !           798:                xs->error = XS_DRIVER_STUFFUP;
        !           799:                return (COMPLETE);
        !           800:        }
        !           801:
        !           802:        TWE_DPRINTF(TWE_D_CMD, ("twe_scsi_cmd "));
        !           803:
        !           804:        xs->error = XS_NOERROR;
        !           805:
        !           806:        switch (xs->cmd->opcode) {
        !           807:        case TEST_UNIT_READY:
        !           808:        case START_STOP:
        !           809: #if 0
        !           810:        case VERIFY:
        !           811: #endif
        !           812:                TWE_DPRINTF(TWE_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
        !           813:                    target));
        !           814:                break;
        !           815:
        !           816:        case REQUEST_SENSE:
        !           817:                TWE_DPRINTF(TWE_D_CMD, ("REQUEST SENSE tgt %d ", target));
        !           818:                bzero(&sd, sizeof sd);
        !           819:                sd.error_code = 0x70;
        !           820:                sd.segment = 0;
        !           821:                sd.flags = SKEY_NO_SENSE;
        !           822:                *(u_int32_t*)sd.info = htole32(0);
        !           823:                sd.extra_len = 0;
        !           824:                twe_copy_internal_data(xs, &sd, sizeof sd);
        !           825:                break;
        !           826:
        !           827:        case INQUIRY:
        !           828:                TWE_DPRINTF(TWE_D_CMD, ("INQUIRY tgt %d devtype %x ", target,
        !           829:                    sc->sc_hdr[target].hd_devtype));
        !           830:                bzero(&inq, sizeof inq);
        !           831:                inq.device =
        !           832:                    (sc->sc_hdr[target].hd_devtype & 4) ? T_CDROM : T_DIRECT;
        !           833:                inq.dev_qual2 =
        !           834:                    (sc->sc_hdr[target].hd_devtype & 1) ? SID_REMOVABLE : 0;
        !           835:                inq.version = 2;
        !           836:                inq.response_format = 2;
        !           837:                inq.additional_length = 32;
        !           838:                strlcpy(inq.vendor, "3WARE  ", sizeof inq.vendor);
        !           839:                snprintf(inq.product, sizeof inq.product, "Host drive  #%02d",
        !           840:                    target);
        !           841:                strlcpy(inq.revision, "   ", sizeof inq.revision);
        !           842:                twe_copy_internal_data(xs, &inq, sizeof inq);
        !           843:                break;
        !           844:
        !           845:        case READ_CAPACITY:
        !           846:                TWE_DPRINTF(TWE_D_CMD, ("READ CAPACITY tgt %d ", target));
        !           847:                bzero(&rcd, sizeof rcd);
        !           848:                _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr);
        !           849:                _lto4b(TWE_SECTOR_SIZE, rcd.length);
        !           850:                twe_copy_internal_data(xs, &rcd, sizeof rcd);
        !           851:                break;
        !           852:
        !           853:        case PREVENT_ALLOW:
        !           854:                TWE_DPRINTF(TWE_D_CMD, ("PREVENT/ALLOW "));
        !           855:                return (COMPLETE);
        !           856:
        !           857:        case READ_COMMAND:
        !           858:        case READ_BIG:
        !           859:        case WRITE_COMMAND:
        !           860:        case WRITE_BIG:
        !           861:        case SYNCHRONIZE_CACHE:
        !           862:                lock = TWE_LOCK(sc);
        !           863:
        !           864:                flags = 0;
        !           865:                if (xs->cmd->opcode != SYNCHRONIZE_CACHE) {
        !           866:                        /* A read or write operation. */
        !           867:                        if (xs->cmdlen == 6) {
        !           868:                                rw = (struct scsi_rw *)xs->cmd;
        !           869:                                blockno = _3btol(rw->addr) &
        !           870:                                    (SRW_TOPADDR << 16 | 0xffff);
        !           871:                                blockcnt = rw->length ? rw->length : 0x100;
        !           872:                        } else {
        !           873:                                rwb = (struct scsi_rw_big *)xs->cmd;
        !           874:                                blockno = _4btol(rwb->addr);
        !           875:                                blockcnt = _2btol(rwb->length);
        !           876:                                /* reflect DPO & FUA flags */
        !           877:                                if (xs->cmd->opcode == WRITE_BIG &&
        !           878:                                    rwb->byte2 & 0x18)
        !           879:                                        flags = TWE_FLAGS_CACHEDISABLE;
        !           880:                        }
        !           881:                        if (blockno >= sc->sc_hdr[target].hd_size ||
        !           882:                            blockno + blockcnt > sc->sc_hdr[target].hd_size) {
        !           883:                                printf("%s: out of bounds %u-%u >= %u\n",
        !           884:                                    sc->sc_dev.dv_xname, blockno, blockcnt,
        !           885:                                    sc->sc_hdr[target].hd_size);
        !           886:                                xs->error = XS_DRIVER_STUFFUP;
        !           887:                                scsi_done(xs);
        !           888:                                TWE_UNLOCK(sc, lock);
        !           889:                                return (COMPLETE);
        !           890:                        }
        !           891:                }
        !           892:
        !           893:                switch (xs->cmd->opcode) {
        !           894:                case READ_COMMAND:      op = TWE_CMD_READ;      break;
        !           895:                case READ_BIG:          op = TWE_CMD_READ;      break;
        !           896:                case WRITE_COMMAND:     op = TWE_CMD_WRITE;     break;
        !           897:                case WRITE_BIG:         op = TWE_CMD_WRITE;     break;
        !           898:                default:                op = TWE_CMD_NOP;       break;
        !           899:                }
        !           900:
        !           901:                if ((ccb = twe_get_ccb(sc)) == NULL) {
        !           902:                        xs->error = XS_DRIVER_STUFFUP;
        !           903:                        scsi_done(xs);
        !           904:                        TWE_UNLOCK(sc, lock);
        !           905:                        return (COMPLETE);
        !           906:                }
        !           907:
        !           908:                ccb->ccb_xs = xs;
        !           909:                ccb->ccb_data = xs->data;
        !           910:                ccb->ccb_length = xs->datalen;
        !           911:                ccb->ccb_state = TWE_CCB_READY;
        !           912:                cmd = ccb->ccb_cmd;
        !           913:                cmd->cmd_unit_host = TWE_UNITHOST(target, 0); /* XXX why 0? */
        !           914:                cmd->cmd_op = op;
        !           915:                cmd->cmd_flags = flags;
        !           916:                cmd->cmd_io.count = htole16(blockcnt);
        !           917:                cmd->cmd_io.lba = htole32(blockno);
        !           918:                wait = xs->flags & SCSI_POLL;
        !           919:                if (!sc->sc_thread_on)
        !           920:                        wait |= SCSI_POLL;
        !           921:
        !           922:                if ((error = twe_cmd(ccb, ((xs->flags & SCSI_NOSLEEP)?
        !           923:                    BUS_DMA_NOWAIT : BUS_DMA_WAITOK), wait))) {
        !           924:
        !           925:                        TWE_UNLOCK(sc, lock);
        !           926:                        TWE_DPRINTF(TWE_D_CMD, ("failed %p ", xs));
        !           927:                        if (xs->flags & SCSI_POLL) {
        !           928:                                return (TRY_AGAIN_LATER);
        !           929:                        } else {
        !           930:                                xs->error = XS_DRIVER_STUFFUP;
        !           931:                                scsi_done(xs);
        !           932:                                return (COMPLETE);
        !           933:                        }
        !           934:                }
        !           935:
        !           936:                TWE_UNLOCK(sc, lock);
        !           937:
        !           938:                if (wait & SCSI_POLL)
        !           939:                        return (COMPLETE);
        !           940:                else
        !           941:                        return (SUCCESSFULLY_QUEUED);
        !           942:
        !           943:        default:
        !           944:                TWE_DPRINTF(TWE_D_CMD, ("unsupported scsi command %#x tgt %d ",
        !           945:                    xs->cmd->opcode, target));
        !           946:                xs->error = XS_DRIVER_STUFFUP;
        !           947:        }
        !           948:
        !           949:        return (COMPLETE);
        !           950: }
        !           951:
        !           952: int
        !           953: twe_intr(v)
        !           954:        void *v;
        !           955: {
        !           956:        struct twe_softc *sc = v;
        !           957:        struct twe_ccb  *ccb;
        !           958:        struct twe_cmd  *cmd;
        !           959:        u_int32_t       status;
        !           960:        twe_lock_t      lock;
        !           961:        int             rv = 0;
        !           962:
        !           963:        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           964:        TWE_DPRINTF(TWE_D_INTR,  ("twe_intr stat=%b ",
        !           965:            status & TWE_STAT_FLAGS, TWE_STAT_BITS));
        !           966: #if 0
        !           967:        if (status & TWE_STAT_HOSTI) {
        !           968:
        !           969:                bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !           970:                    TWE_CTRL_CHOSTI);
        !           971:        }
        !           972: #endif
        !           973:
        !           974:        if (status & TWE_STAT_RDYI) {
        !           975:
        !           976:                while (!(status & TWE_STAT_RQE)) {
        !           977:
        !           978:                        u_int32_t ready;
        !           979:
        !           980:                        /*
        !           981:                         * it seems that reading ready queue
        !           982:                         * we get all the status bits in each ready word.
        !           983:                         * i wonder if it's legal to use those for
        !           984:                         * status and avoid extra read below
        !           985:                         */
        !           986:                        ready = bus_space_read_4(sc->iot, sc->ioh,
        !           987:                            TWE_READYQUEUE);
        !           988:
        !           989:                        ccb = &sc->sc_ccbs[TWE_READYID(ready)];
        !           990:                        TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link);
        !           991:                        ccb->ccb_state = TWE_CCB_DONE;
        !           992:                        TAILQ_INSERT_TAIL(&sc->sc_done_ccb, ccb, ccb_link);
        !           993:                        rv++;
        !           994:
        !           995:                        status = bus_space_read_4(sc->iot, sc->ioh, TWE_STATUS);
        !           996:                        TWE_DPRINTF(TWE_D_INTR, ("twe_intr stat=%b ",
        !           997:                            status & TWE_STAT_FLAGS, TWE_STAT_BITS));
        !           998:                }
        !           999:        }
        !          1000:
        !          1001:        if (status & TWE_STAT_CMDI) {
        !          1002:                rv++;
        !          1003:                bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !          1004:                    TWE_CTRL_MCMDI);
        !          1005:        }
        !          1006:
        !          1007:        if (rv)
        !          1008:                wakeup(sc);
        !          1009:
        !          1010:        if (status & TWE_STAT_ATTNI) {
        !          1011:                u_int16_t aen;
        !          1012:
        !          1013:                /*
        !          1014:                 * we know no attentions of interest right now.
        !          1015:                 * one of those would be mirror degradation i think.
        !          1016:                 * or, what else exists in there?
        !          1017:                 * maybe 3ware can answer that?
        !          1018:                 */
        !          1019:                bus_space_write_4(sc->iot, sc->ioh, TWE_CONTROL,
        !          1020:                    TWE_CTRL_CATTNI);
        !          1021:
        !          1022:                lock = TWE_LOCK(sc);
        !          1023:                for (aen = -1; aen != TWE_AEN_QEMPTY; ) {
        !          1024:                        u_int8_t param_buf[2 * TWE_SECTOR_SIZE + TWE_ALIGN - 1];
        !          1025:                        struct twe_param *pb = (void *) (((u_long)param_buf +
        !          1026:                            TWE_ALIGN - 1) & ~(TWE_ALIGN - 1));
        !          1027:
        !          1028:                        if ((ccb = twe_get_ccb(sc)) == NULL)
        !          1029:                                break;
        !          1030:
        !          1031:                        ccb->ccb_xs = NULL;
        !          1032:                        ccb->ccb_data = pb;
        !          1033:                        ccb->ccb_length = TWE_SECTOR_SIZE;
        !          1034:                        ccb->ccb_state = TWE_CCB_READY;
        !          1035:                        cmd = ccb->ccb_cmd;
        !          1036:                        cmd->cmd_unit_host = TWE_UNITHOST(0, 0);
        !          1037:                        cmd->cmd_op = TWE_CMD_GPARAM;
        !          1038:                        cmd->cmd_flags = 0;
        !          1039:                        cmd->cmd_param.count = 1;
        !          1040:
        !          1041:                        pb->table_id = TWE_PARAM_AEN;
        !          1042:                        pb->param_id = 2;
        !          1043:                        pb->param_size = 2;
        !          1044:                        if (twe_cmd(ccb, BUS_DMA_NOWAIT, 1)) {
        !          1045:                                printf(": error draining attention queue\n");
        !          1046:                                break;
        !          1047:                        }
        !          1048:                        aen = *(u_int16_t *)pb->data;
        !          1049:                        TWE_DPRINTF(TWE_D_AEN, ("aen=%x ", aen));
        !          1050:                }
        !          1051:                TWE_UNLOCK(sc, lock);
        !          1052:        }
        !          1053:
        !          1054:        return rv;
        !          1055: }

CVSweb