152417Sluoqi/*-
252417Sluoqi * Copyright (c) 1999 Luoqi Chen.
352417Sluoqi * All rights reserved.
452417Sluoqi *
552417Sluoqi * Redistribution and use in source and binary forms, with or without
652417Sluoqi * modification, are permitted provided that the following conditions
752417Sluoqi * are met:
852417Sluoqi * 1. Redistributions of source code must retain the above copyright
952417Sluoqi *    notice, this list of conditions and the following disclaimer.
1052417Sluoqi * 2. Redistributions in binary form must reproduce the above copyright
1152417Sluoqi *    notice, this list of conditions and the following disclaimer in the
1252417Sluoqi *    documentation and/or other materials provided with the distribution.
1352417Sluoqi *
1452417Sluoqi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1552417Sluoqi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1652417Sluoqi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1752417Sluoqi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1852417Sluoqi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1952417Sluoqi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2052417Sluoqi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2152417Sluoqi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2252417Sluoqi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2352417Sluoqi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2452417Sluoqi * SUCH DAMAGE.
2552417Sluoqi */
2652417Sluoqi
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD$");
29119418Sobrien
3052417Sluoqi#include <sys/param.h>
31241591Sjhb#include <sys/callout.h>
3252417Sluoqi#include <sys/kernel.h>
33241591Sjhb#include <sys/lock.h>
3452417Sluoqi#include <sys/module.h>
35241591Sjhb#include <sys/mutex.h>
3652417Sluoqi#include <sys/bus.h>
3752417Sluoqi
3852417Sluoqi#include <machine/bus.h>
3952417Sluoqi#include <machine/resource.h>
4052417Sluoqi#include <sys/rman.h>
4152417Sluoqi
4252417Sluoqi#include <isa/isavar.h>
4352417Sluoqi#include <dev/aic/aic6360reg.h>
4452417Sluoqi#include <dev/aic/aicvar.h>
4552417Sluoqi
4652417Sluoqistruct aic_isa_softc {
4752417Sluoqi	struct	aic_softc sc_aic;
4852417Sluoqi	struct	resource *sc_port;
4952417Sluoqi	struct	resource *sc_irq;
5052417Sluoqi	struct	resource *sc_drq;
5152417Sluoqi	void	*sc_ih;
5252417Sluoqi};
5352417Sluoqi
5492739Salfredstatic int aic_isa_alloc_resources(device_t);
5592739Salfredstatic void aic_isa_release_resources(device_t);
5692739Salfredstatic int aic_isa_probe(device_t);
5792739Salfredstatic int aic_isa_attach(device_t);
5852417Sluoqi
5952417Sluoqistatic u_int aic_isa_ports[] = { 0x340, 0x140 };
60298432Spfg
61298432Spfg#define	AIC_ISA_NUMPORTS nitems(aic_isa_ports)
6252417Sluoqi#define	AIC_ISA_PORTSIZE 0x20
6352417Sluoqi
6477844Simpstatic struct isa_pnp_id aic_ids[] = {
6577844Simp	{ 0x15309004, "Adaptec AHA-1530P" },
6677844Simp	{ 0x15209004, "Adaptec AHA-1520P" },
6777844Simp 	{ 0 }
6877844Simp};
6977844Simp
7052417Sluoqistatic int
7152417Sluoqiaic_isa_alloc_resources(device_t dev)
7252417Sluoqi{
7352417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
7452417Sluoqi	int rid;
7552417Sluoqi
76241591Sjhb	sc->sc_port = sc->sc_irq = sc->sc_drq = NULL;
7752417Sluoqi
7852417Sluoqi	rid = 0;
79296137Sjhibbits	sc->sc_port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
80296137Sjhibbits						AIC_ISA_PORTSIZE, RF_ACTIVE);
8174370Sken	if (!sc->sc_port) {
8274370Sken		device_printf(dev, "I/O port allocation failed\n");
8352417Sluoqi		return (ENOMEM);
8474370Sken	}
8552417Sluoqi
8652417Sluoqi	if (isa_get_irq(dev) != -1) {
8752417Sluoqi		rid = 0;
88127135Snjl		sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
89127135Snjl						    RF_ACTIVE);
9052417Sluoqi		if (!sc->sc_irq) {
9174370Sken			device_printf(dev, "IRQ allocation failed\n");
9252417Sluoqi			aic_isa_release_resources(dev);
9352417Sluoqi			return (ENOMEM);
9452417Sluoqi		}
9552417Sluoqi	}
9652417Sluoqi
9752417Sluoqi	if (isa_get_drq(dev) != -1) {
9852417Sluoqi		rid = 0;
99127135Snjl		sc->sc_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid,
100127135Snjl						    RF_ACTIVE);
10152417Sluoqi		if (!sc->sc_drq) {
10274370Sken			device_printf(dev, "DRQ allocation failed\n");
10352417Sluoqi			aic_isa_release_resources(dev);
10452417Sluoqi			return (ENOMEM);
10552417Sluoqi		}
10652417Sluoqi	}
10752417Sluoqi
108170872Sscottl	sc->sc_aic.dev = dev;
109241591Sjhb	sc->sc_aic.res = sc->sc_port;
110241591Sjhb	mtx_init(&sc->sc_aic.lock, "aic", NULL, MTX_DEF);
11152417Sluoqi	return (0);
11252417Sluoqi}
11352417Sluoqi
11452417Sluoqistatic void
11552417Sluoqiaic_isa_release_resources(device_t dev)
11652417Sluoqi{
11752417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
11852417Sluoqi
11952417Sluoqi	if (sc->sc_port)
12052417Sluoqi		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port);
12152417Sluoqi	if (sc->sc_irq)
12252417Sluoqi		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
12352417Sluoqi	if (sc->sc_drq)
12452417Sluoqi		bus_release_resource(dev, SYS_RES_DRQ, 0, sc->sc_drq);
125241591Sjhb	sc->sc_port = sc->sc_irq = sc->sc_drq = NULL;
126241591Sjhb	mtx_destroy(&sc->sc_aic.lock);
12752417Sluoqi}
12852417Sluoqi
12952417Sluoqistatic int
13052417Sluoqiaic_isa_probe(device_t dev)
13152417Sluoqi{
13252417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
13352417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
13452417Sluoqi	int numports, i;
13552417Sluoqi	u_int port, *ports;
13652417Sluoqi	u_int8_t porta;
13752417Sluoqi
13877844Simp	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aic_ids) == ENXIO)
13952417Sluoqi		return (ENXIO);
14052417Sluoqi
14152417Sluoqi	port = isa_get_port(dev);
14252417Sluoqi	if (port != -1) {
14352417Sluoqi		ports = &port;
14452417Sluoqi		numports = 1;
14552417Sluoqi	} else {
14652417Sluoqi		ports = aic_isa_ports;
14752417Sluoqi		numports = AIC_ISA_NUMPORTS;
14852417Sluoqi	}
14952417Sluoqi
15052417Sluoqi	for (i = 0; i < numports; i++) {
15152417Sluoqi		if (bus_set_resource(dev, SYS_RES_IOPORT, 0, ports[i],
15252417Sluoqi				     AIC_ISA_PORTSIZE))
15352417Sluoqi			continue;
15452417Sluoqi		if (aic_isa_alloc_resources(dev))
15552417Sluoqi			continue;
156241591Sjhb		if (aic_probe(aic) == 0)
15752417Sluoqi			break;
15852417Sluoqi		aic_isa_release_resources(dev);
15952417Sluoqi	}
16052417Sluoqi
16152417Sluoqi	if (i == numports)
16252417Sluoqi		return (ENXIO);
16352417Sluoqi
16452417Sluoqi	porta = aic_inb(aic, PORTA);
165241591Sjhb	aic_isa_release_resources(dev);
16652417Sluoqi	if (isa_get_irq(dev) == -1)
16752417Sluoqi		bus_set_resource(dev, SYS_RES_IRQ, 0, PORTA_IRQ(porta), 1);
16852417Sluoqi	if ((aic->flags & AIC_DMA_ENABLE) && isa_get_drq(dev) == -1)
16952417Sluoqi		bus_set_resource(dev, SYS_RES_DRQ, 0, PORTA_DRQ(porta), 1);
17054136Sluoqi	device_set_desc(dev, "Adaptec 6260/6360 SCSI controller");
17152417Sluoqi	return (0);
17252417Sluoqi}
17352417Sluoqi
17452417Sluoqistatic int
17552417Sluoqiaic_isa_attach(device_t dev)
17652417Sluoqi{
17752417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
17852417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
17952417Sluoqi	int error;
18052417Sluoqi
18152417Sluoqi	error = aic_isa_alloc_resources(dev);
18252417Sluoqi	if (error) {
18352417Sluoqi		device_printf(dev, "resource allocation failed\n");
18452417Sluoqi		return (error);
18552417Sluoqi	}
18652417Sluoqi
18752417Sluoqi	error = aic_attach(aic);
18852417Sluoqi	if (error) {
18952417Sluoqi		device_printf(dev, "attach failed\n");
19052417Sluoqi		aic_isa_release_resources(dev);
19152417Sluoqi		return (error);
19252417Sluoqi	}
19352417Sluoqi
194241591Sjhb	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM | INTR_ENTROPY |
195241591Sjhb	    INTR_MPSAFE, NULL, aic_intr, aic, &sc->sc_ih);
19652417Sluoqi	if (error) {
19752417Sluoqi		device_printf(dev, "failed to register interrupt handler\n");
19852417Sluoqi		aic_isa_release_resources(dev);
19952417Sluoqi		return (error);
20052417Sluoqi	}
20152417Sluoqi	return (0);
20252417Sluoqi}
20352417Sluoqi
20452417Sluoqistatic int
20552417Sluoqiaic_isa_detach(device_t dev)
20652417Sluoqi{
20752417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
20852417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
20952417Sluoqi	int error;
21052417Sluoqi
21152417Sluoqi	error = aic_detach(aic);
21252417Sluoqi	if (error) {
21352417Sluoqi		device_printf(dev, "detach failed\n");
21452417Sluoqi		return (error);
21552417Sluoqi	}
21652417Sluoqi
21752417Sluoqi	error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
21852417Sluoqi	if (error) {
21952417Sluoqi		device_printf(dev, "failed to unregister interrupt handler\n");
22052417Sluoqi	}
22152417Sluoqi
22252417Sluoqi	aic_isa_release_resources(dev);
22352417Sluoqi	return (0);
22452417Sluoqi}
22552417Sluoqi
22652417Sluoqistatic device_method_t aic_isa_methods[] = {
22752417Sluoqi	/* Device interface */
22852417Sluoqi	DEVMETHOD(device_probe,		aic_isa_probe),
22952417Sluoqi	DEVMETHOD(device_attach,	aic_isa_attach),
23052417Sluoqi	DEVMETHOD(device_detach,	aic_isa_detach),
23152417Sluoqi	{ 0, 0 }
23252417Sluoqi};
23352417Sluoqi
23452417Sluoqistatic driver_t aic_isa_driver = {
23552417Sluoqi	"aic",
23652417Sluoqi	aic_isa_methods, sizeof(struct aic_isa_softc),
23752417Sluoqi};
23852417Sluoqi
23955997Simpextern devclass_t aic_devclass;
24052417Sluoqi
24169960SimpMODULE_DEPEND(aic, cam, 1,1,1);
24252417SluoqiDRIVER_MODULE(aic, isa, aic_isa_driver, aic_devclass, 0, 0);
243