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/twe.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: twe.c,v 1.54.2.2 2004/06/05 04:59:21 jmc Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2000, 2001, 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; and by Jason R. Thorpe of Wasabi Systems, Inc.
    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) 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: twe.c,v 1.1 2000/05/24 23:35:23 msmith Exp
   66  */
   67 
   68 /*
   69  * Driver for the 3ware Escalade family of RAID controllers.
   70  */
   71 
   72 #include <sys/cdefs.h>
   73 __KERNEL_RCSID(0, "$NetBSD: twe.c,v 1.54.2.2 2004/06/05 04:59:21 jmc Exp $");
   74 
   75 #include <sys/param.h>
   76 #include <sys/systm.h>
   77 #include <sys/kernel.h>
   78 #include <sys/device.h>
   79 #include <sys/queue.h>
   80 #include <sys/proc.h>
   81 #include <sys/buf.h>
   82 #include <sys/endian.h>
   83 #include <sys/malloc.h>
   84 #include <sys/conf.h>
   85 #include <sys/disk.h>
   86 
   87 #include <uvm/uvm_extern.h>
   88 
   89 #include <machine/bswap.h>
   90 #include <machine/bus.h>
   91 
   92 #include <dev/pci/pcireg.h>
   93 #include <dev/pci/pcivar.h>
   94 #include <dev/pci/pcidevs.h>
   95 #include <dev/pci/twereg.h>
   96 #include <dev/pci/twevar.h>
   97 #include <dev/pci/tweio.h>
   98 
   99 #define PCI_CBIO        0x10
  100 
  101 static int      twe_aen_get(struct twe_softc *, uint16_t *);
  102 static void     twe_aen_handler(struct twe_ccb *, int);
  103 static void     twe_aen_enqueue(struct twe_softc *sc, uint16_t, int);
  104 static uint16_t twe_aen_dequeue(struct twe_softc *);
  105 
  106 static void     twe_attach(struct device *, struct device *, void *);
  107 static int      twe_init_connection(struct twe_softc *);
  108 static int      twe_intr(void *);
  109 static int      twe_match(struct device *, struct cfdata *, void *);
  110 static int      twe_param_set(struct twe_softc *, int, int, size_t, void *);
  111 static void     twe_poll(struct twe_softc *);
  112 static int      twe_print(void *, const char *);
  113 static int      twe_reset(struct twe_softc *);
  114 static int      twe_submatch(struct device *, struct cfdata *, void *);
  115 static int      twe_status_check(struct twe_softc *, u_int);
  116 static int      twe_status_wait(struct twe_softc *, u_int, int);
  117 static void     twe_describe_controller(struct twe_softc *);
  118 
  119 static int      twe_add_unit(struct twe_softc *, int);
  120 static int      twe_del_unit(struct twe_softc *, int);
  121 
  122 static inline u_int32_t twe_inl(struct twe_softc *, int);
  123 static inline void twe_outl(struct twe_softc *, int, u_int32_t);
  124 
  125 dev_type_open(tweopen);
  126 dev_type_close(tweclose);
  127 dev_type_ioctl(tweioctl);
  128 
  129 const struct cdevsw twe_cdevsw = {
  130         tweopen, tweclose, noread, nowrite, tweioctl,
  131         nostop, notty, nopoll, nommap,
  132 };
  133 
  134 extern struct   cfdriver twe_cd; 
  135 
  136 CFATTACH_DECL(twe, sizeof(struct twe_softc),
  137     twe_match, twe_attach, NULL, NULL);
  138 
  139 /*
  140  * Tables to convert numeric codes to strings.
  141  */
  142 const struct twe_code_table twe_table_status[] = {
  143         { 0x00, "successful completion" },
  144 
  145         /* info */
  146         { 0x42, "command in progress" },
  147         { 0x6c, "retrying interface CRC error from UDMA command" },
  148 
  149         /* warning */
  150         { 0x81, "redundant/inconsequential request ignored" },
  151         { 0x8e, "failed to write zeroes to LBA 0" },
  152         { 0x8f, "failed to profile TwinStor zones" },
  153 
  154         /* fatal */
  155         { 0xc1, "aborted due to system command or reconfiguration" },
  156         { 0xc4, "aborted" },
  157         { 0xc5, "access error" },
  158         { 0xc6, "access violation" },
  159         { 0xc7, "device failure" },     /* high byte may be port # */
  160         { 0xc8, "controller error" },
  161         { 0xc9, "timed out" },
  162         { 0xcb, "invalid unit number" },
  163         { 0xcf, "unit not available" },
  164         { 0xd2, "undefined opcode" },
  165         { 0xdb, "request incompatible with unit" },
  166         { 0xdc, "invalid request" },
  167         { 0xff, "firmware error, reset requested" },
  168 
  169         { 0,    NULL }
  170 };
  171 
  172 const struct twe_code_table twe_table_unitstate[] = {
  173         { TWE_PARAM_UNITSTATUS_Normal,          "Normal" },
  174         { TWE_PARAM_UNITSTATUS_Initialising,    "Initializing" },
  175         { TWE_PARAM_UNITSTATUS_Degraded,        "Degraded" },
  176         { TWE_PARAM_UNITSTATUS_Rebuilding,      "Rebuilding" },
  177         { TWE_PARAM_UNITSTATUS_Verifying,       "Verifying" },
  178         { TWE_PARAM_UNITSTATUS_Corrupt,         "Corrupt" },
  179         { TWE_PARAM_UNITSTATUS_Missing,         "Missing" },
  180 
  181         { 0,                                    NULL }
  182 };
  183 
  184 const struct twe_code_table twe_table_unittype[] = {
  185         /* array descriptor configuration */
  186         { TWE_AD_CONFIG_RAID0,                  "RAID0" },
  187         { TWE_AD_CONFIG_RAID1,                  "RAID1" },
  188         { TWE_AD_CONFIG_TwinStor,               "TwinStor" },
  189         { TWE_AD_CONFIG_RAID5,                  "RAID5" },
  190         { TWE_AD_CONFIG_RAID10,                 "RAID10" },
  191 
  192         { 0,                                    NULL }
  193 };
  194 
  195 const struct twe_code_table twe_table_stripedepth[] = {
  196         { TWE_AD_STRIPE_4k,                     "4K" },
  197         { TWE_AD_STRIPE_8k,                     "8K" },
  198         { TWE_AD_STRIPE_16k,                    "16K" },
  199         { TWE_AD_STRIPE_32k,                    "32K" },
  200         { TWE_AD_STRIPE_64k,                    "64K" },
  201 
  202         { 0,                                    NULL }
  203 };
  204 
  205 /*
  206  * Asynchronous event notification messages are qualified:
  207  *      a - not unit/port specific
  208  *      u - unit specific
  209  *      p - port specific
  210  */
  211 const struct twe_code_table twe_table_aen[] = {
  212         { 0x00, "a queue empty" },
  213         { 0x01, "a soft reset" },
  214         { 0x02, "u degraded mode" },
  215         { 0x03, "a controller error" },
  216         { 0x04, "u rebuild fail" },
  217         { 0x05, "u rebuild done" },
  218         { 0x06, "u incomplete unit" },
  219         { 0x07, "u initialization done" },
  220         { 0x08, "u unclean shutdown detected" },
  221         { 0x09, "p drive timeout" },
  222         { 0x0a, "p drive error" },
  223         { 0x0b, "u rebuild started" },
  224         { 0x0c, "u initialization started" },
  225         { 0x0d, "u logical unit deleted" },
  226         { 0x0f, "p SMART threshold exceeded" },
  227         { 0x15, "a table undefined" },  /* XXX: Not in FreeBSD's table */
  228         { 0x21, "p ATA UDMA downgrade" },
  229         { 0x22, "p ATA UDMA upgrade" },
  230         { 0x23, "p sector repair occurred" },
  231         { 0x24, "a SBUF integrity check failure" },
  232         { 0x25, "p lost cached write" },
  233         { 0x26, "p drive ECC error detected" },
  234         { 0x27, "p DCB checksum error" },
  235         { 0x28, "p DCB unsupported version" },
  236         { 0x29, "u verify started" },
  237         { 0x2a, "u verify failed" },
  238         { 0x2b, "u verify complete" },
  239         { 0x2c, "p overwrote bad sector during rebuild" },
  240         { 0x2d, "p encountered bad sector during rebuild" },
  241         { 0x2e, "p replacement drive too small" },
  242         { 0x2f, "u array not previously initialized" },
  243         { 0x30, "p drive not supported" },
  244         { 0xff, "a aen queue full" },
  245 
  246         { 0,    NULL },
  247 };
  248 
  249 const char *
  250 twe_describe_code(const struct twe_code_table *table, uint32_t code)
  251 {
  252 
  253         for (; table->string != NULL; table++) {
  254                 if (table->code == code)
  255                         return (table->string);
  256         }
  257         return (NULL);
  258 }
  259 
  260 static inline u_int32_t
  261 twe_inl(struct twe_softc *sc, int off)
  262 {
  263 
  264         bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4,
  265             BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ);
  266         return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off));
  267 }
  268 
  269 static inline void
  270 twe_outl(struct twe_softc *sc, int off, u_int32_t val)
  271 {
  272 
  273         bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
  274         bus_space_barrier(sc->sc_iot, sc->sc_ioh, off, 4,
  275             BUS_SPACE_BARRIER_WRITE);
  276 }
  277 
  278 /*
  279  * Match a supported board.
  280  */
  281 static int
  282 twe_match(struct device *parent, struct cfdata *cfdata, void *aux)
  283 {
  284         struct pci_attach_args *pa;
  285 
  286         pa = aux;
  287 
  288         return (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3WARE &&     
  289             (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3WARE_ESCALADE ||
  290             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3WARE_ESCALADE_ASIC));
  291 }
  292 
  293 /*
  294  * Attach a supported board.
  295  *
  296  * XXX This doesn't fail gracefully.
  297  */
  298 static void
  299 twe_attach(struct device *parent, struct device *self, void *aux)
  300 {
  301         struct pci_attach_args *pa;
  302         struct twe_softc *sc;
  303         pci_chipset_tag_t pc;
  304         pci_intr_handle_t ih;
  305         pcireg_t csr;
  306         const char *intrstr;
  307         int s, size, i, rv, rseg;
  308         size_t max_segs, max_xfer;
  309         bus_dma_segment_t seg;
  310         struct twe_cmd *tc;
  311         struct twe_ccb *ccb;
  312 
  313         sc = (struct twe_softc *)self;
  314         pa = aux;
  315         pc = pa->pa_pc;
  316         sc->sc_dmat = pa->pa_dmat;
  317         SIMPLEQ_INIT(&sc->sc_ccb_queue);
  318         SLIST_INIT(&sc->sc_ccb_freelist);
  319 
  320         aprint_naive(": RAID controller\n");
  321         aprint_normal(": 3ware Escalade\n");
  322 
  323         ccb = malloc(sizeof(*ccb) * TWE_MAX_QUEUECNT, M_DEVBUF, M_NOWAIT);
  324         if (ccb == NULL) {
  325                 aprint_error("%s: unable to allocate memory for ccbs\n",
  326                     sc->sc_dv.dv_xname);
  327                 return;
  328         }
  329 
  330         if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
  331             &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
  332                 aprint_error("%s: can't map i/o space\n", sc->sc_dv.dv_xname);
  333                 return;
  334         }
  335 
  336         /* Enable the device. */
  337         csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
  338         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
  339             csr | PCI_COMMAND_MASTER_ENABLE);
  340 
  341         /* Map and establish the interrupt. */
  342         if (pci_intr_map(pa, &ih)) {
  343                 aprint_error("%s: can't map interrupt\n", sc->sc_dv.dv_xname);
  344                 return;
  345         }
  346 
  347         intrstr = pci_intr_string(pc, ih);
  348         sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, twe_intr, sc);
  349         if (sc->sc_ih == NULL) {
  350                 aprint_error("%s: can't establish interrupt%s%s\n",
  351                         sc->sc_dv.dv_xname,
  352                         (intrstr) ? " at " : "",
  353                         (intrstr) ? intrstr : "");
  354                 return;
  355         }
  356 
  357         if (intrstr != NULL)
  358                 aprint_normal("%s: interrupting at %s\n",
  359                         sc->sc_dv.dv_xname, intrstr);
  360 
  361         /*
  362          * Allocate and initialise the command blocks and CCBs.
  363          */
  364         size = sizeof(struct twe_cmd) * TWE_MAX_QUEUECNT;
  365 
  366         if ((rv = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 
  367             &rseg, BUS_DMA_NOWAIT)) != 0) {
  368                 aprint_error("%s: unable to allocate commands, rv = %d\n",
  369                     sc->sc_dv.dv_xname, rv);
  370                 return;
  371         }
  372 
  373         if ((rv = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 
  374             (caddr_t *)&sc->sc_cmds,
  375             BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  376                 aprint_error("%s: unable to map commands, rv = %d\n",
  377                     sc->sc_dv.dv_xname, rv);
  378                 return;
  379         }
  380 
  381         if ((rv = bus_dmamap_create(sc->sc_dmat, size, size, 1, 0, 
  382             BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
  383                 aprint_error("%s: unable to create command DMA map, rv = %d\n",
  384                     sc->sc_dv.dv_xname, rv);
  385                 return;
  386         }
  387 
  388         if ((rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_cmds, 
  389             size, NULL, BUS_DMA_NOWAIT)) != 0) {
  390                 aprint_error("%s: unable to load command DMA map, rv = %d\n",
  391                     sc->sc_dv.dv_xname, rv);
  392                 return;
  393         }
  394 
  395         sc->sc_cmds_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
  396         memset(sc->sc_cmds, 0, size);
  397 
  398         sc->sc_ccbs = ccb;
  399         tc = (struct twe_cmd *)sc->sc_cmds;
  400         max_segs = twe_get_maxsegs();
  401         max_xfer = twe_get_maxxfer(max_segs);
  402 
  403         for (i = 0; i < TWE_MAX_QUEUECNT; i++, tc++, ccb++) {
  404                 ccb->ccb_cmd = tc;
  405                 ccb->ccb_cmdid = i;
  406                 ccb->ccb_flags = 0;
  407                 rv = bus_dmamap_create(sc->sc_dmat, max_xfer,
  408                     max_segs, PAGE_SIZE, 0,
  409                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  410                     &ccb->ccb_dmamap_xfer);
  411                 if (rv != 0) {
  412                         aprint_error("%s: can't create dmamap, rv = %d\n",
  413                             sc->sc_dv.dv_xname, rv);
  414                         return;
  415                 }
  416 
  417                 /* Save the first CCB for AEN retrieval. */
  418                 if (i != 0)
  419                         SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb,
  420                             ccb_chain.slist);
  421         }
  422 
  423         /* Wait for the controller to become ready. */
  424         if (twe_status_wait(sc, TWE_STS_MICROCONTROLLER_READY, 6)) {
  425                 aprint_error("%s: microcontroller not ready\n",
  426                         sc->sc_dv.dv_xname);
  427                 return;
  428         }
  429 
  430         twe_outl(sc, TWE_REG_CTL, TWE_CTL_DISABLE_INTRS);
  431 
  432         /* Reset the controller. */
  433         s = splbio();
  434         rv = twe_reset(sc);
  435         splx(s);
  436         if (rv) {
  437                 aprint_error("%s: reset failed\n", sc->sc_dv.dv_xname);
  438                 return;
  439         }
  440 
  441         /* Initialise connection with controller. */
  442         twe_init_connection(sc);
  443 
  444         twe_describe_controller(sc);
  445 
  446         /* Find and attach RAID array units. */
  447         sc->sc_nunits = 0;
  448         for (i = 0; i < TWE_MAX_UNITS; i++)
  449                 (void) twe_add_unit(sc, i);
  450 
  451         /* ...and finally, enable interrupts. */
  452         twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR |
  453             TWE_CTL_UNMASK_RESP_INTR |
  454             TWE_CTL_ENABLE_INTRS);
  455 }
  456 
  457 void
  458 twe_register_callbacks(struct twe_softc *sc, int unit,
  459     const struct twe_callbacks *tcb)
  460 {
  461 
  462         sc->sc_units[unit].td_callbacks = tcb;
  463 }
  464 
  465 static void
  466 twe_recompute_openings(struct twe_softc *sc)
  467 {
  468         struct twe_drive *td;
  469         int unit, openings;
  470 
  471         if (sc->sc_nunits != 0)
  472                 openings = (TWE_MAX_QUEUECNT - 1) / sc->sc_nunits;
  473         else
  474                 openings = 0;
  475         if (openings == sc->sc_openings)
  476                 return;
  477         sc->sc_openings = openings;
  478 
  479 #ifdef TWE_DEBUG
  480         printf("%s: %d array%s, %d openings per array\n",
  481             sc->sc_dv.dv_xname, sc->sc_nunits,
  482             sc->sc_nunits == 1 ? "" : "s", sc->sc_openings);
  483 #endif
  484 
  485         for (unit = 0; unit < TWE_MAX_UNITS; unit++) {
  486                 td = &sc->sc_units[unit];
  487                 if (td->td_dev != NULL)
  488                         (*td->td_callbacks->tcb_openings)(td->td_dev,
  489                             sc->sc_openings);
  490         }
  491 }
  492 
  493 static int
  494 twe_add_unit(struct twe_softc *sc, int unit)
  495 {
  496         struct twe_param *dtp, *atp;
  497         struct twe_array_descriptor *ad;
  498         struct twe_drive *td;
  499         struct twe_attach_args twea;
  500         uint32_t newsize;
  501         int rv;
  502         uint16_t dsize;
  503         uint8_t newtype, newstripe;
  504 
  505         if (unit < 0 || unit >= TWE_MAX_UNITS)
  506                 return (EINVAL);
  507 
  508         /* Find attached units. */ 
  509         rv = twe_param_get(sc, TWE_PARAM_UNITSUMMARY,
  510             TWE_PARAM_UNITSUMMARY_Status, TWE_MAX_UNITS, NULL, &dtp);
  511         if (rv != 0) {
  512                 aprint_error("%s: error %d fetching unit summary\n",
  513                     sc->sc_dv.dv_xname, rv);
  514                 return (rv);
  515         }
  516 
  517         /* For each detected unit, collect size and store in an array. */
  518         td = &sc->sc_units[unit];
  519 
  520         /* Unit present? */
  521         if ((dtp->tp_data[unit] & TWE_PARAM_UNITSTATUS_Online) == 0) {
  522                 /*
  523                  * XXX Should we check to see if a device has been
  524                  * XXX attached at this index and detach it if it
  525                  * XXX has?  ("rescan" semantics)
  526                  */
  527                 rv = 0;
  528                 goto out;
  529         }
  530 
  531         rv = twe_param_get_2(sc, TWE_PARAM_UNITINFO + unit,
  532             TWE_PARAM_UNITINFO_DescriptorSize, &dsize);
  533         if (rv != 0) {
  534                 aprint_error("%s: error %d fetching descriptor size "
  535                     "for unit %d\n", sc->sc_dv.dv_xname, rv, unit);
  536                 goto out;
  537         }
  538 
  539         rv = twe_param_get(sc, TWE_PARAM_UNITINFO + unit,
  540             TWE_PARAM_UNITINFO_Descriptor, dsize - 3, NULL, &atp);
  541         if (rv != 0) {
  542                 aprint_error("%s: error %d fetching array descriptor "
  543                     "for unit %d\n", sc->sc_dv.dv_xname, rv, unit);
  544                 goto out;
  545         }
  546 
  547         ad = (struct twe_array_descriptor *)atp->tp_data;
  548         newtype = ad->configuration;
  549         newstripe = ad->stripe_size;
  550         free(atp, M_DEVBUF);
  551 
  552         rv = twe_param_get_4(sc, TWE_PARAM_UNITINFO + unit,
  553             TWE_PARAM_UNITINFO_Capacity, &newsize);
  554         if (rv != 0) {
  555                 aprint_error(
  556                     "%s: error %d fetching capacity for unit %d\n",
  557                     sc->sc_dv.dv_xname, rv, unit);
  558                 goto out;
  559         }
  560 
  561         /*
  562          * Have a device, so we need to attach it.  If there is currently
  563          * something sitting at the slot, and the parameters are different,
  564          * then we detach the old device before attaching the new one.
  565          */
  566         if (td->td_dev != NULL &&
  567             td->td_size == newsize &&
  568             td->td_type == newtype &&
  569             td->td_stripe == newstripe) {
  570                 /* Same as the old device; just keep using it. */
  571                 rv = 0;
  572                 goto out;
  573         } else if (td->td_dev != NULL) {
  574                 /* Detach the old device first. */
  575                 (void) config_detach(td->td_dev, DETACH_FORCE);
  576                 td->td_dev = NULL;
  577         } else if (td->td_size == 0)
  578                 sc->sc_nunits++;
  579 
  580         /*
  581          * Committed to the new array unit; assign its parameters and
  582          * recompute the number of available command openings.
  583          */
  584         td->td_size = newsize;
  585         td->td_type = newtype;
  586         td->td_stripe = newstripe;
  587         twe_recompute_openings(sc);
  588 
  589         twea.twea_unit = unit;
  590         td->td_dev = config_found_sm(&sc->sc_dv, &twea, twe_print,
  591             twe_submatch);
  592 
  593         rv = 0;
  594  out:
  595         free(dtp, M_DEVBUF);
  596         return (rv);
  597 }
  598 
  599 static int
  600 twe_del_unit(struct twe_softc *sc, int unit)
  601 {
  602         struct twe_drive *td;
  603 
  604         if (unit < 0 || unit >= TWE_MAX_UNITS)
  605                 return (EINVAL);
  606 
  607         td = &sc->sc_units[unit];
  608         if (td->td_size != 0)
  609                 sc->sc_nunits--;
  610         td->td_size = 0;
  611         td->td_type = 0;
  612         td->td_stripe = 0;
  613         if (td->td_dev != NULL) {
  614                 (void) config_detach(td->td_dev, DETACH_FORCE);
  615                 td->td_dev = NULL;
  616         }
  617         twe_recompute_openings(sc);
  618         return (0);
  619 }
  620 
  621 /*
  622  * Reset the controller.
  623  * MUST BE CALLED AT splbio()!
  624  */
  625 static int
  626 twe_reset(struct twe_softc *sc)
  627 {
  628         uint16_t aen;
  629         u_int status;
  630         volatile u_int32_t junk;
  631         int got, rv;
  632 
  633         /* Issue a soft reset. */
  634         twe_outl(sc, TWE_REG_CTL, TWE_CTL_ISSUE_SOFT_RESET |
  635             TWE_CTL_CLEAR_HOST_INTR |
  636             TWE_CTL_CLEAR_ATTN_INTR |
  637             TWE_CTL_MASK_CMD_INTR |
  638             TWE_CTL_MASK_RESP_INTR |
  639             TWE_CTL_CLEAR_ERROR_STS |
  640             TWE_CTL_DISABLE_INTRS);
  641 
  642         /* Wait for attention... */
  643         if (twe_status_wait(sc, TWE_STS_ATTN_INTR, 15)) {
  644                 printf("%s: no attention interrupt\n",
  645                     sc->sc_dv.dv_xname);
  646                 return (-1);
  647         }
  648 
  649         /* ...and ACK it. */
  650         twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR);
  651 
  652         /*
  653          * Pull AENs out of the controller; look for a soft reset AEN.
  654          * Open code this, since we want to detect reset even if the
  655          * queue for management tools is full.
  656          *
  657          * Note that since:
  658          *      - interrupts are blocked
  659          *      - we have reset the controller
  660          *      - acknowledged the pending ATTENTION
  661          * that there is no way a pending asynchronous AEN fetch would
  662          * finish, so clear the flag.
  663          */
  664         sc->sc_flags &= ~TWEF_AEN;
  665         for (got = 0;;) {
  666                 rv = twe_aen_get(sc, &aen);
  667                 if (rv != 0)
  668                         printf("%s: error %d while draining event queue\n",
  669                             sc->sc_dv.dv_xname, rv);
  670                 if (TWE_AEN_CODE(aen) == TWE_AEN_QUEUE_EMPTY)
  671                         break;
  672                 if (TWE_AEN_CODE(aen) == TWE_AEN_SOFT_RESET)
  673                         got = 1;
  674                 twe_aen_enqueue(sc, aen, 1);
  675         }
  676 
  677         if (!got) {
  678                 printf("%s: reset not reported\n", sc->sc_dv.dv_xname);
  679                 return (-1);
  680         }
  681 
  682         /* Check controller status. */
  683         status = twe_inl(sc, TWE_REG_STS);
  684         if (twe_status_check(sc, status)) {
  685                 printf("%s: controller errors detected\n",
  686                     sc->sc_dv.dv_xname);
  687                 return (-1);
  688         }
  689 
  690         /* Drain the response queue. */
  691         for (;;) {
  692                 status = twe_inl(sc, TWE_REG_STS);
  693                 if (twe_status_check(sc, status) != 0) {
  694                         printf("%s: can't drain response queue\n",
  695                             sc->sc_dv.dv_xname);
  696                         return (-1);
  697                 }
  698                 if ((status & TWE_STS_RESP_QUEUE_EMPTY) != 0)
  699                         break;
  700                 junk = twe_inl(sc, TWE_REG_RESP_QUEUE);
  701         }
  702 
  703         return (0);
  704 }
  705 
  706 /*
  707  * Print autoconfiguration message for a sub-device.
  708  */
  709 static int
  710 twe_print(void *aux, const char *pnp)
  711 {
  712         struct twe_attach_args *twea;
  713 
  714         twea = aux;
  715 
  716         if (pnp != NULL)
  717                 aprint_normal("block device at %s", pnp);
  718         aprint_normal(" unit %d", twea->twea_unit);
  719         return (UNCONF);
  720 }
  721 
  722 /*
  723  * Match a sub-device.
  724  */
  725 static int
  726 twe_submatch(struct device *parent, struct cfdata *cf, void *aux)
  727 {
  728         struct twe_attach_args *twea;
  729 
  730         twea = aux;
  731 
  732         if (cf->tweacf_unit != TWECF_UNIT_DEFAULT &&
  733             cf->tweacf_unit != twea->twea_unit)
  734                 return (0);
  735 
  736         return (config_match(parent, cf, aux));
  737 }
  738 
  739 /*
  740  * Interrupt service routine.
  741  */
  742 static int
  743 twe_intr(void *arg)
  744 {
  745         struct twe_softc *sc;
  746         u_int status;
  747         int caught, rv;
  748 
  749         sc = arg;
  750         caught = 0;
  751         status = twe_inl(sc, TWE_REG_STS);
  752         twe_status_check(sc, status);
  753 
  754         /* Host interrupts - purpose unknown. */
  755         if ((status & TWE_STS_HOST_INTR) != 0) {
  756 #ifdef DEBUG
  757                 printf("%s: host interrupt\n", sc->sc_dv.dv_xname);
  758 #endif
  759                 twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_HOST_INTR);
  760                 caught = 1;
  761         }
  762 
  763         /*
  764          * Attention interrupts, signalled when a controller or child device
  765          * state change has occurred.
  766          */
  767         if ((status & TWE_STS_ATTN_INTR) != 0) {
  768                 rv = twe_aen_get(sc, NULL);
  769                 if (rv != 0)
  770                         printf("%s: unable to retrieve AEN (%d)\n",
  771                             sc->sc_dv.dv_xname, rv);
  772                 else
  773                         twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR);
  774                 caught = 1;
  775         }
  776 
  777         /*
  778          * Command interrupts, signalled when the controller can accept more
  779          * commands.  We don't use this; instead, we try to submit commands
  780          * when we receive them, and when other commands have completed. 
  781          * Mask it so we don't get another one.
  782          */
  783         if ((status & TWE_STS_CMD_INTR) != 0) {
  784 #ifdef DEBUG
  785                 printf("%s: command interrupt\n", sc->sc_dv.dv_xname);
  786 #endif
  787                 twe_outl(sc, TWE_REG_CTL, TWE_CTL_MASK_CMD_INTR);
  788                 caught = 1;
  789         }
  790 
  791         if ((status & TWE_STS_RESP_INTR) != 0) {
  792                 twe_poll(sc);
  793                 caught = 1;
  794         }
  795 
  796         return (caught);
  797 }
  798 
  799 /*
  800  * Fetch an AEN.  Even though this is really like parameter
  801  * retrieval, we handle this specially, because we issue this
  802  * AEN retrieval command from interrupt context, and thus
  803  * reserve a CCB for it to avoid resource shortage.
  804  *
  805  * XXX There are still potential resource shortages we could
  806  * XXX encounter.  Consider pre-allocating all AEN-related
  807  * XXX resources.
  808  *
  809  * MUST BE CALLED AT splbio()!
  810  */
  811 static int
  812 twe_aen_get(struct twe_softc *sc, uint16_t *aenp)
  813 {
  814         struct twe_ccb *ccb;
  815         struct twe_cmd *tc;
  816         struct twe_param *tp;
  817         int rv;
  818 
  819         /*
  820          * If we're already retrieving an AEN, just wait; another
  821          * retrieval will be chained after the current one completes.
  822          */
  823         if (sc->sc_flags & TWEF_AEN) {
  824                 /*
  825                  * It is a fatal software programming error to attempt
  826                  * to fetch an AEN synchronously when an AEN fetch is
  827                  * already pending.
  828                  */
  829                 KASSERT(aenp == NULL);
  830                 return (0);
  831         }
  832 
  833         tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
  834         if (tp == NULL)
  835                 return (ENOMEM);
  836 
  837         ccb = twe_ccb_alloc(sc,
  838             TWE_CCB_AEN | TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
  839         KASSERT(ccb != NULL);
  840 
  841         ccb->ccb_data = tp;
  842         ccb->ccb_datasize = TWE_SECTOR_SIZE;
  843         ccb->ccb_tx.tx_handler = (aenp == NULL) ? twe_aen_handler : NULL;
  844         ccb->ccb_tx.tx_context = tp;
  845         ccb->ccb_tx.tx_dv = &sc->sc_dv;
  846 
  847         tc = ccb->ccb_cmd;
  848         tc->tc_size = 2;
  849         tc->tc_opcode = TWE_OP_GET_PARAM | (tc->tc_size << 5);
  850         tc->tc_unit = 0;
  851         tc->tc_count = htole16(1);
  852 
  853         /* Fill in the outbound parameter data. */
  854         tp->tp_table_id = htole16(TWE_PARAM_AEN);
  855         tp->tp_param_id = TWE_PARAM_AEN_UnitCode;
  856         tp->tp_param_size = 2;
  857 
  858         /* Map the transfer. */
  859         if ((rv = twe_ccb_map(sc, ccb)) != 0) {
  860                 twe_ccb_free(sc, ccb);
  861                 goto done;
  862         }
  863 
  864         /* Enqueue the command and wait. */
  865         if (aenp != NULL) {
  866                 rv = twe_ccb_poll(sc, ccb, 5);
  867                 twe_ccb_unmap(sc, ccb);
  868                 twe_ccb_free(sc, ccb);
  869                 if (rv == 0)
  870                         *aenp = le16toh(*(uint16_t *)tp->tp_data);
  871                 free(tp, M_DEVBUF);
  872         } else {
  873                 sc->sc_flags |= TWEF_AEN;
  874                 twe_ccb_enqueue(sc, ccb);
  875                 rv = 0;
  876         }
  877 
  878  done:
  879         return (rv);
  880 }
  881 
  882 /*
  883  * Handle an AEN returned by the controller.
  884  * MUST BE CALLED AT splbio()!
  885  */
  886 static void
  887 twe_aen_handler(struct twe_ccb *ccb, int error)
  888 {
  889         struct twe_softc *sc;
  890         struct twe_param *tp;
  891         uint16_t aen;
  892         int rv;
  893 
  894         sc = (struct twe_softc *)ccb->ccb_tx.tx_dv;
  895         tp = ccb->ccb_tx.tx_context;
  896         twe_ccb_unmap(sc, ccb);
  897 
  898         sc->sc_flags &= ~TWEF_AEN;
  899 
  900         if (error) {
  901                 printf("%s: error retrieving AEN\n", sc->sc_dv.dv_xname);
  902                 aen = TWE_AEN_QUEUE_EMPTY;
  903         } else
  904                 aen = le16toh(*(u_int16_t *)tp->tp_data);
  905         free(tp, M_DEVBUF);
  906         twe_ccb_free(sc, ccb);
  907 
  908         if (TWE_AEN_CODE(aen) == TWE_AEN_QUEUE_EMPTY) {
  909                 twe_outl(sc, TWE_REG_CTL, TWE_CTL_CLEAR_ATTN_INTR);
  910                 return;
  911         }
  912 
  913         twe_aen_enqueue(sc, aen, 0);
  914 
  915         /*
  916          * Chain another retrieval in case interrupts have been
  917          * coalesced.
  918          */
  919         rv = twe_aen_get(sc, NULL);
  920         if (rv != 0)
  921                 printf("%s: unable to retrieve AEN (%d)\n",
  922                     sc->sc_dv.dv_xname, rv);
  923 }
  924 
  925 static void
  926 twe_aen_enqueue(struct twe_softc *sc, uint16_t aen, int quiet)
  927 {
  928         const char *str, *msg;
  929         int s, next, nextnext;
  930 
  931         /*
  932          * First report the AEN on the console.  Maybe.
  933          */
  934         if (! quiet) {
  935                 str = twe_describe_code(twe_table_aen, TWE_AEN_CODE(aen));
  936                 if (str == NULL) {
  937                         printf("%s: unknown AEN 0x%04x\n",
  938                             sc->sc_dv.dv_xname, aen);
  939                 } else {
  940                         msg = str + 2;
  941                         switch (*str) {
  942                         case 'u':
  943                                 printf("%s: unit %d: %s\n",
  944                                     sc->sc_dv.dv_xname, TWE_AEN_UNIT(aen), msg);
  945                                 break;
  946 
  947                         case 'p':
  948                                 printf("%s: port %d: %s\n",
  949                                     sc->sc_dv.dv_xname, TWE_AEN_UNIT(aen), msg);
  950                                 break;
  951 
  952                         default:
  953                                 printf("%s: %s\n", sc->sc_dv.dv_xname, msg);
  954                         }
  955                 }
  956         }
  957 
  958         /* Now enqueue the AEN for mangement tools. */
  959         s = splbio();
  960 
  961         next = (sc->sc_aen_head + 1) % TWE_AEN_Q_LENGTH;
  962         nextnext = (sc->sc_aen_head + 2) % TWE_AEN_Q_LENGTH;
  963 
  964         /*
  965          * If this is the last free slot, then queue up a "queue
  966          * full" message.
  967          */
  968         if (nextnext == sc->sc_aen_tail)
  969                 aen = TWE_AEN_QUEUE_FULL;
  970 
  971         if (next != sc->sc_aen_tail) {
  972                 sc->sc_aen_queue[sc->sc_aen_head] = aen;
  973                 sc->sc_aen_head = next;
  974         }
  975 
  976         if (sc->sc_flags & TWEF_AENQ_WAIT) {
  977                 sc->sc_flags &= ~TWEF_AENQ_WAIT;
  978                 wakeup(&sc->sc_aen_queue);
  979         }
  980 
  981         splx(s);
  982 }
  983 
  984 /* NOTE: Must be called at splbio(). */
  985 static uint16_t
  986 twe_aen_dequeue(struct twe_softc *sc)
  987 {
  988         uint16_t aen;
  989 
  990         if (sc->sc_aen_tail == sc->sc_aen_head)
  991                 aen = TWE_AEN_QUEUE_EMPTY;
  992         else {
  993                 aen = sc->sc_aen_queue[sc->sc_aen_tail];
  994                 sc->sc_aen_tail = (sc->sc_aen_tail + 1) & TWE_AEN_Q_LENGTH;
  995         }
  996 
  997         return (aen);
  998 }
  999 
 1000 /*
 1001  * These are short-hand functions that execute TWE_OP_GET_PARAM to
 1002  * fetch 1, 2, and 4 byte parameter values, respectively.
 1003  */
 1004 int
 1005 twe_param_get_1(struct twe_softc *sc, int table_id, int param_id,
 1006     uint8_t *valp)
 1007 {
 1008         struct twe_param *tp;
 1009         int rv;
 1010 
 1011         rv = twe_param_get(sc, table_id, param_id, 1, NULL, &tp);
 1012         if (rv != 0)
 1013                 return (rv);
 1014         *valp = *(uint8_t *)tp->tp_data;
 1015         free(tp, M_DEVBUF);
 1016         return (0);
 1017 }
 1018 
 1019 int
 1020 twe_param_get_2(struct twe_softc *sc, int table_id, int param_id,
 1021     uint16_t *valp)
 1022 {
 1023         struct twe_param *tp;
 1024         int rv;
 1025 
 1026         rv = twe_param_get(sc, table_id, param_id, 2, NULL, &tp);
 1027         if (rv != 0)
 1028                 return (rv);
 1029         *valp = le16toh(*(uint16_t *)tp->tp_data);
 1030         free(tp, M_DEVBUF);
 1031         return (0);
 1032 }
 1033 
 1034 int
 1035 twe_param_get_4(struct twe_softc *sc, int table_id, int param_id,
 1036     uint32_t *valp)
 1037 {
 1038         struct twe_param *tp;
 1039         int rv;
 1040 
 1041         rv = twe_param_get(sc, table_id, param_id, 4, NULL, &tp);
 1042         if (rv != 0)
 1043                 return (rv);
 1044         *valp = le32toh(*(uint32_t *)tp->tp_data);
 1045         free(tp, M_DEVBUF);
 1046         return (0);
 1047 }
 1048 
 1049 /*
 1050  * Execute a TWE_OP_GET_PARAM command.  If a callback function is provided,
 1051  * it will be called with generated context when the command has completed. 
 1052  * If no callback is provided, the command will be executed synchronously
 1053  * and a pointer to a buffer containing the data returned.
 1054  *
 1055  * The caller or callback is responsible for freeing the buffer.
 1056  *
 1057  * NOTE: We assume we can sleep here to wait for a CCB to become available.
 1058  */
 1059 int
 1060 twe_param_get(struct twe_softc *sc, int table_id, int param_id, size_t size,
 1061               void (*func)(struct twe_ccb *, int), struct twe_param **pbuf)
 1062 {
 1063         struct twe_ccb *ccb;
 1064         struct twe_cmd *tc;
 1065         struct twe_param *tp;
 1066         int rv, s;
 1067 
 1068         tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
 1069         if (tp == NULL)
 1070                 return ENOMEM;
 1071 
 1072         ccb = twe_ccb_alloc_wait(sc, TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
 1073         KASSERT(ccb != NULL);
 1074 
 1075         ccb->ccb_data = tp;
 1076         ccb->ccb_datasize = TWE_SECTOR_SIZE;
 1077         ccb->ccb_tx.tx_handler = func;
 1078         ccb->ccb_tx.tx_context = tp;
 1079         ccb->ccb_tx.tx_dv = &sc->sc_dv;
 1080 
 1081         tc = ccb->ccb_cmd;
 1082         tc->tc_size = 2;
 1083         tc->tc_opcode = TWE_OP_GET_PARAM | (tc->tc_size << 5);
 1084         tc->tc_unit = 0;
 1085         tc->tc_count = htole16(1);
 1086 
 1087         /* Fill in the outbound parameter data. */
 1088         tp->tp_table_id = htole16(table_id);
 1089         tp->tp_param_id = param_id;
 1090         tp->tp_param_size = size;
 1091 
 1092         /* Map the transfer. */
 1093         if ((rv = twe_ccb_map(sc, ccb)) != 0) {
 1094                 twe_ccb_free(sc, ccb);
 1095                 goto done;
 1096         }
 1097 
 1098         /* Submit the command and either wait or let the callback handle it. */
 1099         if (func == NULL) {
 1100                 s = splbio();
 1101                 rv = twe_ccb_poll(sc, ccb, 5);
 1102                 twe_ccb_unmap(sc, ccb);
 1103                 twe_ccb_free(sc, ccb);
 1104                 splx(s);
 1105         } else {
 1106 #ifdef DEBUG
 1107                 if (pbuf != NULL)
 1108                         panic("both func and pbuf defined");
 1109 #endif
 1110                 twe_ccb_enqueue(sc, ccb);
 1111                 return 0;
 1112         }
 1113 
 1114 done:
 1115         if (pbuf == NULL || rv != 0)
 1116                 free(tp, M_DEVBUF);
 1117         else if (pbuf != NULL && rv == 0)
 1118                 *pbuf = tp;
 1119         return rv;
 1120 }
 1121 
 1122 /*
 1123  * Execute a TWE_OP_SET_PARAM command.
 1124  *
 1125  * NOTE: We assume we can sleep here to wait for a CCB to become available.
 1126  */
 1127 static int
 1128 twe_param_set(struct twe_softc *sc, int table_id, int param_id, size_t size,
 1129               void *buf)
 1130 {
 1131         struct twe_ccb *ccb;
 1132         struct twe_cmd *tc;
 1133         struct twe_param *tp;
 1134         int rv, s;
 1135 
 1136         tp = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_NOWAIT);
 1137         if (tp == NULL)
 1138                 return ENOMEM;
 1139 
 1140         ccb = twe_ccb_alloc_wait(sc, TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
 1141         KASSERT(ccb != NULL);
 1142 
 1143         ccb->ccb_data = tp;
 1144         ccb->ccb_datasize = TWE_SECTOR_SIZE;
 1145         ccb->ccb_tx.tx_handler = 0;
 1146         ccb->ccb_tx.tx_context = tp;
 1147         ccb->ccb_tx.tx_dv = &sc->sc_dv;
 1148 
 1149         tc = ccb->ccb_cmd;
 1150         tc->tc_size = 2;
 1151         tc->tc_opcode = TWE_OP_SET_PARAM | (tc->tc_size << 5);
 1152         tc->tc_unit = 0;
 1153         tc->tc_count = htole16(1);
 1154 
 1155         /* Fill in the outbound parameter data. */
 1156         tp->tp_table_id = htole16(table_id);
 1157         tp->tp_param_id = param_id;
 1158         tp->tp_param_size = size;
 1159         memcpy(tp->tp_data, buf, size);
 1160 
 1161         /* Map the transfer. */
 1162         if ((rv = twe_ccb_map(sc, ccb)) != 0) {
 1163                 twe_ccb_free(sc, ccb);
 1164                 goto done;
 1165         }
 1166 
 1167         /* Submit the command and wait. */
 1168         s = splbio();
 1169         rv = twe_ccb_poll(sc, ccb, 5);
 1170         twe_ccb_unmap(sc, ccb);
 1171         twe_ccb_free(sc, ccb);
 1172         splx(s);
 1173 done:
 1174         free(tp, M_DEVBUF);
 1175         return (rv);
 1176 }
 1177 
 1178 /*
 1179  * Execute a TWE_OP_INIT_CONNECTION command.  Return non-zero on error. 
 1180  * Must be called with interrupts blocked.
 1181  */
 1182 static int
 1183 twe_init_connection(struct twe_softc *sc)
 1184 /*###762 [cc] warning: `twe_init_connection' was used with no prototype before its definition%%%*/
 1185 /*###762 [cc] warning: `twe_init_connection' was declared implicitly `extern' and later `static'%%%*/
 1186 {
 1187         struct twe_ccb *ccb;
 1188         struct twe_cmd *tc;
 1189         int rv;
 1190 
 1191         if ((ccb = twe_ccb_alloc(sc, 0)) == NULL)
 1192                 return (EAGAIN);
 1193 
 1194         /* Build the command. */
 1195         tc = ccb->ccb_cmd;
 1196         tc->tc_size = 3;
 1197         tc->tc_opcode = TWE_OP_INIT_CONNECTION;
 1198         tc->tc_unit = 0;
 1199         tc->tc_count = htole16(TWE_MAX_CMDS);
 1200         tc->tc_args.init_connection.response_queue_pointer = 0;
 1201 
 1202         /* Submit the command for immediate execution. */
 1203         rv = twe_ccb_poll(sc, ccb, 5);
 1204         twe_ccb_free(sc, ccb);
 1205         return (rv);
 1206 }
 1207 
 1208 /*
 1209  * Poll the controller for completed commands.  Must be called with
 1210  * interrupts blocked.
 1211  */
 1212 static void
 1213 twe_poll(struct twe_softc *sc)
 1214 {
 1215         struct twe_ccb *ccb;
 1216         int found;
 1217         u_int status, cmdid;
 1218 
 1219         found = 0;
 1220 
 1221         for (;;) {
 1222                 status = twe_inl(sc, TWE_REG_STS);
 1223                 twe_status_check(sc, status);
 1224 
 1225                 if ((status & TWE_STS_RESP_QUEUE_EMPTY))
 1226                         break;
 1227 
 1228                 found = 1;
 1229                 cmdid = twe_inl(sc, TWE_REG_RESP_QUEUE);
 1230                 cmdid = (cmdid & TWE_RESP_MASK) >> TWE_RESP_SHIFT;
 1231                 if (cmdid >= TWE_MAX_QUEUECNT) {
 1232                         printf("%s: bad cmdid %d\n", sc->sc_dv.dv_xname, cmdid);
 1233                         continue;
 1234                 }
 1235 
 1236                 ccb = sc->sc_ccbs + cmdid;
 1237                 if ((ccb->ccb_flags & TWE_CCB_ACTIVE) == 0) {
 1238                         printf("%s: CCB for cmdid %d not active\n",
 1239                             sc->sc_dv.dv_xname, cmdid);
 1240                         continue;
 1241                 }
 1242                 ccb->ccb_flags ^= TWE_CCB_COMPLETE | TWE_CCB_ACTIVE;
 1243 
 1244                 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
 1245                     (caddr_t)ccb->ccb_cmd - sc->sc_cmds,
 1246                     sizeof(struct twe_cmd),
 1247                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1248 
 1249                 /* Pass notification to upper layers. */
 1250                 if (ccb->ccb_tx.tx_handler != NULL)
 1251                         (*ccb->ccb_tx.tx_handler)(ccb,
 1252                             ccb->ccb_cmd->tc_status != 0 ? EIO : 0);
 1253         }
 1254 
 1255         /* If any commands have completed, run the software queue. */
 1256         if (found)
 1257                 twe_ccb_enqueue(sc, NULL);
 1258 }
 1259 
 1260 /*
 1261  * Wait for `status' to be set in the controller status register.  Return
 1262  * zero if found, non-zero if the operation timed out.
 1263  */
 1264 static int
 1265 twe_status_wait(struct twe_softc *sc, u_int32_t status, int timo)
 1266 {
 1267 
 1268         for (timo *= 10; timo != 0; timo--) {
 1269                 if ((twe_inl(sc, TWE_REG_STS) & status) == status)
 1270                         break;
 1271                 delay(100000);
 1272         }
 1273 
 1274         return (timo == 0);
 1275 }
 1276 
 1277 /*
 1278  * Complain if the status bits aren't what we expect.
 1279  */
 1280 static int
 1281 twe_status_check(struct twe_softc *sc, u_int status)
 1282 {
 1283         int rv;
 1284 
 1285         rv = 0;
 1286 
 1287         if ((status & TWE_STS_EXPECTED_BITS) != TWE_STS_EXPECTED_BITS) {
 1288                 printf("%s: missing status bits: 0x%08x\n", sc->sc_dv.dv_xname,
 1289                     status & ~TWE_STS_EXPECTED_BITS);
 1290                 rv = -1;
 1291         }
 1292 
 1293         if ((status & TWE_STS_UNEXPECTED_BITS) != 0) {
 1294                 printf("%s: unexpected status bits: 0x%08x\n",
 1295                     sc->sc_dv.dv_xname, status & TWE_STS_UNEXPECTED_BITS);
 1296                 rv = -1;
 1297         }
 1298 
 1299         return (rv);
 1300 }
 1301 
 1302 /*
 1303  * Allocate and initialise a CCB.
 1304  */
 1305 static __inline void
 1306 twe_ccb_init(struct twe_softc *sc, struct twe_ccb *ccb, int flags)
 1307 {
 1308         struct twe_cmd *tc;
 1309 
 1310         ccb->ccb_tx.tx_handler = NULL;
 1311         ccb->ccb_flags = flags;
 1312         tc = ccb->ccb_cmd;
 1313         tc->tc_status = 0;
 1314         tc->tc_flags = 0;
 1315         tc->tc_cmdid = ccb->ccb_cmdid;
 1316 }
 1317 
 1318 struct twe_ccb *
 1319 twe_ccb_alloc(struct twe_softc *sc, int flags)
 1320 {
 1321         struct twe_ccb *ccb;
 1322         int s;
 1323 
 1324         s = splbio();   
 1325         if (__predict_false((flags & TWE_CCB_AEN) != 0)) {
 1326                 /* Use the reserved CCB. */
 1327                 ccb = sc->sc_ccbs;
 1328         } else {
 1329                 /* Allocate a CCB and command block. */
 1330                 if (__predict_false((ccb =
 1331                                 SLIST_FIRST(&sc->sc_ccb_freelist)) == NULL)) {
 1332                         splx(s);
 1333                         return (NULL);
 1334                 }
 1335                 SLIST_REMOVE_HEAD(&sc->sc_ccb_freelist, ccb_chain.slist);
 1336         }
 1337 #ifdef DIAGNOSTIC
 1338         if ((long)(ccb - sc->sc_ccbs) == 0 && (flags & TWE_CCB_AEN) == 0)
 1339                 panic("twe_ccb_alloc: got reserved CCB for non-AEN");
 1340         if ((ccb->ccb_flags & TWE_CCB_ALLOCED) != 0)
 1341                 panic("twe_ccb_alloc: CCB %ld already allocated",
 1342                     (long)(ccb - sc->sc_ccbs));
 1343         flags |= TWE_CCB_ALLOCED;
 1344 #endif
 1345         splx(s);
 1346 
 1347         twe_ccb_init(sc, ccb, flags);
 1348         return (ccb);
 1349 }
 1350 
 1351 struct twe_ccb *
 1352 twe_ccb_alloc_wait(struct twe_softc *sc, int flags)
 1353 {
 1354         struct twe_ccb *ccb;
 1355         int s;
 1356 
 1357         KASSERT((flags & TWE_CCB_AEN) == 0);
 1358 
 1359         s = splbio();
 1360         while (__predict_false((ccb =
 1361                                 SLIST_FIRST(&sc->sc_ccb_freelist)) == NULL)) {
 1362                 sc->sc_flags |= TWEF_WAIT_CCB;
 1363                 (void) tsleep(&sc->sc_ccb_freelist, PRIBIO, "tweccb", 0);
 1364         }
 1365         SLIST_REMOVE_HEAD(&sc->sc_ccb_freelist, ccb_chain.slist);
 1366 #ifdef DIAGNOSTIC
 1367         if ((ccb->ccb_flags & TWE_CCB_ALLOCED) != 0)
 1368                 panic("twe_ccb_alloc_wait: CCB %ld already allocated",
 1369                     (long)(ccb - sc->sc_ccbs));
 1370         flags |= TWE_CCB_ALLOCED;
 1371 #endif
 1372         splx(s);
 1373 
 1374         twe_ccb_init(sc, ccb, flags);
 1375         return (ccb);
 1376 }
 1377 
 1378 /*
 1379  * Free a CCB.
 1380  */
 1381 void
 1382 twe_ccb_free(struct twe_softc *sc, struct twe_ccb *ccb)
 1383 {
 1384         int s;
 1385 
 1386         s = splbio();
 1387         if ((ccb->ccb_flags & TWE_CCB_AEN) == 0) {
 1388                 SLIST_INSERT_HEAD(&sc->sc_ccb_freelist, ccb, ccb_chain.slist);
 1389                 if (__predict_false((sc->sc_flags & TWEF_WAIT_CCB) != 0)) {
 1390                         sc->sc_flags &= ~TWEF_WAIT_CCB;
 1391                         wakeup(&sc->sc_ccb_freelist);
 1392                 }
 1393         }
 1394         ccb->ccb_flags = 0;
 1395         splx(s);
 1396 }
 1397 
 1398 /*
 1399  * Map the specified CCB's command block and data buffer (if any) into
 1400  * controller visible space.  Perform DMA synchronisation.
 1401  */
 1402 int
 1403 twe_ccb_map(struct twe_softc *sc, struct twe_ccb *ccb)
 1404 {
 1405         struct twe_cmd *tc;
 1406         int flags, nsegs, i, s, rv;
 1407         void *data;
 1408 
 1409         /*
 1410          * The data as a whole must be 512-byte aligned.
 1411          */
 1412         if (((u_long)ccb->ccb_data & (TWE_ALIGNMENT - 1)) != 0) {
 1413                 s = splvm();
 1414                 /* XXX */
 1415                 ccb->ccb_abuf = uvm_km_kmemalloc(kmem_map, NULL,
 1416                     ccb->ccb_datasize, UVM_KMF_NOWAIT);
 1417                 splx(s);
 1418                 data = (void *)ccb->ccb_abuf;
 1419                 if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0)
 1420                         memcpy(data, ccb->ccb_data, ccb->ccb_datasize);
 1421         } else {
 1422                 ccb->ccb_abuf = (vaddr_t)0;
 1423                 data = ccb->ccb_data;
 1424         }
 1425 
 1426         /*
 1427          * Map the data buffer into bus space and build the S/G list.
 1428          */
 1429         rv = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, data,
 1430             ccb->ccb_datasize, NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
 1431             ((ccb->ccb_flags & TWE_CCB_DATA_IN) ?
 1432             BUS_DMA_READ : BUS_DMA_WRITE));
 1433         if (rv != 0) {
 1434                 if (ccb->ccb_abuf != (vaddr_t)0) {
 1435                         s = splvm();
 1436                         /* XXX */
 1437                         uvm_km_free(kmem_map, ccb->ccb_abuf,
 1438                             ccb->ccb_datasize);
 1439                         splx(s);
 1440                 }
 1441                 return (rv);
 1442         }
 1443 
 1444         nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
 1445         tc = ccb->ccb_cmd;
 1446         tc->tc_size += 2 * nsegs;
 1447 
 1448         /* The location of the S/G list is dependant upon command type. */
 1449         switch (tc->tc_opcode >> 5) {
 1450         case 2:
 1451                 for (i = 0; i < nsegs; i++) {
 1452                         tc->tc_args.param.sgl[i].tsg_address =
 1453                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
 1454                         tc->tc_args.param.sgl[i].tsg_length =
 1455                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
 1456                 }
 1457                 /* XXX Needed? */
 1458                 for (; i < TWE_SG_SIZE; i++) {
 1459                         tc->tc_args.param.sgl[i].tsg_address = 0;
 1460                         tc->tc_args.param.sgl[i].tsg_length = 0;
 1461                 }
 1462                 break;
 1463         case 3:
 1464                 for (i = 0; i < nsegs; i++) {
 1465                         tc->tc_args.io.sgl[i].tsg_address =
 1466                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
 1467                         tc->tc_args.io.sgl[i].tsg_length =
 1468                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
 1469                 }
 1470                 /* XXX Needed? */
 1471                 for (; i < TWE_SG_SIZE; i++) {
 1472                         tc->tc_args.io.sgl[i].tsg_address = 0;
 1473                         tc->tc_args.io.sgl[i].tsg_length = 0;
 1474                 }
 1475                 break;
 1476         default:
 1477                 /*
 1478                  * In all likelihood, this is a command passed from
 1479                  * management tools in userspace where no S/G list is
 1480                  * necessary because no data is being passed.
 1481                  */
 1482                 break;
 1483         }
 1484 
 1485         if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0)
 1486                 flags = BUS_DMASYNC_PREREAD;
 1487         else
 1488                 flags = 0;
 1489         if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0)
 1490                 flags |= BUS_DMASYNC_PREWRITE;
 1491 
 1492         bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
 1493             ccb->ccb_datasize, flags);
 1494         return (0);
 1495 }
 1496 
 1497 /*
 1498  * Unmap the specified CCB's command block and data buffer (if any) and
 1499  * perform DMA synchronisation.
 1500  */
 1501 void
 1502 twe_ccb_unmap(struct twe_softc *sc, struct twe_ccb *ccb)
 1503 {
 1504         int flags, s;
 1505 
 1506         if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0)
 1507                 flags = BUS_DMASYNC_POSTREAD;
 1508         else
 1509                 flags = 0;
 1510         if ((ccb->ccb_flags & TWE_CCB_DATA_OUT) != 0)
 1511                 flags |= BUS_DMASYNC_POSTWRITE;
 1512 
 1513         bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
 1514             ccb->ccb_datasize, flags);
 1515         bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
 1516 
 1517         if (ccb->ccb_abuf != (vaddr_t)0) {
 1518                 if ((ccb->ccb_flags & TWE_CCB_DATA_IN) != 0)
 1519                         memcpy(ccb->ccb_data, (void *)ccb->ccb_abuf,
 1520                             ccb->ccb_datasize);
 1521                 s = splvm();
 1522                 /* XXX */
 1523                 uvm_km_free(kmem_map, ccb->ccb_abuf, ccb->ccb_datasize);
 1524                 splx(s);
 1525         }
 1526 }
 1527 
 1528 /*
 1529  * Submit a command to the controller and poll on completion.  Return
 1530  * non-zero on timeout (but don't check status, as some command types don't
 1531  * return status).  Must be called with interrupts blocked.
 1532  */
 1533 int
 1534 twe_ccb_poll(struct twe_softc *sc, struct twe_ccb *ccb, int timo)
 1535 {
 1536         int rv;
 1537 
 1538         if ((rv = twe_ccb_submit(sc, ccb)) != 0)
 1539                 return (rv);
 1540 
 1541         for (timo *= 1000; timo != 0; timo--) {
 1542                 twe_poll(sc);
 1543                 if ((ccb->ccb_flags & TWE_CCB_COMPLETE) != 0)
 1544                         break;
 1545                 DELAY(100);
 1546         }
 1547 
 1548         return (timo == 0);
 1549 }
 1550 
 1551 /*
 1552  * If a CCB is specified, enqueue it.  Pull CCBs off the software queue in
 1553  * the order that they were enqueued and try to submit their command blocks
 1554  * to the controller for execution.
 1555  */
 1556 void
 1557 twe_ccb_enqueue(struct twe_softc *sc, struct twe_ccb *ccb)
 1558 {
 1559         int s;
 1560 
 1561         s = splbio();
 1562 
 1563         if (ccb != NULL)
 1564                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain.simpleq);
 1565 
 1566         while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) {
 1567                 if (twe_ccb_submit(sc, ccb))
 1568                         break;
 1569                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain.simpleq);
 1570         }
 1571 
 1572         splx(s);
 1573 }
 1574 
 1575 /*
 1576  * Submit the command block associated with the specified CCB to the
 1577  * controller for execution.  Must be called with interrupts blocked.
 1578  */
 1579 int
 1580 twe_ccb_submit(struct twe_softc *sc, struct twe_ccb *ccb)
 1581 {
 1582         bus_addr_t pa;
 1583         int rv;
 1584         u_int status;
 1585 
 1586         /* Check to see if we can post a command. */
 1587         status = twe_inl(sc, TWE_REG_STS);
 1588         twe_status_check(sc, status);
 1589 
 1590         if ((status & TWE_STS_CMD_QUEUE_FULL) == 0) {
 1591                 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
 1592                     (caddr_t)ccb->ccb_cmd - sc->sc_cmds, sizeof(struct twe_cmd),
 1593                     BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 1594 #ifdef DIAGNOSTIC
 1595                 if ((ccb->ccb_flags & TWE_CCB_ALLOCED) == 0)
 1596                         panic("%s: CCB %ld not ALLOCED\n",
 1597                             sc->sc_dv.dv_xname, (long)(ccb - sc->sc_ccbs));
 1598 #endif
 1599                 ccb->ccb_flags |= TWE_CCB_ACTIVE;
 1600                 pa = sc->sc_cmds_paddr +
 1601                     ccb->ccb_cmdid * sizeof(struct twe_cmd);
 1602                 twe_outl(sc, TWE_REG_CMD_QUEUE, (u_int32_t)pa);
 1603                 rv = 0;
 1604         } else
 1605                 rv = EBUSY;
 1606 
 1607         return (rv);
 1608 }
 1609 
 1610 
 1611 /*
 1612  * Accept an open operation on the control device.
 1613  */
 1614 int
 1615 tweopen(dev_t dev, int flag, int mode, struct proc *p)
 1616 {
 1617         struct twe_softc *twe;
 1618 
 1619         if ((twe = device_lookup(&twe_cd, minor(dev))) == NULL)
 1620                 return (ENXIO);
 1621         if ((twe->sc_flags & TWEF_OPEN) != 0)
 1622                 return (EBUSY);
 1623 
 1624         twe->sc_flags |= TWEF_OPEN;
 1625         return (0);
 1626 }
 1627 
 1628 /*
 1629  * Accept the last close on the control device.
 1630  */
 1631 int
 1632 tweclose(dev_t dev, int flag, int mode, struct proc *p)
 1633 {
 1634         struct twe_softc *twe;
 1635 
 1636         twe = device_lookup(&twe_cd, minor(dev));
 1637         twe->sc_flags &= ~TWEF_OPEN;
 1638         return (0);
 1639 }
 1640 
 1641 void
 1642 twe_ccb_wait_handler(struct twe_ccb *ccb, int error)
 1643 {
 1644 
 1645         /* Just wake up the sleeper. */
 1646         wakeup(ccb);
 1647 }
 1648 
 1649 /*
 1650  * Handle control operations.
 1651  */
 1652 int
 1653 tweioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
 1654 {
 1655         struct twe_softc *twe;
 1656         struct twe_ccb *ccb;
 1657         struct twe_param *param;
 1658         struct twe_usercommand *tu;
 1659         struct twe_paramcommand *tp;
 1660         struct twe_drivecommand *td;
 1661         void *pdata = NULL;
 1662         int s, error = 0;
 1663         u_int8_t cmdid;
 1664 
 1665         if (securelevel >= 2)
 1666                 return (EPERM);
 1667 
 1668         twe = device_lookup(&twe_cd, minor(dev));
 1669         tu = (struct twe_usercommand *)data;
 1670         tp = (struct twe_paramcommand *)data;
 1671         td = (struct twe_drivecommand *)data;
 1672 
 1673         /* This is intended to be compatible with the FreeBSD interface. */
 1674         switch (cmd) {
 1675         case TWEIO_COMMAND:
 1676                 /* XXX mutex */
 1677                 if (tu->tu_size > 0) {
 1678                         /*
 1679                          * XXX Handle > TWE_SECTOR_SIZE?  Let's see if
 1680                          * it's really necessary, first.
 1681                          */
 1682                         if (tu->tu_size > TWE_SECTOR_SIZE) {
 1683 #ifdef TWE_DEBUG
 1684                                 printf("%s: TWEIO_COMMAND: tu_size = %d\n",
 1685                                     twe->sc_dv.dv_xname, tu->tu_size);
 1686 #endif
 1687                                 return EINVAL;
 1688                         }
 1689                         pdata = malloc(TWE_SECTOR_SIZE, M_DEVBUF, M_WAITOK);
 1690                         error = copyin(tu->tu_data, pdata, tu->tu_size);
 1691                         if (error != 0)
 1692                                 goto done;
 1693                         ccb = twe_ccb_alloc_wait(twe,
 1694                             TWE_CCB_DATA_IN | TWE_CCB_DATA_OUT);
 1695                         KASSERT(ccb != NULL);
 1696                         ccb->ccb_data = pdata;
 1697                         ccb->ccb_datasize = TWE_SECTOR_SIZE;
 1698                 } else {
 1699                         ccb = twe_ccb_alloc_wait(twe, 0);
 1700                         KASSERT(ccb != NULL);
 1701                 }
 1702 
 1703                 ccb->ccb_tx.tx_handler = twe_ccb_wait_handler;
 1704                 ccb->ccb_tx.tx_context = NULL;
 1705                 ccb->ccb_tx.tx_dv = &twe->sc_dv;
 1706 
 1707                 cmdid = ccb->ccb_cmdid;
 1708                 memcpy(ccb->ccb_cmd, &tu->tu_cmd, sizeof(struct twe_cmd));
 1709                 ccb->ccb_cmd->tc_cmdid = cmdid;
 1710 
 1711                 /* Map the transfer. */
 1712                 if ((error = twe_ccb_map(twe, ccb)) != 0) {
 1713                         twe_ccb_free(twe, ccb);
 1714                         goto done;
 1715                 }
 1716 
 1717                 /* Submit the command and wait up to 1 minute. */
 1718                 error = 0;
 1719                 twe_ccb_enqueue(twe, ccb);
 1720                 s = splbio();
 1721                 while ((ccb->ccb_flags & TWE_CCB_COMPLETE) == 0)
 1722                         if ((error = tsleep(ccb, PRIBIO, "tweioctl",
 1723                                             60 * hz)) != 0)
 1724                                 break;
 1725                 splx(s);
 1726 
 1727                 /* Copy the command back to the ioctl argument. */
 1728                 memcpy(&tu->tu_cmd, ccb->ccb_cmd, sizeof(struct twe_cmd));
 1729 #ifdef TWE_DEBUG
 1730                 printf("%s: TWEIO_COMMAND: tc_opcode = 0x%02x, "
 1731                     "tc_status = 0x%02x\n", twe->sc_dv.dv_xname,
 1732                     tu->tu_cmd.tc_opcode, tu->tu_cmd.tc_status);
 1733 #endif
 1734 
 1735                 s = splbio();
 1736                 twe_ccb_free(twe, ccb);
 1737                 splx(s);
 1738 
 1739                 if (tu->tu_size > 0)
 1740                         error = copyout(pdata, tu->tu_data, tu->tu_size);
 1741                 goto done;
 1742 
 1743         case TWEIO_STATS:
 1744                 return (ENOENT);
 1745 
 1746         case TWEIO_AEN_POLL:
 1747                 s = splbio();
 1748                 *(u_int *)data = twe_aen_dequeue(twe);
 1749                 splx(s);
 1750                 return (0);
 1751 
 1752         case TWEIO_AEN_WAIT:
 1753                 s = splbio();
 1754                 while ((*(u_int *)data =
 1755                     twe_aen_dequeue(twe)) == TWE_AEN_QUEUE_EMPTY) {
 1756                         twe->sc_flags |= TWEF_AENQ_WAIT;
 1757                         error = tsleep(&twe->sc_aen_queue, PRIBIO | PCATCH,
 1758                             "tweaen", 0);
 1759                         if (error == EINTR) {
 1760                                 splx(s);
 1761                                 return (error);
 1762                         }
 1763                 }
 1764                 splx(s);
 1765                 return (0);
 1766 
 1767         case TWEIO_GET_PARAM:
 1768                 error = twe_param_get(twe, tp->tp_table_id, tp->tp_param_id,
 1769                     tp->tp_size, 0, &param);
 1770                 if (error != 0)
 1771                         return (error);
 1772                 if (param->tp_param_size > tp->tp_size) {
 1773                         error = EFAULT;
 1774                         goto done;
 1775                 }
 1776                 error = copyout(param->tp_data, tp->tp_data, 
 1777                     param->tp_param_size);
 1778                 goto done;
 1779 
 1780         case TWEIO_SET_PARAM:
 1781                 pdata = malloc(tp->tp_size, M_DEVBUF, M_WAITOK);
 1782                 if ((error = copyin(tp->tp_data, pdata, tp->tp_size)) != 0)
 1783                         goto done;
 1784                 error = twe_param_set(twe, tp->tp_table_id, tp->tp_param_id,
 1785                     tp->tp_size, pdata);
 1786                 goto done;
 1787 
 1788         case TWEIO_RESET:
 1789                 s = splbio();
 1790                 twe_reset(twe);
 1791                 splx(s);
 1792                 return (0);
 1793 
 1794         case TWEIO_ADD_UNIT:
 1795                 /* XXX mutex */
 1796                 return (twe_add_unit(twe, td->td_unit));
 1797 
 1798         case TWEIO_DEL_UNIT:
 1799                 /* XXX mutex */
 1800                 return (twe_del_unit(twe, td->td_unit));
 1801 
 1802         default:
 1803                 return EINVAL;
 1804         }
 1805 done:
 1806         if (pdata)
 1807                 free(pdata, M_DEVBUF);
 1808         return error;
 1809 }
 1810 
 1811 /*
 1812  * Print some information about the controller
 1813  */
 1814 static void
 1815 twe_describe_controller(struct twe_softc *sc)
 1816 {
 1817         struct twe_param *p[6];
 1818         int i, rv = 0;
 1819         uint32_t dsize;
 1820         uint8_t ports;
 1821 
 1822         /* get the port count */
 1823         rv |= twe_param_get_1(sc, TWE_PARAM_CONTROLLER,
 1824                 TWE_PARAM_CONTROLLER_PortCount, &ports);
 1825 
 1826         /* get version strings */
 1827         rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_Mon,
 1828                 16, NULL, &p[0]);
 1829         rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_FW,
 1830                 16, NULL, &p[1]);
 1831         rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_BIOS,
 1832                 16, NULL, &p[2]);
 1833         rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCB,
 1834                 8, NULL, &p[3]);
 1835         rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_ATA,
 1836                 8, NULL, &p[4]);
 1837         rv |= twe_param_get(sc, TWE_PARAM_VERSION, TWE_PARAM_VERSION_PCI,
 1838                 8, NULL, &p[5]);
 1839 
 1840         if (rv) {
 1841                 /* some error occurred */
 1842                 aprint_error("%s: failed to fetch version information\n",
 1843                         sc->sc_dv.dv_xname);
 1844                 return;
 1845         }
 1846 
 1847         aprint_normal("%s: %d ports, Firmware %.16s, BIOS %.16s\n",
 1848                 sc->sc_dv.dv_xname, ports,
 1849                 p[1]->tp_data, p[2]->tp_data);
 1850 
 1851         aprint_verbose("%s: Monitor %.16s, PCB %.8s, Achip %.8s, Pchip %.8s\n",
 1852                 sc->sc_dv.dv_xname,
 1853                 p[0]->tp_data, p[3]->tp_data,
 1854                 p[4]->tp_data, p[5]->tp_data);
 1855 
 1856         free(p[0], M_DEVBUF);
 1857         free(p[1], M_DEVBUF);
 1858         free(p[2], M_DEVBUF);
 1859         free(p[3], M_DEVBUF);
 1860         free(p[4], M_DEVBUF);
 1861         free(p[5], M_DEVBUF);
 1862 
 1863         rv = twe_param_get(sc, TWE_PARAM_DRIVESUMMARY,
 1864             TWE_PARAM_DRIVESUMMARY_Status, 16, NULL, &p[0]);
 1865         if (rv) {
 1866                 aprint_error("%s: failed to get drive status summary\n",
 1867                     sc->sc_dv.dv_xname);
 1868                 return;
 1869         }
 1870         for (i = 0; i < ports; i++) {
 1871                 if (p[0]->tp_data[i] != TWE_PARAM_DRIVESTATUS_Present)
 1872                         continue;
 1873                 rv = twe_param_get_4(sc, TWE_PARAM_DRIVEINFO + i,
 1874                     TWE_PARAM_DRIVEINFO_Size, &dsize);
 1875                 if (rv) {
 1876                         aprint_error(
 1877                             "%s: unable to get drive size for port %d\n",
 1878                             sc->sc_dv.dv_xname, i);
 1879                         continue;
 1880                 }
 1881                 rv = twe_param_get(sc, TWE_PARAM_DRIVEINFO + i,
 1882                     TWE_PARAM_DRIVEINFO_Model, 40, NULL, &p[1]);
 1883                 if (rv) {
 1884                         aprint_error(
 1885                             "%s: unable to get drive model for port %d\n",
 1886                             sc->sc_dv.dv_xname, i);
 1887                         continue;
 1888                 }
 1889                 aprint_verbose("%s: port %d: %.40s %d MB\n", sc->sc_dv.dv_xname,
 1890                     i, p[1]->tp_data, dsize / 2048);
 1891                 free(p[1], M_DEVBUF);
 1892         }
 1893         free(p[0], M_DEVBUF);
 1894 }

Cache object: 1f6758247f0a8ccf45a92075ad34a7e2


[ 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.