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