root/dev/ic/ami.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ami_get_ccb
  2. ami_put_ccb
  3. ami_read
  4. ami_write
  5. ami_allocmem
  6. ami_freemem
  7. ami_copyhds
  8. ami_alloc_ccbs
  9. ami_attach
  10. ami_quartz_init
  11. ami_quartz_exec
  12. ami_quartz_done
  13. ami_quartz_poll
  14. ami_schwartz_init
  15. ami_schwartz_exec
  16. ami_schwartz_done
  17. ami_schwartz_poll
  18. ami_start_xs
  19. ami_start
  20. ami_runqueue_tick
  21. ami_runqueue
  22. ami_poll
  23. ami_complete
  24. ami_stimeout
  25. ami_done
  26. ami_done_pt
  27. ami_done_xs
  28. ami_done_flush
  29. ami_done_sysflush
  30. ami_done_ioctl
  31. ami_done_init
  32. amiminphys
  33. ami_copy_internal_data
  34. ami_scsi_raw_cmd
  35. ami_load_ptmem
  36. ami_scsi_cmd
  37. ami_intr
  38. ami_scsi_ioctl
  39. ami_ioctl
  40. ami_drv_inq
  41. ami_mgmt
  42. ami_ioctl_inq
  43. ami_vol
  44. ami_disk
  45. ami_ioctl_vol
  46. ami_ioctl_disk
  47. ami_ioctl_alarm
  48. ami_ioctl_setstate
  49. ami_create_sensors
  50. ami_refresh_sensors
  51. ami_print_mbox

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

/* [<][>][^][v][top][bottom][index][help] */