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

Cache object: e45b9449a387a95421db9c1e8cbf0495


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