xref: /freebsd-12.1/sys/dev/aha/aha_isa.c (revision 5fe4723c)
1 /*
2  * Product specific probe and attach routines for:
3  *      Adaptec 154x.
4  */
5 /*-
6  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7  *
8  * Copyright (c) 1999-2003 M. Warner Losh
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification, immediately at the beginning of the file.
17  * 2. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * Derived from bt isa from end, written by:
33  *
34  * Copyright (c) 1998 Justin T. Gibbs
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions, and the following disclaimer,
42  *    without modification, immediately at the beginning of the file.
43  * 2. The name of the author may not be used to endorse or promote products
44  *    derived from this software without specific prior written permission.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
50  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  */
58 
59 #include <sys/cdefs.h>
60 __FBSDID("$FreeBSD$");
61 
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/lock.h>
66 #include <sys/mutex.h>
67 
68 #include <machine/bus.h>
69 #include <machine/resource.h>
70 #include <sys/module.h>
71 #include <sys/bus.h>
72 #include <sys/rman.h>
73 
74 #include <isa/isavar.h>
75 
76 #include <dev/aha/ahareg.h>
77 
78 #include <cam/scsi/scsi_all.h>
79 
80 static struct isa_pnp_id aha_ids[] = {
81 	{ADP0100_PNP,		"Adaptec 1540/1542 ISA SCSI"},	/* ADP0100 */
82 	{AHA1540_PNP,		"Adaptec 1540/aha-1640/aha-1535"},/* ADP1540 */
83 	{AHA1542_PNP,		"Adaptec 1542/aha-1535"},	/* ADP1542 */
84 	{AHA1542_PNPCOMPAT,	"Adaptec 1542 compatible"},	/* PNP00A0 */
85 	{ICU0091_PNP,		"Adaptec AHA-1540/1542 SCSI"},	/* ICU0091 */
86 	{0}
87 };
88 
89 /*
90  * I/O ports listed in the order enumerated by the card for certain op codes.
91  */
92 static bus_addr_t aha_board_ports[] =
93 {
94 	0x330,
95 	0x334,
96 	0x230,
97 	0x234,
98 	0x130,
99 	0x134
100 };
101 
102 /*
103  * Check if the device can be found at the port given
104  */
105 static int
aha_isa_probe(device_t dev)106 aha_isa_probe(device_t dev)
107 {
108 	/*
109 	 * find unit and check we have that many defined
110 	 */
111 	struct	aha_softc *aha = device_get_softc(dev);
112 	int	error;
113 	u_long	port_start;
114 	int	port_rid;
115 	int	drq;
116 	int	irq;
117 	config_data_t config_data;
118 
119 	aha->dev = dev;
120 	/* Check isapnp ids */
121 	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
122 		return (ENXIO);
123 
124 	port_rid = 0;
125 	aha->port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &port_rid,
126 	    AHA_NREGS, RF_ACTIVE);
127 
128 	if (aha->port == NULL)
129 		return (ENXIO);
130 
131 	port_start = rman_get_start(aha->port);
132 	aha_alloc(aha);
133 
134 	/* See if there is really a card present */
135 	if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
136 		aha_free(aha);
137 		bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port);
138 		return (ENXIO);
139 	}
140 
141 	/*
142 	 * Determine our IRQ, and DMA settings and
143 	 * export them to the configuration system.
144 	 */
145 	error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
146 	    (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT);
147 
148 	if (error != 0) {
149 		device_printf(dev, "Could not determine IRQ or DMA "
150 		    "settings for adapter at %#jx.  Failing probe\n",
151 		    (uintmax_t)port_start);
152 		aha_free(aha);
153 		bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
154 		    aha->port);
155 		return (ENXIO);
156 	}
157 
158 	bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port);
159 	aha->port = NULL;
160 
161 	switch (config_data.dma_chan) {
162 	case DMA_CHAN_5:
163 		drq = 5;
164 		break;
165 	case DMA_CHAN_6:
166 		drq = 6;
167 		break;
168 	case DMA_CHAN_7:
169 		drq = 7;
170 		break;
171 	default:
172 		device_printf(dev, "Invalid DMA setting for adapter at %#jx.",
173 		    (uintmax_t)port_start);
174 		return (ENXIO);
175 	}
176 	error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
177 	if (error)
178 		return error;
179 
180 	irq = ffs(config_data.irq) + 8;
181 	error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
182 	return (error);
183 }
184 
185 /*
186  * Attach all the sub-devices we can find
187  */
188 static int
aha_isa_attach(device_t dev)189 aha_isa_attach(device_t dev)
190 {
191 	struct	aha_softc *aha = device_get_softc(dev);
192 	int		 error = ENOMEM;
193 
194 	aha->dev = dev;
195 	aha->portrid = 0;
196 	aha->port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT,
197 	    &aha->portrid, AHA_NREGS, RF_ACTIVE);
198 	if (!aha->port) {
199 		device_printf(dev, "Unable to allocate I/O ports\n");
200 		goto fail;
201 	}
202 
203 	aha->irqrid = 0;
204 	aha->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &aha->irqrid,
205 	    RF_ACTIVE);
206 	if (!aha->irq) {
207 		device_printf(dev, "Unable to allocate excluse use of irq\n");
208 		goto fail;
209 	}
210 
211 	aha->drqrid = 0;
212 	aha->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &aha->drqrid,
213 	    RF_ACTIVE);
214 	if (!aha->drq) {
215 		device_printf(dev, "Unable to allocate drq\n");
216 		goto fail;
217 	}
218 
219 #if 0				/* is the drq ever unset? */
220 	if (dev->id_drq != -1)
221 		isa_dmacascade(dev->id_drq);
222 #endif
223 	isa_dmacascade(rman_get_start(aha->drq));
224 
225 	/* Allocate our parent dmatag */
226 	if (bus_dma_tag_create(	/* parent	*/ bus_get_dma_tag(dev),
227 				/* alignemnt	*/ 1,
228 				/* boundary	*/ 0,
229 				/* lowaddr	*/ BUS_SPACE_MAXADDR_24BIT,
230 				/* highaddr	*/ BUS_SPACE_MAXADDR,
231 				/* filter	*/ NULL,
232 				/* filterarg	*/ NULL,
233 				/* maxsize	*/ BUS_SPACE_MAXSIZE_24BIT,
234 				/* nsegments	*/ ~0,
235 				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
236 				/* flags	*/ 0,
237 				/* lockfunc	*/ NULL,
238 				/* lockarg	*/ NULL,
239 				&aha->parent_dmat) != 0) {
240 		device_printf(dev, "dma tag create failed.\n");
241 		goto fail;
242         }
243 
244 	if (aha_init(aha)) {
245 		device_printf(dev, "init failed\n");
246 		goto fail;
247         }
248 	/*
249 	 * The 1542A and B look the same.  So we guess based on
250 	 * the firmware revision.  It appears that only rev 0 is on
251 	 * the A cards.
252 	 */
253 	if (aha->boardid <= BOARD_1542 && aha->fw_major == 0) {
254 		device_printf(dev, "154xA may not work\n");
255 		aha->ccb_sg_opcode = INITIATOR_SG_CCB;
256 		aha->ccb_ccb_opcode = INITIATOR_CCB;
257 	}
258 
259 	error = aha_attach(aha);
260 	if (error) {
261 		device_printf(dev, "attach failed\n");
262 		goto fail;
263 	}
264 
265 	error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM|INTR_ENTROPY|
266 	    INTR_MPSAFE, NULL, aha_intr, aha, &aha->ih);
267 	if (error) {
268 		device_printf(dev, "Unable to register interrupt handler\n");
269 		aha_detach(aha);
270                 goto fail;
271 	}
272 
273 	return (0);
274 fail: ;
275 	aha_free(aha);
276 	bus_free_resource(dev, SYS_RES_IOPORT, aha->port);
277 	bus_free_resource(dev, SYS_RES_IRQ, aha->irq);
278 	bus_free_resource(dev, SYS_RES_DRQ, aha->drq);
279 	return (error);
280 }
281 
282 static int
aha_isa_detach(device_t dev)283 aha_isa_detach(device_t dev)
284 {
285 	struct aha_softc *aha = (struct aha_softc *)device_get_softc(dev);
286 	int error;
287 
288 	error = bus_teardown_intr(dev, aha->irq, aha->ih);
289 	if (error)
290 		device_printf(dev, "failed to unregister interrupt handler\n");
291 
292 	error = aha_detach(aha);
293 	if (error) {
294 		device_printf(dev, "detach failed\n");
295 		return (error);
296 	}
297 	aha_free(aha);
298 	bus_free_resource(dev, SYS_RES_IOPORT, aha->port);
299 	bus_free_resource(dev, SYS_RES_IRQ, aha->irq);
300 	bus_free_resource(dev, SYS_RES_DRQ, aha->drq);
301 
302 	return (0);
303 }
304 
305 static void
aha_isa_identify(driver_t * driver,device_t parent)306 aha_isa_identify(driver_t *driver, device_t parent)
307 {
308 	int i;
309 	bus_addr_t ioport;
310 	struct aha_softc aha;
311 	int rid;
312 	device_t child;
313 
314 	/* Attempt to find an adapter */
315 	for (i = 0; i < nitems(aha_board_ports); i++) {
316 		bzero(&aha, sizeof(aha));
317 		ioport = aha_board_ports[i];
318 		/*
319 		 * XXX Check to see if we have a hard-wired aha device at
320 		 * XXX this port, if so, skip.  This should also cover the
321 		 * XXX case where we are run multiple times due to, eg,
322 		 * XXX kldload/kldunload.
323 		 */
324 		rid = 0;
325 		aha.port = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid,
326 		    ioport, ioport, AHA_NREGS, RF_ACTIVE);
327 		if (aha.port == NULL)
328 			continue;
329 		aha_alloc(&aha);
330 		/* See if there is really a card present */
331 		if (aha_probe(&aha) || aha_fetch_adapter_info(&aha))
332 			goto not_this_one;
333 		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "aha", -1);
334 		bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, AHA_NREGS);
335 		/*
336 		 * Could query the board and set IRQ/DRQ, but probe does
337 		 * that.
338 		 */
339 	not_this_one:
340 		bus_release_resource(parent, SYS_RES_IOPORT, rid, aha.port);
341 		aha_free(&aha);
342 	}
343 }
344 
345 static device_method_t aha_isa_methods[] = {
346 	/* Device interface */
347 	DEVMETHOD(device_probe,		aha_isa_probe),
348 	DEVMETHOD(device_attach,	aha_isa_attach),
349 	DEVMETHOD(device_detach,	aha_isa_detach),
350 	DEVMETHOD(device_identify,	aha_isa_identify),
351 
352 	{ 0, 0 }
353 };
354 
355 static driver_t aha_isa_driver = {
356 	"aha",
357 	aha_isa_methods,
358 	sizeof(struct aha_softc),
359 };
360 
361 static devclass_t aha_devclass;
362 
363 DRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0);
364 MODULE_DEPEND(aha, isa, 1, 1, 1);
365 ISA_PNP_INFO(aha_ids);
366