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/buslogic/bt_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  *      Buslogic BT-54X and BT-445 cards
    4  *
    5  * Copyright (c) 1998, 1999 Justin T. Gibbs
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions, and the following disclaimer,
   13  *    without modification, immediately at the beginning of the file.
   14  * 2. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/10.4/sys/dev/buslogic/bt_isa.c 241592 2012-10-15 16:13:55Z jhb $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/bus.h>
   41 
   42 #include <machine/bus.h>
   43 #include <machine/resource.h>
   44 #include <sys/rman.h>
   45 
   46 #include <isa/isavar.h>
   47 #include <dev/buslogic/btreg.h>
   48 
   49 #include <cam/scsi/scsi_all.h>
   50 
   51 static  bus_dma_filter_t btvlbouncefilter;
   52 static  bus_dmamap_callback_t btmapsensebuffers;
   53 
   54 static int
   55 bt_isa_alloc_resources(device_t dev, u_long portstart, u_long portend)
   56 {
   57         int rid;
   58         struct resource *port;
   59         struct resource *irq;
   60         struct resource *drq;
   61 
   62         rid = 0;
   63         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
   64                                   portstart, portend, BT_NREGS, RF_ACTIVE);
   65         if (!port)
   66                 return (ENOMEM);
   67 
   68         if (isa_get_irq(dev) != -1) {
   69                 rid = 0;
   70                 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
   71                 if (!irq) {
   72                         if (port)
   73                                 bus_release_resource(dev, SYS_RES_IOPORT,
   74                                                      0, port);
   75                         return (ENOMEM);
   76                 }
   77         } else
   78                 irq = NULL;
   79 
   80         if (isa_get_drq(dev) != -1) {
   81                 rid = 0;
   82                 drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, RF_ACTIVE);
   83                 if (!drq) {
   84                         if (port)
   85                                 bus_release_resource(dev, SYS_RES_IOPORT,
   86                                                      0, port);
   87                         if (irq)
   88                                 bus_release_resource(dev, SYS_RES_IRQ,
   89                                                      0, irq);
   90                         return (ENOMEM);
   91                 }
   92         } else
   93                 drq = NULL;
   94 
   95         bt_init_softc(dev, port, irq, drq);
   96 
   97         return (0);
   98 }
   99 
  100 static void
  101 bt_isa_release_resources(device_t dev)
  102 {
  103         struct  bt_softc *bt = device_get_softc(dev);
  104 
  105         if (bt->port)
  106                 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
  107         if (bt->irq)
  108                 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
  109         if (bt->drq)
  110                 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
  111         bt_free_softc(dev);
  112 }
  113 
  114 /*
  115  * Check if the device can be found at the port given
  116  * and if so, set it up ready for further work
  117  * as an argument, takes the isa_device structure from
  118  * autoconf.c
  119  */
  120 static int
  121 bt_isa_probe(device_t dev)
  122 {
  123         /*
  124          * find unit and check we have that many defined
  125          */
  126         int     port_index;
  127         int     max_port_index;
  128 
  129         /* No pnp support */
  130         if (isa_get_vendorid(dev))
  131                 return (ENXIO);
  132 
  133         port_index = 0;
  134         max_port_index = BT_NUM_ISAPORTS - 1;
  135         /*
  136          * Bound our board search if the user has
  137          * specified an exact port.
  138          */
  139         bt_find_probe_range(isa_get_port(dev), &port_index, &max_port_index);
  140 
  141         if (port_index < 0)
  142                 return (ENXIO);
  143 
  144         /* Attempt to find an adapter */
  145         for (;port_index <= max_port_index; port_index++) {
  146                 struct bt_probe_info info;
  147                 u_int ioport;
  148 
  149                 ioport = bt_iop_from_bio(port_index);
  150 
  151                 /*
  152                  * Ensure this port has not already been claimed already
  153                  * by a PCI, EISA or ISA adapter.
  154                  */
  155                 if (bt_check_probed_iop(ioport) != 0)
  156                         continue;
  157 
  158                 /* Initialise the softc for use during probing */
  159                 if (bt_isa_alloc_resources(dev, ioport,
  160                                            ioport + BT_NREGS -1) != 0)
  161                         continue;
  162 
  163                 /* We're going to attempt to probe it now, so mark it probed */
  164                 bt_mark_probed_bio(port_index);
  165 
  166                 if (bt_port_probe(dev, &info) != 0) {
  167                         if (bootverbose)
  168                                 printf("bt_isa_probe: Probe failed at 0x%x\n",
  169                                        ioport);
  170                         bt_isa_release_resources(dev);
  171                         continue;
  172                 }
  173 
  174                 bt_isa_release_resources(dev);
  175 
  176                 bus_set_resource(dev, SYS_RES_DRQ, 0, info.drq, 1);
  177                 bus_set_resource(dev, SYS_RES_IRQ, 0, info.irq, 1);
  178 
  179                 return (BUS_PROBE_DEFAULT);
  180         }
  181 
  182         return (ENXIO);
  183 }
  184 
  185 /*
  186  * Attach all the sub-devices we can find
  187  */
  188 static int
  189 bt_isa_attach(device_t dev)
  190 {
  191         struct  bt_softc *bt = device_get_softc(dev);
  192         bus_dma_filter_t *filter;
  193         void             *filter_arg;
  194         bus_addr_t       lowaddr;
  195         int              error, drq;
  196 
  197         /* Initialise softc */
  198         error = bt_isa_alloc_resources(dev, 0, ~0);
  199         if (error) {
  200                 device_printf(dev, "can't allocate resources in bt_isa_attach\n");
  201                 return error;
  202         }
  203 
  204         /* Program the DMA channel for external control */
  205         if ((drq = isa_get_drq(dev)) != -1)
  206                 isa_dmacascade(drq);
  207 
  208         /* Allocate our parent dmatag */
  209         filter = NULL;
  210         filter_arg = NULL;
  211         lowaddr = BUS_SPACE_MAXADDR_24BIT;
  212         if (bt->model[0] == '4') {
  213                 /*
  214                  * This is a VL adapter.  Typically, VL devices have access
  215                  * to the full 32bit address space.  On BT-445S adapters
  216                  * prior to revision E, there is a hardware bug that causes
  217                  * corruption of transfers to/from addresses in the range of
  218                  * the BIOS modulo 16MB.  The only properly functioning
  219                  * BT-445S Host Adapters have firmware version 3.37.
  220                  * If we encounter one of these adapters and the BIOS is
  221                  * installed, install a filter function for our bus_dma_map
  222                  * that will catch these accesses and bounce them to a safe
  223                  * region of memory.
  224                  */
  225                 if (bt->bios_addr != 0
  226                  && strcmp(bt->model, "445S") == 0
  227                  && strcmp(bt->firmware_ver, "3.37") < 0) {
  228                         filter = btvlbouncefilter;
  229                         filter_arg = bt;
  230                 } else {
  231                         lowaddr = BUS_SPACE_MAXADDR_32BIT;
  232                 }
  233         }
  234                         
  235         /* XXX Should be a child of the ISA or VL bus dma tag */
  236         if (bus_dma_tag_create( /* parent       */ bus_get_dma_tag(dev),
  237                                 /* alignemnt    */ 1,
  238                                 /* boundary     */ 0,
  239                                 /* lowaddr      */ lowaddr,
  240                                 /* highaddr     */ BUS_SPACE_MAXADDR,
  241                                 /* filter       */ filter,
  242                                 /* filterarg    */ filter_arg,
  243                                 /* maxsize      */ BUS_SPACE_MAXSIZE_32BIT,
  244                                 /* nsegments    */ ~0,
  245                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
  246                                 /* flags        */ 0,
  247                                 /* lockfunc     */ NULL,
  248                                 /* lockarg      */ NULL,
  249                                 &bt->parent_dmat) != 0) {
  250                 bt_isa_release_resources(dev);
  251                 return (ENOMEM);
  252         }                              
  253 
  254         error = bt_init(dev);
  255         if (error) {
  256                 bt_isa_release_resources(dev);
  257                 return (ENOMEM);
  258         }
  259 
  260         if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
  261                 /* DMA tag for our sense buffers */
  262                 if (bus_dma_tag_create(
  263                                 /* parent       */ bt->parent_dmat,
  264                                 /* alignment    */ 1,
  265                                 /* boundary     */ 0,
  266                                 /* lowaddr      */ BUS_SPACE_MAXADDR,
  267                                 /* highaddr     */ BUS_SPACE_MAXADDR,
  268                                 /* filter       */ NULL,
  269                                 /* filterarg    */ NULL,
  270                                 /* maxsize      */ bt->max_ccbs *
  271                                                    sizeof(struct scsi_sense_data),
  272                                 /* nsegments    */ 1,
  273                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
  274                                 /* flags        */ 0,
  275                                 /* lockfunc     */ NULL,
  276                                 /* lockarg      */ NULL,
  277                                 &bt->sense_dmat) != 0) {
  278                         bt_isa_release_resources(dev);
  279                         return (ENOMEM);
  280                 }
  281 
  282                 bt->init_level++;
  283 
  284                 /* Allocation of sense buffers */
  285                 if (bus_dmamem_alloc(bt->sense_dmat,
  286                                      (void **)&bt->sense_buffers,
  287                                      BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
  288                         bt_isa_release_resources(dev);
  289                         return (ENOMEM);
  290                 }
  291 
  292                 bt->init_level++;
  293 
  294                 /* And permanently map them */
  295                 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
  296                                 bt->sense_buffers,
  297                                 bt->max_ccbs * sizeof(*bt->sense_buffers),
  298                                 btmapsensebuffers, bt, /*flags*/0);
  299 
  300                 bt->init_level++;
  301         }
  302 
  303         error = bt_attach(dev);
  304         if (error) {
  305                 bt_isa_release_resources(dev);
  306                 return (error);
  307         }
  308 
  309         return (0);
  310 }
  311 
  312 #define BIOS_MAP_SIZE (16 * 1024)
  313 
  314 static int
  315 btvlbouncefilter(void *arg, bus_addr_t addr)
  316 {
  317         struct bt_softc *bt;
  318 
  319         bt = (struct bt_softc *)arg;
  320 
  321         addr &= BUS_SPACE_MAXADDR_24BIT;
  322 
  323         if (addr == 0
  324          || (addr >= bt->bios_addr
  325           && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
  326                 return (1);
  327         return (0);
  328 }
  329 
  330 static void
  331 btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  332 {
  333         struct bt_softc* bt;
  334 
  335         bt = (struct bt_softc*)arg;
  336         bt->sense_buffers_physbase = segs->ds_addr;
  337 }
  338 
  339 static device_method_t bt_isa_methods[] = {
  340         /* Device interface */
  341         DEVMETHOD(device_probe,         bt_isa_probe),
  342         DEVMETHOD(device_attach,        bt_isa_attach),
  343 
  344         { 0, 0 }
  345 };
  346 
  347 static driver_t bt_isa_driver = {
  348         "bt",
  349         bt_isa_methods,
  350         sizeof(struct bt_softc),
  351 };
  352 
  353 static devclass_t bt_devclass;
  354 
  355 DRIVER_MODULE(bt, isa, bt_isa_driver, bt_devclass, 0, 0);
  356 MODULE_DEPEND(bt, isa, 1, 1, 1);

Cache object: 2fb6821139ab9efa8cfec9fb79031980


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