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