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

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

1.1     ! nbrk        1: /*     $OpenBSD: mpi.c,v 1.86 2007/06/12 19:29:23 thib Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005, 2006 David Gwynne <dlg@openbsd.org>
        !             5:  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
        !             6:  *
        !             7:  * Permission to use, copy, modify, and distribute this software for any
        !             8:  * purpose with or without fee is hereby granted, provided that the above
        !             9:  * copyright notice and this permission notice appear in all copies.
        !            10:  *
        !            11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19:
        !            20: #include <sys/param.h>
        !            21: #include <sys/systm.h>
        !            22: #include <sys/buf.h>
        !            23: #include <sys/device.h>
        !            24: #include <sys/proc.h>
        !            25: #include <sys/malloc.h>
        !            26: #include <sys/kernel.h>
        !            27:
        !            28: #include <machine/bus.h>
        !            29:
        !            30: #include <scsi/scsi_all.h>
        !            31: #include <scsi/scsiconf.h>
        !            32:
        !            33: #include <dev/ic/mpireg.h>
        !            34: #include <dev/ic/mpivar.h>
        !            35:
        !            36: #ifdef MPI_DEBUG
        !            37: uint32_t       mpi_debug = 0
        !            38: /*                 | MPI_D_CMD */
        !            39: /*                 | MPI_D_INTR */
        !            40: /*                 | MPI_D_MISC */
        !            41: /*                 | MPI_D_DMA */
        !            42: /*                 | MPI_D_IOCTL */
        !            43: /*                 | MPI_D_RW */
        !            44: /*                 | MPI_D_MEM */
        !            45: /*                 | MPI_D_CCB */
        !            46: /*                 | MPI_D_PPR */
        !            47: /*                 | MPI_D_RAID */
        !            48: /*                 | MPI_D_EVT */
        !            49:                ;
        !            50: #endif
        !            51:
        !            52: struct cfdriver mpi_cd = {
        !            53:        NULL, "mpi", DV_DULL
        !            54: };
        !            55:
        !            56: int                    mpi_scsi_cmd(struct scsi_xfer *);
        !            57: void                   mpi_scsi_cmd_done(struct mpi_ccb *);
        !            58: void                   mpi_minphys(struct buf *bp);
        !            59: int                    mpi_scsi_ioctl(struct scsi_link *, u_long, caddr_t,
        !            60:                            int, struct proc *);
        !            61:
        !            62: struct scsi_adapter mpi_switch = {
        !            63:        mpi_scsi_cmd, mpi_minphys, NULL, NULL, mpi_scsi_ioctl
        !            64: };
        !            65:
        !            66: struct scsi_device mpi_dev = {
        !            67:        NULL, NULL, NULL, NULL
        !            68: };
        !            69:
        !            70: struct mpi_dmamem      *mpi_dmamem_alloc(struct mpi_softc *, size_t);
        !            71: void                   mpi_dmamem_free(struct mpi_softc *,
        !            72:                            struct mpi_dmamem *);
        !            73: int                    mpi_alloc_ccbs(struct mpi_softc *);
        !            74: struct mpi_ccb         *mpi_get_ccb(struct mpi_softc *);
        !            75: void                   mpi_put_ccb(struct mpi_softc *, struct mpi_ccb *);
        !            76: int                    mpi_alloc_replies(struct mpi_softc *);
        !            77: void                   mpi_push_replies(struct mpi_softc *);
        !            78:
        !            79: void                   mpi_start(struct mpi_softc *, struct mpi_ccb *);
        !            80: int                    mpi_complete(struct mpi_softc *, struct mpi_ccb *, int);
        !            81: int                    mpi_poll(struct mpi_softc *, struct mpi_ccb *, int);
        !            82: int                    mpi_reply(struct mpi_softc *, u_int32_t);
        !            83:
        !            84: void                   mpi_squash_ppr(struct mpi_softc *);
        !            85: void                   mpi_run_ppr(struct mpi_softc *);
        !            86: int                    mpi_ppr(struct mpi_softc *, struct scsi_link *,
        !            87:                            struct mpi_cfg_raid_physdisk *, int, int, int);
        !            88: int                    mpi_inq(struct mpi_softc *, u_int16_t, int);
        !            89:
        !            90: void                   mpi_timeout_xs(void *);
        !            91: int                    mpi_load_xs(struct mpi_ccb *);
        !            92:
        !            93: u_int32_t              mpi_read(struct mpi_softc *, bus_size_t);
        !            94: void                   mpi_write(struct mpi_softc *, bus_size_t, u_int32_t);
        !            95: int                    mpi_wait_eq(struct mpi_softc *, bus_size_t, u_int32_t,
        !            96:                            u_int32_t);
        !            97: int                    mpi_wait_ne(struct mpi_softc *, bus_size_t, u_int32_t,
        !            98:                            u_int32_t);
        !            99:
        !           100: int                    mpi_init(struct mpi_softc *);
        !           101: int                    mpi_reset_soft(struct mpi_softc *);
        !           102: int                    mpi_reset_hard(struct mpi_softc *);
        !           103:
        !           104: int                    mpi_handshake_send(struct mpi_softc *, void *, size_t);
        !           105: int                    mpi_handshake_recv_dword(struct mpi_softc *,
        !           106:                            u_int32_t *);
        !           107: int                    mpi_handshake_recv(struct mpi_softc *, void *, size_t);
        !           108:
        !           109: void                   mpi_empty_done(struct mpi_ccb *);
        !           110:
        !           111: int                    mpi_iocinit(struct mpi_softc *);
        !           112: int                    mpi_iocfacts(struct mpi_softc *);
        !           113: int                    mpi_portfacts(struct mpi_softc *);
        !           114: int                    mpi_portenable(struct mpi_softc *);
        !           115: void                   mpi_get_raid(struct mpi_softc *);
        !           116: int                    mpi_fwupload(struct mpi_softc *);
        !           117:
        !           118: int                    mpi_eventnotify(struct mpi_softc *);
        !           119: void                   mpi_eventnotify_done(struct mpi_ccb *);
        !           120: void                   mpi_eventack(struct mpi_softc *,
        !           121:                            struct mpi_msg_event_reply *);
        !           122: void                   mpi_eventack_done(struct mpi_ccb *);
        !           123: void                   mpi_evt_sas(void *, void *);
        !           124:
        !           125: int                    mpi_cfg_header(struct mpi_softc *, u_int8_t, u_int8_t,
        !           126:                            u_int32_t, struct mpi_cfg_hdr *);
        !           127: int                    mpi_cfg_page(struct mpi_softc *, u_int32_t,
        !           128:                            struct mpi_cfg_hdr *, int, void *, size_t);
        !           129:
        !           130: #define DEVNAME(s)             ((s)->sc_dev.dv_xname)
        !           131:
        !           132: #define        dwordsof(s)             (sizeof(s) / sizeof(u_int32_t))
        !           133: #define        sizeofa(s)              (sizeof(s) / sizeof((s)[0]))
        !           134:
        !           135: #define mpi_read_db(s)         mpi_read((s), MPI_DOORBELL)
        !           136: #define mpi_write_db(s, v)     mpi_write((s), MPI_DOORBELL, (v))
        !           137: #define mpi_read_intr(s)       mpi_read((s), MPI_INTR_STATUS)
        !           138: #define mpi_write_intr(s, v)   mpi_write((s), MPI_INTR_STATUS, (v))
        !           139: #define mpi_pop_reply(s)       mpi_read((s), MPI_REPLY_QUEUE)
        !           140: #define mpi_push_reply(s, v)   mpi_write((s), MPI_REPLY_QUEUE, (v))
        !           141:
        !           142: #define mpi_wait_db_int(s)     mpi_wait_ne((s), MPI_INTR_STATUS, \
        !           143:                                    MPI_INTR_STATUS_DOORBELL, 0)
        !           144: #define mpi_wait_db_ack(s)     mpi_wait_eq((s), MPI_INTR_STATUS, \
        !           145:                                    MPI_INTR_STATUS_IOCDOORBELL, 0)
        !           146:
        !           147: int
        !           148: mpi_attach(struct mpi_softc *sc)
        !           149: {
        !           150:        struct scsibus_attach_args      saa;
        !           151:        struct mpi_ccb                  *ccb;
        !           152:
        !           153:        printf("\n");
        !           154:
        !           155:        /* disable interrupts */
        !           156:        mpi_write(sc, MPI_INTR_MASK,
        !           157:            MPI_INTR_MASK_REPLY | MPI_INTR_MASK_DOORBELL);
        !           158:
        !           159:        if (mpi_init(sc) != 0) {
        !           160:                printf("%s: unable to initialise\n", DEVNAME(sc));
        !           161:                return (1);
        !           162:        }
        !           163:
        !           164:        if (mpi_iocfacts(sc) != 0) {
        !           165:                printf("%s: unable to get iocfacts\n", DEVNAME(sc));
        !           166:                return (1);
        !           167:        }
        !           168:
        !           169:        if (mpi_alloc_ccbs(sc) != 0) {
        !           170:                /* error already printed */
        !           171:                return (1);
        !           172:        }
        !           173:
        !           174:        if (mpi_alloc_replies(sc) != 0) {
        !           175:                printf("%s: unable to allocate reply space\n", DEVNAME(sc));
        !           176:                goto free_ccbs;
        !           177:        }
        !           178:
        !           179:        if (mpi_iocinit(sc) != 0) {
        !           180:                printf("%s: unable to send iocinit\n", DEVNAME(sc));
        !           181:                goto free_ccbs;
        !           182:        }
        !           183:
        !           184:        /* spin until we're operational */
        !           185:        if (mpi_wait_eq(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
        !           186:            MPI_DOORBELL_STATE_OPER) != 0) {
        !           187:                printf("%s: state: 0x%08x\n", DEVNAME(sc),
        !           188:                    mpi_read_db(sc) & MPI_DOORBELL_STATE);
        !           189:                printf("%s: operational state timeout\n", DEVNAME(sc));
        !           190:                goto free_ccbs;
        !           191:        }
        !           192:
        !           193:        mpi_push_replies(sc);
        !           194:
        !           195:        if (mpi_portfacts(sc) != 0) {
        !           196:                printf("%s: unable to get portfacts\n", DEVNAME(sc));
        !           197:                goto free_replies;
        !           198:        }
        !           199:
        !           200: #ifdef notyet
        !           201:        if (mpi_eventnotify(sc) != 0) {
        !           202:                printf("%s: unable to get portfacts\n", DEVNAME(sc));
        !           203:                goto free_replies;
        !           204:        }
        !           205: #endif
        !           206:
        !           207:        if (mpi_portenable(sc) != 0) {
        !           208:                printf("%s: unable to enable port\n", DEVNAME(sc));
        !           209:                goto free_replies;
        !           210:        }
        !           211:
        !           212:        if (mpi_fwupload(sc) != 0) {
        !           213:                printf("%s: unable to upload firmware\n", DEVNAME(sc));
        !           214:                goto free_replies;
        !           215:        }
        !           216:
        !           217:        if (sc->sc_porttype == MPI_PORTFACTS_PORTTYPE_SCSI)
        !           218:                mpi_squash_ppr(sc);
        !           219:
        !           220:        /* we should be good to go now, attach scsibus */
        !           221:        sc->sc_link.device = &mpi_dev;
        !           222:        sc->sc_link.adapter = &mpi_switch;
        !           223:        sc->sc_link.adapter_softc = sc;
        !           224:        sc->sc_link.adapter_target = sc->sc_target;
        !           225:        sc->sc_link.adapter_buswidth = sc->sc_buswidth;
        !           226:        sc->sc_link.openings = sc->sc_maxcmds / sc->sc_buswidth;
        !           227:
        !           228:        bzero(&saa, sizeof(saa));
        !           229:        saa.saa_sc_link = &sc->sc_link;
        !           230:
        !           231:        /* config_found() returns the scsibus attached to us */
        !           232:        sc->sc_scsibus = (struct scsibus_softc *) config_found(&sc->sc_dev,
        !           233:            &saa, scsiprint);
        !           234:
        !           235:        /* get raid pages */
        !           236:        mpi_get_raid(sc);
        !           237:
        !           238:        /* do domain validation */
        !           239:        if (sc->sc_porttype == MPI_PORTFACTS_PORTTYPE_SCSI)
        !           240:                mpi_run_ppr(sc);
        !           241:
        !           242:        /* enable interrupts */
        !           243:        mpi_write(sc, MPI_INTR_MASK, MPI_INTR_MASK_DOORBELL);
        !           244:
        !           245:        return (0);
        !           246:
        !           247: free_replies:
        !           248:        bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies),
        !           249:            0, PAGE_SIZE, BUS_DMASYNC_POSTREAD);
        !           250:        mpi_dmamem_free(sc, sc->sc_replies);
        !           251: free_ccbs:
        !           252:        while ((ccb = mpi_get_ccb(sc)) != NULL)
        !           253:                bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
        !           254:        mpi_dmamem_free(sc, sc->sc_requests);
        !           255:        free(sc->sc_ccbs, M_DEVBUF);
        !           256:
        !           257:        return(1);
        !           258: }
        !           259:
        !           260: void
        !           261: mpi_squash_ppr(struct mpi_softc *sc)
        !           262: {
        !           263:        struct mpi_cfg_hdr              hdr;
        !           264:        struct mpi_cfg_spi_dev_pg1      page;
        !           265:        int                             i;
        !           266:
        !           267:        DNPRINTF(MPI_D_PPR, "%s: mpi_squash_ppr\n", DEVNAME(sc));
        !           268:
        !           269:        for (i = 0; i < sc->sc_buswidth; i++) {
        !           270:                if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_DEV,
        !           271:                    1, i, &hdr) != 0)
        !           272:                        return;
        !           273:
        !           274:                if (mpi_cfg_page(sc, i, &hdr, 1, &page, sizeof(page)) != 0)
        !           275:                        return;
        !           276:
        !           277:                DNPRINTF(MPI_D_PPR, "%s:  target: %d req_params1: 0x%02x "
        !           278:                    "req_offset: 0x%02x req_period: 0x%02x "
        !           279:                    "req_params2: 0x%02x conf: 0x%08x\n", DEVNAME(sc), i,
        !           280:                    page.req_params1, page.req_offset, page.req_period,
        !           281:                    page.req_params2, letoh32(page.configuration));
        !           282:
        !           283:                page.req_params1 = 0x0;
        !           284:                page.req_offset = 0x0;
        !           285:                page.req_period = 0x0;
        !           286:                page.req_params2 = 0x0;
        !           287:                page.configuration = htole32(0x0);
        !           288:
        !           289:                if (mpi_cfg_page(sc, i, &hdr, 0, &page, sizeof(page)) != 0)
        !           290:                        return;
        !           291:        }
        !           292: }
        !           293:
        !           294: void
        !           295: mpi_run_ppr(struct mpi_softc *sc)
        !           296: {
        !           297:        struct mpi_cfg_hdr              hdr;
        !           298:        struct mpi_cfg_spi_port_pg0     port_pg;
        !           299:        struct mpi_cfg_ioc_pg3          *physdisk_pg;
        !           300:        struct mpi_cfg_raid_physdisk    *physdisk_list, *physdisk;
        !           301:        size_t                          pagelen;
        !           302:        struct scsi_link                *link;
        !           303:        int                             i, tries;
        !           304:
        !           305:        if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_PORT, 0, 0x0,
        !           306:            &hdr) != 0) {
        !           307:                DNPRINTF(MPI_D_PPR, "%s: mpi_run_ppr unable to fetch header\n",
        !           308:                    DEVNAME(sc));
        !           309:                return;
        !           310:        }
        !           311:
        !           312:        if (mpi_cfg_page(sc, 0x0, &hdr, 1, &port_pg, sizeof(port_pg)) != 0) {
        !           313:                DNPRINTF(MPI_D_PPR, "%s: mpi_run_ppr unable to fetch page\n",
        !           314:                    DEVNAME(sc));
        !           315:                return;
        !           316:        }
        !           317:
        !           318:        for (i = 0; i < sc->sc_buswidth; i++) {
        !           319:                link = sc->sc_scsibus->sc_link[i][0];
        !           320:                if (link == NULL)
        !           321:                        continue;
        !           322:
        !           323:                /* do not ppr volumes */
        !           324:                if (link->flags & SDEV_VIRTUAL)
        !           325:                        continue;
        !           326:
        !           327:                tries = 0;
        !           328:                while (mpi_ppr(sc, link, NULL, port_pg.min_period,
        !           329:                    port_pg.max_offset, tries) == EAGAIN)
        !           330:                        tries++;
        !           331:        }
        !           332:
        !           333:        if ((sc->sc_flags & MPI_F_RAID) == 0)
        !           334:                return;
        !           335:
        !           336:        if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_IOC, 3, 0x0,
        !           337:            &hdr) != 0) {
        !           338:                DNPRINTF(MPI_D_RAID|MPI_D_PPR, "%s: mpi_run_ppr unable to "
        !           339:                    "fetch ioc pg 3 header\n", DEVNAME(sc));
        !           340:                return;
        !           341:        }
        !           342:
        !           343:        pagelen = hdr.page_length * 4; /* dwords to bytes */
        !           344:        physdisk_pg = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL);
        !           345:        if (physdisk_pg == NULL) {
        !           346:                DNPRINTF(MPI_D_RAID|MPI_D_PPR, "%s: mpi_run_ppr unable to "
        !           347:                    "allocate ioc pg 3\n", DEVNAME(sc));
        !           348:                return;
        !           349:        }
        !           350:        physdisk_list = (struct mpi_cfg_raid_physdisk *)(physdisk_pg + 1);
        !           351:
        !           352:        if (mpi_cfg_page(sc, 0, &hdr, 1, physdisk_pg, pagelen) != 0) {
        !           353:                DNPRINTF(MPI_D_PPR|MPI_D_PPR, "%s: mpi_run_ppr unable to "
        !           354:                    "fetch ioc page 3\n", DEVNAME(sc));
        !           355:                goto out;
        !           356:        }
        !           357:
        !           358:        DNPRINTF(MPI_D_PPR|MPI_D_PPR, "%s:  no_phys_disks: %d\n", DEVNAME(sc),
        !           359:            physdisk_pg->no_phys_disks);
        !           360:
        !           361:        for (i = 0; i < physdisk_pg->no_phys_disks; i++) {
        !           362:                physdisk = &physdisk_list[i];
        !           363:
        !           364:                DNPRINTF(MPI_D_PPR|MPI_D_PPR, "%s:  id: %d bus: %d ioc: %d "
        !           365:                    "num: %d\n", DEVNAME(sc), physdisk->phys_disk_id,
        !           366:                    physdisk->phys_disk_bus, physdisk->phys_disk_ioc,
        !           367:                    physdisk->phys_disk_num);
        !           368:
        !           369:                if (physdisk->phys_disk_ioc != sc->sc_ioc_number)
        !           370:                        continue;
        !           371:
        !           372:                tries = 0;
        !           373:                while (mpi_ppr(sc, NULL, physdisk, port_pg.min_period,
        !           374:                    port_pg.max_offset, tries) == EAGAIN)
        !           375:                        tries++;
        !           376:        }
        !           377:
        !           378: out:
        !           379:        free(physdisk_pg, M_TEMP);
        !           380: }
        !           381:
        !           382: int
        !           383: mpi_ppr(struct mpi_softc *sc, struct scsi_link *link,
        !           384:     struct mpi_cfg_raid_physdisk *physdisk, int period, int offset, int try)
        !           385: {
        !           386:        struct mpi_cfg_hdr              hdr0, hdr1;
        !           387:        struct mpi_cfg_spi_dev_pg0      pg0;
        !           388:        struct mpi_cfg_spi_dev_pg1      pg1;
        !           389:        u_int32_t                       address;
        !           390:        int                             id;
        !           391:        int                             raid = 0;
        !           392:
        !           393:        DNPRINTF(MPI_D_PPR, "%s: mpi_ppr period: %d offset: %d try: %d "
        !           394:            "link quirks: 0x%x\n", DEVNAME(sc), period, offset, try,
        !           395:            link->quirks);
        !           396:
        !           397:        if (try >= 3)
        !           398:                return (EIO);
        !           399:
        !           400:        if (physdisk == NULL) {
        !           401:                if ((link->inqdata.device & SID_TYPE) == T_PROCESSOR)
        !           402:                        return (EIO);
        !           403:
        !           404:                address = link->target;
        !           405:                id = link->target;
        !           406:        } else {
        !           407:                raid = 1;
        !           408:                address = (physdisk->phys_disk_bus << 8) |
        !           409:                    (physdisk->phys_disk_id);
        !           410:                id = physdisk->phys_disk_num;
        !           411:        }
        !           412:
        !           413:        if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_DEV, 0,
        !           414:            address, &hdr0) != 0) {
        !           415:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch header 0\n",
        !           416:                    DEVNAME(sc));
        !           417:                return (EIO);
        !           418:        }
        !           419:
        !           420:        if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_SCSI_SPI_DEV, 1,
        !           421:            address, &hdr1) != 0) {
        !           422:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch header 1\n",
        !           423:                    DEVNAME(sc));
        !           424:                return (EIO);
        !           425:        }
        !           426:
        !           427: #ifdef MPI_DEBUG
        !           428:        if (mpi_cfg_page(sc, address, &hdr0, 1, &pg0, sizeof(pg0)) != 0) {
        !           429:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch page 0\n",
        !           430:                    DEVNAME(sc));
        !           431:                return (EIO);
        !           432:        }
        !           433:
        !           434:        DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 0 neg_params1: 0x%02x "
        !           435:            "neg_offset: %d neg_period: 0x%02x neg_params2: 0x%02x "
        !           436:            "info: 0x%08x\n", DEVNAME(sc), pg0.neg_params1, pg0.neg_offset,
        !           437:            pg0.neg_period, pg0.neg_params2, letoh32(pg0.information));
        !           438: #endif
        !           439:
        !           440:        if (mpi_cfg_page(sc, address, &hdr1, 1, &pg1, sizeof(pg1)) != 0) {
        !           441:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to fetch page 1\n",
        !           442:                    DEVNAME(sc));
        !           443:                return (EIO);
        !           444:        }
        !           445:
        !           446:        DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 1 req_params1: 0x%02x "
        !           447:            "req_offset: 0x%02x req_period: 0x%02x req_params2: 0x%02x "
        !           448:            "conf: 0x%08x\n", DEVNAME(sc), pg1.req_params1, pg1.req_offset,
        !           449:            pg1.req_period, pg1.req_params2, letoh32(pg1.configuration));
        !           450:
        !           451:        pg1.req_params1 = 0;
        !           452:        pg1.req_offset = offset;
        !           453:        pg1.req_period = period;
        !           454:        pg1.req_params2 &= ~MPI_CFG_SPI_DEV_1_REQPARAMS_WIDTH;
        !           455:
        !           456:        if (raid || !(link->quirks & SDEV_NOSYNC)) {
        !           457:                pg1.req_params2 |= MPI_CFG_SPI_DEV_1_REQPARAMS_WIDTH_WIDE;
        !           458:
        !           459:                switch (try) {
        !           460:                case 0: /* U320 */
        !           461:                        break;
        !           462:                case 1: /* U160 */
        !           463:                        pg1.req_period = 0x09;
        !           464:                        break;
        !           465:                case 2: /* U80 */
        !           466:                        pg1.req_period = 0x0a;
        !           467:                        break;
        !           468:                }
        !           469:
        !           470:                if (pg1.req_period < 0x09) {
        !           471:                        /* Ultra320: enable QAS & PACKETIZED */
        !           472:                        pg1.req_params1 |= MPI_CFG_SPI_DEV_1_REQPARAMS_QAS |
        !           473:                            MPI_CFG_SPI_DEV_1_REQPARAMS_PACKETIZED;
        !           474:                }
        !           475:                if (pg1.req_period < 0xa) {
        !           476:                        /* >= Ultra160: enable dual xfers */
        !           477:                        pg1.req_params1 |=
        !           478:                            MPI_CFG_SPI_DEV_1_REQPARAMS_DUALXFERS;
        !           479:                }
        !           480:        }
        !           481:
        !           482:        DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 1 req_params1: 0x%02x "
        !           483:            "req_offset: 0x%02x req_period: 0x%02x req_params2: 0x%02x "
        !           484:            "conf: 0x%08x\n", DEVNAME(sc), pg1.req_params1, pg1.req_offset,
        !           485:            pg1.req_period, pg1.req_params2, letoh32(pg1.configuration));
        !           486:
        !           487:        if (mpi_cfg_page(sc, address, &hdr1, 0, &pg1, sizeof(pg1)) != 0) {
        !           488:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to write page 1\n",
        !           489:                    DEVNAME(sc));
        !           490:                return (EIO);
        !           491:        }
        !           492:
        !           493:        if (mpi_cfg_page(sc, address, &hdr1, 1, &pg1, sizeof(pg1)) != 0) {
        !           494:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to read page 1\n",
        !           495:                    DEVNAME(sc));
        !           496:                return (EIO);
        !           497:        }
        !           498:
        !           499:        DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 1 req_params1: 0x%02x "
        !           500:            "req_offset: 0x%02x req_period: 0x%02x req_params2: 0x%02x "
        !           501:            "conf: 0x%08x\n", DEVNAME(sc), pg1.req_params1, pg1.req_offset,
        !           502:            pg1.req_period, pg1.req_params2, letoh32(pg1.configuration));
        !           503:
        !           504:        if (mpi_inq(sc, id, raid) != 0) {
        !           505:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to do inquiry against "
        !           506:                    "target %d\n", DEVNAME(sc), link->target);
        !           507:                return (EIO);
        !           508:        }
        !           509:
        !           510:        if (mpi_cfg_page(sc, address, &hdr0, 1, &pg0, sizeof(pg0)) != 0) {
        !           511:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr unable to read page 0 after "
        !           512:                    "inquiry\n", DEVNAME(sc));
        !           513:                return (EIO);
        !           514:        }
        !           515:
        !           516:        DNPRINTF(MPI_D_PPR, "%s: mpi_ppr dev pg 0 neg_params1: 0x%02x "
        !           517:            "neg_offset: %d neg_period: 0x%02x neg_params2: 0x%02x "
        !           518:            "info: 0x%08x\n", DEVNAME(sc), pg0.neg_params1, pg0.neg_offset,
        !           519:            pg0.neg_period, pg0.neg_params2, letoh32(pg0.information));
        !           520:
        !           521:        if (!(letoh32(pg0.information) & 0x07) && (try == 0)) {
        !           522:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr U320 ppr rejected\n",
        !           523:                    DEVNAME(sc));
        !           524:                return (EAGAIN);
        !           525:        }
        !           526:
        !           527:        if ((((letoh32(pg0.information) >> 8) & 0xff) > 0x09) && (try == 1)) {
        !           528:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr U160 ppr rejected\n",
        !           529:                    DEVNAME(sc));
        !           530:                return (EAGAIN);
        !           531:        }
        !           532:
        !           533:        if (letoh32(pg0.information) & 0x0e) {
        !           534:                DNPRINTF(MPI_D_PPR, "%s: mpi_ppr ppr rejected: %0x\n",
        !           535:                    DEVNAME(sc), letoh32(pg0.information));
        !           536:                return (EAGAIN);
        !           537:        }
        !           538:
        !           539:        switch(pg0.neg_period) {
        !           540:        case 0x08:
        !           541:                period = 160;
        !           542:                break;
        !           543:        case 0x09:
        !           544:                period = 80;
        !           545:                break;
        !           546:        case 0x0a:
        !           547:                period = 40;
        !           548:                break;
        !           549:        case 0x0b:
        !           550:                period = 20;
        !           551:                break;
        !           552:        case 0x0c:
        !           553:                period = 10;
        !           554:                break;
        !           555:        default:
        !           556:                period = 0;
        !           557:                break;
        !           558:        }
        !           559:
        !           560:        printf("%s: %s %d %s at %dMHz width %dbit offset %d "
        !           561:            "QAS %d DT %d IU %d\n", DEVNAME(sc), raid ? "phys disk" : "target",
        !           562:            id, period ? "Sync" : "Async", period,
        !           563:            (pg0.neg_params2 & MPI_CFG_SPI_DEV_0_NEGPARAMS_WIDTH_WIDE) ? 16 : 8,
        !           564:            pg0.neg_offset,
        !           565:            (pg0.neg_params1 & MPI_CFG_SPI_DEV_0_NEGPARAMS_QAS) ? 1 : 0,
        !           566:            (pg0.neg_params1 & MPI_CFG_SPI_DEV_0_NEGPARAMS_DUALXFERS) ? 1 : 0,
        !           567:            (pg0.neg_params1 & MPI_CFG_SPI_DEV_0_NEGPARAMS_PACKETIZED) ? 1 : 0);
        !           568:
        !           569:        return (0);
        !           570: }
        !           571:
        !           572: int
        !           573: mpi_inq(struct mpi_softc *sc, u_int16_t target, int physdisk)
        !           574: {
        !           575:        struct mpi_ccb                  *ccb;
        !           576:        struct scsi_inquiry             inq;
        !           577:        struct {
        !           578:                struct mpi_msg_scsi_io          io;
        !           579:                struct mpi_sge                  sge;
        !           580:                struct scsi_inquiry_data        inqbuf;
        !           581:                struct scsi_sense_data          sense;
        !           582:        } __packed                      *bundle;
        !           583:        struct mpi_msg_scsi_io          *io;
        !           584:        struct mpi_sge                  *sge;
        !           585:        u_int64_t                       addr;
        !           586:
        !           587:        DNPRINTF(MPI_D_PPR, "%s: mpi_inq\n", DEVNAME(sc));
        !           588:
        !           589:        bzero(&inq, sizeof(inq));
        !           590:        inq.opcode = INQUIRY;
        !           591:        _lto2b(sizeof(struct scsi_inquiry_data), inq.length);
        !           592:
        !           593:        ccb = mpi_get_ccb(sc);
        !           594:        if (ccb == NULL)
        !           595:                return (1);
        !           596:
        !           597:        ccb->ccb_done = mpi_empty_done;
        !           598:
        !           599:        bundle = ccb->ccb_cmd;
        !           600:        io = &bundle->io;
        !           601:        sge = &bundle->sge;
        !           602:
        !           603:        io->function = physdisk ? MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH :
        !           604:            MPI_FUNCTION_SCSI_IO_REQUEST;
        !           605:        /*
        !           606:         * bus is always 0
        !           607:         * io->bus = htole16(sc->sc_bus);
        !           608:         */
        !           609:        io->target_id = target;
        !           610:
        !           611:        io->cdb_length = sizeof(inq);
        !           612:        io->sense_buf_len = sizeof(struct scsi_sense_data);
        !           613:        io->msg_flags = MPI_SCSIIO_SENSE_BUF_ADDR_WIDTH_64;
        !           614:
        !           615:        io->msg_context = htole32(ccb->ccb_id);
        !           616:
        !           617:        /*
        !           618:         * always lun 0
        !           619:         * io->lun[0] = htobe16(link->lun);
        !           620:         */
        !           621:
        !           622:        io->direction = MPI_SCSIIO_DIR_READ;
        !           623:        io->tagging = MPI_SCSIIO_ATTR_NO_DISCONNECT;
        !           624:
        !           625:        bcopy(&inq, io->cdb, sizeof(inq));
        !           626:
        !           627:        io->data_length = htole32(sizeof(struct scsi_inquiry_data));
        !           628:
        !           629:        io->sense_buf_low_addr = htole32(ccb->ccb_cmd_dva +
        !           630:            ((u_int8_t *)&bundle->sense - (u_int8_t *)bundle));
        !           631:
        !           632:        sge->sg_hdr = htole32(MPI_SGE_FL_TYPE_SIMPLE | MPI_SGE_FL_SIZE_64 |
        !           633:            MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL |
        !           634:            (u_int32_t)sizeof(inq));
        !           635:
        !           636:        addr = ccb->ccb_cmd_dva +
        !           637:            ((u_int8_t *)&bundle->inqbuf - (u_int8_t *)bundle);
        !           638:        sge->sg_hi_addr = htole32((u_int32_t)(addr >> 32));
        !           639:        sge->sg_lo_addr = htole32((u_int32_t)addr);
        !           640:
        !           641:        if (mpi_poll(sc, ccb, 5000) != 0)
        !           642:                return (1);
        !           643:
        !           644:        if (ccb->ccb_rcb != NULL)
        !           645:                mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !           646:
        !           647:        mpi_put_ccb(sc, ccb);
        !           648:
        !           649:        return (0);
        !           650: }
        !           651:
        !           652: void
        !           653: mpi_detach(struct mpi_softc *sc)
        !           654: {
        !           655:
        !           656: }
        !           657:
        !           658: int
        !           659: mpi_intr(void *arg)
        !           660: {
        !           661:        struct mpi_softc                *sc = arg;
        !           662:        u_int32_t                       reg;
        !           663:        int                             rv = 0;
        !           664:
        !           665:        while ((reg = mpi_pop_reply(sc)) != 0xffffffff) {
        !           666:                mpi_reply(sc, reg);
        !           667:                rv = 1;
        !           668:        }
        !           669:
        !           670:        return (rv);
        !           671: }
        !           672:
        !           673: int
        !           674: mpi_reply(struct mpi_softc *sc, u_int32_t reg)
        !           675: {
        !           676:        struct mpi_ccb                  *ccb;
        !           677:        struct mpi_rcb                  *rcb = NULL;
        !           678:        struct mpi_msg_reply            *reply = NULL;
        !           679:        u_int32_t                       reply_dva;
        !           680:        int                             id;
        !           681:        int                             i;
        !           682:
        !           683:        DNPRINTF(MPI_D_INTR, "%s: mpi_reply reg: 0x%08x\n", DEVNAME(sc), reg);
        !           684:
        !           685:        if (reg & MPI_REPLY_QUEUE_ADDRESS) {
        !           686:                bus_dmamap_sync(sc->sc_dmat,
        !           687:                    MPI_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE,
        !           688:                    BUS_DMASYNC_POSTREAD);
        !           689:
        !           690:                reply_dva = (reg & MPI_REPLY_QUEUE_ADDRESS_MASK) << 1;
        !           691:
        !           692:                i = (reply_dva - (u_int32_t)MPI_DMA_DVA(sc->sc_replies)) /
        !           693:                    MPI_REPLY_SIZE;
        !           694:                rcb = &sc->sc_rcbs[i];
        !           695:                reply = rcb->rcb_reply;
        !           696:
        !           697:                id = letoh32(reply->msg_context);
        !           698:
        !           699:                bus_dmamap_sync(sc->sc_dmat,
        !           700:                    MPI_DMA_MAP(sc->sc_replies), 0, PAGE_SIZE,
        !           701:                    BUS_DMASYNC_PREREAD);
        !           702:        } else {
        !           703:                switch (reg & MPI_REPLY_QUEUE_TYPE_MASK) {
        !           704:                case MPI_REPLY_QUEUE_TYPE_INIT:
        !           705:                        id = reg & MPI_REPLY_QUEUE_CONTEXT;
        !           706:                        break;
        !           707:
        !           708:                default:
        !           709:                        panic("%s: unsupported context reply\n",
        !           710:                            DEVNAME(sc));
        !           711:                }
        !           712:        }
        !           713:
        !           714:        DNPRINTF(MPI_D_INTR, "%s: mpi_reply id: %d reply: %p\n",
        !           715:            DEVNAME(sc), id, reply);
        !           716:
        !           717:        ccb = &sc->sc_ccbs[id];
        !           718:
        !           719:        bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
        !           720:            ccb->ccb_offset, MPI_REQUEST_SIZE,
        !           721:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !           722:        ccb->ccb_state = MPI_CCB_READY;
        !           723:        ccb->ccb_rcb = rcb;
        !           724:
        !           725:        ccb->ccb_done(ccb);
        !           726:
        !           727:        return (id);
        !           728: }
        !           729:
        !           730: struct mpi_dmamem *
        !           731: mpi_dmamem_alloc(struct mpi_softc *sc, size_t size)
        !           732: {
        !           733:        struct mpi_dmamem               *mdm;
        !           734:        int                             nsegs;
        !           735:
        !           736:        mdm = malloc(sizeof(struct mpi_dmamem), M_DEVBUF, M_NOWAIT);
        !           737:        if (mdm == NULL)
        !           738:                return (NULL);
        !           739:
        !           740:        bzero(mdm, sizeof(struct mpi_dmamem));
        !           741:        mdm->mdm_size = size;
        !           742:
        !           743:        if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
        !           744:            BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mdm->mdm_map) != 0)
        !           745:                goto mdmfree;
        !           746:
        !           747:        if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mdm->mdm_seg,
        !           748:            1, &nsegs, BUS_DMA_NOWAIT) != 0)
        !           749:                goto destroy;
        !           750:
        !           751:        if (bus_dmamem_map(sc->sc_dmat, &mdm->mdm_seg, nsegs, size,
        !           752:            &mdm->mdm_kva, BUS_DMA_NOWAIT) != 0)
        !           753:                goto free;
        !           754:
        !           755:        if (bus_dmamap_load(sc->sc_dmat, mdm->mdm_map, mdm->mdm_kva, size,
        !           756:            NULL, BUS_DMA_NOWAIT) != 0)
        !           757:                goto unmap;
        !           758:
        !           759:        bzero(mdm->mdm_kva, size);
        !           760:
        !           761:        DNPRINTF(MPI_D_MEM, "%s: mpi_dmamem_alloc size: %d mdm: %#x "
        !           762:            "map: %#x nsegs: %d segs: %#x kva: %x\n",
        !           763:            DEVNAME(sc), size, mdm->mdm_map, nsegs, mdm->mdm_seg, mdm->mdm_kva);
        !           764:
        !           765:        return (mdm);
        !           766:
        !           767: unmap:
        !           768:        bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, size);
        !           769: free:
        !           770:        bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
        !           771: destroy:
        !           772:        bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
        !           773: mdmfree:
        !           774:        free(mdm, M_DEVBUF);
        !           775:
        !           776:        return (NULL);
        !           777: }
        !           778:
        !           779: void
        !           780: mpi_dmamem_free(struct mpi_softc *sc, struct mpi_dmamem *mdm)
        !           781: {
        !           782:        DNPRINTF(MPI_D_MEM, "%s: mpi_dmamem_free %#x\n", DEVNAME(sc), mdm);
        !           783:
        !           784:        bus_dmamap_unload(sc->sc_dmat, mdm->mdm_map);
        !           785:        bus_dmamem_unmap(sc->sc_dmat, mdm->mdm_kva, mdm->mdm_size);
        !           786:        bus_dmamem_free(sc->sc_dmat, &mdm->mdm_seg, 1);
        !           787:        bus_dmamap_destroy(sc->sc_dmat, mdm->mdm_map);
        !           788:        free(mdm, M_DEVBUF);
        !           789: }
        !           790:
        !           791: int
        !           792: mpi_alloc_ccbs(struct mpi_softc *sc)
        !           793: {
        !           794:        struct mpi_ccb                  *ccb;
        !           795:        u_int8_t                        *cmd;
        !           796:        int                             i;
        !           797:
        !           798:        TAILQ_INIT(&sc->sc_ccb_free);
        !           799:
        !           800:        sc->sc_ccbs = malloc(sizeof(struct mpi_ccb) * sc->sc_maxcmds,
        !           801:            M_DEVBUF, M_WAITOK|M_CANFAIL);
        !           802:        if (sc->sc_ccbs == NULL) {
        !           803:                printf("%s: unable to allocate ccbs\n", DEVNAME(sc));
        !           804:                return (1);
        !           805:        }
        !           806:        bzero(sc->sc_ccbs, sizeof(struct mpi_ccb) * sc->sc_maxcmds);
        !           807:
        !           808:        sc->sc_requests = mpi_dmamem_alloc(sc,
        !           809:            MPI_REQUEST_SIZE * sc->sc_maxcmds);
        !           810:        if (sc->sc_requests == NULL) {
        !           811:                printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc));
        !           812:                goto free_ccbs;
        !           813:        }
        !           814:        cmd = MPI_DMA_KVA(sc->sc_requests);
        !           815:        bzero(cmd, MPI_REQUEST_SIZE * sc->sc_maxcmds);
        !           816:
        !           817:        for (i = 0; i < sc->sc_maxcmds; i++) {
        !           818:                ccb = &sc->sc_ccbs[i];
        !           819:
        !           820:                if (bus_dmamap_create(sc->sc_dmat, MAXPHYS,
        !           821:                    sc->sc_max_sgl_len, MAXPHYS, 0, 0,
        !           822:                    &ccb->ccb_dmamap) != 0) {
        !           823:                        printf("%s: unable to create dma map\n", DEVNAME(sc));
        !           824:                        goto free_maps;
        !           825:                }
        !           826:
        !           827:                ccb->ccb_sc = sc;
        !           828:                ccb->ccb_id = i;
        !           829:                ccb->ccb_offset = MPI_REQUEST_SIZE * i;
        !           830:
        !           831:                ccb->ccb_cmd = &cmd[ccb->ccb_offset];
        !           832:                ccb->ccb_cmd_dva = (u_int32_t)MPI_DMA_DVA(sc->sc_requests) +
        !           833:                    ccb->ccb_offset;
        !           834:
        !           835:                DNPRINTF(MPI_D_CCB, "%s: mpi_alloc_ccbs(%d) ccb: %#x map: %#x "
        !           836:                    "sc: %#x id: %#x offs: %#x cmd: %#x dva: %#x\n",
        !           837:                    DEVNAME(sc), i, ccb, ccb->ccb_dmamap, ccb->ccb_sc,
        !           838:                    ccb->ccb_id, ccb->ccb_offset, ccb->ccb_cmd,
        !           839:                    ccb->ccb_cmd_dva);
        !           840:
        !           841:                mpi_put_ccb(sc, ccb);
        !           842:        }
        !           843:
        !           844:        return (0);
        !           845:
        !           846: free_maps:
        !           847:        while ((ccb = mpi_get_ccb(sc)) != NULL)
        !           848:                bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
        !           849:
        !           850:        mpi_dmamem_free(sc, sc->sc_requests);
        !           851: free_ccbs:
        !           852:        free(sc->sc_ccbs, M_DEVBUF);
        !           853:
        !           854:        return (1);
        !           855: }
        !           856:
        !           857: struct mpi_ccb *
        !           858: mpi_get_ccb(struct mpi_softc *sc)
        !           859: {
        !           860:        struct mpi_ccb                  *ccb;
        !           861:
        !           862:        ccb = TAILQ_FIRST(&sc->sc_ccb_free);
        !           863:        if (ccb == NULL) {
        !           864:                DNPRINTF(MPI_D_CCB, "%s: mpi_get_ccb == NULL\n", DEVNAME(sc));
        !           865:                return (NULL);
        !           866:        }
        !           867:
        !           868:        TAILQ_REMOVE(&sc->sc_ccb_free, ccb, ccb_link);
        !           869:
        !           870:        ccb->ccb_state = MPI_CCB_READY;
        !           871:
        !           872:        DNPRINTF(MPI_D_CCB, "%s: mpi_get_ccb %#x\n", DEVNAME(sc), ccb);
        !           873:
        !           874:        return (ccb);
        !           875: }
        !           876:
        !           877: void
        !           878: mpi_put_ccb(struct mpi_softc *sc, struct mpi_ccb *ccb)
        !           879: {
        !           880:        DNPRINTF(MPI_D_CCB, "%s: mpi_put_ccb %#x\n", DEVNAME(sc), ccb);
        !           881:
        !           882:        ccb->ccb_state = MPI_CCB_FREE;
        !           883:        ccb->ccb_xs = NULL;
        !           884:        ccb->ccb_done = NULL;
        !           885:        bzero(ccb->ccb_cmd, MPI_REQUEST_SIZE);
        !           886:        TAILQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_link);
        !           887: }
        !           888:
        !           889: int
        !           890: mpi_alloc_replies(struct mpi_softc *sc)
        !           891: {
        !           892:        DNPRINTF(MPI_D_MISC, "%s: mpi_alloc_replies\n", DEVNAME(sc));
        !           893:
        !           894:        sc->sc_rcbs = malloc(MPI_REPLY_COUNT * sizeof(struct mpi_rcb),
        !           895:            M_DEVBUF, M_WAITOK|M_CANFAIL);
        !           896:        if (sc->sc_rcbs == NULL)
        !           897:                return (1);
        !           898:
        !           899:        sc->sc_replies = mpi_dmamem_alloc(sc, PAGE_SIZE);
        !           900:        if (sc->sc_replies == NULL) {
        !           901:                free(sc->sc_rcbs, M_DEVBUF);
        !           902:                return (1);
        !           903:        }
        !           904:
        !           905:        return (0);
        !           906: }
        !           907:
        !           908: void
        !           909: mpi_push_replies(struct mpi_softc *sc)
        !           910: {
        !           911:        struct mpi_rcb                  *rcb;
        !           912:        char                            *kva = MPI_DMA_KVA(sc->sc_replies);
        !           913:        int                             i;
        !           914:
        !           915:        bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_replies),
        !           916:            0, PAGE_SIZE, BUS_DMASYNC_PREREAD);
        !           917:
        !           918:        for (i = 0; i < MPI_REPLY_COUNT; i++) {
        !           919:                rcb = &sc->sc_rcbs[i];
        !           920:
        !           921:                rcb->rcb_reply = kva + MPI_REPLY_SIZE * i;
        !           922:                rcb->rcb_reply_dva = (u_int32_t)MPI_DMA_DVA(sc->sc_replies) +
        !           923:                    MPI_REPLY_SIZE * i;
        !           924:                mpi_push_reply(sc, rcb->rcb_reply_dva);
        !           925:        }
        !           926: }
        !           927:
        !           928: void
        !           929: mpi_start(struct mpi_softc *sc, struct mpi_ccb *ccb)
        !           930: {
        !           931:        DNPRINTF(MPI_D_RW, "%s: mpi_start %#x\n", DEVNAME(sc),
        !           932:            ccb->ccb_cmd_dva);
        !           933:
        !           934:        bus_dmamap_sync(sc->sc_dmat, MPI_DMA_MAP(sc->sc_requests),
        !           935:            ccb->ccb_offset, MPI_REQUEST_SIZE,
        !           936:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           937:
        !           938:        ccb->ccb_state = MPI_CCB_QUEUED;
        !           939:        mpi_write(sc, MPI_REQ_QUEUE, ccb->ccb_cmd_dva);
        !           940: }
        !           941:
        !           942: int
        !           943: mpi_complete(struct mpi_softc *sc, struct mpi_ccb *ccb, int timeout)
        !           944: {
        !           945:        u_int32_t                       reg;
        !           946:        int                             id = -1;
        !           947:
        !           948:        DNPRINTF(MPI_D_INTR, "%s: mpi_complete timeout %d\n", DEVNAME(sc),
        !           949:            timeout);
        !           950:
        !           951:        do {
        !           952:                reg = mpi_pop_reply(sc);
        !           953:                if (reg == 0xffffffff) {
        !           954:                        if (timeout-- == 0)
        !           955:                                return (1);
        !           956:
        !           957:                        delay(1000);
        !           958:                        continue;
        !           959:                }
        !           960:
        !           961:                id = mpi_reply(sc, reg);
        !           962:
        !           963:        } while (ccb->ccb_id != id);
        !           964:
        !           965:        return (0);
        !           966: }
        !           967:
        !           968: int
        !           969: mpi_poll(struct mpi_softc *sc, struct mpi_ccb *ccb, int timeout)
        !           970: {
        !           971:        int                             error;
        !           972:        int                             s;
        !           973:
        !           974:        DNPRINTF(MPI_D_CMD, "%s: mpi_poll\n", DEVNAME(sc));
        !           975:
        !           976:        s = splbio();
        !           977:        mpi_start(sc, ccb);
        !           978:        error = mpi_complete(sc, ccb, timeout);
        !           979:        splx(s);
        !           980:
        !           981:        return (error);
        !           982: }
        !           983:
        !           984: int
        !           985: mpi_scsi_cmd(struct scsi_xfer *xs)
        !           986: {
        !           987:        struct scsi_link                *link = xs->sc_link;
        !           988:        struct mpi_softc                *sc = link->adapter_softc;
        !           989:        struct mpi_ccb                  *ccb;
        !           990:        struct mpi_ccb_bundle           *mcb;
        !           991:        struct mpi_msg_scsi_io          *io;
        !           992:        int                             s;
        !           993:
        !           994:        DNPRINTF(MPI_D_CMD, "%s: mpi_scsi_cmd\n", DEVNAME(sc));
        !           995:
        !           996:        if (xs->cmdlen > MPI_CDB_LEN) {
        !           997:                DNPRINTF(MPI_D_CMD, "%s: CBD too big %d\n",
        !           998:                    DEVNAME(sc), xs->cmdlen);
        !           999:                bzero(&xs->sense, sizeof(xs->sense));
        !          1000:                xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
        !          1001:                xs->sense.flags = SKEY_ILLEGAL_REQUEST;
        !          1002:                xs->sense.add_sense_code = 0x20;
        !          1003:                xs->error = XS_SENSE;
        !          1004:                s = splbio();
        !          1005:                scsi_done(xs);
        !          1006:                splx(s);
        !          1007:                return (COMPLETE);
        !          1008:        }
        !          1009:
        !          1010:        s = splbio();
        !          1011:        ccb = mpi_get_ccb(sc);
        !          1012:        splx(s);
        !          1013:        if (ccb == NULL) {
        !          1014:                xs->error = XS_DRIVER_STUFFUP;
        !          1015:                s = splbio();
        !          1016:                scsi_done(xs);
        !          1017:                splx(s);
        !          1018:                return (COMPLETE);
        !          1019:        }
        !          1020:        DNPRINTF(MPI_D_CMD, "%s: ccb_id: %d xs->flags: 0x%x\n",
        !          1021:            DEVNAME(sc), ccb->ccb_id, xs->flags);
        !          1022:
        !          1023:        ccb->ccb_xs = xs;
        !          1024:        ccb->ccb_done = mpi_scsi_cmd_done;
        !          1025:
        !          1026:        mcb = ccb->ccb_cmd;
        !          1027:        io = &mcb->mcb_io;
        !          1028:
        !          1029:        io->function = MPI_FUNCTION_SCSI_IO_REQUEST;
        !          1030:        /*
        !          1031:         * bus is always 0
        !          1032:         * io->bus = htole16(sc->sc_bus);
        !          1033:         */
        !          1034:        io->target_id = link->target;
        !          1035:
        !          1036:        io->cdb_length = xs->cmdlen;
        !          1037:        io->sense_buf_len = sizeof(xs->sense);
        !          1038:        io->msg_flags = MPI_SCSIIO_SENSE_BUF_ADDR_WIDTH_64;
        !          1039:
        !          1040:        io->msg_context = htole32(ccb->ccb_id);
        !          1041:
        !          1042:        io->lun[0] = htobe16(link->lun);
        !          1043:
        !          1044:        switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
        !          1045:        case SCSI_DATA_IN:
        !          1046:                io->direction = MPI_SCSIIO_DIR_READ;
        !          1047:                break;
        !          1048:        case SCSI_DATA_OUT:
        !          1049:                io->direction = MPI_SCSIIO_DIR_WRITE;
        !          1050:                break;
        !          1051:        default:
        !          1052:                io->direction = MPI_SCSIIO_DIR_NONE;
        !          1053:                break;
        !          1054:        }
        !          1055:
        !          1056:        if (link->quirks & SDEV_NOTAGS)
        !          1057:                io->tagging = MPI_SCSIIO_ATTR_UNTAGGED;
        !          1058:        else
        !          1059:                io->tagging = MPI_SCSIIO_ATTR_SIMPLE_Q;
        !          1060:
        !          1061:        bcopy(xs->cmd, io->cdb, xs->cmdlen);
        !          1062:
        !          1063:        io->data_length = htole32(xs->datalen);
        !          1064:
        !          1065:        io->sense_buf_low_addr = htole32(ccb->ccb_cmd_dva +
        !          1066:            ((u_int8_t *)&mcb->mcb_sense - (u_int8_t *)mcb));
        !          1067:
        !          1068:        if (mpi_load_xs(ccb) != 0) {
        !          1069:                xs->error = XS_DRIVER_STUFFUP;
        !          1070:                s = splbio();
        !          1071:                mpi_put_ccb(sc, ccb);
        !          1072:                scsi_done(xs);
        !          1073:                splx(s);
        !          1074:                return (COMPLETE);
        !          1075:        }
        !          1076:
        !          1077:        timeout_set(&xs->stimeout, mpi_timeout_xs, ccb);
        !          1078:
        !          1079:        if (xs->flags & SCSI_POLL) {
        !          1080:                if (mpi_poll(sc, ccb, xs->timeout) != 0)
        !          1081:                        xs->error = XS_DRIVER_STUFFUP;
        !          1082:                return (COMPLETE);
        !          1083:        }
        !          1084:
        !          1085:        s = splbio();
        !          1086:        mpi_start(sc, ccb);
        !          1087:        splx(s);
        !          1088:        return (SUCCESSFULLY_QUEUED);
        !          1089: }
        !          1090:
        !          1091: void
        !          1092: mpi_scsi_cmd_done(struct mpi_ccb *ccb)
        !          1093: {
        !          1094:        struct mpi_softc                *sc = ccb->ccb_sc;
        !          1095:        struct scsi_xfer                *xs = ccb->ccb_xs;
        !          1096:        struct mpi_ccb_bundle           *mcb = ccb->ccb_cmd;
        !          1097:        bus_dmamap_t                    dmap = ccb->ccb_dmamap;
        !          1098:        struct mpi_msg_scsi_io_error    *sie;
        !          1099:
        !          1100:        if (xs->datalen != 0) {
        !          1101:                bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
        !          1102:                    (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
        !          1103:                    BUS_DMASYNC_POSTWRITE);
        !          1104:
        !          1105:                bus_dmamap_unload(sc->sc_dmat, dmap);
        !          1106:        }
        !          1107:
        !          1108:        /* timeout_del */
        !          1109:        xs->error = XS_NOERROR;
        !          1110:        xs->resid = 0;
        !          1111:        xs->flags |= ITSDONE;
        !          1112:
        !          1113:        if (ccb->ccb_rcb == NULL) {
        !          1114:                /* no scsi error, we're ok so drop out early */
        !          1115:                xs->status = SCSI_OK;
        !          1116:                mpi_put_ccb(sc, ccb);
        !          1117:                scsi_done(xs);
        !          1118:                return;
        !          1119:        }
        !          1120:
        !          1121:        sie = ccb->ccb_rcb->rcb_reply;
        !          1122:
        !          1123:        DNPRINTF(MPI_D_CMD, "%s: mpi_scsi_cmd_done xs cmd: 0x%02x len: %d "
        !          1124:            "flags 0x%x\n", DEVNAME(sc), xs->cmd->opcode, xs->datalen,
        !          1125:            xs->flags);
        !          1126:        DNPRINTF(MPI_D_CMD, "%s:  target_id: %d bus: %d msg_length: %d "
        !          1127:            "function: 0x%02x\n", DEVNAME(sc), sie->target_id, sie->bus,
        !          1128:            sie->msg_length, sie->function);
        !          1129:        DNPRINTF(MPI_D_CMD, "%s:  cdb_length: %d sense_buf_length: %d "
        !          1130:            "msg_flags: 0x%02x\n", DEVNAME(sc), sie->cdb_length,
        !          1131:            sie->sense_buf_len, sie->msg_flags);
        !          1132:        DNPRINTF(MPI_D_CMD, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
        !          1133:            letoh32(sie->msg_context));
        !          1134:        DNPRINTF(MPI_D_CMD, "%s:  scsi_status: 0x%02x scsi_state: 0x%02x "
        !          1135:            "ioc_status: 0x%04x\n", DEVNAME(sc), sie->scsi_status,
        !          1136:            sie->scsi_state, letoh16(sie->ioc_status));
        !          1137:        DNPRINTF(MPI_D_CMD, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
        !          1138:            letoh32(sie->ioc_loginfo));
        !          1139:        DNPRINTF(MPI_D_CMD, "%s:  transfer_count: %d\n", DEVNAME(sc),
        !          1140:            letoh32(sie->transfer_count));
        !          1141:        DNPRINTF(MPI_D_CMD, "%s:  sense_count: %d\n", DEVNAME(sc),
        !          1142:            letoh32(sie->sense_count));
        !          1143:        DNPRINTF(MPI_D_CMD, "%s:  response_info: 0x%08x\n", DEVNAME(sc),
        !          1144:            letoh32(sie->response_info));
        !          1145:        DNPRINTF(MPI_D_CMD, "%s:  tag: 0x%04x\n", DEVNAME(sc),
        !          1146:            letoh16(sie->tag));
        !          1147:
        !          1148:        xs->status = sie->scsi_status;
        !          1149:        switch (letoh16(sie->ioc_status)) {
        !          1150:        case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
        !          1151:                xs->resid = xs->datalen - letoh32(sie->transfer_count);
        !          1152:                if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_NO_SCSI_STATUS) {
        !          1153:                        xs->error = XS_DRIVER_STUFFUP;
        !          1154:                        break;
        !          1155:                }
        !          1156:                /* FALLTHROUGH */
        !          1157:        case MPI_IOCSTATUS_SUCCESS:
        !          1158:        case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:
        !          1159:                switch (xs->status) {
        !          1160:                case SCSI_OK:
        !          1161:                        xs->resid = 0;
        !          1162:                        break;
        !          1163:
        !          1164:                case SCSI_CHECK:
        !          1165:                        xs->error = XS_SENSE;
        !          1166:                        break;
        !          1167:
        !          1168:                case SCSI_BUSY:
        !          1169:                case SCSI_QUEUE_FULL:
        !          1170:                        xs->error = XS_BUSY;
        !          1171:                        break;
        !          1172:
        !          1173:                default:
        !          1174:                        xs->error = XS_DRIVER_STUFFUP;
        !          1175:                        break;
        !          1176:                }
        !          1177:                break;
        !          1178:
        !          1179:        case MPI_IOCSTATUS_BUSY:
        !          1180:        case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
        !          1181:                xs->error = XS_BUSY;
        !          1182:                break;
        !          1183:
        !          1184:        case MPI_IOCSTATUS_SCSI_INVALID_BUS:
        !          1185:        case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
        !          1186:        case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
        !          1187:                xs->error = XS_SELTIMEOUT;
        !          1188:                break;
        !          1189:
        !          1190:        default:
        !          1191:                xs->error = XS_DRIVER_STUFFUP;
        !          1192:                break;
        !          1193:        }
        !          1194:
        !          1195:        if (sie->scsi_state & MPI_SCSIIO_ERR_STATE_AUTOSENSE_VALID)
        !          1196:                bcopy(&mcb->mcb_sense, &xs->sense, sizeof(xs->sense));
        !          1197:
        !          1198:        DNPRINTF(MPI_D_CMD, "%s:  xs err: 0x%02x status: %d\n", DEVNAME(sc),
        !          1199:            xs->error, xs->status);
        !          1200:
        !          1201:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          1202:        mpi_put_ccb(sc, ccb);
        !          1203:        scsi_done(xs);
        !          1204: }
        !          1205:
        !          1206: void
        !          1207: mpi_timeout_xs(void *arg)
        !          1208: {
        !          1209:        /* XXX */
        !          1210: }
        !          1211:
        !          1212: int
        !          1213: mpi_load_xs(struct mpi_ccb *ccb)
        !          1214: {
        !          1215:        struct mpi_softc                *sc = ccb->ccb_sc;
        !          1216:        struct scsi_xfer                *xs = ccb->ccb_xs;
        !          1217:        struct mpi_ccb_bundle           *mcb = ccb->ccb_cmd;
        !          1218:        struct mpi_msg_scsi_io          *io = &mcb->mcb_io;
        !          1219:        struct mpi_sge                  *sge, *nsge = &mcb->mcb_sgl[0];
        !          1220:        struct mpi_sge                  *ce = NULL, *nce;
        !          1221:        u_int64_t                       ce_dva;
        !          1222:        bus_dmamap_t                    dmap = ccb->ccb_dmamap;
        !          1223:        u_int32_t                       addr, flags;
        !          1224:        int                             i, error;
        !          1225:
        !          1226:        if (xs->datalen == 0) {
        !          1227:                nsge->sg_hdr = htole32(MPI_SGE_FL_TYPE_SIMPLE |
        !          1228:                    MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL);
        !          1229:                return (0);
        !          1230:        }
        !          1231:
        !          1232:        error = bus_dmamap_load(sc->sc_dmat, dmap,
        !          1233:            xs->data, xs->datalen, NULL,
        !          1234:            (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1235:        if (error) {
        !          1236:                printf("%s: error %d loading dmamap\n", DEVNAME(sc), error);
        !          1237:                return (1);
        !          1238:        }
        !          1239:
        !          1240:        flags = MPI_SGE_FL_TYPE_SIMPLE | MPI_SGE_FL_SIZE_64;
        !          1241:        if (xs->flags & SCSI_DATA_OUT)
        !          1242:                flags |= MPI_SGE_FL_DIR_OUT;
        !          1243:
        !          1244:        if (dmap->dm_nsegs > sc->sc_first_sgl_len) {
        !          1245:                ce = &mcb->mcb_sgl[sc->sc_first_sgl_len - 1];
        !          1246:                io->chain_offset = ((u_int8_t *)ce - (u_int8_t *)io) / 4;
        !          1247:        }
        !          1248:
        !          1249:        for (i = 0; i < dmap->dm_nsegs; i++) {
        !          1250:
        !          1251:                if (nsge == ce) {
        !          1252:                        nsge++;
        !          1253:                        sge->sg_hdr |= htole32(MPI_SGE_FL_LAST);
        !          1254:
        !          1255:                        DNPRINTF(MPI_D_DMA, "%s:   - 0x%08x 0x%08x 0x%08x\n",
        !          1256:                            DEVNAME(sc), sge->sg_hdr,
        !          1257:                            sge->sg_hi_addr, sge->sg_lo_addr);
        !          1258:
        !          1259:                        if ((dmap->dm_nsegs - i) > sc->sc_chain_len) {
        !          1260:                                nce = &nsge[sc->sc_chain_len - 1];
        !          1261:                                addr = ((u_int8_t *)nce - (u_int8_t *)nsge) / 4;
        !          1262:                                addr = addr << 16 |
        !          1263:                                    sizeof(struct mpi_sge) * sc->sc_chain_len;
        !          1264:                        } else {
        !          1265:                                nce = NULL;
        !          1266:                                addr = sizeof(struct mpi_sge) *
        !          1267:                                    (dmap->dm_nsegs - i);
        !          1268:                        }
        !          1269:
        !          1270:                        ce->sg_hdr = htole32(MPI_SGE_FL_TYPE_CHAIN |
        !          1271:                            MPI_SGE_FL_SIZE_64 | addr);
        !          1272:
        !          1273:                        ce_dva = ccb->ccb_cmd_dva +
        !          1274:                            ((u_int8_t *)nsge - (u_int8_t *)mcb);
        !          1275:
        !          1276:                        addr = (u_int32_t)(ce_dva >> 32);
        !          1277:                        ce->sg_hi_addr = htole32(addr);
        !          1278:                        addr = (u_int32_t)ce_dva;
        !          1279:                        ce->sg_lo_addr = htole32(addr);
        !          1280:
        !          1281:                        DNPRINTF(MPI_D_DMA, "%s:  ce: 0x%08x 0x%08x 0x%08x\n",
        !          1282:                            DEVNAME(sc), ce->sg_hdr, ce->sg_hi_addr,
        !          1283:                            ce->sg_lo_addr);
        !          1284:
        !          1285:                        ce = nce;
        !          1286:                }
        !          1287:
        !          1288:                DNPRINTF(MPI_D_DMA, "%s:  %d: %d 0x%016llx\n", DEVNAME(sc),
        !          1289:                    i, dmap->dm_segs[i].ds_len,
        !          1290:                    (u_int64_t)dmap->dm_segs[i].ds_addr);
        !          1291:
        !          1292:                sge = nsge;
        !          1293:
        !          1294:                sge->sg_hdr = htole32(flags | dmap->dm_segs[i].ds_len);
        !          1295:                addr = (u_int32_t)((u_int64_t)dmap->dm_segs[i].ds_addr >> 32);
        !          1296:                sge->sg_hi_addr = htole32(addr);
        !          1297:                addr = (u_int32_t)dmap->dm_segs[i].ds_addr;
        !          1298:                sge->sg_lo_addr = htole32(addr);
        !          1299:
        !          1300:                DNPRINTF(MPI_D_DMA, "%s:  %d: 0x%08x 0x%08x 0x%08x\n",
        !          1301:                    DEVNAME(sc), i, sge->sg_hdr, sge->sg_hi_addr,
        !          1302:                    sge->sg_lo_addr);
        !          1303:
        !          1304:                nsge = sge + 1;
        !          1305:        }
        !          1306:
        !          1307:        /* terminate list */
        !          1308:        sge->sg_hdr |= htole32(MPI_SGE_FL_LAST | MPI_SGE_FL_EOB |
        !          1309:            MPI_SGE_FL_EOL);
        !          1310:
        !          1311:        bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
        !          1312:            (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
        !          1313:            BUS_DMASYNC_PREWRITE);
        !          1314:
        !          1315:        return (0);
        !          1316: }
        !          1317:
        !          1318: void
        !          1319: mpi_minphys(struct buf *bp)
        !          1320: {
        !          1321:        /* XXX */
        !          1322:        if (bp->b_bcount > MAXPHYS)
        !          1323:                bp->b_bcount = MAXPHYS;
        !          1324:        minphys(bp);
        !          1325: }
        !          1326:
        !          1327: int
        !          1328: mpi_scsi_ioctl(struct scsi_link *a, u_long b, caddr_t c, int d, struct proc *e)
        !          1329: {
        !          1330:        return (ENOTTY);
        !          1331: }
        !          1332:
        !          1333: u_int32_t
        !          1334: mpi_read(struct mpi_softc *sc, bus_size_t r)
        !          1335: {
        !          1336:        u_int32_t                       rv;
        !          1337:
        !          1338:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
        !          1339:            BUS_SPACE_BARRIER_READ);
        !          1340:        rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
        !          1341:
        !          1342:        DNPRINTF(MPI_D_RW, "%s: mpi_read %#x %#x\n", DEVNAME(sc), r, rv);
        !          1343:
        !          1344:        return (rv);
        !          1345: }
        !          1346:
        !          1347: void
        !          1348: mpi_write(struct mpi_softc *sc, bus_size_t r, u_int32_t v)
        !          1349: {
        !          1350:        DNPRINTF(MPI_D_RW, "%s: mpi_write %#x %#x\n", DEVNAME(sc), r, v);
        !          1351:
        !          1352:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
        !          1353:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
        !          1354:            BUS_SPACE_BARRIER_WRITE);
        !          1355: }
        !          1356:
        !          1357: int
        !          1358: mpi_wait_eq(struct mpi_softc *sc, bus_size_t r, u_int32_t mask,
        !          1359:     u_int32_t target)
        !          1360: {
        !          1361:        int                             i;
        !          1362:
        !          1363:        DNPRINTF(MPI_D_RW, "%s: mpi_wait_eq %#x %#x %#x\n", DEVNAME(sc), r,
        !          1364:            mask, target);
        !          1365:
        !          1366:        for (i = 0; i < 10000; i++) {
        !          1367:                if ((mpi_read(sc, r) & mask) == target)
        !          1368:                        return (0);
        !          1369:                delay(1000);
        !          1370:        }
        !          1371:
        !          1372:        return (1);
        !          1373: }
        !          1374:
        !          1375: int
        !          1376: mpi_wait_ne(struct mpi_softc *sc, bus_size_t r, u_int32_t mask,
        !          1377:     u_int32_t target)
        !          1378: {
        !          1379:        int                             i;
        !          1380:
        !          1381:        DNPRINTF(MPI_D_RW, "%s: mpi_wait_ne %#x %#x %#x\n", DEVNAME(sc), r,
        !          1382:            mask, target);
        !          1383:
        !          1384:        for (i = 0; i < 10000; i++) {
        !          1385:                if ((mpi_read(sc, r) & mask) != target)
        !          1386:                        return (0);
        !          1387:                delay(1000);
        !          1388:        }
        !          1389:
        !          1390:        return (1);
        !          1391: }
        !          1392:
        !          1393: int
        !          1394: mpi_init(struct mpi_softc *sc)
        !          1395: {
        !          1396:        u_int32_t                       db;
        !          1397:        int                             i;
        !          1398:
        !          1399:        /* spin until the IOC leaves the RESET state */
        !          1400:        if (mpi_wait_ne(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
        !          1401:            MPI_DOORBELL_STATE_RESET) != 0) {
        !          1402:                DNPRINTF(MPI_D_MISC, "%s: mpi_init timeout waiting to leave "
        !          1403:                    "reset state\n", DEVNAME(sc));
        !          1404:                return (1);
        !          1405:        }
        !          1406:
        !          1407:        /* check current ownership */
        !          1408:        db = mpi_read_db(sc);
        !          1409:        if ((db & MPI_DOORBELL_WHOINIT) == MPI_DOORBELL_WHOINIT_PCIPEER) {
        !          1410:                DNPRINTF(MPI_D_MISC, "%s: mpi_init initialised by pci peer\n",
        !          1411:                    DEVNAME(sc));
        !          1412:                return (0);
        !          1413:        }
        !          1414:
        !          1415:        for (i = 0; i < 5; i++) {
        !          1416:                switch (db & MPI_DOORBELL_STATE) {
        !          1417:                case MPI_DOORBELL_STATE_READY:
        !          1418:                        DNPRINTF(MPI_D_MISC, "%s: mpi_init ioc is ready\n",
        !          1419:                            DEVNAME(sc));
        !          1420:                        return (0);
        !          1421:
        !          1422:                case MPI_DOORBELL_STATE_OPER:
        !          1423:                case MPI_DOORBELL_STATE_FAULT:
        !          1424:                        DNPRINTF(MPI_D_MISC, "%s: mpi_init ioc is being "
        !          1425:                            "reset\n" , DEVNAME(sc));
        !          1426:                        if (mpi_reset_soft(sc) != 0)
        !          1427:                                mpi_reset_hard(sc);
        !          1428:                        break;
        !          1429:
        !          1430:                case MPI_DOORBELL_STATE_RESET:
        !          1431:                        DNPRINTF(MPI_D_MISC, "%s: mpi_init waiting to come "
        !          1432:                            "out of reset\n", DEVNAME(sc));
        !          1433:                        if (mpi_wait_ne(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
        !          1434:                            MPI_DOORBELL_STATE_RESET) != 0)
        !          1435:                                return (1);
        !          1436:                        break;
        !          1437:                }
        !          1438:                db = mpi_read_db(sc);
        !          1439:        }
        !          1440:
        !          1441:        return (1);
        !          1442: }
        !          1443:
        !          1444: int
        !          1445: mpi_reset_soft(struct mpi_softc *sc)
        !          1446: {
        !          1447:        DNPRINTF(MPI_D_MISC, "%s: mpi_reset_soft\n", DEVNAME(sc));
        !          1448:
        !          1449:        if (mpi_read_db(sc) & MPI_DOORBELL_INUSE)
        !          1450:                return (1);
        !          1451:
        !          1452:        mpi_write_db(sc,
        !          1453:            MPI_DOORBELL_FUNCTION(MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET));
        !          1454:        if (mpi_wait_eq(sc, MPI_INTR_STATUS,
        !          1455:            MPI_INTR_STATUS_IOCDOORBELL, 0) != 0)
        !          1456:                return (1);
        !          1457:
        !          1458:        if (mpi_wait_eq(sc, MPI_DOORBELL, MPI_DOORBELL_STATE,
        !          1459:            MPI_DOORBELL_STATE_READY) != 0)
        !          1460:                return (1);
        !          1461:
        !          1462:        return (0);
        !          1463: }
        !          1464:
        !          1465: int
        !          1466: mpi_reset_hard(struct mpi_softc *sc)
        !          1467: {
        !          1468:        DNPRINTF(MPI_D_MISC, "%s: mpi_reset_hard\n", DEVNAME(sc));
        !          1469:
        !          1470:        /* enable diagnostic register */
        !          1471:        mpi_write(sc, MPI_WRITESEQ, 0xff);
        !          1472:        mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_1);
        !          1473:        mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_2);
        !          1474:        mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_3);
        !          1475:        mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_4);
        !          1476:        mpi_write(sc, MPI_WRITESEQ, MPI_WRITESEQ_5);
        !          1477:
        !          1478:        /* reset ioc */
        !          1479:        mpi_write(sc, MPI_HOSTDIAG, MPI_HOSTDIAG_RESET_ADAPTER);
        !          1480:
        !          1481:        delay(10000);
        !          1482:
        !          1483:        /* disable diagnostic register */
        !          1484:        mpi_write(sc, MPI_WRITESEQ, 0xff);
        !          1485:
        !          1486:        /* restore pci bits? */
        !          1487:
        !          1488:        /* firmware bits? */
        !          1489:        return (0);
        !          1490: }
        !          1491:
        !          1492: int
        !          1493: mpi_handshake_send(struct mpi_softc *sc, void *buf, size_t dwords)
        !          1494: {
        !          1495:        u_int32_t                               *query = buf;
        !          1496:        int                                     i;
        !          1497:
        !          1498:        /* make sure the doorbell is not in use. */
        !          1499:        if (mpi_read_db(sc) & MPI_DOORBELL_INUSE)
        !          1500:                return (1);
        !          1501:
        !          1502:        /* clear pending doorbell interrupts */
        !          1503:        if (mpi_read_intr(sc) & MPI_INTR_STATUS_DOORBELL)
        !          1504:                mpi_write_intr(sc, 0);
        !          1505:
        !          1506:        /*
        !          1507:         * first write the doorbell with the handshake function and the
        !          1508:         * dword count.
        !          1509:         */
        !          1510:        mpi_write_db(sc, MPI_DOORBELL_FUNCTION(MPI_FUNCTION_HANDSHAKE) |
        !          1511:            MPI_DOORBELL_DWORDS(dwords));
        !          1512:
        !          1513:        /*
        !          1514:         * the doorbell used bit will be set because a doorbell function has
        !          1515:         * started. Wait for the interrupt and then ack it.
        !          1516:         */
        !          1517:        if (mpi_wait_db_int(sc) != 0)
        !          1518:                return (1);
        !          1519:        mpi_write_intr(sc, 0);
        !          1520:
        !          1521:        /* poll for the acknowledgement. */
        !          1522:        if (mpi_wait_db_ack(sc) != 0)
        !          1523:                return (1);
        !          1524:
        !          1525:        /* write the query through the doorbell. */
        !          1526:        for (i = 0; i < dwords; i++) {
        !          1527:                mpi_write_db(sc, htole32(query[i]));
        !          1528:                if (mpi_wait_db_ack(sc) != 0)
        !          1529:                        return (1);
        !          1530:        }
        !          1531:
        !          1532:        return (0);
        !          1533: }
        !          1534:
        !          1535: int
        !          1536: mpi_handshake_recv_dword(struct mpi_softc *sc, u_int32_t *dword)
        !          1537: {
        !          1538:        u_int16_t                               *words = (u_int16_t *)dword;
        !          1539:        int                                     i;
        !          1540:
        !          1541:        for (i = 0; i < 2; i++) {
        !          1542:                if (mpi_wait_db_int(sc) != 0)
        !          1543:                        return (1);
        !          1544:                words[i] = letoh16(mpi_read_db(sc) & MPI_DOORBELL_DATA_MASK);
        !          1545:                mpi_write_intr(sc, 0);
        !          1546:        }
        !          1547:
        !          1548:        return (0);
        !          1549: }
        !          1550:
        !          1551: int
        !          1552: mpi_handshake_recv(struct mpi_softc *sc, void *buf, size_t dwords)
        !          1553: {
        !          1554:        struct mpi_msg_reply                    *reply = buf;
        !          1555:        u_int32_t                               *dbuf = buf, dummy;
        !          1556:        int                                     i;
        !          1557:
        !          1558:        /* get the first dword so we can read the length out of the header. */
        !          1559:        if (mpi_handshake_recv_dword(sc, &dbuf[0]) != 0)
        !          1560:                return (1);
        !          1561:
        !          1562:        DNPRINTF(MPI_D_CMD, "%s: mpi_handshake_recv dwords: %d reply: %d\n",
        !          1563:            DEVNAME(sc), dwords, reply->msg_length);
        !          1564:
        !          1565:        /*
        !          1566:         * the total length, in dwords, is in the message length field of the
        !          1567:         * reply header.
        !          1568:         */
        !          1569:        for (i = 1; i < MIN(dwords, reply->msg_length); i++) {
        !          1570:                if (mpi_handshake_recv_dword(sc, &dbuf[i]) != 0)
        !          1571:                        return (1);
        !          1572:        }
        !          1573:
        !          1574:        /* if there's extra stuff to come off the ioc, discard it */
        !          1575:        while (i++ < reply->msg_length) {
        !          1576:                if (mpi_handshake_recv_dword(sc, &dummy) != 0)
        !          1577:                        return (1);
        !          1578:                DNPRINTF(MPI_D_CMD, "%s: mpi_handshake_recv dummy read: "
        !          1579:                    "0x%08x\n", DEVNAME(sc), dummy);
        !          1580:        }
        !          1581:
        !          1582:        /* wait for the doorbell used bit to be reset and clear the intr */
        !          1583:        if (mpi_wait_db_int(sc) != 0)
        !          1584:                return (1);
        !          1585:        mpi_write_intr(sc, 0);
        !          1586:
        !          1587:        return (0);
        !          1588: }
        !          1589:
        !          1590: void
        !          1591: mpi_empty_done(struct mpi_ccb *ccb)
        !          1592: {
        !          1593:        /* nothing to do */
        !          1594: }
        !          1595:
        !          1596: int
        !          1597: mpi_iocfacts(struct mpi_softc *sc)
        !          1598: {
        !          1599:        struct mpi_msg_iocfacts_request         ifq;
        !          1600:        struct mpi_msg_iocfacts_reply           ifp;
        !          1601:
        !          1602:        DNPRINTF(MPI_D_MISC, "%s: mpi_iocfacts\n", DEVNAME(sc));
        !          1603:
        !          1604:        bzero(&ifq, sizeof(ifq));
        !          1605:        bzero(&ifp, sizeof(ifp));
        !          1606:
        !          1607:        ifq.function = MPI_FUNCTION_IOC_FACTS;
        !          1608:        ifq.chain_offset = 0;
        !          1609:        ifq.msg_flags = 0;
        !          1610:        ifq.msg_context = htole32(0xdeadbeef);
        !          1611:
        !          1612:        if (mpi_handshake_send(sc, &ifq, dwordsof(ifq)) != 0) {
        !          1613:                DNPRINTF(MPI_D_MISC, "%s: mpi_iocfacts send failed\n",
        !          1614:                    DEVNAME(sc));
        !          1615:                return (1);
        !          1616:        }
        !          1617:
        !          1618:        if (mpi_handshake_recv(sc, &ifp, dwordsof(ifp)) != 0) {
        !          1619:                DNPRINTF(MPI_D_MISC, "%s: mpi_iocfacts recv failed\n",
        !          1620:                    DEVNAME(sc));
        !          1621:                return (1);
        !          1622:        }
        !          1623:
        !          1624:        DNPRINTF(MPI_D_MISC, "%s:  func: 0x%02x len: %d msgver: %d.%d\n",
        !          1625:            DEVNAME(sc), ifp.function, ifp.msg_length,
        !          1626:            ifp.msg_version_maj, ifp.msg_version_min);
        !          1627:        DNPRINTF(MPI_D_MISC, "%s:  msgflags: 0x%02x iocnumber: 0x%02x "
        !          1628:            "hdrver: %d.%d\n", DEVNAME(sc), ifp.msg_flags,
        !          1629:            ifp.ioc_number, ifp.header_version_maj,
        !          1630:            ifp.header_version_min);
        !          1631:        DNPRINTF(MPI_D_MISC, "%s:  message context: 0x%08x\n", DEVNAME(sc),
        !          1632:            letoh32(ifp.msg_context));
        !          1633:        DNPRINTF(MPI_D_MISC, "%s:  iocstatus: 0x%04x ioexcept: 0x%04x\n",
        !          1634:            DEVNAME(sc), letoh16(ifp.ioc_status),
        !          1635:            letoh16(ifp.ioc_exceptions));
        !          1636:        DNPRINTF(MPI_D_MISC, "%s:  iocloginfo: 0x%08x\n", DEVNAME(sc),
        !          1637:            letoh32(ifp.ioc_loginfo));
        !          1638:        DNPRINTF(MPI_D_MISC, "%s:  flags: 0x%02x blocksize: %d whoinit: 0x%02x "
        !          1639:            "maxchdepth: %d\n", DEVNAME(sc), ifp.flags,
        !          1640:            ifp.block_size, ifp.whoinit, ifp.max_chain_depth);
        !          1641:        DNPRINTF(MPI_D_MISC, "%s:  reqfrsize: %d replyqdepth: %d\n",
        !          1642:            DEVNAME(sc), letoh16(ifp.request_frame_size),
        !          1643:            letoh16(ifp.reply_queue_depth));
        !          1644:        DNPRINTF(MPI_D_MISC, "%s:  productid: 0x%04x\n", DEVNAME(sc),
        !          1645:            letoh16(ifp.product_id));
        !          1646:        DNPRINTF(MPI_D_MISC, "%s:  hostmfahiaddr: 0x%08x\n", DEVNAME(sc),
        !          1647:            letoh32(ifp.current_host_mfa_hi_addr));
        !          1648:        DNPRINTF(MPI_D_MISC, "%s:  event_state: 0x%02x number_of_ports: %d "
        !          1649:            "global_credits: %d\n",
        !          1650:            DEVNAME(sc), ifp.event_state, ifp.number_of_ports,
        !          1651:            letoh16(ifp.global_credits));
        !          1652:        DNPRINTF(MPI_D_MISC, "%s:  sensebufhiaddr: 0x%08x\n", DEVNAME(sc),
        !          1653:            letoh32(ifp.current_sense_buffer_hi_addr));
        !          1654:        DNPRINTF(MPI_D_MISC, "%s:  maxbus: %d maxdev: %d replyfrsize: %d\n",
        !          1655:            DEVNAME(sc), ifp.max_buses, ifp.max_devices,
        !          1656:            letoh16(ifp.current_reply_frame_size));
        !          1657:        DNPRINTF(MPI_D_MISC, "%s:  fw_image_size: %d\n", DEVNAME(sc),
        !          1658:            letoh32(ifp.fw_image_size));
        !          1659:        DNPRINTF(MPI_D_MISC, "%s:  ioc_capabilities: 0x%08x\n", DEVNAME(sc),
        !          1660:            letoh32(ifp.ioc_capabilities));
        !          1661:        DNPRINTF(MPI_D_MISC, "%s:  fw_version: %d.%d fw_version_unit: 0x%02x "
        !          1662:            "fw_version_dev: 0x%02x\n", DEVNAME(sc),
        !          1663:            ifp.fw_version_maj, ifp.fw_version_min,
        !          1664:            ifp.fw_version_unit, ifp.fw_version_dev);
        !          1665:        DNPRINTF(MPI_D_MISC, "%s:  hi_priority_queue_depth: 0x%04x\n",
        !          1666:            DEVNAME(sc), letoh16(ifp.hi_priority_queue_depth));
        !          1667:        DNPRINTF(MPI_D_MISC, "%s:  host_page_buffer_sge: hdr: 0x%08x "
        !          1668:            "addr 0x%08x %08x\n", DEVNAME(sc),
        !          1669:            letoh32(ifp.host_page_buffer_sge.sg_hdr),
        !          1670:            letoh32(ifp.host_page_buffer_sge.sg_hi_addr),
        !          1671:            letoh32(ifp.host_page_buffer_sge.sg_lo_addr));
        !          1672:
        !          1673:        sc->sc_maxcmds = letoh16(ifp.global_credits);
        !          1674:        sc->sc_maxchdepth = ifp.max_chain_depth;
        !          1675:        sc->sc_ioc_number = ifp.ioc_number;
        !          1676:        if (sc->sc_flags & MPI_F_SPI)
        !          1677:                sc->sc_buswidth = 16;
        !          1678:        else
        !          1679:                sc->sc_buswidth =
        !          1680:                    (ifp.max_devices == 0) ? 256 : ifp.max_devices;
        !          1681:        if (ifp.flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
        !          1682:                sc->sc_fw_len = letoh32(ifp.fw_image_size);
        !          1683:
        !          1684:        /*
        !          1685:         * you can fit sg elements on the end of the io cmd if they fit in the
        !          1686:         * request frame size.
        !          1687:         */
        !          1688:        sc->sc_first_sgl_len = ((letoh16(ifp.request_frame_size) * 4) -
        !          1689:            sizeof(struct mpi_msg_scsi_io)) / sizeof(struct mpi_sge);
        !          1690:        DNPRINTF(MPI_D_MISC, "%s:   first sgl len: %d\n", DEVNAME(sc),
        !          1691:            sc->sc_first_sgl_len);
        !          1692:
        !          1693:        sc->sc_chain_len = (letoh16(ifp.request_frame_size) * 4) /
        !          1694:            sizeof(struct mpi_sge);
        !          1695:        DNPRINTF(MPI_D_MISC, "%s:   chain len: %d\n", DEVNAME(sc),
        !          1696:            sc->sc_chain_len);
        !          1697:
        !          1698:        /* the sgl tailing the io cmd loses an entry to the chain element. */
        !          1699:        sc->sc_max_sgl_len = MPI_MAX_SGL - 1;
        !          1700:        /* the sgl chains lose an entry for each chain element */
        !          1701:        sc->sc_max_sgl_len -= (MPI_MAX_SGL - sc->sc_first_sgl_len) /
        !          1702:            sc->sc_chain_len;
        !          1703:        DNPRINTF(MPI_D_MISC, "%s:   max sgl len: %d\n", DEVNAME(sc),
        !          1704:            sc->sc_max_sgl_len);
        !          1705:
        !          1706:        /* XXX we're ignoring the max chain depth */
        !          1707:
        !          1708:        return (0);
        !          1709: }
        !          1710:
        !          1711: int
        !          1712: mpi_iocinit(struct mpi_softc *sc)
        !          1713: {
        !          1714:        struct mpi_msg_iocinit_request          iiq;
        !          1715:        struct mpi_msg_iocinit_reply            iip;
        !          1716:        u_int32_t                               hi_addr;
        !          1717:
        !          1718:        DNPRINTF(MPI_D_MISC, "%s: mpi_iocinit\n", DEVNAME(sc));
        !          1719:
        !          1720:        bzero(&iiq, sizeof(iiq));
        !          1721:        bzero(&iip, sizeof(iip));
        !          1722:
        !          1723:        iiq.function = MPI_FUNCTION_IOC_INIT;
        !          1724:        iiq.whoinit = MPI_WHOINIT_HOST_DRIVER;
        !          1725:
        !          1726:        iiq.max_devices = (sc->sc_buswidth == 256) ? 0 : sc->sc_buswidth;
        !          1727:        iiq.max_buses = 1;
        !          1728:
        !          1729:        iiq.msg_context = htole32(0xd00fd00f);
        !          1730:
        !          1731:        iiq.reply_frame_size = htole16(MPI_REPLY_SIZE);
        !          1732:
        !          1733:        hi_addr = (u_int32_t)((u_int64_t)MPI_DMA_DVA(sc->sc_requests) >> 32);
        !          1734:        iiq.host_mfa_hi_addr = htole32(hi_addr);
        !          1735:        iiq.sense_buffer_hi_addr = htole32(hi_addr);
        !          1736:
        !          1737:        hi_addr = (u_int32_t)((u_int64_t)MPI_DMA_DVA(sc->sc_replies) >> 32);
        !          1738:        iiq.reply_fifo_host_signalling_addr = htole32(hi_addr);
        !          1739:
        !          1740:        iiq.msg_version_maj = 0x01;
        !          1741:        iiq.msg_version_min = 0x02;
        !          1742:
        !          1743:        iiq.hdr_version_unit = 0x0d;
        !          1744:        iiq.hdr_version_dev = 0x00;
        !          1745:
        !          1746:        if (mpi_handshake_send(sc, &iiq, dwordsof(iiq)) != 0) {
        !          1747:                DNPRINTF(MPI_D_MISC, "%s: mpi_iocinit send failed\n",
        !          1748:                    DEVNAME(sc));
        !          1749:                return (1);
        !          1750:        }
        !          1751:
        !          1752:        if (mpi_handshake_recv(sc, &iip, dwordsof(iip)) != 0) {
        !          1753:                DNPRINTF(MPI_D_MISC, "%s: mpi_iocinit recv failed\n",
        !          1754:                    DEVNAME(sc));
        !          1755:                return (1);
        !          1756:        }
        !          1757:
        !          1758:        DNPRINTF(MPI_D_MISC, "%s:  function: 0x%02x msg_length: %d "
        !          1759:            "whoinit: 0x%02x\n", DEVNAME(sc), iip.function,
        !          1760:            iip.msg_length, iip.whoinit);
        !          1761:        DNPRINTF(MPI_D_MISC, "%s:  msg_flags: 0x%02x max_buses: %d "
        !          1762:            "max_devices: %d flags: 0x%02x\n", DEVNAME(sc), iip.msg_flags,
        !          1763:            iip.max_buses, iip.max_devices, iip.flags);
        !          1764:        DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
        !          1765:            letoh32(iip.msg_context));
        !          1766:        DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
        !          1767:            letoh16(iip.ioc_status));
        !          1768:        DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
        !          1769:            letoh32(iip.ioc_loginfo));
        !          1770:
        !          1771:        return (0);
        !          1772: }
        !          1773:
        !          1774: int
        !          1775: mpi_portfacts(struct mpi_softc *sc)
        !          1776: {
        !          1777:        struct mpi_ccb                          *ccb;
        !          1778:        struct mpi_msg_portfacts_request        *pfq;
        !          1779:        volatile struct mpi_msg_portfacts_reply *pfp;
        !          1780:        int                                     s, rv = 1;
        !          1781:
        !          1782:        DNPRINTF(MPI_D_MISC, "%s: mpi_portfacts\n", DEVNAME(sc));
        !          1783:
        !          1784:        s = splbio();
        !          1785:        ccb = mpi_get_ccb(sc);
        !          1786:        splx(s);
        !          1787:        if (ccb == NULL) {
        !          1788:                DNPRINTF(MPI_D_MISC, "%s: mpi_portfacts ccb_get\n",
        !          1789:                    DEVNAME(sc));
        !          1790:                return (rv);
        !          1791:        }
        !          1792:
        !          1793:        ccb->ccb_done = mpi_empty_done;
        !          1794:        pfq = ccb->ccb_cmd;
        !          1795:
        !          1796:        pfq->function = MPI_FUNCTION_PORT_FACTS;
        !          1797:        pfq->chain_offset = 0;
        !          1798:        pfq->msg_flags = 0;
        !          1799:        pfq->port_number = 0;
        !          1800:        pfq->msg_context = htole32(ccb->ccb_id);
        !          1801:
        !          1802:        if (mpi_poll(sc, ccb, 50000) != 0) {
        !          1803:                DNPRINTF(MPI_D_MISC, "%s: mpi_portfacts poll\n", DEVNAME(sc));
        !          1804:                goto err;
        !          1805:        }
        !          1806:
        !          1807:        if (ccb->ccb_rcb == NULL) {
        !          1808:                DNPRINTF(MPI_D_MISC, "%s: empty portfacts reply\n",
        !          1809:                    DEVNAME(sc));
        !          1810:                goto err;
        !          1811:        }
        !          1812:        pfp = ccb->ccb_rcb->rcb_reply;
        !          1813:
        !          1814:        DNPRINTF(MPI_D_MISC, "%s:  function: 0x%02x msg_length: %d\n",
        !          1815:            DEVNAME(sc), pfp->function, pfp->msg_length);
        !          1816:        DNPRINTF(MPI_D_MISC, "%s:  msg_flags: 0x%02x port_number: %d\n",
        !          1817:            DEVNAME(sc), pfp->msg_flags, pfp->port_number);
        !          1818:        DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
        !          1819:            letoh32(pfp->msg_context));
        !          1820:        DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
        !          1821:            letoh16(pfp->ioc_status));
        !          1822:        DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
        !          1823:            letoh32(pfp->ioc_loginfo));
        !          1824:        DNPRINTF(MPI_D_MISC, "%s:  max_devices: %d port_type: 0x%02x\n",
        !          1825:            DEVNAME(sc), letoh16(pfp->max_devices), pfp->port_type);
        !          1826:        DNPRINTF(MPI_D_MISC, "%s:  protocol_flags: 0x%04x port_scsi_id: %d\n",
        !          1827:            DEVNAME(sc), letoh16(pfp->protocol_flags),
        !          1828:            letoh16(pfp->port_scsi_id));
        !          1829:        DNPRINTF(MPI_D_MISC, "%s:  max_persistent_ids: %d "
        !          1830:            "max_posted_cmd_buffers: %d\n", DEVNAME(sc),
        !          1831:            letoh16(pfp->max_persistent_ids),
        !          1832:            letoh16(pfp->max_posted_cmd_buffers));
        !          1833:        DNPRINTF(MPI_D_MISC, "%s:  max_lan_buckets: %d\n", DEVNAME(sc),
        !          1834:            letoh16(pfp->max_lan_buckets));
        !          1835:
        !          1836:        sc->sc_porttype = pfp->port_type;
        !          1837:        sc->sc_target = letoh16(pfp->port_scsi_id);
        !          1838:
        !          1839:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          1840:        rv = 0;
        !          1841: err:
        !          1842:        mpi_put_ccb(sc, ccb);
        !          1843:
        !          1844:        return (rv);
        !          1845: }
        !          1846:
        !          1847: int
        !          1848: mpi_eventnotify(struct mpi_softc *sc)
        !          1849: {
        !          1850:        struct mpi_ccb                          *ccb;
        !          1851:        struct mpi_msg_event_request            *enq;
        !          1852:        int                                     s;
        !          1853:
        !          1854:        s = splbio();
        !          1855:        ccb = mpi_get_ccb(sc);
        !          1856:        splx(s);
        !          1857:        if (ccb == NULL) {
        !          1858:                DNPRINTF(MPI_D_MISC, "%s: mpi_eventnotify ccb_get\n",
        !          1859:                    DEVNAME(sc));
        !          1860:                return (1);
        !          1861:        }
        !          1862:
        !          1863:        ccb->ccb_done = mpi_eventnotify_done;
        !          1864:        enq = ccb->ccb_cmd;
        !          1865:
        !          1866:        enq->function = MPI_FUNCTION_EVENT_NOTIFICATION;
        !          1867:        enq->chain_offset = 0;
        !          1868:        enq->event_switch = MPI_EVENT_SWITCH_ON;
        !          1869:        enq->msg_context = htole32(ccb->ccb_id);
        !          1870:
        !          1871:        mpi_start(sc, ccb);
        !          1872:        return (0);
        !          1873: }
        !          1874:
        !          1875: void
        !          1876: mpi_eventnotify_done(struct mpi_ccb *ccb)
        !          1877: {
        !          1878:        struct mpi_softc                        *sc = ccb->ccb_sc;
        !          1879:        struct mpi_msg_event_reply              *enp = ccb->ccb_rcb->rcb_reply;
        !          1880:        int                                     deferred = 0;
        !          1881:
        !          1882:        DNPRINTF(MPI_D_EVT, "%s: mpi_eventnotify_done\n", DEVNAME(sc));
        !          1883:
        !          1884:        DNPRINTF(MPI_D_EVT, "%s:  function: 0x%02x msg_length: %d "
        !          1885:            "data_length: %d\n", DEVNAME(sc), enp->function, enp->msg_length,
        !          1886:            letoh16(enp->data_length));
        !          1887:        DNPRINTF(MPI_D_EVT, "%s:  ack_required: %d msg_flags 0x%02x\n",
        !          1888:            DEVNAME(sc), enp->ack_required, enp->msg_flags);
        !          1889:        DNPRINTF(MPI_D_EVT, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
        !          1890:            letoh32(enp->msg_context));
        !          1891:        DNPRINTF(MPI_D_EVT, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
        !          1892:            letoh16(enp->ioc_status));
        !          1893:        DNPRINTF(MPI_D_EVT, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
        !          1894:            letoh32(enp->ioc_loginfo));
        !          1895:        DNPRINTF(MPI_D_EVT, "%s:  event: 0x%08x\n", DEVNAME(sc),
        !          1896:            letoh32(enp->event));
        !          1897:        DNPRINTF(MPI_D_EVT, "%s:  event_context: 0x%08x\n", DEVNAME(sc),
        !          1898:            letoh32(enp->event_context));
        !          1899:
        !          1900:        switch (letoh32(enp->event)) {
        !          1901:        /* ignore these */
        !          1902:        case MPI_EVENT_EVENT_CHANGE:
        !          1903:        case MPI_EVENT_SAS_PHY_LINK_STATUS:
        !          1904:                break;
        !          1905:
        !          1906:        case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
        !          1907:                if (sc->sc_scsibus == NULL)
        !          1908:                        break;
        !          1909:
        !          1910:                if (scsi_task(mpi_evt_sas, sc, ccb->ccb_rcb, 0) != 0) {
        !          1911:                        printf("%s: unable to run SAS device status change\n",
        !          1912:                            DEVNAME(sc));
        !          1913:                        break;
        !          1914:                }
        !          1915:                deferred = 1;
        !          1916:                break;
        !          1917:
        !          1918:        default:
        !          1919:                printf("%s: unhandled event 0x%02x\n", DEVNAME(sc),
        !          1920:                    letoh32(enp->event));
        !          1921:                break;
        !          1922:        }
        !          1923:
        !          1924:        if (!deferred) {
        !          1925:                if (enp->ack_required)
        !          1926:                        mpi_eventack(sc, enp);
        !          1927:                mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          1928:        }
        !          1929:
        !          1930:        if ((enp->msg_flags & MPI_EVENT_FLAGS_REPLY_KEPT) == 0) {
        !          1931:                /* XXX this shouldnt happen till shutdown */
        !          1932:                mpi_put_ccb(sc, ccb);
        !          1933:        }
        !          1934: }
        !          1935:
        !          1936: void
        !          1937: mpi_evt_sas(void *xsc, void *arg)
        !          1938: {
        !          1939:        struct mpi_softc                        *sc = xsc;
        !          1940:        struct mpi_rcb                          *rcb = arg;
        !          1941:        struct mpi_msg_event_reply              *enp = rcb->rcb_reply;
        !          1942:        struct mpi_evt_sas_change               *ch;
        !          1943:        u_int8_t                                *data;
        !          1944:        int                                     s;
        !          1945:
        !          1946:        data = rcb->rcb_reply;
        !          1947:        data += sizeof(struct mpi_msg_event_reply);
        !          1948:        ch = (struct mpi_evt_sas_change *)data;
        !          1949:
        !          1950:        if (ch->bus != 0)
        !          1951:                return;
        !          1952:
        !          1953:        switch (ch->reason) {
        !          1954:        case MPI_EVT_SASCH_REASON_ADDED:
        !          1955:        case MPI_EVT_SASCH_REASON_NO_PERSIST_ADDED:
        !          1956:                scsi_probe_target(sc->sc_scsibus, ch->target);
        !          1957:                break;
        !          1958:
        !          1959:        case MPI_EVT_SASCH_REASON_NOT_RESPONDING:
        !          1960:                scsi_detach_target(sc->sc_scsibus, ch->target, DETACH_FORCE);
        !          1961:                break;
        !          1962:
        !          1963:        case MPI_EVT_SASCH_REASON_SMART_DATA:
        !          1964:        case MPI_EVT_SASCH_REASON_UNSUPPORTED:
        !          1965:        case MPI_EVT_SASCH_REASON_INTERNAL_RESET:
        !          1966:                break;
        !          1967:        default:
        !          1968:                printf("%s: unknown reason for SAS device status change: "
        !          1969:                    "0x%02x\n", DEVNAME(sc), ch->reason);
        !          1970:                break;
        !          1971:        }
        !          1972:
        !          1973:        s = splbio();
        !          1974:        mpi_push_reply(sc, rcb->rcb_reply_dva);
        !          1975:        if (enp->ack_required)
        !          1976:                mpi_eventack(sc, enp);
        !          1977:        splx(s);
        !          1978: }
        !          1979:
        !          1980: void
        !          1981: mpi_eventack(struct mpi_softc *sc, struct mpi_msg_event_reply *enp)
        !          1982: {
        !          1983:        struct mpi_ccb                          *ccb;
        !          1984:        struct mpi_msg_eventack_request         *eaq;
        !          1985:
        !          1986:        ccb = mpi_get_ccb(sc);
        !          1987:        if (ccb == NULL) {
        !          1988:                DNPRINTF(MPI_D_EVT, "%s: mpi_eventack ccb_get\n", DEVNAME(sc));
        !          1989:                return;
        !          1990:        }
        !          1991:
        !          1992:        ccb->ccb_done = mpi_eventack_done;
        !          1993:        eaq = ccb->ccb_cmd;
        !          1994:
        !          1995:        eaq->function = MPI_FUNCTION_EVENT_ACK;
        !          1996:        eaq->msg_context = htole32(ccb->ccb_id);
        !          1997:
        !          1998:        eaq->event = enp->event;
        !          1999:        eaq->event_context = enp->event_context;
        !          2000:
        !          2001:        mpi_start(sc, ccb);
        !          2002:        return;
        !          2003: }
        !          2004:
        !          2005: void
        !          2006: mpi_eventack_done(struct mpi_ccb *ccb)
        !          2007: {
        !          2008:        struct mpi_softc                        *sc = ccb->ccb_sc;
        !          2009:
        !          2010:        DNPRINTF(MPI_D_EVT, "%s: event ack done\n", DEVNAME(sc));
        !          2011:
        !          2012:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          2013:        mpi_put_ccb(sc, ccb);
        !          2014: }
        !          2015:
        !          2016: int
        !          2017: mpi_portenable(struct mpi_softc *sc)
        !          2018: {
        !          2019:        struct mpi_ccb                          *ccb;
        !          2020:        struct mpi_msg_portenable_request       *peq;
        !          2021:        struct mpi_msg_portenable_repy          *pep;
        !          2022:        int                                     s;
        !          2023:
        !          2024:        DNPRINTF(MPI_D_MISC, "%s: mpi_portenable\n", DEVNAME(sc));
        !          2025:
        !          2026:        s = splbio();
        !          2027:        ccb = mpi_get_ccb(sc);
        !          2028:        splx(s);
        !          2029:        if (ccb == NULL) {
        !          2030:                DNPRINTF(MPI_D_MISC, "%s: mpi_portenable ccb_get\n",
        !          2031:                    DEVNAME(sc));
        !          2032:                return (1);
        !          2033:        }
        !          2034:
        !          2035:        ccb->ccb_done = mpi_empty_done;
        !          2036:        peq = ccb->ccb_cmd;
        !          2037:
        !          2038:        peq->function = MPI_FUNCTION_PORT_ENABLE;
        !          2039:        peq->port_number = 0;
        !          2040:        peq->msg_context = htole32(ccb->ccb_id);
        !          2041:
        !          2042:        if (mpi_poll(sc, ccb, 50000) != 0) {
        !          2043:                DNPRINTF(MPI_D_MISC, "%s: mpi_portenable poll\n", DEVNAME(sc));
        !          2044:                return (1);
        !          2045:        }
        !          2046:
        !          2047:        if (ccb->ccb_rcb == NULL) {
        !          2048:                DNPRINTF(MPI_D_MISC, "%s: empty portenable reply\n",
        !          2049:                    DEVNAME(sc));
        !          2050:                return (1);
        !          2051:        }
        !          2052:        pep = ccb->ccb_rcb->rcb_reply;
        !          2053:
        !          2054:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          2055:        mpi_put_ccb(sc, ccb);
        !          2056:
        !          2057:        return (0);
        !          2058: }
        !          2059:
        !          2060: int
        !          2061: mpi_fwupload(struct mpi_softc *sc)
        !          2062: {
        !          2063:        struct mpi_ccb                          *ccb;
        !          2064:        struct {
        !          2065:                struct mpi_msg_fwupload_request         req;
        !          2066:                struct mpi_sge                          sge;
        !          2067:        } __packed                              *bundle;
        !          2068:        struct mpi_msg_fwupload_reply           *upp;
        !          2069:        u_int64_t                               addr;
        !          2070:        int                                     s;
        !          2071:        int                                     rv = 0;
        !          2072:
        !          2073:        if (sc->sc_fw_len == 0)
        !          2074:                return (0);
        !          2075:
        !          2076:        DNPRINTF(MPI_D_MISC, "%s: mpi_fwupload\n", DEVNAME(sc));
        !          2077:
        !          2078:        sc->sc_fw = mpi_dmamem_alloc(sc, sc->sc_fw_len);
        !          2079:        if (sc->sc_fw == NULL) {
        !          2080:                DNPRINTF(MPI_D_MISC, "%s: mpi_fwupload unable to allocate %d\n",
        !          2081:                    DEVNAME(sc), sc->sc_fw_len);
        !          2082:                return (1);
        !          2083:        }
        !          2084:
        !          2085:        s = splbio();
        !          2086:        ccb = mpi_get_ccb(sc);
        !          2087:        splx(s);
        !          2088:        if (ccb == NULL) {
        !          2089:                DNPRINTF(MPI_D_MISC, "%s: mpi_fwupload ccb_get\n",
        !          2090:                    DEVNAME(sc));
        !          2091:                goto err;
        !          2092:        }
        !          2093:
        !          2094:        ccb->ccb_done = mpi_empty_done;
        !          2095:        bundle = ccb->ccb_cmd;
        !          2096:
        !          2097:        bundle->req.function = MPI_FUNCTION_FW_UPLOAD;
        !          2098:        bundle->req.msg_context = htole32(ccb->ccb_id);
        !          2099:
        !          2100:        bundle->req.image_type = MPI_FWUPLOAD_IMAGETYPE_IOC_FW;
        !          2101:
        !          2102:        bundle->req.tce.details_length = 12;
        !          2103:        bundle->req.tce.image_size = htole32(sc->sc_fw_len);
        !          2104:
        !          2105:        bundle->sge.sg_hdr = htole32(MPI_SGE_FL_TYPE_SIMPLE |
        !          2106:            MPI_SGE_FL_SIZE_64 | MPI_SGE_FL_LAST | MPI_SGE_FL_EOB |
        !          2107:            MPI_SGE_FL_EOL | (u_int32_t)sc->sc_fw_len);
        !          2108:        addr = MPI_DMA_DVA(sc->sc_fw);
        !          2109:        bundle->sge.sg_hi_addr = htole32((u_int32_t)(addr >> 32));
        !          2110:        bundle->sge.sg_lo_addr = htole32((u_int32_t)addr);
        !          2111:
        !          2112:        if (mpi_poll(sc, ccb, 50000) != 0) {
        !          2113:                DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header poll\n", DEVNAME(sc));
        !          2114:                goto err;
        !          2115:        }
        !          2116:
        !          2117:        if (ccb->ccb_rcb == NULL)
        !          2118:                panic("%s: unable to do fw upload\n", DEVNAME(sc));
        !          2119:        upp = ccb->ccb_rcb->rcb_reply;
        !          2120:
        !          2121:        if (letoh16(upp->ioc_status) != MPI_IOCSTATUS_SUCCESS)
        !          2122:                rv = 1;
        !          2123:
        !          2124:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          2125:        mpi_put_ccb(sc, ccb);
        !          2126:
        !          2127:        return (rv);
        !          2128:
        !          2129: err:
        !          2130:        mpi_dmamem_free(sc, sc->sc_fw);
        !          2131:        return (1);
        !          2132: }
        !          2133:
        !          2134: void
        !          2135: mpi_get_raid(struct mpi_softc *sc)
        !          2136: {
        !          2137:        struct mpi_cfg_hdr              hdr;
        !          2138:        struct mpi_cfg_ioc_pg2          *vol_page;
        !          2139:        struct mpi_cfg_raid_vol         *vol_list, *vol;
        !          2140:        size_t                          pagelen;
        !          2141:        u_int32_t                       capabilities;
        !          2142:        struct scsi_link                *link;
        !          2143:        int                             i;
        !          2144:
        !          2145:        DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid\n", DEVNAME(sc));
        !          2146:
        !          2147:        if (mpi_cfg_header(sc, MPI_CONFIG_REQ_PAGE_TYPE_IOC, 2, 0, &hdr) != 0) {
        !          2148:                DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid unable to fetch header"
        !          2149:                    "for IOC page 2\n", DEVNAME(sc));
        !          2150:                return;
        !          2151:        }
        !          2152:
        !          2153:        pagelen = hdr.page_length * 4; /* dwords to bytes */
        !          2154:        vol_page = malloc(pagelen, M_TEMP, M_WAITOK|M_CANFAIL);
        !          2155:        if (vol_page == NULL) {
        !          2156:                DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid unable to allocate "
        !          2157:                    "space for ioc config page 2\n", DEVNAME(sc));
        !          2158:                return;
        !          2159:        }
        !          2160:        vol_list = (struct mpi_cfg_raid_vol *)(vol_page + 1);
        !          2161:
        !          2162:        if (mpi_cfg_page(sc, 0, &hdr, 1, vol_page, pagelen) != 0) {
        !          2163:                DNPRINTF(MPI_D_RAID, "%s: mpi_get_raid unable to fetch IOC "
        !          2164:                    "page 2\n", DEVNAME(sc));
        !          2165:                goto out;
        !          2166:        }
        !          2167:
        !          2168:        capabilities = letoh32(vol_page->capabilities);
        !          2169:
        !          2170:        DNPRINTF(MPI_D_RAID, "%s:  capabilities: 0x08%x\n", DEVNAME(sc),
        !          2171:            letoh32(vol_page->capabilities));
        !          2172:        DNPRINTF(MPI_D_RAID, "%s:  active_vols: %d max_vols: %d "
        !          2173:            "active_physdisks: %d max_physdisks: %d\n", DEVNAME(sc),
        !          2174:            vol_page->active_vols, vol_page->max_vols,
        !          2175:            vol_page->active_physdisks, vol_page->max_physdisks);
        !          2176:
        !          2177:        /* don't walk list if there are no RAID capability */
        !          2178:        if (capabilities == 0xdeadbeef) {
        !          2179:                printf("%s: deadbeef in raid configuration\n", DEVNAME(sc));
        !          2180:                goto out;
        !          2181:        }
        !          2182:
        !          2183:        if ((capabilities & MPI_CFG_IOC_2_CAPABILITIES_RAID) == 0 ||
        !          2184:            (vol_page->active_vols == 0))
        !          2185:                goto out;
        !          2186:
        !          2187:        sc->sc_flags |= MPI_F_RAID;
        !          2188:
        !          2189:        for (i = 0; i < vol_page->active_vols; i++) {
        !          2190:                vol = &vol_list[i];
        !          2191:
        !          2192:                DNPRINTF(MPI_D_RAID, "%s:   id: %d bus: %d ioc: %d pg: %d\n",
        !          2193:                    DEVNAME(sc), vol->vol_id, vol->vol_bus, vol->vol_ioc,
        !          2194:                    vol->vol_page);
        !          2195:                DNPRINTF(MPI_D_RAID, "%s:   type: 0x%02x flags: 0x%02x\n",
        !          2196:                    DEVNAME(sc), vol->vol_type, vol->flags);
        !          2197:
        !          2198:                if (vol->vol_ioc != sc->sc_ioc_number || vol->vol_bus != 0)
        !          2199:                        continue;
        !          2200:
        !          2201:                link = sc->sc_scsibus->sc_link[vol->vol_id][0];
        !          2202:                if (link == NULL)
        !          2203:                        continue;
        !          2204:
        !          2205:                link->flags |= SDEV_VIRTUAL;
        !          2206:        }
        !          2207:
        !          2208: out:
        !          2209:        free(vol_page, M_TEMP);
        !          2210: }
        !          2211:
        !          2212: int
        !          2213: mpi_cfg_header(struct mpi_softc *sc, u_int8_t type, u_int8_t number,
        !          2214:     u_int32_t address, struct mpi_cfg_hdr *hdr)
        !          2215: {
        !          2216:        struct mpi_ccb                          *ccb;
        !          2217:        struct mpi_msg_config_request           *cq;
        !          2218:        struct mpi_msg_config_reply             *cp;
        !          2219:        int                                     rv = 0;
        !          2220:        int                                     s;
        !          2221:
        !          2222:        DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header type: %#x number: %x "
        !          2223:            "address: %d\n", DEVNAME(sc), type, number, address);
        !          2224:
        !          2225:        s = splbio();
        !          2226:        ccb = mpi_get_ccb(sc);
        !          2227:        splx(s);
        !          2228:        if (ccb == NULL) {
        !          2229:                DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header ccb_get\n",
        !          2230:                    DEVNAME(sc));
        !          2231:                return (1);
        !          2232:        }
        !          2233:
        !          2234:        ccb->ccb_done = mpi_empty_done;
        !          2235:        cq = ccb->ccb_cmd;
        !          2236:
        !          2237:        cq->function = MPI_FUNCTION_CONFIG;
        !          2238:        cq->msg_context = htole32(ccb->ccb_id);
        !          2239:
        !          2240:        cq->action = MPI_CONFIG_REQ_ACTION_PAGE_HEADER;
        !          2241:
        !          2242:        cq->config_header.page_number = number;
        !          2243:        cq->config_header.page_type = type;
        !          2244:        cq->page_address = htole32(address);
        !          2245:        cq->page_buffer.sg_hdr = htole32(MPI_SGE_FL_TYPE_SIMPLE |
        !          2246:            MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL);
        !          2247:
        !          2248:        if (mpi_poll(sc, ccb, 50000) != 0) {
        !          2249:                DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_header poll\n", DEVNAME(sc));
        !          2250:                return (1);
        !          2251:        }
        !          2252:
        !          2253:        if (ccb->ccb_rcb == NULL)
        !          2254:                panic("%s: unable to fetch config header\n", DEVNAME(sc));
        !          2255:        cp = ccb->ccb_rcb->rcb_reply;
        !          2256:
        !          2257:        DNPRINTF(MPI_D_MISC, "%s:  action: 0x%02x msg_length: %d function: "
        !          2258:            "0x%02x\n", DEVNAME(sc), cp->action, cp->msg_length, cp->function);
        !          2259:        DNPRINTF(MPI_D_MISC, "%s:  ext_page_length: %d ext_page_type: 0x%02x "
        !          2260:            "msg_flags: 0x%02x\n", DEVNAME(sc),
        !          2261:            letoh16(cp->ext_page_length), cp->ext_page_type,
        !          2262:            cp->msg_flags);
        !          2263:        DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
        !          2264:            letoh32(cp->msg_context));
        !          2265:        DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
        !          2266:            letoh16(cp->ioc_status));
        !          2267:        DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
        !          2268:            letoh32(cp->ioc_loginfo));
        !          2269:        DNPRINTF(MPI_D_MISC, "%s:  page_version: 0x%02x page_length: %d "
        !          2270:            "page_number: 0x%02x page_type: 0x%02x\n", DEVNAME(sc),
        !          2271:            cp->config_header.page_version,
        !          2272:            cp->config_header.page_length,
        !          2273:            cp->config_header.page_number,
        !          2274:            cp->config_header.page_type);
        !          2275:
        !          2276:        if (letoh16(cp->ioc_status) != MPI_IOCSTATUS_SUCCESS)
        !          2277:                rv = 1;
        !          2278:        else
        !          2279:                *hdr = cp->config_header;
        !          2280:
        !          2281:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          2282:        mpi_put_ccb(sc, ccb);
        !          2283:
        !          2284:        return (rv);
        !          2285: }
        !          2286:
        !          2287: int
        !          2288: mpi_cfg_page(struct mpi_softc *sc, u_int32_t address, struct mpi_cfg_hdr *hdr,
        !          2289:     int read, void *page, size_t len)
        !          2290: {
        !          2291:        struct mpi_ccb                          *ccb;
        !          2292:        struct mpi_msg_config_request           *cq;
        !          2293:        struct mpi_msg_config_reply             *cp;
        !          2294:        u_int64_t                               dva;
        !          2295:        char                                    *kva;
        !          2296:        int                                     rv = 0;
        !          2297:        int                                     s;
        !          2298:
        !          2299:        DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_page address: %d read: %d type: %x\n",
        !          2300:            DEVNAME(sc), address, read, hdr->page_type);
        !          2301:
        !          2302:        if (len > MPI_REQUEST_SIZE - sizeof(struct mpi_msg_config_request) ||
        !          2303:            len < hdr->page_length * 4)
        !          2304:                return (1);
        !          2305:
        !          2306:        s = splbio();
        !          2307:        ccb = mpi_get_ccb(sc);
        !          2308:        splx(s);
        !          2309:        if (ccb == NULL) {
        !          2310:                DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_page ccb_get\n", DEVNAME(sc));
        !          2311:                return (1);
        !          2312:        }
        !          2313:
        !          2314:        ccb->ccb_done = mpi_empty_done;
        !          2315:        cq = ccb->ccb_cmd;
        !          2316:
        !          2317:        cq->function = MPI_FUNCTION_CONFIG;
        !          2318:        cq->msg_context = htole32(ccb->ccb_id);
        !          2319:
        !          2320:        cq->action = (read ? MPI_CONFIG_REQ_ACTION_PAGE_READ_CURRENT :
        !          2321:            MPI_CONFIG_REQ_ACTION_PAGE_WRITE_CURRENT);
        !          2322:
        !          2323:        cq->config_header = *hdr;
        !          2324:        cq->config_header.page_type &= MPI_CONFIG_REQ_PAGE_TYPE_MASK;
        !          2325:        cq->page_address = htole32(address);
        !          2326:        cq->page_buffer.sg_hdr = htole32(MPI_SGE_FL_TYPE_SIMPLE |
        !          2327:            MPI_SGE_FL_LAST | MPI_SGE_FL_EOB | MPI_SGE_FL_EOL |
        !          2328:            (hdr->page_length * 4) |
        !          2329:            (read ? MPI_SGE_FL_DIR_IN : MPI_SGE_FL_DIR_OUT));
        !          2330:
        !          2331:        /* bounce the page via the request space to avoid more bus_dma games */
        !          2332:        dva = ccb->ccb_cmd_dva + sizeof(struct mpi_msg_config_request);
        !          2333:
        !          2334:        cq->page_buffer.sg_hi_addr = htole32((u_int32_t)(dva >> 32));
        !          2335:        cq->page_buffer.sg_lo_addr = htole32((u_int32_t)dva);
        !          2336:
        !          2337:        kva = ccb->ccb_cmd;
        !          2338:        kva += sizeof(struct mpi_msg_config_request);
        !          2339:        if (!read)
        !          2340:                bcopy(page, kva, len);
        !          2341:
        !          2342:        if (mpi_poll(sc, ccb, 50000) != 0) {
        !          2343:                DNPRINTF(MPI_D_MISC, "%s: mpi_cfg_page poll\n", DEVNAME(sc));
        !          2344:                return (1);
        !          2345:        }
        !          2346:
        !          2347:        if (ccb->ccb_rcb == NULL) {
        !          2348:                mpi_put_ccb(sc, ccb);
        !          2349:                return (1);
        !          2350:        }
        !          2351:        cp = ccb->ccb_rcb->rcb_reply;
        !          2352:
        !          2353:        DNPRINTF(MPI_D_MISC, "%s:  action: 0x%02x msg_length: %d function: "
        !          2354:            "0x%02x\n", DEVNAME(sc), cp->action, cp->msg_length, cp->function);
        !          2355:        DNPRINTF(MPI_D_MISC, "%s:  ext_page_length: %d ext_page_type: 0x%02x "
        !          2356:            "msg_flags: 0x%02x\n", DEVNAME(sc),
        !          2357:            letoh16(cp->ext_page_length), cp->ext_page_type,
        !          2358:            cp->msg_flags);
        !          2359:        DNPRINTF(MPI_D_MISC, "%s:  msg_context: 0x%08x\n", DEVNAME(sc),
        !          2360:            letoh32(cp->msg_context));
        !          2361:        DNPRINTF(MPI_D_MISC, "%s:  ioc_status: 0x%04x\n", DEVNAME(sc),
        !          2362:            letoh16(cp->ioc_status));
        !          2363:        DNPRINTF(MPI_D_MISC, "%s:  ioc_loginfo: 0x%08x\n", DEVNAME(sc),
        !          2364:            letoh32(cp->ioc_loginfo));
        !          2365:        DNPRINTF(MPI_D_MISC, "%s:  page_version: 0x%02x page_length: %d "
        !          2366:            "page_number: 0x%02x page_type: 0x%02x\n", DEVNAME(sc),
        !          2367:            cp->config_header.page_version,
        !          2368:            cp->config_header.page_length,
        !          2369:            cp->config_header.page_number,
        !          2370:            cp->config_header.page_type);
        !          2371:
        !          2372:        if (letoh16(cp->ioc_status) != MPI_IOCSTATUS_SUCCESS)
        !          2373:                rv = 1;
        !          2374:        else if (read)
        !          2375:                bcopy(kva, page, len);
        !          2376:
        !          2377:        mpi_push_reply(sc, ccb->ccb_rcb->rcb_reply_dva);
        !          2378:        mpi_put_ccb(sc, ccb);
        !          2379:
        !          2380:        return (rv);
        !          2381: }

CVSweb