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

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

1.1     ! nbrk        1: /*     $OpenBSD: dpt.c,v 1.12 2007/04/10 17:47:55 miod Exp $   */
        !             2: /*     $NetBSD: dpt.c,v 1.12 1999/10/23 16:26:33 ad Exp $      */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Andy Doran, Charles M. Hannum and by Jason R. Thorpe of the Numerical
        !            10:  * Aerospace Simulation Facility, NASA Ames Research Center.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *     This product includes software developed by the NetBSD
        !            23:  *     Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: /*
        !            42:  * Portions of this code fall under the following copyright:
        !            43:  *
        !            44:  * Originally written by Julian Elischer (julian@tfs.com)
        !            45:  * for TRW Financial Systems for use under the MACH(2.5) operating system.
        !            46:  *
        !            47:  * TRW Financial Systems, in accordance with their agreement with Carnegie
        !            48:  * Mellon University, makes this software available to CMU to distribute
        !            49:  * or use in any manner that they see fit as long as this message is kept with
        !            50:  * the software. For this reason TFS also grants any other persons or
        !            51:  * organisations permission to use or modify this software.
        !            52:  *
        !            53:  * TFS supplies this software to be publicly redistributed
        !            54:  * on the understanding that TFS is not responsible for the correct
        !            55:  * functioning of this software in any circumstances.
        !            56:  */
        !            57:
        !            58: /*
        !            59:  * Driver for DPT EATA SCSI adapters.
        !            60:  *
        !            61:  * TODO:
        !            62:  *
        !            63:  * o Need a front-end for (newer) ISA boards.
        !            64:  * o Handle older firmware better.
        !            65:  * o Find a bunch of different firmware EEPROMs and try them out.
        !            66:  * o Test with a bunch of different boards.
        !            67:  * o dpt_readcfg() should not be using CP_PIO_GETCFG.
        !            68:  * o An interface to userland applications.
        !            69:  * o Some sysctls or a utility (eg dptctl(8)) to control parameters.
        !            70:  */
        !            71:
        !            72: #include <sys/cdefs.h>
        !            73: #ifdef __NetBSD__
        !            74: __KERNEL_RCSID(0, "$NetBSD: dpt.c,v 1.12 1999/10/23 16:26:33 ad Exp $");
        !            75: #endif /* __NetBSD__ */
        !            76:
        !            77: #include <sys/param.h>
        !            78: #include <sys/systm.h>
        !            79: #include <sys/kernel.h>
        !            80: #include <sys/device.h>
        !            81: #include <sys/queue.h>
        !            82: #include <sys/proc.h>
        !            83: #include <sys/buf.h>
        !            84:
        !            85: #include <machine/endian.h>
        !            86: #ifdef __NetBSD__
        !            87: #include <machine/bswap.h>
        !            88: #endif /* __NetBSD__ */
        !            89: #include <machine/bus.h>
        !            90:
        !            91: #ifdef __NetBSD__
        !            92: #include <dev/scsipi/scsi_all.h>
        !            93: #include <dev/scsipi/scsipi_all.h>
        !            94: #include <dev/scsipi/scsiconf.h>
        !            95: #endif /* __NetBSD__ */
        !            96: #ifdef __OpenBSD__
        !            97: #include <scsi/scsi_all.h>
        !            98: #include <scsi/scsiconf.h>
        !            99: #endif /* __OpenBSD__ */
        !           100:
        !           101: #include <dev/ic/dptreg.h>
        !           102: #include <dev/ic/dptvar.h>
        !           103:
        !           104: #ifdef __OpenBSD__
        !           105: static void dpt_enqueue(struct dpt_softc *, struct scsi_xfer *, int);
        !           106: static struct scsi_xfer *dpt_dequeue(struct dpt_softc *);
        !           107:
        !           108: struct cfdriver dpt_cd = {
        !           109:        NULL, "dpt", DV_DULL
        !           110: };
        !           111: #endif /* __OpenBSD__ */
        !           112:
        !           113: /* A default for our link struct */
        !           114: #ifdef __NetBSD__
        !           115: static struct scsipi_device dpt_dev = {
        !           116: #endif /* __NetBSD__ */
        !           117: #ifdef __OpenBSD__
        !           118: static struct scsi_device dpt_dev = {
        !           119: #endif /* __OpenBSD__ */
        !           120:        NULL,                   /* Use default error handler */
        !           121:        NULL,                   /* have a queue, served by this */
        !           122:        NULL,                   /* have no async handler */
        !           123:        NULL,                   /* Use default 'done' routine */
        !           124: };
        !           125:
        !           126: #ifndef offsetof
        !           127: #define offsetof(type, member) (int)((&((type *)0)->member))
        !           128: #endif /* offsetof */
        !           129:
        !           130: static char *dpt_cname[] = {
        !           131:        "PM3334", "SmartRAID IV",
        !           132:        "PM3332", "SmartRAID IV",
        !           133:        "PM2144", "SmartCache IV",
        !           134:        "PM2044", "SmartCache IV",
        !           135:        "PM2142", "SmartCache IV",
        !           136:        "PM2042", "SmartCache IV",
        !           137:        "PM2041", "SmartCache IV",
        !           138:        "PM3224", "SmartRAID III",
        !           139:        "PM3222", "SmartRAID III",
        !           140:        "PM3021", "SmartRAID III",
        !           141:        "PM2124", "SmartCache III",
        !           142:        "PM2024", "SmartCache III",
        !           143:        "PM2122", "SmartCache III",
        !           144:        "PM2022", "SmartCache III",
        !           145:        "PM2021", "SmartCache III",
        !           146:        "SK2012", "SmartCache Plus",
        !           147:        "SK2011", "SmartCache Plus",
        !           148:        NULL,     "unknown adapter, please report using sendbug(1)",
        !           149: };
        !           150:
        !           151: /*
        !           152:  * Handle an interrupt from the HBA.
        !           153:  */
        !           154: int
        !           155: dpt_intr(xxx_sc)
        !           156:        void *xxx_sc;
        !           157: {
        !           158:        struct dpt_softc *sc;
        !           159:        struct dpt_ccb *ccb;
        !           160:        struct eata_sp *sp;
        !           161:        static int moretimo;
        !           162:        int more;
        !           163:
        !           164:        sc = xxx_sc;
        !           165:        sp = sc->sc_statpack;
        !           166:
        !           167:        if (!sp) {
        !           168: #ifdef DEBUG
        !           169:                printf("%s: premature intr (st:%02x aux:%02x)\n",
        !           170:                        sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS),
        !           171:                        dpt_inb(sc, HA_AUX_STATUS));
        !           172: #else /* DEBUG */
        !           173:                (void) dpt_inb(sc, HA_STATUS);
        !           174: #endif /* DEBUG */
        !           175:                return (0);
        !           176:        }
        !           177:
        !           178:        more = 0;
        !           179:
        !           180: #ifdef DEBUG
        !           181:        if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0)
        !           182:                printf("%s: spurious intr\n", sc->sc_dv.dv_xname);
        !           183: #endif
        !           184:
        !           185:        /* Don't get stalled by HA_ST_MORE */
        !           186:        if (moretimo < DPT_MORE_TIMEOUT / 100)
        !           187:                moretimo = 0;
        !           188:
        !           189:        for (;;) {
        !           190:                /*
        !           191:                 * HBA might have interrupted while we were dealing with the
        !           192:                 * last completed command, since we ACK before we deal; keep
        !           193:                 * polling. If no interrupt is signalled, but the HBA has
        !           194:                 * indicated that more data will be available soon, hang
        !           195:                 * around.
        !           196:                 */
        !           197:                if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0) {
        !           198:                        if (more != 0 && moretimo++ < DPT_MORE_TIMEOUT / 100) {
        !           199:                                DELAY(10);
        !           200:                                continue;
        !           201:                        }
        !           202:                        break;
        !           203:                }
        !           204:
        !           205:                bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_spoff,
        !           206:                    sizeof(struct eata_sp), BUS_DMASYNC_POSTREAD);
        !           207:
        !           208:                if (!sp) {
        !           209:                        more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
        !           210:
        !           211:                        /* Don't get stalled by HA_ST_MORE */
        !           212:                        if (moretimo < DPT_MORE_TIMEOUT / 100)
        !           213:                                moretimo = 0;
        !           214:                        continue;
        !           215:                }
        !           216:
        !           217:                /* Might have looped before HBA can reset HBA_AUX_INTR */
        !           218:                if (sp->sp_ccbid == -1) {
        !           219:                        DELAY(50);
        !           220: #ifdef DIAGNOSTIC
        !           221:                        printf("%s: slow reset of HA_AUX_STATUS?",
        !           222:                            sc->sc_dv.dv_xname);
        !           223: #endif
        !           224:                        if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) == 0)
        !           225:                                return (0);
        !           226: #ifdef DIAGNOSTIC
        !           227:                        printf("%s: was a slow reset of HA_AUX_STATUS",
        !           228:                            sc->sc_dv.dv_xname);
        !           229: #endif
        !           230:                        /* Re-sync DMA map */
        !           231:                        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
        !           232:                            sc->sc_spoff, sizeof(struct eata_sp),
        !           233:                            BUS_DMASYNC_POSTREAD);
        !           234:                }
        !           235:
        !           236:                /* Make sure CCB ID from status packet is realistic */
        !           237:                if (sp->sp_ccbid >= 0 && sp->sp_ccbid < sc->sc_nccbs) {
        !           238:                        /* Sync up DMA map and cache cmd status */
        !           239:                        ccb = sc->sc_ccbs + sp->sp_ccbid;
        !           240:
        !           241:                        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb,
        !           242:                            CCB_OFF(sc, ccb), sizeof(struct dpt_ccb),
        !           243:                            BUS_DMASYNC_POSTWRITE);
        !           244:
        !           245:                        ccb->ccb_hba_status = sp->sp_hba_status & 0x7F;
        !           246:                        ccb->ccb_scsi_status = sp->sp_scsi_status;
        !           247:
        !           248:                        /*
        !           249:                         * Ack the interrupt and process the CCB. If this
        !           250:                         * is a private CCB it's up to dpt_poll() to notice.
        !           251:                         */
        !           252:                        sp->sp_ccbid = -1;
        !           253:                        ccb->ccb_flg |= CCB_INTR;
        !           254:                        more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
        !           255:                        if ((ccb->ccb_flg & CCB_PRIVATE) == 0)
        !           256:                                dpt_done_ccb(sc, ccb);
        !           257:                } else {
        !           258:                        printf("%s: bogus status (returned CCB id %d)\n",
        !           259:                            sc->sc_dv.dv_xname, sp->sp_ccbid);
        !           260:
        !           261:                        /* Ack the interrupt */
        !           262:                        sp->sp_ccbid = -1;
        !           263:                        more = dpt_inb(sc, HA_STATUS) & HA_ST_MORE;
        !           264:                }
        !           265:
        !           266:                /* Don't get stalled by HA_ST_MORE */
        !           267:                if (moretimo < DPT_MORE_TIMEOUT / 100)
        !           268:                        moretimo = 0;
        !           269:        }
        !           270:
        !           271:        return (0);
        !           272: }
        !           273:
        !           274: /*
        !           275:  * Initialize and attach the HBA. This is the entry point from bus
        !           276:  * specific probe-and-attach code.
        !           277:  */
        !           278: void
        !           279: dpt_init(sc, intrstr)
        !           280:        struct dpt_softc *sc;
        !           281:        const char *intrstr;
        !           282: {
        !           283:        struct eata_inquiry_data *ei;
        !           284:        int i, j, error, rseg, mapsize;
        !           285:        bus_dma_segment_t seg;
        !           286:        struct eata_cfg *ec;
        !           287:        char model[16];
        !           288:
        !           289:        ec = &sc->sc_ec;
        !           290:
        !           291:        /* Allocate the CCB/status packet/scratch DMA map and load */
        !           292:        sc->sc_nccbs = min(betoh16(*(int16_t *)ec->ec_queuedepth),
        !           293:                           DPT_MAX_CCBS);
        !           294:        sc->sc_spoff = sc->sc_nccbs * sizeof(struct dpt_ccb);
        !           295:        sc->sc_scroff = sc->sc_spoff + sizeof(struct eata_sp);
        !           296:        sc->sc_scrlen = 256; /* XXX */
        !           297:        mapsize = sc->sc_nccbs * sizeof(struct dpt_ccb) + sc->sc_scrlen +
        !           298:            sizeof(struct eata_sp);
        !           299:
        !           300:        if ((error = bus_dmamem_alloc(sc->sc_dmat, mapsize, NBPG, 0,
        !           301:            &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           302:                printf("%s: unable to allocate CCBs, error = %d\n",
        !           303:                    sc->sc_dv.dv_xname, error);
        !           304:                return;
        !           305:        }
        !           306:
        !           307:        if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, mapsize,
        !           308:            (caddr_t *)&sc->sc_ccbs, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
        !           309:                printf("%s: unable to map CCBs, error = %d\n",
        !           310:                    sc->sc_dv.dv_xname, error);
        !           311:                return;
        !           312:        }
        !           313:
        !           314:        if ((error = bus_dmamap_create(sc->sc_dmat, mapsize, mapsize, 1, 0,
        !           315:            BUS_DMA_NOWAIT, &sc->sc_dmamap_ccb)) != 0) {
        !           316:                printf("%s: unable to create CCB DMA map, error = %d\n",
        !           317:                    sc->sc_dv.dv_xname, error);
        !           318:                return;
        !           319:        }
        !           320:
        !           321:        if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_ccb,
        !           322:            sc->sc_ccbs, mapsize, NULL, BUS_DMA_NOWAIT)) != 0) {
        !           323:                printf("%s: unable to load CCB DMA map, error = %d\n",
        !           324:                    sc->sc_dv.dv_xname, error);
        !           325:                return;
        !           326:        }
        !           327:
        !           328:        sc->sc_statpack = (struct eata_sp *)((caddr_t)sc->sc_ccbs +
        !           329:            sc->sc_spoff);
        !           330:        sc->sc_sppa = sc->sc_dmamap_ccb->dm_segs[0].ds_addr + sc->sc_spoff;
        !           331:        sc->sc_scr = (caddr_t)sc->sc_ccbs + sc->sc_scroff;
        !           332:        sc->sc_scrpa = sc->sc_dmamap_ccb->dm_segs[0].ds_addr + sc->sc_scroff;
        !           333:        sc->sc_statpack->sp_ccbid = -1;
        !           334:
        !           335:        /* Initialize the CCBs */
        !           336:        TAILQ_INIT(&sc->sc_free_ccb);
        !           337:        i = dpt_create_ccbs(sc, sc->sc_ccbs, sc->sc_nccbs);
        !           338:
        !           339:        if (i == 0) {
        !           340:                printf("%s: unable to create CCBs\n", sc->sc_dv.dv_xname);
        !           341:                return;
        !           342:        } else if (i != sc->sc_nccbs) {
        !           343:                printf("%s: %d/%d CCBs created!\n", sc->sc_dv.dv_xname, i,
        !           344:                    sc->sc_nccbs);
        !           345:                sc->sc_nccbs = i;
        !           346:        }
        !           347:
        !           348:        /* Set shutdownhook before we start any device activity */
        !           349:        sc->sc_sdh = shutdownhook_establish(dpt_shutdown, sc);
        !           350:
        !           351:        /* Get the page 0 inquiry data from the HBA */
        !           352:        dpt_hba_inquire(sc, &ei);
        !           353:
        !           354:        /*
        !           355:         * dpt0 at pci0 dev 12 function 0: DPT SmartRAID III (PM3224A/9X-R)
        !           356:         * dpt0: interrupting at irq 10
        !           357:         * dpt0: 64 queued commands, 1 channel(s), adapter on ID(s) 7
        !           358:         */
        !           359:        for (i = 0; ei->ei_vendor[i] != ' ' && i < 8; i++)
        !           360:                ;
        !           361:        ei->ei_vendor[i] = '\0';
        !           362:
        !           363:        for (i = 0; ei->ei_model[i] != ' ' && i < 7; i++)
        !           364:                model[i] = ei->ei_model[i];
        !           365:        for (j = 0; ei->ei_suffix[j] != ' ' && j < 7; j++)
        !           366:                model[i++] = ei->ei_suffix[j];
        !           367:        model[i] = '\0';
        !           368:
        !           369:        /* Find the canonical name for the board */
        !           370:        for (i = 0; dpt_cname[i] != NULL; i += 2)
        !           371:                if (memcmp(ei->ei_model, dpt_cname[i], 6) == 0)
        !           372:                        break;
        !           373:
        !           374:        printf("%s %s (%s)\n", ei->ei_vendor, dpt_cname[i + 1], model);
        !           375:
        !           376:        if (intrstr != NULL)
        !           377:                printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr);
        !           378:
        !           379:        printf("%s: %d queued commands, %d channel(s), adapter on ID(s)",
        !           380:            sc->sc_dv.dv_xname, sc->sc_nccbs, ec->ec_maxchannel + 1);
        !           381:
        !           382:        for (i = 0; i <= ec->ec_maxchannel; i++)
        !           383:                printf(" %d", ec->ec_hba[3 - i]);
        !           384:        printf("\n");
        !           385:
        !           386:        /* Reset the SCSI bus */
        !           387:        if (dpt_cmd(sc, NULL, 0, CP_IMMEDIATE, CPI_BUS_RESET))
        !           388:                panic("%s: dpt_cmd failed", sc->sc_dv.dv_xname);
        !           389:         DELAY(20000);
        !           390:
        !           391:        /* Fill in the adapter, each link and attach in turn */
        !           392: #ifdef __NetBSD__
        !           393:        sc->sc_adapter.scsipi_cmd = dpt_scsi_cmd;
        !           394:        sc->sc_adapter.scsipi_minphys = dpt_minphys;
        !           395: #endif /* __NetBSD__ */
        !           396: #ifdef __OpenBSD__
        !           397:        sc->sc_adapter.scsi_cmd = dpt_scsi_cmd;
        !           398:        sc->sc_adapter.scsi_minphys = dpt_minphys;
        !           399: #endif /* __OpenBSD__ */
        !           400:
        !           401:        for (i = 0; i <= ec->ec_maxchannel; i++) {
        !           402: #ifdef __NetBSD__
        !           403:                struct scsipi_link *link;
        !           404: #endif /* __NetBSD__ */
        !           405: #ifdef __OpenBSD__
        !           406:                struct scsi_link *link;
        !           407: #endif /* __OpenBSD__ */
        !           408:                sc->sc_hbaid[i] = ec->ec_hba[3 - i];
        !           409:                link = &sc->sc_link[i];
        !           410: #ifdef __NetBSD__
        !           411:                link->scsipi_scsi.scsibus = i;
        !           412:                link->scsipi_scsi.adapter_target = sc->sc_hbaid[i];
        !           413:                link->scsipi_scsi.max_lun = ec->ec_maxlun;
        !           414:                link->scsipi_scsi.max_target = ec->ec_maxtarget;
        !           415:                link->type = BUS_SCSI;
        !           416: #endif /* __NetBSD__ */
        !           417: #ifdef __OpenBSD__
        !           418:                link->scsibus = i;
        !           419:                link->adapter_target = sc->sc_hbaid[i];
        !           420:                link->luns = ec->ec_maxlun + 1;
        !           421:                link->adapter_buswidth = ec->ec_maxtarget + 1;
        !           422: #endif /* __OpenBSD__ */
        !           423:                link->device = &dpt_dev;
        !           424:                link->adapter = &sc->sc_adapter;
        !           425:                link->adapter_softc = sc;
        !           426:                link->openings = sc->sc_nccbs;
        !           427:                config_found(&sc->sc_dv, link, scsiprint);
        !           428:        }
        !           429: }
        !           430:
        !           431: /*
        !           432:  * Our 'shutdownhook' to cleanly shut down the HBA. The HBA must flush
        !           433:  * all data from its cache and mark array groups as clean.
        !           434:  */
        !           435: void
        !           436: dpt_shutdown(xxx_sc)
        !           437:        void *xxx_sc;
        !           438: {
        !           439:        struct dpt_softc *sc;
        !           440:
        !           441:        sc = xxx_sc;
        !           442:        printf("shutting down %s...", sc->sc_dv.dv_xname);
        !           443:        dpt_cmd(sc, NULL, 0, CP_IMMEDIATE, CPI_POWEROFF_WARN);
        !           444:        DELAY(5000*1000);
        !           445:        printf(" done\n");
        !           446: }
        !           447:
        !           448: /*
        !           449:  * Send an EATA command to the HBA.
        !           450:  */
        !           451: int
        !           452: dpt_cmd(sc, cp, addr, eatacmd, icmd)
        !           453:        struct dpt_softc *sc;
        !           454:        struct eata_cp *cp;
        !           455:        u_int32_t addr;
        !           456:        int eatacmd, icmd;
        !           457: {
        !           458:        int i;
        !           459:
        !           460:        for (i = 20000; i; i--) {
        !           461:                if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_BUSY) == 0)
        !           462:                        break;
        !           463:                DELAY(50);
        !           464:        }
        !           465:
        !           466:        /* Not the most graceful way to handle this */
        !           467:        if (i == 0) {
        !           468:                printf("%s: HBA timeout on EATA command issue; aborting\n",
        !           469:                    sc->sc_dv.dv_xname);
        !           470:                return (-1);
        !           471:        }
        !           472:
        !           473:        if (cp == NULL)
        !           474:                addr = 0;
        !           475:
        !           476:        dpt_outb(sc, HA_DMA_BASE + 0, (u_int32_t)addr);
        !           477:        dpt_outb(sc, HA_DMA_BASE + 1, (u_int32_t)addr >> 8);
        !           478:        dpt_outb(sc, HA_DMA_BASE + 2, (u_int32_t)addr >> 16);
        !           479:        dpt_outb(sc, HA_DMA_BASE + 3, (u_int32_t)addr >> 24);
        !           480:
        !           481:        if (eatacmd == CP_IMMEDIATE) {
        !           482:                if (cp == NULL) {
        !           483:                        /* XXX should really pass meaningful values */
        !           484:                        dpt_outb(sc, HA_ICMD_CODE2, 0);
        !           485:                        dpt_outb(sc, HA_ICMD_CODE1, 0);
        !           486:                }
        !           487:                dpt_outb(sc, HA_ICMD, icmd);
        !           488:        }
        !           489:
        !           490:         dpt_outb(sc, HA_COMMAND, eatacmd);
        !           491:         return (0);
        !           492: }
        !           493:
        !           494: /*
        !           495:  * Wait for the HBA to reach an arbitrary state.
        !           496:  */
        !           497: int
        !           498: dpt_wait(sc, mask, state, ms)
        !           499:         struct dpt_softc *sc;
        !           500:         u_int8_t mask, state;
        !           501:         int ms;
        !           502: {
        !           503:
        !           504:         for (ms *= 10; ms; ms--) {
        !           505:                 if ((dpt_inb(sc, HA_STATUS) & mask) == state)
        !           506:                        return (0);
        !           507:                 DELAY(100);
        !           508:         }
        !           509:         return (-1);
        !           510: }
        !           511:
        !           512: /*
        !           513:  * Wait for the specified CCB to finish. This is used when we may not be
        !           514:  * able to sleep and/or interrupts are disabled (eg autoconfiguration).
        !           515:  * The timeout value from the CCB is used. This should only be used for
        !           516:  * CCB_PRIVATE requests; otherwise the CCB will get recycled before we get
        !           517:  * a look at it.
        !           518:  */
        !           519: int
        !           520: dpt_poll(sc, ccb)
        !           521:         struct dpt_softc *sc;
        !           522:         struct dpt_ccb *ccb;
        !           523: {
        !           524:        int i;
        !           525:
        !           526: #ifdef DEBUG
        !           527:        if ((ccb->ccb_flg & CCB_PRIVATE) == 0)
        !           528:                panic("dpt_poll: called for non-CCB_PRIVATE request");
        !           529: #endif
        !           530:
        !           531:        if ((ccb->ccb_flg & CCB_INTR) != 0)
        !           532:                return (0);
        !           533:
        !           534:         for (i = ccb->ccb_timeout * 20; i; i--) {
        !           535:                 if ((dpt_inb(sc, HA_AUX_STATUS) & HA_AUX_INTR) != 0)
        !           536:                        dpt_intr(sc);
        !           537:                 if ((ccb->ccb_flg & CCB_INTR) != 0)
        !           538:                        return (0);
        !           539:                 DELAY(50);
        !           540:         }
        !           541:         return (-1);
        !           542: }
        !           543:
        !           544: /*
        !           545:  * Read the EATA configuration from the HBA and perform some sanity checks.
        !           546:  */
        !           547: int
        !           548: dpt_readcfg(sc)
        !           549:        struct dpt_softc *sc;
        !           550: {
        !           551:        struct eata_cfg *ec;
        !           552:        int i, j, stat;
        !           553:        u_int16_t *p;
        !           554:
        !           555:        ec = &sc->sc_ec;
        !           556:
        !           557:        /* Older firmware may puke if we talk to it too soon after reset */
        !           558:        dpt_outb(sc, HA_COMMAND, CP_RESET);
        !           559:         DELAY(750000);
        !           560:
        !           561:        for (i = 1000; i; i--) {
        !           562:                if ((dpt_inb(sc, HA_STATUS) & HA_ST_READY) != 0)
        !           563:                        break;
        !           564:                DELAY(2000);
        !           565:        }
        !           566:
        !           567:        if (i == 0) {
        !           568:                printf("%s: HBA not ready after reset: %02x\n",
        !           569:                    sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS));
        !           570:                return (-1);
        !           571:        }
        !           572:
        !           573:        while((((stat = dpt_inb(sc, HA_STATUS))
        !           574:             != (HA_ST_READY|HA_ST_SEEK_COMPLETE))
        !           575:             && (stat != (HA_ST_READY|HA_ST_SEEK_COMPLETE|HA_ST_ERROR))
        !           576:             && (stat != (HA_ST_READY|HA_ST_SEEK_COMPLETE|HA_ST_ERROR|HA_ST_DRQ)))
        !           577:             || (dpt_wait(sc, HA_ST_BUSY, 0, 2000))) {
        !           578:                /* RAID drives still spinning up? */
        !           579:                 if((dpt_inb(sc, HA_ERROR) != 'D')
        !           580:                     || (dpt_inb(sc, HA_ERROR + 1) != 'P')
        !           581:                     || (dpt_inb(sc, HA_ERROR + 2) != 'T')) {
        !           582:                        printf("%s: HBA not ready\n", sc->sc_dv.dv_xname);
        !           583:                         return (-1);
        !           584:                }
        !           585:         }
        !           586:
        !           587:        /*
        !           588:         * Issue the read-config command and wait for the data to appear.
        !           589:         * XXX we shouldn't be doing this with PIO, but it makes it a lot
        !           590:         * easier as no DMA setup is required.
        !           591:         */
        !           592:        dpt_outb(sc, HA_COMMAND, CP_PIO_GETCFG);
        !           593:        memset(ec, 0, sizeof(*ec));
        !           594:        i = ((int)&((struct eata_cfg *)0)->ec_cfglen +
        !           595:            sizeof(ec->ec_cfglen)) >> 1;
        !           596:        p = (u_int16_t *)ec;
        !           597:
        !           598:        if (dpt_wait(sc, 0xFF, HA_ST_DATA_RDY, 2000)) {
        !           599:                printf("%s: cfg data didn't appear (status:%02x)\n",
        !           600:                    sc->sc_dv.dv_xname, dpt_inb(sc, HA_STATUS));
        !           601:                return (-1);
        !           602:        }
        !           603:
        !           604:        /* Begin reading */
        !           605:        while (i--)
        !           606:                *p++ = dpt_inw(sc, HA_DATA);
        !           607:
        !           608:         if ((i = ec->ec_cfglen) > (sizeof(struct eata_cfg)
        !           609:             - (int)(&(((struct eata_cfg *)0L)->ec_cfglen))
        !           610:             - sizeof(ec->ec_cfglen)))
        !           611:                 i = sizeof(struct eata_cfg)
        !           612:                   - (int)(&(((struct eata_cfg *)0L)->ec_cfglen))
        !           613:                   - sizeof(ec->ec_cfglen);
        !           614:
        !           615:         j = i + (int)(&(((struct eata_cfg *)0L)->ec_cfglen)) +
        !           616:             sizeof(ec->ec_cfglen);
        !           617:         i >>= 1;
        !           618:
        !           619:        while (i--)
        !           620:                 *p++ = dpt_inw(sc, HA_DATA);
        !           621:
        !           622:         /* Flush until we have read 512 bytes. */
        !           623:         i = (512 - j + 1) >> 1;
        !           624:        while (i--)
        !           625:                dpt_inw(sc, HA_DATA);
        !           626:
        !           627:         /* Defaults for older Firmware */
        !           628:        if (p <= (u_short *)&ec->ec_hba[DPT_MAX_CHANNELS - 1])
        !           629:                ec->ec_hba[DPT_MAX_CHANNELS - 1] = 7;
        !           630:
        !           631:         if ((dpt_inb(sc, HA_STATUS) & HA_ST_ERROR) != 0) {
        !           632:                printf("%s: HBA error\n", sc->sc_dv.dv_xname);
        !           633:                return (-1);
        !           634:         }
        !           635:
        !           636:         if (!ec->ec_hbavalid) {
        !           637:                 printf("%s: ec_hba field invalid\n", sc->sc_dv.dv_xname);
        !           638:                return (-1);
        !           639:        }
        !           640:
        !           641:        if (memcmp(ec->ec_eatasig, "EATA", 4) != 0) {
        !           642:                printf("%s: EATA signature mismatch\n", sc->sc_dv.dv_xname);
        !           643:                return (-1);
        !           644:        }
        !           645:
        !           646:        if (!ec->ec_dmasupported) {
        !           647:                printf("%s: DMA not supported\n", sc->sc_dv.dv_xname);
        !           648:                return (-1);
        !           649:        }
        !           650:
        !           651:        return (0);
        !           652: }
        !           653:
        !           654: /*
        !           655:  * Adjust the size of each I/O before it passes to the SCSI layer.
        !           656:  */
        !           657: void
        !           658: dpt_minphys(bp)
        !           659:        struct buf *bp;
        !           660: {
        !           661:
        !           662:        if (bp->b_bcount > DPT_MAX_XFER)
        !           663:                bp->b_bcount = DPT_MAX_XFER;
        !           664:        minphys(bp);
        !           665: }
        !           666:
        !           667: /*
        !           668:  * Put a CCB onto the freelist.
        !           669:  */
        !           670: void
        !           671: dpt_free_ccb(sc, ccb)
        !           672:        struct dpt_softc *sc;
        !           673:        struct dpt_ccb *ccb;
        !           674: {
        !           675:        int s;
        !           676:
        !           677:        s = splbio();
        !           678:        ccb->ccb_flg = 0;
        !           679:        TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, ccb_chain);
        !           680:
        !           681:        /* Wake anybody waiting for a free ccb */
        !           682:        if (TAILQ_NEXT(ccb, ccb_chain) == NULL)
        !           683:                wakeup(&sc->sc_free_ccb);
        !           684:        splx(s);
        !           685: }
        !           686:
        !           687: /*
        !           688:  * Initialize the specified CCB.
        !           689:  */
        !           690: int
        !           691: dpt_init_ccb(sc, ccb)
        !           692:        struct dpt_softc *sc;
        !           693:        struct dpt_ccb *ccb;
        !           694: {
        !           695:        int error;
        !           696:
        !           697:        /* Create the DMA map for this CCB's data */
        !           698:        error = bus_dmamap_create(sc->sc_dmat, DPT_MAX_XFER, DPT_SG_SIZE,
        !           699:            DPT_MAX_XFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
        !           700:            &ccb->ccb_dmamap_xfer);
        !           701:
        !           702:        if (error) {
        !           703:                printf("%s: can't create ccb dmamap (%d)\n",
        !           704:                   sc->sc_dv.dv_xname, error);
        !           705:                return (error);
        !           706:        }
        !           707:
        !           708:        ccb->ccb_flg = 0;
        !           709:        ccb->ccb_ccbpa = sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
        !           710:            CCB_OFF(sc, ccb);
        !           711:        return (0);
        !           712: }
        !           713:
        !           714: /*
        !           715:  * Create a set of CCBs and add them to the free list.
        !           716:  */
        !           717: int
        !           718: dpt_create_ccbs(sc, ccbstore, count)
        !           719:        struct dpt_softc *sc;
        !           720:        struct dpt_ccb *ccbstore;
        !           721:        int count;
        !           722: {
        !           723:        struct dpt_ccb *ccb;
        !           724:        int i, error;
        !           725:
        !           726:        memset(ccbstore, 0, sizeof(struct dpt_ccb) * count);
        !           727:
        !           728:        for (i = 0, ccb = ccbstore; i < count; i++, ccb++) {
        !           729:                if ((error = dpt_init_ccb(sc, ccb)) != 0) {
        !           730:                        printf("%s: unable to init ccb, error = %d\n",
        !           731:                            sc->sc_dv.dv_xname, error);
        !           732:                        break;
        !           733:                }
        !           734:                ccb->ccb_id = i;
        !           735:                TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_chain);
        !           736:        }
        !           737:
        !           738:        return (i);
        !           739: }
        !           740:
        !           741: /*
        !           742:  * Get a free ccb. If there are none, see if we can allocate a new one. If
        !           743:  * none are available right now and we are permitted to sleep, then wait
        !           744:  * until one becomes free, otherwise return an error.
        !           745:  */
        !           746: struct dpt_ccb *
        !           747: dpt_alloc_ccb(sc, flg)
        !           748:        struct dpt_softc *sc;
        !           749:        int flg;
        !           750: {
        !           751:        struct dpt_ccb *ccb;
        !           752:        int s;
        !           753:
        !           754:        s = splbio();
        !           755:
        !           756:        for (;;) {
        !           757:                ccb = TAILQ_FIRST(&sc->sc_free_ccb);
        !           758:                if (ccb) {
        !           759:                        TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_chain);
        !           760:                        break;
        !           761:                }
        !           762: #ifdef __NetBSD__
        !           763:                if ((flg & XS_CTL_NOSLEEP) != 0) {
        !           764: #endif /* __NetBSD__ */
        !           765: #ifdef __OpenBSD__
        !           766:                if ((flg & SCSI_NOSLEEP) != 0) {
        !           767: #endif /* __OpenBSD__ */
        !           768:                        splx(s);
        !           769:                        return (NULL);
        !           770:                }
        !           771:                tsleep(&sc->sc_free_ccb, PRIBIO, "dptccb", 0);
        !           772:        }
        !           773:
        !           774:        ccb->ccb_flg |= CCB_ALLOC;
        !           775:        splx(s);
        !           776:        return (ccb);
        !           777: }
        !           778:
        !           779: /*
        !           780:  * We have a CCB which has been processed by the HBA, now we look to see how
        !           781:  * the operation went. CCBs marked with CCB_PRIVATE are not automatically
        !           782:  * passed here by dpt_intr().
        !           783:  */
        !           784: void
        !           785: dpt_done_ccb(sc, ccb)
        !           786:        struct dpt_softc *sc;
        !           787:        struct dpt_ccb *ccb;
        !           788: {
        !           789: #ifdef __NetBSD__
        !           790:        struct scsipi_sense_data *s1, *s2;
        !           791:        struct scsipi_xfer *xs;
        !           792: #endif /* __NetBSD__ */
        !           793: #ifdef __OpenBSD__
        !           794:        struct scsi_sense_data *s1, *s2;
        !           795:        struct scsi_xfer *xs;
        !           796: #endif /* __OpenBSD__ */
        !           797:        bus_dma_tag_t dmat;
        !           798:
        !           799:        dmat = sc->sc_dmat;
        !           800:        xs = ccb->ccb_xs;
        !           801:
        !           802:        SC_DEBUG(xs->sc_link, SDEV_DB2, ("dpt_done_ccb\n"));
        !           803:
        !           804:        /*
        !           805:         * If we were a data transfer, unload the map that described the
        !           806:         * data buffer.
        !           807:         */
        !           808:        if (xs->datalen) {
        !           809:                bus_dmamap_sync(dmat, ccb->ccb_dmamap_xfer, 0,
        !           810:                    ccb->ccb_dmamap_xfer->dm_mapsize,
        !           811:                    (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
        !           812:                    BUS_DMASYNC_POSTWRITE);
        !           813:                bus_dmamap_unload(dmat, ccb->ccb_dmamap_xfer);
        !           814:        }
        !           815:
        !           816:        /*
        !           817:         * Otherwise, put the results of the operation into the xfer and
        !           818:         * call whoever started it.
        !           819:         */
        !           820: #ifdef DIAGNOSTIC
        !           821:        if ((ccb->ccb_flg & CCB_ALLOC) == 0) {
        !           822:                panic("%s: done ccb not allocated!", sc->sc_dv.dv_xname);
        !           823:                return;
        !           824:        }
        !           825: #endif
        !           826:
        !           827:        if (xs->error == XS_NOERROR) {
        !           828:                if (ccb->ccb_hba_status != HA_NO_ERROR) {
        !           829:                        switch (ccb->ccb_hba_status) {
        !           830:                        case HA_ERROR_SEL_TO:
        !           831:                                xs->error = XS_SELTIMEOUT;
        !           832:                                break;
        !           833:                        case HA_ERROR_RESET:
        !           834:                                xs->error = XS_RESET;
        !           835:                                break;
        !           836:                        default:        /* Other scsi protocol messes */
        !           837:                                printf("%s: HBA status %x\n",
        !           838:                                    sc->sc_dv.dv_xname, ccb->ccb_hba_status);
        !           839:                                xs->error = XS_DRIVER_STUFFUP;
        !           840:                        }
        !           841:                } else if (ccb->ccb_scsi_status != SCSI_OK) {
        !           842:                        switch (ccb->ccb_scsi_status) {
        !           843:                        case SCSI_CHECK:
        !           844:                                s1 = &ccb->ccb_sense;
        !           845: #ifdef __NetBSD__
        !           846:                                s2 = &xs->sense.scsi_sense;
        !           847: #endif /* __NetBSD__ */
        !           848: #ifdef __OpenBSD__
        !           849:                                s2 = &xs->sense;
        !           850: #endif /* __OpenBSD__ */
        !           851:                                *s2 = *s1;
        !           852:                                xs->error = XS_SENSE;
        !           853:                                break;
        !           854:                        case SCSI_BUSY:
        !           855:                                xs->error = XS_BUSY;
        !           856:                                break;
        !           857:                        default:
        !           858:                                printf("%s: SCSI status %x\n",
        !           859:                                    sc->sc_dv.dv_xname, ccb->ccb_scsi_status);
        !           860:                                xs->error = XS_DRIVER_STUFFUP;
        !           861:                        }
        !           862:                } else
        !           863:                        xs->resid = 0;
        !           864:
        !           865:                xs->status = ccb->ccb_scsi_status;
        !           866:        }
        !           867:
        !           868:        /* Free up the CCB and mark the command as done */
        !           869:        dpt_free_ccb(sc, ccb);
        !           870: #ifdef __NetBSD__
        !           871:        xs->xs_status |= XS_STS_DONE;
        !           872:        scsipi_done(xs);
        !           873: #endif /* __NetBSD__ */
        !           874: #ifdef __OpenBSD__
        !           875:        xs->flags |= ITSDONE;
        !           876:        scsi_done(xs);
        !           877: #endif /* __OpenBSD__ */
        !           878:
        !           879:        /*
        !           880:         * If there are entries in the software queue, try to run the first
        !           881:         * one. We should be more or less guaranteed to succeed, since we
        !           882:         * just freed an CCB. NOTE: dpt_scsi_cmd() relies on our calling it
        !           883:         * with the first entry in the queue.
        !           884:         */
        !           885: #ifdef __NetBSD__
        !           886:        if ((xs = TAILQ_FIRST(&sc->sc_queue)) != NULL)
        !           887: #endif /* __NetBSD__ */
        !           888: #ifdef __OpenBSD__
        !           889:        if ((xs = LIST_FIRST(&sc->sc_queue)) != NULL)
        !           890: #endif /* __OpenBSD__ */
        !           891:                dpt_scsi_cmd(xs);
        !           892: }
        !           893:
        !           894: #ifdef __OpenBSD__
        !           895: /*
        !           896:  * Insert a scsi_xfer into the software queue.  We overload xs->free_list
        !           897:  * to avoid having to allocate additional resources (since we're used
        !           898:  * only during resource shortages anyhow.
        !           899:  */
        !           900: static void
        !           901: dpt_enqueue(sc, xs, infront)
        !           902:        struct dpt_softc *sc;
        !           903:        struct scsi_xfer *xs;
        !           904:        int             infront;
        !           905: {
        !           906:
        !           907:        if (infront || LIST_EMPTY(&sc->sc_queue)) {
        !           908:                if (LIST_EMPTY(&sc->sc_queue))
        !           909:                        sc->sc_queuelast = xs;
        !           910:                LIST_INSERT_HEAD(&sc->sc_queue, xs, free_list);
        !           911:                return;
        !           912:        }
        !           913:        LIST_INSERT_AFTER(sc->sc_queuelast, xs, free_list);
        !           914:        sc->sc_queuelast = xs;
        !           915: }
        !           916:
        !           917: /*
        !           918:  * Pull a scsi_xfer off the front of the software queue.
        !           919:  */
        !           920: static struct scsi_xfer *
        !           921: dpt_dequeue(sc)
        !           922:        struct dpt_softc *sc;
        !           923: {
        !           924:        struct scsi_xfer *xs;
        !           925:
        !           926:        xs = LIST_FIRST(&sc->sc_queue);
        !           927:        LIST_REMOVE(xs, free_list);
        !           928:
        !           929:        if (LIST_EMPTY(&sc->sc_queue))
        !           930:                sc->sc_queuelast = NULL;
        !           931:
        !           932:        return (xs);
        !           933: }
        !           934: #endif /* __OpenBSD__ */
        !           935:
        !           936: /*
        !           937:  * Start a SCSI command.
        !           938:  */
        !           939: int
        !           940: dpt_scsi_cmd(xs)
        !           941: #ifdef __NetBSD__
        !           942:        struct scsipi_xfer *xs;
        !           943: #endif /* __NetBSD__ */
        !           944: #ifdef __OpenBSD__
        !           945:        struct scsi_xfer *xs;
        !           946: #endif /* __OpenBSD__ */
        !           947: {
        !           948:        int error, i, flags, s, fromqueue, dontqueue;
        !           949: #ifdef __NetBSD__
        !           950:        struct scsipi_link *sc_link;
        !           951: #endif /* __NetBSD__ */
        !           952: #ifdef __OpenBSD__
        !           953:        struct scsi_link *sc_link;
        !           954: #endif /* __OpenBSD__ */
        !           955:        struct dpt_softc *sc;
        !           956:        struct dpt_ccb *ccb;
        !           957:        struct eata_sg *sg;
        !           958:        struct eata_cp *cp;
        !           959:        bus_dma_tag_t dmat;
        !           960:        bus_dmamap_t xfer;
        !           961:
        !           962:        sc_link = xs->sc_link;
        !           963: #ifdef __NetBSD__
        !           964:        flags = xs->xs_control;
        !           965: #endif /* __NetBSD__ */
        !           966: #ifdef __OpenBSD__
        !           967:        flags = xs->flags;
        !           968: #endif /* __OpenBSD__ */
        !           969:        sc = sc_link->adapter_softc;
        !           970:        dmat = sc->sc_dmat;
        !           971:        fromqueue = 0;
        !           972:        dontqueue = 0;
        !           973:
        !           974:        SC_DEBUG(sc_link, SDEV_DB2, ("dpt_scsi_cmd\n"));
        !           975:
        !           976:        /* Protect the queue */
        !           977:        s = splbio();
        !           978:
        !           979:        /*
        !           980:         * If we're running the queue from dpt_done_ccb(), we've been called
        !           981:         * with the first queue entry as our argument.
        !           982:         */
        !           983: #ifdef __NetBSD__
        !           984:        if (xs == TAILQ_FIRST(&sc->sc_queue)) {
        !           985:                TAILQ_REMOVE(&sc->sc_queue, xs, adapter_q);
        !           986: #endif /* __NetBSD__ */
        !           987: #ifdef __OpenBSD__
        !           988:        if (xs == LIST_FIRST(&sc->sc_queue)) {
        !           989:                xs = dpt_dequeue(sc);
        !           990: #endif /* __OpenBSD__ */
        !           991:                fromqueue = 1;
        !           992:        } else {
        !           993:                /* Cmds must be no more than 12 bytes for us */
        !           994:                if (xs->cmdlen > 12) {
        !           995:                        splx(s);
        !           996:                        xs->error = XS_DRIVER_STUFFUP;
        !           997:                        return (COMPLETE);
        !           998:                }
        !           999:
        !          1000:                /* XXX we can't reset devices just yet */
        !          1001: #ifdef __NetBSD__
        !          1002:                if ((flags & XS_CTL_RESET) != 0) {
        !          1003: #endif /* __NetBSD__ */
        !          1004: #ifdef __OpenBSD__
        !          1005:                if ((xs->flags & SCSI_RESET) != 0) {
        !          1006: #endif /* __OpenBSD__ */
        !          1007:                        splx(s);
        !          1008:                        xs->error = XS_DRIVER_STUFFUP;
        !          1009:                        return (COMPLETE);
        !          1010:                }
        !          1011:
        !          1012:                /* Polled requests can't be queued for later */
        !          1013: #ifdef __NetBSD__
        !          1014:                dontqueue = flags & XS_CTL_POLL;
        !          1015: #endif /* __NetBSD__ */
        !          1016: #ifdef __OpenBSD__
        !          1017:                dontqueue = xs->flags & SCSI_POLL;
        !          1018: #endif /* __OpenBSD__ */
        !          1019:
        !          1020:                /* If there are jobs in the queue, run them first */
        !          1021: #ifdef __NetBSD__
        !          1022:                if (TAILQ_FIRST(&sc->sc_queue) != NULL) {
        !          1023: #endif /* __NetBSD__ */
        !          1024: #ifdef __OpenBSD__
        !          1025:                if (!LIST_EMPTY(&sc->sc_queue)) {
        !          1026: #endif /* __OpenBSD__ */
        !          1027:                        /*
        !          1028:                         * If we can't queue we abort, since we must
        !          1029:                         * preserve the queue order.
        !          1030:                         */
        !          1031:                        if (dontqueue) {
        !          1032:                                splx(s);
        !          1033:                                return (TRY_AGAIN_LATER);
        !          1034:                        }
        !          1035:
        !          1036:                        /* Swap with the first queue entry. */
        !          1037: #ifdef __NetBSD__
        !          1038:                        TAILQ_INSERT_TAIL(&sc->sc_queue, xs, adapter_q);
        !          1039:                        xs = TAILQ_FIRST(&sc->sc_queue);
        !          1040:                        TAILQ_REMOVE(&sc->sc_queue, xs, adapter_q);
        !          1041: #endif /* __NetBSD__ */
        !          1042: #ifdef __OpenBSD__
        !          1043:                        dpt_enqueue(sc, xs, 0);
        !          1044:                        xs = dpt_dequeue(sc);
        !          1045: #endif /* __OpenBSD__ */
        !          1046:                        fromqueue = 1;
        !          1047:                }
        !          1048:        }
        !          1049:
        !          1050:        /* Get a CCB */
        !          1051: #ifdef __NetBSD__
        !          1052:        if ((ccb = dpt_alloc_ccb(sc, flags)) == NULL) {
        !          1053: #endif /* __NetBSD__ */
        !          1054: #ifdef __OpenBSD__
        !          1055:        if ((ccb = dpt_alloc_ccb(sc, xs->flags)) == NULL) {
        !          1056: #endif /* __OpenBSD__ */
        !          1057:                /* If we can't queue, we lose */
        !          1058:                if (dontqueue) {
        !          1059:                        splx(s);
        !          1060:                        return (TRY_AGAIN_LATER);
        !          1061:                }
        !          1062:
        !          1063:                /*
        !          1064:                 * Stuff request into the queue, in front if we came off
        !          1065:                 * it in the first place.
        !          1066:                 */
        !          1067: #ifdef __NetBSD__
        !          1068:                if (fromqueue)
        !          1069:                        TAILQ_INSERT_HEAD(&sc->sc_queue, xs, adapter_q);
        !          1070:                else
        !          1071:                        TAILQ_INSERT_TAIL(&sc->sc_queue, xs, adapter_q);
        !          1072: #endif /* __NetBSD__ */
        !          1073: #ifdef __OpenBSD__
        !          1074:                dpt_enqueue(sc, xs, fromqueue);
        !          1075: #endif /* __OpenBSD__ */
        !          1076:                splx(s);
        !          1077:                return (SUCCESSFULLY_QUEUED);
        !          1078:        }
        !          1079:
        !          1080:        splx(s);
        !          1081:
        !          1082:        ccb->ccb_xs = xs;
        !          1083:        ccb->ccb_timeout = xs->timeout;
        !          1084:
        !          1085:        cp = &ccb->ccb_eata_cp;
        !          1086: #ifdef __NetBSD__
        !          1087:        memcpy(&cp->cp_scsi_cmd, xs->cmd, xs->cmdlen);
        !          1088: #endif /* __NetBSD__ */
        !          1089: #ifdef __OpenBSD__
        !          1090:        bcopy(xs->cmd, &cp->cp_scsi_cmd, xs->cmdlen);
        !          1091: #endif /* __OpenBSD__ */
        !          1092:        cp->cp_ccbid = ccb->ccb_id;
        !          1093: #ifdef __NetBSD__
        !          1094:        cp->cp_id = sc_link->scsipi_scsi.target;
        !          1095:        cp->cp_lun = sc_link->scsipi_scsi.lun;
        !          1096:        cp->cp_channel = sc_link->scsipi_scsi.channel;
        !          1097: #endif /* __NetBSD__ */
        !          1098: #ifdef __OpenBSD__
        !          1099:        cp->cp_id = sc_link->target;
        !          1100:        cp->cp_lun = sc_link->lun;
        !          1101:        cp->cp_channel = sc_link->scsibus;
        !          1102: #endif /* __OpenBSD__ */
        !          1103:        cp->cp_senselen = sizeof(ccb->ccb_sense);
        !          1104:        cp->cp_stataddr = htobe32(sc->sc_sppa);
        !          1105:        cp->cp_dispri = 1;
        !          1106:        cp->cp_identify = 1;
        !          1107:        cp->cp_autosense = 1;
        !          1108: #ifdef __NetBSD__
        !          1109:        cp->cp_datain = ((flags & XS_CTL_DATA_IN) != 0);
        !          1110:        cp->cp_dataout = ((flags & XS_CTL_DATA_OUT) != 0);
        !          1111:        cp->cp_interpret = (sc->sc_hbaid[sc_link->scsipi_scsi.channel] ==
        !          1112:            sc_link->scsipi_scsi.target);
        !          1113: #endif /* __NetBSD__ */
        !          1114: #ifdef __OpenBSD__
        !          1115:        cp->cp_datain = ((xs->flags & SCSI_DATA_IN) != 0);
        !          1116:        cp->cp_dataout = ((xs->flags & SCSI_DATA_OUT) != 0);
        !          1117:        cp->cp_interpret = (sc->sc_hbaid[sc_link->scsibus] == sc_link->target);
        !          1118: #endif /* __OpenBSD__ */
        !          1119:
        !          1120:        /* Synchronous xfers musn't write-back through the cache */
        !          1121:        if (xs->bp != NULL && (xs->bp->b_flags & (B_ASYNC | B_READ)) == 0)
        !          1122:                cp->cp_nocache = 1;
        !          1123:        else
        !          1124:                cp->cp_nocache = 0;
        !          1125:
        !          1126:        cp->cp_senseaddr = htobe32(sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
        !          1127:            CCB_OFF(sc, ccb) + offsetof(struct dpt_ccb, ccb_sense));
        !          1128:
        !          1129:        if (xs->datalen) {
        !          1130:                xfer = ccb->ccb_dmamap_xfer;
        !          1131: #ifdef TFS
        !          1132: #ifdef __NetBSD__
        !          1133:                if ((flags & XS_CTL_DATA_UIO) != 0) {
        !          1134:                        error = bus_dmamap_load_uio(dmat, xfer,
        !          1135:                            (struct uio *)xs->data, (flags & XS_CTL_NOSLEEP) ?
        !          1136:                            BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1137: #endif /* __NetBSD__ */
        !          1138: #ifdef __OpenBSD__
        !          1139:                if ((xs->flags & SCSI_DATA_UIO) != 0) {
        !          1140:                        error = bus_dmamap_load_uio(dmat, xfer,
        !          1141:                            (xs->flags & SCSI_NOSLEEP) ?
        !          1142:                            BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1143: #endif /* __OpenBSD__ */
        !          1144:                } else
        !          1145: #endif /*TFS */
        !          1146:                {
        !          1147: #ifdef __NetBSD__
        !          1148:                        error = bus_dmamap_load(dmat, xfer, xs->data,
        !          1149:                            xs->datalen, NULL, (flags & XS_CTL_NOSLEEP) ?
        !          1150:                            BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1151: #endif /* __NetBSD__ */
        !          1152: #ifdef __OpenBSD__
        !          1153:                        error = bus_dmamap_load(dmat, xfer, xs->data,
        !          1154:                            xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ?
        !          1155:                            BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1156: #endif /* __OpenBSD__ */
        !          1157:                }
        !          1158:
        !          1159:                if (error) {
        !          1160:                        printf("%s: dpt_scsi_cmd: ", sc->sc_dv.dv_xname);
        !          1161:                        if (error == EFBIG)
        !          1162:                                printf("more than %d dma segs\n", DPT_SG_SIZE);
        !          1163:                        else
        !          1164:                                printf("error %d loading dma map\n", error);
        !          1165:
        !          1166:                        xs->error = XS_DRIVER_STUFFUP;
        !          1167:                        dpt_free_ccb(sc, ccb);
        !          1168:                        return (COMPLETE);
        !          1169:                }
        !          1170:
        !          1171:                bus_dmamap_sync(dmat, xfer, 0, xfer->dm_mapsize,
        !          1172:                    (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
        !          1173:                    BUS_DMASYNC_PREWRITE);
        !          1174:
        !          1175:                /* Don't bother using scatter/gather for just 1 segment */
        !          1176:                if (xfer->dm_nsegs == 1) {
        !          1177:                        cp->cp_dataaddr = htobe32(xfer->dm_segs[0].ds_addr);
        !          1178:                        cp->cp_datalen = htobe32(xfer->dm_segs[0].ds_len);
        !          1179:                        cp->cp_scatter = 0;
        !          1180:                } else {
        !          1181:                        /*
        !          1182:                         * Load the hardware scatter/gather map with the
        !          1183:                         * contents of the DMA map.
        !          1184:                         */
        !          1185:                        sg = ccb->ccb_sg;
        !          1186:                        for (i = 0; i < xfer->dm_nsegs; i++, sg++) {
        !          1187:                                sg->sg_addr =
        !          1188:                                  htobe32(xfer->dm_segs[i].ds_addr);
        !          1189:                                sg->sg_len =
        !          1190:                                  htobe32(xfer->dm_segs[i].ds_len);
        !          1191:                        }
        !          1192:                        cp->cp_dataaddr = htobe32(CCB_OFF(sc, ccb) +
        !          1193:                            sc->sc_dmamap_ccb->dm_segs[0].ds_addr +
        !          1194:                            offsetof(struct dpt_ccb, ccb_sg));
        !          1195:                        cp->cp_datalen = htobe32(i * sizeof(struct eata_sg));
        !          1196:                        cp->cp_scatter = 1;
        !          1197:                }
        !          1198:        } else {
        !          1199:                cp->cp_dataaddr = 0;
        !          1200:                cp->cp_datalen = 0;
        !          1201:                cp->cp_scatter = 0;
        !          1202:        }
        !          1203:
        !          1204:        /* Sync up CCB and status packet */
        !          1205:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, CCB_OFF(sc, ccb),
        !          1206:            sizeof(struct dpt_ccb), BUS_DMASYNC_PREWRITE);
        !          1207:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_spoff,
        !          1208:            sizeof(struct eata_sp), BUS_DMASYNC_PREREAD);
        !          1209:
        !          1210:        /*
        !          1211:         * Start the command. If we are polling on completion, mark it
        !          1212:         * private so that dpt_intr/dpt_done_ccb don't recycle the CCB
        !          1213:         * without us noticing.
        !          1214:         */
        !          1215:        if (dontqueue != 0)
        !          1216:                ccb->ccb_flg |= CCB_PRIVATE;
        !          1217:
        !          1218:        if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa, CP_DMA_CMD, 0)) {
        !          1219:                printf("%s: dpt_cmd failed\n", sc->sc_dv.dv_xname);
        !          1220:                dpt_free_ccb(sc, ccb);
        !          1221:                return (TRY_AGAIN_LATER);
        !          1222:        }
        !          1223:
        !          1224:        if (dontqueue == 0)
        !          1225:                return (SUCCESSFULLY_QUEUED);
        !          1226:
        !          1227:        /* Don't wait longer than this single command wants to wait */
        !          1228:        if (dpt_poll(sc, ccb)) {
        !          1229:                dpt_timeout(ccb);
        !          1230:                /* Wait for abort to complete */
        !          1231:                if (dpt_poll(sc, ccb))
        !          1232:                        dpt_timeout(ccb);
        !          1233:        }
        !          1234:
        !          1235:        dpt_done_ccb(sc, ccb);
        !          1236:        return (COMPLETE);
        !          1237: }
        !          1238:
        !          1239: /*
        !          1240:  * Specified CCB has timed out, abort it.
        !          1241:  */
        !          1242: void
        !          1243: dpt_timeout(arg)
        !          1244:        void *arg;
        !          1245: {
        !          1246: #ifdef __NetBSD__
        !          1247:        struct scsipi_link *sc_link;
        !          1248:        struct scsipi_xfer *xs;
        !          1249: #endif /* __NetBSD__ */
        !          1250: #ifdef __OpenBSD__
        !          1251:        struct scsi_link *sc_link;
        !          1252:        struct scsi_xfer *xs;
        !          1253: #endif /* __OpenBSD__ */
        !          1254:        struct dpt_softc *sc;
        !          1255:        struct dpt_ccb *ccb;
        !          1256:        int s;
        !          1257:
        !          1258:        ccb = arg;
        !          1259:        xs = ccb->ccb_xs;
        !          1260:        sc_link = xs->sc_link;
        !          1261:        sc  = sc_link->adapter_softc;
        !          1262:
        !          1263: #ifdef __NetBSD__
        !          1264:        scsi_print_addr(sc_link);
        !          1265: #endif /* __NetBSD__ */
        !          1266: #ifdef __OpenBSD__
        !          1267:        sc_print_addr(sc_link);
        !          1268: #endif /* __OpenBSD__ */
        !          1269:        printf("timed out (status:%02x aux status:%02x)",
        !          1270:            dpt_inb(sc, HA_STATUS), dpt_inb(sc, HA_AUX_STATUS));
        !          1271:
        !          1272:        s = splbio();
        !          1273:
        !          1274:        if ((ccb->ccb_flg & CCB_ABORT) != 0) {
        !          1275:                /* Abort timed out, reset the HBA */
        !          1276:                printf(" AGAIN, resetting HBA\n");
        !          1277:                dpt_outb(sc, HA_COMMAND, CP_RESET);
        !          1278:                DELAY(750000);
        !          1279:        } else {
        !          1280:                /* Abort the operation that has timed out */
        !          1281:                printf("\n");
        !          1282:                ccb->ccb_xs->error = XS_TIMEOUT;
        !          1283:                ccb->ccb_timeout = DPT_ABORT_TIMEOUT;
        !          1284:                ccb->ccb_flg |= CCB_ABORT;
        !          1285:                /* Start the abort */
        !          1286:                if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa,
        !          1287:                    CP_IMMEDIATE, CPI_SPEC_ABORT))
        !          1288:                    printf("%s: dpt_cmd failed\n", sc->sc_dv.dv_xname);
        !          1289:        }
        !          1290:
        !          1291:        splx(s);
        !          1292: }
        !          1293:
        !          1294: #ifdef DEBUG
        !          1295: /*
        !          1296:  * Dump the contents of an EATA status packet.
        !          1297:  */
        !          1298: void
        !          1299: dpt_dump_sp(sp)
        !          1300:        struct eata_sp *sp;
        !          1301: {
        !          1302:        int i;
        !          1303:
        !          1304:        printf("\thba_status\t%02x\n", sp->sp_hba_status);
        !          1305:        printf("\tscsi_status\t%02x\n", sp->sp_scsi_status);
        !          1306:        printf("\tinv_residue\t%d\n", sp->sp_inv_residue);
        !          1307:        printf("\tccbid\t\t%d\n", sp->sp_ccbid);
        !          1308:        printf("\tid_message\t%d\n", sp->sp_id_message);
        !          1309:        printf("\tque_message\t%d\n", sp->sp_que_message);
        !          1310:        printf("\ttag_message\t%d\n", sp->sp_tag_message);
        !          1311:        printf("\tmessages\t");
        !          1312:
        !          1313:        for (i = 0; i < 9; i++)
        !          1314:                printf("%d ", sp->sp_messages[i]);
        !          1315:
        !          1316:        printf("\n");
        !          1317: }
        !          1318: #endif /* DEBUG */
        !          1319:
        !          1320: /*
        !          1321:  * Get inquiry data from the adapter.
        !          1322:  */
        !          1323: void
        !          1324: dpt_hba_inquire(sc, ei)
        !          1325:        struct dpt_softc *sc;
        !          1326:        struct eata_inquiry_data **ei;
        !          1327: {
        !          1328:        struct dpt_ccb *ccb;
        !          1329:        struct eata_cp *cp;
        !          1330:        bus_dma_tag_t dmat;
        !          1331:
        !          1332:        *ei = (struct eata_inquiry_data *)sc->sc_scr;
        !          1333:        dmat = sc->sc_dmat;
        !          1334:
        !          1335:        /* Get a CCB and mark as private */
        !          1336:        if ((ccb = dpt_alloc_ccb(sc, 0)) == NULL)
        !          1337:                panic("%s: no CCB for inquiry", sc->sc_dv.dv_xname);
        !          1338:
        !          1339:        ccb->ccb_flg |= CCB_PRIVATE;
        !          1340:        ccb->ccb_timeout = 200;
        !          1341:
        !          1342:        /* Put all the arguments into the CCB */
        !          1343:        cp = &ccb->ccb_eata_cp;
        !          1344:        cp->cp_ccbid = ccb->ccb_id;
        !          1345:        cp->cp_id = sc->sc_hbaid[0];
        !          1346:        cp->cp_lun = 0;
        !          1347:        cp->cp_channel = 0;
        !          1348:        cp->cp_senselen = sizeof(ccb->ccb_sense);
        !          1349:        cp->cp_stataddr = htobe32(sc->sc_sppa);
        !          1350:        cp->cp_dispri = 1;
        !          1351:        cp->cp_identify = 1;
        !          1352:        cp->cp_autosense = 0;
        !          1353:        cp->cp_interpret = 1;
        !          1354:        cp->cp_nocache = 0;
        !          1355:        cp->cp_datain = 1;
        !          1356:        cp->cp_dataout = 0;
        !          1357:        cp->cp_senseaddr = 0;
        !          1358:        cp->cp_dataaddr = htobe32(sc->sc_scrpa);
        !          1359:        cp->cp_datalen = htobe32(sizeof(struct eata_inquiry_data));
        !          1360:        cp->cp_scatter = 0;
        !          1361:
        !          1362:        /* Put together the SCSI inquiry command */
        !          1363:        memset(&cp->cp_scsi_cmd, 0, 12);        /* XXX */
        !          1364:        cp->cp_scsi_cmd = INQUIRY;
        !          1365:        cp->cp_len = sizeof(struct eata_inquiry_data);
        !          1366:
        !          1367:        /* Sync up CCB, status packet and scratch area */
        !          1368:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, CCB_OFF(sc, ccb),
        !          1369:            sizeof(struct dpt_ccb), BUS_DMASYNC_PREWRITE);
        !          1370:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_spoff,
        !          1371:            sizeof(struct eata_sp), BUS_DMASYNC_PREREAD);
        !          1372:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_scroff,
        !          1373:            sizeof(struct eata_inquiry_data), BUS_DMASYNC_PREREAD);
        !          1374:
        !          1375:        /* Start the command and poll on completion */
        !          1376:        if (dpt_cmd(sc, &ccb->ccb_eata_cp, ccb->ccb_ccbpa, CP_DMA_CMD, 0))
        !          1377:                panic("%s: dpt_cmd failed", sc->sc_dv.dv_xname);
        !          1378:
        !          1379:        if (dpt_poll(sc, ccb))
        !          1380:                panic("%s: inquiry timed out", sc->sc_dv.dv_xname);
        !          1381:
        !          1382:        if (ccb->ccb_hba_status != HA_NO_ERROR ||
        !          1383:            ccb->ccb_scsi_status != SCSI_OK)
        !          1384:                panic("%s: inquiry failed (hba:%02x scsi:%02x",
        !          1385:                    sc->sc_dv.dv_xname, ccb->ccb_hba_status,
        !          1386:                    ccb->ccb_scsi_status);
        !          1387:
        !          1388:        /* Sync up the DMA map and free CCB, returning */
        !          1389:        bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ccb, sc->sc_scroff,
        !          1390:            sizeof(struct eata_inquiry_data), BUS_DMASYNC_POSTREAD);
        !          1391:        dpt_free_ccb(sc, ccb);
        !          1392: }

CVSweb