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/eisa/mlx_eisa.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: mlx_eisa.c,v 1.22 2009/05/12 14:21:32 cegger Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2001 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  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * EISA front-end for mlx(4) driver.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: mlx_eisa.c,v 1.22 2009/05/12 14:21:32 cegger Exp $");
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/device.h>
   42 
   43 #include <sys/bus.h>
   44 #include <sys/intr.h>
   45 
   46 #include <dev/eisa/eisavar.h>
   47 #include <dev/eisa/eisadevs.h>
   48 
   49 #include <dev/ic/mlxreg.h>
   50 #include <dev/ic/mlxio.h>
   51 #include <dev/ic/mlxvar.h>
   52 
   53 #define MLX_EISA_SLOT_OFFSET            0x0c80
   54 #define MLX_EISA_IOSIZE                 (0x0ce0 - MLX_EISA_SLOT_OFFSET)
   55 #define MLX_EISA_CFG01                  (0x0cc0 - MLX_EISA_SLOT_OFFSET)
   56 #define MLX_EISA_CFG02                  (0x0cc1 - MLX_EISA_SLOT_OFFSET)
   57 #define MLX_EISA_CFG03                  (0x0cc3 - MLX_EISA_SLOT_OFFSET)
   58 #define MLX_EISA_CFG04                  (0x0c8d - MLX_EISA_SLOT_OFFSET)
   59 #define MLX_EISA_CFG05                  (0x0c90 - MLX_EISA_SLOT_OFFSET)
   60 #define MLX_EISA_CFG06                  (0x0c91 - MLX_EISA_SLOT_OFFSET)
   61 #define MLX_EISA_CFG07                  (0x0c92 - MLX_EISA_SLOT_OFFSET)
   62 #define MLX_EISA_CFG08                  (0x0c93 - MLX_EISA_SLOT_OFFSET)
   63 #define MLX_EISA_CFG09                  (0x0c94 - MLX_EISA_SLOT_OFFSET)
   64 #define MLX_EISA_CFG10                  (0x0c95 - MLX_EISA_SLOT_OFFSET)
   65 
   66 static void     mlx_eisa_attach(device_t, device_t, void *);
   67 static int      mlx_eisa_match(device_t, cfdata_t, void *);
   68 
   69 static int      mlx_v1_submit(struct mlx_softc *, struct mlx_ccb *);
   70 static int      mlx_v1_findcomplete(struct mlx_softc *, u_int *, u_int *);
   71 static void     mlx_v1_intaction(struct mlx_softc *, int);
   72 static int      mlx_v1_fw_handshake(struct mlx_softc *, int *, int *, int *);
   73 #ifdef MLX_RESET
   74 static int      mlx_v1_reset(struct mlx_softc *);
   75 #endif
   76 
   77 CFATTACH_DECL(mlx_eisa, sizeof(struct mlx_softc),
   78     mlx_eisa_match, mlx_eisa_attach, NULL, NULL);
   79 
   80 static struct mlx_eisa_prod {
   81         const char      *mp_idstr;
   82         int             mp_nchan;
   83 } const mlx_eisa_prod[] = {
   84         { "MLX0070", 1 },
   85         { "MLX0071", 3 },
   86         { "MLX0072", 3 },
   87         { "MLX0073", 2 },
   88         { "MLX0074", 1 },
   89         { "MLX0075", 3 },
   90         { "MLX0076", 2 },
   91         { "MLX0077", 1 },
   92 };
   93 
   94 static int
   95 mlx_eisa_match(device_t parent, cfdata_t match,
   96     void *aux)
   97 {
   98         struct eisa_attach_args *ea;
   99         int i;
  100 
  101         ea = aux;
  102 
  103         for (i = 0; i < sizeof(mlx_eisa_prod) / sizeof(mlx_eisa_prod[0]); i++)
  104                 if (strcmp(ea->ea_idstring, mlx_eisa_prod[i].mp_idstr) == 0)
  105                         return (1);
  106 
  107         return (0);
  108 }
  109 
  110 static void
  111 mlx_eisa_attach(device_t parent, device_t self, void *aux)
  112 {
  113         struct eisa_attach_args *ea;
  114         bus_space_handle_t ioh;
  115         eisa_chipset_tag_t ec;
  116         eisa_intr_handle_t ih;
  117         struct mlx_softc *mlx;
  118         bus_space_tag_t iot;
  119         const char *intrstr;
  120         int irq, i, icfg;
  121 
  122         ea = aux;
  123         mlx = device_private(self);
  124         iot = ea->ea_iot;
  125         ec = ea->ea_ec;
  126 
  127         if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
  128             MLX_EISA_SLOT_OFFSET, MLX_EISA_IOSIZE, 0, &ioh)) {
  129                 printf("can't map i/o space\n");
  130                 return;
  131         }
  132 
  133         mlx->mlx_iot = iot;
  134         mlx->mlx_ioh = ioh;
  135         mlx->mlx_dmat = ea->ea_dmat;
  136 
  137         /*
  138          * Map and establish the interrupt.
  139          */
  140         icfg = bus_space_read_1(iot, ioh, MLX_EISA_CFG03);
  141 
  142         switch (icfg & 0xf0) {
  143         case 0xa0:
  144                 irq = 11;
  145                 break;
  146         case 0xc0:
  147                 irq = 12;
  148                 break;
  149         case 0xe0:
  150                 irq = 14;
  151                 break;
  152         case 0x80:
  153                 irq = 15;
  154                 break;
  155         default:
  156                 printf("controller on invalid IRQ\n");
  157                 return;
  158         }
  159 
  160         if (eisa_intr_map(ec, irq, &ih)) {
  161                 printf("can't map interrupt (%d)\n", irq);
  162                 return;
  163         }
  164 
  165         intrstr = eisa_intr_string(ec, ih);
  166         mlx->mlx_ih = eisa_intr_establish(ec, ih,
  167             ((icfg & 0x08) != 0 ? IST_LEVEL : IST_EDGE),
  168             IPL_BIO, mlx_intr, mlx);
  169         if (mlx->mlx_ih == NULL) {
  170                 printf("can't establish interrupt");
  171                 if (intrstr != NULL)
  172                         printf(" at %s", intrstr);
  173                 printf("\n");
  174                 return;
  175         }
  176 
  177         for (i = 0; i < sizeof(mlx_eisa_prod) / sizeof(mlx_eisa_prod[0]); i++)
  178                 if (strcmp(ea->ea_idstring, mlx_eisa_prod[i].mp_idstr) == 0) {
  179                         mlx->mlx_ci.ci_nchan = mlx_eisa_prod[i].mp_nchan;
  180                         break;
  181                 }
  182         mlx->mlx_ci.ci_iftype = 1;
  183 
  184         mlx->mlx_submit = mlx_v1_submit;
  185         mlx->mlx_findcomplete = mlx_v1_findcomplete;
  186         mlx->mlx_intaction = mlx_v1_intaction;
  187         mlx->mlx_fw_handshake = mlx_v1_fw_handshake;
  188 #ifdef MLX_RESET
  189         mlx->mlx_reset = mlx_v1_reset;
  190 #endif
  191 
  192         printf(": Mylex RAID\n");
  193         mlx_init(mlx, intrstr);
  194 }
  195 
  196 /*
  197  * ================= V1 interface linkage =================
  198  */
  199 
  200 /*
  201  * Try to give (mc) to the controller.  Returns 1 if successful, 0 on
  202  * failure (the controller is not ready to take a command).
  203  *
  204  * Must be called at splbio or in a fashion that prevents reentry.
  205  */
  206 static int
  207 mlx_v1_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
  208 {
  209 
  210         /* Ready for our command? */
  211         if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_FULL) == 0) {
  212                 /* Copy mailbox data to window. */
  213                 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
  214                     MLX_V1REG_MAILBOX, mc->mc_mbox, 13);
  215                 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
  216                     MLX_V1REG_MAILBOX, 13,
  217                     BUS_SPACE_BARRIER_WRITE);
  218 
  219                 /* Post command. */
  220                 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_FULL);
  221                 return (1);
  222         }
  223 
  224         return (0);
  225 }
  226 
  227 /*
  228  * See if a command has been completed, if so acknowledge its completion and
  229  * recover the slot number and status code.
  230  *
  231  * Must be called at splbio or in a fashion that prevents reentry.
  232  */
  233 static int
  234 mlx_v1_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
  235 {
  236 
  237         /* Status available? */
  238         if ((mlx_inb(mlx, MLX_V1REG_ODB) & MLX_V1_ODB_SAVAIL) != 0) {
  239                 *slot = mlx_inb(mlx, MLX_V1REG_MAILBOX + 0x0d);
  240                 *status = mlx_inw(mlx, MLX_V1REG_MAILBOX + 0x0e);
  241 
  242                 /* Acknowledge completion. */
  243                 mlx_outb(mlx, MLX_V1REG_ODB, MLX_V1_ODB_SAVAIL);
  244                 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
  245                 return (1);
  246         }
  247 
  248         return (0);
  249 }
  250 
  251 /*
  252  * Enable/disable interrupts as requested. (No acknowledge required)
  253  *
  254  * Must be called at splbio or in a fashion that prevents reentry.
  255  */
  256 static void
  257 mlx_v1_intaction(struct mlx_softc *mlx, int action)
  258 {
  259 
  260         mlx_outb(mlx, MLX_V1REG_IE, action ? 1 : 0);
  261 }
  262 
  263 /*
  264  * Poll for firmware error codes during controller initialisation.
  265  *
  266  * Returns 0 if initialisation is complete, 1 if still in progress but no
  267  * error has been fetched, 2 if an error has been retrieved.
  268  */
  269 static int
  270 mlx_v1_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
  271 {
  272         u_int8_t fwerror;
  273 
  274         /*
  275          * First time around, enable the IDB interrupt and clear any
  276          * hardware completion status.
  277          */
  278         if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
  279                 mlx_outb(mlx, MLX_V1REG_ODB_EN, 1);
  280                 DELAY(1000);
  281                 mlx_outb(mlx, MLX_V1REG_ODB, 1);
  282                 DELAY(1000);
  283                 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
  284                 DELAY(1000);
  285                 mlx->mlx_flags |= MLXF_FW_INITTED;
  286         }
  287 
  288         /* Init in progress? */
  289         if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_INIT_BUSY) == 0)
  290                 return (0);
  291 
  292         /* Test error value. */
  293         fwerror = mlx_inb(mlx, MLX_V1REG_ODB);
  294 
  295         if ((fwerror & MLX_V1_FWERROR_PEND) == 0)
  296                 return (1);
  297 
  298         /* XXX Fetch status. */
  299         *error = fwerror & 0xf0;
  300         *param1 = -1;
  301         *param2 = -1;
  302 
  303         /* Acknowledge. */
  304         mlx_outb(mlx, MLX_V1REG_ODB, fwerror);
  305 
  306         return (2);
  307 }
  308 
  309 #ifdef MLX_RESET
  310 /*
  311  * Reset the controller.  Return non-zero on failure.
  312  */
  313 static int
  314 mlx_v1_reset(struct mlx_softc *mlx)
  315 {
  316         int i;
  317 
  318         mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
  319         delay(1000000);
  320 
  321         /* Wait up to 2 minutes for the bit to clear. */
  322         for (i = 120; i != 0; i--) {
  323                 delay(1000000);
  324                 if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_SACK) == 0)
  325                         break;
  326         }
  327         if (i == 0)
  328                 return (-1);
  329 
  330         mlx_outb(mlx, MLX_V1REG_ODB, MLX_V1_ODB_RESET);
  331         mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_RESET);
  332 
  333         /* Wait up to 5 seconds for the bit to clear... */
  334         for (i = 5; i != 0; i--) {
  335                 delay(1000000);
  336                 if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_RESET) == 0)
  337                         break;
  338         }
  339         if (i == 0)
  340                 return (-1);
  341 
  342         /* Wait up to 3 seconds for the other bit to clear... */
  343         for (i = 5; i != 0; i--) {
  344                 delay(1000000);
  345                 if ((mlx_inb(mlx, MLX_V1REG_ODB) & MLX_V1_ODB_RESET) == 0)
  346                         break;
  347         }
  348         if (i == 0)
  349                 return (-1);
  350 
  351         return (0);
  352 }
  353 #endif  /* MLX_RESET */

Cache object: e50ed43ae64b8201a1a6dc35e18b552d


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