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/aha/aha_isa.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 /*
    2  * Product specific probe and attach routines for:
    3  *      Adaptec 154x.
    4  *
    5  * Derived from code written by:
    6  *
    7  * Copyright (c) 1998 Justin T. Gibbs
    8  * All rights reserved.
    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  *    without modification, immediately at the beginning of the file.
   16  * 2. The name of the author may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  * $FreeBSD$
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 
   38 #include <machine/bus_pio.h>
   39 #include <machine/bus.h>
   40 #include <machine/resource.h>
   41 #include <sys/module.h>
   42 #include <sys/bus.h>
   43 #include <sys/rman.h>
   44 
   45 #include <isa/isavar.h>
   46 
   47 #include <dev/aha/ahareg.h>
   48 
   49 #include <cam/scsi/scsi_all.h>
   50 
   51 static struct isa_pnp_id aha_ids[] = {
   52         {ADP0100_PNP,           "Adaptec 1540/1542 ISA SCSI"},  /* ADP0100 */
   53         {AHA1540_PNP,           "Adaptec 1540/aha-1640/aha-1535"},/* ADP1542 */
   54         {AHA1542_PNP,           "Adaptec 1542/aha-1535"},       /* ADP1542 */
   55         {AHA1542_PNPCOMPAT,     "Adaptec 1542 compatible"},     /* PNP00A0 */
   56         {ICU0091_PNP,           "Adaptec AHA-1540/1542 SCSI"},  /* ICU0091 */
   57         {0}
   58 };
   59 
   60 /*
   61  * Check if the device can be found at the port given
   62  * and if so, set it up ready for further work
   63  * as an argument, takes the isa_device structure from
   64  * autoconf.c
   65  */
   66 static int
   67 aha_isa_probe(device_t dev)
   68 {
   69         /*
   70          * find unit and check we have that many defined
   71          */
   72         struct  aha_softc **sc = device_get_softc(dev);
   73         struct  aha_softc *aha;
   74         int     port_index;
   75         int     max_port_index;
   76         int     error;
   77         u_long  port_start, port_count;
   78         struct resource *port_res;
   79         int     port_rid;
   80         int     drq;
   81         int     irq;
   82 
   83         aha = NULL;
   84 
   85         /* Check isapnp ids */
   86         if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
   87                 return (ENXIO);
   88 
   89         error = bus_get_resource(dev, SYS_RES_IOPORT, 0,
   90                                  &port_start, &port_count);
   91         if (error != 0)
   92                 port_start = 0;
   93 
   94         /*
   95          * Bound our board search if the user has
   96          * specified an exact port.
   97          */
   98         aha_find_probe_range(port_start, &port_index, &max_port_index);
   99 
  100         if (port_index < 0)
  101                 return ENXIO;
  102 
  103         /* Attempt to find an adapter */
  104         for (;port_index <= max_port_index; port_index++) {
  105                 config_data_t config_data;
  106                 u_int ioport;
  107                 int error;
  108 
  109                 ioport = aha_iop_from_bio(port_index);
  110 
  111                 error = bus_set_resource(dev, SYS_RES_IOPORT, 0,
  112                                          ioport, AHA_NREGS);
  113                 if (error)
  114                         return error;
  115                 
  116                 port_rid = 0;
  117                 port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
  118                     0, ~0, AHA_NREGS, RF_ACTIVE);
  119                 if (!port_res)
  120                         continue;
  121 
  122                 /* Allocate a softc for use during probing */
  123                 aha = aha_alloc(device_get_unit(dev), rman_get_bustag(port_res),
  124                     rman_get_bushandle(port_res));
  125 
  126                 if (aha == NULL) {
  127                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 
  128                             port_res);
  129                         break;
  130                 }
  131 
  132                 /* See if there is really a card present */
  133                 if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
  134                         aha_free(aha);
  135                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
  136                             port_res);
  137                         continue;
  138                 }
  139 
  140                 /*
  141                  * Determine our IRQ, and DMA settings and
  142                  * export them to the configuration system.
  143                  */
  144                 error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
  145                     (u_int8_t*)&config_data, sizeof(config_data), 
  146                     DEFAULT_CMD_TIMEOUT);
  147 
  148                 if (error != 0) {
  149                         printf("aha_isa_probe: Could not determine IRQ or DMA "
  150                             "settings for adapter at 0x%x.  Failing probe\n",
  151                             ioport);
  152                         aha_free(aha);
  153                         bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 
  154                             port_res);
  155                         continue;
  156                 }
  157 
  158                 bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
  159 
  160                 switch (config_data.dma_chan) {
  161                 case DMA_CHAN_5:
  162                         drq = 5;
  163                         break;
  164                 case DMA_CHAN_6:
  165                         drq = 6;
  166                         break;
  167                 case DMA_CHAN_7:
  168                         drq = 7;
  169                         break;
  170                 default:
  171                         printf("aha_isa_probe: Invalid DMA setting "
  172                             "detected for adapter at 0x%x.  "
  173                             "Failing probe\n", ioport);
  174                         return (ENXIO);
  175                 }
  176                 error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
  177                 if (error)
  178                         return error;
  179 
  180                 irq = ffs(config_data.irq) + 8;
  181                 error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
  182                 if (error)
  183                         return error;
  184 
  185                 *sc = aha;
  186                 aha_unit++;
  187 
  188                 return (0);
  189         }
  190 
  191         return (ENXIO);
  192 }
  193 
  194 /*
  195  * Attach all the sub-devices we can find
  196  */
  197 static int
  198 aha_isa_attach(device_t dev)
  199 {
  200         struct  aha_softc **sc = device_get_softc(dev);
  201         struct  aha_softc *aha;
  202         bus_dma_filter_t *filter;
  203         void             *filter_arg;
  204         bus_addr_t       lowaddr;
  205         void             *ih;
  206         int              error;
  207 
  208         aha = *sc;
  209         aha->portrid = 0;
  210         aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid,
  211             0, ~0, AHA_NREGS, RF_ACTIVE);
  212         if (!aha->port) {
  213                 device_printf(dev, "Unable to allocate I/O ports\n");
  214                 return ENOMEM;
  215         }
  216 
  217         aha->irqrid = 0;
  218         aha->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &aha->irqrid, 0, ~0, 1,
  219             RF_ACTIVE);
  220         if (!aha->irq) {
  221                 device_printf(dev, "Unable to allocate excluse use of irq\n");
  222                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  223                 return ENOMEM;
  224         }
  225 
  226         aha->drqrid = 0;
  227         aha->drq = bus_alloc_resource(dev, SYS_RES_DRQ, &aha->drqrid, 0, ~0, 1,
  228             RF_ACTIVE);
  229         if (!aha->drq) {
  230                 device_printf(dev, "Unable to allocate drq\n");
  231                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  232                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
  233                 return ENOMEM;
  234         }
  235 
  236 #if 0                           /* is the drq ever unset? */
  237         if (dev->id_drq != -1)
  238                 isa_dmacascade(dev->id_drq);
  239 #endif
  240         isa_dmacascade(rman_get_start(aha->drq));
  241 
  242         /* Allocate our parent dmatag */
  243         filter = NULL;
  244         filter_arg = NULL;
  245         lowaddr = BUS_SPACE_MAXADDR_24BIT;
  246 
  247         if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
  248             lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
  249             filter, filter_arg,
  250             /*maxsize*/BUS_SPACE_MAXSIZE_24BIT,
  251             /*nsegments*/BUS_SPACE_UNRESTRICTED,
  252             /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
  253             /*flags*/0, &aha->parent_dmat) != 0) {
  254                 aha_free(aha);
  255                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  256                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
  257                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
  258                 return (ENOMEM);
  259         }                              
  260 
  261         if (aha_init(aha)) {
  262                 device_printf(dev, "init failed\n");
  263                 aha_free(aha);
  264                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  265                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
  266                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
  267                 return (ENOMEM);
  268         }
  269 
  270         error = aha_attach(aha);
  271         if (error) {
  272                 device_printf(dev, "attach failed\n");
  273                 aha_free(aha);
  274                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  275                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
  276                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
  277                 return (error);
  278         }
  279 
  280         error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM, aha_intr, aha,
  281             &ih);
  282         if (error) {
  283                 device_printf(dev, "Unable to register interrupt handler\n");
  284                 aha_free(aha);
  285                 bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  286                 bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
  287                 bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
  288                 return (error);
  289         }
  290 
  291         return (0);
  292 }
  293 
  294 static int
  295 aha_isa_detach(device_t dev)
  296 {
  297         struct aha_softc *aha = *(struct aha_softc **) device_get_softc(dev);
  298         int error;
  299 
  300         error = bus_teardown_intr(dev, aha->irq, aha->ih);
  301         if (error) {
  302                 device_printf(dev, "failed to unregister interrupt handler\n");
  303         }
  304 
  305         bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
  306         bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
  307         bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
  308 
  309         error = aha_detach(aha);
  310         if (error) {
  311                 device_printf(dev, "detach failed\n");
  312                 return (error);
  313         }
  314         aha_free(aha);
  315 
  316         return (0);
  317 }
  318 
  319 static void
  320 aha_isa_identify(driver_t *driver, device_t parent)
  321 {
  322 }
  323 
  324 static device_method_t aha_isa_methods[] = {
  325         /* Device interface */
  326         DEVMETHOD(device_probe,         aha_isa_probe),
  327         DEVMETHOD(device_attach,        aha_isa_attach),
  328         DEVMETHOD(device_detach,        aha_isa_detach),
  329         DEVMETHOD(device_identify,      aha_isa_identify),
  330 
  331         { 0, 0 }
  332 };
  333 
  334 static driver_t aha_isa_driver = {
  335         "aha",
  336         aha_isa_methods,
  337         sizeof(struct aha_softc*),
  338 };
  339 
  340 static devclass_t aha_devclass;
  341 
  342 DRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0);

Cache object: 542f6839c06589b0be1a51d3e444b14e


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