aha_isa.c revision 51713
1/*
2 * Product specific probe and attach routines for:
3 *      Adaptec 154x.
4 *
5 * Derived from code written by:
6 *
7 * Copyright (c) 1998 Justin T. Gibbs
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions, and the following disclaimer,
15 *    without modification, immediately at the beginning of the file.
16 * 2. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sys/dev/aha/aha_isa.c 50782 1999-09-02 04:37:07Z peter $
32 */
33
34/* #include "pnp.h" */
35#define NPNP 0
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40
41#include <machine/bus_pio.h>
42#include <machine/bus.h>
43
44#include <i386/isa/isa_device.h>
45#include <dev/aha/ahareg.h>
46
47#include <cam/scsi/scsi_all.h>
48
49#if NPNP > 0
50#include <i386/isa/pnp.h>
51#endif
52
53static	int aha_isa_probe(struct isa_device *dev);
54static	int aha_isa_attach(struct isa_device *dev);
55static	void aha_isa_intr(void *unit);
56
57struct isa_driver ahadriver =
58{
59    aha_isa_probe,
60    aha_isa_attach,
61    "aha"
62};
63
64/*
65 * Check if the device can be found at the port given
66 * and if so, set it up ready for further work
67 * as an argument, takes the isa_device structure from
68 * autoconf.c
69 */
70static int
71aha_isa_probe(dev)
72	struct isa_device *dev;
73{
74	/*
75	 * find unit and check we have that many defined
76	 */
77	struct	aha_softc *aha;
78	int	port_index;
79	int	max_port_index;
80
81	aha = NULL;
82
83	/*
84	 * Bound our board search if the user has
85	 * specified an exact port.
86	 */
87	aha_find_probe_range(dev->id_iobase, &port_index, &max_port_index);
88
89	if (port_index < 0)
90		return 0;
91
92	/* Attempt to find an adapter */
93	for (;port_index <= max_port_index; port_index++) {
94		config_data_t config_data;
95		u_int ioport;
96		int error;
97
98		ioport = aha_iop_from_bio(port_index);
99
100		/*
101		 * Ensure this port has not already been claimed already
102		 * by a PCI, EISA or ISA adapter.
103		 */
104		if (aha_check_probed_iop(ioport) != 0)
105			continue;
106		dev->id_iobase = ioport;
107		if (haveseen_iobase(dev, AHA_NREGS))
108			continue;
109
110		/* Allocate a softc for use during probing */
111		aha = aha_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport);
112
113		if (aha == NULL)
114			break;
115
116		/* We're going to attempt to probe it now, so mark it probed */
117		aha_mark_probed_bio(port_index);
118
119		/* See if there is really a card present */
120		if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
121			aha_free(aha);
122			continue;
123		}
124
125		/*
126		 * Determine our IRQ, and DMA settings and
127		 * export them to the configuration system.
128		 */
129		error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
130			       (u_int8_t*)&config_data, sizeof(config_data),
131			       DEFAULT_CMD_TIMEOUT);
132		if (error != 0) {
133			printf("aha_isa_probe: Could not determine IRQ or DMA "
134			       "settings for adapter at 0x%x.  Failing probe\n",
135			       ioport);
136			aha_free(aha);
137			continue;
138		}
139
140		switch (config_data.dma_chan) {
141		case DMA_CHAN_5:
142			dev->id_drq = 5;
143			break;
144		case DMA_CHAN_6:
145			dev->id_drq = 6;
146			break;
147		case DMA_CHAN_7:
148			dev->id_drq = 7;
149			break;
150		default:
151			printf("aha_isa_probe: Invalid DMA setting "
152				"detected for adapter at 0x%x.  "
153				"Failing probe\n", ioport);
154			return (0);
155		}
156		dev->id_irq = (config_data.irq << 9);
157		dev->id_intr = aha_isa_intr;
158		aha_unit++;
159		return (AHA_NREGS);
160	}
161
162	return (0);
163}
164
165/*
166 * Attach all the sub-devices we can find
167 */
168static int
169aha_isa_attach(dev)
170	struct isa_device *dev;
171{
172	struct	aha_softc *aha;
173	bus_dma_filter_t *filter;
174	void		 *filter_arg;
175	bus_addr_t	 lowaddr;
176
177	aha = aha_softcs[dev->id_unit];
178	if (dev->id_drq != -1)
179		isa_dmacascade(dev->id_drq);
180
181	/* Allocate our parent dmatag */
182	filter = NULL;
183	filter_arg = NULL;
184	lowaddr = BUS_SPACE_MAXADDR_24BIT;
185
186	if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
187                               lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
188                               filter, filter_arg,
189                               /*maxsize*/BUS_SPACE_MAXSIZE_24BIT,
190                               /*nsegments*/BUS_SPACE_UNRESTRICTED,
191                               /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
192                               /*flags*/0, &aha->parent_dmat) != 0) {
193                aha_free(aha);
194                return (-1);
195        }
196
197        if (aha_init(aha)) {
198		printf("aha init failed\n");
199                aha_free(aha);
200                return (-1);
201        }
202
203	return (aha_attach(aha));
204}
205
206/*
207 * Handle an ISA interrupt.
208 * XXX should go away as soon as ISA interrupt handlers
209 * take a (void *) arg.
210 */
211static void
212aha_isa_intr(void *unit)
213{
214	struct aha_softc* arg = aha_softcs[(int)unit];
215	aha_intr((void *)arg);
216}
217
218/*
219 * support PnP cards if we are using 'em
220 */
221
222#if NPNP > 0
223
224static char *ahapnp_probe(u_long csn, u_long vend_id);
225static void ahapnp_attach(u_long csn, u_long vend_id, char *name,
226	struct isa_device *dev);
227static u_long nahapnp = NAHA;
228
229static struct pnp_device ahapnp = {
230	"ahapnp",
231	ahapnp_probe,
232	ahapnp_attach,
233	&nahapnp,
234	&bio_imask
235};
236DATA_SET (pnpdevice_set, ahapnp);
237
238static char *
239ahapnp_probe(u_long csn, u_long vend_id)
240{
241	struct pnp_cinfo d;
242	char *s = NULL;
243
244	if (vend_id != AHA1542_PNP && vend_id != AHA1542_PNPCOMPAT)
245		return (NULL);
246
247	read_pnp_parms(&d, 0);
248	if (d.enable == 0 || d.flags & 1) {
249		printf("CSN %lu is disabled.\n", csn);
250		return (NULL);
251	}
252	s = "Adaptec 1542CP";
253
254	return (s);
255}
256
257static void
258ahapnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev)
259{
260	struct pnp_cinfo d;
261
262	if (dev->id_unit >= NAHATOT)
263		return;
264
265	if (read_pnp_parms(&d, 0) == 0) {
266		printf("failed to read pnp parms\n");
267		return;
268	}
269
270	write_pnp_parms(&d, 0);
271
272	enable_pnp_card();
273
274	dev->id_iobase = d.port[0];
275	dev->id_irq = (1 << d.irq[0]);
276	dev->id_intr = aha_intr;
277	dev->id_drq = d.drq[0];
278
279	if (dev->id_driver == NULL) {
280		dev->id_driver = &ahadriver;
281		dev->id_id = isa_compat_nextid();
282	}
283
284	if ((dev->id_alive = aha_isa_probe(dev)) != 0)
285		aha_isa_attach(dev);
286	else
287		printf("aha%d: probe failed\n", dev->id_unit);
288}
289#endif
290