bt_mca.c revision 112782
1/*-
2 * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/buslogic/bt_mca.c 112782 2003-03-29 09:46:10Z mdodd $
27 */
28
29/*
30 * Written using the bt_isa/bt_pci code as a reference.
31 *
32 * Thanks to Andy Farkas <andyf@speednet.com.au> for
33 * testing and feedback.
34 */
35
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40
41#include <machine/cpufunc.h>
42#include <machine/md_var.h>
43
44#include <sys/module.h>
45#include <sys/bus.h>
46
47#include <machine/bus.h>
48#include <machine/resource.h>
49#include <sys/rman.h>
50
51#include <dev/mca/mca_busreg.h>
52#include <dev/mca/mca_busvar.h>
53
54#include <i386/isa/isa_dma.h>
55
56#include <dev/buslogic/btreg.h>
57
58#include <cam/scsi/scsi_all.h>
59
60static struct mca_ident bt_mca_devs[] = {
61	{ 0x0708, "BusLogic 32 Bit Bus Master MCA-to-SCSI Host Adapter" },
62	{ 0x0708, "BusTek BT-640A Micro Channel to SCSI Host Adapter" },
63	{ 0x0708, "Storage Dimensions SDC3211B 32-bit SCSI Host Adapter" },
64	{ 0x0709, "Storage Dimensions SDC3211F 32-bit FAST SCSI Host Adapter" },
65	{ 0, NULL },
66};
67
68#define BT_MCA_IOPORT_POS1		MCA_ADP_POS(MCA_POS0)
69#define BT_MCA_IOPORT_POS2		MCA_ADP_POS(MCA_POS1)
70#define BT_MCA_IOPORT_MASK1		0x10
71#define BT_MCA_IOPORT_MASK2		0x03
72#define BT_MCA_IOPORT_SIZE		0x03
73#define BT_MCA_IOPORT(pos)		(0x30 + \
74					(((u_int32_t)pos &\
75						BT_MCA_IOPORT_MASK2) << 8) + \
76					(((u_int32_t)pos &\
77						BT_MCA_IOPORT_MASK1) >> 2))
78
79#define BT_MCA_IRQ_POS			MCA_ADP_POS(MCA_POS0)
80#define BT_MCA_IRQ_MASK			0x0e
81#define BT_MCA_IRQ(pos)			(((pos & BT_MCA_IRQ_MASK) >> 1) + 8)
82
83#define BT_MCA_DRQ_POS			MCA_ADP_POS(MCA_POS3)
84#define BT_MCA_DRQ_MASK			0x0f
85#define BT_MCA_DRQ(pos)			(pos & BT_MCA_DRQ_MASK)
86
87#define BT_MCA_SCSIID_POS		MCA_ADP_POS(MCA_POS2)
88#define BT_MCA_SCSIID_MASK		0xe0
89#define BT_MCA_SCSIID(pos)		((pos & BT_MCA_SCSIID_MASK) >> 5)
90
91static	bus_dma_filter_t	btvlbouncefilter;
92static	bus_dmamap_callback_t	btmapsensebuffers;
93
94static void
95bt_mca_release_resources (device_t dev)
96{
97	struct  bt_softc *	bt = device_get_softc(dev);
98
99	if (bt->port)
100		bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port);
101	if (bt->irq)
102		bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq);
103	if (bt->drq)
104		bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq);
105
106	bt_free_softc(dev);
107}
108
109#define BT_MCA_PROBE	0
110#define BT_MCA_ATTACH	1
111
112static int
113bt_mca_alloc_resources(device_t dev, int mode)
114{
115	struct resource *	io = NULL;
116	struct resource *	irq = NULL;
117	struct resource *	drq = NULL;
118	int			rid;
119
120	rid = 0;
121	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
122				0, ~0, 1, RF_ACTIVE);
123	if (io == NULL) {
124		printf("bt_mca_alloc_resources() failed to allocate IOPORT\n");
125		return (ENOMEM);
126	}
127
128	if (mode == BT_MCA_ATTACH) {
129
130		rid = 0;
131		irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
132					 0, ~0, 1, RF_ACTIVE);
133		if (irq == NULL) {
134			printf("bt_mca_alloc_resources() failed to allocate IRQ\n");
135			goto bad;
136		}
137
138		rid = 0;
139		drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid,
140						 0, ~0, 1, RF_ACTIVE);
141		if (drq == NULL) {
142			printf("bt_mca_alloc_resources() failed to allocate DRQ\n");
143			goto bad;
144		}
145	}
146
147	bt_init_softc(dev, io, irq, drq);
148
149	return (0);
150bad:
151	bt_mca_release_resources(dev);
152	return (ENOMEM);
153}
154
155static int
156bt_mca_probe (device_t dev)
157{
158	const char *		desc;
159	mca_id_t		id = mca_get_id(dev);
160	struct bt_probe_info	info;
161	u_int32_t		iobase = 0;
162	u_int32_t		iosize = 0;
163	u_int8_t		drq = 0;
164	u_int8_t		irq = 0;
165	u_int8_t		pos;
166	int			result;
167
168	desc = mca_match_id(id, bt_mca_devs);
169	if (!desc)
170		return (ENXIO);
171	device_set_desc(dev, desc);
172
173	pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) |
174	      (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2);
175	iobase = BT_MCA_IOPORT(pos);
176	iosize = BT_MCA_IOPORT_SIZE;
177
178	pos = mca_pos_read(dev, BT_MCA_DRQ_POS);
179	drq = BT_MCA_DRQ(pos);
180
181	pos = mca_pos_read(dev, BT_MCA_IRQ_POS);
182	irq = BT_MCA_IRQ(pos);
183
184	bt_mark_probed_iop(iobase);
185
186	mca_add_iospace(dev, iobase, iosize);
187
188	/* And allocate them */
189	bt_mca_alloc_resources(dev, BT_MCA_PROBE);
190
191	if (bt_port_probe(dev, &info) != 0) {
192		printf("bt_mca_probe: Probe failed for "
193		       "card at slot %d\n", mca_get_slot(dev) + 1);
194		result = ENXIO;
195	} else {
196		mca_add_drq(dev, drq);
197		mca_add_irq(dev, irq);
198		result = 0;
199	}
200	bt_mca_release_resources(dev);
201
202	return (result);
203}
204
205static int
206bt_mca_attach (device_t dev)
207{
208	struct bt_softc *	bt = device_get_softc(dev);
209	int			error = 0;
210
211	/* Allocate resources */
212	if ((error = bt_mca_alloc_resources(dev, BT_MCA_ATTACH))) {
213		device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n");
214		return (error);
215	}
216
217	isa_dmacascade(rman_get_start(bt->drq));
218
219	/* Allocate a dmatag for our CCB DMA maps */
220	if (bus_dma_tag_create( /* parent	*/ NULL,
221				/* alignemnt	*/ 1,
222				/* boundary	*/ 0,
223				/* lowaddr	*/ BUS_SPACE_MAXADDR_24BIT,
224				/* highaddr	*/ BUS_SPACE_MAXADDR,
225				/* filter	*/ btvlbouncefilter,
226				/* filterarg	*/ bt,
227				/* maxsize	*/ BUS_SPACE_MAXSIZE_32BIT,
228				/* nsegments	*/ ~0,
229				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
230				/* flags	*/ 0,
231				&bt->parent_dmat) != 0) {
232		bt_mca_release_resources(dev);
233		return (ENOMEM);
234	}
235
236	if (bt_init(dev)) {
237		bt_mca_release_resources(dev);
238		return (ENOMEM);
239	}
240
241	/* DMA tag for our sense buffers */
242	if (bus_dma_tag_create(	/* parent	*/ bt->parent_dmat,
243				/* alignment	*/ 1,
244				/* boundary	*/ 0,
245				/* lowaddr	*/ BUS_SPACE_MAXADDR,
246				/* highaddr	*/ BUS_SPACE_MAXADDR,
247				/* filter	*/ NULL,
248				/* filterarg	*/ NULL,
249				/* maxsize	*/ bt->max_ccbs *
250						   sizeof(struct scsi_sense_data),
251				/* nsegments	*/ 1,
252				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
253				/* flags	*/ 0,
254				&bt->sense_dmat) != 0) {
255		bt_mca_release_resources(dev);
256		return (ENOMEM);
257	}
258
259	bt->init_level++;
260
261	/* Allocation of sense buffers */
262	if (bus_dmamem_alloc(bt->sense_dmat,
263			     (void **)&bt->sense_buffers,
264			     BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) {
265		bt_mca_release_resources(dev);
266		return (ENOMEM);
267	}
268
269	bt->init_level++;
270
271	/* And permanently map them */
272	bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap,
273			bt->sense_buffers,
274			bt->max_ccbs * sizeof(*bt->sense_buffers),
275			btmapsensebuffers, bt, /*flags*/0);
276
277	bt->init_level++;
278
279	if ((error = bt_attach(dev))) {
280		bt_mca_release_resources(dev);
281		return (error);
282	}
283
284	return (0);
285}
286
287/*
288 * This code should be shared with the ISA
289 * stubs as its exactly the same.
290 */
291
292#define BIOS_MAP_SIZE (16 * 1024)
293
294static int
295btvlbouncefilter(void *arg, bus_addr_t addr)
296{
297	struct bt_softc *bt;
298
299	bt = (struct bt_softc *)arg;
300
301	addr &= BUS_SPACE_MAXADDR_24BIT;
302
303	if (addr == 0
304	 || (addr >= bt->bios_addr
305	  && addr < (bt->bios_addr + BIOS_MAP_SIZE)))
306		return (1);
307	return (0);
308}
309
310static void
311btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error)
312{
313	struct bt_softc* bt;
314
315	bt = (struct bt_softc*)arg;
316	bt->sense_buffers_physbase = segs->ds_addr;
317}
318
319static device_method_t bt_mca_methods[] = {
320	/* Device interface */
321	DEVMETHOD(device_probe,		bt_mca_probe),
322	DEVMETHOD(device_attach,	bt_mca_attach),
323
324	{ 0, 0 }
325};
326
327static driver_t bt_mca_driver = {
328	"bt",
329	bt_mca_methods,
330	sizeof(struct bt_softc),
331};
332
333static devclass_t bt_devclass;
334
335DRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0);
336