LCOV - code coverage report
Current view: top level - dev/ic - ami.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1224 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 51 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13