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

Annotation of sys/dev/sbus/isp_sbus.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: isp_sbus.c,v 1.8 2006/06/02 20:00:56 miod Exp $       */
        !             2: /* $NetBSD: isp_sbus.c,v 1.46 2001/09/26 20:53:14 eeh Exp $ */
        !             3:
        !             4: /*
        !             5:  * This driver, which is contained in NetBSD in the files:
        !             6:  *
        !             7:  *     sys/dev/ic/isp.c
        !             8:  *     sys/dev/ic/isp_inline.h
        !             9:  *     sys/dev/ic/isp_netbsd.c
        !            10:  *     sys/dev/ic/isp_netbsd.h
        !            11:  *     sys/dev/ic/isp_target.c
        !            12:  *     sys/dev/ic/isp_target.h
        !            13:  *     sys/dev/ic/isp_tpublic.h
        !            14:  *     sys/dev/ic/ispmbox.h
        !            15:  *     sys/dev/ic/ispreg.h
        !            16:  *     sys/dev/ic/ispvar.h
        !            17:  *     sys/microcode/isp/asm_sbus.h
        !            18:  *     sys/microcode/isp/asm_1040.h
        !            19:  *     sys/microcode/isp/asm_1080.h
        !            20:  *     sys/microcode/isp/asm_12160.h
        !            21:  *     sys/microcode/isp/asm_2100.h
        !            22:  *     sys/microcode/isp/asm_2200.h
        !            23:  *     sys/pci/isp_pci.c
        !            24:  *     sys/sbus/isp_sbus.c
        !            25:  *
        !            26:  * Is being actively maintained by Matthew Jacob (mjacob@netbsd.org).
        !            27:  * This driver also is shared source with FreeBSD, OpenBSD, Linux, Solaris,
        !            28:  * Linux versions. This tends to be an interesting maintenance problem.
        !            29:  *
        !            30:  * Please coordinate with Matthew Jacob on changes you wish to make here.
        !            31:  */
        !            32: /*
        !            33:  * SBus specific probe and attach routines for Qlogic ISP SCSI adapters.
        !            34:  *
        !            35:  * Copyright (c) 1997, 2001 by Matthew Jacob
        !            36:  * NASA AMES Research Center
        !            37:  * All rights reserved.
        !            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 immediately at the beginning of the file, without modification,
        !            44:  *    this list of conditions, and the following disclaimer.
        !            45:  * 2. Redistributions in binary form must reproduce the above copyright
        !            46:  *    notice, this list of conditions and the following disclaimer in the
        !            47:  *    documentation and/or other materials provided with the distribution.
        !            48:  *
        !            49:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            52:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
        !            53:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            59:  * SUCH DAMAGE.
        !            60:  *
        !            61:  */
        !            62:
        !            63: #include <sys/param.h>
        !            64: #include <sys/systm.h>
        !            65: #include <sys/device.h>
        !            66: #include <sys/kernel.h>
        !            67: #include <sys/malloc.h>
        !            68: #include <sys/queue.h>
        !            69:
        !            70: #include <machine/bus.h>
        !            71: #include <machine/intr.h>
        !            72: #include <machine/autoconf.h>
        !            73:
        !            74: #include <dev/ic/isp_openbsd.h>
        !            75: #if    defined(ISP_COMPILE_FW) || defined(ISP_COMPILE_1000_FW)
        !            76: #include <dev/microcode/isp/asm_sbus.h>
        !            77: #endif
        !            78: #include <dev/sbus/sbusvar.h>
        !            79: #include <sys/reboot.h>
        !            80:
        !            81: static int isp_sbus_intr(void *);
        !            82: static int
        !            83: isp_sbus_rd_isr(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *);
        !            84: static u_int16_t isp_sbus_rd_reg(struct ispsoftc *, int);
        !            85: static void isp_sbus_wr_reg (struct ispsoftc *, int, u_int16_t);
        !            86: static int isp_sbus_mbxdma(struct ispsoftc *);
        !            87: static int isp_sbus_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, u_int16_t *,
        !            88:     u_int16_t);
        !            89: static void isp_sbus_dmateardown(struct ispsoftc *, XS_T *, u_int16_t);
        !            90:
        !            91: #ifndef        ISP_1000_RISC_CODE
        !            92: #define        ISP_1000_RISC_CODE      NULL
        !            93: #endif
        !            94:
        !            95: static struct ispmdvec mdvec = {
        !            96:        isp_sbus_rd_isr,
        !            97:        isp_sbus_rd_reg,
        !            98:        isp_sbus_wr_reg,
        !            99:        isp_sbus_mbxdma,
        !           100:        isp_sbus_dmasetup,
        !           101:        isp_sbus_dmateardown,
        !           102:        NULL,
        !           103:        NULL,
        !           104:        NULL,
        !           105:        (u_int16_t *) ISP_1000_RISC_CODE
        !           106: };
        !           107:
        !           108: struct isp_sbussoftc {
        !           109:        struct ispsoftc sbus_isp;
        !           110:        sdparam         sbus_dev;
        !           111:        bus_space_tag_t sbus_bustag;
        !           112:        bus_space_handle_t sbus_reg;
        !           113:        int             sbus_node;
        !           114:        int             sbus_pri;
        !           115:        struct ispmdvec sbus_mdvec;
        !           116:        bus_dmamap_t    *sbus_dmamap;
        !           117:        int16_t         sbus_poff[_NREG_BLKS];
        !           118: };
        !           119:
        !           120:
        !           121: static int isp_match(struct device *, void *, void *);
        !           122: static void isp_sbus_attach(struct device *, struct device *, void *);
        !           123: struct cfattach isp_sbus_ca = {
        !           124:        sizeof (struct isp_sbussoftc), isp_match, isp_sbus_attach
        !           125: };
        !           126:
        !           127: static int
        !           128: isp_match(struct device *parent, void *vcf, void *aux)
        !           129: {
        !           130:        struct cfdata *cf = vcf;
        !           131:        int rv;
        !           132: #ifdef DEBUG
        !           133:        static int oneshot = 1;
        !           134: #endif
        !           135:        struct sbus_attach_args *sa = aux;
        !           136:
        !           137:        rv = (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0 ||
        !           138:                strcmp("PTI,ptisp", sa->sa_name) == 0 ||
        !           139:                strcmp("ptisp", sa->sa_name) == 0 ||
        !           140:                strcmp("SUNW,isp", sa->sa_name) == 0 ||
        !           141:                strcmp("QLGC,isp", sa->sa_name) == 0);
        !           142: #ifdef DEBUG
        !           143:        if (rv && oneshot) {
        !           144:                oneshot = 0;
        !           145:                printf("Qlogic ISP Driver, NetBSD (sbus) Platform Version "
        !           146:                    "%d.%d Core Version %d.%d\n",
        !           147:                    ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
        !           148:                    ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
        !           149:        }
        !           150: #endif
        !           151:        return (rv);
        !           152: }
        !           153:
        !           154:
        !           155: static void
        !           156: isp_sbus_attach(struct device *parent, struct device *self, void *aux)
        !           157: {
        !           158:        int freq, ispburst, sbusburst;
        !           159:        struct sbus_attach_args *sa = aux;
        !           160:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) self;
        !           161:        struct ispsoftc *isp = &sbc->sbus_isp;
        !           162:
        !           163:        printf(": %s\n", sa->sa_name);
        !           164:
        !           165:        sbc->sbus_bustag = sa->sa_bustag;
        !           166:        if (sa->sa_nintr != 0)
        !           167:                sbc->sbus_pri = sa->sa_pri;
        !           168:        sbc->sbus_mdvec = mdvec;
        !           169:
        !           170:        if (sa->sa_npromvaddrs != 0) {
        !           171:                if (bus_space_map(sa->sa_bustag, sa->sa_promvaddrs[0],
        !           172:                    sa->sa_size,
        !           173:                    BUS_SPACE_MAP_PROMADDRESS | BUS_SPACE_MAP_LINEAR,
        !           174:                    &sbc->sbus_reg) == 0) {
        !           175:                        printf("%s: cannot map registers\n", self->dv_xname);
        !           176:                        return;
        !           177:                }
        !           178:        } else {
        !           179:                if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset,
        !           180:                                 sa->sa_size, BUS_SPACE_MAP_LINEAR, 0,
        !           181:                                 &sbc->sbus_reg) != 0) {
        !           182:                        printf("%s: cannot map registers\n", self->dv_xname);
        !           183:                        return;
        !           184:                }
        !           185:        }
        !           186:        sbc->sbus_node = sa->sa_node;
        !           187:
        !           188:        freq = getpropint(sa->sa_node, "clock-frequency", 0);
        !           189:        if (freq) {
        !           190:                /*
        !           191:                 * Convert from HZ to MHz, rounding up.
        !           192:                 */
        !           193:                freq = (freq + 500000)/1000000;
        !           194: #if    0
        !           195:                printf("%s: %d MHz\n", self->dv_xname, freq);
        !           196: #endif
        !           197:        }
        !           198:        sbc->sbus_mdvec.dv_clock = freq;
        !           199:
        !           200:        /*
        !           201:         * Now figure out what the proper burst sizes, etc., to use.
        !           202:         * Unfortunately, there is no ddi_dma_burstsizes here which
        !           203:         * walks up the tree finding the limiting burst size node (if
        !           204:         * any).
        !           205:         */
        !           206:        sbusburst = ((struct sbus_softc *)parent)->sc_burst;
        !           207:        if (sbusburst == 0)
        !           208:                sbusburst = SBUS_BURST_32 - 1;
        !           209:        ispburst = getpropint(sa->sa_node, "burst-sizes", -1);
        !           210:        if (ispburst == -1) {
        !           211:                ispburst = sbusburst;
        !           212:        }
        !           213:        ispburst &= sbusburst;
        !           214:        ispburst &= ~(1 << 7);
        !           215:        ispburst &= ~(1 << 6);
        !           216:        sbc->sbus_mdvec.dv_conf1 =  0;
        !           217:        if (ispburst & (1 << 5)) {
        !           218:                sbc->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_32;
        !           219:        } else if (ispburst & (1 << 4)) {
        !           220:                sbc->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_16;
        !           221:        } else if (ispburst & (1 << 3)) {
        !           222:                sbc->sbus_mdvec.dv_conf1 =
        !           223:                    BIU_SBUS_CONF1_BURST8 | BIU_SBUS_CONF1_FIFO_8;
        !           224:        }
        !           225:        if (sbc->sbus_mdvec.dv_conf1) {
        !           226:                sbc->sbus_mdvec.dv_conf1 |= BIU_BURST_ENABLE;
        !           227:        }
        !           228:
        !           229:        /*
        !           230:         * Some early versions of the PTI SBus adapter
        !           231:         * would fail in trying to download (via poking)
        !           232:         * FW. We give up on them.
        !           233:         */
        !           234:        if (strcmp("PTI,ptisp", sa->sa_name) == 0 ||
        !           235:            strcmp("ptisp", sa->sa_name) == 0) {
        !           236:                sbc->sbus_mdvec.dv_ispfw = NULL;
        !           237:        }
        !           238:
        !           239:        isp->isp_mdvec = &sbc->sbus_mdvec;
        !           240:        isp->isp_bustype = ISP_BT_SBUS;
        !           241:        isp->isp_type = ISP_HA_SCSI_UNKNOWN;
        !           242:        isp->isp_param = &sbc->sbus_dev;
        !           243:        isp->isp_dmatag = sa->sa_dmatag;
        !           244:        MEMZERO(isp->isp_param, sizeof (sdparam));
        !           245:
        !           246:        sbc->sbus_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
        !           247:        sbc->sbus_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = SBUS_MBOX_REGS_OFF;
        !           248:        sbc->sbus_poff[SXP_BLOCK >> _BLK_REG_SHFT] = SBUS_SXP_REGS_OFF;
        !           249:        sbc->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF;
        !           250:        sbc->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
        !           251:
        !           252:        /* Establish interrupt channel */
        !           253:        bus_intr_establish(sbc->sbus_bustag, sbc->sbus_pri, IPL_BIO, 0,
        !           254:            isp_sbus_intr, sbc, self->dv_xname);
        !           255:
        !           256:        /*
        !           257:         * Set up logging levels.
        !           258:         */
        !           259: #ifdef ISP_LOGDEFAULT
        !           260:        isp->isp_dblev = ISP_LOGDEFAULT;
        !           261: #else
        !           262:        isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
        !           263: #ifdef SCSIDEBUG
        !           264:        isp->isp_dblev |= ISP_LOGDEBUG1|ISP_LOGDEBUG2;
        !           265: #endif
        !           266: #ifdef DEBUG
        !           267:        isp->isp_dblev |= ISP_LOGDEBUG0|ISP_LOGCONFIG|ISP_LOGINFO;
        !           268: #endif
        !           269: #endif
        !           270:
        !           271:        isp->isp_confopts = self->dv_cfdata->cf_flags;
        !           272:        isp->isp_role = ISP_DEFAULT_ROLES;
        !           273:
        !           274:        /*
        !           275:         * There's no tool on sparc to set NVRAM for ISPs, so ignore it.
        !           276:         */
        !           277:        isp->isp_confopts |= ISP_CFG_NONVRAM;
        !           278:        ISP_LOCK(isp);
        !           279:        isp->isp_osinfo.no_mbox_ints = 1;
        !           280:        isp_reset(isp);
        !           281:        if (isp->isp_state != ISP_RESETSTATE) {
        !           282:                ISP_UNLOCK(isp);
        !           283:                return;
        !           284:        }
        !           285:        ENABLE_INTS(isp);
        !           286:        isp_init(isp);
        !           287:        if (isp->isp_state != ISP_INITSTATE) {
        !           288:                isp_uninit(isp);
        !           289:                ISP_UNLOCK(isp);
        !           290:                return;
        !           291:        }
        !           292:
        !           293:        /*
        !           294:         * do generic attach.
        !           295:         */
        !           296:        ISP_UNLOCK(isp);
        !           297:        isp_attach(isp);
        !           298:        if (isp->isp_state != ISP_RUNSTATE) {
        !           299:                ISP_LOCK(isp);
        !           300:                isp_uninit(isp);
        !           301:                ISP_UNLOCK(isp);
        !           302:        }
        !           303: }
        !           304:
        !           305: static int
        !           306: isp_sbus_intr(void *arg)
        !           307: {
        !           308:        u_int16_t isr, sema, mbox;
        !           309:        struct ispsoftc *isp = arg;
        !           310:
        !           311:        isp->isp_intcnt++;
        !           312:        if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
        !           313:                isp->isp_intbogus++;
        !           314:                return (0);
        !           315:        } else {
        !           316:                isp->isp_osinfo.onintstack = 1;
        !           317:                isp_intr(isp, isr, sema, mbox);
        !           318:                isp->isp_osinfo.onintstack = 0;
        !           319:                return (1);
        !           320:        }
        !           321: }
        !           322:
        !           323: #define        IspVirt2Off(a, x)       \
        !           324:        (((struct isp_sbussoftc *)a)->sbus_poff[((x) & _BLK_REG_MASK) >> \
        !           325:        _BLK_REG_SHFT] + ((x) & 0xff))
        !           326:
        !           327: #define        BXR2(sbc, off)          \
        !           328:        bus_space_read_2(sbc->sbus_bustag, sbc->sbus_reg, off)
        !           329:
        !           330: static int
        !           331: isp_sbus_rd_isr(struct ispsoftc *isp, u_int16_t *isrp,
        !           332:     u_int16_t *semap, u_int16_t *mbp)
        !           333: {
        !           334:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
        !           335:        u_int16_t isr, sema;
        !           336:
        !           337:        isr = BXR2(sbc, IspVirt2Off(isp, BIU_ISR));
        !           338:        sema = BXR2(sbc, IspVirt2Off(isp, BIU_SEMA));
        !           339:        isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
        !           340:        isr &= INT_PENDING_MASK(isp);
        !           341:        sema &= BIU_SEMA_LOCK;
        !           342:        if (isr == 0 && sema == 0) {
        !           343:                return (0);
        !           344:        }
        !           345:        *isrp = isr;
        !           346:        if ((*semap = sema) != 0) {
        !           347:                *mbp = BXR2(sbc, IspVirt2Off(isp, OUTMAILBOX0));
        !           348:        }
        !           349:        return (1);
        !           350: }
        !           351:
        !           352: static u_int16_t
        !           353: isp_sbus_rd_reg(struct ispsoftc *isp, int regoff)
        !           354: {
        !           355:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
        !           356:        int offset = sbc->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
        !           357:        offset += (regoff & 0xff);
        !           358:        return (bus_space_read_2(sbc->sbus_bustag, sbc->sbus_reg, offset));
        !           359: }
        !           360:
        !           361: static void
        !           362: isp_sbus_wr_reg(struct ispsoftc *isp, int regoff, u_int16_t val)
        !           363: {
        !           364:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
        !           365:        int offset = sbc->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
        !           366:        offset += (regoff & 0xff);
        !           367:        bus_space_write_2(sbc->sbus_bustag, sbc->sbus_reg, offset, val);
        !           368: }
        !           369:
        !           370: static int
        !           371: isp_sbus_mbxdma(struct ispsoftc *isp)
        !           372: {
        !           373:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
        !           374:        bus_dma_segment_t reqseg, rspseg;
        !           375:        int reqrs, rsprs, i, progress;
        !           376:        size_t n;
        !           377:        bus_size_t len;
        !           378:
        !           379:        if (isp->isp_rquest_dma)
        !           380:                return (0);
        !           381:
        !           382:        n = isp->isp_maxcmds * sizeof (XS_T *);
        !           383:        isp->isp_xflist = (XS_T **) malloc(n, M_DEVBUF, M_WAITOK);
        !           384:        if (isp->isp_xflist == NULL) {
        !           385:                isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
        !           386:                return (1);
        !           387:        }
        !           388:        MEMZERO(isp->isp_xflist, n);
        !           389:        n = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
        !           390:        sbc->sbus_dmamap = (bus_dmamap_t *) malloc(n, M_DEVBUF, M_WAITOK);
        !           391:        if (sbc->sbus_dmamap == NULL) {
        !           392:                free(isp->isp_xflist, M_DEVBUF);
        !           393:                isp->isp_xflist = NULL;
        !           394:                isp_prt(isp, ISP_LOGERR, "cannot alloc dmamap array");
        !           395:                return (1);
        !           396:        }
        !           397:        for (i = 0; i < isp->isp_maxcmds; i++) {
        !           398:                /* Allocate a DMA handle */
        !           399:                if (bus_dmamap_create(isp->isp_dmatag, MAXPHYS, 1, MAXPHYS, 0,
        !           400:                    BUS_DMA_NOWAIT, &sbc->sbus_dmamap[i]) != 0) {
        !           401:                        isp_prt(isp, ISP_LOGERR, "cmd DMA maps create error");
        !           402:                        break;
        !           403:                }
        !           404:        }
        !           405:        if (i < isp->isp_maxcmds) {
        !           406:                while (--i >= 0) {
        !           407:                        bus_dmamap_destroy(isp->isp_dmatag,
        !           408:                            sbc->sbus_dmamap[i]);
        !           409:                }
        !           410:                free(isp->isp_xflist, M_DEVBUF);
        !           411:                free(sbc->sbus_dmamap, M_DEVBUF);
        !           412:                isp->isp_xflist = NULL;
        !           413:                sbc->sbus_dmamap = NULL;
        !           414:                return (1);
        !           415:        }
        !           416:
        !           417:        /*
        !           418:         * Allocate and map the request and response queues
        !           419:         */
        !           420:        progress = 0;
        !           421:        len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
        !           422:        if (bus_dmamem_alloc(isp->isp_dmatag, len, 0, 0, &reqseg, 1, &reqrs,
        !           423:            BUS_DMA_NOWAIT)) {
        !           424:                goto dmafail;
        !           425:        }
        !           426:        progress++;
        !           427:        if (bus_dmamem_map(isp->isp_dmatag, &reqseg, reqrs, len,
        !           428:            (caddr_t *)&isp->isp_rquest, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
        !           429:                goto dmafail;
        !           430:        }
        !           431:        progress++;
        !           432:        if (bus_dmamap_create(isp->isp_dmatag, len, 1, len, 0, BUS_DMA_NOWAIT,
        !           433:            &isp->isp_rqdmap) != 0) {
        !           434:                goto dmafail;
        !           435:        }
        !           436:        progress++;
        !           437:        if (bus_dmamap_load(isp->isp_dmatag, isp->isp_rqdmap,
        !           438:            isp->isp_rquest, len, NULL, BUS_DMA_NOWAIT) != 0) {
        !           439:                goto dmafail;
        !           440:        }
        !           441:        progress++;
        !           442:        isp->isp_rquest_dma = isp->isp_rqdmap->dm_segs[0].ds_addr;
        !           443:
        !           444:        len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
        !           445:        if (bus_dmamem_alloc(isp->isp_dmatag, len, 0, 0, &rspseg, 1, &rsprs,
        !           446:            BUS_DMA_NOWAIT)) {
        !           447:                goto dmafail;
        !           448:        }
        !           449:        progress++;
        !           450:        if (bus_dmamem_map(isp->isp_dmatag, &rspseg, rsprs, len,
        !           451:            (caddr_t *)&isp->isp_result, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
        !           452:                goto dmafail;
        !           453:        }
        !           454:        progress++;
        !           455:        if (bus_dmamap_create(isp->isp_dmatag, len, 1, len, 0, BUS_DMA_NOWAIT,
        !           456:            &isp->isp_rsdmap) != 0) {
        !           457:                goto dmafail;
        !           458:        }
        !           459:        progress++;
        !           460:        if (bus_dmamap_load(isp->isp_dmatag, isp->isp_rsdmap,
        !           461:            isp->isp_result, len, NULL, BUS_DMA_NOWAIT) != 0) {
        !           462:                goto dmafail;
        !           463:        }
        !           464:        isp->isp_result_dma = isp->isp_rsdmap->dm_segs[0].ds_addr;
        !           465:
        !           466:        return (0);
        !           467:
        !           468: dmafail:
        !           469:        isp_prt(isp, ISP_LOGERR, "Mailbox DMA Setup Failure");
        !           470:
        !           471:        if (progress >= 8) {
        !           472:                bus_dmamap_unload(isp->isp_dmatag, isp->isp_rsdmap);
        !           473:        }
        !           474:        if (progress >= 7) {
        !           475:                bus_dmamap_destroy(isp->isp_dmatag, isp->isp_rsdmap);
        !           476:        }
        !           477:        if (progress >= 6) {
        !           478:                bus_dmamem_unmap(isp->isp_dmatag,
        !           479:                    isp->isp_result, ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)));
        !           480:        }
        !           481:        if (progress >= 5) {
        !           482:                bus_dmamem_free(isp->isp_dmatag, &rspseg, rsprs);
        !           483:        }
        !           484:
        !           485:        if (progress >= 4) {
        !           486:                bus_dmamap_unload(isp->isp_dmatag, isp->isp_rqdmap);
        !           487:        }
        !           488:        if (progress >= 3) {
        !           489:                bus_dmamap_destroy(isp->isp_dmatag, isp->isp_rqdmap);
        !           490:        }
        !           491:        if (progress >= 2) {
        !           492:                bus_dmamem_unmap(isp->isp_dmatag,
        !           493:                    isp->isp_rquest, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)));
        !           494:        }
        !           495:        if (progress >= 1) {
        !           496:                bus_dmamem_free(isp->isp_dmatag, &reqseg, reqrs);
        !           497:        }
        !           498:
        !           499:        for (i = 0; i < isp->isp_maxcmds; i++) {
        !           500:                bus_dmamap_destroy(isp->isp_dmatag, sbc->sbus_dmamap[i]);
        !           501:        }
        !           502:        free(sbc->sbus_dmamap, M_DEVBUF);
        !           503:        free(isp->isp_xflist, M_DEVBUF);
        !           504:        isp->isp_xflist = NULL;
        !           505:        sbc->sbus_dmamap = NULL;
        !           506:        return (1);
        !           507: }
        !           508:
        !           509: /*
        !           510:  * Map a DMA request.
        !           511:  * We're guaranteed that rq->req_handle is a value from 1 to isp->isp_maxcmds.
        !           512:  */
        !           513:
        !           514: static int
        !           515: isp_sbus_dmasetup(struct ispsoftc *isp, XS_T *xs, ispreq_t *rq,
        !           516:     u_int16_t *nxtip, u_int16_t optr)
        !           517: {
        !           518:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
        !           519:        bus_dmamap_t dmap;
        !           520:        ispreq_t *qep;
        !           521:        int cansleep = (xs->flags & SCSI_NOSLEEP) == 0;
        !           522:        int in = (xs->flags & SCSI_DATA_IN) != 0;
        !           523:
        !           524:        qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx);
        !           525:        if (xs->datalen == 0) {
        !           526:                rq->req_seg_count = 1;
        !           527:                goto mbxsync;
        !           528:        }
        !           529:
        !           530:        dmap = sbc->sbus_dmamap[isp_handle_index(rq->req_handle)];
        !           531:        if (dmap->dm_nsegs != 0) {
        !           532:                panic("%s: dma map already allocated", isp->isp_name);
        !           533:                /* NOTREACHED */
        !           534:        }
        !           535:        if (bus_dmamap_load(isp->isp_dmatag, dmap, xs->data, xs->datalen,
        !           536:            NULL, (cansleep ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) |
        !           537:            BUS_DMA_STREAMING) != 0) {
        !           538:                XS_SETERR(xs, HBA_BOTCH);
        !           539:                return (CMD_COMPLETE);
        !           540:        }
        !           541:
        !           542:        bus_dmamap_sync(isp->isp_dmatag, dmap, 0, xs->datalen,
        !           543:            in? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
        !           544:
        !           545:        if (in) {
        !           546:                rq->req_flags |= REQFLAG_DATA_IN;
        !           547:        } else {
        !           548:                rq->req_flags |= REQFLAG_DATA_OUT;
        !           549:        }
        !           550:
        !           551:        if (XS_CDBLEN(xs) > 12) {
        !           552:                u_int16_t onxti;
        !           553:                ispcontreq_t local, *crq = &local, *cqe;
        !           554:
        !           555:                onxti = *nxtip;
        !           556:                cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, onxti);
        !           557:                *nxtip = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
        !           558:                if (*nxtip == optr) {
        !           559:                        isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
        !           560:                        bus_dmamap_unload(isp->isp_dmatag, dmap);
        !           561:                        XS_SETERR(xs, HBA_BOTCH);
        !           562:                        return (CMD_EAGAIN);
        !           563:                }
        !           564:                rq->req_seg_count = 2;
        !           565:                MEMZERO((void *)crq, sizeof (*crq));
        !           566:                crq->req_header.rqs_entry_count = 1;
        !           567:                crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
        !           568:                crq->req_dataseg[0].ds_count = xs->datalen;
        !           569:                crq->req_dataseg[0].ds_base = dmap->dm_segs[0].ds_addr;
        !           570:                isp_put_cont_req(isp, crq, cqe);
        !           571:                MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
        !           572:        } else {
        !           573:                rq->req_seg_count = 1;
        !           574:                rq->req_dataseg[0].ds_count = xs->datalen;
        !           575:                rq->req_dataseg[0].ds_base = dmap->dm_segs[0].ds_addr;
        !           576:        }
        !           577:
        !           578: mbxsync:
        !           579:        if (XS_CDBLEN(xs) > 12) {
        !           580:                isp_put_extended_request(isp,
        !           581:                    (ispextreq_t *)rq, (ispextreq_t *) qep);
        !           582:        } else {
        !           583:                isp_put_request(isp, rq, qep);
        !           584:        }
        !           585:        return (CMD_QUEUED);
        !           586: }
        !           587:
        !           588: static void
        !           589: isp_sbus_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle)
        !           590: {
        !           591:        struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
        !           592:        bus_dmamap_t dmap;
        !           593:
        !           594:        dmap = sbc->sbus_dmamap[isp_handle_index(handle)];
        !           595:
        !           596:        if (dmap->dm_nsegs == 0) {
        !           597:                panic("%s: dma map not already allocated", isp->isp_name);
        !           598:                /* NOTREACHED */
        !           599:        }
        !           600:        bus_dmamap_sync(isp->isp_dmatag, dmap, 0,
        !           601:            xs->datalen, (xs->flags & SCSI_DATA_IN)?
        !           602:            BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !           603:        bus_dmamap_unload(isp->isp_dmatag, dmap);
        !           604: }

CVSweb