bt_isa.c revision 41048
1/*
2 * Product specific probe and attach routines for:
3 *      Buslogic BT-54X and BT-445 cards
4 *
5 * Copyright (c) 1998 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 *	$Id: bt_isa.c,v 1.4 1998/10/12 18:53:33 imp Exp $
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34
35#include <machine/bus_pio.h>
36#include <machine/bus.h>
37
38#include <i386/isa/isa_device.h>
39#include <dev/buslogic/btreg.h>
40
41#include <cam/scsi/scsi_all.h>
42
43static	int bt_isa_probe __P((struct isa_device *dev));
44static	int bt_isa_attach __P((struct isa_device *dev));
45static	void bt_isa_intr __P((void *unit));
46
47static	bus_dma_filter_t btvlbouncefilter;
48static	bus_dmamap_callback_t btmapsensebuffers;
49
50struct isa_driver btdriver =
51{
52    bt_isa_probe,
53    bt_isa_attach,
54    "bt"
55};
56
57/*
58 * Check if the device can be found at the port given
59 * and if so, set it up ready for further work
60 * as an argument, takes the isa_device structure from
61 * autoconf.c
62 */
63static int
64bt_isa_probe(dev)
65	struct isa_device *dev;
66{
67	/*
68	 * find unit and check we have that many defined
69	 */
70	struct	bt_softc *bt;
71	int	port_index;
72        int	max_port_index;
73
74	/*
75	 * We ignore the unit number assigned by config to allow
76	 * consistant numbering between PCI/EISA/ISA devices.
77	 * This is a total kludge until we have a configuration
78	 * manager.
79	 */
80	dev->id_unit = bt_unit;
81
82	bt = NULL;
83	port_index = 0;
84	max_port_index = BT_NUM_ISAPORTS - 1;
85	/*
86	 * Bound our board search if the user has
87	 * specified an exact port.
88	 */
89	bt_find_probe_range(dev->id_iobase, &port_index, &max_port_index);
90
91	if (port_index < 0)
92		return 0;
93
94	/* Attempt to find an adapter */
95	for (;port_index <= max_port_index; port_index++) {
96		config_data_t config_data;
97		u_int ioport;
98		int error;
99
100		ioport = bt_iop_from_bio(port_index);
101
102		/*
103		 * Ensure this port has not already been claimed already
104		 * by a PCI, EISA or ISA adapter.
105		 */
106		if (bt_check_probed_iop(ioport) != 0)
107			continue;
108		dev->id_iobase = ioport;
109		if (haveseen_isadev(dev, CC_IOADDR | CC_QUIET))
110			continue;
111
112		/* Allocate a softc for use during probing */
113		bt = bt_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport);
114
115		if (bt == NULL)
116			break;
117
118		/* We're going to attempt to probe it now, so mark it probed */
119		bt_mark_probed_bio(port_index);
120
121		/* See if there is really a card present */
122		if (bt_probe(bt) || bt_fetch_adapter_info(bt)) {
123			bt_free(bt);
124			continue;
125		}
126
127		/*
128		 * Determine our IRQ, and DMA settings and
129		 * export them to the configuration system.
130		 */
131		error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
132			       (u_int8_t*)&config_data, sizeof(config_data),
133			       DEFAULT_CMD_TIMEOUT);
134		if (error != 0) {
135			printf("bt_isa_probe: Could not determine IRQ or DMA "
136			       "settings for adapter at 0x%x.  Failing probe\n",
137			       ioport);
138			bt_free(bt);
139			continue;
140		}
141
142		if (bt->model[0] == '5') {
143			/* DMA settings only make sense for ISA cards */
144			switch (config_data.dma_chan) {
145			case DMA_CHAN_5:
146				dev->id_drq = 5;
147				break;
148			case DMA_CHAN_6:
149				dev->id_drq = 6;
150				break;
151			case DMA_CHAN_7:
152				dev->id_drq = 7;
153				break;
154			default:
155				printf("bt_isa_probe: Invalid DMA setting "
156				       "detected for adapter at 0x%x.  "
157				       "Failing probe\n", ioport);
158				return (0);
159			}
160		} else {
161			/* VL DMA */
162			dev->id_drq = -1;
163		}
164		dev->id_irq = (config_data.irq << 9);
165		dev->id_intr = bt_isa_intr;
166
167		bt_unit++;
168		return (BT_NREGS);
169	}
170
171	return (0);
172}
173
174/*
175 * Attach all the sub-devices we can find
176 */
177static int
178bt_isa_attach(dev)
179	struct isa_device *dev;
180{
181	struct	bt_softc *bt;
182	bus_dma_filter_t *filter;
183	void		 *filter_arg;
184	bus_addr_t	 lowaddr;
185
186	bt = bt_softcs[dev->id_unit];
187	if (dev->id_drq != -1)
188		isa_dmacascade(dev->id_drq);
189
190	/* Allocate our parent dmatag */
191	filter = NULL;
192	filter_arg = NULL;
193	lowaddr = BUS_SPACE_MAXADDR_24BIT;
194	if (bt->model[0] == '4') {
195		/*
196		 * This is a VL adapter.  Typically, VL devices have access
197		 * to the full 32bit address space.  On BT-445S adapters
198		 * prior to revision E, there is a hardware bug that causes
199		 * corruption of transfers to/from addresses in the range of
200		 * the BIOS modulo 16MB.  The only properly functioning
201		 * BT-445S Host Adapters have firmware version 3.37.
202		 * If we encounter one of these adapters and the BIOS is
203		 * installed, install a filter function for our bus_dma_map
204		 * that will catch these accesses and bounce them to a safe
205		 * region of memory.
206		 */
207		if (bt->bios_addr != 0
208		 && strcmp(bt->model, "445S") == 0
209		 && strcmp(bt->firmware_ver, "3.37") < 0) {
210			filter = btvlbouncefilter;
211			filter_arg = bt;
212		} else {
213			lowaddr = BUS_SPACE_MAXADDR_32BIT;
214		}
215	}
216
217	/* XXX Should be a child of the ISA or VL bus dma tag */
218	if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0,
219                               lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
220                               filter, filter_arg,
221                               /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
222                               /*nsegments*/BUS_SPACE_UNRESTRICTED,
223                               /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
224                               /*flags*/0, &bt->parent_dmat) != 0) {
225                bt_free(bt);
226                return (-1);
227        }
228
229        if (bt_init(bt)) {
230                bt_free(bt);
231                return (-1);
232        }
233
234	if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
235		/* DMA tag for our sense buffers */
236		if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0,
237				       /*boundary*/0,
238				       /*lowaddr*/BUS_SPACE_MAXADDR,
239				       /*highaddr*/BUS_SPACE_MAXADDR,
240				       /*filter*/NULL, /*filterarg*/NULL,
241				       bt->max_ccbs
242					   * sizeof(struct scsi_sense_data),
243				       /*nsegments*/1,
244				       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
245				       /*flags*/0, &bt->sense_dmat) != 0) {
246			bt_free(bt);
247			return (-1);
248		}
249
250		bt->init_level++;
251
252		/* Allocation of sense buffers */
253		if (bus_dmamem_alloc(bt->sense_dmat,
254				     (void **)&bt->sense_buffers,
255				     BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
256			bt_free(bt);
257			return (-1);
258		}
259
260		bt->init_level++;
261
262		/* And permanently map them */
263		bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
264       				bt->sense_buffers,
265				bt->max_ccbs * sizeof(*bt->sense_buffers),
266				btmapsensebuffers, bt, /*flags*/0);
267
268		bt->init_level++;
269	}
270
271	return (bt_attach(bt));
272}
273
274/*
275 * Handle an ISA interrupt.
276 * XXX should go away as soon as ISA interrupt handlers
277 * take a (void *) arg.
278 */
279static void
280bt_isa_intr(void *unit)
281{
282	struct bt_softc* arg = bt_softcs[(int)unit];
283	bt_intr((void *)arg);
284}
285
286#define BIOS_MAP_SIZE (16 * 1024)
287
288static int
289btvlbouncefilter(void *arg, bus_addr_t addr)
290{
291	struct bt_softc *bt;
292
293	bt = (struct bt_softc *)arg;
294
295	addr &= BUS_SPACE_MAXADDR_24BIT;
296
297	if (addr == 0
298	 || (addr >= bt->bios_addr
299	  && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
300		return (1);
301	return (0);
302}
303
304static void
305btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
306{
307	struct bt_softc* bt;
308
309	bt = (struct bt_softc*)arg;
310	bt->sense_buffers_physbase = segs->ds_addr;
311}
312