1140039Simp/* 239225Sgibbs * Product specific probe and attach routines for: 339225Sgibbs * Adaptec 154x. 4140039Simp */ 5140039Simp/*- 6122362Simp * Copyright (c) 1999-2003 M. Warner Losh 7122362Simp * All rights reserved. 839225Sgibbs * 9122362Simp * Redistribution and use in source and binary forms, with or without 10122362Simp * modification, are permitted provided that the following conditions 11122362Simp * are met: 12122362Simp * 1. Redistributions of source code must retain the above copyright 13122362Simp * notice, this list of conditions, and the following disclaimer, 14122362Simp * without modification, immediately at the beginning of the file. 15122362Simp * 2. The name of the author may not be used to endorse or promote products 16122362Simp * derived from this software without specific prior written permission. 17122362Simp * 18122362Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19122362Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20122362Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21122362Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 22122362Simp * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23122362Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24122362Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25122362Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26122362Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27122362Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28122362Simp * SUCH DAMAGE. 29122362Simp * 30122362Simp * Derived from bt isa from end, written by: 31122362Simp * 3239225Sgibbs * Copyright (c) 1998 Justin T. Gibbs 3339225Sgibbs * All rights reserved. 3439225Sgibbs * 3539225Sgibbs * Redistribution and use in source and binary forms, with or without 3639225Sgibbs * modification, are permitted provided that the following conditions 3739225Sgibbs * are met: 3839225Sgibbs * 1. Redistributions of source code must retain the above copyright 3939225Sgibbs * notice, this list of conditions, and the following disclaimer, 4039225Sgibbs * without modification, immediately at the beginning of the file. 4139225Sgibbs * 2. The name of the author may not be used to endorse or promote products 4239225Sgibbs * derived from this software without specific prior written permission. 4339225Sgibbs * 4439225Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4539225Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4639225Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4739225Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 4839225Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4939225Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5039225Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5139225Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5239225Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5339225Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5439225Sgibbs * SUCH DAMAGE. 5539225Sgibbs */ 5639225Sgibbs 57119418Sobrien#include <sys/cdefs.h> 58119418Sobrien__FBSDID("$FreeBSD$"); 59119418Sobrien 6039225Sgibbs#include <sys/param.h> 6139225Sgibbs#include <sys/systm.h> 6242887Simp#include <sys/kernel.h> 63117126Sscottl#include <sys/lock.h> 64117126Sscottl#include <sys/mutex.h> 6539225Sgibbs 6639225Sgibbs#include <machine/bus.h> 6751738Simp#include <machine/resource.h> 6851738Simp#include <sys/module.h> 6951738Simp#include <sys/bus.h> 7051738Simp#include <sys/rman.h> 7139225Sgibbs 7251738Simp#include <isa/isavar.h> 7351738Simp 7439225Sgibbs#include <dev/aha/ahareg.h> 7539225Sgibbs 7639225Sgibbs#include <cam/scsi/scsi_all.h> 7739225Sgibbs 7851738Simpstatic struct isa_pnp_id aha_ids[] = { 7958544Simp {ADP0100_PNP, "Adaptec 1540/1542 ISA SCSI"}, /* ADP0100 */ 80122385Simp {AHA1540_PNP, "Adaptec 1540/aha-1640/aha-1535"},/* ADP1540 */ 8158544Simp {AHA1542_PNP, "Adaptec 1542/aha-1535"}, /* ADP1542 */ 8258544Simp {AHA1542_PNPCOMPAT, "Adaptec 1542 compatible"}, /* PNP00A0 */ 8358544Simp {ICU0091_PNP, "Adaptec AHA-1540/1542 SCSI"}, /* ICU0091 */ 8451738Simp {0} 8539225Sgibbs}; 8639225Sgibbs 8739225Sgibbs/* 88122385Simp * I/O ports listed in the order enumerated by the card for certain op codes. 89122385Simp */ 90122385Simpstatic bus_addr_t aha_board_ports[] = 91122385Simp{ 92122385Simp 0x330, 93122385Simp 0x334, 94122385Simp 0x230, 95122385Simp 0x234, 96122385Simp 0x130, 97122385Simp 0x134 98122385Simp}; 99122385Simp 100122385Simp/* 10139225Sgibbs * Check if the device can be found at the port given 10239225Sgibbs */ 10339225Sgibbsstatic int 10451738Simpaha_isa_probe(device_t dev) 10539225Sgibbs{ 10639225Sgibbs /* 10739225Sgibbs * find unit and check we have that many defined 10839225Sgibbs */ 109122361Simp struct aha_softc *aha = device_get_softc(dev); 11051738Simp int error; 111122385Simp u_long port_start; 11251738Simp int port_rid; 11351738Simp int drq; 11451738Simp int irq; 115122385Simp config_data_t config_data; 11639225Sgibbs 117122597Simp aha->dev = dev; 11851738Simp /* Check isapnp ids */ 11951738Simp if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO) 12051738Simp return (ENXIO); 12151738Simp 122122385Simp port_rid = 0; 123241589Sjhb aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 124241589Sjhb 0ul, ~0ul, AHA_NREGS, RF_ACTIVE); 12551738Simp 126241589Sjhb if (aha->port == NULL) 127122385Simp return (ENXIO); 12839225Sgibbs 129241603Sglebius port_start = rman_get_start(aha->port); 130241589Sjhb aha_alloc(aha); 13141048Sgibbs 132122385Simp /* See if there is really a card present */ 133122385Simp if (aha_probe(aha) || aha_fetch_adapter_info(aha)) { 134122385Simp aha_free(aha); 135241589Sjhb bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port); 136122385Simp return (ENXIO); 137122385Simp } 13839225Sgibbs 139122385Simp /* 140122385Simp * Determine our IRQ, and DMA settings and 141122385Simp * export them to the configuration system. 142122385Simp */ 143122385Simp error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 144122385Simp (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 14539225Sgibbs 146122385Simp if (error != 0) { 147122385Simp device_printf(dev, "Could not determine IRQ or DMA " 148122385Simp "settings for adapter at %#jx. Failing probe\n", 149122385Simp (uintmax_t)port_start); 150122385Simp aha_free(aha); 151137599Simp bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 152241589Sjhb aha->port); 153122385Simp return (ENXIO); 154122385Simp } 15540160Simp 156241589Sjhb bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port); 157241589Sjhb aha->port = NULL; 15839225Sgibbs 159122385Simp switch (config_data.dma_chan) { 160122385Simp case DMA_CHAN_5: 161122385Simp drq = 5; 162122385Simp break; 163122385Simp case DMA_CHAN_6: 164122385Simp drq = 6; 165122385Simp break; 166122385Simp case DMA_CHAN_7: 167122385Simp drq = 7; 168122385Simp break; 169122385Simp default: 170122385Simp device_printf(dev, "Invalid DMA setting for adapter at %#jx.", 171122385Simp (uintmax_t)port_start); 172122385Simp return (ENXIO); 17339225Sgibbs } 174122385Simp error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1); 175122385Simp if (error) 176122385Simp return error; 17739225Sgibbs 178122385Simp irq = ffs(config_data.irq) + 8; 179122385Simp error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 180122385Simp return (error); 18139225Sgibbs} 18239225Sgibbs 18339225Sgibbs/* 18439225Sgibbs * Attach all the sub-devices we can find 18539225Sgibbs */ 18639225Sgibbsstatic int 18751738Simpaha_isa_attach(device_t dev) 18839225Sgibbs{ 189122361Simp struct aha_softc *aha = device_get_softc(dev); 190140467Simp int error = ENOMEM; 19139225Sgibbs 192122597Simp aha->dev = dev; 19356504Simp aha->portrid = 0; 19456504Simp aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid, 195241589Sjhb 0ul, ~0ul, AHA_NREGS, RF_ACTIVE); 19656504Simp if (!aha->port) { 19751738Simp device_printf(dev, "Unable to allocate I/O ports\n"); 198140467Simp goto fail; 19951738Simp } 20051738Simp 20156504Simp aha->irqrid = 0; 202127135Snjl aha->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &aha->irqrid, 20351738Simp RF_ACTIVE); 20456504Simp if (!aha->irq) { 20551738Simp device_printf(dev, "Unable to allocate excluse use of irq\n"); 206140467Simp goto fail; 20751738Simp } 20851738Simp 20956504Simp aha->drqrid = 0; 210127135Snjl aha->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &aha->drqrid, 21151738Simp RF_ACTIVE); 21256504Simp if (!aha->drq) { 21351738Simp device_printf(dev, "Unable to allocate drq\n"); 214140467Simp goto fail; 21551738Simp } 21651738Simp 21751738Simp#if 0 /* is the drq ever unset? */ 21839225Sgibbs if (dev->id_drq != -1) 21939225Sgibbs isa_dmacascade(dev->id_drq); 22051738Simp#endif 22156504Simp isa_dmacascade(rman_get_start(aha->drq)); 22239225Sgibbs 22339225Sgibbs /* Allocate our parent dmatag */ 224183678Simp if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(dev), 225112782Smdodd /* alignemnt */ 1, 226112782Smdodd /* boundary */ 0, 227241589Sjhb /* lowaddr */ BUS_SPACE_MAXADDR_24BIT, 228112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 229241589Sjhb /* filter */ NULL, 230241589Sjhb /* filterarg */ NULL, 231112782Smdodd /* maxsize */ BUS_SPACE_MAXSIZE_24BIT, 232112782Smdodd /* nsegments */ ~0, 233112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 234112782Smdodd /* flags */ 0, 235241589Sjhb /* lockfunc */ NULL, 236241589Sjhb /* lockarg */ NULL, 237112782Smdodd &aha->parent_dmat) != 0) { 238140467Simp device_printf(dev, "dma tag create failed.\n"); 239140467Simp goto fail; 240140467Simp } 24139225Sgibbs 242137599Simp if (aha_init(aha)) { 24351738Simp device_printf(dev, "init failed\n"); 244140467Simp goto fail; 245140467Simp } 246140025Simp /* 247140025Simp * The 1542A and B look the same. So we guess based on 248140025Simp * the firmware revision. It appears that only rev 0 is on 249140025Simp * the A cards. 250140025Simp */ 251140025Simp if (aha->boardid <= BOARD_1542 && aha->fw_major == 0) { 252140025Simp device_printf(dev, "154xA may not work\n"); 253140025Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB; 254140025Simp aha->ccb_ccb_opcode = INITIATOR_CCB; 255137599Simp } 256140025Simp 25751738Simp error = aha_attach(aha); 25851738Simp if (error) { 25951738Simp device_printf(dev, "attach failed\n"); 260140467Simp goto fail; 26151738Simp } 26239225Sgibbs 263241589Sjhb error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM|INTR_ENTROPY| 264241589Sjhb INTR_MPSAFE, NULL, aha_intr, aha, &aha->ih); 26551738Simp if (error) { 26651738Simp device_printf(dev, "Unable to register interrupt handler\n"); 267241589Sjhb aha_detach(aha); 268140467Simp goto fail; 26942887Simp } 27042887Simp 27151738Simp return (0); 272140467Simpfail: ; 273241589Sjhb aha_free(aha); 274140467Simp bus_free_resource(dev, SYS_RES_IOPORT, aha->port); 275140467Simp bus_free_resource(dev, SYS_RES_IRQ, aha->irq); 276140467Simp bus_free_resource(dev, SYS_RES_DRQ, aha->drq); 277140467Simp return (error); 27842887Simp} 27942887Simp 28056504Simpstatic int 28156504Simpaha_isa_detach(device_t dev) 28256504Simp{ 283122361Simp struct aha_softc *aha = (struct aha_softc *)device_get_softc(dev); 28456504Simp int error; 28556504Simp 28656504Simp error = bus_teardown_intr(dev, aha->irq, aha->ih); 287140467Simp if (error) 28856504Simp device_printf(dev, "failed to unregister interrupt handler\n"); 28956504Simp 29056504Simp error = aha_detach(aha); 29156504Simp if (error) { 29256504Simp device_printf(dev, "detach failed\n"); 29356504Simp return (error); 29456504Simp } 29556504Simp aha_free(aha); 296241589Sjhb bus_free_resource(dev, SYS_RES_IOPORT, aha->port); 297241589Sjhb bus_free_resource(dev, SYS_RES_IRQ, aha->irq); 298241589Sjhb bus_free_resource(dev, SYS_RES_DRQ, aha->drq); 29956504Simp 30056504Simp return (0); 30156504Simp} 30256504Simp 30356504Simpstatic void 30456504Simpaha_isa_identify(driver_t *driver, device_t parent) 30556504Simp{ 306122385Simp int i; 307122385Simp bus_addr_t ioport; 308122385Simp struct aha_softc aha; 309122385Simp int rid; 310122385Simp device_t child; 311122385Simp 312122385Simp /* Attempt to find an adapter */ 313122385Simp for (i = 0; i < sizeof(aha_board_ports) / sizeof(aha_board_ports[0]); 314122385Simp i++) { 315122385Simp bzero(&aha, sizeof(aha)); 316122385Simp ioport = aha_board_ports[i]; 317122385Simp /* 318122385Simp * XXX Check to see if we have a hard-wired aha device at 319122385Simp * XXX this port, if so, skip. This should also cover the 320122385Simp * XXX case where we are run multiple times due to, eg, 321122385Simp * XXX kldload/kldunload. 322122385Simp */ 323122385Simp rid = 0; 324241603Sglebius aha.port = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid, 325122385Simp ioport, ioport, AHA_NREGS, RF_ACTIVE); 326241603Sglebius if (aha.port == NULL) 327122385Simp continue; 328241589Sjhb aha_alloc(&aha); 329122385Simp /* See if there is really a card present */ 330122385Simp if (aha_probe(&aha) || aha_fetch_adapter_info(&aha)) 331122385Simp goto not_this_one; 332122385Simp child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "aha", -1); 333122385Simp bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, AHA_NREGS); 334122385Simp /* 335122385Simp * Could query the board and set IRQ/DRQ, but probe does 336122385Simp * that. 337122385Simp */ 338241603Sglebius not_this_one: 339241603Sglebius bus_release_resource(parent, SYS_RES_IOPORT, rid, aha.port); 340122385Simp aha_free(&aha); 341122385Simp } 34256504Simp} 34356504Simp 34451738Simpstatic device_method_t aha_isa_methods[] = { 34551738Simp /* Device interface */ 34651738Simp DEVMETHOD(device_probe, aha_isa_probe), 34751738Simp DEVMETHOD(device_attach, aha_isa_attach), 34856504Simp DEVMETHOD(device_detach, aha_isa_detach), 34956504Simp DEVMETHOD(device_identify, aha_isa_identify), 35042887Simp 35151738Simp { 0, 0 } 35251738Simp}; 35342887Simp 35451738Simpstatic driver_t aha_isa_driver = { 35551738Simp "aha", 35651738Simp aha_isa_methods, 357122361Simp sizeof(struct aha_softc), 35851738Simp}; 35942887Simp 36051738Simpstatic devclass_t aha_devclass; 36142887Simp 36251738SimpDRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0); 363165102SmjacobMODULE_DEPEND(aha, isa, 1, 1, 1); 364