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