158789Snyan/*-
258789Snyan * Copyright (c) 1999 Luoqi Chen.
358789Snyan * All rights reserved.
458789Snyan *
558789Snyan * Redistribution and use in source and binary forms, with or without
658789Snyan * modification, are permitted provided that the following conditions
758789Snyan * are met:
858789Snyan * 1. Redistributions of source code must retain the above copyright
958789Snyan *    notice, this list of conditions and the following disclaimer.
1058789Snyan * 2. Redistributions in binary form must reproduce the above copyright
1158789Snyan *    notice, this list of conditions and the following disclaimer in the
1258789Snyan *    documentation and/or other materials provided with the distribution.
1358789Snyan *
1458789Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1558789Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1658789Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1758789Snyan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1858789Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1958789Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2058789Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2158789Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2258789Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2358789Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2458789Snyan * SUCH DAMAGE.
2558789Snyan */
2658789Snyan
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/aic/aic_cbus.c 241591 2012-10-15 16:09:59Z jhb $");
29119418Sobrien
3058789Snyan#include <sys/param.h>
31241591Sjhb#include <sys/callout.h>
3258789Snyan#include <sys/kernel.h>
33241591Sjhb#include <sys/lock.h>
3458789Snyan#include <sys/module.h>
35241591Sjhb#include <sys/mutex.h>
3658789Snyan#include <sys/bus.h>
3758789Snyan
3858789Snyan#include <machine/bus.h>
3958789Snyan#include <machine/resource.h>
4058789Snyan#include <sys/rman.h>
4158789Snyan
4258789Snyan#include <isa/isavar.h>
4358789Snyan#include <dev/aic/aic6360reg.h>
4458789Snyan#include <dev/aic/aicvar.h>
4558789Snyan
4658789Snyanstruct aic_isa_softc {
4758789Snyan	struct	aic_softc sc_aic;
4858789Snyan	struct	resource *sc_port;
4958789Snyan	struct	resource *sc_irq;
5058789Snyan	struct	resource *sc_drq;
5158789Snyan	void	*sc_ih;
5258789Snyan};
5358789Snyan
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);
5858789Snyan
5958789Snyanstatic u_int aic_isa_ports[] = { 0x1840 };
6058789Snyan#define	AIC_ISA_NUMPORTS (sizeof(aic_isa_ports) / sizeof(aic_isa_ports[0]))
6158789Snyan#define	AIC_ISA_PORTSIZE 0x20
6258789Snyan
6358789Snyan#define	AIC98_GENERIC		0x00
6458789Snyan#define	AIC98_NEC100		0x01
6558789Snyan#define	AIC_TYPE98(x)		(((x) >> 16) & 0x01)
6658789Snyan
6758789Snyanstatic bus_addr_t aicport_generic[AIC_ISA_PORTSIZE] = {
6858789Snyan	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
6958789Snyan	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
7058789Snyan	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
7158789Snyan	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
7258789Snyan};
7358789Snyanstatic bus_addr_t aicport_100[AIC_ISA_PORTSIZE] = {
7458789Snyan	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
7558789Snyan	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
7658789Snyan	0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
7758789Snyan	0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
7858789Snyan};
7958789Snyan
8058789Snyanstatic struct isa_pnp_id aic_ids[] = {
8178807Snyan	{ 0xa180a3b8, "NEC PC9801-100" },
8278807Snyan 	{ 0 }
8358789Snyan};
8458789Snyan
8558789Snyanstatic int
8658789Snyanaic_isa_alloc_resources(device_t dev)
8758789Snyan{
8858789Snyan	struct aic_isa_softc *sc = device_get_softc(dev);
8958789Snyan	int rid;
9058789Snyan	bus_addr_t *bs_iat;
9158789Snyan
9258789Snyan	if ((isa_get_logicalid(dev) == 0xa180a3b8) ||
9358789Snyan	    (AIC_TYPE98(device_get_flags(dev)) == AIC98_NEC100))
9458789Snyan		bs_iat = aicport_100;
9558789Snyan	else
9658789Snyan		bs_iat = aicport_generic;
9758789Snyan
98241591Sjhb	sc->sc_port = sc->sc_irq = sc->sc_drq = NULL;
9958789Snyan
10058789Snyan	rid = 0;
10158789Snyan	sc->sc_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
10258789Snyan					  bs_iat, AIC_ISA_PORTSIZE, RF_ACTIVE);
10375054Snyan	if (!sc->sc_port) {
10475054Snyan		device_printf(dev, "I/O port allocation failed\n");
10558789Snyan		return (ENOMEM);
10675054Snyan	}
10758789Snyan	isa_load_resourcev(sc->sc_port, bs_iat, AIC_ISA_PORTSIZE);
108241591Sjhb	mtx_init(&sc->sc_aic.lock, "aic", NULL, MTX_DEF);
10958789Snyan
11058789Snyan	if (isa_get_irq(dev) != -1) {
11158789Snyan		rid = 0;
112127135Snjl		sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
113127135Snjl						    RF_ACTIVE);
11458789Snyan		if (!sc->sc_irq) {
11575054Snyan			device_printf(dev, "IRQ allocation failed\n");
11658789Snyan			aic_isa_release_resources(dev);
11758789Snyan			return (ENOMEM);
11858789Snyan		}
11958789Snyan	}
12058789Snyan
12158789Snyan	if (isa_get_drq(dev) != -1) {
12258789Snyan		rid = 0;
123127135Snjl		sc->sc_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid,
124127135Snjl						    RF_ACTIVE);
12558789Snyan		if (!sc->sc_drq) {
12675054Snyan			device_printf(dev, "DRQ allocation failed\n");
12758789Snyan			aic_isa_release_resources(dev);
12858789Snyan			return (ENOMEM);
12958789Snyan		}
13058789Snyan	}
13158789Snyan
132170872Sscottl	sc->sc_aic.dev = dev;
133241591Sjhb	sc->sc_aic.res = sc->sc_port;
13458789Snyan	return (0);
13558789Snyan}
13658789Snyan
13758789Snyanstatic void
13858789Snyanaic_isa_release_resources(device_t dev)
13958789Snyan{
14058789Snyan	struct aic_isa_softc *sc = device_get_softc(dev);
14158789Snyan
14258789Snyan	if (sc->sc_port)
14358789Snyan		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port);
14458789Snyan	if (sc->sc_irq)
14558789Snyan		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
14658789Snyan	if (sc->sc_drq)
14758789Snyan		bus_release_resource(dev, SYS_RES_DRQ, 0, sc->sc_drq);
148241591Sjhb	sc->sc_port = sc->sc_irq = sc->sc_drq = NULL;
149241591Sjhb	mtx_destroy(&sc->sc_aic.lock);
15058789Snyan}
15158789Snyan
15258789Snyanstatic int
15358789Snyanaic_isa_probe(device_t dev)
15458789Snyan{
15558789Snyan	struct aic_isa_softc *sc = device_get_softc(dev);
15658789Snyan	struct aic_softc *aic = &sc->sc_aic;
15758789Snyan	int numports, i;
15858789Snyan	u_int port, *ports;
15958789Snyan	u_int8_t porta;
16058789Snyan
16158789Snyan	if (ISA_PNP_PROBE(device_get_parent(dev), dev, aic_ids) == ENXIO)
16258789Snyan		return (ENXIO);
16358789Snyan
16458789Snyan	port = isa_get_port(dev);
16558789Snyan	if (port != -1) {
16658789Snyan		ports = &port;
16758789Snyan		numports = 1;
16858789Snyan	} else {
16958789Snyan		ports = aic_isa_ports;
17058789Snyan		numports = AIC_ISA_NUMPORTS;
17158789Snyan	}
17258789Snyan
17358789Snyan	for (i = 0; i < numports; i++) {
17458789Snyan		if (bus_set_resource(dev, SYS_RES_IOPORT, 0, ports[i], 1))
17558789Snyan			continue;
17658789Snyan		if (aic_isa_alloc_resources(dev))
17758789Snyan			continue;
178241591Sjhb		if (aic_probe(aic) == 0)
17958789Snyan			break;
18058789Snyan		aic_isa_release_resources(dev);
18158789Snyan	}
18258789Snyan
18358789Snyan	if (i == numports)
18458789Snyan		return (ENXIO);
18558789Snyan
18658789Snyan	porta = aic_inb(aic, PORTA);
187241591Sjhb	aic_isa_release_resources(dev);
18858789Snyan	if (isa_get_irq(dev) == -1)
18958789Snyan		bus_set_resource(dev, SYS_RES_IRQ, 0, PORTA_IRQ(porta), 1);
19058789Snyan	if ((aic->flags & AIC_DMA_ENABLE) && isa_get_drq(dev) == -1)
19158789Snyan		bus_set_resource(dev, SYS_RES_DRQ, 0, PORTA_DRQ(porta), 1);
19258789Snyan	device_set_desc(dev, "Adaptec 6260/6360 SCSI controller");
19358789Snyan	return (0);
19458789Snyan}
19558789Snyan
19658789Snyanstatic int
19758789Snyanaic_isa_attach(device_t dev)
19858789Snyan{
19958789Snyan	struct aic_isa_softc *sc = device_get_softc(dev);
20058789Snyan	struct aic_softc *aic = &sc->sc_aic;
20158789Snyan	int error;
20258789Snyan
20358789Snyan	error = aic_isa_alloc_resources(dev);
20458789Snyan	if (error) {
20558789Snyan		device_printf(dev, "resource allocation failed\n");
20658789Snyan		return (error);
20758789Snyan	}
20858789Snyan
20958789Snyan	error = aic_attach(aic);
21058789Snyan	if (error) {
21158789Snyan		device_printf(dev, "attach failed\n");
21258789Snyan		aic_isa_release_resources(dev);
21358789Snyan		return (error);
21458789Snyan	}
21558789Snyan
216241591Sjhb	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM | INTR_ENTROPY |
217241591Sjhb	    INTR_MPSAFE, NULL, aic_intr, aic, &sc->sc_ih);
21858789Snyan	if (error) {
21958789Snyan		device_printf(dev, "failed to register interrupt handler\n");
22058789Snyan		aic_isa_release_resources(dev);
22158789Snyan		return (error);
22258789Snyan	}
22358789Snyan	return (0);
22458789Snyan}
22558789Snyan
22658789Snyanstatic int
22758789Snyanaic_isa_detach(device_t dev)
22858789Snyan{
22958789Snyan	struct aic_isa_softc *sc = device_get_softc(dev);
23058789Snyan	struct aic_softc *aic = &sc->sc_aic;
23158789Snyan	int error;
23258789Snyan
23358789Snyan	error = aic_detach(aic);
23458789Snyan	if (error) {
23558789Snyan		device_printf(dev, "detach failed\n");
23658789Snyan		return (error);
23758789Snyan	}
23858789Snyan
23958789Snyan	error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
24058789Snyan	if (error) {
24158789Snyan		device_printf(dev, "failed to unregister interrupt handler\n");
24258789Snyan	}
24358789Snyan
24458789Snyan	aic_isa_release_resources(dev);
24558789Snyan	return (0);
24658789Snyan}
24758789Snyan
24858789Snyanstatic device_method_t aic_isa_methods[] = {
24958789Snyan	/* Device interface */
25058789Snyan	DEVMETHOD(device_probe,		aic_isa_probe),
25158789Snyan	DEVMETHOD(device_attach,	aic_isa_attach),
25258789Snyan	DEVMETHOD(device_detach,	aic_isa_detach),
25358789Snyan	{ 0, 0 }
25458789Snyan};
25558789Snyan
25658789Snyanstatic driver_t aic_isa_driver = {
25758789Snyan	"aic",
25858789Snyan	aic_isa_methods, sizeof(struct aic_isa_softc),
25958789Snyan};
26058789Snyan
26158789Snyanextern devclass_t aic_devclass;
26258789Snyan
26369960SimpMODULE_DEPEND(aic, cam, 1,1,1);
26458789SnyanDRIVER_MODULE(aic, isa, aic_isa_driver, aic_devclass, 0, 0);
265