diff options
Diffstat (limited to 'sys/isa')
-rw-r--r-- | sys/isa/bt_isa.c | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/sys/isa/bt_isa.c b/sys/isa/bt_isa.c new file mode 100644 index 0000000..adab9cf --- /dev/null +++ b/sys/isa/bt_isa.c @@ -0,0 +1,322 @@ +/* + * Product specific probe and attach routines for: + * Buslogic BT-54X and BT-445 cards + * + * Copyright (c) 1998 Justin T. Gibbs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> + +#include <machine/bus_pio.h> +#include <machine/bus.h> + +#include <i386/isa/isa_device.h> +#include <dev/buslogic/btreg.h> + +#include <cam/scsi/scsi_all.h> + +#include "ioconf.h" + +static int bt_isa_probe __P((struct isa_device *dev)); +static int bt_isa_attach __P((struct isa_device *dev)); +static void bt_isa_intr __P((void *unit)); + +static bus_dma_filter_t btvlbouncefilter; +static bus_dmamap_callback_t btmapsensebuffers; + +struct isa_driver btdriver = +{ + bt_isa_probe, + bt_isa_attach, + "bt" +}; + +/* + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c + */ +static int +bt_isa_probe(dev) + struct isa_device *dev; +{ + /* + * find unit and check we have that many defined + */ + struct bt_softc *bt; + int port_index; + int max_port_index; + + /* + * We ignore the unit number assigned by config to allow + * consistant numbering between PCI/EISA/ISA devices. + * This is a total kludge until we have a configuration + * manager. + */ + dev->id_unit = bt_unit; + + bt = NULL; + port_index = 0; + max_port_index = BT_NUM_ISAPORTS - 1; + /* + * Bound our board search if the user has + * specified an exact port. + */ + if (dev->id_iobase > 0) { + for (;port_index <= max_port_index; port_index++) + if (dev->id_iobase >= bt_isa_ports[port_index].addr) + break; + if ((port_index > max_port_index) + || (dev->id_iobase != bt_isa_ports[port_index].addr)) { + printf(" +bt_isa_probe: Invalid baseport of 0x%x specified. +bt_isa_probe: Nearest valid baseport is 0x%x. +bt_isa_probe: Failing probe.\n", + dev->id_iobase, + (port_index <= max_port_index) + ? bt_isa_ports[port_index].addr + : bt_isa_ports[max_port_index].addr); + return 0; + } + } + + /* Attempt to find an adapter */ + for (;port_index <= max_port_index; port_index++) { + config_data_t config_data; + u_int ioport; + int error; + + ioport = bt_isa_ports[port_index].addr; + + /* + * Ensure this port has not already been claimed already + * by a PCI or EISA adapter. + */ + if (bt_check_probed_iop(ioport) != 0) + continue; + + /* Allocate a softc for use during probing */ + bt = bt_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport); + + if (bt == NULL) + break; + + /* We're going to attempt to probe it now, so mark it probed */ + bt_mark_probed_bio(port_index); + + /* See if there is really a card present */ + if (bt_probe(bt) || bt_fetch_adapter_info(bt)) { + bt_free(bt); + continue; + } + + /* + * Determine our IRQ, and DMA settings and + * export them to the configuration system. + */ + error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, + (u_int8_t*)&config_data, sizeof(config_data), + DEFAULT_CMD_TIMEOUT); + if (error != 0) { + printf("bt_isa_probe: Could not determine IRQ or DMA " + "settings for adapter at 0x%x. Failing probe\n", + ioport); + bt_free(bt); + continue; + } + + if (bt->model[0] == '5') { + /* DMA settings only make sense for ISA cards */ + switch (config_data.dma_chan) { + case DMA_CHAN_5: + dev->id_drq = 5; + break; + case DMA_CHAN_6: + dev->id_drq = 6; + break; + case DMA_CHAN_7: + dev->id_drq = 7; + break; + default: + printf("bt_isa_probe: Invalid DMA setting " + "detected for adapter at 0x%x. " + "Failing probe\n", ioport); + } + } else { + /* VL DMA */ + dev->id_drq = -1; + } + dev->id_iobase = bt_isa_ports[port_index].addr; + dev->id_irq = (config_data.irq << 9); + dev->id_intr = bt_isa_intr; + bt_unit++; + return (BT_NREGS); + } + + return (0); +} + +/* + * Attach all the sub-devices we can find + */ +static int +bt_isa_attach(dev) + struct isa_device *dev; +{ + struct bt_softc *bt; + bus_dma_filter_t *filter; + void *filter_arg; + bus_addr_t lowaddr; + + bt = bt_softcs[dev->id_unit]; + if (dev->id_drq != -1) + isa_dmacascade(dev->id_drq); + + /* Allocate our parent dmatag */ + filter = NULL; + filter_arg = NULL; + lowaddr = BUS_SPACE_MAXADDR_24BIT; + if (bt->model[0] == '4') { + /* + * This is a VL adapter. Typically, VL devices have access + * to the full 32bit address space. On BT-445S adapters + * prior to revision E, there is a hardware bug that causes + * corruption of transfers to/from addresses in the range of + * the BIOS modulo 16MB. The only properly functioning + * BT-445S Host Adapters have firmware version 3.37. + * If we encounter one of these adapters and the BIOS is + * installed, install a filter function for our bus_dma_map + * that will catch these accesses and bounce them to a safe + * region of memory. + */ + if (bt->bios_addr != 0 + && strcmp(bt->model, "445S") == 0 + && strcmp(bt->firmware_ver, "3.37") < 0) { + filter = btvlbouncefilter; + filter_arg = bt; + } else { + lowaddr = BUS_SPACE_MAXADDR_32BIT; + } + } + + /* XXX Should be a child of the ISA or VL bus dma tag */ + if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0, + lowaddr, /*highaddr*/BUS_SPACE_MAXADDR, + filter, filter_arg, + /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, + /*nsegments*/BUS_SPACE_UNRESTRICTED, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &bt->parent_dmat) != 0) { + bt_free(bt); + return (-1); + } + + if (bt_init(bt)) { + bt_free(bt); + return (-1); + } + + if (lowaddr != BUS_SPACE_MAXADDR_32BIT) { + /* DMA tag for our sense buffers */ + if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, + /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + bt->max_ccbs + * sizeof(struct scsi_sense_data), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &bt->sense_dmat) != 0) { + bt_free(bt); + return (-1); + } + + bt->init_level++; + + /* Allocation of sense buffers */ + if (bus_dmamem_alloc(bt->sense_dmat, + (void **)&bt->sense_buffers, + BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { + bt_free(bt); + return (-1); + } + + bt->init_level++; + + /* And permanently map them */ + bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, + bt->sense_buffers, + bt->max_ccbs * sizeof(*bt->sense_buffers), + btmapsensebuffers, bt, /*flags*/0); + + bt->init_level++; + } + + return (bt_attach(bt)); +} + +/* + * Handle an ISA interrupt. + * XXX should go away as soon as ISA interrupt handlers + * take a (void *) arg. + */ +static void +bt_isa_intr(void *unit) +{ + struct bt_softc* arg = bt_softcs[(int)unit]; + bt_intr((void *)arg); +} + +#define BIOS_MAP_SIZE (16 * 1024) + +static int +btvlbouncefilter(void *arg, bus_addr_t addr) +{ + struct bt_softc *bt; + + bt = (struct bt_softc *)arg; + + addr &= BUS_SPACE_MAXADDR_24BIT; + + if (addr == 0 + || (addr >= bt->bios_addr + && addr < (bt->bios_addr + BIOS_MAP_SIZE))) + return (1); + return (0); +} + +static void +btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct bt_softc* bt; + + bt = (struct bt_softc*)arg; + bt->sense_buffers_physbase = segs->ds_addr; +} |