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/5.2/sys/dev/buslogic/bt_isa.c 119418 2003-08-24 17:55:58Z obrien $");
   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_pio.h>
   43 #include <machine/bus.h>
   44 #include <machine/resource.h>
   45 #include <sys/rman.h>
   46 
   47 #include <isa/isavar.h>
   48 #include <dev/buslogic/btreg.h>
   49 
   50 #include <cam/scsi/scsi_all.h>
   51 
   52 static  bus_dma_filter_t btvlbouncefilter;
   53 static  bus_dmamap_callback_t btmapsensebuffers;
   54 
   55 static int
   56 bt_isa_alloc_resources(device_t dev, u_long portstart, u_long portend)
   57 {
   58         int rid;
   59         struct resource *port;
   60         struct resource *irq;
   61         struct resource *drq;
   62 
   63         rid = 0;
   64         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
   65                                   portstart, portend, BT_NREGS, RF_ACTIVE);
   66         if (!port)
   67                 return (ENOMEM);
   68 
   69         if (isa_get_irq(dev) != -1) {
   70                 rid = 0;
   71                 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
   72                                          0, ~0, 1, RF_ACTIVE);
   73                 if (!irq) {
   74                         if (port)
   75                                 bus_release_resource(dev, SYS_RES_IOPORT,
   76                                                      0, port);
   77                         return (ENOMEM);
   78                 }
   79         } else
   80                 irq = 0;
   81 
   82         if (isa_get_drq(dev) != -1) {
   83                 rid = 0;
   84                 drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid,
   85                                          0, ~0, 1, RF_ACTIVE);
   86                 if (!drq) {
   87                         if (port)
   88                                 bus_release_resource(dev, SYS_RES_IOPORT,
   89                                                      0, port);
   90                         if (irq)
   91                                 bus_release_resource(dev, SYS_RES_IRQ,
   92                                                      0, irq);
   93                         return (ENOMEM);
   94                 }
   95         } else
   96                 drq = 0;
   97 
   98         bt_init_softc(dev, port, irq, drq);
   99 
  100         return (0);
  101 }
  102 
  103 static void
  104 bt_isa_release_resources(device_t dev)
  105 {
  106         struct  bt_softc *bt = device_get_softc(dev);
  107 
  108         if (bt->port)
  109                 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
  110         if (bt->irq)
  111                 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
  112         if (bt->drq)
  113                 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
  114         bt_free_softc(dev);
  115 }
  116 
  117 /*
  118  * Check if the device can be found at the port given
  119  * and if so, set it up ready for further work
  120  * as an argument, takes the isa_device structure from
  121  * autoconf.c
  122  */
  123 static int
  124 bt_isa_probe(device_t dev)
  125 {
  126         /*
  127          * find unit and check we have that many defined
  128          */
  129         int     port_index;
  130         int     max_port_index;
  131 
  132         /* No pnp support */
  133         if (isa_get_vendorid(dev))
  134                 return (ENXIO);
  135 
  136         port_index = 0;
  137         max_port_index = BT_NUM_ISAPORTS - 1;
  138         /*
  139          * Bound our board search if the user has
  140          * specified an exact port.
  141          */
  142         bt_find_probe_range(isa_get_port(dev), &port_index, &max_port_index);
  143 
  144         if (port_index < 0)
  145                 return (ENXIO);
  146 
  147         /* Attempt to find an adapter */
  148         for (;port_index <= max_port_index; port_index++) {
  149                 struct bt_probe_info info;
  150                 u_int ioport;
  151 
  152                 ioport = bt_iop_from_bio(port_index);
  153 
  154                 /*
  155                  * Ensure this port has not already been claimed already
  156                  * by a PCI, EISA or ISA adapter.
  157                  */
  158                 if (bt_check_probed_iop(ioport) != 0)
  159                         continue;
  160 
  161                 /* Initialise the softc for use during probing */
  162                 if (bt_isa_alloc_resources(dev, ioport,
  163                                            ioport + BT_NREGS -1) != 0)
  164                         continue;
  165 
  166                 /* We're going to attempt to probe it now, so mark it probed */
  167                 bt_mark_probed_bio(port_index);
  168 
  169                 if (bt_port_probe(dev, &info) != 0) {
  170                         if (bootverbose)
  171                                 printf("bt_isa_probe: Probe failed at 0x%x\n",
  172                                        ioport);
  173                         bt_isa_release_resources(dev);
  174                         continue;
  175                 }
  176 
  177                 bt_isa_release_resources(dev);
  178 
  179                 bus_set_resource(dev, SYS_RES_DRQ, 0, info.drq, 1);
  180                 bus_set_resource(dev, SYS_RES_IRQ, 0, info.irq, 1);
  181 
  182                 return (0);
  183         }
  184 
  185         return (ENXIO);
  186 }
  187 
  188 /*
  189  * Attach all the sub-devices we can find
  190  */
  191 static int
  192 bt_isa_attach(device_t dev)
  193 {
  194         struct  bt_softc *bt = device_get_softc(dev);
  195         bus_dma_filter_t *filter;
  196         void             *filter_arg;
  197         bus_addr_t       lowaddr;
  198         int              error, drq;
  199 
  200         /* Initialise softc */
  201         error = bt_isa_alloc_resources(dev, 0, ~0);
  202         if (error) {
  203                 device_printf(dev, "can't allocate resources in bt_isa_attach\n");
  204                 return error;
  205         }
  206 
  207         /* Program the DMA channel for external control */
  208         if ((drq = isa_get_drq(dev)) != -1)
  209                 isa_dmacascade(drq);
  210 
  211         /* Allocate our parent dmatag */
  212         filter = NULL;
  213         filter_arg = NULL;
  214         lowaddr = BUS_SPACE_MAXADDR_24BIT;
  215         if (bt->model[0] == '4') {
  216                 /*
  217                  * This is a VL adapter.  Typically, VL devices have access
  218                  * to the full 32bit address space.  On BT-445S adapters
  219                  * prior to revision E, there is a hardware bug that causes
  220                  * corruption of transfers to/from addresses in the range of
  221                  * the BIOS modulo 16MB.  The only properly functioning
  222                  * BT-445S Host Adapters have firmware version 3.37.
  223                  * If we encounter one of these adapters and the BIOS is
  224                  * installed, install a filter function for our bus_dma_map
  225                  * that will catch these accesses and bounce them to a safe
  226                  * region of memory.
  227                  */
  228                 if (bt->bios_addr != 0
  229                  && strcmp(bt->model, "445S") == 0
  230                  && strcmp(bt->firmware_ver, "3.37") < 0) {
  231                         filter = btvlbouncefilter;
  232                         filter_arg = bt;
  233                 } else {
  234                         lowaddr = BUS_SPACE_MAXADDR_32BIT;
  235                 }
  236         }
  237                         
  238         /* XXX Should be a child of the ISA or VL bus dma tag */
  239         if (bus_dma_tag_create( /* parent       */ NULL,
  240                                 /* alignemnt    */ 1,
  241                                 /* boundary     */ 0,
  242                                 /* lowaddr      */ lowaddr,
  243                                 /* highaddr     */ BUS_SPACE_MAXADDR,
  244                                 /* filter       */ filter,
  245                                 /* filterarg    */ filter_arg,
  246                                 /* maxsize      */ BUS_SPACE_MAXSIZE_32BIT,
  247                                 /* nsegments    */ ~0,
  248                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
  249                                 /* flags        */ 0,
  250                                 /* lockfunc     */ busdma_lock_mutex,
  251                                 /* lockarg      */ &Giant,
  252                                 &bt->parent_dmat) != 0) {
  253                 bt_isa_release_resources(dev);
  254                 return (ENOMEM);
  255         }                              
  256 
  257         error = bt_init(dev);
  258         if (error) {
  259                 bt_isa_release_resources(dev);
  260                 return (ENOMEM);
  261         }
  262 
  263         if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
  264                 /* DMA tag for our sense buffers */
  265                 if (bus_dma_tag_create(
  266                                 /* parent       */ bt->parent_dmat,
  267                                 /* alignment    */ 1,
  268                                 /* boundary     */ 0,
  269                                 /* lowaddr      */ BUS_SPACE_MAXADDR,
  270                                 /* highaddr     */ BUS_SPACE_MAXADDR,
  271                                 /* filter       */ NULL,
  272                                 /* filterarg    */ NULL,
  273                                 /* maxsize      */ bt->max_ccbs *
  274                                                    sizeof(struct scsi_sense_data),
  275                                 /* nsegments    */ 1,
  276                                 /* maxsegsz     */ BUS_SPACE_MAXSIZE_32BIT,
  277                                 /* flags        */ 0,
  278                                 /* lockfunc     */ busdma_lock_mutex,
  279                                 /* lockarg      */ &Giant,
  280                                 &bt->sense_dmat) != 0) {
  281                         bt_isa_release_resources(dev);
  282                         return (ENOMEM);
  283                 }
  284 
  285                 bt->init_level++;
  286 
  287                 /* Allocation of sense buffers */
  288                 if (bus_dmamem_alloc(bt->sense_dmat,
  289                                      (void **)&bt->sense_buffers,
  290                                      BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
  291                         bt_isa_release_resources(dev);
  292                         return (ENOMEM);
  293                 }
  294 
  295                 bt->init_level++;
  296 
  297                 /* And permanently map them */
  298                 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
  299                                 bt->sense_buffers,
  300                                 bt->max_ccbs * sizeof(*bt->sense_buffers),
  301                                 btmapsensebuffers, bt, /*flags*/0);
  302 
  303                 bt->init_level++;
  304         }
  305 
  306         error = bt_attach(dev);
  307         if (error) {
  308                 bt_isa_release_resources(dev);
  309                 return (error);
  310         }
  311 
  312         return (0);
  313 }
  314 
  315 #define BIOS_MAP_SIZE (16 * 1024)
  316 
  317 static int
  318 btvlbouncefilter(void *arg, bus_addr_t addr)
  319 {
  320         struct bt_softc *bt;
  321 
  322         bt = (struct bt_softc *)arg;
  323 
  324         addr &= BUS_SPACE_MAXADDR_24BIT;
  325 
  326         if (addr == 0
  327          || (addr >= bt->bios_addr
  328           && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
  329                 return (1);
  330         return (0);
  331 }
  332 
  333 static void
  334 btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
  335 {
  336         struct bt_softc* bt;
  337 
  338         bt = (struct bt_softc*)arg;
  339         bt->sense_buffers_physbase = segs->ds_addr;
  340 }
  341 
  342 static device_method_t bt_isa_methods[] = {
  343         /* Device interface */
  344         DEVMETHOD(device_probe,         bt_isa_probe),
  345         DEVMETHOD(device_attach,        bt_isa_attach),
  346 
  347         { 0, 0 }
  348 };
  349 
  350 static driver_t bt_isa_driver = {
  351         "bt",
  352         bt_isa_methods,
  353         sizeof(struct bt_softc),
  354 };
  355 
  356 static devclass_t bt_devclass;
  357 
  358 DRIVER_MODULE(bt, isa, bt_isa_driver, bt_devclass, 0, 0);

Cache object: 3f16afc6fba762f06d9fc6596d2d9346


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