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

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

1.1     ! nbrk        1: /*     $OpenBSD: ami.c,v 1.184 2007/06/24 05:34:35 dlg Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2001 Michael Shalayeff
        !             5:  * Copyright (c) 2005 Marco Peereboom
        !             6:  * Copyright (c) 2006 David Gwynne
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * The SCSI emulation layer is derived from gdt(4) driver,
        !            10:  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            24:  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
        !            25:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            26:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            27:  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            29:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
        !            30:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            31:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33: /*
        !            34:  * American Megatrends Inc. MegaRAID controllers driver
        !            35:  *
        !            36:  * This driver was made because these ppl and organizations
        !            37:  * donated hardware and provided documentation:
        !            38:  *
        !            39:  * - 428 model card
        !            40:  *     John Kerbawy, Stephan Matis, Mark Stovall;
        !            41:  *
        !            42:  * - 467 and 475 model cards, docs
        !            43:  *     American Megatrends Inc.;
        !            44:  *
        !            45:  * - uninterruptable electric power for cvs
        !            46:  *     Theo de Raadt.
        !            47:  */
        !            48:
        !            49: #include "bio.h"
        !            50:
        !            51: /* #define     AMI_DEBUG */
        !            52:
        !            53: #include <sys/param.h>
        !            54: #include <sys/systm.h>
        !            55: #include <sys/buf.h>
        !            56: #include <sys/ioctl.h>
        !            57: #include <sys/device.h>
        !            58: #include <sys/kernel.h>
        !            59: #include <sys/malloc.h>
        !            60: #include <sys/proc.h>
        !            61: #include <sys/rwlock.h>
        !            62:
        !            63: #include <machine/bus.h>
        !            64:
        !            65: #include <scsi/scsi_all.h>
        !            66: #include <scsi/scsi_disk.h>
        !            67: #include <scsi/scsiconf.h>
        !            68:
        !            69: #include <dev/ic/amireg.h>
        !            70: #include <dev/ic/amivar.h>
        !            71:
        !            72:
        !            73: #if NBIO > 0
        !            74: #include <dev/biovar.h>
        !            75: #include <sys/sensors.h>
        !            76: #endif
        !            77:
        !            78: #ifdef AMI_DEBUG
        !            79: #define        AMI_DPRINTF(m,a)        do { if (ami_debug & (m)) printf a; } while (0)
        !            80: #define        AMI_D_CMD       0x0001
        !            81: #define        AMI_D_INTR      0x0002
        !            82: #define        AMI_D_MISC      0x0004
        !            83: #define        AMI_D_DMA       0x0008
        !            84: #define        AMI_D_IOCTL     0x0010
        !            85: int ami_debug = 0
        !            86:        | AMI_D_CMD
        !            87:        | AMI_D_INTR
        !            88:        | AMI_D_MISC
        !            89: /*     | AMI_D_DMA */
        !            90: /*     | AMI_D_IOCTL */
        !            91:        ;
        !            92: #else
        !            93: #define        AMI_DPRINTF(m,a)        /* m, a */
        !            94: #endif
        !            95:
        !            96: struct cfdriver ami_cd = {
        !            97:        NULL, "ami", DV_DULL
        !            98: };
        !            99:
        !           100: int    ami_scsi_cmd(struct scsi_xfer *);
        !           101: int    ami_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, struct proc *);
        !           102: void   amiminphys(struct buf *bp);
        !           103:
        !           104: struct scsi_adapter ami_switch = {
        !           105:        ami_scsi_cmd, amiminphys, 0, 0, ami_scsi_ioctl
        !           106: };
        !           107:
        !           108: struct scsi_device ami_dev = {
        !           109:        NULL, NULL, NULL, NULL
        !           110: };
        !           111:
        !           112: int    ami_scsi_raw_cmd(struct scsi_xfer *);
        !           113:
        !           114: struct scsi_adapter ami_raw_switch = {
        !           115:        ami_scsi_raw_cmd, amiminphys, 0, 0,
        !           116: };
        !           117:
        !           118: struct scsi_device ami_raw_dev = {
        !           119:        NULL, NULL, NULL, NULL
        !           120: };
        !           121:
        !           122: struct ami_ccb *ami_get_ccb(struct ami_softc *);
        !           123: void           ami_put_ccb(struct ami_ccb *);
        !           124:
        !           125: u_int32_t      ami_read(struct ami_softc *, bus_size_t);
        !           126: void           ami_write(struct ami_softc *, bus_size_t, u_int32_t);
        !           127:
        !           128: void           ami_copyhds(struct ami_softc *, const u_int32_t *,
        !           129:                    const u_int8_t *, const u_int8_t *);
        !           130: struct ami_mem *ami_allocmem(struct ami_softc *, size_t);
        !           131: void           ami_freemem(struct ami_softc *, struct ami_mem *);
        !           132: int            ami_alloc_ccbs(struct ami_softc *, int);
        !           133:
        !           134: int            ami_poll(struct ami_softc *, struct ami_ccb *);
        !           135: void           ami_start(struct ami_softc *, struct ami_ccb *);
        !           136: void           ami_complete(struct ami_softc *, struct ami_ccb *, int);
        !           137: int            ami_done(struct ami_softc *, int);
        !           138: void           ami_runqueue_tick(void *);
        !           139: void           ami_runqueue(struct ami_softc *);
        !           140:
        !           141: int            ami_start_xs(struct ami_softc *sc, struct ami_ccb *,
        !           142:                    struct scsi_xfer *);
        !           143: void           ami_done_xs(struct ami_softc *, struct ami_ccb *);
        !           144: void           ami_done_pt(struct ami_softc *, struct ami_ccb *);
        !           145: void           ami_done_flush(struct ami_softc *, struct ami_ccb *);
        !           146: void           ami_done_sysflush(struct ami_softc *, struct ami_ccb *);
        !           147: void           ami_stimeout(void *);
        !           148:
        !           149: void           ami_done_ioctl(struct ami_softc *, struct ami_ccb *);
        !           150: void           ami_done_init(struct ami_softc *, struct ami_ccb *);
        !           151:
        !           152: void           ami_copy_internal_data(struct scsi_xfer *, void *, size_t);
        !           153:
        !           154: int            ami_load_ptmem(struct ami_softc*, struct ami_ccb *,
        !           155:                    void *, size_t, int, int);
        !           156:
        !           157: #if NBIO > 0
        !           158: int            ami_mgmt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t,
        !           159:                    u_int8_t, size_t, void *);
        !           160: int            ami_drv_inq(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t,
        !           161:                    void *);
        !           162: int            ami_ioctl(struct device *, u_long, caddr_t);
        !           163: int            ami_ioctl_inq(struct ami_softc *, struct bioc_inq *);
        !           164: int            ami_vol(struct ami_softc *, struct bioc_vol *,
        !           165:                    struct ami_big_diskarray *);
        !           166: int            ami_disk(struct ami_softc *, struct bioc_disk *,
        !           167:                    struct ami_big_diskarray *);
        !           168: int            ami_ioctl_vol(struct ami_softc *, struct bioc_vol *);
        !           169: int            ami_ioctl_disk(struct ami_softc *, struct bioc_disk *);
        !           170: int            ami_ioctl_alarm(struct ami_softc *, struct bioc_alarm *);
        !           171: int            ami_ioctl_setstate(struct ami_softc *, struct bioc_setstate *);
        !           172:
        !           173: #ifndef SMALL_KERNEL
        !           174: int            ami_create_sensors(struct ami_softc *);
        !           175: void           ami_refresh_sensors(void *);
        !           176: #endif
        !           177: #endif /* NBIO > 0 */
        !           178:
        !           179: #define DEVNAME(_s)    ((_s)->sc_dev.dv_xname)
        !           180:
        !           181: struct ami_ccb *
        !           182: ami_get_ccb(struct ami_softc *sc)
        !           183: {
        !           184:        struct ami_ccb *ccb;
        !           185:
        !           186:        ccb = TAILQ_FIRST(&sc->sc_ccb_freeq);
        !           187:        if (ccb) {
        !           188:                TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link);
        !           189:                ccb->ccb_state = AMI_CCB_READY;
        !           190:        }
        !           191:
        !           192:        return (ccb);
        !           193: }
        !           194:
        !           195: void
        !           196: ami_put_ccb(struct ami_ccb *ccb)
        !           197: {
        !           198:        struct ami_softc *sc = ccb->ccb_sc;
        !           199:
        !           200:        ccb->ccb_state = AMI_CCB_FREE;
        !           201:        ccb->ccb_xs = NULL;
        !           202:        ccb->ccb_flags = 0;
        !           203:        ccb->ccb_done = NULL;
        !           204:        TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link);
        !           205: }
        !           206:
        !           207: u_int32_t
        !           208: ami_read(struct ami_softc *sc, bus_size_t r)
        !           209: {
        !           210:        u_int32_t rv;
        !           211:
        !           212:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
        !           213:            BUS_SPACE_BARRIER_READ);
        !           214:        rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r);
        !           215:
        !           216:        AMI_DPRINTF(AMI_D_CMD, ("ari 0x%x 0x08%x ", r, rv));
        !           217:        return (rv);
        !           218: }
        !           219:
        !           220: void
        !           221: ami_write(struct ami_softc *sc, bus_size_t r, u_int32_t v)
        !           222: {
        !           223:        AMI_DPRINTF(AMI_D_CMD, ("awo 0x%x 0x%08x ", r, v));
        !           224:
        !           225:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
        !           226:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
        !           227:            BUS_SPACE_BARRIER_WRITE);
        !           228: }
        !           229:
        !           230: struct ami_mem *
        !           231: ami_allocmem(struct ami_softc *sc, size_t size)
        !           232: {
        !           233:        struct ami_mem          *am;
        !           234:        int                     nsegs;
        !           235:
        !           236:        am = malloc(sizeof(struct ami_mem), M_DEVBUF, M_NOWAIT);
        !           237:        if (am == NULL)
        !           238:                return (NULL);
        !           239:
        !           240:        memset(am, 0, sizeof(struct ami_mem));
        !           241:        am->am_size = size;
        !           242:
        !           243:        if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
        !           244:            BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &am->am_map) != 0)
        !           245:                goto amfree;
        !           246:
        !           247:        if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &am->am_seg, 1,
        !           248:            &nsegs, BUS_DMA_NOWAIT) != 0)
        !           249:                goto destroy;
        !           250:
        !           251:        if (bus_dmamem_map(sc->sc_dmat, &am->am_seg, nsegs, size, &am->am_kva,
        !           252:            BUS_DMA_NOWAIT) != 0)
        !           253:                goto free;
        !           254:
        !           255:        if (bus_dmamap_load(sc->sc_dmat, am->am_map, am->am_kva, size, NULL,
        !           256:            BUS_DMA_NOWAIT) != 0)
        !           257:                goto unmap;
        !           258:
        !           259:        memset(am->am_kva, 0, size);
        !           260:        return (am);
        !           261:
        !           262: unmap:
        !           263:        bus_dmamem_unmap(sc->sc_dmat, am->am_kva, size);
        !           264: free:
        !           265:        bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1);
        !           266: destroy:
        !           267:        bus_dmamap_destroy(sc->sc_dmat, am->am_map);
        !           268: amfree:
        !           269:        free(am, M_DEVBUF);
        !           270:
        !           271:        return (NULL);
        !           272: }
        !           273:
        !           274: void
        !           275: ami_freemem(struct ami_softc *sc, struct ami_mem *am)
        !           276: {
        !           277:        bus_dmamap_unload(sc->sc_dmat, am->am_map);
        !           278:        bus_dmamem_unmap(sc->sc_dmat, am->am_kva, am->am_size);
        !           279:        bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1);
        !           280:        bus_dmamap_destroy(sc->sc_dmat, am->am_map);
        !           281:        free(am, M_DEVBUF);
        !           282: }
        !           283:
        !           284: void
        !           285: ami_copyhds(struct ami_softc *sc, const u_int32_t *sizes,
        !           286:     const u_int8_t *props, const u_int8_t *stats)
        !           287: {
        !           288:        int i;
        !           289:
        !           290:        for (i = 0; i < sc->sc_nunits; i++) {
        !           291:                sc->sc_hdr[i].hd_present = 1;
        !           292:                sc->sc_hdr[i].hd_is_logdrv = 1;
        !           293:                sc->sc_hdr[i].hd_size = letoh32(sizes[i]);
        !           294:                sc->sc_hdr[i].hd_prop = props[i];
        !           295:                sc->sc_hdr[i].hd_stat = stats[i];
        !           296:        }
        !           297: }
        !           298:
        !           299: int
        !           300: ami_alloc_ccbs(struct ami_softc *sc, int nccbs)
        !           301: {
        !           302:        struct ami_ccb *ccb;
        !           303:        struct ami_ccbmem *ccbmem, *mem;
        !           304:        int i, error;
        !           305:
        !           306:        sc->sc_ccbs = malloc(sizeof(struct ami_ccb) * nccbs,
        !           307:            M_DEVBUF, M_NOWAIT);
        !           308:        if (sc->sc_ccbs == NULL) {
        !           309:                printf(": unable to allocate ccbs\n");
        !           310:                return (1);
        !           311:        }
        !           312:
        !           313:        sc->sc_ccbmem_am = ami_allocmem(sc, sizeof(struct ami_ccbmem) * nccbs);
        !           314:        if (sc->sc_ccbmem_am == NULL) {
        !           315:                printf(": unable to allocate ccb dmamem\n");
        !           316:                goto free_ccbs;
        !           317:        }
        !           318:        ccbmem = AMIMEM_KVA(sc->sc_ccbmem_am);
        !           319:
        !           320:        TAILQ_INIT(&sc->sc_ccb_freeq);
        !           321:        TAILQ_INIT(&sc->sc_ccb_preq);
        !           322:        TAILQ_INIT(&sc->sc_ccb_runq);
        !           323:        timeout_set(&sc->sc_run_tmo, ami_runqueue_tick, sc);
        !           324:
        !           325:        for (i = 0; i < nccbs; i++) {
        !           326:                ccb = &sc->sc_ccbs[i];
        !           327:                mem = &ccbmem[i];
        !           328:
        !           329:                error = bus_dmamap_create(sc->sc_dmat, AMI_MAXFER,
        !           330:                    AMI_MAXOFFSETS, AMI_MAXFER, 0,
        !           331:                    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap);
        !           332:                if (error) {
        !           333:                        printf(": cannot create ccb dmamap (%d)\n", error);
        !           334:                        goto free_list;
        !           335:                }
        !           336:
        !           337:                ccb->ccb_sc = sc;
        !           338:
        !           339:                ccb->ccb_cmd.acc_id = i + 1;
        !           340:                ccb->ccb_offset = sizeof(struct ami_ccbmem) * i;
        !           341:
        !           342:                ccb->ccb_pt = &mem->cd_pt;
        !           343:                ccb->ccb_ptpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) +
        !           344:                    ccb->ccb_offset);
        !           345:
        !           346:                ccb->ccb_sglist = mem->cd_sg;
        !           347:                ccb->ccb_sglistpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) +
        !           348:                    ccb->ccb_offset + sizeof(struct ami_passthrough));
        !           349:
        !           350:                ami_put_ccb(ccb);
        !           351:        }
        !           352:
        !           353:        return (0);
        !           354:
        !           355: free_list:
        !           356:        while ((ccb = ami_get_ccb(sc)) != NULL)
        !           357:                bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
        !           358:
        !           359:        ami_freemem(sc, sc->sc_ccbmem_am);
        !           360: free_ccbs:
        !           361:        free(sc->sc_ccbs, M_DEVBUF);
        !           362:
        !           363:        return (1);
        !           364: }
        !           365:
        !           366: int
        !           367: ami_attach(struct ami_softc *sc)
        !           368: {
        !           369:        struct scsibus_attach_args saa;
        !           370:        struct ami_rawsoftc *rsc;
        !           371:        struct ami_ccb iccb;
        !           372:        struct ami_iocmd *cmd;
        !           373:        struct ami_mem *am;
        !           374:        const char *p;
        !           375:        paddr_t pa;
        !           376:        int s;
        !           377:
        !           378:        am = ami_allocmem(sc, NBPG);
        !           379:        if (am == NULL) {
        !           380:                printf(": unable to allocate init data\n");
        !           381:                return (1);
        !           382:        }
        !           383:        pa = htole32(AMIMEM_DVA(am));
        !           384:
        !           385:        sc->sc_mbox_am = ami_allocmem(sc, sizeof(struct ami_iocmd));
        !           386:        if (sc->sc_mbox_am == NULL) {
        !           387:                printf(": unable to allocate mbox\n");
        !           388:                goto free_idata;
        !           389:        }
        !           390:        sc->sc_mbox = (volatile struct ami_iocmd *)AMIMEM_KVA(sc->sc_mbox_am);
        !           391:        sc->sc_mbox_pa = htole32(AMIMEM_DVA(sc->sc_mbox_am));
        !           392:        AMI_DPRINTF(AMI_D_CMD, ("mbox=%p ", sc->sc_mbox));
        !           393:        AMI_DPRINTF(AMI_D_CMD, ("mbox_pa=0x%llx ", (long long)sc->sc_mbox_pa));
        !           394:
        !           395:        /* create a spartan ccb for use with ami_poll */
        !           396:        bzero(&iccb, sizeof(iccb));
        !           397:        iccb.ccb_sc = sc;
        !           398:        iccb.ccb_done = ami_done_init;
        !           399:        cmd = &iccb.ccb_cmd;
        !           400:
        !           401:        (sc->sc_init)(sc);
        !           402:
        !           403:        s = splbio();
        !           404:
        !           405:        /* try FC inquiry first */
        !           406:        cmd->acc_cmd = AMI_FCOP;
        !           407:        cmd->acc_io.aio_channel = AMI_FC_EINQ3;
        !           408:        cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL;
        !           409:        cmd->acc_io.aio_data = pa;
        !           410:        if (ami_poll(sc, &iccb) == 0) {
        !           411:                struct ami_fc_einquiry *einq = AMIMEM_KVA(am);
        !           412:                struct ami_fc_prodinfo *pi = AMIMEM_KVA(am);
        !           413:
        !           414:                sc->sc_nunits = einq->ain_nlogdrv;
        !           415:                ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop,
        !           416:                    einq->ain_ldstat);
        !           417:
        !           418:                cmd->acc_cmd = AMI_FCOP;
        !           419:                cmd->acc_io.aio_channel = AMI_FC_PRODINF;
        !           420:                cmd->acc_io.aio_param = 0;
        !           421:                cmd->acc_io.aio_data = pa;
        !           422:                if (ami_poll(sc, &iccb) == 0) {
        !           423:                        sc->sc_maxunits = AMI_BIG_MAX_LDRIVES;
        !           424:
        !           425:                        bcopy (pi->api_fwver, sc->sc_fwver, 16);
        !           426:                        sc->sc_fwver[15] = '\0';
        !           427:                        bcopy (pi->api_biosver, sc->sc_biosver, 16);
        !           428:                        sc->sc_biosver[15] = '\0';
        !           429:                        sc->sc_channels = pi->api_channels;
        !           430:                        sc->sc_targets = pi->api_fcloops;
        !           431:                        sc->sc_memory = letoh16(pi->api_ramsize);
        !           432:                        sc->sc_maxcmds = pi->api_maxcmd;
        !           433:                        p = "FC loop";
        !           434:                }
        !           435:        }
        !           436:
        !           437:        if (sc->sc_maxunits == 0) {
        !           438:                struct ami_inquiry *inq = AMIMEM_KVA(am);
        !           439:
        !           440:                cmd->acc_cmd = AMI_EINQUIRY;
        !           441:                cmd->acc_io.aio_channel = 0;
        !           442:                cmd->acc_io.aio_param = 0;
        !           443:                cmd->acc_io.aio_data = pa;
        !           444:                if (ami_poll(sc, &iccb) != 0) {
        !           445:                        cmd->acc_cmd = AMI_INQUIRY;
        !           446:                        cmd->acc_io.aio_channel = 0;
        !           447:                        cmd->acc_io.aio_param = 0;
        !           448:                        cmd->acc_io.aio_data = pa;
        !           449:                        if (ami_poll(sc, &iccb) != 0) {
        !           450:                                splx(s);
        !           451:                                printf(": cannot do inquiry\n");
        !           452:                                goto free_mbox;
        !           453:                        }
        !           454:                }
        !           455:
        !           456:                sc->sc_maxunits = AMI_MAX_LDRIVES;
        !           457:                sc->sc_nunits = inq->ain_nlogdrv;
        !           458:                ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop,
        !           459:                    inq->ain_ldstat);
        !           460:
        !           461:                bcopy (inq->ain_fwver, sc->sc_fwver, 4);
        !           462:                sc->sc_fwver[4] = '\0';
        !           463:                bcopy (inq->ain_biosver, sc->sc_biosver, 4);
        !           464:                sc->sc_biosver[4] = '\0';
        !           465:                sc->sc_channels = inq->ain_channels;
        !           466:                sc->sc_targets = inq->ain_targets;
        !           467:                sc->sc_memory = inq->ain_ramsize;
        !           468:                sc->sc_maxcmds = inq->ain_maxcmd;
        !           469:                p = "target";
        !           470:        }
        !           471:
        !           472:        if (sc->sc_flags & AMI_BROKEN) {
        !           473:                sc->sc_link.openings = 1;
        !           474:                sc->sc_maxcmds = 1;
        !           475:                sc->sc_maxunits = 1;
        !           476:        } else {
        !           477:                sc->sc_maxunits = AMI_BIG_MAX_LDRIVES;
        !           478:                if (sc->sc_maxcmds > AMI_MAXCMDS)
        !           479:                        sc->sc_maxcmds = AMI_MAXCMDS;
        !           480:                /*
        !           481:                 * Reserve ccb's for ioctl's and raw commands to
        !           482:                 * processors/enclosures by lowering the number of
        !           483:                 * openings available for logical units.
        !           484:                 */
        !           485:                sc->sc_maxcmds -= AMI_MAXIOCTLCMDS + AMI_MAXPROCS *
        !           486:                    AMI_MAXRAWCMDS * sc->sc_channels;
        !           487:
        !           488:                if (sc->sc_nunits)
        !           489:                        sc->sc_link.openings =
        !           490:                            sc->sc_maxcmds / sc->sc_nunits;
        !           491:                else
        !           492:                        sc->sc_link.openings = sc->sc_maxcmds;
        !           493:        }
        !           494:
        !           495:        splx(s);
        !           496:
        !           497:        ami_freemem(sc, am);
        !           498:
        !           499:        if (ami_alloc_ccbs(sc, AMI_MAXCMDS) != 0) {
        !           500:                /* error already printed */
        !           501:                goto free_mbox;
        !           502:        }
        !           503:
        !           504:        /* hack for hp netraid version encoding */
        !           505:        if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' &&
        !           506:            sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' &&
        !           507:            'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' &&
        !           508:            sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') {
        !           509:
        !           510:                snprintf(sc->sc_fwver, sizeof sc->sc_fwver, "%c.%02d.%02d",
        !           511:                    sc->sc_fwver[2], sc->sc_fwver[1], sc->sc_fwver[0]);
        !           512:                snprintf(sc->sc_biosver, sizeof sc->sc_biosver, "%c.%02d.%02d",
        !           513:                    sc->sc_biosver[2], sc->sc_biosver[1], sc->sc_biosver[0]);
        !           514:        }
        !           515:
        !           516:        /* TODO: fetch & print cache strategy */
        !           517:        /* TODO: fetch & print scsi and raid info */
        !           518:
        !           519:        sc->sc_link.device = &ami_dev;
        !           520:        sc->sc_link.adapter_softc = sc;
        !           521:        sc->sc_link.adapter = &ami_switch;
        !           522:        sc->sc_link.adapter_target = sc->sc_maxunits;
        !           523:        sc->sc_link.adapter_buswidth = sc->sc_maxunits;
        !           524:
        !           525: #ifdef AMI_DEBUG
        !           526:        printf(", FW %s, BIOS v%s, %dMB RAM\n"
        !           527:            "%s: %d channels, %d %ss, %d logical drives, "
        !           528:            "openings %d, max commands %d, quirks: %04x\n",
        !           529:            sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc),
        !           530:            sc->sc_channels, sc->sc_targets, p, sc->sc_nunits,
        !           531:            sc->sc_link.openings, sc->sc_maxcmds, sc->sc_flags);
        !           532: #else
        !           533:        printf(", FW %s, BIOS v%s, %dMB RAM\n"
        !           534:            "%s: %d channels, %d %ss, %d logical drives\n",
        !           535:            sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc),
        !           536:            sc->sc_channels, sc->sc_targets, p, sc->sc_nunits);
        !           537: #endif /* AMI_DEBUG */
        !           538:
        !           539:        if (sc->sc_flags & AMI_BROKEN && sc->sc_nunits > 1)
        !           540:                printf("%s: firmware buggy, limiting access to first logical "
        !           541:                    "disk\n", DEVNAME(sc));
        !           542:
        !           543:        /* lock around ioctl requests */
        !           544:        rw_init(&sc->sc_lock, NULL);
        !           545:
        !           546:        bzero(&saa, sizeof(saa));
        !           547:        saa.saa_sc_link = &sc->sc_link;
        !           548:
        !           549:        config_found(&sc->sc_dev, &saa, scsiprint);
        !           550:
        !           551:        /* can't do bioctls, sensors, or pass-through on broken devices */
        !           552:        if (sc->sc_flags & AMI_BROKEN)
        !           553:                return (0);
        !           554:
        !           555: #if NBIO > 0
        !           556:        if (bio_register(&sc->sc_dev, ami_ioctl) != 0)
        !           557:                printf("%s: controller registration failed\n", DEVNAME(sc));
        !           558:        else
        !           559:                sc->sc_ioctl = ami_ioctl;
        !           560:
        !           561: #ifndef SMALL_KERNEL
        !           562:        if (ami_create_sensors(sc) != 0)
        !           563:                printf("%s: unable to create sensors\n", DEVNAME(sc));
        !           564: #endif
        !           565: #endif
        !           566:
        !           567:        rsc = malloc(sizeof(struct ami_rawsoftc) * sc->sc_channels,
        !           568:            M_DEVBUF, M_NOWAIT);
        !           569:        if (!rsc) {
        !           570:                printf("%s: no memory for raw interface\n", DEVNAME(sc));
        !           571:                return (0);
        !           572:        }
        !           573:
        !           574:        bzero(rsc, sizeof(struct ami_rawsoftc) * sc->sc_channels);
        !           575:        for (sc->sc_rawsoftcs = rsc;
        !           576:             rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) {
        !           577:
        !           578:                rsc->sc_softc = sc;
        !           579:                rsc->sc_channel = rsc - sc->sc_rawsoftcs;
        !           580:                rsc->sc_link.device = &ami_raw_dev;
        !           581:                rsc->sc_link.openings = AMI_MAXRAWCMDS;
        !           582:                rsc->sc_link.adapter_softc = rsc;
        !           583:                rsc->sc_link.adapter = &ami_raw_switch;
        !           584:                rsc->sc_proctarget = -1;
        !           585:                /* TODO fetch it from the controller */
        !           586:                rsc->sc_link.adapter_target = 16;
        !           587:                rsc->sc_link.adapter_buswidth = 16;
        !           588:
        !           589:                bzero(&saa, sizeof(saa));
        !           590:                saa.saa_sc_link = &rsc->sc_link;
        !           591:
        !           592:                config_found(&sc->sc_dev, &saa, scsiprint);
        !           593:        }
        !           594:
        !           595:        return (0);
        !           596:
        !           597: free_mbox:
        !           598:        ami_freemem(sc, sc->sc_mbox_am);
        !           599: free_idata:
        !           600:        ami_freemem(sc, am);
        !           601:
        !           602:        return (1);
        !           603: }
        !           604:
        !           605: int
        !           606: ami_quartz_init(struct ami_softc *sc)
        !           607: {
        !           608:        ami_write(sc, AMI_QIDB, 0);
        !           609:
        !           610:        return (0);
        !           611: }
        !           612:
        !           613: int
        !           614: ami_quartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd)
        !           615: {
        !           616:        if (sc->sc_mbox->acc_busy) {
        !           617:                AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
        !           618:                return (EBUSY);
        !           619:        }
        !           620:
        !           621:        memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
        !           622:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
        !           623:            sizeof(struct ami_iocmd), BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
        !           624:
        !           625:        sc->sc_mbox->acc_busy = 1;
        !           626:        sc->sc_mbox->acc_poll = 0;
        !           627:        sc->sc_mbox->acc_ack = 0;
        !           628:
        !           629:        ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC));
        !           630:
        !           631:        return (0);
        !           632: }
        !           633:
        !           634: int
        !           635: ami_quartz_done(struct ami_softc *sc, struct ami_iocmd *mbox)
        !           636: {
        !           637:        u_int32_t i, n;
        !           638:        u_int8_t nstat, status;
        !           639:        u_int8_t completed[AMI_MAXSTATACK];
        !           640:
        !           641:        if (ami_read(sc, AMI_QODB) != AMI_QODB_READY)
        !           642:                return (0); /* nothing to do */
        !           643:
        !           644:        ami_write(sc, AMI_QODB, AMI_QODB_READY);
        !           645:
        !           646:        /*
        !           647:         * The following sequence is not supposed to have a timeout clause
        !           648:         * since the firmware has a "guarantee" that all commands will
        !           649:         * complete.  The choice is either panic or hoping for a miracle
        !           650:         * and that the IOs will complete much later.
        !           651:         */
        !           652:        i = 0;
        !           653:        while ((nstat = sc->sc_mbox->acc_nstat) == 0xff) {
        !           654:                bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
        !           655:                    sizeof(struct ami_iocmd), BUS_DMASYNC_POSTREAD);
        !           656:                delay(1);
        !           657:                if (i++ > 1000000)
        !           658:                        return (0); /* nothing to do */
        !           659:        }
        !           660:        sc->sc_mbox->acc_nstat = 0xff;
        !           661:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
        !           662:            sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE);
        !           663:
        !           664:        /* wait until fw wrote out all completions */
        !           665:        i = 0;
        !           666:        AMI_DPRINTF(AMI_D_CMD, ("aqd %d ", nstat));
        !           667:        for (n = 0; n < nstat; n++) {
        !           668:                bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
        !           669:                    sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD);
        !           670:                while ((completed[n] = sc->sc_mbox->acc_cmplidl[n]) == 0xff) {
        !           671:                        delay(1);
        !           672:                        if (i++ > 1000000)
        !           673:                                return (0); /* nothing to do */
        !           674:                }
        !           675:                sc->sc_mbox->acc_cmplidl[n] = 0xff;
        !           676:                bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
        !           677:                    sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE);
        !           678:        }
        !           679:
        !           680:        /* this should never happen, someone screwed up the completion status */
        !           681:        if ((status = sc->sc_mbox->acc_status) == 0xff)
        !           682:                panic("%s: status 0xff from the firmware", DEVNAME(sc));
        !           683:
        !           684:        sc->sc_mbox->acc_status = 0xff;
        !           685:
        !           686:        /* copy mailbox to temporary one and fixup other changed values */
        !           687:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16,
        !           688:            BUS_DMASYNC_POSTWRITE);
        !           689:        memcpy(mbox, (struct ami_iocmd *)sc->sc_mbox, 16);
        !           690:        mbox->acc_nstat = nstat;
        !           691:        mbox->acc_status = status;
        !           692:        for (n = 0; n < nstat; n++)
        !           693:                mbox->acc_cmplidl[n] = completed[n];
        !           694:
        !           695:        /* ack interrupt */
        !           696:        ami_write(sc, AMI_QIDB, AMI_QIDB_ACK);
        !           697:
        !           698:        return (1);     /* ready to complete all IOs in acc_cmplidl */
        !           699: }
        !           700:
        !           701: int
        !           702: ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
        !           703: {
        !           704:        /* struct scsi_xfer *xs = ccb->ccb_xs; */
        !           705:        u_int32_t i;
        !           706:        u_int8_t status;
        !           707:
        !           708:        if (sc->sc_dis_poll)
        !           709:                return (1); /* fail */
        !           710:
        !           711:        i = 0;
        !           712:        while (sc->sc_mbox->acc_busy && (i < AMI_MAX_BUSYWAIT)) {
        !           713:                delay(1);
        !           714:                i++;
        !           715:        }
        !           716:        if (sc->sc_mbox->acc_busy) {
        !           717:                AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
        !           718:                return (EBUSY);
        !           719:        }
        !           720:
        !           721:        memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
        !           722:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16,
        !           723:            BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
        !           724:
        !           725:        sc->sc_mbox->acc_id = 0xfe;
        !           726:        sc->sc_mbox->acc_busy = 1;
        !           727:        sc->sc_mbox->acc_poll = 0;
        !           728:        sc->sc_mbox->acc_ack = 0;
        !           729:
        !           730:        sc->sc_mbox->acc_nstat = 0xff;
        !           731:        sc->sc_mbox->acc_status = 0xff;
        !           732:
        !           733:        /* send command to firmware */
        !           734:        ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC));
        !           735:
        !           736:        while ((sc->sc_mbox->acc_nstat == 0xff) && (i < AMI_MAX_POLLWAIT)) {
        !           737:                delay(1);
        !           738:                i++;
        !           739:        }
        !           740:        if (i >= AMI_MAX_POLLWAIT) {
        !           741:                printf("%s: command not accepted, polling disabled\n",
        !           742:                    DEVNAME(sc));
        !           743:                sc->sc_dis_poll = 1;
        !           744:                return (1);
        !           745:        }
        !           746:
        !           747:        sc->sc_mbox->acc_nstat = 0xff;
        !           748:
        !           749:        while ((sc->sc_mbox->acc_status == 0xff) && (i < AMI_MAX_POLLWAIT)) {
        !           750:                delay(1);
        !           751:                i++;
        !           752:        }
        !           753:        if (i >= AMI_MAX_POLLWAIT) {
        !           754:                printf("%s: bad status, polling disabled\n", DEVNAME(sc));
        !           755:                sc->sc_dis_poll = 1;
        !           756:                return (1);
        !           757:        }
        !           758:        status = sc->sc_mbox->acc_status;
        !           759:        sc->sc_mbox->acc_status = 0xff;
        !           760:
        !           761:        /* poll firmware */
        !           762:        while ((sc->sc_mbox->acc_poll != 0x77) && (i < AMI_MAX_POLLWAIT)) {
        !           763:                delay(1);
        !           764:                i++;
        !           765:        }
        !           766:        if (i >= AMI_MAX_POLLWAIT) {
        !           767:                printf("%s: firmware didn't reply, polling disabled\n",
        !           768:                    DEVNAME(sc));
        !           769:                sc->sc_dis_poll = 1;
        !           770:                return 1;
        !           771:        }
        !           772:
        !           773:        sc->sc_mbox->acc_poll = 0;
        !           774:        sc->sc_mbox->acc_ack = 0x77;
        !           775:
        !           776:        /* ack */
        !           777:        ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_ACK));
        !           778:
        !           779:        while((ami_read(sc, AMI_QIDB) & AMI_QIDB_ACK) &&
        !           780:            (i < AMI_MAX_POLLWAIT)) {
        !           781:                delay(1);
        !           782:                i++;
        !           783:        }
        !           784:        if (i >= AMI_MAX_POLLWAIT) {
        !           785:                printf("%s: firmware didn't ack the ack, polling disabled\n",
        !           786:                    DEVNAME(sc));
        !           787:                sc->sc_dis_poll = 1;
        !           788:                return (1);
        !           789:        }
        !           790:
        !           791:        for (i = 0; i < AMI_MAXSTATACK; i++)
        !           792:                sc->sc_mbox->acc_cmplidl[i] = 0xff;
        !           793:
        !           794:        return (status);
        !           795: }
        !           796:
        !           797: int
        !           798: ami_schwartz_init(struct ami_softc *sc)
        !           799: {
        !           800:        u_int32_t a = (u_int32_t)sc->sc_mbox_pa;
        !           801:
        !           802:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, AMI_SMBADDR, a);
        !           803:        /* XXX 40bit address ??? */
        !           804:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SMBENA, 0);
        !           805:
        !           806:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK);
        !           807:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM, AMI_SEIM_ENA |
        !           808:            bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM));
        !           809:
        !           810:        return (0);
        !           811: }
        !           812:
        !           813: int
        !           814: ami_schwartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd)
        !           815: {
        !           816:        if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
        !           817:            AMI_SMBST_BUSY) {
        !           818:                AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
        !           819:                return (EBUSY);
        !           820:        }
        !           821:
        !           822:        memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
        !           823:        sc->sc_mbox->acc_busy = 1;
        !           824:        sc->sc_mbox->acc_poll = 0;
        !           825:        sc->sc_mbox->acc_ack = 0;
        !           826:
        !           827:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC);
        !           828:        return (0);
        !           829: }
        !           830:
        !           831: int
        !           832: ami_schwartz_done(struct ami_softc *sc, struct ami_iocmd *mbox)
        !           833: {
        !           834:        u_int8_t stat;
        !           835:
        !           836: #if 0
        !           837:        /* do not scramble the busy mailbox */
        !           838:        if (sc->sc_mbox->acc_busy)
        !           839:                return (0);
        !           840: #endif
        !           841:        if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
        !           842:            AMI_SMBST_BUSY)
        !           843:                return (0);
        !           844:
        !           845:        stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT);
        !           846:        if (stat & AMI_ISTAT_PEND) {
        !           847:                bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, stat);
        !           848:
        !           849:                *mbox = *sc->sc_mbox;
        !           850:                AMI_DPRINTF(AMI_D_CMD, ("asd %d ", mbox->acc_nstat));
        !           851:
        !           852:                bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD,
        !           853:                    AMI_SCMD_ACK);
        !           854:
        !           855:                return (1);
        !           856:        }
        !           857:
        !           858:        return (0);
        !           859: }
        !           860:
        !           861: int
        !           862: ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
        !           863: {
        !           864:        u_int8_t status;
        !           865:        u_int32_t i;
        !           866:        int rv;
        !           867:
        !           868:        if (sc->sc_dis_poll)
        !           869:                return (1); /* fail */
        !           870:
        !           871:        for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
        !           872:                if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
        !           873:                    AMI_SMBST_BUSY))
        !           874:                        break;
        !           875:                delay(1);
        !           876:        }
        !           877:        if (i >= AMI_MAX_POLLWAIT) {
        !           878:                AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
        !           879:                return (EBUSY);
        !           880:        }
        !           881:
        !           882:        memcpy((struct ami_iocmd *)sc->sc_mbox, mbox, 16);
        !           883:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16,
        !           884:            BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
        !           885:
        !           886:        sc->sc_mbox->acc_busy = 1;
        !           887:        sc->sc_mbox->acc_poll = 0;
        !           888:        sc->sc_mbox->acc_ack = 0;
        !           889:        /* send command to firmware */
        !           890:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC);
        !           891:
        !           892:        /* wait until no longer busy */
        !           893:        for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
        !           894:                if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
        !           895:                    AMI_SMBST_BUSY))
        !           896:                        break;
        !           897:                delay(1);
        !           898:        }
        !           899:        if (i >= AMI_MAX_POLLWAIT) {
        !           900:                printf("%s: command not accepted, polling disabled\n",
        !           901:                    DEVNAME(sc));
        !           902:                sc->sc_dis_poll = 1;
        !           903:                return (1); /* fail */
        !           904:        }
        !           905:
        !           906:        /* wait for interrupt bit */
        !           907:        for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
        !           908:                status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT);
        !           909:                if (status & AMI_ISTAT_PEND)
        !           910:                        break;
        !           911:                delay(1);
        !           912:        }
        !           913:        if (i >= AMI_MAX_POLLWAIT) {
        !           914:                printf("%s: interrupt didn't arrive, polling disabled\n",
        !           915:                    DEVNAME(sc));
        !           916:                sc->sc_dis_poll = 1;
        !           917:                return (1); /* fail */
        !           918:        }
        !           919:
        !           920:        /* write ststus back to firmware */
        !           921:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, status);
        !           922:
        !           923:        /* copy mailbox and status back */
        !           924:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0,
        !           925:            sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD);
        !           926:        *mbox = *sc->sc_mbox;
        !           927:        rv = sc->sc_mbox->acc_status;
        !           928:
        !           929:        /* ack interrupt */
        !           930:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK);
        !           931:
        !           932:        return (rv);
        !           933: }
        !           934:
        !           935: int
        !           936: ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs)
        !           937: {
        !           938:        timeout_set(&xs->stimeout, ami_stimeout, ccb);
        !           939:
        !           940:        if (xs->flags & SCSI_POLL) {
        !           941:                ami_complete(sc, ccb, xs->timeout);
        !           942:                return (COMPLETE);
        !           943:        }
        !           944:
        !           945:        timeout_add(&xs->stimeout, 61 * hz);
        !           946:        ami_start(sc, ccb);
        !           947:
        !           948:        return (SUCCESSFULLY_QUEUED);
        !           949: }
        !           950:
        !           951: void
        !           952: ami_start(struct ami_softc *sc, struct ami_ccb *ccb)
        !           953: {
        !           954:        int s;
        !           955:
        !           956:        s = splbio();
        !           957:        ccb->ccb_state = AMI_CCB_PREQUEUED;
        !           958:        TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link);
        !           959:        ami_runqueue(sc);
        !           960:        splx(s);
        !           961: }
        !           962:
        !           963: void
        !           964: ami_runqueue_tick(void *arg)
        !           965: {
        !           966:        struct ami_softc *sc = arg;
        !           967:        int s;
        !           968:
        !           969:        s = splbio();
        !           970:        ami_runqueue(sc);
        !           971:        splx(s);
        !           972: }
        !           973:
        !           974: void
        !           975: ami_runqueue(struct ami_softc *sc)
        !           976: {
        !           977:        struct ami_ccb *ccb;
        !           978:
        !           979:        while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) {
        !           980:                if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) {
        !           981:                        /* this is now raceable too with other incomming io */
        !           982:                        timeout_add(&sc->sc_run_tmo, 1);
        !           983:                        break;
        !           984:                }
        !           985:
        !           986:                TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
        !           987:                ccb->ccb_state = AMI_CCB_QUEUED;
        !           988:                TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
        !           989:        }
        !           990: }
        !           991:
        !           992: int
        !           993: ami_poll(struct ami_softc *sc, struct ami_ccb *ccb)
        !           994: {
        !           995:        int error;
        !           996:        int s;
        !           997:
        !           998:        /* XXX this is broken, shall drain IO or consider this
        !           999:         * a normal completion which can complete async and
        !          1000:         * polled commands until the polled commands completes
        !          1001:         */
        !          1002:
        !          1003:        s = splbio();
        !          1004:        error = sc->sc_poll(sc, &ccb->ccb_cmd);
        !          1005:        if (error)
        !          1006:                ccb->ccb_flags |= AMI_CCB_F_ERR;
        !          1007:
        !          1008:        ccb->ccb_done(sc, ccb);
        !          1009:        splx(s);
        !          1010:
        !          1011:        return (error);
        !          1012: }
        !          1013:
        !          1014: void
        !          1015: ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
        !          1016: {
        !          1017:        struct ami_iocmd mbox;
        !          1018:        int i = 0, j, done = 0;
        !          1019:        int s;
        !          1020:
        !          1021:        s = splbio();
        !          1022:
        !          1023:        /*
        !          1024:         * since exec will return if the mbox is busy we have to busy wait
        !          1025:         * ourselves. once its in, jam it into the runq.
        !          1026:         */
        !          1027:        while (i < AMI_MAX_BUSYWAIT) {
        !          1028:                if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) {
        !          1029:                        ccb->ccb_state = AMI_CCB_QUEUED;
        !          1030:                        TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
        !          1031:                        break;
        !          1032:                }
        !          1033:
        !          1034:                DELAY(1000);
        !          1035:                i++;
        !          1036:        }
        !          1037:        if (ccb->ccb_state != AMI_CCB_QUEUED)
        !          1038:                goto err;
        !          1039:
        !          1040:        i = 0;
        !          1041:        while (i < timeout) {
        !          1042:                if (sc->sc_done(sc, &mbox) != 0) {
        !          1043:                        for (j = 0; j < mbox.acc_nstat; j++) {
        !          1044:                                int ready = mbox.acc_cmplidl[j];
        !          1045:                                ami_done(sc, ready);
        !          1046:                                if (ready == ccb->ccb_cmd.acc_id)
        !          1047:                                        done = 1;
        !          1048:                        }
        !          1049:                        if (done)
        !          1050:                                break;
        !          1051:                }
        !          1052:
        !          1053:                DELAY(1000);
        !          1054:                i++;
        !          1055:        }
        !          1056:        if (!done) {
        !          1057:                printf("%s: timeout ccb %d\n", DEVNAME(sc),
        !          1058:                    ccb->ccb_cmd.acc_id);
        !          1059:                TAILQ_REMOVE(&sc->sc_ccb_runq, ccb, ccb_link);
        !          1060:                goto err;
        !          1061:        }
        !          1062:
        !          1063:        /* start the runqueue again */
        !          1064:        ami_runqueue(sc);
        !          1065:
        !          1066:        splx(s);
        !          1067:
        !          1068:        return;
        !          1069:
        !          1070: err:
        !          1071:        ccb->ccb_flags |= AMI_CCB_F_ERR;
        !          1072:        ccb->ccb_state = AMI_CCB_READY;
        !          1073:        ccb->ccb_done(sc, ccb);
        !          1074:        splx(s);
        !          1075: }
        !          1076:
        !          1077: void
        !          1078: ami_stimeout(void *v)
        !          1079: {
        !          1080:        struct ami_ccb *ccb = v;
        !          1081:        struct ami_softc *sc = ccb->ccb_sc;
        !          1082:        struct ami_iocmd *cmd = &ccb->ccb_cmd;
        !          1083:        int s;
        !          1084:
        !          1085:        s = splbio();
        !          1086:        switch (ccb->ccb_state) {
        !          1087:        case AMI_CCB_PREQUEUED:
        !          1088:                /* command never ran, cleanup is easy */
        !          1089:                TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
        !          1090:                ccb->ccb_flags |= AMI_CCB_F_ERR;
        !          1091:                ccb->ccb_done(sc, ccb);
        !          1092:                break;
        !          1093:
        !          1094:        case AMI_CCB_QUEUED:
        !          1095:                /*
        !          1096:                 * ccb has taken more than a minute to finish. we can't take
        !          1097:                 * it off the hardware in case it finishes later, but we can
        !          1098:                 * warn the user to look at what is happening.
        !          1099:                 */
        !          1100:                AMI_DPRINTF(AMI_D_CMD, ("%s: stimeout ccb %d, check volume "
        !          1101:                    "state\n", DEVNAME(sc), cmd->acc_id));
        !          1102:                break;
        !          1103:
        !          1104:        default:
        !          1105:                panic("%s: ami_stimeout(%d) botch", DEVNAME(sc), cmd->acc_id);
        !          1106:        }
        !          1107:
        !          1108:        splx(s);
        !          1109: }
        !          1110:
        !          1111: int
        !          1112: ami_done(struct ami_softc *sc, int idx)
        !          1113: {
        !          1114:        struct ami_ccb *ccb = &sc->sc_ccbs[idx - 1];
        !          1115:
        !          1116:        AMI_DPRINTF(AMI_D_CMD, ("done(%d) ", ccb->ccb_cmd.acc_id));
        !          1117:
        !          1118:        if (ccb->ccb_state != AMI_CCB_QUEUED) {
        !          1119:                printf("%s: unqueued ccb %d ready, state = %d\n",
        !          1120:                    DEVNAME(sc), idx, ccb->ccb_state);
        !          1121:                return (1);
        !          1122:        }
        !          1123:
        !          1124:        ccb->ccb_state = AMI_CCB_READY;
        !          1125:        TAILQ_REMOVE(&sc->sc_ccb_runq, ccb, ccb_link);
        !          1126:
        !          1127:        ccb->ccb_done(sc, ccb);
        !          1128:
        !          1129:        return (0);
        !          1130: }
        !          1131:
        !          1132: void
        !          1133: ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb)
        !          1134: {
        !          1135:        struct scsi_xfer *xs = ccb->ccb_xs;
        !          1136:        struct scsi_link *link = xs->sc_link;
        !          1137:        struct ami_rawsoftc *rsc = link->adapter_softc;
        !          1138:        u_int8_t target = link->target, type;
        !          1139:
        !          1140:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
        !          1141:            ccb->ccb_offset, sizeof(struct ami_ccbmem),
        !          1142:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1143:
        !          1144:        if (xs->data != NULL) {
        !          1145:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
        !          1146:                    ccb->ccb_dmamap->dm_mapsize,
        !          1147:                    (xs->flags & SCSI_DATA_IN) ?
        !          1148:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !          1149:
        !          1150:                bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
        !          1151:        }
        !          1152:
        !          1153:        timeout_del(&xs->stimeout);
        !          1154:        xs->resid = 0;
        !          1155:        xs->flags |= ITSDONE;
        !          1156:
        !          1157:        if (ccb->ccb_flags & AMI_CCB_F_ERR)
        !          1158:                xs->error = XS_DRIVER_STUFFUP;
        !          1159:        else if (xs->flags & SCSI_POLL && xs->cmd->opcode == INQUIRY) {
        !          1160:                type = ((struct scsi_inquiry_data *)xs->data)->device &
        !          1161:                    SID_TYPE;
        !          1162:                if (!(type == T_PROCESSOR || type == T_ENCLOSURE))
        !          1163:                        xs->error = XS_DRIVER_STUFFUP;
        !          1164:                else
        !          1165:                        rsc->sc_proctarget = target;
        !          1166:        }
        !          1167:
        !          1168:        ami_put_ccb(ccb);
        !          1169:        scsi_done(xs);
        !          1170: }
        !          1171:
        !          1172: void
        !          1173: ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb)
        !          1174: {
        !          1175:        struct scsi_xfer *xs = ccb->ccb_xs;
        !          1176:
        !          1177:        if (xs->data != NULL) {
        !          1178:                bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
        !          1179:                    ccb->ccb_dmamap->dm_mapsize,
        !          1180:                    (xs->flags & SCSI_DATA_IN) ?
        !          1181:                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        !          1182:
        !          1183:                bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
        !          1184:                    ccb->ccb_offset, sizeof(struct ami_ccbmem),
        !          1185:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1186:
        !          1187:                bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
        !          1188:        }
        !          1189:
        !          1190:        timeout_del(&xs->stimeout);
        !          1191:        xs->resid = 0;
        !          1192:        xs->flags |= ITSDONE;
        !          1193:
        !          1194:        if (ccb->ccb_flags & AMI_CCB_F_ERR)
        !          1195:                xs->error = XS_DRIVER_STUFFUP;
        !          1196:
        !          1197:        ami_put_ccb(ccb);
        !          1198:        scsi_done(xs);
        !          1199: }
        !          1200:
        !          1201: void
        !          1202: ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb)
        !          1203: {
        !          1204:        struct scsi_xfer *xs = ccb->ccb_xs;
        !          1205:        struct ami_iocmd *cmd = &ccb->ccb_cmd;
        !          1206:
        !          1207:        timeout_del(&xs->stimeout);
        !          1208:        if (ccb->ccb_flags & AMI_CCB_F_ERR) {
        !          1209:                xs->error = XS_DRIVER_STUFFUP;
        !          1210:                xs->resid = 0;
        !          1211:                xs->flags |= ITSDONE;
        !          1212:
        !          1213:                ami_put_ccb(ccb);
        !          1214:                scsi_done(xs);
        !          1215:                return;
        !          1216:        }
        !          1217:
        !          1218:        /* reuse the ccb for the sysflush command */
        !          1219:        ccb->ccb_done = ami_done_sysflush;
        !          1220:        cmd->acc_cmd = AMI_SYSFLUSH;
        !          1221:
        !          1222:        ami_start_xs(sc, ccb, xs);
        !          1223: }
        !          1224:
        !          1225: void
        !          1226: ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb)
        !          1227: {
        !          1228:        struct scsi_xfer *xs = ccb->ccb_xs;
        !          1229:
        !          1230:        timeout_del(&xs->stimeout);
        !          1231:        xs->resid = 0;
        !          1232:        xs->flags |= ITSDONE;
        !          1233:        if (ccb->ccb_flags & AMI_CCB_F_ERR)
        !          1234:                xs->error = XS_DRIVER_STUFFUP;
        !          1235:
        !          1236:        ami_put_ccb(ccb);
        !          1237:        scsi_done(xs);
        !          1238: }
        !          1239:
        !          1240: void
        !          1241: ami_done_ioctl(struct ami_softc *sc, struct ami_ccb *ccb)
        !          1242: {
        !          1243:        wakeup(ccb);
        !          1244: }
        !          1245:
        !          1246: void
        !          1247: ami_done_init(struct ami_softc *sc, struct ami_ccb *ccb)
        !          1248: {
        !          1249:        /* the ccb is going to be reused, so do nothing with it */
        !          1250: }
        !          1251:
        !          1252: void
        !          1253: amiminphys(struct buf *bp)
        !          1254: {
        !          1255:        if (bp->b_bcount > AMI_MAXFER)
        !          1256:                bp->b_bcount = AMI_MAXFER;
        !          1257:        minphys(bp);
        !          1258: }
        !          1259:
        !          1260: void
        !          1261: ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size)
        !          1262: {
        !          1263:        size_t copy_cnt;
        !          1264:
        !          1265:        AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data "));
        !          1266:
        !          1267:        if (!xs->datalen)
        !          1268:                printf("uio move not yet supported\n");
        !          1269:        else {
        !          1270:                copy_cnt = MIN(size, xs->datalen);
        !          1271:                bcopy(v, xs->data, copy_cnt);
        !          1272:        }
        !          1273: }
        !          1274:
        !          1275: int
        !          1276: ami_scsi_raw_cmd(struct scsi_xfer *xs)
        !          1277: {
        !          1278:        struct scsi_link *link = xs->sc_link;
        !          1279:        struct ami_rawsoftc *rsc = link->adapter_softc;
        !          1280:        struct ami_softc *sc = rsc->sc_softc;
        !          1281:        u_int8_t channel = rsc->sc_channel, target = link->target;
        !          1282:        struct device *dev = link->device_softc;
        !          1283:        struct ami_ccb *ccb;
        !          1284:        int s;
        !          1285:
        !          1286:        AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd "));
        !          1287:
        !          1288:        if (!cold && target == rsc->sc_proctarget)
        !          1289:                strlcpy(rsc->sc_procdev, dev->dv_xname,
        !          1290:                    sizeof(rsc->sc_procdev));
        !          1291:
        !          1292:        if (xs->cmdlen > AMI_MAX_CDB) {
        !          1293:                AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs));
        !          1294:                bzero(&xs->sense, sizeof(xs->sense));
        !          1295:                xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
        !          1296:                xs->sense.flags = SKEY_ILLEGAL_REQUEST;
        !          1297:                xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
        !          1298:                xs->error = XS_SENSE;
        !          1299:                s = splbio();
        !          1300:                scsi_done(xs);
        !          1301:                splx(s);
        !          1302:                return (COMPLETE);
        !          1303:        }
        !          1304:
        !          1305:        xs->error = XS_NOERROR;
        !          1306:
        !          1307:        s = splbio();
        !          1308:        ccb = ami_get_ccb(sc);
        !          1309:        splx(s);
        !          1310:        if (ccb == NULL) {
        !          1311:                xs->error = XS_DRIVER_STUFFUP;
        !          1312:                s = splbio();
        !          1313:                scsi_done(xs);
        !          1314:                splx(s);
        !          1315:                return (COMPLETE);
        !          1316:        }
        !          1317:
        !          1318:        memset(ccb->ccb_pt, 0, sizeof(struct ami_passthrough));
        !          1319:
        !          1320:        ccb->ccb_xs = xs;
        !          1321:        ccb->ccb_done = ami_done_pt;
        !          1322:
        !          1323:        ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU;
        !          1324:        ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa;
        !          1325:
        !          1326:        ccb->ccb_pt->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0);
        !          1327:        ccb->ccb_pt->apt_channel = channel;
        !          1328:        ccb->ccb_pt->apt_target = target;
        !          1329:        bcopy(xs->cmd, ccb->ccb_pt->apt_cdb, AMI_MAX_CDB);
        !          1330:        ccb->ccb_pt->apt_ncdb = xs->cmdlen;
        !          1331:        ccb->ccb_pt->apt_nsense = AMI_MAX_SENSE;
        !          1332:        ccb->ccb_pt->apt_datalen = xs->datalen;
        !          1333:        ccb->ccb_pt->apt_data = 0;
        !          1334:
        !          1335:        if (ami_load_ptmem(sc, ccb, xs->data, xs->datalen,
        !          1336:            xs->flags & SCSI_DATA_IN, xs->flags & SCSI_NOSLEEP) != 0) {
        !          1337:                xs->error = XS_DRIVER_STUFFUP;
        !          1338:                s = splbio();
        !          1339:                ami_put_ccb(ccb);
        !          1340:                scsi_done(xs);
        !          1341:                splx(s);
        !          1342:                return (COMPLETE);
        !          1343:        }
        !          1344:
        !          1345:        return (ami_start_xs(sc, ccb, xs));
        !          1346: }
        !          1347:
        !          1348: int
        !          1349: ami_load_ptmem(struct ami_softc *sc, struct ami_ccb *ccb, void *data,
        !          1350:     size_t len, int read, int nowait)
        !          1351: {
        !          1352:        bus_dmamap_t dmap = ccb->ccb_dmamap;
        !          1353:        bus_dma_segment_t *sgd;
        !          1354:        int error, i;
        !          1355:
        !          1356:        if (data != NULL) {
        !          1357:                error = bus_dmamap_load(sc->sc_dmat, dmap, data, len, NULL,
        !          1358:                    nowait ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1359:                if (error) {
        !          1360:                        if (error == EFBIG)
        !          1361:                                printf("more than %d dma segs\n",
        !          1362:                                    AMI_MAXOFFSETS);
        !          1363:                        else
        !          1364:                                printf("error %d loading dma map\n", error);
        !          1365:
        !          1366:                        return (1);
        !          1367:                }
        !          1368:
        !          1369:                sgd = dmap->dm_segs;
        !          1370:                if (dmap->dm_nsegs > 1) {
        !          1371:                        struct ami_sgent *sgl = ccb->ccb_sglist;
        !          1372:
        !          1373:                        ccb->ccb_pt->apt_nsge = dmap->dm_nsegs;
        !          1374:                        ccb->ccb_pt->apt_data = ccb->ccb_sglistpa;
        !          1375:
        !          1376:                        for (i = 0; i < dmap->dm_nsegs; i++) {
        !          1377:                                sgl[i].asg_addr = htole32(sgd[i].ds_addr);
        !          1378:                                sgl[i].asg_len = htole32(sgd[i].ds_len);
        !          1379:                        }
        !          1380:                } else {
        !          1381:                        ccb->ccb_pt->apt_nsge = 0;
        !          1382:                        ccb->ccb_pt->apt_data = htole32(sgd->ds_addr);
        !          1383:                }
        !          1384:
        !          1385:                bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
        !          1386:                    read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
        !          1387:        }
        !          1388:
        !          1389:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
        !          1390:            ccb->ccb_offset, sizeof(struct ami_ccbmem),
        !          1391:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !          1392:
        !          1393:        return (0);
        !          1394: }
        !          1395:
        !          1396: int
        !          1397: ami_scsi_cmd(struct scsi_xfer *xs)
        !          1398: {
        !          1399:        struct scsi_link *link = xs->sc_link;
        !          1400:        struct ami_softc *sc = link->adapter_softc;
        !          1401:        struct device *dev = link->device_softc;
        !          1402:        struct ami_ccb *ccb;
        !          1403:        struct ami_iocmd *cmd;
        !          1404:        struct scsi_inquiry_data inq;
        !          1405:        struct scsi_sense_data sd;
        !          1406:        struct scsi_read_cap_data rcd;
        !          1407:        u_int8_t target = link->target;
        !          1408:        u_int32_t blockno, blockcnt;
        !          1409:        struct scsi_rw *rw;
        !          1410:        struct scsi_rw_big *rwb;
        !          1411:        bus_dma_segment_t *sgd;
        !          1412:        int error;
        !          1413:        int s;
        !          1414:        int i;
        !          1415:
        !          1416:        AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd "));
        !          1417:
        !          1418:        if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present ||
        !          1419:            link->lun != 0) {
        !          1420:                AMI_DPRINTF(AMI_D_CMD, ("no target %d ", target));
        !          1421:                /* XXX should be XS_SENSE and sense filled out */
        !          1422:                xs->error = XS_DRIVER_STUFFUP;
        !          1423:                xs->flags |= ITSDONE;
        !          1424:                s = splbio();
        !          1425:                scsi_done(xs);
        !          1426:                splx(s);
        !          1427:                return (COMPLETE);
        !          1428:        }
        !          1429:
        !          1430:        error = 0;
        !          1431:        xs->error = XS_NOERROR;
        !          1432:
        !          1433:        switch (xs->cmd->opcode) {
        !          1434:        case READ_COMMAND:
        !          1435:        case READ_BIG:
        !          1436:        case WRITE_COMMAND:
        !          1437:        case WRITE_BIG:
        !          1438:                /* deal with io outside the switch */
        !          1439:                break;
        !          1440:
        !          1441:        case SYNCHRONIZE_CACHE:
        !          1442:                s = splbio();
        !          1443:                ccb = ami_get_ccb(sc);
        !          1444:                splx(s);
        !          1445:                if (ccb == NULL) {
        !          1446:                        xs->error = XS_DRIVER_STUFFUP;
        !          1447:                        s = splbio();
        !          1448:                        scsi_done(xs);
        !          1449:                        splx(s);
        !          1450:                        return (COMPLETE);
        !          1451:                }
        !          1452:
        !          1453:                ccb->ccb_xs = xs;
        !          1454:                ccb->ccb_done = ami_done_flush;
        !          1455:                if (xs->timeout < 30000)
        !          1456:                        xs->timeout = 30000;    /* at least 30sec */
        !          1457:
        !          1458:                cmd = &ccb->ccb_cmd;
        !          1459:                cmd->acc_cmd = AMI_FLUSH;
        !          1460:
        !          1461:                return (ami_start_xs(sc, ccb, xs));
        !          1462:
        !          1463:        case TEST_UNIT_READY:
        !          1464:                /* save off sd? after autoconf */
        !          1465:                if (!cold)      /* XXX bogus */
        !          1466:                        strlcpy(sc->sc_hdr[target].dev, dev->dv_xname,
        !          1467:                            sizeof(sc->sc_hdr[target].dev));
        !          1468:        case START_STOP:
        !          1469: #if 0
        !          1470:        case VERIFY:
        !          1471: #endif
        !          1472:        case PREVENT_ALLOW:
        !          1473:                AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode,
        !          1474:                    target));
        !          1475:                return (COMPLETE);
        !          1476:
        !          1477:        case REQUEST_SENSE:
        !          1478:                AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target));
        !          1479:                bzero(&sd, sizeof(sd));
        !          1480:                sd.error_code = 0x70;
        !          1481:                sd.segment = 0;
        !          1482:                sd.flags = SKEY_NO_SENSE;
        !          1483:                *(u_int32_t*)sd.info = htole32(0);
        !          1484:                sd.extra_len = 0;
        !          1485:                ami_copy_internal_data(xs, &sd, sizeof(sd));
        !          1486:                s = splbio();
        !          1487:                scsi_done(xs);
        !          1488:                splx(s);
        !          1489:                return (COMPLETE);
        !          1490:
        !          1491:        case INQUIRY:
        !          1492:                AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target));
        !          1493:                bzero(&inq, sizeof(inq));
        !          1494:                inq.device = T_DIRECT;
        !          1495:                inq.dev_qual2 = 0;
        !          1496:                inq.version = 2;
        !          1497:                inq.response_format = 2;
        !          1498:                inq.additional_length = 32;
        !          1499:                strlcpy(inq.vendor, "AMI    ", sizeof(inq.vendor));
        !          1500:                snprintf(inq.product, sizeof(inq.product),
        !          1501:                    "Host drive  #%02d", target);
        !          1502:                strlcpy(inq.revision, "   ", sizeof(inq.revision));
        !          1503:                ami_copy_internal_data(xs, &inq, sizeof(inq));
        !          1504:                s = splbio();
        !          1505:                scsi_done(xs);
        !          1506:                splx(s);
        !          1507:                return (COMPLETE);
        !          1508:
        !          1509:        case READ_CAPACITY:
        !          1510:                AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target));
        !          1511:                bzero(&rcd, sizeof(rcd));
        !          1512:                _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr);
        !          1513:                _lto4b(AMI_SECTOR_SIZE, rcd.length);
        !          1514:                ami_copy_internal_data(xs, &rcd, sizeof(rcd));
        !          1515:                s = splbio();
        !          1516:                scsi_done(xs);
        !          1517:                splx(s);
        !          1518:                return (COMPLETE);
        !          1519:
        !          1520:        default:
        !          1521:                AMI_DPRINTF(AMI_D_CMD, ("unsupported scsi command %#x tgt %d ",
        !          1522:                    xs->cmd->opcode, target));
        !          1523:                xs->error = XS_DRIVER_STUFFUP;
        !          1524:                s = splbio();
        !          1525:                scsi_done(xs);
        !          1526:                splx(s);
        !          1527:                return (COMPLETE);
        !          1528:        }
        !          1529:
        !          1530:        /* A read or write operation. */
        !          1531:        if (xs->cmdlen == 6) {
        !          1532:                rw = (struct scsi_rw *)xs->cmd;
        !          1533:                blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
        !          1534:                blockcnt = rw->length ? rw->length : 0x100;
        !          1535:        } else {
        !          1536:                rwb = (struct scsi_rw_big *)xs->cmd;
        !          1537:                blockno = _4btol(rwb->addr);
        !          1538:                blockcnt = _2btol(rwb->length);
        !          1539:        }
        !          1540:
        !          1541:        if (blockno >= sc->sc_hdr[target].hd_size ||
        !          1542:            blockno + blockcnt > sc->sc_hdr[target].hd_size) {
        !          1543:                printf("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc),
        !          1544:                    blockno, blockcnt, sc->sc_hdr[target].hd_size);
        !          1545:                xs->error = XS_DRIVER_STUFFUP;
        !          1546:                s = splbio();
        !          1547:                scsi_done(xs);
        !          1548:                splx(s);
        !          1549:                return (COMPLETE);
        !          1550:        }
        !          1551:
        !          1552:        s = splbio();
        !          1553:        ccb = ami_get_ccb(sc);
        !          1554:        splx(s);
        !          1555:        if (ccb == NULL) {
        !          1556:                xs->error = XS_DRIVER_STUFFUP;
        !          1557:                s = splbio();
        !          1558:                scsi_done(xs);
        !          1559:                splx(s);
        !          1560:                return (COMPLETE);
        !          1561:        }
        !          1562:
        !          1563:        ccb->ccb_xs = xs;
        !          1564:        ccb->ccb_done = ami_done_xs;
        !          1565:
        !          1566:        cmd = &ccb->ccb_cmd;
        !          1567:        cmd->acc_cmd = (xs->flags & SCSI_DATA_IN) ? AMI_READ : AMI_WRITE;
        !          1568:        cmd->acc_mbox.amb_nsect = htole16(blockcnt);
        !          1569:        cmd->acc_mbox.amb_lba = htole32(blockno);
        !          1570:        cmd->acc_mbox.amb_ldn = target;
        !          1571:
        !          1572:        error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap,
        !          1573:            xs->data, xs->datalen, NULL,
        !          1574:            (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
        !          1575:        if (error) {
        !          1576:                if (error == EFBIG)
        !          1577:                        printf("more than %d dma segs\n", AMI_MAXOFFSETS);
        !          1578:                else
        !          1579:                        printf("error %d loading dma map\n", error);
        !          1580:
        !          1581:                xs->error = XS_DRIVER_STUFFUP;
        !          1582:                s = splbio();
        !          1583:                ami_put_ccb(ccb);
        !          1584:                scsi_done(xs);
        !          1585:                splx(s);
        !          1586:                return (COMPLETE);
        !          1587:        }
        !          1588:
        !          1589:        sgd = ccb->ccb_dmamap->dm_segs;
        !          1590:        if (ccb->ccb_dmamap->dm_nsegs > 1) {
        !          1591:                struct ami_sgent *sgl = ccb->ccb_sglist;
        !          1592:
        !          1593:                cmd->acc_mbox.amb_nsge = ccb->ccb_dmamap->dm_nsegs;
        !          1594:                cmd->acc_mbox.amb_data = ccb->ccb_sglistpa;
        !          1595:
        !          1596:                for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) {
        !          1597:                        sgl[i].asg_addr = htole32(sgd[i].ds_addr);
        !          1598:                        sgl[i].asg_len = htole32(sgd[i].ds_len);
        !          1599:                }
        !          1600:        } else {
        !          1601:                cmd->acc_mbox.amb_nsge = 0;
        !          1602:                cmd->acc_mbox.amb_data = htole32(sgd->ds_addr);
        !          1603:        }
        !          1604:
        !          1605:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
        !          1606:            ccb->ccb_offset, sizeof(struct ami_ccbmem),
        !          1607:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !          1608:
        !          1609:        bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
        !          1610:            ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?
        !          1611:            BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
        !          1612:
        !          1613:        return (ami_start_xs(sc, ccb, xs));
        !          1614: }
        !          1615:
        !          1616: int
        !          1617: ami_intr(void *v)
        !          1618: {
        !          1619:        struct ami_softc *sc = v;
        !          1620:        struct ami_iocmd mbox;
        !          1621:        int i, rv = 0;
        !          1622:
        !          1623:        if (TAILQ_EMPTY(&sc->sc_ccb_runq))
        !          1624:                return (0);
        !          1625:
        !          1626:        AMI_DPRINTF(AMI_D_INTR, ("intr "));
        !          1627:
        !          1628:        while ((sc->sc_done)(sc, &mbox)) {
        !          1629:                AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat));
        !          1630:                for (i = 0; i < mbox.acc_nstat; i++ ) {
        !          1631:                        int ready = mbox.acc_cmplidl[i];
        !          1632:
        !          1633:                        AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready));
        !          1634:
        !          1635:                        if (!ami_done(sc, ready))
        !          1636:                                rv |= 1;
        !          1637:                }
        !          1638:        }
        !          1639:
        !          1640:        if (rv)
        !          1641:                ami_runqueue(sc);
        !          1642:
        !          1643:        AMI_DPRINTF(AMI_D_INTR, ("exit "));
        !          1644:        return (rv);
        !          1645: }
        !          1646:
        !          1647: int
        !          1648: ami_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag,
        !          1649:     struct proc *p)
        !          1650: {
        !          1651:        struct ami_softc *sc = (struct ami_softc *)link->adapter_softc;
        !          1652:        /* struct device *dev = (struct device *)link->device_softc; */
        !          1653:        /* u_int8_t target = link->target; */
        !          1654:
        !          1655:        if (sc->sc_ioctl)
        !          1656:                return (sc->sc_ioctl(link->adapter_softc, cmd, addr));
        !          1657:        else
        !          1658:                return (ENOTTY);
        !          1659: }
        !          1660:
        !          1661: #if NBIO > 0
        !          1662: int
        !          1663: ami_ioctl(struct device *dev, u_long cmd, caddr_t addr)
        !          1664: {
        !          1665:        struct ami_softc *sc = (struct ami_softc *)dev;
        !          1666:        int error = 0;
        !          1667:
        !          1668:        AMI_DPRINTF(AMI_D_IOCTL, ("%s: ioctl ", DEVNAME(sc)));
        !          1669:
        !          1670:        if (sc->sc_flags & AMI_BROKEN)
        !          1671:                return (ENODEV); /* can't do this to broken device for now */
        !          1672:
        !          1673:        switch (cmd) {
        !          1674:        case BIOCINQ:
        !          1675:                AMI_DPRINTF(AMI_D_IOCTL, ("inq "));
        !          1676:                error = ami_ioctl_inq(sc, (struct bioc_inq *)addr);
        !          1677:                break;
        !          1678:
        !          1679:        case BIOCVOL:
        !          1680:                AMI_DPRINTF(AMI_D_IOCTL, ("vol "));
        !          1681:                error = ami_ioctl_vol(sc, (struct bioc_vol *)addr);
        !          1682:                break;
        !          1683:
        !          1684:        case BIOCDISK:
        !          1685:                AMI_DPRINTF(AMI_D_IOCTL, ("disk "));
        !          1686:                error = ami_ioctl_disk(sc, (struct bioc_disk *)addr);
        !          1687:                break;
        !          1688:
        !          1689:        case BIOCALARM:
        !          1690:                AMI_DPRINTF(AMI_D_IOCTL, ("alarm "));
        !          1691:                error = ami_ioctl_alarm(sc, (struct bioc_alarm *)addr);
        !          1692:                break;
        !          1693:
        !          1694:        case BIOCSETSTATE:
        !          1695:                AMI_DPRINTF(AMI_D_IOCTL, ("setstate "));
        !          1696:                error = ami_ioctl_setstate(sc, (struct bioc_setstate *)addr);
        !          1697:                break;
        !          1698:
        !          1699:        default:
        !          1700:                AMI_DPRINTF(AMI_D_IOCTL, (" invalid ioctl\n"));
        !          1701:                error = EINVAL;
        !          1702:        }
        !          1703:
        !          1704:        return (error);
        !          1705: }
        !          1706:
        !          1707: int
        !          1708: ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
        !          1709:     void *inqbuf)
        !          1710: {
        !          1711:        struct ami_ccb *ccb;
        !          1712:        struct ami_passthrough *pt;
        !          1713:        struct scsi_inquiry_data *inq = inqbuf;
        !          1714:        int error = 0;
        !          1715:        int s;
        !          1716:
        !          1717:        rw_enter_write(&sc->sc_lock);
        !          1718:
        !          1719:        s = splbio();
        !          1720:        ccb = ami_get_ccb(sc);
        !          1721:        splx(s);
        !          1722:        if (ccb == NULL) {
        !          1723:                error = ENOMEM;
        !          1724:                goto err;
        !          1725:        }
        !          1726:
        !          1727:        ccb->ccb_done = ami_done_ioctl;
        !          1728:
        !          1729:        ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU;
        !          1730:        ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa;
        !          1731:
        !          1732:        pt = ccb->ccb_pt;
        !          1733:        memset(pt, 0, sizeof(struct ami_passthrough));
        !          1734:        pt->apt_channel = ch;
        !          1735:        pt->apt_target = tg;
        !          1736:        pt->apt_ncdb = sizeof(struct scsi_inquiry);
        !          1737:        pt->apt_nsense = sizeof(struct scsi_sense_data);
        !          1738:        pt->apt_datalen = sizeof(struct scsi_inquiry_data);
        !          1739:        pt->apt_data = 0;
        !          1740:
        !          1741:        pt->apt_cdb[0] = INQUIRY;
        !          1742:        pt->apt_cdb[1] = 0;
        !          1743:        pt->apt_cdb[2] = 0;
        !          1744:        pt->apt_cdb[3] = 0;
        !          1745:        pt->apt_cdb[4] = sizeof(struct scsi_inquiry_data); /* INQUIRY length */
        !          1746:        pt->apt_cdb[5] = 0;
        !          1747:
        !          1748:        if (page != 0) {
        !          1749:                pt->apt_cdb[1] = SI_EVPD;
        !          1750:                pt->apt_cdb[2] = page;
        !          1751:        }
        !          1752:
        !          1753:        if (ami_load_ptmem(sc, ccb, inqbuf, sizeof(struct scsi_inquiry_data),
        !          1754:            1, 0) != 0) {
        !          1755:                error = ENOMEM;
        !          1756:                goto ptmemerr;
        !          1757:        }
        !          1758:
        !          1759:        ami_start(sc, ccb);
        !          1760:
        !          1761:        while (ccb->ccb_state != AMI_CCB_READY)
        !          1762:                tsleep(ccb, PRIBIO, "ami_drv_inq", 0);
        !          1763:
        !          1764:        bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
        !          1765:            ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
        !          1766:        bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am),
        !          1767:            ccb->ccb_offset, sizeof(struct ami_ccbmem),
        !          1768:            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1769:        bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
        !          1770:
        !          1771:        if (ccb->ccb_flags & AMI_CCB_F_ERR)
        !          1772:                error = EIO;
        !          1773:        else if (pt->apt_scsistat != 0x00)
        !          1774:                error = EIO;
        !          1775:        else if ((inq->device & SID_TYPE) != T_DIRECT)
        !          1776:                error = EINVAL;
        !          1777:
        !          1778: ptmemerr:
        !          1779:        s = splbio();
        !          1780:        ami_put_ccb(ccb);
        !          1781:        splx(s);
        !          1782:
        !          1783: err:
        !          1784:        rw_exit_write(&sc->sc_lock);
        !          1785:        return (error);
        !          1786: }
        !          1787:
        !          1788: int
        !          1789: ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
        !          1790:     u_int8_t par3, size_t size, void *buffer)
        !          1791: {
        !          1792:        struct ami_ccb *ccb;
        !          1793:        struct ami_iocmd *cmd;
        !          1794:        struct ami_mem *am = NULL;
        !          1795:        char *idata = NULL;
        !          1796:        int error = 0;
        !          1797:        int s;
        !          1798:
        !          1799:        rw_enter_write(&sc->sc_lock);
        !          1800:
        !          1801:        s = splbio();
        !          1802:        ccb = ami_get_ccb(sc);
        !          1803:        splx(s);
        !          1804:        if (ccb == NULL) {
        !          1805:                error = ENOMEM;
        !          1806:                goto err;
        !          1807:        }
        !          1808:
        !          1809:        if (size) {
        !          1810:                if ((am = ami_allocmem(sc, size)) == NULL) {
        !          1811:                        error = ENOMEM;
        !          1812:                        goto memerr;
        !          1813:                }
        !          1814:                idata = AMIMEM_KVA(am);
        !          1815:        }
        !          1816:
        !          1817:        ccb->ccb_done = ami_done_ioctl;
        !          1818:        cmd = &ccb->ccb_cmd;
        !          1819:
        !          1820:        cmd->acc_cmd = opcode;
        !          1821:
        !          1822:        /*
        !          1823:         * some commands require data to be written to idata before sending
        !          1824:         * command to fw
        !          1825:         */
        !          1826:        switch (opcode) {
        !          1827:        case AMI_SPEAKER:
        !          1828:                *idata = par1;
        !          1829:                break;
        !          1830:        default:
        !          1831:                cmd->acc_io.aio_channel = par1;
        !          1832:                cmd->acc_io.aio_param = par2;
        !          1833:                cmd->acc_io.aio_pad[0] = par3;
        !          1834:                break;
        !          1835:        };
        !          1836:
        !          1837:        cmd->acc_io.aio_data = am ? htole32(AMIMEM_DVA(am)) : 0;
        !          1838:
        !          1839:        ami_start(sc, ccb);
        !          1840:        while (ccb->ccb_state != AMI_CCB_READY)
        !          1841:                tsleep(ccb, PRIBIO,"ami_mgmt", 0);
        !          1842:
        !          1843:        if (ccb->ccb_flags & AMI_CCB_F_ERR)
        !          1844:                error = EIO;
        !          1845:        else if (buffer && size)
        !          1846:                memcpy(buffer, idata, size);
        !          1847:
        !          1848:        if (am)
        !          1849:                ami_freemem(sc, am);
        !          1850:
        !          1851: memerr:
        !          1852:        s = splbio();
        !          1853:        ami_put_ccb(ccb);
        !          1854:        splx(s);
        !          1855:
        !          1856: err:
        !          1857:        rw_exit_write(&sc->sc_lock);
        !          1858:        return (error);
        !          1859: }
        !          1860:
        !          1861: int
        !          1862: ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi)
        !          1863: {
        !          1864:        struct ami_big_diskarray *p; /* struct too large for stack */
        !          1865:        char *plist;
        !          1866:        int i, s, t;
        !          1867:        int off;
        !          1868:        int error = 0;
        !          1869:        struct scsi_inquiry_data inqbuf;
        !          1870:        u_int8_t ch, tg;
        !          1871:
        !          1872:        p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
        !          1873:        if (!p)
        !          1874:                return (ENOMEM);
        !          1875:
        !          1876:        plist = malloc(AMI_BIG_MAX_PDRIVES, M_DEVBUF, M_NOWAIT);
        !          1877:        if (!plist) {
        !          1878:                error = ENOMEM;
        !          1879:                goto bail;
        !          1880:        }
        !          1881:
        !          1882:        if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p,
        !          1883:            p)))
        !          1884:                goto bail2;
        !          1885:
        !          1886:        memset(plist, 0, AMI_BIG_MAX_PDRIVES);
        !          1887:
        !          1888:        bi->bi_novol = p->ada_nld;
        !          1889:        bi->bi_nodisk = 0;
        !          1890:
        !          1891:        strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
        !          1892:
        !          1893:        /* do we actually care how many disks we have at this point? */
        !          1894:        for (i = 0; i < p->ada_nld; i++)
        !          1895:                for (s = 0; s < p->ald[i].adl_spandepth; s++)
        !          1896:                        for (t = 0; t < p->ald[i].adl_nstripes; t++) {
        !          1897:                                off = p->ald[i].asp[s].adv[t].add_channel *
        !          1898:                                    AMI_MAX_TARGET +
        !          1899:                                    p->ald[i].asp[s].adv[t].add_target;
        !          1900:
        !          1901:                                if (!plist[off]) {
        !          1902:                                        plist[off] = 1;
        !          1903:                                        bi->bi_nodisk++;
        !          1904:                                }
        !          1905:                        }
        !          1906:
        !          1907:        /*
        !          1908:         * hack warning!
        !          1909:         * Megaraid cards sometimes return a size in the PD structure
        !          1910:         * even though there is no disk in that slot.  Work around
        !          1911:         * that by issuing an INQUIRY to determine if there is
        !          1912:         * an actual disk in the slot.
        !          1913:         */
        !          1914:        for(i = 0; i < ((sc->sc_flags & AMI_QUARTZ) ?
        !          1915:            AMI_BIG_MAX_PDRIVES : AMI_MAX_PDRIVES); i++) {
        !          1916:                /* skip claimed drives */
        !          1917:                if (plist[i])
        !          1918:                        continue;
        !          1919:
        !          1920:                /*
        !          1921:                 * poke drive to make sure its there.  If it is it is either
        !          1922:                 * unused or a hot spare; at this point we dont care which it is
        !          1923:                 */
        !          1924:                if (p->apd[i].adp_size) {
        !          1925:                        ch = (i & 0xf0) >> 4;
        !          1926:                        tg = i & 0x0f;
        !          1927:
        !          1928:                        if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
        !          1929:                                bi->bi_novol++;
        !          1930:                                bi->bi_nodisk++;
        !          1931:                                plist[i] = 1;
        !          1932:                        }
        !          1933:                }
        !          1934:        }
        !          1935:
        !          1936: bail2:
        !          1937:        free(plist, M_DEVBUF);
        !          1938: bail:
        !          1939:        free(p, M_DEVBUF);
        !          1940:
        !          1941:        return (error);
        !          1942: }
        !          1943:
        !          1944: int
        !          1945: ami_vol(struct ami_softc *sc, struct bioc_vol *bv, struct ami_big_diskarray *p)
        !          1946: {
        !          1947:        struct scsi_inquiry_data inqbuf;
        !          1948:        char *plist;
        !          1949:        int i, s, t, off;
        !          1950:        int ld = p->ada_nld, error = EINVAL;
        !          1951:        u_int8_t ch, tg;
        !          1952:
        !          1953:        plist = malloc(AMI_BIG_MAX_PDRIVES, M_DEVBUF, M_NOWAIT);
        !          1954:        if (!plist)
        !          1955:                return (ENOMEM);
        !          1956:
        !          1957:        memset(plist, 0, AMI_BIG_MAX_PDRIVES);
        !          1958:
        !          1959:        /* setup plist */
        !          1960:        for (i = 0; i < p->ada_nld; i++)
        !          1961:                for (s = 0; s < p->ald[i].adl_spandepth; s++)
        !          1962:                        for (t = 0; t < p->ald[i].adl_nstripes; t++) {
        !          1963:                                off = p->ald[i].asp[s].adv[t].add_channel *
        !          1964:                                    AMI_MAX_TARGET +
        !          1965:                                    p->ald[i].asp[s].adv[t].add_target;
        !          1966:
        !          1967:                                if (!plist[off])
        !          1968:                                        plist[off] = 1;
        !          1969:                        }
        !          1970:
        !          1971:        for(i = 0; i < ((sc->sc_flags & AMI_QUARTZ) ?
        !          1972:            AMI_BIG_MAX_PDRIVES : AMI_MAX_PDRIVES); i++) {
        !          1973:                /* skip claimed drives */
        !          1974:                if (plist[i])
        !          1975:                        continue;
        !          1976:
        !          1977:                /*
        !          1978:                 * poke drive to make sure its there.  If it is it is either
        !          1979:                 * unused or a hot spare; at this point we dont care which it is
        !          1980:                 */
        !          1981:                if (p->apd[i].adp_size) {
        !          1982:                        ch = (i & 0xf0) >> 4;
        !          1983:                        tg = i & 0x0f;
        !          1984:
        !          1985:                        if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
        !          1986:                                if (ld != bv->bv_volid) {
        !          1987:                                        ld++;
        !          1988:                                        continue;
        !          1989:                                }
        !          1990:
        !          1991:                                bv->bv_status = BIOC_SVONLINE;
        !          1992:                                bv->bv_size = (u_quad_t)p->apd[i].adp_size *
        !          1993:                                    (u_quad_t)512;
        !          1994:                                bv->bv_nodisk = 1;
        !          1995:                                strlcpy(bv->bv_dev,
        !          1996:                                    sc->sc_hdr[bv->bv_volid].dev,
        !          1997:                                    sizeof(bv->bv_dev));
        !          1998:
        !          1999:                                if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE
        !          2000:                                    && p->apd[i].adp_type == 0)
        !          2001:                                        bv->bv_level = -1;
        !          2002:                                else
        !          2003:                                        bv->bv_level = -2;
        !          2004:
        !          2005:                                error = 0;
        !          2006:                                goto bail;
        !          2007:                        }
        !          2008:                }
        !          2009:        }
        !          2010:
        !          2011: bail:
        !          2012:        free(plist, M_DEVBUF);
        !          2013:
        !          2014:        return (error);
        !          2015: }
        !          2016:
        !          2017: int
        !          2018: ami_disk(struct ami_softc *sc, struct bioc_disk *bd,
        !          2019:     struct ami_big_diskarray *p)
        !          2020: {
        !          2021:        struct scsi_inquiry_data inqbuf;
        !          2022:        struct scsi_inquiry_vpd vpdbuf;
        !          2023:        char *plist;
        !          2024:        int i, s, t, off;
        !          2025:        int ld = p->ada_nld, error = EINVAL;
        !          2026:        u_int8_t ch, tg;
        !          2027:
        !          2028:        plist = malloc(AMI_BIG_MAX_PDRIVES, M_DEVBUF, M_NOWAIT);
        !          2029:        if (!plist)
        !          2030:                return (ENOMEM);
        !          2031:
        !          2032:        memset(plist, 0, AMI_BIG_MAX_PDRIVES);
        !          2033:
        !          2034:        /* setup plist */
        !          2035:        for (i = 0; i < p->ada_nld; i++)
        !          2036:                for (s = 0; s < p->ald[i].adl_spandepth; s++)
        !          2037:                        for (t = 0; t < p->ald[i].adl_nstripes; t++) {
        !          2038:                                off = p->ald[i].asp[s].adv[t].add_channel *
        !          2039:                                    AMI_MAX_TARGET +
        !          2040:                                    p->ald[i].asp[s].adv[t].add_target;
        !          2041:
        !          2042:                                if (!plist[off])
        !          2043:                                        plist[off] = 1;
        !          2044:                        }
        !          2045:
        !          2046:        for(i = 0; i < ((sc->sc_flags & AMI_QUARTZ) ?
        !          2047:            AMI_BIG_MAX_PDRIVES : AMI_MAX_PDRIVES); i++) {
        !          2048:                char vend[8+16+4+1];
        !          2049:
        !          2050:                /* skip claimed drives */
        !          2051:                if (plist[i])
        !          2052:                        continue;
        !          2053:
        !          2054:                /* no size no disk, most of the times */
        !          2055:                if (!p->apd[i].adp_size)
        !          2056:                        continue;
        !          2057:
        !          2058:                ch = (i & 0xf0) >> 4;
        !          2059:                tg = i & 0x0f;
        !          2060:
        !          2061:                /*
        !          2062:                 * poke drive to make sure its there.  If it is it is either
        !          2063:                 * unused or a hot spare; at this point we dont care which it is
        !          2064:                 */
        !          2065:                if (ami_drv_inq(sc, ch, tg, 0, &inqbuf))
        !          2066:                        continue;
        !          2067:
        !          2068:                if (ld != bd->bd_volid) {
        !          2069:                        ld++;
        !          2070:                        continue;
        !          2071:                }
        !          2072:
        !          2073:                bcopy(inqbuf.vendor, vend, sizeof vend - 1);
        !          2074:
        !          2075:                vend[sizeof vend - 1] = '\0';
        !          2076:                strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
        !          2077:
        !          2078:                if (!ami_drv_inq(sc, ch, tg, 0x80, &vpdbuf)) {
        !          2079:                        char ser[32 + 1];
        !          2080:
        !          2081:                        bcopy(vpdbuf.serial, ser, sizeof ser - 1);
        !          2082:
        !          2083:                        ser[sizeof ser - 1] = '\0';
        !          2084:                        if (vpdbuf.page_length < sizeof ser)
        !          2085:                                ser[vpdbuf.page_length] = '\0';
        !          2086:
        !          2087:                        strlcpy(bd->bd_serial, ser, sizeof(bd->bd_serial));
        !          2088:                }
        !          2089:
        !          2090:                bd->bd_size = (u_quad_t)p->apd[i].adp_size * (u_quad_t)512;
        !          2091:
        !          2092:                bd->bd_channel = ch;
        !          2093:                bd->bd_target = tg;
        !          2094:
        !          2095:                strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev,
        !          2096:                    sizeof(bd->bd_procdev));
        !          2097:
        !          2098:                if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE)
        !          2099:                        bd->bd_status = BIOC_SDHOTSPARE;
        !          2100:                else
        !          2101:                        bd->bd_status = BIOC_SDUNUSED;
        !          2102:
        !          2103: #ifdef AMI_DEBUG
        !          2104:                if (p->apd[i].adp_type != 0)
        !          2105:                        printf("invalid disk type: %d %d %x inquiry type: %x\n",
        !          2106:                            ch, tg, p->apd[i].adp_type, inqbuf.device);
        !          2107: #endif /* AMI_DEBUG */
        !          2108:
        !          2109:                error = 0;
        !          2110:                goto bail;
        !          2111:        }
        !          2112:
        !          2113: bail:
        !          2114:        free(plist, M_DEVBUF);
        !          2115:
        !          2116:        return (error);
        !          2117: }
        !          2118:
        !          2119: int
        !          2120: ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv)
        !          2121: {
        !          2122:        struct ami_big_diskarray *p; /* struct too large for stack */
        !          2123:        int i, s, t, off;
        !          2124:        int error = 0;
        !          2125:        struct ami_progress perc;
        !          2126:        u_int8_t bgi[5]; /* 40 LD, 1 bit per LD if BGI is active */
        !          2127:
        !          2128:        p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
        !          2129:        if (!p)
        !          2130:                return (ENOMEM);
        !          2131:
        !          2132:        if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p)))
        !          2133:                goto bail;
        !          2134:
        !          2135:        if (bv->bv_volid >= p->ada_nld) {
        !          2136:                error = ami_vol(sc, bv, p);
        !          2137:                goto bail;
        !          2138:        }
        !          2139:
        !          2140:        i = bv->bv_volid;
        !          2141:
        !          2142:        switch (p->ald[i].adl_status) {
        !          2143:        case AMI_RDRV_OFFLINE:
        !          2144:                bv->bv_status = BIOC_SVOFFLINE;
        !          2145:                break;
        !          2146:
        !          2147:        case AMI_RDRV_DEGRADED:
        !          2148:                bv->bv_status = BIOC_SVDEGRADED;
        !          2149:                break;
        !          2150:
        !          2151:        case AMI_RDRV_OPTIMAL:
        !          2152:                bv->bv_status = BIOC_SVONLINE;
        !          2153:                bv->bv_percent = -1;
        !          2154:
        !          2155:                /* get BGI progress here and over-ride status if so */
        !          2156:                memset(bgi, 0, sizeof bgi);
        !          2157:                if (ami_mgmt(sc, AMI_MISC, AMI_GET_BGI, 0, 0, sizeof bgi, &bgi))
        !          2158:                        break;
        !          2159:
        !          2160:                if ((bgi[i / 8] & (1 << i % 8)) == 0)
        !          2161:                        break;
        !          2162:
        !          2163:                if (!ami_mgmt(sc, AMI_GCHECKPROGR, i, 0, 0, sizeof perc, &perc))
        !          2164:                        if (perc.apr_progress < 100) {
        !          2165:                                bv->bv_status = BIOC_SVSCRUB;
        !          2166:                                bv->bv_percent = perc.apr_progress >= 100 ? -1 :
        !          2167:                                    perc.apr_progress;
        !          2168:                        }
        !          2169:                break;
        !          2170:
        !          2171:        default:
        !          2172:                bv->bv_status = BIOC_SVINVALID;
        !          2173:        }
        !          2174:
        !          2175:        /* over-ride status if a pd is in rebuild status for this ld */
        !          2176:        for (s = 0; s < p->ald[i].adl_spandepth; s++)
        !          2177:                for (t = 0; t < p->ald[i].adl_nstripes; t++) {
        !          2178:                        off = p->ald[i].asp[s].adv[t].add_channel *
        !          2179:                            AMI_MAX_TARGET +
        !          2180:                            p->ald[i].asp[s].adv[t].add_target;
        !          2181:
        !          2182:                        if (p->apd[off].adp_ostatus != AMI_PD_RBLD)
        !          2183:                                continue;
        !          2184:
        !          2185:                        /* get rebuild progress here */
        !          2186:                        bv->bv_status = BIOC_SVREBUILD;
        !          2187:                        if (ami_mgmt(sc, AMI_GRBLDPROGR,
        !          2188:                            p->ald[i].asp[s].adv[t].add_channel,
        !          2189:                            p->ald[i].asp[s].adv[t].add_target, 0,
        !          2190:                            sizeof perc, &perc))
        !          2191:                                bv->bv_percent = -1;
        !          2192:                        else
        !          2193:                                bv->bv_percent = perc.apr_progress >= 100 ? -1 :
        !          2194:                                    perc.apr_progress;
        !          2195:
        !          2196:                        /* XXX fix this, we should either use lowest percentage
        !          2197:                         * of all disks in rebuild state or an average
        !          2198:                         */
        !          2199:                        break;
        !          2200:                }
        !          2201:
        !          2202:        bv->bv_size = 0;
        !          2203:        bv->bv_level = p->ald[i].adl_raidlvl;
        !          2204:        bv->bv_nodisk = 0;
        !          2205:
        !          2206:        for (s = 0; s < p->ald[i].adl_spandepth; s++) {
        !          2207:                for (t = 0; t < p->ald[i].adl_nstripes; t++)
        !          2208:                        bv->bv_nodisk++;
        !          2209:
        !          2210:                switch (bv->bv_level) {
        !          2211:                case 0:
        !          2212:                        bv->bv_size += p->ald[i].asp[s].ads_length *
        !          2213:                            p->ald[i].adl_nstripes;
        !          2214:                        break;
        !          2215:
        !          2216:                case 1:
        !          2217:                        bv->bv_size += p->ald[i].asp[s].ads_length;
        !          2218:                        break;
        !          2219:
        !          2220:                case 5:
        !          2221:                        bv->bv_size += p->ald[i].asp[s].ads_length *
        !          2222:                            (p->ald[i].adl_nstripes - 1);
        !          2223:                        break;
        !          2224:                }
        !          2225:        }
        !          2226:
        !          2227:        if (p->ald[i].adl_spandepth > 1)
        !          2228:                bv->bv_level *= 10;
        !          2229:
        !          2230:        bv->bv_size *= (u_quad_t)512;
        !          2231:
        !          2232:        strlcpy(bv->bv_dev, sc->sc_hdr[i].dev, sizeof(bv->bv_dev));
        !          2233:
        !          2234: bail:
        !          2235:        free(p, M_DEVBUF);
        !          2236:
        !          2237:        return (error);
        !          2238: }
        !          2239:
        !          2240: int
        !          2241: ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
        !          2242: {
        !          2243:        struct scsi_inquiry_data inqbuf;
        !          2244:        struct scsi_inquiry_vpd vpdbuf;
        !          2245:        struct ami_big_diskarray *p; /* struct too large for stack */
        !          2246:        int i, s, t, d;
        !          2247:        int off;
        !          2248:        int error = 0;
        !          2249:        u_int16_t ch, tg;
        !          2250:
        !          2251:        p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
        !          2252:        if (!p)
        !          2253:                return (ENOMEM);
        !          2254:
        !          2255:        if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p)))
        !          2256:                goto bail;
        !          2257:
        !          2258:        if (bd->bd_volid >= p->ada_nld) {
        !          2259:                error = ami_disk(sc, bd, p);
        !          2260:                goto bail;
        !          2261:        }
        !          2262:
        !          2263:        i = bd->bd_volid;
        !          2264:        error = EINVAL;
        !          2265:
        !          2266:        for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++)
        !          2267:                for (t = 0; t < p->ald[i].adl_nstripes; t++) {
        !          2268:                        if (d != bd->bd_diskid) {
        !          2269:                                d++;
        !          2270:                                continue;
        !          2271:                        }
        !          2272:
        !          2273:                        off = p->ald[i].asp[s].adv[t].add_channel *
        !          2274:                            AMI_MAX_TARGET +
        !          2275:                            p->ald[i].asp[s].adv[t].add_target;
        !          2276:
        !          2277:                        switch (p->apd[off].adp_ostatus) {
        !          2278:                        case AMI_PD_UNCNF:
        !          2279:                                bd->bd_status = BIOC_SDUNUSED;
        !          2280:                                break;
        !          2281:
        !          2282:                        case AMI_PD_ONLINE:
        !          2283:                                bd->bd_status = BIOC_SDONLINE;
        !          2284:                                break;
        !          2285:
        !          2286:                        case AMI_PD_FAILED:
        !          2287:                                bd->bd_status = BIOC_SDFAILED;
        !          2288:                                break;
        !          2289:
        !          2290:                        case AMI_PD_RBLD:
        !          2291:                                bd->bd_status = BIOC_SDREBUILD;
        !          2292:                                break;
        !          2293:
        !          2294:                        case AMI_PD_HOTSPARE:
        !          2295:                                bd->bd_status = BIOC_SDHOTSPARE;
        !          2296:                                break;
        !          2297:
        !          2298:                        default:
        !          2299:                                bd->bd_status = BIOC_SDINVALID;
        !          2300:                        }
        !          2301:
        !          2302:                        bd->bd_size = (u_quad_t)p->apd[off].adp_size *
        !          2303:                            (u_quad_t)512;
        !          2304:
        !          2305:                        ch = p->ald[i].asp[s].adv[t].add_target >> 4;
        !          2306:                        tg = p->ald[i].asp[s].adv[t].add_target & 0x0f;
        !          2307:
        !          2308:                        if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
        !          2309:                                char vend[8+16+4+1];
        !          2310:
        !          2311:                                bcopy(inqbuf.vendor, vend, sizeof vend - 1);
        !          2312:
        !          2313:                                vend[sizeof vend - 1] = '\0';
        !          2314:                                strlcpy(bd->bd_vendor, vend,
        !          2315:                                    sizeof(bd->bd_vendor));
        !          2316:                        }
        !          2317:
        !          2318:                        if (!ami_drv_inq(sc, ch, tg, 0x80, &vpdbuf)) {
        !          2319:                                char ser[32 + 1];
        !          2320:
        !          2321:                                bcopy(vpdbuf.serial, ser, sizeof ser - 1);
        !          2322:
        !          2323:                                ser[sizeof ser - 1] = '\0';
        !          2324:                                if (vpdbuf.page_length < sizeof ser)
        !          2325:                                        ser[vpdbuf.page_length] = '\0';
        !          2326:                                strlcpy(bd->bd_serial, ser,
        !          2327:                                    sizeof(bd->bd_serial));
        !          2328:                        }
        !          2329:
        !          2330:                        bd->bd_channel = ch;
        !          2331:                        bd->bd_target = tg;
        !          2332:
        !          2333:                        strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev,
        !          2334:                            sizeof(bd->bd_procdev));
        !          2335:
        !          2336:                        error = 0;
        !          2337:                        goto bail;
        !          2338:                }
        !          2339:
        !          2340:        /* XXX if we reach this do dedicated hotspare magic*/
        !          2341: bail:
        !          2342:        free(p, M_DEVBUF);
        !          2343:
        !          2344:        return (error);
        !          2345: }
        !          2346:
        !          2347: int ami_ioctl_alarm(struct ami_softc *sc, struct bioc_alarm *ba)
        !          2348: {
        !          2349:        int error = 0;
        !          2350:        u_int8_t func, ret;
        !          2351:
        !          2352:        switch(ba->ba_opcode) {
        !          2353:        case BIOC_SADISABLE:
        !          2354:                func = AMI_SPKR_OFF;
        !          2355:                break;
        !          2356:
        !          2357:        case BIOC_SAENABLE:
        !          2358:                func = AMI_SPKR_ON;
        !          2359:                break;
        !          2360:
        !          2361:        case BIOC_SASILENCE:
        !          2362:                func = AMI_SPKR_SHUT;
        !          2363:                break;
        !          2364:
        !          2365:        case BIOC_GASTATUS:
        !          2366:                func = AMI_SPKR_GVAL;
        !          2367:                break;
        !          2368:
        !          2369:        case BIOC_SATEST:
        !          2370:                func = AMI_SPKR_TEST;
        !          2371:                break;
        !          2372:
        !          2373:        default:
        !          2374:                AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocalarm invalid opcode %x\n",
        !          2375:                    DEVNAME(sc), ba->ba_opcode));
        !          2376:                return (EINVAL);
        !          2377:        }
        !          2378:
        !          2379:        if (!(error = ami_mgmt(sc, AMI_SPEAKER, func, 0, 0, sizeof ret,
        !          2380:            &ret))) {
        !          2381:                if (ba->ba_opcode == BIOC_GASTATUS)
        !          2382:                        ba->ba_status = ret;
        !          2383:                else
        !          2384:                        ba->ba_status = 0;
        !          2385:        }
        !          2386:
        !          2387:        return (error);
        !          2388: }
        !          2389:
        !          2390: int
        !          2391: ami_ioctl_setstate(struct ami_softc *sc, struct bioc_setstate *bs)
        !          2392: {
        !          2393:        struct scsi_inquiry_data inqbuf;
        !          2394:        int func, off, error;
        !          2395:
        !          2396:        switch (bs->bs_status) {
        !          2397:        case BIOC_SSONLINE:
        !          2398:                func = AMI_STATE_ON;
        !          2399:                break;
        !          2400:
        !          2401:        case BIOC_SSOFFLINE:
        !          2402:                func = AMI_STATE_FAIL;
        !          2403:                break;
        !          2404:
        !          2405:        case BIOC_SSHOTSPARE:
        !          2406:                off = bs->bs_channel * AMI_MAX_TARGET + bs->bs_target;
        !          2407:
        !          2408:                if (ami_drv_inq(sc, bs->bs_channel, bs->bs_target, 0,
        !          2409:                    &inqbuf))
        !          2410:                        return (EINVAL);
        !          2411:
        !          2412:                func = AMI_STATE_SPARE;
        !          2413:                break;
        !          2414:
        !          2415:        default:
        !          2416:                AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocsetstate invalid opcode %x\n"
        !          2417:                    , DEVNAME(sc), bs->bs_status));
        !          2418:                return (EINVAL);
        !          2419:        }
        !          2420:
        !          2421:        if ((error = ami_mgmt(sc, AMI_CHSTATE, bs->bs_channel, bs->bs_target,
        !          2422:            func, 0, NULL)))
        !          2423:                return (error);
        !          2424:
        !          2425:        return (0);
        !          2426: }
        !          2427:
        !          2428: #ifndef SMALL_KERNEL
        !          2429: int
        !          2430: ami_create_sensors(struct ami_softc *sc)
        !          2431: {
        !          2432:        struct device *dev;
        !          2433:        struct scsibus_softc *ssc;
        !          2434:        int i;
        !          2435:
        !          2436:        TAILQ_FOREACH(dev, &alldevs, dv_list) {
        !          2437:                if (dev->dv_parent != &sc->sc_dev)
        !          2438:                        continue;
        !          2439:
        !          2440:                /* check if this is the scsibus for the logical disks */
        !          2441:                ssc = (struct scsibus_softc *)dev;
        !          2442:                if (ssc->adapter_link == &sc->sc_link)
        !          2443:                        break;
        !          2444:        }
        !          2445:
        !          2446:        if (ssc == NULL)
        !          2447:                return (1);
        !          2448:
        !          2449:        sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nunits,
        !          2450:            M_DEVBUF, M_WAITOK);
        !          2451:        if (sc->sc_sensors == NULL)
        !          2452:                return (1);
        !          2453:        bzero(sc->sc_sensors, sizeof(struct ksensor) * sc->sc_nunits);
        !          2454:
        !          2455:        strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
        !          2456:            sizeof(sc->sc_sensordev.xname));
        !          2457:
        !          2458:        for (i = 0; i < sc->sc_nunits; i++) {
        !          2459:                if (ssc->sc_link[i][0] == NULL)
        !          2460:                        goto bad;
        !          2461:
        !          2462:                dev = ssc->sc_link[i][0]->device_softc;
        !          2463:
        !          2464:                sc->sc_sensors[i].type = SENSOR_DRIVE;
        !          2465:                sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
        !          2466:
        !          2467:                strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
        !          2468:                    sizeof(sc->sc_sensors[i].desc));
        !          2469:
        !          2470:                sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
        !          2471:        }
        !          2472:
        !          2473:        sc->sc_bd = malloc(sizeof(*sc->sc_bd), M_DEVBUF, M_WAITOK);
        !          2474:        if (sc->sc_bd == NULL)
        !          2475:                goto bad;
        !          2476:
        !          2477:        if (sensor_task_register(sc, ami_refresh_sensors, 10) == NULL)
        !          2478:                goto freebd;
        !          2479:
        !          2480:        sensordev_install(&sc->sc_sensordev);
        !          2481:
        !          2482:        return (0);
        !          2483:
        !          2484: freebd:
        !          2485:        free(sc->sc_bd, M_DEVBUF);
        !          2486: bad:
        !          2487:        free(sc->sc_sensors, M_DEVBUF);
        !          2488:
        !          2489:        return (1);
        !          2490: }
        !          2491:
        !          2492: void
        !          2493: ami_refresh_sensors(void *arg)
        !          2494: {
        !          2495:        struct ami_softc *sc = arg;
        !          2496:        int i;
        !          2497:
        !          2498:        if (ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof(*sc->sc_bd),
        !          2499:            sc->sc_bd)) {
        !          2500:                for (i = 0; i < sc->sc_nunits; i++) {
        !          2501:                        sc->sc_sensors[i].value = 0; /* unknown */
        !          2502:                        sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
        !          2503:                }
        !          2504:                return;
        !          2505:        }
        !          2506:
        !          2507:        for (i = 0; i < sc->sc_nunits; i++) {
        !          2508:                switch (sc->sc_bd->ald[i].adl_status) {
        !          2509:                case AMI_RDRV_OFFLINE:
        !          2510:                        sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
        !          2511:                        sc->sc_sensors[i].status = SENSOR_S_CRIT;
        !          2512:                        break;
        !          2513:
        !          2514:                case AMI_RDRV_DEGRADED:
        !          2515:                        sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
        !          2516:                        sc->sc_sensors[i].status = SENSOR_S_WARN;
        !          2517:                        break;
        !          2518:
        !          2519:                case AMI_RDRV_OPTIMAL:
        !          2520:                        sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
        !          2521:                        sc->sc_sensors[i].status = SENSOR_S_OK;
        !          2522:                        break;
        !          2523:
        !          2524:                default:
        !          2525:                        sc->sc_sensors[i].value = 0; /* unknown */
        !          2526:                        sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
        !          2527:                }
        !          2528:        }
        !          2529: }
        !          2530: #endif /* SMALL_KERNEL */
        !          2531: #endif /* NBIO > 0 */
        !          2532:
        !          2533: #ifdef AMI_DEBUG
        !          2534: void
        !          2535: ami_print_mbox(struct ami_iocmd *mbox)
        !          2536: {
        !          2537:        int i;
        !          2538:
        !          2539:        printf("acc_cmd: %d  aac_id: %d  acc_busy: %d  acc_nstat: %d  ",
        !          2540:            mbox->acc_cmd, mbox->acc_id, mbox->acc_busy, mbox->acc_nstat);
        !          2541:        printf("acc_status: %d  acc_poll: %d  acc_ack: %d\n",
        !          2542:            mbox->acc_status, mbox->acc_poll, mbox->acc_ack);
        !          2543:
        !          2544:        printf("acc_cmplidl: ");
        !          2545:        for (i = 0; i < AMI_MAXSTATACK; i++) {
        !          2546:                printf("[%d] = %d  ", i, mbox->acc_cmplidl[i]);
        !          2547:        }
        !          2548:
        !          2549:        printf("\n");
        !          2550: }
        !          2551: #endif /* AMI_DEBUG */

CVSweb