[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

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