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

Annotation of sys/dev/pci/ips.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ips.c,v 1.29 2007/06/06 20:51:13 grange Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006, 2007 Alexander Yurchenko <grange@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * IBM (Adaptec) ServeRAID controller driver.
        !            21:  */
        !            22:
        !            23: #include <sys/param.h>
        !            24: #include <sys/systm.h>
        !            25: #include <sys/buf.h>
        !            26: #include <sys/device.h>
        !            27: #include <sys/kernel.h>
        !            28: #include <sys/malloc.h>
        !            29: #include <sys/timeout.h>
        !            30: #include <sys/queue.h>
        !            31:
        !            32: #include <machine/bus.h>
        !            33:
        !            34: #include <scsi/scsi_all.h>
        !            35: #include <scsi/scsi_disk.h>
        !            36: #include <scsi/scsiconf.h>
        !            37:
        !            38: #include <dev/pci/pcidevs.h>
        !            39: #include <dev/pci/pcireg.h>
        !            40: #include <dev/pci/pcivar.h>
        !            41:
        !            42: #define IPS_DEBUG      /* XXX: remove when driver becomes stable */
        !            43:
        !            44: /* Debug levels */
        !            45: #define IPS_D_ERR      0x0001  /* errors */
        !            46: #define IPS_D_INFO     0x0002  /* information */
        !            47: #define IPS_D_XFER     0x0004  /* transfers */
        !            48:
        !            49: #ifdef IPS_DEBUG
        !            50: #define DPRINTF(a, b)  do { if (ips_debug & (a)) printf b; } while (0)
        !            51: int ips_debug = IPS_D_ERR;
        !            52: #else
        !            53: #define DPRINTF(a, b)
        !            54: #endif
        !            55:
        !            56: #define IPS_MAXDRIVES          8
        !            57: #define IPS_MAXCHANS           4
        !            58: #define IPS_MAXTARGETS         15
        !            59: #define IPS_MAXCMDS            128
        !            60:
        !            61: #define IPS_MAXFER             (64 * 1024)
        !            62: #define IPS_MAXSGS             16
        !            63: #define IPS_MAXCMDSZ           (IPS_CMDSZ + IPS_MAXSGS * IPS_SGSZ)
        !            64:
        !            65: #define IPS_CMDSZ              sizeof(struct ips_cmd)
        !            66: #define IPS_SGSZ               sizeof(struct ips_sg)
        !            67: #define IPS_SECSZ              512
        !            68:
        !            69: /* Command codes */
        !            70: #define IPS_CMD_READ           0x02
        !            71: #define IPS_CMD_WRITE          0x03
        !            72: #define IPS_CMD_DCDB           0x04
        !            73: #define IPS_CMD_GETADAPTERINFO 0x05
        !            74: #define IPS_CMD_FLUSH          0x0a
        !            75: #define IPS_CMD_ERRORTABLE     0x17
        !            76: #define IPS_CMD_GETDRIVEINFO   0x19
        !            77: #define IPS_CMD_RESETCHAN      0x1a
        !            78: #define IPS_CMD_DOWNLOAD       0x20
        !            79: #define IPS_CMD_RWBIOSFW       0x22
        !            80: #define IPS_CMD_READCONF       0x38
        !            81: #define IPS_CMD_GETSUBSYS      0x40
        !            82: #define IPS_CMD_CONFIGSYNC     0x58
        !            83: #define IPS_CMD_READ_SG                0x82
        !            84: #define IPS_CMD_WRITE_SG       0x83
        !            85: #define IPS_CMD_DCDB_SG                0x84
        !            86: #define IPS_CMD_EXT_DCDB       0x95
        !            87: #define IPS_CMD_EXT_DCDB_SG    0x96
        !            88: #define IPS_CMD_RWNVRAMPAGE    0xbc
        !            89: #define IPS_CMD_GETVERINFO     0xc6
        !            90: #define IPS_CMD_FFDC           0xd7
        !            91: #define IPS_CMD_SG             0x80
        !            92:
        !            93: /* Register definitions */
        !            94: #define IPS_REG_HIS            0x08    /* host interrupt status */
        !            95: #define IPS_REG_HIS_SCE                        0x01    /* status channel enqueue */
        !            96: #define IPS_REG_HIS_EN                 0x80    /* enable interrupts */
        !            97: #define IPS_REG_CCSA           0x10    /* command channel system address */
        !            98: #define IPS_REG_CCC            0x14    /* command channel control */
        !            99: #define IPS_REG_CCC_SEM                        0x0008  /* semaphore */
        !           100: #define IPS_REG_CCC_START              0x101a  /* start command */
        !           101: #define IPS_REG_OIS            0x30    /* outbound interrupt status */
        !           102: #define IPS_REG_OIS_PEND               0x0008  /* interrupt is pending */
        !           103: #define IPS_REG_OIM            0x34    /* outbound interrupt mask */
        !           104: #define IPS_REG_OIM_DS                 0x0008  /* disable interrupts */
        !           105: #define IPS_REG_IQP            0x40    /* inbound queue port */
        !           106: #define IPS_REG_OQP            0x44    /* outbound queue port */
        !           107:
        !           108: #define IPS_REG_STAT_ID(x)     (((x) >> 8) & 0xff)
        !           109: #define IPS_REG_STAT_BASIC(x)  (((x) >> 16) & 0xff)
        !           110: #define IPS_REG_STAT_GSC(x)    (((x) >> 16) & 0x0f)
        !           111: #define IPS_REG_STAT_EXT(x)    (((x) >> 24) & 0xff)
        !           112:
        !           113: /* Command frame */
        !           114: struct ips_cmd {
        !           115:        u_int8_t        code;
        !           116:        u_int8_t        id;
        !           117:        u_int8_t        drive;
        !           118:        u_int8_t        sgcnt;
        !           119:        u_int32_t       lba;
        !           120:        u_int32_t       sgaddr;
        !           121:        u_int16_t       seccnt;
        !           122:        u_int8_t        seg4g;
        !           123:        u_int8_t        esg;
        !           124:        u_int32_t       ccsar;
        !           125:        u_int32_t       cccr;
        !           126: };
        !           127:
        !           128: /* Scatter-gather array element */
        !           129: struct ips_sg {
        !           130:        u_int32_t       addr;
        !           131:        u_int32_t       size;
        !           132: };
        !           133:
        !           134: /* Data frames */
        !           135: struct ips_adapterinfo {
        !           136:        u_int8_t        drivecnt;
        !           137:        u_int8_t        miscflag;
        !           138:        u_int8_t        sltflag;
        !           139:        u_int8_t        bstflag;
        !           140:        u_int8_t        pwrchgcnt;
        !           141:        u_int8_t        wrongaddrcnt;
        !           142:        u_int8_t        unidentcnt;
        !           143:        u_int8_t        nvramdevchgcnt;
        !           144:        u_int8_t        codeblkver[8];
        !           145:        u_int8_t        bootblkver[8];
        !           146:        u_int32_t       drivesize[IPS_MAXDRIVES];
        !           147:        u_int8_t        cmdcnt;
        !           148:        u_int8_t        maxphysdevs;
        !           149:        u_int16_t       flashrepgmcnt;
        !           150:        u_int8_t        defunctdiskcnt;
        !           151:        u_int8_t        rebuildflag;
        !           152:        u_int8_t        offdrivecnt;
        !           153:        u_int8_t        critdrivecnt;
        !           154:        u_int16_t       confupdcnt;
        !           155:        u_int8_t        blkflag;
        !           156:        u_int8_t        __reserved;
        !           157:        u_int16_t       deaddisk[IPS_MAXCHANS * (IPS_MAXTARGETS + 1)];
        !           158: };
        !           159:
        !           160: struct ips_driveinfo {
        !           161:        u_int8_t        drivecnt;
        !           162:        u_int8_t        __reserved[3];
        !           163:        struct ips_drive {
        !           164:                u_int8_t        id;
        !           165:                u_int8_t        __reserved;
        !           166:                u_int8_t        raid;
        !           167:                u_int8_t        state;
        !           168:                u_int32_t       seccnt;
        !           169:        }               drive[IPS_MAXDRIVES];
        !           170: };
        !           171:
        !           172: /* Command control block */
        !           173: struct ips_ccb {
        !           174:        int                     c_id;           /* command id */
        !           175:        int                     c_flags;        /* flags */
        !           176: #define IPS_CCB_READ   0x0001
        !           177: #define IPS_CCB_WRITE  0x0002
        !           178: #define IPS_CCB_POLL   0x0004
        !           179: #define IPS_CCB_RUN    0x0008
        !           180:
        !           181:        void *                  c_cmdva;        /* command frame virt addr */
        !           182:        paddr_t                 c_cmdpa;        /* command frame phys addr */
        !           183:        bus_dmamap_t            c_dmam;         /* data buffer DMA map */
        !           184:        struct scsi_xfer *      c_xfer;         /* corresponding SCSI xfer */
        !           185:        int                     c_stat;         /* status word copy */
        !           186:        int                     c_estat;        /* ext status word copy */
        !           187:
        !           188:        TAILQ_ENTRY(ips_ccb)    c_link;         /* queue link */
        !           189: };
        !           190:
        !           191: /* CCB queue */
        !           192: TAILQ_HEAD(ips_ccbq, ips_ccb);
        !           193:
        !           194: /* DMA-able chunk of memory */
        !           195: struct dmamem {
        !           196:        bus_dma_tag_t           dm_tag;
        !           197:        bus_dmamap_t            dm_map;
        !           198:        bus_dma_segment_t       dm_seg;
        !           199:        bus_size_t              dm_size;
        !           200:        void *                  dm_vaddr;
        !           201: #define dm_paddr dm_seg.ds_addr
        !           202: };
        !           203:
        !           204: struct ips_softc {
        !           205:        struct device           sc_dev;
        !           206:
        !           207:        struct scsi_link        sc_scsi_link;
        !           208:
        !           209:        bus_space_tag_t         sc_iot;
        !           210:        bus_space_handle_t      sc_ioh;
        !           211:        bus_dma_tag_t           sc_dmat;
        !           212:
        !           213:        const struct ips_chipset *sc_chip;
        !           214:
        !           215:        struct ips_driveinfo    sc_di;
        !           216:        int                     sc_nunits;
        !           217:
        !           218:        struct dmamem           sc_cmdm;
        !           219:
        !           220:        struct ips_ccb *        sc_ccb;
        !           221:        int                     sc_nccbs;
        !           222:        struct ips_ccbq         sc_ccbq_free;
        !           223:        struct ips_ccbq         sc_ccbq_run;
        !           224: };
        !           225:
        !           226: int    ips_match(struct device *, void *, void *);
        !           227: void   ips_attach(struct device *, struct device *, void *);
        !           228:
        !           229: int    ips_scsi_cmd(struct scsi_xfer *);
        !           230:
        !           231: int    ips_cmd(struct ips_softc *, int, int, u_int32_t, void *, size_t, int,
        !           232:            struct scsi_xfer *);
        !           233: int    ips_poll(struct ips_softc *, struct ips_ccb *);
        !           234: void   ips_done(struct ips_softc *, struct ips_ccb *);
        !           235: int    ips_intr(void *);
        !           236:
        !           237: int    ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *);
        !           238: int    ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *);
        !           239: int    ips_flush(struct ips_softc *);
        !           240:
        !           241: void   ips_copperhead_exec(struct ips_softc *, struct ips_ccb *);
        !           242: void   ips_copperhead_init(struct ips_softc *);
        !           243: void   ips_copperhead_intren(struct ips_softc *);
        !           244: int    ips_copperhead_isintr(struct ips_softc *);
        !           245: int    ips_copperhead_reset(struct ips_softc *);
        !           246: u_int32_t ips_copperhead_status(struct ips_softc *);
        !           247:
        !           248: void   ips_morpheus_exec(struct ips_softc *, struct ips_ccb *);
        !           249: void   ips_morpheus_init(struct ips_softc *);
        !           250: void   ips_morpheus_intren(struct ips_softc *);
        !           251: int    ips_morpheus_isintr(struct ips_softc *);
        !           252: int    ips_morpheus_reset(struct ips_softc *);
        !           253: u_int32_t ips_morpheus_status(struct ips_softc *);
        !           254:
        !           255: struct ips_ccb *ips_ccb_alloc(struct ips_softc *, int);
        !           256: void   ips_ccb_free(struct ips_softc *, struct ips_ccb *, int);
        !           257: struct ips_ccb *ips_ccb_get(struct ips_softc *);
        !           258: void   ips_ccb_put(struct ips_softc *, struct ips_ccb *);
        !           259:
        !           260: int    ips_dmamem_alloc(struct dmamem *, bus_dma_tag_t, bus_size_t);
        !           261: void   ips_dmamem_free(struct dmamem *);
        !           262:
        !           263: struct cfattach ips_ca = {
        !           264:        sizeof(struct ips_softc),
        !           265:        ips_match,
        !           266:        ips_attach
        !           267: };
        !           268:
        !           269: struct cfdriver ips_cd = {
        !           270:        NULL, "ips", DV_DULL
        !           271: };
        !           272:
        !           273: static struct scsi_adapter ips_scsi_adapter = {
        !           274:        ips_scsi_cmd,
        !           275:        minphys,
        !           276:        NULL,
        !           277:        NULL,
        !           278:        NULL
        !           279: };
        !           280:
        !           281: static struct scsi_device ips_scsi_device = {
        !           282:        NULL,
        !           283:        NULL,
        !           284:        NULL,
        !           285:        NULL
        !           286: };
        !           287:
        !           288: static const struct pci_matchid ips_ids[] = {
        !           289:        { PCI_VENDOR_IBM,       PCI_PRODUCT_IBM_SERVERAID },
        !           290:        { PCI_VENDOR_IBM,       PCI_PRODUCT_IBM_SERVERAID2 },
        !           291:        { PCI_VENDOR_ADP2,      PCI_PRODUCT_ADP2_SERVERAID }
        !           292: };
        !           293:
        !           294: static const struct ips_chipset {
        !           295:        const char *    ic_name;
        !           296:        int             ic_bar;
        !           297:
        !           298:        void            (*ic_exec)(struct ips_softc *, struct ips_ccb *);
        !           299:        void            (*ic_init)(struct ips_softc *);
        !           300:        void            (*ic_intren)(struct ips_softc *);
        !           301:        int             (*ic_isintr)(struct ips_softc *);
        !           302:        int             (*ic_reset)(struct ips_softc *);
        !           303:        u_int32_t       (*ic_status)(struct ips_softc *);
        !           304: } ips_chips[] = {
        !           305:        {
        !           306:                "Copperhead",
        !           307:                0x14,
        !           308:                ips_copperhead_exec,
        !           309:                ips_copperhead_init,
        !           310:                ips_copperhead_intren,
        !           311:                ips_copperhead_isintr,
        !           312:                ips_copperhead_reset,
        !           313:                ips_copperhead_status
        !           314:        },
        !           315:        {
        !           316:                "Morpheus",
        !           317:                0x10,
        !           318:                ips_morpheus_exec,
        !           319:                ips_morpheus_init,
        !           320:                ips_morpheus_intren,
        !           321:                ips_morpheus_isintr,
        !           322:                ips_morpheus_reset,
        !           323:                ips_morpheus_status
        !           324:        }
        !           325: };
        !           326:
        !           327: enum {
        !           328:        IPS_CHIP_COPPERHEAD = 0,
        !           329:        IPS_CHIP_MORPHEUS
        !           330: };
        !           331:
        !           332: #define ips_exec(s, c) (s)->sc_chip->ic_exec((s), (c))
        !           333: #define ips_init(s)    (s)->sc_chip->ic_init((s))
        !           334: #define ips_intren(s)  (s)->sc_chip->ic_intren((s))
        !           335: #define ips_isintr(s)  (s)->sc_chip->ic_isintr((s))
        !           336: #define ips_reset(s)   (s)->sc_chip->ic_reset((s))
        !           337: #define ips_status(s)  (s)->sc_chip->ic_status((s))
        !           338:
        !           339: int
        !           340: ips_match(struct device *parent, void *match, void *aux)
        !           341: {
        !           342:        return (pci_matchbyid(aux, ips_ids,
        !           343:            sizeof(ips_ids) / sizeof(ips_ids[0])));
        !           344: }
        !           345:
        !           346: void
        !           347: ips_attach(struct device *parent, struct device *self, void *aux)
        !           348: {
        !           349:        struct ips_softc *sc = (struct ips_softc *)self;
        !           350:        struct pci_attach_args *pa = aux;
        !           351:        struct ips_ccb ccb0;
        !           352:        struct scsibus_attach_args saa;
        !           353:        struct ips_adapterinfo ai;
        !           354:        pcireg_t maptype;
        !           355:        bus_size_t iosize;
        !           356:        pci_intr_handle_t ih;
        !           357:        const char *intrstr;
        !           358:        int i;
        !           359:
        !           360:        sc->sc_dmat = pa->pa_dmat;
        !           361:
        !           362:        /* Identify chipset */
        !           363:        switch (PCI_PRODUCT(pa->pa_id)) {
        !           364:        case PCI_PRODUCT_IBM_SERVERAID:
        !           365:                sc->sc_chip = &ips_chips[IPS_CHIP_COPPERHEAD];
        !           366:                break;
        !           367:        case PCI_PRODUCT_IBM_SERVERAID2:
        !           368:        case PCI_PRODUCT_ADP2_SERVERAID:
        !           369:                sc->sc_chip = &ips_chips[IPS_CHIP_MORPHEUS];
        !           370:                break;
        !           371:        default:
        !           372:                printf(": unsupported chipset\n");
        !           373:                return;
        !           374:        }
        !           375:
        !           376:        /* Map registers */
        !           377:        maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_chip->ic_bar);
        !           378:        if (pci_mapreg_map(pa, sc->sc_chip->ic_bar, maptype, 0, &sc->sc_iot,
        !           379:            &sc->sc_ioh, NULL, &iosize, 0)) {
        !           380:                printf(": can't map registers\n");
        !           381:                return;
        !           382:        }
        !           383:
        !           384:        /* Initialize hardware */
        !           385:        ips_init(sc);
        !           386:
        !           387:        /* Allocate command buffer */
        !           388:        if (ips_dmamem_alloc(&sc->sc_cmdm, sc->sc_dmat,
        !           389:            IPS_MAXCMDS * IPS_MAXCMDSZ)) {
        !           390:                printf(": can't allocate command buffer\n");
        !           391:                goto fail1;
        !           392:        }
        !           393:
        !           394:        /* Bootstrap CCB queue */
        !           395:        sc->sc_nccbs = 1;
        !           396:        sc->sc_ccb = &ccb0;
        !           397:        bzero(&ccb0, sizeof(ccb0));
        !           398:        ccb0.c_cmdva = sc->sc_cmdm.dm_vaddr;
        !           399:        ccb0.c_cmdpa = sc->sc_cmdm.dm_paddr;
        !           400:        if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
        !           401:            IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
        !           402:            &ccb0.c_dmam)) {
        !           403:                printf(": can't bootstrap CCB queue\n");
        !           404:                goto fail2;
        !           405:        }
        !           406:        TAILQ_INIT(&sc->sc_ccbq_free);
        !           407:        TAILQ_INIT(&sc->sc_ccbq_run);
        !           408:        TAILQ_INSERT_TAIL(&sc->sc_ccbq_free, &ccb0, c_link);
        !           409:
        !           410:        /* Get adapter info */
        !           411:        if (ips_getadapterinfo(sc, &ai)) {
        !           412:                printf(": can't get adapter info\n");
        !           413:                bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
        !           414:                goto fail2;
        !           415:        }
        !           416:
        !           417:        /* Get logical drives info */
        !           418:        if (ips_getdriveinfo(sc, &sc->sc_di)) {
        !           419:                printf(": can't get logical drives info\n");
        !           420:                bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
        !           421:                goto fail2;
        !           422:        }
        !           423:        sc->sc_nunits = sc->sc_di.drivecnt;
        !           424:
        !           425:        bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
        !           426:
        !           427:        /* Initialize CCB queue */
        !           428:        sc->sc_nccbs = ai.cmdcnt;
        !           429:        if ((sc->sc_ccb = ips_ccb_alloc(sc, sc->sc_nccbs)) == NULL) {
        !           430:                printf(": can't allocate CCB queue\n");
        !           431:                goto fail2;
        !           432:        }
        !           433:        TAILQ_INIT(&sc->sc_ccbq_free);
        !           434:        TAILQ_INIT(&sc->sc_ccbq_run);
        !           435:        for (i = 0; i < sc->sc_nccbs; i++)
        !           436:                TAILQ_INSERT_TAIL(&sc->sc_ccbq_free,
        !           437:                    &sc->sc_ccb[i], c_link);
        !           438:
        !           439:        /* Install interrupt handler */
        !           440:        if (pci_intr_map(pa, &ih)) {
        !           441:                printf(": can't map interrupt\n");
        !           442:                goto fail3;
        !           443:        }
        !           444:        intrstr = pci_intr_string(pa->pa_pc, ih);
        !           445:        if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ips_intr, sc,
        !           446:            sc->sc_dev.dv_xname) == NULL) {
        !           447:                printf(": can't establish interrupt");
        !           448:                if (intrstr != NULL)
        !           449:                        printf(" at %s", intrstr);
        !           450:                printf("\n");
        !           451:                goto fail3;
        !           452:        }
        !           453:        printf(": %s\n", intrstr);
        !           454:
        !           455:        /* Display adapter info */
        !           456:        printf("%s", sc->sc_dev.dv_xname);
        !           457:        printf(": %s", sc->sc_chip->ic_name);
        !           458:        printf(", firmware %c%c%c%c%c%c%c",
        !           459:            ai.codeblkver[0], ai.codeblkver[1], ai.codeblkver[2],
        !           460:            ai.codeblkver[3], ai.codeblkver[4], ai.codeblkver[5],
        !           461:            ai.codeblkver[6]);
        !           462:        printf(", bootblock %c%c%c%c%c%c%c",
        !           463:            ai.bootblkver[0], ai.bootblkver[1], ai.bootblkver[2],
        !           464:            ai.bootblkver[3], ai.bootblkver[4], ai.bootblkver[5],
        !           465:            ai.bootblkver[6]);
        !           466:        printf(", %d CCBs, %d units", sc->sc_nccbs, sc->sc_nunits);
        !           467:        printf("\n");
        !           468:
        !           469:        /* Attach SCSI bus */
        !           470:        if (sc->sc_nunits > 0)
        !           471:                sc->sc_scsi_link.openings = sc->sc_nccbs / sc->sc_nunits;
        !           472:        sc->sc_scsi_link.adapter_target = sc->sc_nunits;
        !           473:        sc->sc_scsi_link.adapter_buswidth = sc->sc_nunits;
        !           474:        sc->sc_scsi_link.device = &ips_scsi_device;
        !           475:        sc->sc_scsi_link.adapter = &ips_scsi_adapter;
        !           476:        sc->sc_scsi_link.adapter_softc = sc;
        !           477:
        !           478:        bzero(&saa, sizeof(saa));
        !           479:        saa.saa_sc_link = &sc->sc_scsi_link;
        !           480:        config_found(self, &saa, scsiprint);
        !           481:
        !           482:        /* Enable interrupts */
        !           483:        ips_intren(sc);
        !           484:
        !           485:        return;
        !           486: fail3:
        !           487:        ips_ccb_free(sc, sc->sc_ccb, sc->sc_nccbs);
        !           488: fail2:
        !           489:        ips_dmamem_free(&sc->sc_cmdm);
        !           490: fail1:
        !           491:        bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
        !           492: }
        !           493:
        !           494: int
        !           495: ips_scsi_cmd(struct scsi_xfer *xs)
        !           496: {
        !           497:        struct scsi_link *link = xs->sc_link;
        !           498:        struct ips_softc *sc = link->adapter_softc;
        !           499:        struct ips_drive *drive;
        !           500:        struct scsi_inquiry_data *id;
        !           501:        struct scsi_read_cap_data *rcd;
        !           502:        struct scsi_sense_data *sd;
        !           503:        struct scsi_rw *rw;
        !           504:        struct scsi_rw_big *rwb;
        !           505:        int target = link->target;
        !           506:        u_int32_t blkno, blkcnt;
        !           507:        int cmd, error, flags, s;
        !           508:
        !           509:        if (target >= sc->sc_nunits || link->lun != 0) {
        !           510:                DPRINTF(IPS_D_INFO, ("%s: invalid scsi command, "
        !           511:                    "target %d, lun %d\n", sc->sc_dev.dv_xname,
        !           512:                    target, link->lun));
        !           513:                xs->error = XS_DRIVER_STUFFUP;
        !           514:                s = splbio();
        !           515:                scsi_done(xs);
        !           516:                splx(s);
        !           517:                return (COMPLETE);
        !           518:        }
        !           519:
        !           520:        s = splbio();
        !           521:        drive = &sc->sc_di.drive[target];
        !           522:        xs->error = XS_NOERROR;
        !           523:
        !           524:        /* Fake SCSI commands */
        !           525:        switch (xs->cmd->opcode) {
        !           526:        case READ_BIG:
        !           527:        case READ_COMMAND:
        !           528:        case WRITE_BIG:
        !           529:        case WRITE_COMMAND:
        !           530:                if (xs->cmdlen == sizeof(struct scsi_rw)) {
        !           531:                        rw = (void *)xs->cmd;
        !           532:                        blkno = _3btol(rw->addr) &
        !           533:                            (SRW_TOPADDR << 16 | 0xffff);
        !           534:                        blkcnt = rw->length ? rw->length : 0x100;
        !           535:                } else {
        !           536:                        rwb = (void *)xs->cmd;
        !           537:                        blkno = _4btol(rwb->addr);
        !           538:                        blkcnt = _2btol(rwb->length);
        !           539:                }
        !           540:
        !           541:                if (blkno >= letoh32(drive->seccnt) || blkno + blkcnt >
        !           542:                    letoh32(drive->seccnt)) {
        !           543:                        DPRINTF(IPS_D_ERR, ("%s: invalid scsi command, "
        !           544:                            "blkno %u, blkcnt %u\n", sc->sc_dev.dv_xname,
        !           545:                            blkno, blkcnt));
        !           546:                        xs->error = XS_DRIVER_STUFFUP;
        !           547:                        scsi_done(xs);
        !           548:                        break;
        !           549:                }
        !           550:
        !           551:                if (xs->flags & SCSI_DATA_IN) {
        !           552:                        cmd = IPS_CMD_READ;
        !           553:                        flags = IPS_CCB_READ;
        !           554:                } else {
        !           555:                        cmd = IPS_CMD_WRITE;
        !           556:                        flags = IPS_CCB_WRITE;
        !           557:                }
        !           558:                if (xs->flags & SCSI_POLL)
        !           559:                        flags |= IPS_CCB_POLL;
        !           560:
        !           561:                if ((error = ips_cmd(sc, cmd, target, blkno, xs->data,
        !           562:                    blkcnt * IPS_SECSZ, flags, xs))) {
        !           563:                        if (error == ENOMEM) {
        !           564:                                splx(s);
        !           565:                                return (NO_CCB);
        !           566:                        } else if (flags & IPS_CCB_POLL) {
        !           567:                                splx(s);
        !           568:                                return (TRY_AGAIN_LATER);
        !           569:                        } else {
        !           570:                                xs->error = XS_DRIVER_STUFFUP;
        !           571:                                scsi_done(xs);
        !           572:                                break;
        !           573:                        }
        !           574:                }
        !           575:
        !           576:                splx(s);
        !           577:                if (flags & IPS_CCB_POLL)
        !           578:                        return (COMPLETE);
        !           579:                else
        !           580:                        return (SUCCESSFULLY_QUEUED);
        !           581:        case INQUIRY:
        !           582:                id = (void *)xs->data;
        !           583:                bzero(id, sizeof(*id));
        !           584:                id->device = T_DIRECT;
        !           585:                id->version = 2;
        !           586:                id->response_format = 2;
        !           587:                id->additional_length = 32;
        !           588:                strlcpy(id->vendor, "IBM     ", sizeof(id->vendor));
        !           589:                snprintf(id->product, sizeof(id->product),
        !           590:                    "ServeRAID RAID%d #%02d", drive->raid, target);
        !           591:                strlcpy(id->revision, "   ", sizeof(id->revision));
        !           592:                break;
        !           593:        case READ_CAPACITY:
        !           594:                rcd = (void *)xs->data;
        !           595:                bzero(rcd, sizeof(*rcd));
        !           596:                _lto4b(letoh32(drive->seccnt) - 1, rcd->addr);
        !           597:                _lto4b(IPS_SECSZ, rcd->length);
        !           598:                break;
        !           599:        case REQUEST_SENSE:
        !           600:                sd = (void *)xs->data;
        !           601:                bzero(sd, sizeof(*sd));
        !           602:                sd->error_code = SSD_ERRCODE_CURRENT;
        !           603:                sd->flags = SKEY_NO_SENSE;
        !           604:                break;
        !           605:        case SYNCHRONIZE_CACHE:
        !           606:                if (ips_flush(sc))
        !           607:                        xs->error = XS_DRIVER_STUFFUP;
        !           608:                break;
        !           609:        case PREVENT_ALLOW:
        !           610:        case START_STOP:
        !           611:        case TEST_UNIT_READY:
        !           612:                break;
        !           613:        default:
        !           614:                DPRINTF(IPS_D_INFO, ("%s: unsupported scsi command 0x%02x\n",
        !           615:                    sc->sc_dev.dv_xname, xs->cmd->opcode));
        !           616:                xs->error = XS_DRIVER_STUFFUP;
        !           617:        }
        !           618:        scsi_done(xs);
        !           619:        splx(s);
        !           620:
        !           621:        return (COMPLETE);
        !           622: }
        !           623:
        !           624: int
        !           625: ips_cmd(struct ips_softc *sc, int code, int drive, u_int32_t lba, void *data,
        !           626:     size_t size, int flags, struct scsi_xfer *xs)
        !           627: {
        !           628:        struct ips_cmd *cmd;
        !           629:        struct ips_sg *sg;
        !           630:        struct ips_ccb *ccb;
        !           631:        int nsegs, i, error = 0;
        !           632:
        !           633:        DPRINTF(IPS_D_XFER, ("%s: cmd code 0x%02x, drive %d, lba %u, "
        !           634:            "size %lu, flags 0x%02x\n", sc->sc_dev.dv_xname, code, drive, lba,
        !           635:            (u_long)size, flags));
        !           636:
        !           637:        /* Grab free CCB */
        !           638:        if ((ccb = ips_ccb_get(sc)) == NULL) {
        !           639:                DPRINTF(IPS_D_ERR, ("%s: no free CCB\n", sc->sc_dev.dv_xname));
        !           640:                return (ENOMEM);
        !           641:        }
        !           642:
        !           643:        ccb->c_flags = flags;
        !           644:        ccb->c_xfer = xs;
        !           645:
        !           646:        /* Fill in command frame */
        !           647:        cmd = ccb->c_cmdva;
        !           648:        cmd->code = code;
        !           649:        cmd->id = ccb->c_id;
        !           650:        cmd->drive = drive;
        !           651:        cmd->lba = htole32(lba);
        !           652:        cmd->seccnt = htole16(howmany(size, IPS_SECSZ));
        !           653:
        !           654:        if (size > 0) {
        !           655:                /* Map data buffer into DMA segments */
        !           656:                if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, data, size,
        !           657:                    NULL, BUS_DMA_NOWAIT)) {
        !           658:                        printf("%s: can't load DMA map\n",
        !           659:                            sc->sc_dev.dv_xname);
        !           660:                        return (1);     /* XXX: return code */
        !           661:                }
        !           662:                bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
        !           663:                    ccb->c_dmam->dm_mapsize,
        !           664:                    flags & IPS_CCB_READ ? BUS_DMASYNC_PREREAD :
        !           665:                    BUS_DMASYNC_PREWRITE);
        !           666:
        !           667:                if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS) {
        !           668:                        printf("%s: too many DMA segments\n",
        !           669:                            sc->sc_dev.dv_xname);
        !           670:                        return (1);     /* XXX: return code */
        !           671:                }
        !           672:
        !           673:                if (nsegs > 1) {
        !           674:                        cmd->code |= IPS_CMD_SG;
        !           675:                        cmd->sgcnt = nsegs;
        !           676:                        cmd->sgaddr = htole32(ccb->c_cmdpa + IPS_CMDSZ);
        !           677:
        !           678:                        /* Fill in scatter-gather array */
        !           679:                        sg = (void *)(cmd + 1);
        !           680:                        for (i = 0; i < nsegs; i++) {
        !           681:                                sg[i].addr =
        !           682:                                    htole32(ccb->c_dmam->dm_segs[i].ds_addr);
        !           683:                                sg[i].size =
        !           684:                                    htole32(ccb->c_dmam->dm_segs[i].ds_len);
        !           685:                        }
        !           686:                } else {
        !           687:                        cmd->sgcnt = 0;
        !           688:                        cmd->sgaddr = htole32(ccb->c_dmam->dm_segs[0].ds_addr);
        !           689:                }
        !           690:        }
        !           691:
        !           692:        /* Pass command to hardware */
        !           693:        DPRINTF(IPS_D_XFER, ("%s: run command 0x%02x\n", sc->sc_dev.dv_xname,
        !           694:            ccb->c_id));
        !           695:        ccb->c_flags |= IPS_CCB_RUN;
        !           696:        TAILQ_INSERT_TAIL(&sc->sc_ccbq_run, ccb, c_link);
        !           697:        ips_exec(sc, ccb);
        !           698:
        !           699:        if (flags & IPS_CCB_POLL)
        !           700:                /* Wait for command to complete */
        !           701:                error = ips_poll(sc, ccb);
        !           702:
        !           703:        return (error);
        !           704: }
        !           705:
        !           706: int
        !           707: ips_poll(struct ips_softc *sc, struct ips_ccb *c)
        !           708: {
        !           709:        struct ips_ccb *ccb = NULL;
        !           710:        u_int32_t status;
        !           711:        int id, timeout;
        !           712:
        !           713:        while (ccb != c) {
        !           714:                for (timeout = 100; timeout-- > 0; delay(100)) {
        !           715:                        if ((status = ips_status(sc)) == 0xffffffff)
        !           716:                                continue;
        !           717:                        id = IPS_REG_STAT_ID(status);
        !           718:                        if (id >= sc->sc_nccbs) {
        !           719:                                DPRINTF(IPS_D_ERR, ("%s: invalid command "
        !           720:                                    "0x%02x\n", sc->sc_dev.dv_xname, id));
        !           721:                                continue;
        !           722:                        }
        !           723:                        break;
        !           724:                }
        !           725:                if (timeout < 0) {
        !           726:                        printf("%s: poll timeout\n", sc->sc_dev.dv_xname);
        !           727:                        return (EBUSY);
        !           728:                }
        !           729:                ccb = &sc->sc_ccb[id];
        !           730:                ccb->c_stat = IPS_REG_STAT_GSC(status);
        !           731:                ccb->c_estat = IPS_REG_STAT_EXT(status);
        !           732:                ips_done(sc, ccb);
        !           733:        }
        !           734:
        !           735:        return (0);
        !           736: }
        !           737:
        !           738: void
        !           739: ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
        !           740: {
        !           741:        struct scsi_xfer *xs = ccb->c_xfer;
        !           742:        int flags = ccb->c_flags;
        !           743:        int error = 0;
        !           744:
        !           745:        if ((flags & IPS_CCB_RUN) == 0) {
        !           746:                printf("%s: command 0x%02x not run\n", sc->sc_dev.dv_xname,
        !           747:                    ccb->c_id);
        !           748:                if (xs != NULL) {
        !           749:                        xs->error = XS_DRIVER_STUFFUP;
        !           750:                        scsi_done(xs);
        !           751:                }
        !           752:                return;
        !           753:        }
        !           754:
        !           755:        if (flags & (IPS_CCB_READ | IPS_CCB_WRITE)) {
        !           756:                bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
        !           757:                    ccb->c_dmam->dm_mapsize, flags & IPS_CCB_READ ?
        !           758:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !           759:                bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
        !           760:        }
        !           761:
        !           762:        if (ccb->c_stat) {
        !           763:                printf("%s: ", sc->sc_dev.dv_xname);
        !           764:                if (ccb->c_stat == 1) {
        !           765:                        printf("recovered error\n");
        !           766:                } else {
        !           767:                        printf("error\n");
        !           768:                        error = 1;
        !           769:                }
        !           770:        }
        !           771:
        !           772:        /* Release CCB */
        !           773:        TAILQ_REMOVE(&sc->sc_ccbq_run, ccb, c_link);
        !           774:        ips_ccb_put(sc, ccb);
        !           775:
        !           776:        if (xs != NULL) {
        !           777:                if (error)
        !           778:                        xs->error = XS_DRIVER_STUFFUP;
        !           779:                else
        !           780:                        xs->resid = 0;
        !           781:                xs->flags |= ITSDONE;
        !           782:                scsi_done(xs);
        !           783:        }
        !           784: }
        !           785:
        !           786: int
        !           787: ips_intr(void *arg)
        !           788: {
        !           789:        struct ips_softc *sc = arg;
        !           790:        struct ips_ccb *ccb;
        !           791:        u_int32_t status;
        !           792:        int id;
        !           793:
        !           794:        if (!ips_isintr(sc))
        !           795:                return (0);
        !           796:
        !           797:        /* Process completed commands */
        !           798:        while ((status = ips_status(sc)) != 0xffffffff) {
        !           799:                DPRINTF(IPS_D_XFER, ("%s: intr status 0x%08x\n",
        !           800:                    sc->sc_dev.dv_xname, status));
        !           801:
        !           802:                id = IPS_REG_STAT_ID(status);
        !           803:                if (id >= sc->sc_nccbs) {
        !           804:                        DPRINTF(IPS_D_ERR, ("%s: invalid command %d\n",
        !           805:                            sc->sc_dev.dv_xname, id));
        !           806:                        continue;
        !           807:                }
        !           808:                ccb = &sc->sc_ccb[id];
        !           809:                ccb->c_stat = IPS_REG_STAT_GSC(status);
        !           810:                ccb->c_estat = IPS_REG_STAT_EXT(status);
        !           811:                ips_done(sc, ccb);
        !           812:        }
        !           813:
        !           814:        return (1);
        !           815: }
        !           816:
        !           817: int
        !           818: ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai)
        !           819: {
        !           820:        return (ips_cmd(sc, IPS_CMD_GETADAPTERINFO, 0, 0, ai, sizeof(*ai),
        !           821:            IPS_CCB_READ | IPS_CCB_POLL, NULL));
        !           822: }
        !           823:
        !           824: int
        !           825: ips_getdriveinfo(struct ips_softc *sc, struct ips_driveinfo *di)
        !           826: {
        !           827:        return (ips_cmd(sc, IPS_CMD_GETDRIVEINFO, 0, 0, di, sizeof(*di),
        !           828:            IPS_CCB_READ | IPS_CCB_POLL, NULL));
        !           829: }
        !           830:
        !           831: int
        !           832: ips_flush(struct ips_softc *sc)
        !           833: {
        !           834:        return (ips_cmd(sc, IPS_CMD_FLUSH, 0, 0, NULL, 0, IPS_CCB_POLL, NULL));
        !           835: }
        !           836:
        !           837: void
        !           838: ips_copperhead_exec(struct ips_softc *sc, struct ips_ccb *ccb)
        !           839: {
        !           840:        u_int32_t reg;
        !           841:        int timeout;
        !           842:
        !           843:        for (timeout = 100; timeout-- > 0; delay(100)) {
        !           844:                reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC);
        !           845:                if ((reg & IPS_REG_CCC_SEM) == 0)
        !           846:                        break;
        !           847:        }
        !           848:        if (timeout < 0) {
        !           849:                printf("%s: semaphore timeout\n", sc->sc_dev.dv_xname);
        !           850:                return;
        !           851:        }
        !           852:
        !           853:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_CCSA, ccb->c_cmdpa);
        !           854:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, IPS_REG_CCC,
        !           855:            IPS_REG_CCC_START);
        !           856: }
        !           857:
        !           858: void
        !           859: ips_copperhead_init(struct ips_softc *sc)
        !           860: {
        !           861:        /* XXX: not implemented */
        !           862: }
        !           863:
        !           864: void
        !           865: ips_copperhead_intren(struct ips_softc *sc)
        !           866: {
        !           867:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, IPS_REG_HIS_EN);
        !           868: }
        !           869:
        !           870: int
        !           871: ips_copperhead_isintr(struct ips_softc *sc)
        !           872: {
        !           873:        u_int8_t reg;
        !           874:
        !           875:        reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS);
        !           876:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, IPS_REG_HIS, reg);
        !           877:        if (reg != 0xff && (reg & IPS_REG_HIS_SCE))
        !           878:                return (1);
        !           879:
        !           880:        return (0);
        !           881: }
        !           882:
        !           883: int
        !           884: ips_copperhead_reset(struct ips_softc *sc)
        !           885: {
        !           886:        /* XXX: not implemented */
        !           887:        return (0);
        !           888: }
        !           889:
        !           890: u_int32_t
        !           891: ips_copperhead_status(struct ips_softc *sc)
        !           892: {
        !           893:        /* XXX: not implemented */
        !           894:        return (0);
        !           895: }
        !           896:
        !           897: void
        !           898: ips_morpheus_exec(struct ips_softc *sc, struct ips_ccb *ccb)
        !           899: {
        !           900:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_IQP, ccb->c_cmdpa);
        !           901: }
        !           902:
        !           903: void
        !           904: ips_morpheus_init(struct ips_softc *sc)
        !           905: {
        !           906:        /* XXX: not implemented */
        !           907: }
        !           908:
        !           909: void
        !           910: ips_morpheus_intren(struct ips_softc *sc)
        !           911: {
        !           912:        u_int32_t reg;
        !           913:
        !           914:        reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM);
        !           915:        reg &= ~IPS_REG_OIM_DS;
        !           916:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM, reg);
        !           917: }
        !           918:
        !           919: int
        !           920: ips_morpheus_isintr(struct ips_softc *sc)
        !           921: {
        !           922:        u_int32_t reg;
        !           923:
        !           924:        reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIS);
        !           925:        DPRINTF(IPS_D_XFER, ("%s: isintr 0x%08x\n", sc->sc_dev.dv_xname, reg));
        !           926:
        !           927:        return (reg & IPS_REG_OIS_PEND);
        !           928: }
        !           929:
        !           930: int
        !           931: ips_morpheus_reset(struct ips_softc *sc)
        !           932: {
        !           933:        /* XXX: not implemented */
        !           934:        return (0);
        !           935: }
        !           936:
        !           937: u_int32_t
        !           938: ips_morpheus_status(struct ips_softc *sc)
        !           939: {
        !           940:        u_int32_t reg;
        !           941:
        !           942:        reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OQP);
        !           943:        DPRINTF(IPS_D_XFER, ("%s: status 0x%08x\n", sc->sc_dev.dv_xname, reg));
        !           944:
        !           945:        return (reg);
        !           946: }
        !           947:
        !           948: struct ips_ccb *
        !           949: ips_ccb_alloc(struct ips_softc *sc, int n)
        !           950: {
        !           951:        struct ips_ccb *ccb;
        !           952:        int i;
        !           953:
        !           954:        if ((ccb = malloc(n * sizeof(*ccb), M_DEVBUF, M_NOWAIT)) == NULL)
        !           955:                return (NULL);
        !           956:        bzero(ccb, n * sizeof(*ccb));
        !           957:
        !           958:        for (i = 0; i < n; i++) {
        !           959:                ccb[i].c_id = i;
        !           960:                ccb[i].c_cmdva = (char *)sc->sc_cmdm.dm_vaddr +
        !           961:                    i * IPS_MAXCMDSZ;
        !           962:                ccb[i].c_cmdpa = sc->sc_cmdm.dm_paddr + i * IPS_MAXCMDSZ;
        !           963:                if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
        !           964:                    IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
        !           965:                    &ccb[i].c_dmam))
        !           966:                        goto fail;
        !           967:        }
        !           968:
        !           969:        return (ccb);
        !           970: fail:
        !           971:        for (; i > 0; i--)
        !           972:                bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
        !           973:        free(ccb, M_DEVBUF);
        !           974:        return (NULL);
        !           975: }
        !           976:
        !           977: void
        !           978: ips_ccb_free(struct ips_softc *sc, struct ips_ccb *ccb, int n)
        !           979: {
        !           980:        int i;
        !           981:
        !           982:        for (i = 0; i < n; i++)
        !           983:                bus_dmamap_destroy(sc->sc_dmat, ccb[i - 1].c_dmam);
        !           984:        free(ccb, M_DEVBUF);
        !           985: }
        !           986:
        !           987: struct ips_ccb *
        !           988: ips_ccb_get(struct ips_softc *sc)
        !           989: {
        !           990:        struct ips_ccb *ccb;
        !           991:
        !           992:        if ((ccb = TAILQ_FIRST(&sc->sc_ccbq_free)) != NULL)
        !           993:                TAILQ_REMOVE(&sc->sc_ccbq_free, ccb, c_link);
        !           994:
        !           995:        return (ccb);
        !           996: }
        !           997:
        !           998: void
        !           999: ips_ccb_put(struct ips_softc *sc, struct ips_ccb *ccb)
        !          1000: {
        !          1001:        ccb->c_flags = 0;
        !          1002:        ccb->c_xfer = NULL;
        !          1003:        TAILQ_INSERT_TAIL(&sc->sc_ccbq_free, ccb, c_link);
        !          1004: }
        !          1005:
        !          1006: int
        !          1007: ips_dmamem_alloc(struct dmamem *dm, bus_dma_tag_t tag, bus_size_t size)
        !          1008: {
        !          1009:        int nsegs;
        !          1010:
        !          1011:        dm->dm_tag = tag;
        !          1012:        dm->dm_size = size;
        !          1013:
        !          1014:        if (bus_dmamap_create(tag, size, 1, size, 0,
        !          1015:            BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dm->dm_map))
        !          1016:                return (1);
        !          1017:        if (bus_dmamem_alloc(tag, size, 0, 0, &dm->dm_seg, 1, &nsegs,
        !          1018:            BUS_DMA_NOWAIT))
        !          1019:                goto fail1;
        !          1020:        if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, (caddr_t *)&dm->dm_vaddr,
        !          1021:            BUS_DMA_NOWAIT))
        !          1022:                goto fail2;
        !          1023:        if (bus_dmamap_load(tag, dm->dm_map, dm->dm_vaddr, size, NULL,
        !          1024:            BUS_DMA_NOWAIT))
        !          1025:                goto fail3;
        !          1026:
        !          1027:        return (0);
        !          1028:
        !          1029: fail3:
        !          1030:        bus_dmamem_unmap(tag, dm->dm_vaddr, size);
        !          1031: fail2:
        !          1032:        bus_dmamem_free(tag, &dm->dm_seg, 1);
        !          1033: fail1:
        !          1034:        bus_dmamap_destroy(tag, dm->dm_map);
        !          1035:        return (1);
        !          1036: }
        !          1037:
        !          1038: void
        !          1039: ips_dmamem_free(struct dmamem *dm)
        !          1040: {
        !          1041:        bus_dmamap_unload(dm->dm_tag, dm->dm_map);
        !          1042:        bus_dmamem_unmap(dm->dm_tag, dm->dm_vaddr, dm->dm_size);
        !          1043:        bus_dmamem_free(dm->dm_tag, &dm->dm_seg, 1);
        !          1044:        bus_dmamap_destroy(dm->dm_tag, dm->dm_map);
        !          1045: }

CVSweb