adv_eisa.c revision 49360
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 *	$Id: adv_eisa.c,v 1.4 1999/05/08 21:59:16 dfr Exp $
36 */
37
38#include "eisa.h"
39#if NEISA > 0
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
44#include <sys/module.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 <i386/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 *adveisamatch(eisa_id_t type);
85
86static const char*
87adveisamatch(eisa_id_t type)
88{
89	switch (type & ~0xF) {
90	case EISA_DEVICE_ID_ADVANSYS_740:
91		return ("AdvanSys ABP-740/742 SCSI adapter");
92		break;
93	case EISA_DEVICE_ID_ADVANSYS_750:
94		return ("AdvanSys ABP-750/752 SCSI adapter");
95		break;
96	default:
97		break;
98	}
99	return (NULL);
100}
101
102static int
103adveisaprobe(device_t dev)
104{
105	const char *desc;
106	u_int32_t iobase;
107	u_int8_t irq;
108
109	desc = adveisamatch(eisa_get_id(dev));
110	if (!desc)
111		return (ENXIO);
112	device_set_desc(dev, desc);
113
114	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE)
115	    + ADV_EISA_SLOT_OFFSET;
116
117	eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE);
118	irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG);
119	irq &= ADV_EISA_IRQ_MASK;
120	switch (irq) {
121	case 0:
122	case 1:
123	case 2:
124	case 4:
125	case 5:
126	    break;
127	default:
128	    printf("adv at slot %d: illegal "
129		   "irq setting %d\n", eisa_get_slot(dev),
130		   irq);
131	    return ENXIO;
132	}
133	eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL);
134
135	return 0;
136}
137
138static int
139adveisaattach(device_t dev)
140{
141	struct adv_softc *adv;
142	struct adv_softc *adv_b;
143	struct resource *io;
144	struct resource *irq;
145	int unit = device_get_unit(dev);
146	int rid, error;
147	void *ih;
148
149	adv_b = NULL;
150
151	rid = 0;
152	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
153				0, ~0, 1, RF_ACTIVE);
154	if (!io) {
155		device_printf(dev, "No I/O space?!\n");
156		return ENOMEM;
157	}
158
159	rid = 0;
160	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
161				 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
162	if (!irq) {
163		device_printf(dev, "No irq?!\n");
164		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
165		return ENOMEM;
166
167	}
168
169	switch (eisa_get_id(dev) & ~0xF) {
170	case EISA_DEVICE_ID_ADVANSYS_750:
171		adv_b = adv_alloc(unit, rman_get_bustag(io),
172				  rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN2);
173		if (adv_b == NULL)
174			goto bad;
175
176		/*
177		 * Allocate a parent dmatag for all tags created
178		 * by the MI portions of the advansys driver
179		 */
180		/* XXX Should be a child of the PCI bus dma tag */
181		error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0,
182					   /*boundary*/0,
183					   /*lowaddr*/ADV_EISA_MAX_DMA_ADDR,
184					   /*highaddr*/BUS_SPACE_MAXADDR,
185					   /*filter*/NULL, /*filterarg*/NULL,
186					   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
187					   /*nsegments*/BUS_SPACE_UNRESTRICTED,
188					   /*maxsegsz*/ADV_EISA_MAX_DMA_COUNT,
189					   /*flags*/0,
190					   &adv_b->parent_dmat);
191
192		if (error != 0) {
193			printf("%s: Could not allocate DMA tag - error %d\n",
194			       adv_name(adv_b), error);
195			adv_free(adv_b);
196			goto bad;
197		}
198
199		adv_b->init_level++;
200
201		/* FALLTHROUGH */
202	case EISA_DEVICE_ID_ADVANSYS_740:
203		adv = adv_alloc(unit, rman_get_bustag(io),
204				rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN1);
205		if (adv == NULL) {
206			if (adv_b != NULL)
207				adv_free(adv_b);
208			goto bad;
209		}
210
211		/*
212		 * Allocate a parent dmatag for all tags created
213		 * by the MI portions of the advansys driver
214		 */
215		/* XXX Should be a child of the PCI bus dma tag */
216		error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0,
217					   /*boundary*/0,
218					   /*lowaddr*/ADV_EISA_MAX_DMA_ADDR,
219					   /*highaddr*/BUS_SPACE_MAXADDR,
220					   /*filter*/NULL, /*filterarg*/NULL,
221					   /*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
222					   /*nsegments*/BUS_SPACE_UNRESTRICTED,
223					   /*maxsegsz*/ADV_EISA_MAX_DMA_COUNT,
224					   /*flags*/0,
225					   &adv->parent_dmat);
226
227		if (error != 0) {
228			printf("%s: Could not allocate DMA tag - error %d\n",
229			       adv_name(adv), error);
230			adv_free(adv);
231			goto bad;
232		}
233
234		adv->init_level++;
235		break;
236	default:
237		printf("adveisaattach: Unknown device type!\n");
238		goto bad;
239		break;
240	}
241
242	if (overrun_buf == NULL) {
243		/* Need to allocate our overrun buffer */
244		if (bus_dma_tag_create(adv->parent_dmat,
245				       /*alignment*/8,
246				       /*boundary*/0,
247				       ADV_EISA_MAX_DMA_ADDR,
248				       BUS_SPACE_MAXADDR,
249				       /*filter*/NULL,
250				       /*filterarg*/NULL,
251				       ADV_OVERRUN_BSIZE,
252				       /*nsegments*/1,
253				       BUS_SPACE_MAXSIZE_32BIT,
254				       /*flags*/0,
255				       &overrun_dmat) != 0) {
256			adv_free(adv);
257			goto bad;
258       		}
259		if (bus_dmamem_alloc(overrun_dmat,
260				     (void **)&overrun_buf,
261				     BUS_DMA_NOWAIT,
262				     &overrun_dmamap) != 0) {
263			bus_dma_tag_destroy(overrun_dmat);
264			adv_free(adv);
265			goto bad;
266		}
267		/* And permanently map it in */
268		bus_dmamap_load(overrun_dmat, overrun_dmamap,
269				overrun_buf, ADV_OVERRUN_BSIZE,
270				adv_map, &overrun_physbase,
271				/*flags*/0);
272	}
273
274	/*
275	 * Now that we know we own the resources we need, do the
276	 * card initialization.
277	 */
278
279	/*
280	 * Stop the chip.
281	 */
282	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
283	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
284
285	adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
286			  + ADV_CHIP_MIN_VER_EISA - 1;
287
288	if (adv_init(adv) != 0) {
289		adv_free(adv);
290		if (adv_b != NULL)
291			adv_free(adv_b);
292		return(-1);
293	}
294
295	adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
296	adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
297
298	if (adv_b != NULL) {
299		/*
300		 * Stop the chip.
301		 */
302		ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT);
303		ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0);
304
305		adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev))
306				    + ADV_CHIP_MIN_VER_EISA - 1;
307
308		if (adv_init(adv_b) != 0) {
309			adv_free(adv_b);
310		} else {
311			adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT;
312			adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR;
313		}
314	}
315
316	/*
317	 * Enable our interrupt handler.
318	 */
319	bus_setup_intr(dev, irq, INTR_TYPE_CAM, adv_intr, adv, &ih);
320
321	/* Attach sub-devices - always succeeds */
322	adv_attach(adv);
323	if (adv_b != NULL)
324		adv_attach(adv_b);
325
326	return 0;
327
328 bad:
329	bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
330	bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
331	return -1;
332}
333
334static device_method_t adv_eisa_methods[] = {
335	/* Device interface */
336	DEVMETHOD(device_probe,		adveisaprobe),
337	DEVMETHOD(device_attach,	adveisaattach),
338
339	{ 0, 0 }
340};
341
342static driver_t adv_eisa_driver = {
343	"adv",
344	adv_eisa_methods,
345	1,			/* unused */
346};
347
348static devclass_t adv_devclass;
349
350DRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_devclass, 0, 0);
351
352#endif /* NEISA > 0 */
353