aha_isa.c revision 58544
11592Srgrimes/*
21592Srgrimes * Product specific probe and attach routines for:
31592Srgrimes *      Adaptec 154x.
41592Srgrimes *
51592Srgrimes * Derived from code written by:
61592Srgrimes *
71592Srgrimes * Copyright (c) 1998 Justin T. Gibbs
81592Srgrimes * All rights reserved.
91592Srgrimes *
101592Srgrimes * Redistribution and use in source and binary forms, with or without
111592Srgrimes * modification, are permitted provided that the following conditions
121592Srgrimes * are met:
131592Srgrimes * 1. Redistributions of source code must retain the above copyright
141592Srgrimes *    notice, this list of conditions, and the following disclaimer,
151592Srgrimes *    without modification, immediately at the beginning of the file.
161592Srgrimes * 2. The name of the author may not be used to endorse or promote products
171592Srgrimes *    derived from this software without specific prior written permission.
181592Srgrimes *
191592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
201592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
231592Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291592Srgrimes * SUCH DAMAGE.
301592Srgrimes *
311592Srgrimes * $FreeBSD: head/sys/dev/aha/aha_isa.c 58544 2000-03-25 03:24:43Z imp $
321592Srgrimes */
331592Srgrimes
341592Srgrimes#include <sys/param.h>
351592Srgrimes#include <sys/systm.h>
361592Srgrimes#include <sys/kernel.h>
371592Srgrimes
381592Srgrimes#include <machine/bus_pio.h>
391592Srgrimes#include <machine/bus.h>
401592Srgrimes#include <machine/resource.h>
411592Srgrimes#include <sys/module.h>
421592Srgrimes#include <sys/bus.h>
431592Srgrimes#include <sys/rman.h>
4431329Scharnier
451592Srgrimes#include <isa/isavar.h>
4631329Scharnier
4731329Scharnier#include <dev/aha/ahareg.h>
4850476Speter
491592Srgrimes#include <cam/scsi/scsi_all.h>
501592Srgrimes
511592Srgrimesstatic struct isa_pnp_id aha_ids[] = {
521592Srgrimes	{ADP0100_PNP,		"Adaptec 1540/1542 ISA SCSI"},	/* ADP0100 */
531592Srgrimes	{AHA1540_PNP,		"Adaptec 1540/aha-1640/aha-1535"},/* ADP1542 */
541592Srgrimes	{AHA1542_PNP,		"Adaptec 1542/aha-1535"},	/* ADP1542 */
551592Srgrimes	{AHA1542_PNPCOMPAT,	"Adaptec 1542 compatible"},	/* PNP00A0 */
561592Srgrimes	{ICU0091_PNP,		"Adaptec AHA-1540/1542 SCSI"},	/* ICU0091 */
571592Srgrimes	{0}
581592Srgrimes};
591592Srgrimes
601592Srgrimes/*
6192090Smaxim * Check if the device can be found at the port given
6292272Smaxim * and if so, set it up ready for further work
6392090Smaxim * as an argument, takes the isa_device structure from
6456668Sshin * autoconf.c
651592Srgrimes */
661592Srgrimesstatic int
671592Srgrimesaha_isa_probe(device_t dev)
681592Srgrimes{
691592Srgrimes	/*
701592Srgrimes	 * find unit and check we have that many defined
711592Srgrimes	 */
721592Srgrimes	struct	aha_softc **sc = device_get_softc(dev);
731592Srgrimes	struct	aha_softc *aha;
741592Srgrimes	int	port_index;
75109380Syar	int	max_port_index;
761592Srgrimes	int	error;
7756668Sshin	u_long	port_start, port_count;
781592Srgrimes	struct resource *port_res;
791592Srgrimes	int	port_rid;
801592Srgrimes	int	drq;
8117435Spst	int	irq;
821592Srgrimes
831592Srgrimes	aha = NULL;
841592Srgrimes
8576096Smarkm	/* Check isapnp ids */
861592Srgrimes	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO)
871592Srgrimes		return (ENXIO);
881592Srgrimes
8927650Sdavidn	error = bus_get_resource(dev, SYS_RES_IOPORT, 0,
9027650Sdavidn				 &port_start, &port_count);
911592Srgrimes	if (error != 0)
921592Srgrimes		port_start = 0;
931592Srgrimes
941592Srgrimes	/*
9570102Sphk	 * Bound our board search if the user has
9670102Sphk	 * specified an exact port.
9782460Snik	 */
9882796Ssheldonh	aha_find_probe_range(port_start, &port_index, &max_port_index);
99100684Syar
1001592Srgrimes	if (port_index < 0)
1011592Srgrimes		return ENXIO;
1021592Srgrimes
1031592Srgrimes	/* Attempt to find an adapter */
1041592Srgrimes	for (;port_index <= max_port_index; port_index++) {
1051592Srgrimes		config_data_t config_data;
10689935Syar		u_int ioport;
1071592Srgrimes		int error;
10888935Sdwmalone
1091592Srgrimes		ioport = aha_iop_from_bio(port_index);
11056668Sshin
11156668Sshin		error = bus_set_resource(dev, SYS_RES_IOPORT, 0,
1121592Srgrimes					 ioport, AHA_NREGS);
1131592Srgrimes		if (error)
1141592Srgrimes			return error;
11592272Smaxim
11692272Smaxim		port_rid = 0;
11792272Smaxim		port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid,
11892272Smaxim		    0, ~0, AHA_NREGS, RF_ACTIVE);
1191592Srgrimes		if (!port_res)
1201592Srgrimes			continue;
1211592Srgrimes
1221592Srgrimes		/* Allocate a softc for use during probing */
1231592Srgrimes		aha = aha_alloc(device_get_unit(dev), rman_get_bustag(port_res),
1241592Srgrimes		    rman_get_bushandle(port_res));
12556668Sshin
1261592Srgrimes		if (aha == NULL) {
1271592Srgrimes			bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
1281592Srgrimes			    port_res);
1291592Srgrimes			break;
1301592Srgrimes		}
1311592Srgrimes
1321592Srgrimes		/* See if there is really a card present */
1331592Srgrimes		if (aha_probe(aha) || aha_fetch_adapter_info(aha)) {
1341592Srgrimes			aha_free(aha);
1351592Srgrimes			bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
13656668Sshin			    port_res);
1371592Srgrimes			continue;
13875535Sphk		}
1391592Srgrimes
140102565Syar		/*
1411592Srgrimes		 * Determine our IRQ, and DMA settings and
1421592Srgrimes		 * export them to the configuration system.
14392272Smaxim		 */
1441592Srgrimes		error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
14592272Smaxim		    (u_int8_t*)&config_data, sizeof(config_data),
14692272Smaxim		    DEFAULT_CMD_TIMEOUT);
14792272Smaxim
14875567Speter		if (error != 0) {
149102565Syar			printf("aha_isa_probe: Could not determine IRQ or DMA "
1501592Srgrimes			    "settings for adapter at 0x%x.  Failing probe\n",
1511592Srgrimes			    ioport);
1521592Srgrimes			aha_free(aha);
1531592Srgrimes			bus_release_resource(dev, SYS_RES_IOPORT, port_rid,
1541592Srgrimes			    port_res);
1551592Srgrimes			continue;
1561592Srgrimes		}
1571592Srgrimes
1581592Srgrimes		bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res);
15988935Sdwmalone
16088935Sdwmalone		switch (config_data.dma_chan) {
1611592Srgrimes		case DMA_CHAN_5:
1621592Srgrimes			drq = 5;
1631592Srgrimes			break;
1641592Srgrimes		case DMA_CHAN_6:
1651592Srgrimes			drq = 6;
1661592Srgrimes			break;
1671592Srgrimes		case DMA_CHAN_7:
1681592Srgrimes			drq = 7;
1691592Srgrimes			break;
1701592Srgrimes		default:
1711592Srgrimes			printf("aha_isa_probe: Invalid DMA setting "
1721592Srgrimes			    "detected for adapter at 0x%x.  "
1731592Srgrimes			    "Failing probe\n", ioport);
1741592Srgrimes			return (ENXIO);
1751592Srgrimes		}
1761592Srgrimes		error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1);
1771592Srgrimes		if (error)
17875556Sgreen			return error;
17975556Sgreen
18075556Sgreen		irq = ffs(config_data.irq) + 8;
18175556Sgreen		error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
18217433Spst		if (error)
1831592Srgrimes			return error;
18456668Sshin
18556668Sshin		*sc = aha;
18656668Sshin		aha_unit++;
18756668Sshin
18856668Sshin		return (0);
18956668Sshin	}
19056668Sshin
19156668Sshin	return (ENXIO);
19256668Sshin}
19356668Sshin
19456668Sshin/*
19556668Sshin * Attach all the sub-devices we can find
19656668Sshin */
19756668Sshinstatic int
19856668Sshinaha_isa_attach(device_t dev)
19956668Sshin{
20056668Sshin	struct	aha_softc **sc = device_get_softc(dev);
20156668Sshin	struct	aha_softc *aha;
20256668Sshin	bus_dma_filter_t *filter;
20356668Sshin	void		 *filter_arg;
20456668Sshin	bus_addr_t	 lowaddr;
20556668Sshin	void		 *ih;
20656668Sshin	int		 error;
20756668Sshin
20856668Sshin	aha = *sc;
20956668Sshin	aha->portrid = 0;
21056668Sshin	aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid,
21156668Sshin	    0, ~0, AHA_NREGS, RF_ACTIVE);
21256668Sshin	if (!aha->port) {
21356668Sshin		device_printf(dev, "Unable to allocate I/O ports\n");
21456668Sshin		return ENOMEM;
21556668Sshin	}
21656668Sshin
21756668Sshin	aha->irqrid = 0;
21856668Sshin	aha->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &aha->irqrid, 0, ~0, 1,
21956668Sshin	    RF_ACTIVE);
22056668Sshin	if (!aha->irq) {
22156668Sshin		device_printf(dev, "Unable to allocate excluse use of irq\n");
22256668Sshin		bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
22356668Sshin		return ENOMEM;
22456668Sshin	}
22556668Sshin
22656668Sshin	aha->drqrid = 0;
22756668Sshin	aha->drq = bus_alloc_resource(dev, SYS_RES_DRQ, &aha->drqrid, 0, ~0, 1,
22856668Sshin	    RF_ACTIVE);
22956668Sshin	if (!aha->drq) {
23056668Sshin		device_printf(dev, "Unable to allocate drq\n");
23156668Sshin		bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
23256668Sshin		bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
23356668Sshin		return ENOMEM;
23456668Sshin	}
23556668Sshin
23656668Sshin#if 0				/* is the drq ever unset? */
23756668Sshin	if (dev->id_drq != -1)
23856668Sshin		isa_dmacascade(dev->id_drq);
23956668Sshin#endif
24056668Sshin	isa_dmacascade(rman_get_start(aha->drq));
24156668Sshin
24256668Sshin	/* Allocate our parent dmatag */
24356668Sshin	filter = NULL;
24476096Smarkm	filter_arg = NULL;
24556668Sshin	lowaddr = BUS_SPACE_MAXADDR_24BIT;
24656668Sshin
24776096Smarkm	if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0,
24856668Sshin	    lowaddr, /*highaddr*/BUS_SPACE_MAXADDR,
24956668Sshin	    filter, filter_arg,
25056668Sshin	    /*maxsize*/BUS_SPACE_MAXSIZE_24BIT,
25156668Sshin	    /*nsegments*/BUS_SPACE_UNRESTRICTED,
25256668Sshin	    /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
25356668Sshin	    /*flags*/0, &aha->parent_dmat) != 0) {
25456668Sshin                aha_free(aha);
25556668Sshin		bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
25656668Sshin		bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
25756668Sshin		bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
25856668Sshin                return (ENOMEM);
25956668Sshin        }
26056668Sshin
26156668Sshin        if (aha_init(aha)) {
26217433Spst		device_printf(dev, "init failed\n");
26356668Sshin                aha_free(aha);
26417433Spst		bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
26556668Sshin		bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
26656668Sshin		bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
26776096Smarkm                return (ENOMEM);
26856668Sshin        }
26956668Sshin
2701592Srgrimes	error = aha_attach(aha);
27156668Sshin	if (error) {
27256668Sshin		device_printf(dev, "attach failed\n");
27356668Sshin                aha_free(aha);
27456668Sshin		bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
27556668Sshin		bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
27656668Sshin		bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
27756668Sshin                return (error);
27856668Sshin	}
27956668Sshin
28056668Sshin	error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM, aha_intr, aha,
28156668Sshin	    &ih);
28256668Sshin	if (error) {
28356668Sshin		device_printf(dev, "Unable to register interrupt handler\n");
28456668Sshin                aha_free(aha);
28556668Sshin		bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
28656668Sshin		bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
28756668Sshin		bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
28856668Sshin                return (error);
28956668Sshin	}
29056668Sshin
29156668Sshin	return (0);
29256668Sshin}
29356668Sshin
29456668Sshinstatic int
29556668Sshinaha_isa_detach(device_t dev)
29656668Sshin{
29756668Sshin	struct aha_softc *aha = *(struct aha_softc **) device_get_softc(dev);
29856668Sshin	int error;
29956668Sshin
30056668Sshin	error = bus_teardown_intr(dev, aha->irq, aha->ih);
30156668Sshin	if (error) {
30256668Sshin		device_printf(dev, "failed to unregister interrupt handler\n");
30356668Sshin	}
30456668Sshin
30556668Sshin	bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port);
30656668Sshin	bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq);
30756668Sshin	bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq);
30856668Sshin
30956668Sshin	error = aha_detach(aha);
31056668Sshin	if (error) {
31156668Sshin		device_printf(dev, "detach failed\n");
31256668Sshin		return (error);
31356668Sshin	}
31456668Sshin	aha_free(aha);
31556668Sshin
31656668Sshin	return (0);
31756668Sshin}
31856668Sshin
31956668Sshinstatic void
32056668Sshinaha_isa_identify(driver_t *driver, device_t parent)
32156668Sshin{
32256668Sshin}
32388935Sdwmalone
32488935Sdwmalonestatic device_method_t aha_isa_methods[] = {
3251592Srgrimes	/* Device interface */
32617433Spst	DEVMETHOD(device_probe,		aha_isa_probe),
3271592Srgrimes	DEVMETHOD(device_attach,	aha_isa_attach),
32856668Sshin	DEVMETHOD(device_detach,	aha_isa_detach),
32956668Sshin	DEVMETHOD(device_identify,	aha_isa_identify),
33056668Sshin
33117433Spst	{ 0, 0 }
3321592Srgrimes};
33356668Sshin
33456668Sshinstatic driver_t aha_isa_driver = {
33556668Sshin	"aha",
33656668Sshin	aha_isa_methods,
33756668Sshin	sizeof(struct aha_softc*),
33856668Sshin};
33956668Sshin
34070102Sphkstatic devclass_t aha_devclass;
34156668Sshin
34256668SshinDRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0);
34356668Sshin