aha_isa.c revision 157085
180709Sjake/*
280709Sjake * Product specific probe and attach routines for:
380709Sjake *      Adaptec 154x.
480709Sjake */
580709Sjake/*-
680709Sjake * Copyright (c) 1999-2003 M. Warner Losh
780709Sjake * All rights reserved.
880709Sjake *
980709Sjake * Redistribution and use in source and binary forms, with or without
1080709Sjake * modification, are permitted provided that the following conditions
1180709Sjake * are met:
1280709Sjake * 1. Redistributions of source code must retain the above copyright
1380709Sjake *    notice, this list of conditions, and the following disclaimer,
1481337Sobrien *    without modification, immediately at the beginning of the file.
1580709Sjake * 2. The name of the author may not be used to endorse or promote products
1680709Sjake *    derived from this software without specific prior written permission.
1781337Sobrien *
1880709Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1980709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2080709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2180709Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2280709Sjake * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2380709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2480709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2580709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2680709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27114188Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28114188Sjake * SUCH DAMAGE.
29114188Sjake *
30166105Smarius * Derived from bt isa from end, written by:
31166105Smarius *
3280709Sjake * Copyright (c) 1998 Justin T. Gibbs
3380709Sjake * All rights reserved.
34166105Smarius *
35166105Smarius * Redistribution and use in source and binary forms, with or without
36166105Smarius * modification, are permitted provided that the following conditions
3782909Sjake * are met:
38205409Smarius * 1. Redistributions of source code must retain the above copyright
3980709Sjake *    notice, this list of conditions, and the following disclaimer,
4080709Sjake *    without modification, immediately at the beginning of the file.
4180709Sjake * 2. The name of the author may not be used to endorse or promote products
4288641Sjake *    derived from this software without specific prior written permission.
4388641Sjake *
4488641Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4588641Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4684193Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4784193Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
4884193Sjake * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4984193Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5084193Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5184193Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5284193Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5384193Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5484193Sjake * SUCH DAMAGE.
5584193Sjake */
5684193Sjake
5784193Sjake#include <sys/cdefs.h>
5884193Sjake__FBSDID("$FreeBSD: head/sys/dev/aha/aha_isa.c 157085 2006-03-24 06:33:25Z imp $");
5984193Sjake
6084193Sjake#include <sys/param.h>
6184193Sjake#include <sys/systm.h>
6284193Sjake#include <sys/kernel.h>
6384193Sjake#include <sys/lock.h>
6484193Sjake#include <sys/mutex.h>
6584193Sjake
6684193Sjake#include <machine/bus.h>
6784193Sjake#include <machine/resource.h>
6884193Sjake#include <sys/module.h>
6984193Sjake#include <sys/bus.h>
7084193Sjake#include <sys/rman.h>
7184193Sjake
7284193Sjake#include <isa/isavar.h>
7384193Sjake
74116589Sjake#include <dev/aha/ahareg.h>
7580709Sjake
7684193Sjake#include <cam/scsi/scsi_all.h>
7784193Sjake
7884193Sjakestatic struct isa_pnp_id aha_ids[] = {
7984193Sjake	{ADP0100_PNP,		"Adaptec 1540/1542 ISA SCSI"},	/* ADP0100 */
8084193Sjake	{AHA1540_PNP,		"Adaptec 1540/aha-1640/aha-1535"},/* ADP1540 */
8180709Sjake	{AHA1542_PNP,		"Adaptec 1542/aha-1535"},	/* ADP1542 */
8284193Sjake	{AHA1542_PNPCOMPAT,	"Adaptec 1542 compatible"},	/* PNP00A0 */
8384193Sjake	{ICU0091_PNP,		"Adaptec AHA-1540/1542 SCSI"},	/* ICU0091 */
8486520Sjake	{0}
8584193Sjake};
8684193Sjake
8784193Sjake/*
8884193Sjake * I/O ports listed in the order enumerated by the card for certain op codes.
8984193Sjake */
9084193Sjakestatic bus_addr_t aha_board_ports[] =
9184193Sjake{
9284193Sjake	0x330,
9384193Sjake	0x334,
9484193Sjake	0x230,
9584193Sjake	0x234,
9684193Sjake	0x130,
9784193Sjake	0x134
9884193Sjake};
9984193Sjake
10084193Sjake/*
10184193Sjake * Check if the device can be found at the port given
10284193Sjake */
10384193Sjakestatic int
10484193Sjakeaha_isa_probe(device_t dev)
105114189Sjake{
10684193Sjake	/*
10784193Sjake	 * find unit and check we have that many defined
10884193Sjake	 */
10984193Sjake	struct	aha_softc *aha = device_get_softc(dev);
11084193Sjake	int	error;
11184193Sjake	u_long	port_start;
112116589Sjake	struct resource *port_res;
11384193Sjake	int	port_rid;
114114189Sjake	int	drq;
11584193Sjake	int	irq;
11684193Sjake	config_data_t config_data;
11784193Sjake
11884193Sjake	aha->dev = dev;
11984193Sjake	/* Check isapnp ids */
12084193Sjake	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
12184193Sjake		return (ENXIO);
122116589Sjake
12384193Sjake	port_rid = 0;
124114189Sjake	port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
12584193Sjake	    0, ~0, AHA_NREGS, RF_ACTIVE);
12684193Sjake
12784193Sjake	if (port_res == NULL)
12884193Sjake		return (ENXIO);
129116589Sjake
13084193Sjake	port_start = rman_get_start(port_res);
131114189Sjake	aha_alloc(aha, device_get_unit(dev), rman_get_bustag(port_res),
13284193Sjake	    rman_get_bushandle(port_res));
13384193Sjake
13484193Sjake	/* See if there is really a card present */
13584193Sjake	if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
136116589Sjake		aha_free(aha);
13784193Sjake		bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
13884193Sjake		return (ENXIO);
13980709Sjake	}
14084193Sjake
14184193Sjake	/*
14286520Sjake	 * Determine our IRQ, and DMA settings and
14386520Sjake	 * export them to the configuration system.
14484193Sjake	 */
14584193Sjake	error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
14684193Sjake	    (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT);
14784193Sjake
14884193Sjake	if (error != 0) {
14988641Sjake		device_printf(dev, "Could not determine IRQ or DMA "
15084193Sjake		    "settings for adapter at %#jx.  Failing probe\n",
15184193Sjake		    (uintmax_t)port_start);
15284193Sjake		aha_free(aha);
15384193Sjake		bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
15484193Sjake		    port_res);
15584193Sjake		return (ENXIO);
15684193Sjake	}
15784193Sjake
15884193Sjake	bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
15984193Sjake
16084193Sjake	switch (config_data.dma_chan) {
16184193Sjake	case DMA_CHAN_5:
16284193Sjake		drq = 5;
16380709Sjake		break;
16484193Sjake	case DMA_CHAN_6:
165116589Sjake		drq = 6;
16684193Sjake		break;
167114189Sjake	case DMA_CHAN_7:
16884193Sjake		drq = 7;
16984193Sjake		break;
17084193Sjake	default:
171116589Sjake		device_printf(dev, "Invalid DMA setting for adapter at %#jx.",
172114189Sjake		    (uintmax_t)port_start);
17384193Sjake		return (ENXIO);
17484193Sjake	}
17584193Sjake	error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
17684193Sjake	if (error)
17784193Sjake		return error;
17884193Sjake
17984193Sjake	irq = ffs(config_data.irq) + 8;
18084193Sjake	error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
18184193Sjake	return (error);
18284193Sjake}
18384193Sjake
18484193Sjake/*
185116589Sjake * Attach all the sub-devices we can find
18684193Sjake */
187114189Sjakestatic int
18884193Sjakeaha_isa_attach(device_t dev)
18984193Sjake{
19084193Sjake	struct	aha_softc *aha = device_get_softc(dev);
19184193Sjake	bus_dma_filter_t *filter;
19284193Sjake	void		 *filter_arg;
19384193Sjake	bus_addr_t	 lowaddr;
194116589Sjake	void		 *ih;
19584193Sjake	int		 error = ENOMEM;
196114189Sjake	int		 aha_free_needed = 0;
19784193Sjake
19884193Sjake	aha->dev = dev;
19984193Sjake	aha->portrid = 0;
20084193Sjake	aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid,
20184193Sjake	    0, ~0, AHA_NREGS, RF_ACTIVE);
20280709Sjake	if (!aha->port) {
203116589Sjake		device_printf(dev, "Unable to allocate I/O ports\n");
20480709Sjake		goto fail;
20584193Sjake	}
20680709Sjake
207101955Sjake	aha->irqrid = 0;
208101955Sjake	aha->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &aha->irqrid,
209101955Sjake	    RF_ACTIVE);
210101955Sjake	if (!aha->irq) {
211101955Sjake		device_printf(dev, "Unable to allocate excluse use of irq\n");
212101955Sjake		goto fail;
213101955Sjake	}
214101955Sjake
215101955Sjake	aha->drqrid = 0;
21680709Sjake	aha->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &aha->drqrid,
217101955Sjake	    RF_ACTIVE);
218101955Sjake	if (!aha->drq) {
219101955Sjake		device_printf(dev, "Unable to allocate drq\n");
220101955Sjake		goto fail;
221101955Sjake	}
222216802Smarius
223101955Sjake#if 0				/* is the drq ever unset? */
224101955Sjake	if (dev->id_drq != -1)
225101955Sjake		isa_dmacascade(dev->id_drq);
22680709Sjake#endif
227101955Sjake	isa_dmacascade(rman_get_start(aha->drq));
228101955Sjake
229101955Sjake	/* Allocate our parent dmatag */
230101955Sjake	filter = NULL;
231101955Sjake	filter_arg = NULL;
232216802Smarius	lowaddr = BUS_SPACE_MAXADDR_24BIT;
233101955Sjake
234101955Sjake	if (bus_dma_tag_create(	/* parent	*/ NULL,
235101955Sjake				/* alignemnt	*/ 1,
23680709Sjake				/* boundary	*/ 0,
237101955Sjake				/* lowaddr	*/ lowaddr,
238101955Sjake				/* highaddr	*/ BUS_SPACE_MAXADDR,
239101955Sjake				/* filter	*/ filter,
240101955Sjake				/* filterarg	*/ filter_arg,
241101955Sjake				/* maxsize	*/ BUS_SPACE_MAXSIZE_24BIT,
242101955Sjake				/* nsegments	*/ ~0,
243101955Sjake				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
244101955Sjake				/* flags	*/ 0,
245101955Sjake				/* lockfunc	*/ busdma_lock_mutex,
24680709Sjake				/* lockarg	*/ &Giant,
24780709Sjake				&aha->parent_dmat) != 0) {
24884193Sjake		device_printf(dev, "dma tag create failed.\n");
24980709Sjake		goto fail;
25080709Sjake        }
25180709Sjake
25280709Sjake	if (aha_init(aha)) {
25380709Sjake		device_printf(dev, "init failed\n");
25480709Sjake		goto fail;
25580709Sjake        }
25684193Sjake	/*
25780709Sjake	 * The 1542A and B look the same.  So we guess based on
25880709Sjake	 * the firmware revision.  It appears that only rev 0 is on
25980709Sjake	 * the A cards.
26080709Sjake	 */
26180709Sjake	if (aha->boardid <= BOARD_1542 && aha->fw_major == 0) {
26280709Sjake		device_printf(dev, "154xA may not work\n");
26380709Sjake		aha->ccb_sg_opcode = INITIATOR_SG_CCB;
26480709Sjake		aha->ccb_ccb_opcode = INITIATOR_CCB;
26580709Sjake	}
26680709Sjake	aha_free_needed++;
26780709Sjake
26886520Sjake	error = aha_attach(aha);
26984193Sjake	if (error) {
27084193Sjake		device_printf(dev, "attach failed\n");
27184193Sjake		goto fail;
27284193Sjake	}
27384193Sjake
27484193Sjake	error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM|INTR_ENTROPY,
27584193Sjake	    aha_intr, aha, &ih);
27684193Sjake	if (error) {
27784193Sjake		device_printf(dev, "Unable to register interrupt handler\n");
27884193Sjake                goto fail;
27984193Sjake	}
28084193Sjake
28184193Sjake	return (0);
28284193Sjakefail: ;
28384193Sjake	bus_free_resource(dev, SYS_RES_IOPORT, aha->port);
28484193Sjake	bus_free_resource(dev, SYS_RES_IRQ, aha->irq);
28584193Sjake	bus_free_resource(dev, SYS_RES_DRQ, aha->drq);
28684193Sjake	if (aha_free_needed)
28784193Sjake		aha_free(aha);
288116589Sjake	return (error);
28984193Sjake}
29084193Sjake
29184193Sjakestatic int
29284193Sjakeaha_isa_detach(device_t dev)
29384193Sjake{
29484193Sjake	struct aha_softc *aha = (struct aha_softc *)device_get_softc(dev);
29584193Sjake	int error;
296216802Smarius
29780709Sjake	error = bus_teardown_intr(dev, aha->irq, aha->ih);
29880709Sjake	if (error)
29980709Sjake		device_printf(dev, "failed to unregister interrupt handler\n");
30080709Sjake
30180709Sjake	bus_free_resource(dev, SYS_RES_IOPORT, aha->port);
30284193Sjake	bus_free_resource(dev, SYS_RES_IRQ, aha->irq);
30380709Sjake	bus_free_resource(dev, SYS_RES_DRQ, aha->drq);
30484193Sjake
305216802Smarius	error = aha_detach(aha);
30680709Sjake	if (error) {
30780709Sjake		device_printf(dev, "detach failed\n");
30884193Sjake		return (error);
30980709Sjake	}
31080709Sjake	aha_free(aha);
311101955Sjake
31280709Sjake	return (0);
313101955Sjake}
314216802Smarius
31584193Sjakestatic void
316101955Sjakeaha_isa_identify(driver_t *driver, device_t parent)
317101955Sjake{
31884193Sjake	int i;
31984193Sjake	bus_addr_t ioport;
32080709Sjake	struct aha_softc aha;
32180709Sjake	int rid;
32280709Sjake	struct resource *res;
32384193Sjake	device_t child;
324216802Smarius
32580709Sjake	/* Attempt to find an adapter */
32680709Sjake	for (i = 0; i < sizeof(aha_board_ports) / sizeof(aha_board_ports[0]);
32780709Sjake	    i++) {
32880709Sjake		bzero(&aha, sizeof(aha));
32980709Sjake		ioport = aha_board_ports[i];
33084193Sjake		/*
33184193Sjake		 * XXX Check to see if we have a hard-wired aha device at
33284193Sjake		 * XXX this port, if so, skip.  This should also cover the
33384193Sjake		 * XXX case where we are run multiple times due to, eg,
334216802Smarius		 * XXX kldload/kldunload.
33584193Sjake		 */
33684193Sjake		rid = 0;
33784193Sjake		res = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid,
33884193Sjake		    ioport, ioport, AHA_NREGS, RF_ACTIVE);
339101955Sjake		if (res == NULL)
340101955Sjake			continue;
341101955Sjake		aha_alloc(&aha, -1, rman_get_bustag(res),
342101955Sjake		    rman_get_bushandle(res));
34384193Sjake		/* See if there is really a card present */
34480709Sjake		if (aha_probe(&aha) || aha_fetch_adapter_info(&aha))
34580709Sjake			goto not_this_one;
34680709Sjake		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "aha", -1);
34784193Sjake		bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, AHA_NREGS);
348216802Smarius		/*
34980709Sjake		 * Could query the board and set IRQ/DRQ, but probe does
35080709Sjake		 * that.
35180709Sjake		 */
35280709Sjake	not_this_one:;
35380709Sjake		bus_release_resource(parent, SYS_RES_IOPORT, rid, res);
35480709Sjake		aha_free(&aha);
35580709Sjake	}
35680709Sjake}
35784193Sjake
358216802Smariusstatic device_method_t aha_isa_methods[] = {
35980709Sjake	/* Device interface */
36084193Sjake	DEVMETHOD(device_probe,		aha_isa_probe),
36180709Sjake	DEVMETHOD(device_attach,	aha_isa_attach),
36280709Sjake	DEVMETHOD(device_detach,	aha_isa_detach),
36380709Sjake	DEVMETHOD(device_identify,	aha_isa_identify),
36480709Sjake
36580709Sjake	{ 0, 0 }
36680709Sjake};
36784193Sjake
368216802Smariusstatic driver_t aha_isa_driver = {
36980709Sjake	"aha",
37080709Sjake	aha_isa_methods,
37180709Sjake	sizeof(struct aha_softc),
37280709Sjake};
373101955Sjake
374101955Sjakestatic devclass_t aha_devclass;
375101955Sjake
376101955SjakeDRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0);
377101955SjakeMODULE_DEPEND(aha, cam, 1, 1, 1);
37880709Sjake