bt_isa.c revision 40160
139223Sgibbs/*
239223Sgibbs * Product specific probe and attach routines for:
339223Sgibbs *      Buslogic BT-54X and BT-445 cards
439223Sgibbs *
539223Sgibbs * Copyright (c) 1998 Justin T. Gibbs
639223Sgibbs * All rights reserved.
739223Sgibbs *
839223Sgibbs * Redistribution and use in source and binary forms, with or without
939223Sgibbs * modification, are permitted provided that the following conditions
1039223Sgibbs * are met:
1139223Sgibbs * 1. Redistributions of source code must retain the above copyright
1239223Sgibbs *    notice, this list of conditions, and the following disclaimer,
1339223Sgibbs *    without modification, immediately at the beginning of the file.
1439223Sgibbs * 2. The name of the author may not be used to endorse or promote products
1539223Sgibbs *    derived from this software without specific prior written permission.
1639223Sgibbs *
1739223Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1839223Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1939223Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2039223Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2139223Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2239223Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2339223Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2439223Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2539223Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2639223Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2739223Sgibbs * SUCH DAMAGE.
2839223Sgibbs *
2940160Simp *	$Id: bt_isa.c,v 1.2 1998/09/24 10:43:42 bde Exp $
3039223Sgibbs */
3139223Sgibbs
3239223Sgibbs#include <sys/param.h>
3339223Sgibbs#include <sys/systm.h>
3439223Sgibbs
3539223Sgibbs#include <machine/bus_pio.h>
3639223Sgibbs#include <machine/bus.h>
3739223Sgibbs
3839223Sgibbs#include <i386/isa/isa_device.h>
3939223Sgibbs#include <dev/buslogic/btreg.h>
4039223Sgibbs
4139223Sgibbs#include <cam/scsi/scsi_all.h>
4239223Sgibbs
4339223Sgibbsstatic	int bt_isa_probe __P((struct isa_device *dev));
4439223Sgibbsstatic	int bt_isa_attach __P((struct isa_device *dev));
4539223Sgibbsstatic	void bt_isa_intr __P((void *unit));
4639223Sgibbs
4739223Sgibbsstatic	bus_dma_filter_t btvlbouncefilter;
4839223Sgibbsstatic	bus_dmamap_callback_t btmapsensebuffers;
4939223Sgibbs
5039223Sgibbsstruct isa_driver btdriver =
5139223Sgibbs{
5239223Sgibbs    bt_isa_probe,
5339223Sgibbs    bt_isa_attach,
5439223Sgibbs    "bt"
5539223Sgibbs};
5639223Sgibbs
5739223Sgibbs/*
5839223Sgibbs * Check if the device can be found at the port given
5939223Sgibbs * and if so, set it up ready for further work
6039223Sgibbs * as an argument, takes the isa_device structure from
6139223Sgibbs * autoconf.c
6239223Sgibbs */
6339223Sgibbsstatic int
6439223Sgibbsbt_isa_probe(dev)
6539223Sgibbs	struct isa_device *dev;
6639223Sgibbs{
6739223Sgibbs	/*
6839223Sgibbs	 * find unit and check we have that many defined
6939223Sgibbs	 */
7039223Sgibbs	struct	bt_softc *bt;
7139223Sgibbs	int	port_index;
7239223Sgibbs        int	max_port_index;
7339223Sgibbs
7439223Sgibbs	/*
7539223Sgibbs	 * We ignore the unit number assigned by config to allow
7639223Sgibbs	 * consistant numbering between PCI/EISA/ISA devices.
7739223Sgibbs	 * This is a total kludge until we have a configuration
7839223Sgibbs	 * manager.
7939223Sgibbs	 */
8039223Sgibbs	dev->id_unit = bt_unit;
8139223Sgibbs
8239223Sgibbs	bt = NULL;
8339223Sgibbs	port_index = 0;
8439223Sgibbs	max_port_index = BT_NUM_ISAPORTS - 1;
8539223Sgibbs	/*
8639223Sgibbs	 * Bound our board search if the user has
8739223Sgibbs	 * specified an exact port.
8839223Sgibbs	 */
8939223Sgibbs	if (dev->id_iobase > 0) {
9039223Sgibbs		for (;port_index <= max_port_index; port_index++)
9139223Sgibbs			if (dev->id_iobase >= bt_isa_ports[port_index].addr)
9239223Sgibbs				break;
9339223Sgibbs		if ((port_index > max_port_index)
9439223Sgibbs		 || (dev->id_iobase != bt_isa_ports[port_index].addr)) {
9539223Sgibbs			printf("
9639223Sgibbsbt_isa_probe: Invalid baseport of 0x%x specified.
9739223Sgibbsbt_isa_probe: Nearest valid baseport is 0x%x.
9839223Sgibbsbt_isa_probe: Failing probe.\n",
9939223Sgibbs			       dev->id_iobase,
10039223Sgibbs			       (port_index <= max_port_index)
10139223Sgibbs				    ? bt_isa_ports[port_index].addr
10239223Sgibbs				    : bt_isa_ports[max_port_index].addr);
10339223Sgibbs			return 0;
10439223Sgibbs		}
10540160Simp		max_port_index = port_index;
10639223Sgibbs	}
10739223Sgibbs
10839223Sgibbs	/* Attempt to find an adapter */
10939223Sgibbs	for (;port_index <= max_port_index; port_index++) {
11039223Sgibbs		config_data_t config_data;
11139223Sgibbs		u_int ioport;
11239223Sgibbs		int error;
11339223Sgibbs
11439223Sgibbs		ioport = bt_isa_ports[port_index].addr;
11539223Sgibbs
11639223Sgibbs		/*
11739223Sgibbs		 * Ensure this port has not already been claimed already
11839223Sgibbs		 * by a PCI or EISA adapter.
11939223Sgibbs		 */
12039223Sgibbs		if (bt_check_probed_iop(ioport) != 0)
12139223Sgibbs			continue;
12239223Sgibbs
12340160Simp		/*
12440160Simp		 * Make sure that we do not conflict with another device's
12540160Simp		 * I/O address.
12640160Simp		 */
12740160Simp		if (haveseen_isadev(dev, CC_IOADDR))
12840160Simp			continue;
12940160Simp
13039223Sgibbs		/* Allocate a softc for use during probing */
13139223Sgibbs		bt = bt_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport);
13239223Sgibbs
13339223Sgibbs		if (bt == NULL)
13439223Sgibbs			break;
13539223Sgibbs
13639223Sgibbs		/* We're going to attempt to probe it now, so mark it probed */
13739223Sgibbs		bt_mark_probed_bio(port_index);
13839223Sgibbs
13939223Sgibbs		/* See if there is really a card present */
14039223Sgibbs		if (bt_probe(bt) || bt_fetch_adapter_info(bt)) {
14139223Sgibbs			bt_free(bt);
14239223Sgibbs			continue;
14339223Sgibbs		}
14439223Sgibbs
14539223Sgibbs		/*
14639223Sgibbs		 * Determine our IRQ, and DMA settings and
14739223Sgibbs		 * export them to the configuration system.
14839223Sgibbs		 */
14939223Sgibbs		error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
15039223Sgibbs			       (u_int8_t*)&config_data, sizeof(config_data),
15139223Sgibbs			       DEFAULT_CMD_TIMEOUT);
15239223Sgibbs		if (error != 0) {
15339223Sgibbs			printf("bt_isa_probe: Could not determine IRQ or DMA "
15439223Sgibbs			       "settings for adapter at 0x%x.  Failing probe\n",
15539223Sgibbs			       ioport);
15639223Sgibbs			bt_free(bt);
15739223Sgibbs			continue;
15839223Sgibbs		}
15939223Sgibbs
16039223Sgibbs		if (bt->model[0] == '5') {
16139223Sgibbs			/* DMA settings only make sense for ISA cards */
16239223Sgibbs			switch (config_data.dma_chan) {
16339223Sgibbs			case DMA_CHAN_5:
16439223Sgibbs				dev->id_drq = 5;
16539223Sgibbs				break;
16639223Sgibbs			case DMA_CHAN_6:
16739223Sgibbs				dev->id_drq = 6;
16839223Sgibbs				break;
16939223Sgibbs			case DMA_CHAN_7:
17039223Sgibbs				dev->id_drq = 7;
17139223Sgibbs				break;
17239223Sgibbs			default:
17339223Sgibbs				printf("bt_isa_probe: Invalid DMA setting "
17439223Sgibbs				       "detected for adapter at 0x%x.  "
17539223Sgibbs				       "Failing probe\n", ioport);
17639223Sgibbs			}
17739223Sgibbs		} else {
17839223Sgibbs			/* VL DMA */
17939223Sgibbs			dev->id_drq = -1;
18039223Sgibbs		}
18139223Sgibbs		dev->id_iobase = bt_isa_ports[port_index].addr;
18239223Sgibbs		dev->id_irq = (config_data.irq << 9);
18339223Sgibbs		dev->id_intr = bt_isa_intr;
18440160Simp
18540160Simp		/*
18640160Simp		 * OK, check to make sure that we're not stepping on
18740160Simp		 * someone else's IRQ or DRQ
18840160Simp		 */
18940160Simp		if (haveseen_isadev(dev, CC_DRQ)) {
19040160Simp			printf("bt_isa_probe: Bt card at I/O 0x%x's drq %d "
19140160Simp				"conflicts, ignoring card.\n", dev->id_iobase,
19240160Simp				dev->id_drq);
19340160Simp			bt_free(bt);
19440160Simp			return 0;
19540160Simp		}
19640160Simp		if (haveseen_isadev(dev, CC_IRQ)) {
19740160Simp			printf("bt_isa_probe: Bt card at I/O 0x%x's irq %d "
19840160Simp				"conflicts, ignoring card.\n", dev->id_iobase,
19940160Simp				config_data.irq + 9);
20040160Simp			bt_free(bt);
20140160Simp			return 0;
20240160Simp		}
20339223Sgibbs		bt_unit++;
20439223Sgibbs		return (BT_NREGS);
20539223Sgibbs	}
20639223Sgibbs
20739223Sgibbs	return (0);
20839223Sgibbs}
20939223Sgibbs
21039223Sgibbs/*
21139223Sgibbs * Attach all the sub-devices we can find
21239223Sgibbs */
21339223Sgibbsstatic int
21439223Sgibbsbt_isa_attach(dev)
21539223Sgibbs	struct isa_device *dev;
21639223Sgibbs{
21739223Sgibbs	struct	bt_softc *bt;
21839223Sgibbs	bus_dma_filter_t *filter;
21939223Sgibbs	void		 *filter_arg;
22039223Sgibbs	bus_addr_t	 lowaddr;
22139223Sgibbs
22239223Sgibbs	bt = bt_softcs[dev->id_unit];
22339223Sgibbs	if (dev->id_drq != -1)
22439223Sgibbs		isa_dmacascade(dev->id_drq);
22539223Sgibbs
22639223Sgibbs	/* Allocate our parent dmatag */
22739223Sgibbs	filter = NULL;
22839223Sgibbs	filter_arg = NULL;
22939223Sgibbs	lowaddr = BUS_SPACE_MAXADDR_24BIT;
23039223Sgibbs	if (bt->model[0] == '4') {
23139223Sgibbs		/*
23239223Sgibbs		 * This is a VL adapter.  Typically, VL devices have access
23339223Sgibbs		 * to the full 32bit address space.  On BT-445S adapters
23439223Sgibbs		 * prior to revision E, there is a hardware bug that causes
23539223Sgibbs		 * corruption of transfers to/from addresses in the range of
23639223Sgibbs		 * the BIOS modulo 16MB.  The only properly functioning
23739223Sgibbs		 * BT-445S Host Adapters have firmware version 3.37.
23839223Sgibbs		 * If we encounter one of these adapters and the BIOS is
23939223Sgibbs		 * installed, install a filter function for our bus_dma_map
24039223Sgibbs		 * that will catch these accesses and bounce them to a safe
24139223Sgibbs		 * region of memory.
24239223Sgibbs		 */
24339223Sgibbs		if (bt->bios_addr != 0
24439223Sgibbs		 && strcmp(bt->model, "445S") == 0
24539223Sgibbs		 && strcmp(bt->firmware_ver, "3.37") < 0) {
24639223Sgibbs			filter = btvlbouncefilter;
24739223Sgibbs			filter_arg = bt;
24839223Sgibbs		} else {
24939223Sgibbs			lowaddr = BUS_SPACE_MAXADDR_32BIT;
25039223Sgibbs		}
25139223Sgibbs	}
25239223Sgibbs
25339223Sgibbs	/* XXX Should be a child of the ISA or VL bus dma tag */
25439223Sgibbs	if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0,
25539223Sgibbs                               lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
25639223Sgibbs                               filter, filter_arg,
25739223Sgibbs                               /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
25839223Sgibbs                               /*nsegments*/BUS_SPACE_UNRESTRICTED,
25939223Sgibbs                               /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
26039223Sgibbs                               /*flags*/0, &bt->parent_dmat) != 0) {
26139223Sgibbs                bt_free(bt);
26239223Sgibbs                return (-1);
26339223Sgibbs        }
26439223Sgibbs
26539223Sgibbs        if (bt_init(bt)) {
26639223Sgibbs                bt_free(bt);
26739223Sgibbs                return (-1);
26839223Sgibbs        }
26939223Sgibbs
27039223Sgibbs	if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
27139223Sgibbs		/* DMA tag for our sense buffers */
27239223Sgibbs		if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0,
27339223Sgibbs				       /*boundary*/0,
27439223Sgibbs				       /*lowaddr*/BUS_SPACE_MAXADDR,
27539223Sgibbs				       /*highaddr*/BUS_SPACE_MAXADDR,
27639223Sgibbs				       /*filter*/NULL, /*filterarg*/NULL,
27739223Sgibbs				       bt->max_ccbs
27839223Sgibbs					   * sizeof(struct scsi_sense_data),
27939223Sgibbs				       /*nsegments*/1,
28039223Sgibbs				       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
28139223Sgibbs				       /*flags*/0, &bt->sense_dmat) != 0) {
28239223Sgibbs			bt_free(bt);
28339223Sgibbs			return (-1);
28439223Sgibbs		}
28539223Sgibbs
28639223Sgibbs		bt->init_level++;
28739223Sgibbs
28839223Sgibbs		/* Allocation of sense buffers */
28939223Sgibbs		if (bus_dmamem_alloc(bt->sense_dmat,
29039223Sgibbs				     (void **)&bt->sense_buffers,
29139223Sgibbs				     BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
29239223Sgibbs			bt_free(bt);
29339223Sgibbs			return (-1);
29439223Sgibbs		}
29539223Sgibbs
29639223Sgibbs		bt->init_level++;
29739223Sgibbs
29839223Sgibbs		/* And permanently map them */
29939223Sgibbs		bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
30039223Sgibbs       				bt->sense_buffers,
30139223Sgibbs				bt->max_ccbs * sizeof(*bt->sense_buffers),
30239223Sgibbs				btmapsensebuffers, bt, /*flags*/0);
30339223Sgibbs
30439223Sgibbs		bt->init_level++;
30539223Sgibbs	}
30639223Sgibbs
30739223Sgibbs	return (bt_attach(bt));
30839223Sgibbs}
30939223Sgibbs
31039223Sgibbs/*
31139223Sgibbs * Handle an ISA interrupt.
31239223Sgibbs * XXX should go away as soon as ISA interrupt handlers
31339223Sgibbs * take a (void *) arg.
31439223Sgibbs */
31539223Sgibbsstatic void
31639223Sgibbsbt_isa_intr(void *unit)
31739223Sgibbs{
31839223Sgibbs	struct bt_softc* arg = bt_softcs[(int)unit];
31939223Sgibbs	bt_intr((void *)arg);
32039223Sgibbs}
32139223Sgibbs
32239223Sgibbs#define BIOS_MAP_SIZE (16 * 1024)
32339223Sgibbs
32439223Sgibbsstatic int
32539223Sgibbsbtvlbouncefilter(void *arg, bus_addr_t addr)
32639223Sgibbs{
32739223Sgibbs	struct bt_softc *bt;
32839223Sgibbs
32939223Sgibbs	bt = (struct bt_softc *)arg;
33039223Sgibbs
33139223Sgibbs	addr &= BUS_SPACE_MAXADDR_24BIT;
33239223Sgibbs
33339223Sgibbs	if (addr == 0
33439223Sgibbs	 || (addr >= bt->bios_addr
33539223Sgibbs	  && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
33639223Sgibbs		return (1);
33739223Sgibbs	return (0);
33839223Sgibbs}
33939223Sgibbs
34039223Sgibbsstatic void
34139223Sgibbsbtmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
34239223Sgibbs{
34339223Sgibbs	struct bt_softc* bt;
34439223Sgibbs
34539223Sgibbs	bt = (struct bt_softc*)arg;
34639223Sgibbs	bt->sense_buffers_physbase = segs->ds_addr;
34739223Sgibbs}
348