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

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

1.1     ! nbrk        1: /*     $OpenBSD: cac.c,v 1.23 2006/11/28 23:59:45 dlg Exp $    */
        !             2: /*     $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $      */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 2001,2003 Michael Shalayeff
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * The SCSI emulation layer is derived from gdt(4) driver,
        !             9:  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
        !            10:  *
        !            11:  * Redistribution and use in source and binary forms, with or without
        !            12:  * modification, are permitted provided that the following conditions
        !            13:  * are met:
        !            14:  * 1. Redistributions of source code must retain the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer.
        !            16:  * 2. Redistributions in binary form must reproduce the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer in the
        !            18:  *    documentation and/or other materials provided with the distribution.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            21:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            22:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            23:  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
        !            24:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            25:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            26:  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            28:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
        !            29:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            30:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            31:  */
        !            32: /*-
        !            33:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
        !            34:  * All rights reserved.
        !            35:  *
        !            36:  * This code is derived from software contributed to The NetBSD Foundation
        !            37:  * by Andrew Doran.
        !            38:  *
        !            39:  * Redistribution and use in source and binary forms, with or without
        !            40:  * modification, are permitted provided that the following conditions
        !            41:  * are met:
        !            42:  * 1. Redistributions of source code must retain the above copyright
        !            43:  *    notice, this list of conditions and the following disclaimer.
        !            44:  * 2. Redistributions in binary form must reproduce the above copyright
        !            45:  *    notice, this list of conditions and the following disclaimer in the
        !            46:  *    documentation and/or other materials provided with the distribution.
        !            47:  * 3. All advertising materials mentioning features or use of this software
        !            48:  *    must display the following acknowledgement:
        !            49:  *        This product includes software developed by the NetBSD
        !            50:  *        Foundation, Inc. and its contributors.
        !            51:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            52:  *    contributors may be used to endorse or promote products derived
        !            53:  *    from this software without specific prior written permission.
        !            54:  *
        !            55:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            56:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            57:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            58:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            59:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            60:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            61:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            62:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            63:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            64:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            65:  * POSSIBILITY OF SUCH DAMAGE.
        !            66:  */
        !            67:
        !            68: /*
        !            69:  * Driver for Compaq array controllers.
        !            70:  */
        !            71:
        !            72: /* #define     CAC_DEBUG */
        !            73:
        !            74: #include <sys/param.h>
        !            75: #include <sys/systm.h>
        !            76: #include <sys/kernel.h>
        !            77: #include <sys/device.h>
        !            78: #include <sys/queue.h>
        !            79: #include <sys/proc.h>
        !            80: #include <sys/buf.h>
        !            81: #include <sys/endian.h>
        !            82: #include <sys/malloc.h>
        !            83: #include <sys/pool.h>
        !            84:
        !            85: #include <machine/bus.h>
        !            86:
        !            87: #include <scsi/scsi_all.h>
        !            88: #include <scsi/scsi_disk.h>
        !            89: #include <scsi/scsiconf.h>
        !            90:
        !            91: #include <dev/ic/cacreg.h>
        !            92: #include <dev/ic/cacvar.h>
        !            93:
        !            94: struct cfdriver cac_cd = {
        !            95:        NULL, "cac", DV_DULL
        !            96: };
        !            97:
        !            98: int     cac_scsi_cmd(struct scsi_xfer *);
        !            99: void   cacminphys(struct buf *bp);
        !           100:
        !           101: struct scsi_adapter cac_switch = {
        !           102:        cac_scsi_cmd, cacminphys, 0, 0,
        !           103: };
        !           104:
        !           105: struct scsi_device cac_dev = {
        !           106:        NULL, NULL, NULL, NULL
        !           107: };
        !           108:
        !           109: struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int);
        !           110: void   cac_ccb_done(struct cac_softc *, struct cac_ccb *);
        !           111: void   cac_ccb_free(struct cac_softc *, struct cac_ccb *);
        !           112: int    cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
        !           113: int    cac_ccb_start(struct cac_softc *, struct cac_ccb *);
        !           114: int    cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
        !           115:        int drive, int blkno, int flags, struct scsi_xfer *xs);
        !           116: int    cac_get_dinfo(struct cac_softc *sc, int target);
        !           117: int    cac_flush(struct cac_softc *sc);
        !           118: void   cac_shutdown(void *);
        !           119: void   cac_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
        !           120:
        !           121: struct cac_ccb *cac_l0_completed(struct cac_softc *);
        !           122: int    cac_l0_fifo_full(struct cac_softc *);
        !           123: void   cac_l0_intr_enable(struct cac_softc *, int);
        !           124: int    cac_l0_intr_pending(struct cac_softc *);
        !           125: void   cac_l0_submit(struct cac_softc *, struct cac_ccb *);
        !           126:
        !           127: void   *cac_sdh;       /* shutdown hook */
        !           128:
        !           129: const
        !           130: struct cac_linkage cac_l0 = {
        !           131:        cac_l0_completed,
        !           132:        cac_l0_fifo_full,
        !           133:        cac_l0_intr_enable,
        !           134:        cac_l0_intr_pending,
        !           135:        cac_l0_submit
        !           136: };
        !           137:
        !           138: /*
        !           139:  * Initialise our interface to the controller.
        !           140:  */
        !           141: int
        !           142: cac_init(struct cac_softc *sc, int startfw)
        !           143: {
        !           144:        struct scsibus_attach_args saa;
        !           145:        struct cac_controller_info cinfo;
        !           146:        int error, rseg, size, i;
        !           147:        bus_dma_segment_t seg[1];
        !           148:        struct cac_ccb *ccb;
        !           149:
        !           150:        SIMPLEQ_INIT(&sc->sc_ccb_free);
        !           151:        SIMPLEQ_INIT(&sc->sc_ccb_queue);
        !           152:
        !           153:         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
        !           154:
        !           155:        if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
        !           156:            &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           157:                printf("%s: unable to allocate CCBs, error = %d\n",
        !           158:                    sc->sc_dv.dv_xname, error);
        !           159:                return (-1);
        !           160:        }
        !           161:
        !           162:        if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
        !           163:            &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
        !           164:                printf("%s: unable to map CCBs, error = %d\n",
        !           165:                    sc->sc_dv.dv_xname, error);
        !           166:                return (-1);
        !           167:        }
        !           168:
        !           169:        if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
        !           170:            BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
        !           171:                printf("%s: unable to create CCB DMA map, error = %d\n",
        !           172:                    sc->sc_dv.dv_xname, error);
        !           173:                return (-1);
        !           174:        }
        !           175:
        !           176:        if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
        !           177:            size, NULL, BUS_DMA_NOWAIT)) != 0) {
        !           178:                printf("%s: unable to load CCB DMA map, error = %d\n",
        !           179:                    sc->sc_dv.dv_xname, error);
        !           180:                return (-1);
        !           181:        }
        !           182:
        !           183:        sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
        !           184:        memset(sc->sc_ccbs, 0, size);
        !           185:        ccb = (struct cac_ccb *)sc->sc_ccbs;
        !           186:
        !           187:        for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
        !           188:                /* Create the DMA map for this CCB's data */
        !           189:                error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
        !           190:                    CAC_SG_SIZE, CAC_MAX_XFER, 0,
        !           191:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
        !           192:                    &ccb->ccb_dmamap_xfer);
        !           193:
        !           194:                if (error) {
        !           195:                        printf("%s: can't create ccb dmamap (%d)\n",
        !           196:                            sc->sc_dv.dv_xname, error);
        !           197:                        break;
        !           198:                }
        !           199:
        !           200:                ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
        !           201:                SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
        !           202:        }
        !           203:
        !           204:        /* Start firmware background tasks, if needed. */
        !           205:        if (startfw) {
        !           206:                if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
        !           207:                    0, 0, CAC_CCB_DATA_IN, NULL)) {
        !           208:                        printf("%s: CAC_CMD_START_FIRMWARE failed\n",
        !           209:                            sc->sc_dv.dv_xname);
        !           210:                        return (-1);
        !           211:                }
        !           212:        }
        !           213:
        !           214:        if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
        !           215:            CAC_CCB_DATA_IN, NULL)) {
        !           216:                printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
        !           217:                    sc->sc_dv.dv_xname);
        !           218:                return (-1);
        !           219:        }
        !           220:
        !           221:        if (!cinfo.num_drvs) {
        !           222:                printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
        !           223:                return (-1);
        !           224:        }
        !           225:
        !           226:        sc->sc_nunits = cinfo.num_drvs;
        !           227:        sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info),
        !           228:            M_DEVBUF, M_NOWAIT);
        !           229:        if (sc->sc_dinfos == NULL) {
        !           230:                printf("%s: cannot allocate memory for drive_info\n",
        !           231:                    sc->sc_dv.dv_xname);
        !           232:                return (-1);
        !           233:        }
        !           234:        bzero(sc->sc_dinfos, cinfo.num_drvs * sizeof(struct cac_drive_info));
        !           235:
        !           236:        sc->sc_link.adapter_softc = sc;
        !           237:        sc->sc_link.adapter = &cac_switch;
        !           238:        sc->sc_link.adapter_target = cinfo.num_drvs;
        !           239:        sc->sc_link.adapter_buswidth = cinfo.num_drvs;
        !           240:        sc->sc_link.device = &cac_dev;
        !           241:        sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
        !           242:        if (sc->sc_link.openings < 4 )
        !           243:                sc->sc_link.openings = 4;
        !           244:
        !           245:        bzero(&saa, sizeof(saa));
        !           246:        saa.saa_sc_link = &sc->sc_link;
        !           247:
        !           248:        config_found(&sc->sc_dv, &saa, scsiprint);
        !           249:
        !           250:        /* Set our `shutdownhook' before we start any device activity. */
        !           251:        if (cac_sdh == NULL)
        !           252:                cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
        !           253:
        !           254:        (*sc->sc_cl->cl_intr_enable)(sc, 1);
        !           255:
        !           256:        return (0);
        !           257: }
        !           258:
        !           259: int
        !           260: cac_flush(sc)
        !           261:        struct cac_softc *sc;
        !           262: {
        !           263:        u_int8_t buf[512];
        !           264:
        !           265:        memset(buf, 0, sizeof(buf));
        !           266:        buf[0] = 1;
        !           267:        return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
        !           268:            CAC_CCB_DATA_OUT, NULL);
        !           269: }
        !           270:
        !           271: /*
        !           272:  * Shut down all `cac' controllers.
        !           273:  */
        !           274: void
        !           275: cac_shutdown(void *cookie)
        !           276: {
        !           277:        extern struct cfdriver cac_cd;
        !           278:        struct cac_softc *sc;
        !           279:        int i;
        !           280:
        !           281:        for (i = 0; i < cac_cd.cd_ndevs; i++) {
        !           282:                if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL)
        !           283:                        continue;
        !           284:                cac_flush(sc);
        !           285:        }
        !           286: }
        !           287:
        !           288: /*
        !           289:  * Handle an interrupt from the controller: process finished CCBs and
        !           290:  * dequeue any waiting CCBs.
        !           291:  */
        !           292: int
        !           293: cac_intr(v)
        !           294:        void *v;
        !           295: {
        !           296:        struct cac_softc *sc = v;
        !           297:        struct cac_ccb *ccb;
        !           298:        int istat, ret = 0;
        !           299:
        !           300:        if (!(istat = (sc->sc_cl->cl_intr_pending)(sc)))
        !           301:                return 0;
        !           302:
        !           303:        if (istat & CAC_INTR_FIFO_NEMPTY)
        !           304:                while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
        !           305:                        ret = 1;
        !           306:                        cac_ccb_done(sc, ccb);
        !           307:                }
        !           308:        cac_ccb_start(sc, NULL);
        !           309:
        !           310:        return (ret);
        !           311: }
        !           312:
        !           313: /*
        !           314:  * Execute a [polled] command.
        !           315:  */
        !           316: int
        !           317: cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
        !           318:        int drive, int blkno, int flags, struct scsi_xfer *xs)
        !           319: {
        !           320:        struct cac_ccb *ccb;
        !           321:        struct cac_sgb *sgb;
        !           322:        int i, rv, size, nsegs;
        !           323:
        !           324: #ifdef CAC_DEBUG
        !           325:        printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
        !           326:            command, drive, blkno, data, datasize, flags, xs);
        !           327: #endif
        !           328:
        !           329:        if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) {
        !           330:                printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
        !           331:                return (ENOMEM);
        !           332:        }
        !           333:
        !           334:        if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
        !           335:                bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
        !           336:                    (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
        !           337:
        !           338:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
        !           339:                    ccb->ccb_dmamap_xfer->dm_mapsize,
        !           340:                    (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
        !           341:                    BUS_DMASYNC_PREWRITE);
        !           342:
        !           343:                sgb = ccb->ccb_seg;
        !           344:                nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
        !           345:                if (nsegs > CAC_SG_SIZE)
        !           346:                        panic("cac_cmd: nsegs botch");
        !           347:
        !           348:                size = 0;
        !           349:                for (i = 0; i < nsegs; i++, sgb++) {
        !           350:                        size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
        !           351:                        sgb->length =
        !           352:                            htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
        !           353:                        sgb->addr =
        !           354:                            htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
        !           355:                }
        !           356:        } else {
        !           357:                size = datasize;
        !           358:                nsegs = 0;
        !           359:        }
        !           360:
        !           361:        ccb->ccb_hdr.drive = drive;
        !           362:        ccb->ccb_hdr.priority = 0;
        !           363:        ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
        !           364:            sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
        !           365:
        !           366:        ccb->ccb_req.next = 0;
        !           367:        ccb->ccb_req.command = command;
        !           368:        ccb->ccb_req.error = 0;
        !           369:        ccb->ccb_req.blkno = htole32(blkno);
        !           370:        ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
        !           371:        ccb->ccb_req.sgcount = nsegs;
        !           372:        ccb->ccb_req.reserved = 0;
        !           373:
        !           374:        ccb->ccb_flags = flags;
        !           375:        ccb->ccb_datasize = size;
        !           376:        ccb->ccb_xs = xs;
        !           377:
        !           378:        if (!xs || xs->flags & SCSI_POLL) {
        !           379:
        !           380:                /* Synchronous commands musn't wait. */
        !           381:                if ((*sc->sc_cl->cl_fifo_full)(sc)) {
        !           382:                        cac_ccb_free(sc, ccb);
        !           383:                        rv = -1;
        !           384:                } else {
        !           385:                        ccb->ccb_flags |= CAC_CCB_ACTIVE;
        !           386:                        (*sc->sc_cl->cl_submit)(sc, ccb);
        !           387:                        rv = cac_ccb_poll(sc, ccb, 2000);
        !           388:                }
        !           389:        } else
        !           390:                rv = cac_ccb_start(sc, ccb);
        !           391:
        !           392:        return (rv);
        !           393: }
        !           394:
        !           395: /*
        !           396:  * Wait for the specified CCB to complete.  Must be called at splbio.
        !           397:  */
        !           398: int
        !           399: cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
        !           400: {
        !           401:        struct cac_ccb *ccb;
        !           402:        int t = timo * 10;
        !           403:
        !           404:        do {
        !           405:                for (; t--; DELAY(100))
        !           406:                        if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
        !           407:                                break;
        !           408:                if (t < 0) {
        !           409:                        printf("%s: timeout\n", sc->sc_dv.dv_xname);
        !           410:                        return (EBUSY);
        !           411:                }
        !           412:                cac_ccb_done(sc, ccb);
        !           413:        } while (ccb != wantccb);
        !           414:
        !           415:        return (0);
        !           416: }
        !           417:
        !           418: /*
        !           419:  * Enqueue the specified command (if any) and attempt to start all enqueued
        !           420:  * commands.  Must be called at splbio.
        !           421:  */
        !           422: int
        !           423: cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
        !           424: {
        !           425:        if (ccb != NULL)
        !           426:                SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
        !           427:
        !           428:        while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL &&
        !           429:            !(*sc->sc_cl->cl_fifo_full)(sc)) {
        !           430:                SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
        !           431:                ccb->ccb_flags |= CAC_CCB_ACTIVE;
        !           432:                (*sc->sc_cl->cl_submit)(sc, ccb);
        !           433:        }
        !           434:
        !           435:        return (0);
        !           436: }
        !           437:
        !           438: /*
        !           439:  * Process a finished CCB.
        !           440:  */
        !           441: void
        !           442: cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
        !           443: {
        !           444:        struct scsi_xfer *xs = ccb->ccb_xs;
        !           445:        int error = 0;
        !           446:
        !           447:        if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
        !           448:                printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
        !           449:                if (xs) {
        !           450:                        xs->error = XS_DRIVER_STUFFUP;
        !           451:                        scsi_done(xs);
        !           452:                }
        !           453:                return;
        !           454:        }
        !           455:
        !           456:        if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
        !           457:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
        !           458:                    ccb->ccb_dmamap_xfer->dm_mapsize,
        !           459:                    ccb->ccb_flags & CAC_CCB_DATA_IN ?
        !           460:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !           461:                bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
        !           462:        }
        !           463:
        !           464:        if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
        !           465:                printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
        !           466:        if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
        !           467:                error = 1;
        !           468:                printf("%s: hard error\n", sc->sc_dv.dv_xname);
        !           469:        }
        !           470:        if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
        !           471:                error = 1;
        !           472:                printf("%s: invalid request\n", sc->sc_dv.dv_xname);
        !           473:        }
        !           474:
        !           475:        cac_ccb_free(sc, ccb);
        !           476:        if (xs) {
        !           477:                if (error)
        !           478:                        xs->error = XS_DRIVER_STUFFUP;
        !           479:                else
        !           480:                        xs->resid = 0;
        !           481:
        !           482:                xs->flags |= ITSDONE;
        !           483:                scsi_done(xs);
        !           484:        }
        !           485: }
        !           486:
        !           487: /*
        !           488:  * Allocate a CCB.
        !           489:  */
        !           490: struct cac_ccb *
        !           491: cac_ccb_alloc(struct cac_softc *sc, int nosleep)
        !           492: {
        !           493:        struct cac_ccb *ccb;
        !           494:
        !           495:        if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL)
        !           496:                SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
        !           497:        else
        !           498:                ccb = NULL;
        !           499:        return (ccb);
        !           500: }
        !           501:
        !           502: /*
        !           503:  * Put a CCB onto the freelist.
        !           504:  */
        !           505: void
        !           506: cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb)
        !           507: {
        !           508:
        !           509:        ccb->ccb_flags = 0;
        !           510:        SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
        !           511: }
        !           512:
        !           513: int
        !           514: cac_get_dinfo(sc, target)
        !           515:        struct cac_softc *sc;
        !           516:        int target;
        !           517: {
        !           518:        if (sc->sc_dinfos[target].ncylinders)
        !           519:                return (0);
        !           520:
        !           521:        if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
        !           522:            sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
        !           523:                printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
        !           524:                    sc->sc_dv.dv_xname);
        !           525:                return (-1);
        !           526:        }
        !           527:
        !           528:        return (0);
        !           529: }
        !           530:
        !           531: void
        !           532: cacminphys(bp)
        !           533:        struct buf *bp;
        !           534: {
        !           535:        if (bp->b_bcount > CAC_MAX_XFER)
        !           536:                bp->b_bcount = CAC_MAX_XFER;
        !           537:        minphys(bp);
        !           538: }
        !           539:
        !           540: void
        !           541: cac_copy_internal_data(xs, v, size)
        !           542:        struct scsi_xfer *xs;
        !           543:        void *v;
        !           544:        size_t size;
        !           545: {
        !           546:        size_t copy_cnt;
        !           547:
        !           548:        if (!xs->datalen)
        !           549:                printf("uio move is not yet supported\n");
        !           550:        else {
        !           551:                copy_cnt = MIN(size, xs->datalen);
        !           552:                bcopy(v, xs->data, copy_cnt);
        !           553:        }
        !           554: }
        !           555:
        !           556: int
        !           557: cac_scsi_cmd(xs)
        !           558:        struct scsi_xfer *xs;
        !           559: {
        !           560:        struct scsi_link *link = xs->sc_link;
        !           561:        struct cac_softc *sc = link->adapter_softc;
        !           562:        struct cac_drive_info *dinfo;
        !           563:        struct scsi_inquiry_data inq;
        !           564:        struct scsi_sense_data sd;
        !           565:        struct scsi_read_cap_data rcd;
        !           566:        u_int8_t target = link->target;
        !           567:        u_int32_t blockno, blockcnt, size;
        !           568:        struct scsi_rw *rw;
        !           569:        struct scsi_rw_big *rwb;
        !           570:        int op, flags, s, error, poll;
        !           571:        const char *p;
        !           572:
        !           573:        if (target >= sc->sc_nunits || link->lun != 0) {
        !           574:                xs->error = XS_DRIVER_STUFFUP;
        !           575:                return (COMPLETE);
        !           576:        }
        !           577:
        !           578:        s = splbio();
        !           579:        xs->error = XS_NOERROR;
        !           580:        xs->free_list.le_next = NULL;
        !           581:        dinfo = &sc->sc_dinfos[target];
        !           582:
        !           583:        switch (xs->cmd->opcode) {
        !           584:        case TEST_UNIT_READY:
        !           585:        case START_STOP:
        !           586: #if 0
        !           587:        case VERIFY:
        !           588: #endif
        !           589:                break;
        !           590:
        !           591:        case REQUEST_SENSE:
        !           592:                bzero(&sd, sizeof sd);
        !           593:                sd.error_code = 0x70;
        !           594:                sd.segment = 0;
        !           595:                sd.flags = SKEY_NO_SENSE;
        !           596:                *(u_int32_t*)sd.info = htole32(0);
        !           597:                sd.extra_len = 0;
        !           598:                cac_copy_internal_data(xs, &sd, sizeof sd);
        !           599:                break;
        !           600:
        !           601:        case INQUIRY:
        !           602:                if (cac_get_dinfo(sc, target)) {
        !           603:                        xs->error = XS_DRIVER_STUFFUP;
        !           604:                        break;
        !           605:                }
        !           606:                bzero(&inq, sizeof inq);
        !           607:                inq.device = T_DIRECT;
        !           608:                inq.dev_qual2 = 0;
        !           609:                inq.version = 2;
        !           610:                inq.response_format = 2;
        !           611:                inq.additional_length = 32;
        !           612:                strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
        !           613:                switch (CAC_GET1(dinfo->mirror)) {
        !           614:                case 0: p = "RAID0";    break;
        !           615:                case 1: p = "RAID4";    break;
        !           616:                case 2: p = "RAID1";    break;
        !           617:                case 3: p = "RAID5";    break;
        !           618:                default:p = "<UNK>";    break;
        !           619:                }
        !           620:                snprintf(inq.product, sizeof inq.product, "%s vol  #%02d",
        !           621:                    p, target);
        !           622:                strlcpy(inq.revision, "   ", sizeof inq.revision);
        !           623:                cac_copy_internal_data(xs, &inq, sizeof inq);
        !           624:                break;
        !           625:
        !           626:        case READ_CAPACITY:
        !           627:                if (cac_get_dinfo(sc, target)) {
        !           628:                        xs->error = XS_DRIVER_STUFFUP;
        !           629:                        break;
        !           630:                }
        !           631:                bzero(&rcd, sizeof rcd);
        !           632:                _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
        !           633:                    CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
        !           634:                _lto4b(CAC_SECTOR_SIZE, rcd.length);
        !           635:                cac_copy_internal_data(xs, &rcd, sizeof rcd);
        !           636:                break;
        !           637:
        !           638:        case PREVENT_ALLOW:
        !           639:                break;
        !           640:
        !           641:        case SYNCHRONIZE_CACHE:
        !           642:                if (cac_flush(sc))
        !           643:                        xs->error = XS_DRIVER_STUFFUP;
        !           644:                break;
        !           645:
        !           646:        case READ_COMMAND:
        !           647:        case READ_BIG:
        !           648:        case WRITE_COMMAND:
        !           649:        case WRITE_BIG:
        !           650:
        !           651:                flags = 0;
        !           652:                /* A read or write operation. */
        !           653:                if (xs->cmdlen == 6) {
        !           654:                        rw = (struct scsi_rw *)xs->cmd;
        !           655:                        blockno = _3btol(rw->addr) &
        !           656:                            (SRW_TOPADDR << 16 | 0xffff);
        !           657:                        blockcnt = rw->length ? rw->length : 0x100;
        !           658:                } else {
        !           659:                        rwb = (struct scsi_rw_big *)xs->cmd;
        !           660:                        blockno = _4btol(rwb->addr);
        !           661:                        blockcnt = _2btol(rwb->length);
        !           662:                }
        !           663:                size = CAC_GET2(dinfo->ncylinders) *
        !           664:                    CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
        !           665:                if (blockno >= size || blockno + blockcnt > size) {
        !           666:                        printf("%s: out of bounds %u-%u >= %u\n",
        !           667:                            sc->sc_dv.dv_xname, blockno, blockcnt, size);
        !           668:                        xs->error = XS_DRIVER_STUFFUP;
        !           669:                        scsi_done(xs);
        !           670:                        break;
        !           671:                }
        !           672:
        !           673:                switch (xs->cmd->opcode) {
        !           674:                case READ_COMMAND:
        !           675:                case READ_BIG:
        !           676:                        op = CAC_CMD_READ;
        !           677:                        flags = CAC_CCB_DATA_IN;
        !           678:                        break;
        !           679:                case WRITE_COMMAND:
        !           680:                case WRITE_BIG:
        !           681:                        op = CAC_CMD_WRITE;
        !           682:                        flags = CAC_CCB_DATA_OUT;
        !           683:                        break;
        !           684:                }
        !           685:
        !           686:                poll = xs->flags & SCSI_POLL;
        !           687:                if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
        !           688:                    target, blockno, flags, xs))) {
        !           689:
        !           690:                        if (error == ENOMEM) {
        !           691:                                splx(s);
        !           692:                                return (TRY_AGAIN_LATER);
        !           693:                        } else if (poll) {
        !           694:                                splx(s);
        !           695:                                return (TRY_AGAIN_LATER);
        !           696:                        } else {
        !           697:                                xs->error = XS_DRIVER_STUFFUP;
        !           698:                                scsi_done(xs);
        !           699:                                break;
        !           700:                        }
        !           701:                }
        !           702:
        !           703:                splx(s);
        !           704:
        !           705:                if (poll)
        !           706:                        return (COMPLETE);
        !           707:                else
        !           708:                        return (SUCCESSFULLY_QUEUED);
        !           709:
        !           710:        default:
        !           711:                SC_DEBUG(link, SDEV_DB1, ("unsupported scsi command %#x "
        !           712:                    "tgt %d ", xs->cmd->opcode, target));
        !           713:                xs->error = XS_DRIVER_STUFFUP;
        !           714:        }
        !           715:        splx(s);
        !           716:
        !           717:        return (COMPLETE);
        !           718: }
        !           719:
        !           720: /*
        !           721:  * Board specific linkage shared between multiple bus types.
        !           722:  */
        !           723:
        !           724: int
        !           725: cac_l0_fifo_full(struct cac_softc *sc)
        !           726: {
        !           727:
        !           728:        return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
        !           729: }
        !           730:
        !           731: void
        !           732: cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
        !           733: {
        !           734: #ifdef CAC_DEBUG
        !           735:        printf("submit-%x ", ccb->ccb_paddr);
        !           736: #endif
        !           737:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
        !           738:            sc->sc_dmamap->dm_mapsize,
        !           739:            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        !           740:        cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
        !           741: }
        !           742:
        !           743: struct cac_ccb *
        !           744: cac_l0_completed(sc)
        !           745:        struct cac_softc *sc;
        !           746: {
        !           747:        struct cac_ccb *ccb;
        !           748:        paddr_t off;
        !           749:
        !           750:        if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
        !           751:                return NULL;
        !           752: #ifdef CAC_DEBUG
        !           753:        printf("compl-%x ", off);
        !           754: #endif
        !           755:        if (off & 3 && ccb->ccb_req.error == 0)
        !           756:                ccb->ccb_req.error = CAC_RET_CMD_INVALID;
        !           757:
        !           758:        off = (off & ~3) - sc->sc_ccbs_paddr;
        !           759:        ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
        !           760:
        !           761:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
        !           762:            sc->sc_dmamap->dm_mapsize,
        !           763:            BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        !           764:
        !           765:        return (ccb);
        !           766: }
        !           767:
        !           768: int
        !           769: cac_l0_intr_pending(struct cac_softc *sc)
        !           770: {
        !           771:
        !           772:        return (cac_inl(sc, CAC_REG_INTR_PENDING));
        !           773: }
        !           774:
        !           775: void
        !           776: cac_l0_intr_enable(struct cac_softc *sc, int state)
        !           777: {
        !           778:
        !           779:        cac_outl(sc, CAC_REG_INTR_MASK,
        !           780:            state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
        !           781: }

CVSweb