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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/pci/amr.c

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

    1 /*      $NetBSD: amr.c,v 1.19.2.3 2004/11/12 06:27:33 jmc Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Doran.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*-
   40  * Copyright (c) 1999,2000 Michael Smith
   41  * Copyright (c) 2000 BSDi
   42  * All rights reserved.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  *
   53  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   63  * SUCH DAMAGE.
   64  *
   65  * from FreeBSD: amr_pci.c,v 1.5 2000/08/30 07:52:40 msmith Exp
   66  * from FreeBSD: amr.c,v 1.16 2000/08/30 07:52:40 msmith Exp 
   67  */
   68 
   69 /*
   70  * Driver for AMI RAID controllers.
   71  */
   72 
   73 #include <sys/cdefs.h>
   74 __KERNEL_RCSID(0, "$NetBSD: amr.c,v 1.19.2.3 2004/11/12 06:27:33 jmc Exp $");
   75 
   76 #include <sys/param.h>
   77 #include <sys/systm.h>
   78 #include <sys/kernel.h>
   79 #include <sys/device.h>
   80 #include <sys/queue.h>
   81 #include <sys/proc.h>
   82 #include <sys/buf.h>
   83 #include <sys/malloc.h>
   84 #include <sys/kthread.h>
   85 
   86 #include <uvm/uvm_extern.h>
   87 
   88 #include <machine/endian.h>
   89 #include <machine/bus.h>
   90 
   91 #include <dev/pci/pcidevs.h>
   92 #include <dev/pci/pcivar.h>
   93 #include <dev/pci/amrreg.h>
   94 #include <dev/pci/amrvar.h>
   95 
   96 void    amr_attach(struct device *, struct device *, void *);
   97 void    amr_ccb_dump(struct amr_softc *, struct amr_ccb *);
   98 void    *amr_enquire(struct amr_softc *, u_int8_t, u_int8_t, u_int8_t, void *);
   99 int     amr_init(struct amr_softc *, const char *,
  100                          struct pci_attach_args *pa);
  101 int     amr_intr(void *);
  102 int     amr_match(struct device *, struct cfdata *, void *);
  103 int     amr_print(void *, const char *);
  104 void    amr_shutdown(void *);
  105 int     amr_submatch(struct device *, struct cfdata *, void *);
  106 void    amr_teardown(struct amr_softc *);
  107 void    amr_thread(void *);
  108 void    amr_thread_create(void *);
  109 
  110 int     amr_mbox_wait(struct amr_softc *);
  111 int     amr_quartz_get_work(struct amr_softc *, struct amr_mailbox_resp *);
  112 int     amr_quartz_submit(struct amr_softc *, struct amr_ccb *);
  113 int     amr_std_get_work(struct amr_softc *, struct amr_mailbox_resp *);
  114 int     amr_std_submit(struct amr_softc *, struct amr_ccb *);
  115 
  116 static inline u_int8_t  amr_inb(struct amr_softc *, int);
  117 static inline u_int32_t amr_inl(struct amr_softc *, int);
  118 static inline void      amr_outb(struct amr_softc *, int, u_int8_t);
  119 static inline void      amr_outl(struct amr_softc *, int, u_int32_t);
  120 
  121 CFATTACH_DECL(amr, sizeof(struct amr_softc),
  122     amr_match, amr_attach, NULL, NULL);
  123 
  124 #define AT_QUARTZ       0x01    /* `Quartz' chipset */
  125 #define AT_SIG          0x02    /* Check for signature */
  126 
  127 struct amr_pci_type {
  128         u_short apt_vendor;
  129         u_short apt_product;
  130         u_short apt_flags;
  131 } const amr_pci_type[] = {
  132         { PCI_VENDOR_AMI,   PCI_PRODUCT_AMI_MEGARAID,  0 },
  133         { PCI_VENDOR_AMI,   PCI_PRODUCT_AMI_MEGARAID2, 0 },
  134         { PCI_VENDOR_AMI,   PCI_PRODUCT_AMI_MEGARAID3, AT_QUARTZ },
  135         { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_AMI_MEGARAID3, AT_QUARTZ },
  136         { PCI_VENDOR_INTEL, PCI_PRODUCT_AMI_MEGARAID3, AT_QUARTZ | AT_SIG },
  137         { PCI_VENDOR_DELL,  PCI_PRODUCT_DELL_PERC_4DI, AT_QUARTZ },
  138         { PCI_VENDOR_DELL,  PCI_PRODUCT_DELL_PERC_4DI_2, AT_QUARTZ },
  139         { PCI_VENDOR_DELL,  PCI_PRODUCT_DELL_PERC_4ESI, AT_QUARTZ },
  140         { PCI_VENDOR_SYMBIOS,  PCI_PRODUCT_SYMBIOS_PERC_4SC, AT_QUARTZ },
  141 };
  142 
  143 struct amr_typestr {
  144         const char      *at_str;
  145         int             at_sig;
  146 } const amr_typestr[] = {
  147         { "Series 431",                 AMR_SIG_431 },
  148         { "Series 438",                 AMR_SIG_438 },
  149         { "Series 466",                 AMR_SIG_466 },
  150         { "Series 467",                 AMR_SIG_467 },
  151         { "Series 490",                 AMR_SIG_490 },
  152         { "Series 762",                 AMR_SIG_762 },
  153         { "HP NetRAID (T5)",            AMR_SIG_T5 },
  154         { "HP NetRAID (T7)",            AMR_SIG_T7 },
  155 };
  156 
  157 struct {
  158         const char      *ds_descr;
  159         int     ds_happy;
  160 } const amr_dstate[] = {
  161         { "offline",    0 },
  162         { "degraded",   1 },
  163         { "optimal",    1 },
  164         { "online",     1 },
  165         { "failed",     0 },
  166         { "rebuilding", 1 },
  167         { "hotspare",   0 },
  168 };
  169 
  170 void    *amr_sdh;
  171 int     amr_max_segs;
  172 int     amr_max_xfer;
  173 
  174 static inline u_int8_t
  175 amr_inb(struct amr_softc *amr, int off)
  176 {
  177 
  178         bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 1,
  179             BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
  180         return (bus_space_read_1(amr->amr_iot, amr->amr_ioh, off));
  181 }
  182 
  183 static inline u_int32_t
  184 amr_inl(struct amr_softc *amr, int off)
  185 {
  186 
  187         bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 4,
  188             BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
  189         return (bus_space_read_4(amr->amr_iot, amr->amr_ioh, off));
  190 }
  191 
  192 static inline void
  193 amr_outb(struct amr_softc *amr, int off, u_int8_t val)
  194 {
  195 
  196         bus_space_write_1(amr->amr_iot, amr->amr_ioh, off, val);
  197         bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 1,
  198             BUS_SPACE_BARRIER_WRITE);
  199 }
  200 
  201 static inline void
  202 amr_outl(struct amr_softc *amr, int off, u_int32_t val)
  203 {
  204 
  205         bus_space_write_4(amr->amr_iot, amr->amr_ioh, off, val);
  206         bus_space_barrier(amr->amr_iot, amr->amr_ioh, off, 4,
  207             BUS_SPACE_BARRIER_WRITE);
  208 }
  209 
  210 /*
  211  * Match a supported device.
  212  */
  213 int
  214 amr_match(struct device *parent, struct cfdata *match, void *aux)
  215 {
  216         struct pci_attach_args *pa;
  217         pcireg_t s;
  218         int i;
  219 
  220         pa = (struct pci_attach_args *)aux;
  221 
  222         /*
  223          * Don't match the device if it's operating in I2O mode.  In this
  224          * case it should be handled by the `iop' driver.
  225          */
  226         if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
  227                 return (0);
  228 
  229         for (i = 0; i < sizeof(amr_pci_type) / sizeof(amr_pci_type[0]); i++)
  230                 if (PCI_VENDOR(pa->pa_id) == amr_pci_type[i].apt_vendor && 
  231                     PCI_PRODUCT(pa->pa_id) == amr_pci_type[i].apt_product)
  232                         break;
  233 
  234         if (i == sizeof(amr_pci_type) / sizeof(amr_pci_type[0]))
  235                 return (0);
  236 
  237         if ((amr_pci_type[i].apt_flags & AT_SIG) == 0)
  238                 return (1);
  239 
  240         s = pci_conf_read(pa->pa_pc, pa->pa_tag, AMR_QUARTZ_SIG_REG) & 0xffff;
  241         return (s == AMR_QUARTZ_SIG0 || s == AMR_QUARTZ_SIG1);
  242 }
  243 
  244 /*
  245  * Attach a supported device.
  246  */
  247 void
  248 amr_attach(struct device *parent, struct device *self, void *aux)
  249 {
  250         struct pci_attach_args *pa;
  251         struct amr_attach_args amra;
  252         const struct amr_pci_type *apt;
  253         struct amr_softc *amr;
  254         pci_chipset_tag_t pc;
  255         pci_intr_handle_t ih;
  256         const char *intrstr;
  257         pcireg_t reg;
  258         int rseg, i, j, size, rv, memreg, ioreg;
  259         struct amr_ccb *ac;
  260 
  261         aprint_naive(": RAID controller\n");
  262 
  263         amr = (struct amr_softc *)self;
  264         pa = (struct pci_attach_args *)aux;
  265         pc = pa->pa_pc;
  266 
  267         for (i = 0; i < sizeof(amr_pci_type) / sizeof(amr_pci_type[0]); i++)
  268                 if (PCI_VENDOR(pa->pa_id) == amr_pci_type[i].apt_vendor &&
  269                     PCI_PRODUCT(pa->pa_id) == amr_pci_type[i].apt_product)
  270                         break;
  271         apt = amr_pci_type + i;
  272 
  273         memreg = ioreg = 0;
  274         for (i = 0x10; i <= 0x14; i += 4) {
  275                 reg = pci_conf_read(pc, pa->pa_tag, i);
  276                 switch (PCI_MAPREG_TYPE(reg)) {
  277                 case PCI_MAPREG_TYPE_MEM:
  278                         if (PCI_MAPREG_MEM_SIZE(reg) != 0)
  279                                 memreg = i;
  280                         break;
  281                 case PCI_MAPREG_TYPE_IO:
  282                         if (PCI_MAPREG_IO_SIZE(reg) != 0)
  283                                 ioreg = i;
  284                         break;
  285 
  286                 }
  287         }
  288 
  289         if (memreg && pci_mapreg_map(pa, memreg, PCI_MAPREG_TYPE_MEM, 0,
  290             &amr->amr_iot, &amr->amr_ioh, NULL, &amr->amr_ios) == 0)
  291                 ;
  292         else if (ioreg && pci_mapreg_map(pa, ioreg, PCI_MAPREG_TYPE_IO, 0,
  293             &amr->amr_iot, &amr->amr_ioh, NULL, &amr->amr_ios) == 0)
  294                 ;
  295         else {
  296                 aprint_error("can't map control registers\n");
  297                 amr_teardown(amr);
  298                 return;
  299         }
  300 
  301         amr->amr_flags |= AMRF_PCI_REGS;
  302         amr->amr_dmat = pa->pa_dmat;
  303         amr->amr_pc = pa->pa_pc;
  304 
  305         /* Enable the device. */
  306         reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
  307         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
  308             reg | PCI_COMMAND_MASTER_ENABLE);
  309 
  310         /* Map and establish the interrupt. */
  311         if (pci_intr_map(pa, &ih)) {
  312                 aprint_error("can't map interrupt\n");
  313                 amr_teardown(amr);
  314                 return;
  315         }
  316         intrstr = pci_intr_string(pc, ih);
  317         amr->amr_ih = pci_intr_establish(pc, ih, IPL_BIO, amr_intr, amr);
  318         if (amr->amr_ih == NULL) {
  319                 aprint_error("can't establish interrupt");
  320                 if (intrstr != NULL)
  321                         aprint_normal(" at %s", intrstr);
  322                 aprint_normal("\n");
  323                 amr_teardown(amr);
  324                 return;
  325         }
  326         amr->amr_flags |= AMRF_PCI_INTR;
  327 
  328         /*
  329          * Allocate space for the mailbox and S/G lists.  Some controllers
  330          * don't like S/G lists to be located below 0x2000, so we allocate
  331          * enough slop to enable us to compensate.
  332          *
  333          * The standard mailbox structure needs to be aligned on a 16-byte
  334          * boundary.  The 64-bit mailbox has one extra field, 4 bytes in
  335          * size, which preceeds the standard mailbox.
  336          */
  337         size = AMR_SGL_SIZE * AMR_MAX_CMDS + 0x2000;
  338         amr->amr_dmasize = size;
  339 
  340         if ((rv = bus_dmamem_alloc(amr->amr_dmat, size, PAGE_SIZE, 0,
  341             &amr->amr_dmaseg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
  342                 aprint_error("%s: unable to allocate buffer, rv = %d\n",
  343                     amr->amr_dv.dv_xname, rv);
  344                 amr_teardown(amr);
  345                 return;
  346         }
  347         amr->amr_flags |= AMRF_DMA_ALLOC;
  348 
  349         if ((rv = bus_dmamem_map(amr->amr_dmat, &amr->amr_dmaseg, rseg, size, 
  350             (caddr_t *)&amr->amr_mbox,
  351             BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  352                 aprint_error("%s: unable to map buffer, rv = %d\n",
  353                     amr->amr_dv.dv_xname, rv);
  354                 amr_teardown(amr);
  355                 return;
  356         }
  357         amr->amr_flags |= AMRF_DMA_MAP;
  358 
  359         if ((rv = bus_dmamap_create(amr->amr_dmat, size, 1, size, 0, 
  360             BUS_DMA_NOWAIT, &amr->amr_dmamap)) != 0) {
  361                 aprint_error("%s: unable to create buffer DMA map, rv = %d\n",
  362                     amr->amr_dv.dv_xname, rv);
  363                 amr_teardown(amr);
  364                 return;
  365         }
  366         amr->amr_flags |= AMRF_DMA_CREATE;
  367 
  368         if ((rv = bus_dmamap_load(amr->amr_dmat, amr->amr_dmamap,
  369             amr->amr_mbox, size, NULL, BUS_DMA_NOWAIT)) != 0) {
  370                 aprint_error("%s: unable to load buffer DMA map, rv = %d\n",
  371                     amr->amr_dv.dv_xname, rv);
  372                 amr_teardown(amr);
  373                 return;
  374         }
  375         amr->amr_flags |= AMRF_DMA_LOAD;
  376 
  377         memset(amr->amr_mbox, 0, size);
  378 
  379         amr->amr_mbox_paddr = amr->amr_dmamap->dm_segs[0].ds_addr;
  380         amr->amr_sgls_paddr = (amr->amr_mbox_paddr + 0x1fff) & ~0x1fff;
  381         amr->amr_sgls = (struct amr_sgentry *)((caddr_t)amr->amr_mbox +
  382             amr->amr_sgls_paddr - amr->amr_dmamap->dm_segs[0].ds_addr);
  383 
  384         /*
  385          * Allocate and initalise the command control blocks.
  386          */
  387         ac = malloc(sizeof(*ac) * AMR_MAX_CMDS, M_DEVBUF, M_NOWAIT | M_ZERO);
  388         amr->amr_ccbs = ac;
  389         SLIST_INIT(&amr->amr_ccb_freelist);
  390         TAILQ_INIT(&amr->amr_ccb_active);
  391         amr->amr_flags |= AMRF_CCBS;
  392 
  393         if (amr_max_xfer == 0) {
  394                 amr_max_xfer = min(((AMR_MAX_SEGS - 1) * PAGE_SIZE), MAXPHYS);
  395                 amr_max_segs = (amr_max_xfer + (PAGE_SIZE * 2) - 1) / PAGE_SIZE;
  396         }
  397 
  398         for (i = 0; i < AMR_MAX_CMDS; i++, ac++) {
  399                 rv = bus_dmamap_create(amr->amr_dmat, amr_max_xfer,
  400                     amr_max_segs, amr_max_xfer, 0,
  401                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ac->ac_xfer_map);
  402                 if (rv != 0)
  403                         break;
  404 
  405                 ac->ac_ident = i;
  406                 amr_ccb_free(amr, ac);
  407         }
  408         if (i != AMR_MAX_CMDS) {
  409                 aprint_error("%s: memory exhausted\n", amr->amr_dv.dv_xname);
  410                 amr_teardown(amr);
  411                 return;
  412         }
  413 
  414         /*
  415          * Take care of model-specific tasks.
  416          */
  417         if ((apt->apt_flags & AT_QUARTZ) != 0) {
  418                 amr->amr_submit = amr_quartz_submit;
  419                 amr->amr_get_work = amr_quartz_get_work;
  420         } else {
  421                 amr->amr_submit = amr_std_submit;
  422                 amr->amr_get_work = amr_std_get_work;
  423 
  424                 /* Notify the controller of the mailbox location. */
  425                 amr_outl(amr, AMR_SREG_MBOX, (u_int32_t)amr->amr_mbox_paddr + 16);
  426                 amr_outb(amr, AMR_SREG_MBOX_ENABLE, AMR_SMBOX_ENABLE_ADDR);
  427 
  428                 /* Clear outstanding interrupts and enable interrupts. */
  429                 amr_outb(amr, AMR_SREG_CMD, AMR_SCMD_ACKINTR);
  430                 amr_outb(amr, AMR_SREG_TOGL,
  431                     amr_inb(amr, AMR_SREG_TOGL) | AMR_STOGL_ENABLE);
  432         }
  433 
  434         /*
  435          * Retrieve parameters, and tell the world about us.
  436          */
  437         amr->amr_enqbuf = malloc(AMR_ENQUIRY_BUFSIZE, M_DEVBUF, M_NOWAIT);
  438         amr->amr_flags |= AMRF_ENQBUF;
  439         amr->amr_maxqueuecnt = i;
  440         aprint_normal(": AMI RAID ");
  441         if (amr_init(amr, intrstr, pa) != 0) {
  442                 amr_teardown(amr);
  443                 return;
  444         }
  445 
  446         /* 
  447          * Cap the maximum number of outstanding commands.  AMI's Linux
  448          * driver doesn't trust the controller's reported value, and lockups
  449          * have been seen when we do.
  450          */
  451         amr->amr_maxqueuecnt = min(amr->amr_maxqueuecnt, AMR_MAX_CMDS);
  452         if (amr->amr_maxqueuecnt > i)
  453                 amr->amr_maxqueuecnt = i;
  454 
  455         /* Set our `shutdownhook' before we start any device activity. */
  456         if (amr_sdh == NULL)
  457                 amr_sdh = shutdownhook_establish(amr_shutdown, NULL);
  458 
  459         /* Attach sub-devices. */
  460         for (j = 0; j < amr->amr_numdrives; j++) {
  461                 if (amr->amr_drive[j].al_size == 0)
  462                         continue;
  463                 amra.amra_unit = j;
  464                 amr->amr_drive[j].al_dv = config_found_sm(&amr->amr_dv, &amra,
  465                     amr_print, amr_submatch);
  466         }
  467 
  468         SIMPLEQ_INIT(&amr->amr_ccb_queue);
  469 
  470         /* XXX This doesn't work for newer boards yet. */
  471         if ((apt->apt_flags & AT_QUARTZ) == 0)
  472                 kthread_create(amr_thread_create, amr);
  473 }
  474 
  475 /*
  476  * Free up resources.
  477  */
  478 void
  479 amr_teardown(struct amr_softc *amr)
  480 {
  481         struct amr_ccb *ac;
  482         int fl;
  483 
  484         fl = amr->amr_flags;
  485 
  486         if ((fl & AMRF_THREAD) != 0) {
  487                 amr->amr_flags |= AMRF_THREAD_EXIT;
  488                 wakeup(amr_thread);
  489                 while ((amr->amr_flags & AMRF_THREAD_EXIT) != 0)
  490                         tsleep(&amr->amr_flags, PWAIT, "amrexit", 0);
  491         }
  492         if ((fl & AMRF_CCBS) != 0) {
  493                 SLIST_FOREACH(ac, &amr->amr_ccb_freelist, ac_chain.slist) {
  494                         bus_dmamap_destroy(amr->amr_dmat, ac->ac_xfer_map);
  495                 }
  496                 free(amr->amr_ccbs, M_DEVBUF);
  497         }
  498         if ((fl & AMRF_ENQBUF) != 0)
  499                 free(amr->amr_enqbuf, M_DEVBUF);
  500         if ((fl & AMRF_DMA_LOAD) != 0)
  501                 bus_dmamap_unload(amr->amr_dmat, amr->amr_dmamap);
  502         if ((fl & AMRF_DMA_MAP) != 0)
  503                 bus_dmamem_unmap(amr->amr_dmat, (caddr_t)amr->amr_mbox,
  504                     amr->amr_dmasize);
  505         if ((fl & AMRF_DMA_ALLOC) != 0)
  506                 bus_dmamem_free(amr->amr_dmat, &amr->amr_dmaseg, 1);
  507         if ((fl & AMRF_DMA_CREATE) != 0)
  508                 bus_dmamap_destroy(amr->amr_dmat, amr->amr_dmamap);
  509         if ((fl & AMRF_PCI_INTR) != 0)
  510                 pci_intr_disestablish(amr->amr_pc, amr->amr_ih);
  511         if ((fl & AMRF_PCI_REGS) != 0)
  512                 bus_space_unmap(amr->amr_iot, amr->amr_ioh, amr->amr_ios);
  513 }
  514 
  515 /*
  516  * Print autoconfiguration message for a sub-device.
  517  */
  518 int
  519 amr_print(void *aux, const char *pnp)
  520 {
  521         struct amr_attach_args *amra;
  522 
  523         amra = (struct amr_attach_args *)aux;
  524 
  525         if (pnp != NULL)
  526                 aprint_normal("block device at %s", pnp);
  527         aprint_normal(" unit %d", amra->amra_unit);
  528         return (UNCONF);
  529 }
  530 
  531 /*
  532  * Match a sub-device.
  533  */
  534 int
  535 amr_submatch(struct device *parent, struct cfdata *cf, void *aux)
  536 {
  537         struct amr_attach_args *amra;
  538 
  539         amra = (struct amr_attach_args *)aux;
  540 
  541         if (cf->amracf_unit != AMRCF_UNIT_DEFAULT &&
  542             cf->amracf_unit != amra->amra_unit)
  543                 return (0);
  544 
  545         return (config_match(parent, cf, aux));
  546 }
  547 
  548 /*
  549  * Retrieve operational parameters and describe the controller.
  550  */
  551 int
  552 amr_init(struct amr_softc *amr, const char *intrstr,
  553          struct pci_attach_args *pa)
  554 {
  555         struct amr_adapter_info *aa;
  556         struct amr_prodinfo *ap;
  557         struct amr_enquiry *ae;
  558         struct amr_enquiry3 *aex;
  559         const char *prodstr;
  560         u_int i, sig, ishp;
  561         char buf[64];
  562 
  563         /*
  564          * Try to get 40LD product info, which tells us what the card is
  565          * labelled as.
  566          */
  567         ap = amr_enquire(amr, AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0,
  568             amr->amr_enqbuf);
  569         if (ap != NULL) {
  570                 aprint_normal("<%.80s>\n", ap->ap_product);
  571                 if (intrstr != NULL)
  572                         aprint_normal("%s: interrupting at %s\n",
  573                             amr->amr_dv.dv_xname, intrstr);
  574                 aprint_normal("%s: firmware %.16s, BIOS %.16s, %dMB RAM\n",
  575                     amr->amr_dv.dv_xname, ap->ap_firmware, ap->ap_bios,
  576                     le16toh(ap->ap_memsize));
  577 
  578                 amr->amr_maxqueuecnt = ap->ap_maxio;
  579 
  580                 /*
  581                  * Fetch and record state of logical drives.
  582                  */
  583                 aex = amr_enquire(amr, AMR_CMD_CONFIG, AMR_CONFIG_ENQ3,
  584                     AMR_CONFIG_ENQ3_SOLICITED_FULL, amr->amr_enqbuf);
  585                 if (aex == NULL) {
  586                         aprint_error("%s ENQUIRY3 failed\n",
  587                             amr->amr_dv.dv_xname);
  588                         return (-1);
  589                 }
  590 
  591                 if (aex->ae_numldrives > AMR_MAX_UNITS) {
  592                         aprint_error(
  593                             "%s: adjust AMR_MAX_UNITS to %d (currently %d)"
  594                             "\n", amr->amr_dv.dv_xname, AMR_MAX_UNITS,
  595                             amr->amr_numdrives);
  596                         amr->amr_numdrives = AMR_MAX_UNITS;
  597                 } else
  598                         amr->amr_numdrives = aex->ae_numldrives;
  599 
  600                 for (i = 0; i < amr->amr_numdrives; i++) {
  601                         amr->amr_drive[i].al_size =
  602                             le32toh(aex->ae_drivesize[i]);
  603                         amr->amr_drive[i].al_state = aex->ae_drivestate[i];
  604                         amr->amr_drive[i].al_properties = aex->ae_driveprop[i];
  605                 }
  606 
  607                 return (0);
  608         }
  609 
  610         /*
  611          * Try 8LD extended ENQUIRY to get the controller signature.  Once
  612          * found, search for a product description.
  613          */
  614         ae = amr_enquire(amr, AMR_CMD_EXT_ENQUIRY2, 0, 0, amr->amr_enqbuf);
  615         if (ae != NULL) {
  616                 i = 0;
  617                 sig = le32toh(ae->ae_signature);
  618 
  619                 while (i < sizeof(amr_typestr) / sizeof(amr_typestr[0])) {
  620                         if (amr_typestr[i].at_sig == sig)
  621                                 break;
  622                         i++;
  623                 }
  624                 if (i == sizeof(amr_typestr) / sizeof(amr_typestr[0])) {
  625                         sprintf(buf, "unknown ENQUIRY2 sig (0x%08x)", sig);
  626                         prodstr = buf;
  627                 } else
  628                         prodstr = amr_typestr[i].at_str;
  629         } else {
  630                 ae = amr_enquire(amr, AMR_CMD_ENQUIRY, 0, 0, amr->amr_enqbuf);
  631                 if (ae == NULL) {
  632                         aprint_error("%s: unsupported controller\n",
  633                             amr->amr_dv.dv_xname);
  634                         return (-1);
  635                 }
  636 
  637                 switch (PCI_PRODUCT(pa->pa_id)) {
  638                 case PCI_PRODUCT_AMI_MEGARAID:
  639                         prodstr = "Series 428";
  640                         break;
  641                 case PCI_PRODUCT_AMI_MEGARAID2:
  642                         prodstr = "Series 434";
  643                         break;
  644                 default:
  645                         sprintf(buf, "unknown PCI dev (0x%04x)",
  646                             PCI_PRODUCT(pa->pa_id));
  647                         prodstr = buf;
  648                         break;
  649                 }
  650         }
  651 
  652         /*
  653          * HP NetRaid controllers have a special encoding of the firmware
  654          * and BIOS versions.  The AMI version seems to have it as strings
  655          * whereas the HP version does it with a leading uppercase character
  656          * and two binary numbers.
  657         */
  658         aa = &ae->ae_adapter;
  659 
  660         if (aa->aa_firmware[2] >= 'A' && aa->aa_firmware[2] <= 'Z' &&
  661             aa->aa_firmware[1] <  ' ' && aa->aa_firmware[0] <  ' ' &&
  662             aa->aa_bios[2] >= 'A' && aa->aa_bios[2] <= 'Z' &&
  663             aa->aa_bios[1] <  ' ' && aa->aa_bios[0] <  ' ') {
  664                 if (le32toh(ae->ae_signature) == AMR_SIG_438) {
  665                         /* The AMI 438 is a NetRaid 3si in HP-land. */
  666                         prodstr = "HP NetRaid 3si";
  667                 }
  668                 ishp = 1;
  669         } else
  670                 ishp = 0;
  671 
  672         aprint_normal("<%s>\n", prodstr);
  673         if (intrstr != NULL)
  674                 aprint_normal("%s: interrupting at %s\n", amr->amr_dv.dv_xname,
  675                     intrstr);
  676 
  677         if (ishp)
  678                 aprint_normal("%s: firmware <%c.%02d.%02d>, BIOS <%c.%02d.%02d>"
  679                     ", %dMB RAM\n", amr->amr_dv.dv_xname, aa->aa_firmware[2],
  680                      aa->aa_firmware[1], aa->aa_firmware[0], aa->aa_bios[2],
  681                      aa->aa_bios[1], aa->aa_bios[0], aa->aa_memorysize);
  682         else
  683                 aprint_normal("%s: firmware <%.4s>, BIOS <%.4s>, %dMB RAM\n",
  684                     amr->amr_dv.dv_xname, aa->aa_firmware, aa->aa_bios,
  685                     aa->aa_memorysize);
  686 
  687         amr->amr_maxqueuecnt = aa->aa_maxio;
  688 
  689         /*
  690          * Record state of logical drives.
  691          */
  692         if (ae->ae_ldrv.al_numdrives > AMR_MAX_UNITS) {
  693                 aprint_error("%s: adjust AMR_MAX_UNITS to %d (currently %d)\n",
  694                     amr->amr_dv.dv_xname, ae->ae_ldrv.al_numdrives,
  695                     AMR_MAX_UNITS);
  696                 amr->amr_numdrives = AMR_MAX_UNITS;
  697         } else
  698                 amr->amr_numdrives = ae->ae_ldrv.al_numdrives;
  699 
  700         for (i = 0; i < AMR_MAX_UNITS; i++) {
  701                 amr->amr_drive[i].al_size = le32toh(ae->ae_ldrv.al_size[i]);
  702                 amr->amr_drive[i].al_state = ae->ae_ldrv.al_state[i];
  703                 amr->amr_drive[i].al_properties = ae->ae_ldrv.al_properties[i];
  704         }
  705 
  706         return (0);
  707 }
  708 
  709 /*
  710  * Flush the internal cache on each configured controller.  Called at
  711  * shutdown time.
  712  */
  713 void
  714 amr_shutdown(void *cookie)
  715 {
  716         extern struct cfdriver amr_cd;
  717         struct amr_softc *amr;
  718         struct amr_ccb *ac;
  719         int i, rv, s;
  720 
  721         for (i = 0; i < amr_cd.cd_ndevs; i++) {
  722                 if ((amr = device_lookup(&amr_cd, i)) == NULL)
  723                         continue;
  724 
  725                 if ((rv = amr_ccb_alloc(amr, &ac)) == 0) {
  726                         ac->ac_cmd.mb_command = AMR_CMD_FLUSH;
  727                         s = splbio();
  728                         rv = amr_ccb_poll(amr, ac, 30000);
  729                         splx(s);
  730                         amr_ccb_free(amr, ac);
  731                 }
  732                 if (rv != 0)
  733                         printf("%s: unable to flush cache (%d)\n",
  734                             amr->amr_dv.dv_xname, rv);
  735         }
  736 }
  737 
  738 /*
  739  * Interrupt service routine.
  740  */
  741 int
  742 amr_intr(void *cookie)
  743 {
  744         struct amr_softc *amr;
  745         struct amr_ccb *ac;
  746         struct amr_mailbox_resp mbox;
  747         u_int i, forus, idx;
  748 
  749         amr = cookie;
  750         forus = 0;
  751 
  752         while ((*amr->amr_get_work)(amr, &mbox) == 0) {
  753                 /* Iterate over completed commands in this result. */
  754                 for (i = 0; i < mbox.mb_nstatus; i++) {
  755                         idx = mbox.mb_completed[i] - 1;
  756                         ac = amr->amr_ccbs + idx;
  757 
  758                         if (idx >= amr->amr_maxqueuecnt) {
  759                                 printf("%s: bad status (bogus ID: %u=%u)\n",
  760                                     amr->amr_dv.dv_xname, i, idx);
  761                                 continue;
  762                         }
  763 
  764                         if ((ac->ac_flags & AC_ACTIVE) == 0) {
  765                                 printf("%s: bad status (not active; 0x04%x)\n",
  766                                     amr->amr_dv.dv_xname, ac->ac_flags);
  767                                 continue;
  768                         }
  769 
  770                         ac->ac_status = mbox.mb_status;
  771                         ac->ac_flags = (ac->ac_flags & ~AC_ACTIVE) |
  772                             AC_COMPLETE;
  773                         TAILQ_REMOVE(&amr->amr_ccb_active, ac, ac_chain.tailq);
  774 
  775                         if ((ac->ac_flags & AC_MOAN) != 0)
  776                                 printf("%s: ccb %d completed\n",
  777                                     amr->amr_dv.dv_xname, ac->ac_ident);
  778 
  779                         /* Pass notification to upper layers. */
  780                         if (ac->ac_handler != NULL)
  781                                 (*ac->ac_handler)(ac);
  782                         else
  783                                 wakeup(ac);
  784                 }
  785                 forus = 1;
  786         }
  787 
  788         if (forus)
  789                 amr_ccb_enqueue(amr, NULL);
  790 
  791         return (forus);
  792 }
  793 
  794 /*
  795  * Create the watchdog thread.
  796  */
  797 void
  798 amr_thread_create(void *cookie)
  799 {
  800         struct amr_softc *amr;
  801         int rv;
  802 
  803         amr = cookie;
  804 
  805         if ((amr->amr_flags & AMRF_THREAD_EXIT) != 0) {
  806                 amr->amr_flags ^= AMRF_THREAD_EXIT;
  807                 wakeup(&amr->amr_flags);
  808                 return;
  809         }
  810 
  811         rv = kthread_create1(amr_thread, amr, &amr->amr_thread, "%s",
  812             amr->amr_dv.dv_xname);
  813         if (rv != 0)
  814                 aprint_error("%s: unable to create thread (%d)",
  815                     amr->amr_dv.dv_xname, rv);
  816         else
  817                 amr->amr_flags |= AMRF_THREAD;
  818 }
  819 
  820 /*
  821  * Watchdog thread.
  822  */
  823 void
  824 amr_thread(void *cookie)
  825 {
  826         struct amr_softc *amr;
  827         struct amr_ccb *ac;
  828         struct amr_logdrive *al;
  829         struct amr_enquiry *ae;
  830         time_t curtime;
  831         int rv, i, s;
  832 
  833         amr = cookie;
  834         ae = amr->amr_enqbuf;
  835 
  836         for (;;) {
  837                 tsleep(amr_thread, PWAIT, "amrwdog", AMR_WDOG_TICKS);
  838 
  839                 if ((amr->amr_flags & AMRF_THREAD_EXIT) != 0) {
  840                         amr->amr_flags ^= AMRF_THREAD_EXIT;
  841                         wakeup(&amr->amr_flags);
  842                         kthread_exit(0);
  843                 }
  844 
  845                 s = splbio();
  846                 amr_intr(cookie);
  847                 curtime = (time_t)mono_time.tv_sec;
  848                 ac = TAILQ_FIRST(&amr->amr_ccb_active);
  849                 while (ac != NULL) {
  850                         if (ac->ac_start_time + AMR_TIMEOUT > curtime)
  851                                 break;
  852                         if ((ac->ac_flags & AC_MOAN) == 0) {
  853                                 printf("%s: ccb %d timed out; mailbox:\n",
  854                                     amr->amr_dv.dv_xname, ac->ac_ident);
  855                                 amr_ccb_dump(amr, ac);
  856                                 ac->ac_flags |= AC_MOAN;
  857                         }
  858                         ac = TAILQ_NEXT(ac, ac_chain.tailq);
  859                 }
  860                 splx(s);
  861 
  862                 if ((rv = amr_ccb_alloc(amr, &ac)) != 0) {
  863                         printf("%s: ccb_alloc failed (%d)\n",
  864                             amr->amr_dv.dv_xname, rv);          
  865                         continue;
  866                 }
  867 
  868                 ac->ac_cmd.mb_command = AMR_CMD_ENQUIRY;
  869 
  870                 rv = amr_ccb_map(amr, ac, amr->amr_enqbuf,
  871                     AMR_ENQUIRY_BUFSIZE, 0);
  872                 if (rv != 0) {
  873                         printf("%s: ccb_map failed (%d)\n",
  874                             amr->amr_dv.dv_xname, rv);
  875                         amr_ccb_free(amr, ac);
  876                         continue;
  877                 }
  878 
  879                 rv = amr_ccb_wait(amr, ac);
  880                 amr_ccb_unmap(amr, ac);
  881                 if (rv != 0) {
  882                         printf("%s: enquiry failed (st=%d)\n",
  883                             amr->amr_dv.dv_xname, ac->ac_status);
  884                         continue;
  885                 }
  886                 amr_ccb_free(amr, ac);
  887 
  888                 al = amr->amr_drive;
  889                 for (i = 0; i < AMR_MAX_UNITS; i++, al++) {
  890                         if (al->al_dv == NULL)
  891                                 continue;
  892                         if (al->al_state == ae->ae_ldrv.al_state[i])
  893                                 continue;
  894 
  895                         printf("%s: state changed: %s -> %s\n",
  896                             al->al_dv->dv_xname,
  897                             amr_drive_state(al->al_state, NULL),
  898                             amr_drive_state(ae->ae_ldrv.al_state[i], NULL));
  899 
  900                         al->al_state = ae->ae_ldrv.al_state[i];
  901                 }
  902         }
  903 }
  904 
  905 /*
  906  * Return a text description of a logical drive's current state.
  907  */
  908 const char *
  909 amr_drive_state(int state, int *happy)
  910 {
  911         const char *str;
  912 
  913         state = AMR_DRV_CURSTATE(state);
  914         if (state >= sizeof(amr_dstate) / sizeof(amr_dstate[0])) {
  915                 if (happy)
  916                         *happy = 1;
  917                 str = "status unknown";
  918         } else {
  919                 if (happy)
  920                         *happy = amr_dstate[state].ds_happy;
  921                 str = amr_dstate[state].ds_descr;
  922         }
  923 
  924         return (str);
  925 }
  926 
  927 /*
  928  * Run a generic enquiry-style command.
  929  */
  930 void *
  931 amr_enquire(struct amr_softc *amr, u_int8_t cmd, u_int8_t cmdsub,
  932             u_int8_t cmdqual, void *buf)
  933 {
  934         struct amr_ccb *ac;
  935         u_int8_t *mb;
  936         int rv;
  937 
  938         if (amr_ccb_alloc(amr, &ac) != 0)
  939                 return (NULL);
  940 
  941         /* Build the command proper. */
  942         mb = (u_int8_t *)&ac->ac_cmd;
  943         mb[0] = cmd;
  944         mb[2] = cmdsub;
  945         mb[3] = cmdqual;
  946 
  947         rv = amr_ccb_map(amr, ac, buf, AMR_ENQUIRY_BUFSIZE, 0);
  948         if (rv == 0) {
  949                 rv = amr_ccb_poll(amr, ac, 2000);
  950                 amr_ccb_unmap(amr, ac);
  951         }
  952         amr_ccb_free(amr, ac);
  953 
  954         return (rv ? NULL : buf);
  955 }
  956 
  957 /*
  958  * Allocate and initialise a CCB.
  959  */
  960 int
  961 amr_ccb_alloc(struct amr_softc *amr, struct amr_ccb **acp)
  962 {
  963         int s;
  964 
  965         s = splbio();
  966         if ((*acp = SLIST_FIRST(&amr->amr_ccb_freelist)) == NULL) {
  967                 splx(s);
  968                 return (EAGAIN);
  969         }
  970         SLIST_REMOVE_HEAD(&amr->amr_ccb_freelist, ac_chain.slist);
  971         splx(s);
  972 
  973         return (0);
  974 }
  975 
  976 /*
  977  * Free a CCB.
  978  */
  979 void
  980 amr_ccb_free(struct amr_softc *amr, struct amr_ccb *ac)
  981 {
  982         int s;
  983 
  984         memset(&ac->ac_cmd, 0, sizeof(ac->ac_cmd));
  985         ac->ac_cmd.mb_ident = ac->ac_ident + 1;
  986         ac->ac_cmd.mb_busy = 1;
  987         ac->ac_handler = NULL;
  988         ac->ac_flags = 0;
  989 
  990         s = splbio();
  991         SLIST_INSERT_HEAD(&amr->amr_ccb_freelist, ac, ac_chain.slist);
  992         splx(s);
  993 }
  994 
  995 /*
  996  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
  997  * the order that they were enqueued and try to submit their command blocks
  998  * to the controller for execution.
  999  */
 1000 void
 1001 amr_ccb_enqueue(struct amr_softc *amr, struct amr_ccb *ac)
 1002 {
 1003         int s;
 1004 
 1005         s = splbio();
 1006 
 1007         if (ac != NULL)
 1008                 SIMPLEQ_INSERT_TAIL(&amr->amr_ccb_queue, ac, ac_chain.simpleq);
 1009 
 1010         while ((ac = SIMPLEQ_FIRST(&amr->amr_ccb_queue)) != NULL) {
 1011                 if ((*amr->amr_submit)(amr, ac) != 0)
 1012                         break;
 1013                 SIMPLEQ_REMOVE_HEAD(&amr->amr_ccb_queue, ac_chain.simpleq);
 1014                 TAILQ_INSERT_TAIL(&amr->amr_ccb_active, ac, ac_chain.tailq);
 1015         }
 1016 
 1017         splx(s);
 1018 }
 1019 
 1020 /*
 1021  * Map the specified CCB's data buffer onto the bus, and fill the
 1022  * scatter-gather list.
 1023  */
 1024 int
 1025 amr_ccb_map(struct amr_softc *amr, struct amr_ccb *ac, void *data, int size,
 1026             int out)
 1027 {
 1028         struct amr_sgentry *sge;
 1029         struct amr_mailbox_cmd *mb;
 1030         int nsegs, i, rv, sgloff;
 1031         bus_dmamap_t xfer;
 1032 
 1033         xfer = ac->ac_xfer_map;
 1034 
 1035         rv = bus_dmamap_load(amr->amr_dmat, xfer, data, size, NULL,
 1036             BUS_DMA_NOWAIT);
 1037         if (rv != 0)
 1038                 return (rv);
 1039 
 1040         mb = &ac->ac_cmd;
 1041         ac->ac_xfer_size = size;
 1042         ac->ac_flags |= (out ? AC_XFER_OUT : AC_XFER_IN);
 1043         sgloff = AMR_SGL_SIZE * ac->ac_ident;
 1044 
 1045         /* We don't need to use a scatter/gather list for just 1 segment. */
 1046         nsegs = xfer->dm_nsegs;
 1047         if (nsegs == 1) {
 1048                 mb->mb_nsgelem = 0;
 1049                 mb->mb_physaddr = htole32(xfer->dm_segs[0].ds_addr);
 1050                 ac->ac_flags |= AC_NOSGL;
 1051         } else {
 1052                 mb->mb_nsgelem = nsegs;
 1053                 mb->mb_physaddr = htole32(amr->amr_sgls_paddr + sgloff);
 1054 
 1055                 sge = (struct amr_sgentry *)((caddr_t)amr->amr_sgls + sgloff);
 1056                 for (i = 0; i < nsegs; i++, sge++) {
 1057                         sge->sge_addr = htole32(xfer->dm_segs[i].ds_addr);
 1058                         sge->sge_count = htole32(xfer->dm_segs[i].ds_len);
 1059                 }
 1060         }
 1061 
 1062         bus_dmamap_sync(amr->amr_dmat, xfer, 0, ac->ac_xfer_size,
 1063             out ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
 1064 
 1065         if ((ac->ac_flags & AC_NOSGL) == 0)
 1066                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, sgloff,
 1067                     AMR_SGL_SIZE, BUS_DMASYNC_PREWRITE);
 1068 
 1069         return (0);
 1070 }
 1071 
 1072 /*
 1073  * Unmap the specified CCB's data buffer.
 1074  */
 1075 void
 1076 amr_ccb_unmap(struct amr_softc *amr, struct amr_ccb *ac)
 1077 {
 1078 
 1079         if ((ac->ac_flags & AC_NOSGL) == 0)
 1080                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap,
 1081                     AMR_SGL_SIZE * ac->ac_ident, AMR_SGL_SIZE,
 1082                     BUS_DMASYNC_POSTWRITE);
 1083         bus_dmamap_sync(amr->amr_dmat, ac->ac_xfer_map, 0, ac->ac_xfer_size,
 1084             (ac->ac_flags & AC_XFER_IN) != 0 ?
 1085             BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 1086         bus_dmamap_unload(amr->amr_dmat, ac->ac_xfer_map);
 1087 }
 1088 
 1089 /*
 1090  * Submit a command to the controller and poll on completion.  Return
 1091  * non-zero on timeout or error.  Must be called with interrupts blocked.
 1092  */
 1093 int
 1094 amr_ccb_poll(struct amr_softc *amr, struct amr_ccb *ac, int timo)
 1095 {
 1096         int rv;
 1097 
 1098         if ((rv = (*amr->amr_submit)(amr, ac)) != 0)
 1099                 return (rv);
 1100         TAILQ_INSERT_TAIL(&amr->amr_ccb_active, ac, ac_chain.tailq);
 1101 
 1102         for (timo *= 10; timo != 0; timo--) {
 1103                 amr_intr(amr);
 1104                 if ((ac->ac_flags & AC_COMPLETE) != 0)
 1105                         break;
 1106                 DELAY(100);
 1107         }
 1108 
 1109         return (timo == 0 || ac->ac_status != 0 ? EIO : 0);
 1110 }
 1111 
 1112 /*
 1113  * Submit a command to the controller and sleep on completion.  Return
 1114  * non-zero on error.
 1115  */
 1116 int
 1117 amr_ccb_wait(struct amr_softc *amr, struct amr_ccb *ac)
 1118 {
 1119         int s;
 1120 
 1121         s = splbio();
 1122         amr_ccb_enqueue(amr, ac);
 1123         tsleep(ac, PRIBIO, "amrcmd", 0); 
 1124         splx(s);
 1125 
 1126         return (ac->ac_status != 0 ? EIO : 0);
 1127 }
 1128 
 1129 /*
 1130  * Wait for the mailbox to become available.
 1131  */
 1132 int
 1133 amr_mbox_wait(struct amr_softc *amr)
 1134 {
 1135         int timo;
 1136 
 1137         for (timo = 10000; timo != 0; timo--) {
 1138                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1139                     sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
 1140                 if (amr->amr_mbox->mb_cmd.mb_busy == 0)
 1141                         break;
 1142                 DELAY(100);
 1143         }
 1144 
 1145         if (timo == 0)
 1146                 printf("%s: controller wedged\n", amr->amr_dv.dv_xname);
 1147 
 1148         return (timo != 0 ? 0 : EAGAIN);
 1149 }
 1150 
 1151 /*
 1152  * Tell the controller that the mailbox contains a valid command.  Must be
 1153  * called with interrupts blocked.
 1154  */
 1155 int
 1156 amr_quartz_submit(struct amr_softc *amr, struct amr_ccb *ac)
 1157 {
 1158         u_int32_t v;
 1159 
 1160         amr->amr_mbox->mb_poll = 0;
 1161         amr->amr_mbox->mb_ack = 0;
 1162         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1163             sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 1164         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1165             sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
 1166         if (amr->amr_mbox->mb_cmd.mb_busy != 0)
 1167                 return (EAGAIN);
 1168 
 1169         v = amr_inl(amr, AMR_QREG_IDB);
 1170         if ((v & AMR_QIDB_SUBMIT) != 0) {
 1171                 amr->amr_mbox->mb_cmd.mb_busy = 0;
 1172                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1173                     sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 1174                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1175                     sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
 1176                 return (EAGAIN);
 1177         }
 1178 
 1179         amr->amr_mbox->mb_segment = 0;
 1180         memcpy(&amr->amr_mbox->mb_cmd, &ac->ac_cmd, sizeof(ac->ac_cmd));
 1181         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1182             sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 1183 
 1184         ac->ac_start_time = (time_t)mono_time.tv_sec;
 1185         ac->ac_flags |= AC_ACTIVE;
 1186         amr_outl(amr, AMR_QREG_IDB,
 1187             (amr->amr_mbox_paddr + 16) | AMR_QIDB_SUBMIT);
 1188         return (0);
 1189 }
 1190 
 1191 int
 1192 amr_std_submit(struct amr_softc *amr, struct amr_ccb *ac)
 1193 {
 1194 
 1195         amr->amr_mbox->mb_poll = 0;
 1196         amr->amr_mbox->mb_ack = 0;
 1197         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1198             sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 1199         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1200             sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
 1201         if (amr->amr_mbox->mb_cmd.mb_busy != 0)
 1202                 return (EAGAIN);
 1203 
 1204         if ((amr_inb(amr, AMR_SREG_MBOX_BUSY) & AMR_SMBOX_BUSY_FLAG) != 0) {
 1205                 amr->amr_mbox->mb_cmd.mb_busy = 0;
 1206                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1207                     sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 1208                 bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1209                     sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
 1210                 return (EAGAIN);
 1211         }
 1212 
 1213         amr->amr_mbox->mb_segment = 0;
 1214         memcpy(&amr->amr_mbox->mb_cmd, &ac->ac_cmd, sizeof(ac->ac_cmd));
 1215         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1216             sizeof(struct amr_mailbox), BUS_DMASYNC_PREWRITE);
 1217 
 1218         ac->ac_start_time = (time_t)mono_time.tv_sec;
 1219         ac->ac_flags |= AC_ACTIVE;
 1220         amr_outb(amr, AMR_SREG_CMD, AMR_SCMD_POST);
 1221         return (0);
 1222 }
 1223 
 1224 /*
 1225  * Claim any work that the controller has completed; acknowledge completion,
 1226  * save details of the completion in (mbsave).  Must be called with
 1227  * interrupts blocked.
 1228  */
 1229 int
 1230 amr_quartz_get_work(struct amr_softc *amr, struct amr_mailbox_resp *mbsave)
 1231 {
 1232 
 1233         /* Work waiting for us? */
 1234         if (amr_inl(amr, AMR_QREG_ODB) != AMR_QODB_READY)
 1235                 return (-1);
 1236 
 1237         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1238             sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
 1239 
 1240         /* Save the mailbox, which contains a list of completed commands. */
 1241         memcpy(mbsave, &amr->amr_mbox->mb_resp, sizeof(*mbsave));
 1242 
 1243         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1244             sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
 1245 
 1246         /* Ack the interrupt and mailbox transfer. */
 1247         amr_outl(amr, AMR_QREG_ODB, AMR_QODB_READY);
 1248         amr_outl(amr, AMR_QREG_IDB, (amr->amr_mbox_paddr+16) | AMR_QIDB_ACK);
 1249 
 1250         /*
 1251          * This waits for the controller to notice that we've taken the
 1252          * command from it.  It's very inefficient, and we shouldn't do it,
 1253          * but if we remove this code, we stop completing commands under
 1254          * load.
 1255          *
 1256          * Peter J says we shouldn't do this.  The documentation says we
 1257          * should.  Who is right?
 1258          */
 1259         while ((amr_inl(amr, AMR_QREG_IDB) & AMR_QIDB_ACK) != 0)
 1260                 DELAY(10);
 1261 
 1262         return (0);
 1263 }
 1264 
 1265 int
 1266 amr_std_get_work(struct amr_softc *amr, struct amr_mailbox_resp *mbsave)
 1267 {
 1268         u_int8_t istat;
 1269 
 1270         /* Check for valid interrupt status. */
 1271         if (((istat = amr_inb(amr, AMR_SREG_INTR)) & AMR_SINTR_VALID) == 0)
 1272                 return (-1);
 1273 
 1274         /* Ack the interrupt. */
 1275         amr_outb(amr, AMR_SREG_INTR, istat);
 1276 
 1277         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1278             sizeof(struct amr_mailbox), BUS_DMASYNC_POSTREAD);
 1279 
 1280         /* Save mailbox, which contains a list of completed commands. */
 1281         memcpy(mbsave, &amr->amr_mbox->mb_resp, sizeof(*mbsave));
 1282 
 1283         bus_dmamap_sync(amr->amr_dmat, amr->amr_dmamap, 0,
 1284             sizeof(struct amr_mailbox), BUS_DMASYNC_PREREAD);
 1285 
 1286         /* Ack mailbox transfer. */
 1287         amr_outb(amr, AMR_SREG_CMD, AMR_SCMD_ACKINTR);
 1288 
 1289         return (0);
 1290 }
 1291 
 1292 void
 1293 amr_ccb_dump(struct amr_softc *amr, struct amr_ccb *ac)
 1294 {
 1295         int i;
 1296 
 1297         printf("%s: ", amr->amr_dv.dv_xname);
 1298         for (i = 0; i < 4; i++)
 1299                 printf("%08x ", ((u_int32_t *)&ac->ac_cmd)[i]);
 1300         printf("\n");
 1301 }

Cache object: e43c4ab2f493eeca055d90f472e59f6d


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


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