bt_isa.c revision 40265
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.3 1998/10/10 00:44:12 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	if (dev->id_iobase > 0) {
90		for (;port_index <= max_port_index; port_index++)
91			if (dev->id_iobase >= bt_isa_ports[port_index].addr)
92				break;
93		if ((port_index > max_port_index)
94		 || (dev->id_iobase != bt_isa_ports[port_index].addr)) {
95			printf("
96bt_isa_probe: Invalid baseport of 0x%x specified.
97bt_isa_probe: Nearest valid baseport is 0x%x.
98bt_isa_probe: Failing probe.\n",
99			       dev->id_iobase,
100			       (port_index <= max_port_index)
101				    ? bt_isa_ports[port_index].addr
102				    : bt_isa_ports[max_port_index].addr);
103			return 0;
104		}
105		max_port_index = port_index;
106	}
107
108	/* Attempt to find an adapter */
109	for (;port_index <= max_port_index; port_index++) {
110		config_data_t config_data;
111		u_int ioport;
112		int error;
113
114		ioport = bt_isa_ports[port_index].addr;
115
116		/*
117		 * Ensure this port has not already been claimed already
118		 * by a PCI, EISA or ISA adapter.
119		 */
120		if (bt_check_probed_iop(ioport) != 0)
121			continue;
122		dev->id_iobase = bt_isa_ports[port_index].addr;
123		if (haveseen_isadev(dev, CC_IOADDR | CC_QUIET))
124			continue;
125
126		/* Allocate a softc for use during probing */
127		bt = bt_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport);
128
129		if (bt == NULL)
130			break;
131
132		/* We're going to attempt to probe it now, so mark it probed */
133		bt_mark_probed_bio(port_index);
134
135		/* See if there is really a card present */
136		if (bt_probe(bt) || bt_fetch_adapter_info(bt)) {
137			bt_free(bt);
138			continue;
139		}
140
141		/*
142		 * Determine our IRQ, and DMA settings and
143		 * export them to the configuration system.
144		 */
145		error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
146			       (u_int8_t*)&config_data, sizeof(config_data),
147			       DEFAULT_CMD_TIMEOUT);
148		if (error != 0) {
149			printf("bt_isa_probe: Could not determine IRQ or DMA "
150			       "settings for adapter at 0x%x.  Failing probe\n",
151			       ioport);
152			bt_free(bt);
153			continue;
154		}
155
156		if (bt->model[0] == '5') {
157			/* DMA settings only make sense for ISA cards */
158			switch (config_data.dma_chan) {
159			case DMA_CHAN_5:
160				dev->id_drq = 5;
161				break;
162			case DMA_CHAN_6:
163				dev->id_drq = 6;
164				break;
165			case DMA_CHAN_7:
166				dev->id_drq = 7;
167				break;
168			default:
169				printf("bt_isa_probe: Invalid DMA setting "
170				       "detected for adapter at 0x%x.  "
171				       "Failing probe\n", ioport);
172			}
173		} else {
174			/* VL DMA */
175			dev->id_drq = -1;
176		}
177		dev->id_irq = (config_data.irq << 9);
178		dev->id_intr = bt_isa_intr;
179
180		bt_unit++;
181		return (BT_NREGS);
182	}
183
184	return (0);
185}
186
187/*
188 * Attach all the sub-devices we can find
189 */
190static int
191bt_isa_attach(dev)
192	struct isa_device *dev;
193{
194	struct	bt_softc *bt;
195	bus_dma_filter_t *filter;
196	void		 *filter_arg;
197	bus_addr_t	 lowaddr;
198
199	bt = bt_softcs[dev->id_unit];
200	if (dev->id_drq != -1)
201		isa_dmacascade(dev->id_drq);
202
203	/* Allocate our parent dmatag */
204	filter = NULL;
205	filter_arg = NULL;
206	lowaddr = BUS_SPACE_MAXADDR_24BIT;
207	if (bt->model[0] == '4') {
208		/*
209		 * This is a VL adapter.  Typically, VL devices have access
210		 * to the full 32bit address space.  On BT-445S adapters
211		 * prior to revision E, there is a hardware bug that causes
212		 * corruption of transfers to/from addresses in the range of
213		 * the BIOS modulo 16MB.  The only properly functioning
214		 * BT-445S Host Adapters have firmware version 3.37.
215		 * If we encounter one of these adapters and the BIOS is
216		 * installed, install a filter function for our bus_dma_map
217		 * that will catch these accesses and bounce them to a safe
218		 * region of memory.
219		 */
220		if (bt->bios_addr != 0
221		 && strcmp(bt->model, "445S") == 0
222		 && strcmp(bt->firmware_ver, "3.37") < 0) {
223			filter = btvlbouncefilter;
224			filter_arg = bt;
225		} else {
226			lowaddr = BUS_SPACE_MAXADDR_32BIT;
227		}
228	}
229
230	/* XXX Should be a child of the ISA or VL bus dma tag */
231	if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0,
232                               lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
233                               filter, filter_arg,
234                               /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
235                               /*nsegments*/BUS_SPACE_UNRESTRICTED,
236                               /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
237                               /*flags*/0, &bt->parent_dmat) != 0) {
238                bt_free(bt);
239                return (-1);
240        }
241
242        if (bt_init(bt)) {
243                bt_free(bt);
244                return (-1);
245        }
246
247	if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
248		/* DMA tag for our sense buffers */
249		if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0,
250				       /*boundary*/0,
251				       /*lowaddr*/BUS_SPACE_MAXADDR,
252				       /*highaddr*/BUS_SPACE_MAXADDR,
253				       /*filter*/NULL, /*filterarg*/NULL,
254				       bt->max_ccbs
255					   * sizeof(struct scsi_sense_data),
256				       /*nsegments*/1,
257				       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
258				       /*flags*/0, &bt->sense_dmat) != 0) {
259			bt_free(bt);
260			return (-1);
261		}
262
263		bt->init_level++;
264
265		/* Allocation of sense buffers */
266		if (bus_dmamem_alloc(bt->sense_dmat,
267				     (void **)&bt->sense_buffers,
268				     BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
269			bt_free(bt);
270			return (-1);
271		}
272
273		bt->init_level++;
274
275		/* And permanently map them */
276		bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
277       				bt->sense_buffers,
278				bt->max_ccbs * sizeof(*bt->sense_buffers),
279				btmapsensebuffers, bt, /*flags*/0);
280
281		bt->init_level++;
282	}
283
284	return (bt_attach(bt));
285}
286
287/*
288 * Handle an ISA interrupt.
289 * XXX should go away as soon as ISA interrupt handlers
290 * take a (void *) arg.
291 */
292static void
293bt_isa_intr(void *unit)
294{
295	struct bt_softc* arg = bt_softcs[(int)unit];
296	bt_intr((void *)arg);
297}
298
299#define BIOS_MAP_SIZE (16 * 1024)
300
301static int
302btvlbouncefilter(void *arg, bus_addr_t addr)
303{
304	struct bt_softc *bt;
305
306	bt = (struct bt_softc *)arg;
307
308	addr &= BUS_SPACE_MAXADDR_24BIT;
309
310	if (addr == 0
311	 || (addr >= bt->bios_addr
312	  && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
313		return (1);
314	return (0);
315}
316
317static void
318btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
319{
320	struct bt_softc* bt;
321
322	bt = (struct bt_softc*)arg;
323	bt->sense_buffers_physbase = segs->ds_addr;
324}
325