bt_isa.c revision 331722
1/*-
2 * Product specific probe and attach routines for:
3 *      Buslogic BT-54X and BT-445 cards
4 *
5 * Copyright (c) 1998, 1999 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 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/11/sys/dev/buslogic/bt_isa.c 331722 2018-03-29 02:50:57Z eadler $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/module.h>
38#include <sys/lock.h>
39#include <sys/mutex.h>
40#include <sys/bus.h>
41
42#include <machine/bus.h>
43#include <machine/resource.h>
44#include <sys/rman.h>
45
46#include <isa/isavar.h>
47#include <dev/buslogic/btreg.h>
48
49#include <cam/scsi/scsi_all.h>
50
51static	bus_dma_filter_t btvlbouncefilter;
52static	bus_dmamap_callback_t btmapsensebuffers;
53
54static int
55bt_isa_alloc_resources(device_t dev, u_long portstart, u_long portend)
56{
57	int rid;
58	struct resource *port;
59	struct resource *irq;
60	struct resource *drq;
61
62	rid = 0;
63	port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
64				  portstart, portend, BT_NREGS, RF_ACTIVE);
65	if (!port)
66		return (ENOMEM);
67
68	if (isa_get_irq(dev) != -1) {
69		rid = 0;
70		irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
71		if (!irq) {
72			if (port)
73				bus_release_resource(dev, SYS_RES_IOPORT,
74						     0, port);
75			return (ENOMEM);
76		}
77	} else
78		irq = NULL;
79
80	if (isa_get_drq(dev) != -1) {
81		rid = 0;
82		drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, RF_ACTIVE);
83		if (!drq) {
84			if (port)
85				bus_release_resource(dev, SYS_RES_IOPORT,
86						     0, port);
87			if (irq)
88				bus_release_resource(dev, SYS_RES_IRQ,
89						     0, irq);
90			return (ENOMEM);
91		}
92	} else
93		drq = NULL;
94
95	bt_init_softc(dev, port, irq, drq);
96
97	return (0);
98}
99
100static void
101bt_isa_release_resources(device_t dev)
102{
103	struct	bt_softc *bt = device_get_softc(dev);
104
105	if (bt->port)
106		bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
107	if (bt->irq)
108		bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
109	if (bt->drq)
110		bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
111	bt_free_softc(dev);
112}
113
114/*
115 * Check if the device can be found at the port given
116 * and if so, set it up ready for further work
117 * as an argument, takes the isa_device structure from
118 * autoconf.c
119 */
120static int
121bt_isa_probe(device_t dev)
122{
123	/*
124	 * find unit and check we have that many defined
125	 */
126	int	port_index;
127        int	max_port_index;
128
129	/* No pnp support */
130	if (isa_get_vendorid(dev))
131		return (ENXIO);
132
133	port_index = 0;
134	max_port_index = BT_NUM_ISAPORTS - 1;
135	/*
136	 * Bound our board search if the user has
137	 * specified an exact port.
138	 */
139	bt_find_probe_range(isa_get_port(dev), &port_index, &max_port_index);
140
141	if (port_index < 0)
142		return (ENXIO);
143
144	/* Attempt to find an adapter */
145	for (;port_index <= max_port_index; port_index++) {
146		struct bt_probe_info info;
147		u_int ioport;
148
149		ioport = bt_iop_from_bio(port_index);
150
151		/*
152		 * Ensure this port has not already been claimed already
153		 * by a PCI, EISA or ISA adapter.
154		 */
155		if (bt_check_probed_iop(ioport) != 0)
156			continue;
157
158		/* Initialise the softc for use during probing */
159		if (bt_isa_alloc_resources(dev, ioport,
160					   ioport + BT_NREGS -1) != 0)
161			continue;
162
163		/* We're going to attempt to probe it now, so mark it probed */
164		bt_mark_probed_bio(port_index);
165
166		if (bt_port_probe(dev, &info) != 0) {
167			if (bootverbose)
168				printf("bt_isa_probe: Probe failed at 0x%x\n",
169				       ioport);
170			bt_isa_release_resources(dev);
171			continue;
172		}
173
174		bt_isa_release_resources(dev);
175
176		bus_set_resource(dev, SYS_RES_DRQ, 0, info.drq, 1);
177		bus_set_resource(dev, SYS_RES_IRQ, 0, info.irq, 1);
178
179		return (BUS_PROBE_DEFAULT);
180	}
181
182	return (ENXIO);
183}
184
185/*
186 * Attach all the sub-devices we can find
187 */
188static int
189bt_isa_attach(device_t dev)
190{
191	struct	bt_softc *bt = device_get_softc(dev);
192	bus_dma_filter_t *filter;
193	void		 *filter_arg;
194	bus_addr_t	 lowaddr;
195	int		 error, drq;
196
197	/* Initialise softc */
198	error = bt_isa_alloc_resources(dev, 0, ~0);
199	if (error) {
200		device_printf(dev, "can't allocate resources in bt_isa_attach\n");
201		return error;
202	}
203
204	/* Program the DMA channel for external control */
205	if ((drq = isa_get_drq(dev)) != -1)
206		isa_dmacascade(drq);
207
208	/* Allocate our parent dmatag */
209	filter = NULL;
210	filter_arg = NULL;
211	lowaddr = BUS_SPACE_MAXADDR_24BIT;
212	if (bt->model[0] == '4') {
213		/*
214		 * This is a VL adapter.  Typically, VL devices have access
215		 * to the full 32bit address space.  On BT-445S adapters
216		 * prior to revision E, there is a hardware bug that causes
217		 * corruption of transfers to/from addresses in the range of
218		 * the BIOS modulo 16MB.  The only properly functioning
219		 * BT-445S Host Adapters have firmware version 3.37.
220		 * If we encounter one of these adapters and the BIOS is
221		 * installed, install a filter function for our bus_dma_map
222		 * that will catch these accesses and bounce them to a safe
223		 * region of memory.
224		 */
225		if (bt->bios_addr != 0
226		 && strcmp(bt->model, "445S") == 0
227		 && strcmp(bt->firmware_ver, "3.37") < 0) {
228			filter = btvlbouncefilter;
229			filter_arg = bt;
230		} else {
231			lowaddr = BUS_SPACE_MAXADDR_32BIT;
232		}
233	}
234
235	/* XXX Should be a child of the ISA or VL bus dma tag */
236	if (bus_dma_tag_create(	/* parent	*/ bus_get_dma_tag(dev),
237				/* alignemnt	*/ 1,
238				/* boundary	*/ 0,
239				/* lowaddr	*/ lowaddr,
240				/* highaddr	*/ BUS_SPACE_MAXADDR,
241				/* filter	*/ filter,
242				/* filterarg	*/ filter_arg,
243				/* maxsize	*/ BUS_SPACE_MAXSIZE_32BIT,
244				/* nsegments	*/ ~0,
245				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
246				/* flags	*/ 0,
247				/* lockfunc	*/ NULL,
248				/* lockarg	*/ NULL,
249				&bt->parent_dmat) != 0) {
250		bt_isa_release_resources(dev);
251                return (ENOMEM);
252        }
253
254        error = bt_init(dev);
255        if (error) {
256		bt_isa_release_resources(dev);
257                return (ENOMEM);
258        }
259
260	if (lowaddr != BUS_SPACE_MAXADDR_32BIT) {
261		/* DMA tag for our sense buffers */
262		if (bus_dma_tag_create(
263				/* parent	*/ bt->parent_dmat,
264				/* alignment	*/ 1,
265				/* boundary	*/ 0,
266				/* lowaddr	*/ BUS_SPACE_MAXADDR,
267				/* highaddr	*/ BUS_SPACE_MAXADDR,
268				/* filter	*/ NULL,
269				/* filterarg	*/ NULL,
270				/* maxsize	*/ bt->max_ccbs *
271						   sizeof(struct scsi_sense_data),
272				/* nsegments	*/ 1,
273				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
274				/* flags	*/ 0,
275				/* lockfunc	*/ NULL,
276				/* lockarg	*/ NULL,
277				&bt->sense_dmat) != 0) {
278			bt_isa_release_resources(dev);
279			return (ENOMEM);
280		}
281
282		bt->init_level++;
283
284		/* Allocation of sense buffers */
285		if (bus_dmamem_alloc(bt->sense_dmat,
286				     (void **)&bt->sense_buffers,
287				     BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
288			bt_isa_release_resources(dev);
289			return (ENOMEM);
290		}
291
292		bt->init_level++;
293
294		/* And permanently map them */
295		bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
296       				bt->sense_buffers,
297				bt->max_ccbs * sizeof(*bt->sense_buffers),
298				btmapsensebuffers, bt, /*flags*/0);
299
300		bt->init_level++;
301	}
302
303	error = bt_attach(dev);
304	if (error) {
305		bt_isa_release_resources(dev);
306		return (error);
307	}
308
309	return (0);
310}
311
312#define BIOS_MAP_SIZE (16 * 1024)
313
314static int
315btvlbouncefilter(void *arg, bus_addr_t addr)
316{
317	struct bt_softc *bt;
318
319	bt = (struct bt_softc *)arg;
320
321	addr &= BUS_SPACE_MAXADDR_24BIT;
322
323	if (addr == 0
324	 || (addr >= bt->bios_addr
325	  && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
326		return (1);
327	return (0);
328}
329
330static void
331btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
332{
333	struct bt_softc* bt;
334
335	bt = (struct bt_softc*)arg;
336	bt->sense_buffers_physbase = segs->ds_addr;
337}
338
339static device_method_t bt_isa_methods[] = {
340	/* Device interface */
341	DEVMETHOD(device_probe,		bt_isa_probe),
342	DEVMETHOD(device_attach,	bt_isa_attach),
343
344	{ 0, 0 }
345};
346
347static driver_t bt_isa_driver = {
348	"bt",
349	bt_isa_methods,
350	sizeof(struct bt_softc),
351};
352
353static devclass_t bt_devclass;
354
355DRIVER_MODULE(bt, isa, bt_isa_driver, bt_devclass, 0, 0);
356MODULE_DEPEND(bt, isa, 1, 1, 1);
357