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 };
6052417Sluoqi#define	AIC_ISA_NUMPORTS (sizeof(aic_isa_ports) / sizeof(aic_isa_ports[0]))
6152417Sluoqi#define	AIC_ISA_PORTSIZE 0x20
6252417Sluoqi
6377844Simpstatic struct isa_pnp_id aic_ids[] = {
6477844Simp	{ 0x15309004, "Adaptec AHA-1530P" },
6577844Simp	{ 0x15209004, "Adaptec AHA-1520P" },
6677844Simp 	{ 0 }
6777844Simp};
6877844Simp
6952417Sluoqistatic int
7052417Sluoqiaic_isa_alloc_resources(device_t dev)
7152417Sluoqi{
7252417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
7352417Sluoqi	int rid;
7452417Sluoqi
75241591Sjhb	sc->sc_port = sc->sc_irq = sc->sc_drq = NULL;
7652417Sluoqi
7752417Sluoqi	rid = 0;
7852417Sluoqi	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
7952417Sluoqi					0ul, ~0ul, AIC_ISA_PORTSIZE, RF_ACTIVE);
8074370Sken	if (!sc->sc_port) {
8174370Sken		device_printf(dev, "I/O port allocation failed\n");
8252417Sluoqi		return (ENOMEM);
8374370Sken	}
8452417Sluoqi
8552417Sluoqi	if (isa_get_irq(dev) != -1) {
8652417Sluoqi		rid = 0;
87127135Snjl		sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
88127135Snjl						    RF_ACTIVE);
8952417Sluoqi		if (!sc->sc_irq) {
9074370Sken			device_printf(dev, "IRQ allocation failed\n");
9152417Sluoqi			aic_isa_release_resources(dev);
9252417Sluoqi			return (ENOMEM);
9352417Sluoqi		}
9452417Sluoqi	}
9552417Sluoqi
9652417Sluoqi	if (isa_get_drq(dev) != -1) {
9752417Sluoqi		rid = 0;
98127135Snjl		sc->sc_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid,
99127135Snjl						    RF_ACTIVE);
10052417Sluoqi		if (!sc->sc_drq) {
10174370Sken			device_printf(dev, "DRQ allocation failed\n");
10252417Sluoqi			aic_isa_release_resources(dev);
10352417Sluoqi			return (ENOMEM);
10452417Sluoqi		}
10552417Sluoqi	}
10652417Sluoqi
107170872Sscottl	sc->sc_aic.dev = dev;
108241591Sjhb	sc->sc_aic.res = sc->sc_port;
109241591Sjhb	mtx_init(&sc->sc_aic.lock, "aic", NULL, MTX_DEF);
11052417Sluoqi	return (0);
11152417Sluoqi}
11252417Sluoqi
11352417Sluoqistatic void
11452417Sluoqiaic_isa_release_resources(device_t dev)
11552417Sluoqi{
11652417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
11752417Sluoqi
11852417Sluoqi	if (sc->sc_port)
11952417Sluoqi		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port);
12052417Sluoqi	if (sc->sc_irq)
12152417Sluoqi		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
12252417Sluoqi	if (sc->sc_drq)
12352417Sluoqi		bus_release_resource(dev, SYS_RES_DRQ, 0, sc->sc_drq);
124241591Sjhb	sc->sc_port = sc->sc_irq = sc->sc_drq = NULL;
125241591Sjhb	mtx_destroy(&sc->sc_aic.lock);
12652417Sluoqi}
12752417Sluoqi
12852417Sluoqistatic int
12952417Sluoqiaic_isa_probe(device_t dev)
13052417Sluoqi{
13152417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
13252417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
13352417Sluoqi	int numports, i;
13452417Sluoqi	u_int port, *ports;
13552417Sluoqi	u_int8_t porta;
13652417Sluoqi
13777844Simp	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aic_ids) == ENXIO)
13852417Sluoqi		return (ENXIO);
13952417Sluoqi
14052417Sluoqi	port = isa_get_port(dev);
14152417Sluoqi	if (port != -1) {
14252417Sluoqi		ports = &port;
14352417Sluoqi		numports = 1;
14452417Sluoqi	} else {
14552417Sluoqi		ports = aic_isa_ports;
14652417Sluoqi		numports = AIC_ISA_NUMPORTS;
14752417Sluoqi	}
14852417Sluoqi
14952417Sluoqi	for (i = 0; i < numports; i++) {
15052417Sluoqi		if (bus_set_resource(dev, SYS_RES_IOPORT, 0, ports[i],
15152417Sluoqi				     AIC_ISA_PORTSIZE))
15252417Sluoqi			continue;
15352417Sluoqi		if (aic_isa_alloc_resources(dev))
15452417Sluoqi			continue;
155241591Sjhb		if (aic_probe(aic) == 0)
15652417Sluoqi			break;
15752417Sluoqi		aic_isa_release_resources(dev);
15852417Sluoqi	}
15952417Sluoqi
16052417Sluoqi	if (i == numports)
16152417Sluoqi		return (ENXIO);
16252417Sluoqi
16352417Sluoqi	porta = aic_inb(aic, PORTA);
164241591Sjhb	aic_isa_release_resources(dev);
16552417Sluoqi	if (isa_get_irq(dev) == -1)
16652417Sluoqi		bus_set_resource(dev, SYS_RES_IRQ, 0, PORTA_IRQ(porta), 1);
16752417Sluoqi	if ((aic->flags & AIC_DMA_ENABLE) && isa_get_drq(dev) == -1)
16852417Sluoqi		bus_set_resource(dev, SYS_RES_DRQ, 0, PORTA_DRQ(porta), 1);
16954136Sluoqi	device_set_desc(dev, "Adaptec 6260/6360 SCSI controller");
17052417Sluoqi	return (0);
17152417Sluoqi}
17252417Sluoqi
17352417Sluoqistatic int
17452417Sluoqiaic_isa_attach(device_t dev)
17552417Sluoqi{
17652417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
17752417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
17852417Sluoqi	int error;
17952417Sluoqi
18052417Sluoqi	error = aic_isa_alloc_resources(dev);
18152417Sluoqi	if (error) {
18252417Sluoqi		device_printf(dev, "resource allocation failed\n");
18352417Sluoqi		return (error);
18452417Sluoqi	}
18552417Sluoqi
18652417Sluoqi	error = aic_attach(aic);
18752417Sluoqi	if (error) {
18852417Sluoqi		device_printf(dev, "attach failed\n");
18952417Sluoqi		aic_isa_release_resources(dev);
19052417Sluoqi		return (error);
19152417Sluoqi	}
19252417Sluoqi
193241591Sjhb	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM | INTR_ENTROPY |
194241591Sjhb	    INTR_MPSAFE, NULL, aic_intr, aic, &sc->sc_ih);
19552417Sluoqi	if (error) {
19652417Sluoqi		device_printf(dev, "failed to register interrupt handler\n");
19752417Sluoqi		aic_isa_release_resources(dev);
19852417Sluoqi		return (error);
19952417Sluoqi	}
20052417Sluoqi	return (0);
20152417Sluoqi}
20252417Sluoqi
20352417Sluoqistatic int
20452417Sluoqiaic_isa_detach(device_t dev)
20552417Sluoqi{
20652417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
20752417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
20852417Sluoqi	int error;
20952417Sluoqi
21052417Sluoqi	error = aic_detach(aic);
21152417Sluoqi	if (error) {
21252417Sluoqi		device_printf(dev, "detach failed\n");
21352417Sluoqi		return (error);
21452417Sluoqi	}
21552417Sluoqi
21652417Sluoqi	error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
21752417Sluoqi	if (error) {
21852417Sluoqi		device_printf(dev, "failed to unregister interrupt handler\n");
21952417Sluoqi	}
22052417Sluoqi
22152417Sluoqi	aic_isa_release_resources(dev);
22252417Sluoqi	return (0);
22352417Sluoqi}
22452417Sluoqi
22552417Sluoqistatic device_method_t aic_isa_methods[] = {
22652417Sluoqi	/* Device interface */
22752417Sluoqi	DEVMETHOD(device_probe,		aic_isa_probe),
22852417Sluoqi	DEVMETHOD(device_attach,	aic_isa_attach),
22952417Sluoqi	DEVMETHOD(device_detach,	aic_isa_detach),
23052417Sluoqi	{ 0, 0 }
23152417Sluoqi};
23252417Sluoqi
23352417Sluoqistatic driver_t aic_isa_driver = {
23452417Sluoqi	"aic",
23552417Sluoqi	aic_isa_methods, sizeof(struct aic_isa_softc),
23652417Sluoqi};
23752417Sluoqi
23855997Simpextern devclass_t aic_devclass;
23952417Sluoqi
24069960SimpMODULE_DEPEND(aic, cam, 1,1,1);
24152417SluoqiDRIVER_MODULE(aic, isa, aic_isa_driver, aic_devclass, 0, 0);
242