aha_isa.c revision 39225
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 *	$Id$
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36
37#include <machine/bus_pio.h>
38#include <machine/bus.h>
39
40#include <i386/isa/isa_device.h>
41#include <dev/aha/ahareg.h>
42
43#include <cam/scsi/scsi_all.h>
44
45#include "ioconf.h"
46
47static	int aha_isa_probe __P((struct isa_device *dev));
48static	int aha_isa_attach __P((struct isa_device *dev));
49static	void aha_isa_intr __P((void *unit));
50
51struct isa_driver ahadriver =
52{
53    aha_isa_probe,
54    aha_isa_attach,
55    "aha"
56};
57
58/*
59 * Check if the device can be found at the port given
60 * and if so, set it up ready for further work
61 * as an argument, takes the isa_device structure from
62 * autoconf.c
63 */
64static int
65aha_isa_probe(dev)
66	struct isa_device *dev;
67{
68	/*
69	 * find unit and check we have that many defined
70	 */
71	struct	aha_softc *aha;
72	int	port_index;
73        int	max_port_index;
74
75	/*
76	 * We ignore the unit number assigned by config to allow
77	 * consistant numbering between PCI/EISA/ISA devices.
78	 * This is a total kludge until we have a configuration
79	 * manager.
80	 */
81	dev->id_unit = aha_unit;
82
83	aha = NULL;
84	port_index = 0;
85	max_port_index = AHA_NUM_ISAPORTS - 1;
86	/*
87	 * Bound our board search if the user has
88	 * specified an exact port.
89	 */
90	if (dev->id_iobase > 0) {
91		for (;port_index <= max_port_index; port_index++)
92			if (dev->id_iobase >= aha_isa_ports[port_index].addr)
93				break;
94		if ((port_index > max_port_index)
95		 || (dev->id_iobase != aha_isa_ports[port_index].addr)) {
96			printf("
97aha_isa_probe: Invalid baseport of 0x%x specified.
98aha_isa_probe: Nearest valid baseport is 0x%x.
99aha_isa_probe: Failing probe.\n",
100			       dev->id_iobase,
101			       (port_index <= max_port_index)
102				    ? aha_isa_ports[port_index].addr
103				    : aha_isa_ports[max_port_index].addr);
104			return 0;
105		}
106	}
107
108	/* Attempt to find an adapter */
109	for (;port_index <= max_port_index; port_index++) {
110		config_data_t config_data;
111		u_int ioport;
112		int error;
113
114		ioport = aha_isa_ports[port_index].addr;
115
116		/*
117		 * Ensure this port has not already been claimed already
118		 * by a PCI or EISA adapter.
119		 */
120		if (aha_check_probed_iop(ioport) != 0)
121			continue;
122
123		/* Allocate a softc for use during probing */
124		aha = aha_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport);
125
126		if (aha == NULL)
127			break;
128
129		/* We're going to attempt to probe it now, so mark it probed */
130		aha_mark_probed_bio(port_index);
131
132		/* See if there is really a card present */
133		if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
134			aha_free(aha);
135			continue;
136		}
137
138		/*
139		 * Determine our IRQ, and DMA settings and
140		 * export them to the configuration system.
141		 */
142		error = aha_cmd(aha, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
143			       (u_int8_t*)&config_data, sizeof(config_data),
144			       DEFAULT_CMD_TIMEOUT);
145		if (error != 0) {
146			printf("aha_isa_probe: Could not determine IRQ or DMA "
147			       "settings for adapter at 0x%x.  Failing probe\n",
148			       ioport);
149			aha_free(aha);
150			continue;
151		}
152
153		switch (config_data.dma_chan) {
154		case DMA_CHAN_5:
155			dev->id_drq = 5;
156			break;
157		case DMA_CHAN_6:
158			dev->id_drq = 6;
159			break;
160		case DMA_CHAN_7:
161			dev->id_drq = 7;
162			break;
163		default:
164			printf("aha_isa_probe: Invalid DMA setting "
165				"detected for adapter at 0x%x.  "
166				"Failing probe\n", ioport);
167		}
168		dev->id_iobase = aha_isa_ports[port_index].addr;
169		dev->id_irq = (config_data.irq << 9);
170		dev->id_intr = aha_isa_intr;
171		aha_unit++;
172		return (AHA_NREGS);
173	}
174
175	return (0);
176}
177
178/*
179 * Attach all the sub-devices we can find
180 */
181static int
182aha_isa_attach(dev)
183	struct isa_device *dev;
184{
185	struct	aha_softc *aha;
186	bus_dma_filter_t *filter;
187	void		 *filter_arg;
188	bus_addr_t	 lowaddr;
189
190	aha = aha_softcs[dev->id_unit];
191	if (dev->id_drq != -1)
192		isa_dmacascade(dev->id_drq);
193
194	/* Allocate our parent dmatag */
195	filter = NULL;
196	filter_arg = NULL;
197	lowaddr = BUS_SPACE_MAXADDR_24BIT;
198
199	if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0,
200                               lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
201                               filter, filter_arg,
202                               /*maxsize*/BUS_SPACE_MAXSIZE_24BIT,
203                               /*nsegments*/BUS_SPACE_UNRESTRICTED,
204                               /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
205                               /*flags*/0, &aha->parent_dmat) != 0) {
206                aha_free(aha);
207                return (-1);
208        }
209
210        if (aha_init(aha)) {
211		printf("aha init failed\n");
212                aha_free(aha);
213                return (-1);
214        }
215
216	return (aha_attach(aha));
217}
218
219/*
220 * Handle an ISA interrupt.
221 * XXX should go away as soon as ISA interrupt handlers
222 * take a (void *) arg.
223 */
224static void
225aha_isa_intr(void *unit)
226{
227	struct aha_softc* arg = aha_softcs[(int)unit];
228	aha_intr((void *)arg);
229}
230