1140039Simp/*
239225Sgibbs * Product specific probe and attach routines for:
339225Sgibbs *      Adaptec 154x.
4140039Simp */
5140039Simp/*-
6122362Simp * Copyright (c) 1999-2003 M. Warner Losh
7122362Simp * All rights reserved.
839225Sgibbs *
9122362Simp * Redistribution and use in source and binary forms, with or without
10122362Simp * modification, are permitted provided that the following conditions
11122362Simp * are met:
12122362Simp * 1. Redistributions of source code must retain the above copyright
13122362Simp *    notice, this list of conditions, and the following disclaimer,
14122362Simp *    without modification, immediately at the beginning of the file.
15122362Simp * 2. The name of the author may not be used to endorse or promote products
16122362Simp *    derived from this software without specific prior written permission.
17122362Simp *
18122362Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19122362Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20122362Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21122362Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22122362Simp * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23122362Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24122362Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25122362Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26122362Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27122362Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28122362Simp * SUCH DAMAGE.
29122362Simp *
30122362Simp * Derived from bt isa from end, written by:
31122362Simp *
3239225Sgibbs * Copyright (c) 1998 Justin T. Gibbs
3339225Sgibbs * All rights reserved.
3439225Sgibbs *
3539225Sgibbs * Redistribution and use in source and binary forms, with or without
3639225Sgibbs * modification, are permitted provided that the following conditions
3739225Sgibbs * are met:
3839225Sgibbs * 1. Redistributions of source code must retain the above copyright
3939225Sgibbs *    notice, this list of conditions, and the following disclaimer,
4039225Sgibbs *    without modification, immediately at the beginning of the file.
4139225Sgibbs * 2. The name of the author may not be used to endorse or promote products
4239225Sgibbs *    derived from this software without specific prior written permission.
4339225Sgibbs *
4439225Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4539225Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4639225Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4739225Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
4839225Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4939225Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5039225Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5139225Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5239225Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5339225Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5439225Sgibbs * SUCH DAMAGE.
5539225Sgibbs */
5639225Sgibbs
57119418Sobrien#include <sys/cdefs.h>
58119418Sobrien__FBSDID("$FreeBSD$");
59119418Sobrien
6039225Sgibbs#include <sys/param.h>
6139225Sgibbs#include <sys/systm.h>
6242887Simp#include <sys/kernel.h>
63117126Sscottl#include <sys/lock.h>
64117126Sscottl#include <sys/mutex.h>
6539225Sgibbs
6639225Sgibbs#include <machine/bus.h>
6751738Simp#include <machine/resource.h>
6851738Simp#include <sys/module.h>
6951738Simp#include <sys/bus.h>
7051738Simp#include <sys/rman.h>
7139225Sgibbs
7251738Simp#include <isa/isavar.h>
7351738Simp
7439225Sgibbs#include <dev/aha/ahareg.h>
7539225Sgibbs
7639225Sgibbs#include <cam/scsi/scsi_all.h>
7739225Sgibbs
7851738Simpstatic struct isa_pnp_id aha_ids[] = {
7958544Simp	{ADP0100_PNP,		"Adaptec 1540/1542 ISA SCSI"},	/* ADP0100 */
80122385Simp	{AHA1540_PNP,		"Adaptec 1540/aha-1640/aha-1535"},/* ADP1540 */
8158544Simp	{AHA1542_PNP,		"Adaptec 1542/aha-1535"},	/* ADP1542 */
8258544Simp	{AHA1542_PNPCOMPAT,	"Adaptec 1542 compatible"},	/* PNP00A0 */
8358544Simp	{ICU0091_PNP,		"Adaptec AHA-1540/1542 SCSI"},	/* ICU0091 */
8451738Simp	{0}
8539225Sgibbs};
8639225Sgibbs
8739225Sgibbs/*
88122385Simp * I/O ports listed in the order enumerated by the card for certain op codes.
89122385Simp */
90122385Simpstatic bus_addr_t aha_board_ports[] =
91122385Simp{
92122385Simp	0x330,
93122385Simp	0x334,
94122385Simp	0x230,
95122385Simp	0x234,
96122385Simp	0x130,
97122385Simp	0x134
98122385Simp};
99122385Simp
100122385Simp/*
10139225Sgibbs * Check if the device can be found at the port given
10239225Sgibbs */
10339225Sgibbsstatic int
10451738Simpaha_isa_probe(device_t dev)
10539225Sgibbs{
10639225Sgibbs	/*
10739225Sgibbs	 * find unit and check we have that many defined
10839225Sgibbs	 */
109122361Simp	struct	aha_softc *aha = device_get_softc(dev);
11051738Simp	int	error;
111122385Simp	u_long	port_start;
11251738Simp	int	port_rid;
11351738Simp	int	drq;
11451738Simp	int	irq;
115122385Simp	config_data_t config_data;
11639225Sgibbs
117122597Simp	aha->dev = dev;
11851738Simp	/* Check isapnp ids */
11951738Simp	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
12051738Simp		return (ENXIO);
12151738Simp
122122385Simp	port_rid = 0;
123241589Sjhb	aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
124241589Sjhb	    0ul, ~0ul, AHA_NREGS, RF_ACTIVE);
12551738Simp
126241589Sjhb	if (aha->port == NULL)
127122385Simp		return (ENXIO);
12839225Sgibbs
129241603Sglebius	port_start = rman_get_start(aha->port);
130241589Sjhb	aha_alloc(aha);
13141048Sgibbs
132122385Simp	/* See if there is really a card present */
133122385Simp	if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
134122385Simp		aha_free(aha);
135241589Sjhb		bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port);
136122385Simp		return (ENXIO);
137122385Simp	}
13839225Sgibbs
139122385Simp	/*
140122385Simp	 * Determine our IRQ, and DMA settings and
141122385Simp	 * export them to the configuration system.
142122385Simp	 */
143122385Simp	error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
144122385Simp	    (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT);
14539225Sgibbs
146122385Simp	if (error != 0) {
147122385Simp		device_printf(dev, "Could not determine IRQ or DMA "
148122385Simp		    "settings for adapter at %#jx.  Failing probe\n",
149122385Simp		    (uintmax_t)port_start);
150122385Simp		aha_free(aha);
151137599Simp		bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
152241589Sjhb		    aha->port);
153122385Simp		return (ENXIO);
154122385Simp	}
15540160Simp
156241589Sjhb	bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port);
157241589Sjhb	aha->port = NULL;
15839225Sgibbs
159122385Simp	switch (config_data.dma_chan) {
160122385Simp	case DMA_CHAN_5:
161122385Simp		drq = 5;
162122385Simp		break;
163122385Simp	case DMA_CHAN_6:
164122385Simp		drq = 6;
165122385Simp		break;
166122385Simp	case DMA_CHAN_7:
167122385Simp		drq = 7;
168122385Simp		break;
169122385Simp	default:
170122385Simp		device_printf(dev, "Invalid DMA setting for adapter at %#jx.",
171122385Simp		    (uintmax_t)port_start);
172122385Simp		return (ENXIO);
17339225Sgibbs	}
174122385Simp	error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
175122385Simp	if (error)
176122385Simp		return error;
17739225Sgibbs
178122385Simp	irq = ffs(config_data.irq) + 8;
179122385Simp	error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
180122385Simp	return (error);
18139225Sgibbs}
18239225Sgibbs
18339225Sgibbs/*
18439225Sgibbs * Attach all the sub-devices we can find
18539225Sgibbs */
18639225Sgibbsstatic int
18751738Simpaha_isa_attach(device_t dev)
18839225Sgibbs{
189122361Simp	struct	aha_softc *aha = device_get_softc(dev);
190140467Simp	int		 error = ENOMEM;
19139225Sgibbs
192122597Simp	aha->dev = dev;
19356504Simp	aha->portrid = 0;
19456504Simp	aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid,
195241589Sjhb	    0ul, ~0ul, AHA_NREGS, RF_ACTIVE);
19656504Simp	if (!aha->port) {
19751738Simp		device_printf(dev, "Unable to allocate I/O ports\n");
198140467Simp		goto fail;
19951738Simp	}
20051738Simp
20156504Simp	aha->irqrid = 0;
202127135Snjl	aha->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &aha->irqrid,
20351738Simp	    RF_ACTIVE);
20456504Simp	if (!aha->irq) {
20551738Simp		device_printf(dev, "Unable to allocate excluse use of irq\n");
206140467Simp		goto fail;
20751738Simp	}
20851738Simp
20956504Simp	aha->drqrid = 0;
210127135Snjl	aha->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &aha->drqrid,
21151738Simp	    RF_ACTIVE);
21256504Simp	if (!aha->drq) {
21351738Simp		device_printf(dev, "Unable to allocate drq\n");
214140467Simp		goto fail;
21551738Simp	}
21651738Simp
21751738Simp#if 0				/* is the drq ever unset? */
21839225Sgibbs	if (dev->id_drq != -1)
21939225Sgibbs		isa_dmacascade(dev->id_drq);
22051738Simp#endif
22156504Simp	isa_dmacascade(rman_get_start(aha->drq));
22239225Sgibbs
22339225Sgibbs	/* Allocate our parent dmatag */
224183678Simp	if (bus_dma_tag_create(	/* parent	*/ bus_get_dma_tag(dev),
225112782Smdodd				/* alignemnt	*/ 1,
226112782Smdodd				/* boundary	*/ 0,
227241589Sjhb				/* lowaddr	*/ BUS_SPACE_MAXADDR_24BIT,
228112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
229241589Sjhb				/* filter	*/ NULL,
230241589Sjhb				/* filterarg	*/ NULL,
231112782Smdodd				/* maxsize	*/ BUS_SPACE_MAXSIZE_24BIT,
232112782Smdodd				/* nsegments	*/ ~0,
233112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
234112782Smdodd				/* flags	*/ 0,
235241589Sjhb				/* lockfunc	*/ NULL,
236241589Sjhb				/* lockarg	*/ NULL,
237112782Smdodd				&aha->parent_dmat) != 0) {
238140467Simp		device_printf(dev, "dma tag create failed.\n");
239140467Simp		goto fail;
240140467Simp        }
24139225Sgibbs
242137599Simp	if (aha_init(aha)) {
24351738Simp		device_printf(dev, "init failed\n");
244140467Simp		goto fail;
245140467Simp        }
246140025Simp	/*
247140025Simp	 * The 1542A and B look the same.  So we guess based on
248140025Simp	 * the firmware revision.  It appears that only rev 0 is on
249140025Simp	 * the A cards.
250140025Simp	 */
251140025Simp	if (aha->boardid <= BOARD_1542 && aha->fw_major == 0) {
252140025Simp		device_printf(dev, "154xA may not work\n");
253140025Simp		aha->ccb_sg_opcode = INITIATOR_SG_CCB;
254140025Simp		aha->ccb_ccb_opcode = INITIATOR_CCB;
255137599Simp	}
256140025Simp
25751738Simp	error = aha_attach(aha);
25851738Simp	if (error) {
25951738Simp		device_printf(dev, "attach failed\n");
260140467Simp		goto fail;
26151738Simp	}
26239225Sgibbs
263241589Sjhb	error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM|INTR_ENTROPY|
264241589Sjhb	    INTR_MPSAFE, NULL, aha_intr, aha, &aha->ih);
26551738Simp	if (error) {
26651738Simp		device_printf(dev, "Unable to register interrupt handler\n");
267241589Sjhb		aha_detach(aha);
268140467Simp                goto fail;
26942887Simp	}
27042887Simp
27151738Simp	return (0);
272140467Simpfail: ;
273241589Sjhb	aha_free(aha);
274140467Simp	bus_free_resource(dev, SYS_RES_IOPORT, aha->port);
275140467Simp	bus_free_resource(dev, SYS_RES_IRQ, aha->irq);
276140467Simp	bus_free_resource(dev, SYS_RES_DRQ, aha->drq);
277140467Simp	return (error);
27842887Simp}
27942887Simp
28056504Simpstatic int
28156504Simpaha_isa_detach(device_t dev)
28256504Simp{
283122361Simp	struct aha_softc *aha = (struct aha_softc *)device_get_softc(dev);
28456504Simp	int error;
28556504Simp
28656504Simp	error = bus_teardown_intr(dev, aha->irq, aha->ih);
287140467Simp	if (error)
28856504Simp		device_printf(dev, "failed to unregister interrupt handler\n");
28956504Simp
29056504Simp	error = aha_detach(aha);
29156504Simp	if (error) {
29256504Simp		device_printf(dev, "detach failed\n");
29356504Simp		return (error);
29456504Simp	}
29556504Simp	aha_free(aha);
296241589Sjhb	bus_free_resource(dev, SYS_RES_IOPORT, aha->port);
297241589Sjhb	bus_free_resource(dev, SYS_RES_IRQ, aha->irq);
298241589Sjhb	bus_free_resource(dev, SYS_RES_DRQ, aha->drq);
29956504Simp
30056504Simp	return (0);
30156504Simp}
30256504Simp
30356504Simpstatic void
30456504Simpaha_isa_identify(driver_t *driver, device_t parent)
30556504Simp{
306122385Simp	int i;
307122385Simp	bus_addr_t ioport;
308122385Simp	struct aha_softc aha;
309122385Simp	int rid;
310122385Simp	device_t child;
311122385Simp
312122385Simp	/* Attempt to find an adapter */
313122385Simp	for (i = 0; i < sizeof(aha_board_ports) / sizeof(aha_board_ports[0]);
314122385Simp	    i++) {
315122385Simp		bzero(&aha, sizeof(aha));
316122385Simp		ioport = aha_board_ports[i];
317122385Simp		/*
318122385Simp		 * XXX Check to see if we have a hard-wired aha device at
319122385Simp		 * XXX this port, if so, skip.  This should also cover the
320122385Simp		 * XXX case where we are run multiple times due to, eg,
321122385Simp		 * XXX kldload/kldunload.
322122385Simp		 */
323122385Simp		rid = 0;
324241603Sglebius		aha.port = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid,
325122385Simp		    ioport, ioport, AHA_NREGS, RF_ACTIVE);
326241603Sglebius		if (aha.port == NULL)
327122385Simp			continue;
328241589Sjhb		aha_alloc(&aha);
329122385Simp		/* See if there is really a card present */
330122385Simp		if (aha_probe(&aha) || aha_fetch_adapter_info(&aha))
331122385Simp			goto not_this_one;
332122385Simp		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "aha", -1);
333122385Simp		bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, AHA_NREGS);
334122385Simp		/*
335122385Simp		 * Could query the board and set IRQ/DRQ, but probe does
336122385Simp		 * that.
337122385Simp		 */
338241603Sglebius	not_this_one:
339241603Sglebius		bus_release_resource(parent, SYS_RES_IOPORT, rid, aha.port);
340122385Simp		aha_free(&aha);
341122385Simp	}
34256504Simp}
34356504Simp
34451738Simpstatic device_method_t aha_isa_methods[] = {
34551738Simp	/* Device interface */
34651738Simp	DEVMETHOD(device_probe,		aha_isa_probe),
34751738Simp	DEVMETHOD(device_attach,	aha_isa_attach),
34856504Simp	DEVMETHOD(device_detach,	aha_isa_detach),
34956504Simp	DEVMETHOD(device_identify,	aha_isa_identify),
35042887Simp
35151738Simp	{ 0, 0 }
35251738Simp};
35342887Simp
35451738Simpstatic driver_t aha_isa_driver = {
35551738Simp	"aha",
35651738Simp	aha_isa_methods,
357122361Simp	sizeof(struct aha_softc),
35851738Simp};
35942887Simp
36051738Simpstatic devclass_t aha_devclass;
36142887Simp
36251738SimpDRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0);
363165102SmjacobMODULE_DEPEND(aha, isa, 1, 1, 1);
364