The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/ami.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 00d019a15bd437dac5e44fb27494cf24


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.