adv_eisa.c revision 119418
1/*
2 * Device probe and attach routines for the following
3 * Advanced Systems Inc. SCSI controllers:
4 *
5 *   Single Channel Products:
6 *	ABP742 - Bus-Master EISA (240 CDB)
7 *
8 *   Dual Channel Products:
9 *	ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
10 *
11 * Copyright (c) 1997 Justin Gibbs.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions, and the following disclaimer,
19 *    without modification, immediately at the beginning of the file.
20 * 2. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/dev/advansys/adv_eisa.c 119418 2003-08-24 17:55:58Z obrien $");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/module.h>
43#include <sys/lock.h>
44#include <sys/mutex.h>
45#include <sys/bus.h>
46
47#include <machine/bus_pio.h>
48#include <machine/bus.h>
49#include <machine/resource.h>
50#include <sys/rman.h>
51
52#include <dev/eisa/eisaconf.h>
53
54#include <dev/advansys/advansys.h>
55
56#define EISA_DEVICE_ID_ADVANSYS_740	0x04507400
57#define EISA_DEVICE_ID_ADVANSYS_750	0x04507500
58
59#define ADV_EISA_SLOT_OFFSET		0xc00
60#define ADV_EISA_OFFSET_CHAN1		0x30
61#define ADV_EISA_OFFSET_CHAN2		0x50
62#define ADV_EISA_IOSIZE			0x100
63
64#define ADV_EISA_ROM_BIOS_ADDR_REG	0x86
65#define ADV_EISA_IRQ_BURST_LEN_REG	0x87
66#define 	ADV_EISA_IRQ_MASK	0x07
67#define 	ADV_EISA_IRQ_10		0x00
68#define 	ADV_EISA_IRQ_11		0x01
69#define 	ADV_EISA_IRQ_12		0x02
70#define 	ADV_EISA_IRQ_14		0x04
71#define 	ADV_EISA_IRQ_15		0x05
72
73#define	ADV_EISA_MAX_DMA_ADDR   (0x07FFFFFFL)
74#define	ADV_EISA_MAX_DMA_COUNT  (0x07FFFFFFL)
75
76/*
77 * The overrun buffer shared amongst all EISA adapters.
78 */
79static	u_int8_t*	overrun_buf;
80static	bus_dma_tag_t	overrun_dmat;
81static	bus_dmamap_t	overrun_dmamap;
82static	bus_addr_t	overrun_physbase;
83
84static const char*
85adv_eisa_match(eisa_id_t type)
86{
87	switch (type & ~0xF) {
88	case EISA_DEVICE_ID_ADVANSYS_740:
89		return ("AdvanSys ABP-740/742 SCSI adapter");
90		break;
91	case EISA_DEVICE_ID_ADVANSYS_750:
92		return ("AdvanSys ABP-750/752 SCSI adapter");
93		break;
94	default:
95		break;
96	}
97	return (NULL);
98}
99
100static int
101adv_eisa_probe(device_t dev)
102{
103	const char *desc;
104	u_int32_t iobase;
105	u_int8_t irq;
106
107	desc = adv_eisa_match(eisa_get_id(dev));
108	if (!desc)
109		return (ENXIO);
110	device_set_desc(dev, desc);
111
112	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET;
113
114	eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE);
115	irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG);
116	irq &= ADV_EISA_IRQ_MASK;
117	switch (irq) {
118	case 0:
119	case 1:
120	case 2:
121	case 4:
122	case 5:
123	    break;
124	default:
125	    printf("adv at slot %d: illegal "
126		   "irq setting %d\n", eisa_get_slot(dev),
127		   irq);
128	    return ENXIO;
129	}
130	eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL);
131
132	return 0;
133}
134
135static int
136adv_eisa_attach(device_t dev)
137{
138	struct adv_softc *adv;
139	struct adv_softc *adv_b;
140	struct resource *io;
141	struct resource *irq;
142	int rid, error;
143	void *ih;
144
145	adv_b = NULL;
146
147	rid = 0;
148	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
149				0, ~0, 1, RF_ACTIVE);
150	if (!io) {
151		device_printf(dev, "No I/O space?!\n");
152		return ENOMEM;
153	}
154
155	rid = 0;
156	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
157				 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
158	if (!irq) {
159		device_printf(dev, "No irq?!\n");
160		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
161		return ENOMEM;
162
163	}
164
165	switch (eisa_get_id(dev) & ~0xF) {
166	case EISA_DEVICE_ID_ADVANSYS_750:
167		adv_b = adv_alloc(dev, rman_get_bustag(io),
168				  rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN2);
169		if (adv_b == NULL)
170			goto bad;
171
172		/*
173		 * Allocate a parent dmatag for all tags created
174		 * by the MI portions of the advansys driver
175		 */
176		/* XXX Should be a child of the PCI bus dma tag */
177		error = bus_dma_tag_create(
178				/* parent	*/ NULL,
179				/* alignment	*/ 1,
180				/* boundary	*/ 0,
181				/* lowaddr	*/ ADV_EISA_MAX_DMA_ADDR,
182				/* highaddr	*/ BUS_SPACE_MAXADDR,
183				/* filter	*/ NULL,
184				/* filterarg	*/ NULL,
185				/* maxsize	*/ BUS_SPACE_MAXSIZE_32BIT,
186				/* nsegments	*/ ~0,
187				/* maxsegsz	*/ ADV_EISA_MAX_DMA_COUNT,
188				/* flags	*/ 0,
189				/* lockfunc	*/ busdma_lock_mutex,
190				/* lockarg	*/ &Giant,
191				&adv_b->parent_dmat);
192
193		if (error != 0) {
194			printf("%s: Could not allocate DMA tag - error %d\n",
195			       adv_name(adv_b), error);
196			adv_free(adv_b);
197			goto bad;
198		}
199
200		adv_b->init_level++;
201
202		/* FALLTHROUGH */
203	case EISA_DEVICE_ID_ADVANSYS_740:
204		adv = adv_alloc(dev, rman_get_bustag(io),
205				rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN1);
206		if (adv == NULL) {
207			if (adv_b != NULL)
208				adv_free(adv_b);
209			goto bad;
210		}
211
212		/*
213		 * Allocate a parent dmatag for all tags created
214		 * by the MI portions of the advansys driver
215		 */
216		/* XXX Should be a child of the PCI bus dma tag */
217		error = bus_dma_tag_create(
218				/* parent	*/ NULL,
219				/* alignment	*/ 1,
220				/* boundary	*/ 0,
221				/* lowaddr	*/ ADV_EISA_MAX_DMA_ADDR,
222				/* highaddr	*/ BUS_SPACE_MAXADDR,
223				/* filter	*/ NULL,
224				/* filterarg	*/ NULL,
225				/* maxsize	*/ BUS_SPACE_MAXSIZE_32BIT,
226				/* nsegments	*/ ~0,
227				/* maxsegsz	*/ ADV_EISA_MAX_DMA_COUNT,
228				/* flags	*/ 0,
229				/* lockfunc	*/ busdma_lock_mutex,
230				/* lockarg	*/ &Giant,
231				&adv->parent_dmat);
232
233		if (error != 0) {
234			printf("%s: Could not allocate DMA tag - error %d\n",
235			       adv_name(adv), error);
236			adv_free(adv);
237			goto bad;
238		}
239
240		adv->init_level++;
241		break;
242	default:
243		printf("adveisaattach: Unknown device type!\n");
244		goto bad;
245		break;
246	}
247
248	if (overrun_buf == NULL) {
249		/* Need to allocate our overrun buffer */
250		if (bus_dma_tag_create(
251				/* parent	*/ adv->parent_dmat,
252				/* alignment	*/ 8,
253				/* boundary	*/ 0,
254				/* lowaddr	*/ ADV_EISA_MAX_DMA_ADDR,
255				/* highaddr	*/ BUS_SPACE_MAXADDR,
256				/* filter	*/ NULL,
257				/* filterarg	*/ NULL,
258				/* maxsize	*/ ADV_OVERRUN_BSIZE,
259				/* nsegments	*/ 1,
260				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
261				/* flags	*/ 0,
262				/* lockfunc	*/ busdma_lock_mutex,
263				/* lockarg	*/ &Giant,
264				&overrun_dmat) != 0) {
265			adv_free(adv);
266			goto bad;
267       		}
268		if (bus_dmamem_alloc(overrun_dmat,
269				     (void **)&overrun_buf,
270				     BUS_DMA_NOWAIT,
271				     &overrun_dmamap) != 0) {
272			bus_dma_tag_destroy(overrun_dmat);
273			adv_free(adv);
274			goto bad;
275		}
276		/* And permanently map it in */
277		bus_dmamap_load(overrun_dmat, overrun_dmamap,
278				overrun_buf, ADV_OVERRUN_BSIZE,
279				adv_map, &overrun_physbase,
280				/*flags*/0);
281	}
282
283	/*
284	 * Now that we know we own the resources we need, do the
285	 * card initialization.
286	 */
287
288	/*
289	 * Stop the chip.
290	 */
291	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
292	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
293
294	adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
295			  + ADV_CHIP_MIN_VER_EISA - 1;
296
297	if (adv_init(adv) != 0) {
298		adv_free(adv);
299		if (adv_b != NULL)
300			adv_free(adv_b);
301		return(-1);
302	}
303
304	adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
305	adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
306
307	if (adv_b != NULL) {
308		/*
309		 * Stop the chip.
310		 */
311		ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT);
312		ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0);
313
314		adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
315				    + ADV_CHIP_MIN_VER_EISA - 1;
316
317		if (adv_init(adv_b) != 0) {
318			adv_free(adv_b);
319		} else {
320			adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
321			adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
322		}
323	}
324
325	/*
326	 * Enable our interrupt handler.
327	 */
328	bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih);
329
330	/* Attach sub-devices - always succeeds */
331	adv_attach(adv);
332	if (adv_b != NULL)
333		adv_attach(adv_b);
334
335	return 0;
336
337 bad:
338	bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
339	bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
340	return -1;
341}
342
343static device_method_t adv_eisa_methods[] = {
344	/* Device interface */
345	DEVMETHOD(device_probe,		adv_eisa_probe),
346	DEVMETHOD(device_attach,	adv_eisa_attach),
347	{ 0, 0 }
348};
349
350static driver_t adv_eisa_driver = {
351	"adv", adv_eisa_methods, sizeof(struct adv_softc)
352};
353
354static devclass_t adv_eisa_devclass;
355DRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_eisa_devclass, 0, 0);
356