aha_isa.c revision 140039
1214501Srpaulo/* 2214501Srpaulo * Product specific probe and attach routines for: 3214501Srpaulo * Adaptec 154x. 4214501Srpaulo */ 5252726Srpaulo/*- 6252726Srpaulo * Copyright (c) 1999-2003 M. Warner Losh 7214501Srpaulo * All rights reserved. 8214501Srpaulo * 9214501Srpaulo * Redistribution and use in source and binary forms, with or without 10214501Srpaulo * modification, are permitted provided that the following conditions 11214501Srpaulo * are met: 12214501Srpaulo * 1. Redistributions of source code must retain the above copyright 13214501Srpaulo * notice, this list of conditions, and the following disclaimer, 14214501Srpaulo * without modification, immediately at the beginning of the file. 15252726Srpaulo * 2. The name of the author may not be used to endorse or promote products 16214501Srpaulo * derived from this software without specific prior written permission. 17214501Srpaulo * 18214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 22214501Srpaulo * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28214501Srpaulo * SUCH DAMAGE. 29214501Srpaulo * 30214501Srpaulo * Derived from bt isa from end, written by: 31214501Srpaulo * 32214501Srpaulo * Copyright (c) 1998 Justin T. Gibbs 33214501Srpaulo * All rights reserved. 34214501Srpaulo * 35214501Srpaulo * Redistribution and use in source and binary forms, with or without 36214501Srpaulo * modification, are permitted provided that the following conditions 37214501Srpaulo * are met: 38214501Srpaulo * 1. Redistributions of source code must retain the above copyright 39214501Srpaulo * notice, this list of conditions, and the following disclaimer, 40214501Srpaulo * without modification, immediately at the beginning of the file. 41214501Srpaulo * 2. The name of the author may not be used to endorse or promote products 42214501Srpaulo * derived from this software without specific prior written permission. 43214501Srpaulo * 44214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47214501Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 48214501Srpaulo * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54214501Srpaulo * SUCH DAMAGE. 55214501Srpaulo */ 56214501Srpaulo 57214501Srpaulo#include <sys/cdefs.h> 58214501Srpaulo__FBSDID("$FreeBSD: head/sys/dev/aha/aha_isa.c 140039 2005-01-11 06:22:48Z imp $"); 59214501Srpaulo 60214501Srpaulo#include <sys/param.h> 61214501Srpaulo#include <sys/systm.h> 62214501Srpaulo#include <sys/kernel.h> 63214501Srpaulo#include <sys/lock.h> 64214501Srpaulo#include <sys/mutex.h> 65214501Srpaulo 66214501Srpaulo#include <machine/bus_pio.h> 67214501Srpaulo#include <machine/bus.h> 68214501Srpaulo#include <machine/resource.h> 69214501Srpaulo#include <sys/module.h> 70214501Srpaulo#include <sys/bus.h> 71214501Srpaulo#include <sys/rman.h> 72214501Srpaulo 73214501Srpaulo#include <isa/isavar.h> 74214501Srpaulo 75214501Srpaulo#include <dev/aha/ahareg.h> 76214501Srpaulo 77214501Srpaulo#include <cam/scsi/scsi_all.h> 78214501Srpaulo 79214501Srpaulostatic struct isa_pnp_id aha_ids[] = { 80214501Srpaulo {ADP0100_PNP, "Adaptec 1540/1542 ISA SCSI"}, /* ADP0100 */ 81214501Srpaulo {AHA1540_PNP, "Adaptec 1540/aha-1640/aha-1535"},/* ADP1540 */ 82214501Srpaulo {AHA1542_PNP, "Adaptec 1542/aha-1535"}, /* ADP1542 */ 83214501Srpaulo {AHA1542_PNPCOMPAT, "Adaptec 1542 compatible"}, /* PNP00A0 */ 84214501Srpaulo {ICU0091_PNP, "Adaptec AHA-1540/1542 SCSI"}, /* ICU0091 */ 85214501Srpaulo {0} 86214501Srpaulo}; 87214501Srpaulo 88214501Srpaulo/* 89214501Srpaulo * I/O ports listed in the order enumerated by the card for certain op codes. 90214501Srpaulo */ 91214501Srpaulostatic bus_addr_t aha_board_ports[] = 92214501Srpaulo{ 93214501Srpaulo 0x330, 94214501Srpaulo 0x334, 95214501Srpaulo 0x230, 96214501Srpaulo 0x234, 97214501Srpaulo 0x130, 98214501Srpaulo 0x134 99214501Srpaulo}; 100214501Srpaulo 101214501Srpaulo/* 102214501Srpaulo * Check if the device can be found at the port given 103214501Srpaulo */ 104214501Srpaulostatic int 105214501Srpauloaha_isa_probe(device_t dev) 106214501Srpaulo{ 107214501Srpaulo /* 108214501Srpaulo * find unit and check we have that many defined 109214501Srpaulo */ 110214501Srpaulo struct aha_softc *aha = device_get_softc(dev); 111214501Srpaulo int error; 112214501Srpaulo u_long port_start; 113214501Srpaulo struct resource *port_res; 114214501Srpaulo int port_rid; 115214501Srpaulo int drq; 116214501Srpaulo int irq; 117214501Srpaulo config_data_t config_data; 118214501Srpaulo 119214501Srpaulo aha->dev = dev; 120214501Srpaulo /* Check isapnp ids */ 121214501Srpaulo if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO) 122214501Srpaulo return (ENXIO); 123214501Srpaulo 124214501Srpaulo port_rid = 0; 125214501Srpaulo port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 126214501Srpaulo 0, ~0, AHA_NREGS, RF_ACTIVE); 127214501Srpaulo 128214501Srpaulo if (port_res == NULL) 129214501Srpaulo return (ENXIO); 130214501Srpaulo 131214501Srpaulo port_start = rman_get_start(port_res); 132214501Srpaulo aha_alloc(aha, device_get_unit(dev), rman_get_bustag(port_res), 133214501Srpaulo rman_get_bushandle(port_res)); 134214501Srpaulo 135214501Srpaulo /* See if there is really a card present */ 136214501Srpaulo if (aha_probe(aha) || aha_fetch_adapter_info(aha)) { 137214501Srpaulo aha_free(aha); 138214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res); 139214501Srpaulo return (ENXIO); 140214501Srpaulo } 141214501Srpaulo 142214501Srpaulo /* 143214501Srpaulo * Determine our IRQ, and DMA settings and 144214501Srpaulo * export them to the configuration system. 145214501Srpaulo */ 146214501Srpaulo error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 147214501Srpaulo (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 148214501Srpaulo 149214501Srpaulo if (error != 0) { 150214501Srpaulo device_printf(dev, "Could not determine IRQ or DMA " 151214501Srpaulo "settings for adapter at %#jx. Failing probe\n", 152214501Srpaulo (uintmax_t)port_start); 153214501Srpaulo aha_free(aha); 154214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 155214501Srpaulo port_res); 156214501Srpaulo return (ENXIO); 157214501Srpaulo } 158214501Srpaulo 159214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, port_rid, port_res); 160214501Srpaulo 161214501Srpaulo switch (config_data.dma_chan) { 162214501Srpaulo case DMA_CHAN_5: 163214501Srpaulo drq = 5; 164214501Srpaulo break; 165214501Srpaulo case DMA_CHAN_6: 166214501Srpaulo drq = 6; 167214501Srpaulo break; 168214501Srpaulo case DMA_CHAN_7: 169214501Srpaulo drq = 7; 170214501Srpaulo break; 171214501Srpaulo default: 172214501Srpaulo device_printf(dev, "Invalid DMA setting for adapter at %#jx.", 173214501Srpaulo (uintmax_t)port_start); 174214501Srpaulo return (ENXIO); 175214501Srpaulo } 176214501Srpaulo error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1); 177214501Srpaulo if (error) 178214501Srpaulo return error; 179214501Srpaulo 180214501Srpaulo irq = ffs(config_data.irq) + 8; 181214501Srpaulo error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 182214501Srpaulo return (error); 183214501Srpaulo} 184214501Srpaulo 185214501Srpaulo/* 186214501Srpaulo * Attach all the sub-devices we can find 187214501Srpaulo */ 188214501Srpaulostatic int 189214501Srpauloaha_isa_attach(device_t dev) 190214501Srpaulo{ 191214501Srpaulo struct aha_softc *aha = device_get_softc(dev); 192214501Srpaulo bus_dma_filter_t *filter; 193214501Srpaulo void *filter_arg; 194214501Srpaulo bus_addr_t lowaddr; 195214501Srpaulo void *ih; 196214501Srpaulo int error; 197214501Srpaulo 198214501Srpaulo aha->dev = dev; 199214501Srpaulo aha->portrid = 0; 200214501Srpaulo aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid, 201214501Srpaulo 0, ~0, AHA_NREGS, RF_ACTIVE); 202214501Srpaulo if (!aha->port) { 203214501Srpaulo device_printf(dev, "Unable to allocate I/O ports\n"); 204214501Srpaulo return ENOMEM; 205214501Srpaulo } 206214501Srpaulo 207214501Srpaulo aha->irqrid = 0; 208214501Srpaulo aha->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &aha->irqrid, 209214501Srpaulo RF_ACTIVE); 210214501Srpaulo if (!aha->irq) { 211214501Srpaulo device_printf(dev, "Unable to allocate excluse use of irq\n"); 212214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, 213214501Srpaulo aha->port); 214214501Srpaulo return ENOMEM; 215214501Srpaulo } 216214501Srpaulo 217214501Srpaulo aha->drqrid = 0; 218214501Srpaulo aha->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &aha->drqrid, 219214501Srpaulo RF_ACTIVE); 220214501Srpaulo if (!aha->drq) { 221214501Srpaulo device_printf(dev, "Unable to allocate drq\n"); 222214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, 223214501Srpaulo aha->port); 224214501Srpaulo bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq); 225214501Srpaulo return ENOMEM; 226214501Srpaulo } 227214501Srpaulo 228214501Srpaulo#if 0 /* is the drq ever unset? */ 229214501Srpaulo if (dev->id_drq != -1) 230214501Srpaulo isa_dmacascade(dev->id_drq); 231214501Srpaulo#endif 232214501Srpaulo isa_dmacascade(rman_get_start(aha->drq)); 233214501Srpaulo 234214501Srpaulo /* Allocate our parent dmatag */ 235214501Srpaulo filter = NULL; 236214501Srpaulo filter_arg = NULL; 237214501Srpaulo lowaddr = BUS_SPACE_MAXADDR_24BIT; 238214501Srpaulo 239214501Srpaulo if (bus_dma_tag_create( /* parent */ NULL, 240214501Srpaulo /* alignemnt */ 1, 241214501Srpaulo /* boundary */ 0, 242214501Srpaulo /* lowaddr */ lowaddr, 243214501Srpaulo /* highaddr */ BUS_SPACE_MAXADDR, 244214501Srpaulo /* filter */ filter, 245214501Srpaulo /* filterarg */ filter_arg, 246214501Srpaulo /* maxsize */ BUS_SPACE_MAXSIZE_24BIT, 247214501Srpaulo /* nsegments */ ~0, 248214501Srpaulo /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 249214501Srpaulo /* flags */ 0, 250214501Srpaulo /* lockfunc */ busdma_lock_mutex, 251214501Srpaulo /* lockarg */ &Giant, 252214501Srpaulo &aha->parent_dmat) != 0) { 253214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, 254214501Srpaulo aha->port); 255214501Srpaulo bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq); 256214501Srpaulo bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq); 257214501Srpaulo aha_free(aha); 258214501Srpaulo return (ENOMEM); 259214501Srpaulo } 260214501Srpaulo 261214501Srpaulo if (aha_init(aha)) { 262214501Srpaulo device_printf(dev, "init failed\n"); 263214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, 264214501Srpaulo aha->port); 265214501Srpaulo bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq); 266214501Srpaulo bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq); 267214501Srpaulo aha_free(aha); 268214501Srpaulo return (ENOMEM); 269214501Srpaulo } 270214501Srpaulo /* 271214501Srpaulo * The 1542A and B look the same. So we guess based on 272214501Srpaulo * the firmware revision. It appears that only rev 0 is on 273214501Srpaulo * the A cards. 274214501Srpaulo */ 275214501Srpaulo if (aha->boardid <= BOARD_1542 && aha->fw_major == 0) { 276214501Srpaulo device_printf(dev, "154xA may not work\n"); 277214501Srpaulo aha->ccb_sg_opcode = INITIATOR_SG_CCB; 278214501Srpaulo aha->ccb_ccb_opcode = INITIATOR_CCB; 279214501Srpaulo } 280214501Srpaulo 281214501Srpaulo error = aha_attach(aha); 282214501Srpaulo if (error) { 283214501Srpaulo device_printf(dev, "attach failed\n"); 284214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, 285214501Srpaulo aha->port); 286214501Srpaulo bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq); 287214501Srpaulo bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq); 288214501Srpaulo aha_free(aha); 289214501Srpaulo return (error); 290214501Srpaulo } 291214501Srpaulo 292214501Srpaulo error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM|INTR_ENTROPY, 293214501Srpaulo aha_intr, aha, &ih); 294214501Srpaulo if (error) { 295214501Srpaulo device_printf(dev, "Unable to register interrupt handler\n"); 296214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, 297214501Srpaulo aha->port); 298214501Srpaulo bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq); 299214501Srpaulo bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq); 300214501Srpaulo aha_free(aha); 301214501Srpaulo return (error); 302214501Srpaulo } 303214501Srpaulo 304214501Srpaulo return (0); 305214501Srpaulo} 306214501Srpaulo 307214501Srpaulostatic int 308214501Srpauloaha_isa_detach(device_t dev) 309214501Srpaulo{ 310214501Srpaulo struct aha_softc *aha = (struct aha_softc *)device_get_softc(dev); 311214501Srpaulo int error; 312214501Srpaulo 313214501Srpaulo error = bus_teardown_intr(dev, aha->irq, aha->ih); 314214501Srpaulo if (error) { 315214501Srpaulo device_printf(dev, "failed to unregister interrupt handler\n"); 316214501Srpaulo } 317214501Srpaulo 318214501Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, aha->portrid, aha->port); 319214501Srpaulo bus_release_resource(dev, SYS_RES_IRQ, aha->irqrid, aha->irq); 320214501Srpaulo bus_release_resource(dev, SYS_RES_DRQ, aha->drqrid, aha->drq); 321214501Srpaulo 322214501Srpaulo error = aha_detach(aha); 323214501Srpaulo if (error) { 324214501Srpaulo device_printf(dev, "detach failed\n"); 325214501Srpaulo return (error); 326214501Srpaulo } 327214501Srpaulo aha_free(aha); 328214501Srpaulo 329214501Srpaulo return (0); 330214501Srpaulo} 331214501Srpaulo 332214501Srpaulostatic void 333214501Srpauloaha_isa_identify(driver_t *driver, device_t parent) 334214501Srpaulo{ 335214501Srpaulo int i; 336214501Srpaulo bus_addr_t ioport; 337214501Srpaulo struct aha_softc aha; 338214501Srpaulo int rid; 339214501Srpaulo struct resource *res; 340214501Srpaulo device_t child; 341214501Srpaulo 342214501Srpaulo /* Attempt to find an adapter */ 343214501Srpaulo for (i = 0; i < sizeof(aha_board_ports) / sizeof(aha_board_ports[0]); 344214501Srpaulo i++) { 345214501Srpaulo bzero(&aha, sizeof(aha)); 346214501Srpaulo ioport = aha_board_ports[i]; 347214501Srpaulo /* 348214501Srpaulo * XXX Check to see if we have a hard-wired aha device at 349214501Srpaulo * XXX this port, if so, skip. This should also cover the 350214501Srpaulo * XXX case where we are run multiple times due to, eg, 351214501Srpaulo * XXX kldload/kldunload. 352214501Srpaulo */ 353214501Srpaulo rid = 0; 354214501Srpaulo res = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid, 355214501Srpaulo ioport, ioport, AHA_NREGS, RF_ACTIVE); 356214501Srpaulo if (res == NULL) 357214501Srpaulo continue; 358214501Srpaulo aha_alloc(&aha, -1, rman_get_bustag(res), 359214501Srpaulo rman_get_bushandle(res)); 360214501Srpaulo /* See if there is really a card present */ 361214501Srpaulo if (aha_probe(&aha) || aha_fetch_adapter_info(&aha)) 362214501Srpaulo goto not_this_one; 363214501Srpaulo child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "aha", -1); 364214501Srpaulo bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, AHA_NREGS); 365214501Srpaulo /* 366214501Srpaulo * Could query the board and set IRQ/DRQ, but probe does 367214501Srpaulo * that. 368214501Srpaulo */ 369214501Srpaulo not_this_one:; 370214501Srpaulo bus_release_resource(parent, SYS_RES_IOPORT, rid, res); 371214501Srpaulo aha_free(&aha); 372214501Srpaulo } 373214501Srpaulo} 374214501Srpaulo 375214501Srpaulostatic device_method_t aha_isa_methods[] = { 376214501Srpaulo /* Device interface */ 377214501Srpaulo DEVMETHOD(device_probe, aha_isa_probe), 378214501Srpaulo DEVMETHOD(device_attach, aha_isa_attach), 379214501Srpaulo DEVMETHOD(device_detach, aha_isa_detach), 380214501Srpaulo DEVMETHOD(device_identify, aha_isa_identify), 381214501Srpaulo 382214501Srpaulo { 0, 0 } 383214501Srpaulo}; 384214501Srpaulo 385214501Srpaulostatic driver_t aha_isa_driver = { 386214501Srpaulo "aha", 387214501Srpaulo aha_isa_methods, 388214501Srpaulo sizeof(struct aha_softc), 389214501Srpaulo}; 390214501Srpaulo 391214501Srpaulostatic devclass_t aha_devclass; 392214501Srpaulo 393214501SrpauloDRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0); 394214501Srpaulo