1151497Sru/* 275584Sru * Product specific probe and attach routines for: 3151497Sru * Adaptec 154x. 4151497Sru */ 575584Sru/*- 675584Sru * Copyright (c) 1999-2003 M. Warner Losh 775584Sru * All rights reserved. 875584Sru * 975584Sru * Redistribution and use in source and binary forms, with or without 1075584Sru * modification, are permitted provided that the following conditions 1175584Sru * are met: 1275584Sru * 1. Redistributions of source code must retain the above copyright 1375584Sru * notice, this list of conditions, and the following disclaimer, 1475584Sru * without modification, immediately at the beginning of the file. 1575584Sru * 2. The name of the author may not be used to endorse or promote products 1675584Sru * derived from this software without specific prior written permission. 1775584Sru * 1875584Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1975584Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2075584Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21151497Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2275584Sru * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28151497Sru * SUCH DAMAGE. 29151497Sru * 30151497Sru * Derived from bt isa from end, written by: 31151497Sru * 32151497Sru * Copyright (c) 1998 Justin T. Gibbs 33151497Sru * All rights reserved. 34151497Sru * 35151497Sru * Redistribution and use in source and binary forms, with or without 36151497Sru * modification, are permitted provided that the following conditions 37151497Sru * are met: 38151497Sru * 1. Redistributions of source code must retain the above copyright 39151497Sru * notice, this list of conditions, and the following disclaimer, 40151497Sru * without modification, immediately at the beginning of the file. 41151497Sru * 2. The name of the author may not be used to endorse or promote products 42151497Sru * derived from this software without specific prior written permission. 43151497Sru * 44151497Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47151497Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 48151497Sru * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54151497Sru * SUCH DAMAGE. 55151497Sru */ 56151497Sru 57151497Sru#include <sys/cdefs.h> 58151497Sru__FBSDID("$FreeBSD$"); 59151497Sru 60151497Sru#include <sys/param.h> 61151497Sru#include <sys/systm.h> 62151497Sru#include <sys/kernel.h> 63151497Sru#include <sys/lock.h> 64151497Sru#include <sys/mutex.h> 65151497Sru 66151497Sru#include <machine/bus.h> 67151497Sru#include <machine/resource.h> 68151497Sru#include <sys/module.h> 69151497Sru#include <sys/bus.h> 70151497Sru#include <sys/rman.h> 71151497Sru 72151497Sru#include <isa/isavar.h> 73151497Sru 74151497Sru#include <dev/aha/ahareg.h> 75151497Sru 76151497Sru#include <cam/scsi/scsi_all.h> 77151497Sru 78151497Srustatic struct isa_pnp_id aha_ids[] = { 79151497Sru {ADP0100_PNP, "Adaptec 1540/1542 ISA SCSI"}, /* ADP0100 */ 80151497Sru {AHA1540_PNP, "Adaptec 1540/aha-1640/aha-1535"},/* ADP1540 */ 81151497Sru {AHA1542_PNP, "Adaptec 1542/aha-1535"}, /* ADP1542 */ 82151497Sru {AHA1542_PNPCOMPAT, "Adaptec 1542 compatible"}, /* PNP00A0 */ 83151497Sru {ICU0091_PNP, "Adaptec AHA-1540/1542 SCSI"}, /* ICU0091 */ 84151497Sru {0} 85151497Sru}; 86151497Sru 87151497Sru/* 88151497Sru * I/O ports listed in the order enumerated by the card for certain op codes. 89151497Sru */ 90151497Srustatic bus_addr_t aha_board_ports[] = 91151497Sru{ 92151497Sru 0x330, 93151497Sru 0x334, 94151497Sru 0x230, 95151497Sru 0x234, 96151497Sru 0x130, 97151497Sru 0x134 98151497Sru}; 99151497Sru 100151497Sru/* 101151497Sru * Check if the device can be found at the port given 102151497Sru */ 103151497Srustatic int 104151497Sruaha_isa_probe(device_t dev) 105151497Sru{ 106151497Sru /* 107151497Sru * find unit and check we have that many defined 108151497Sru */ 109151497Sru struct aha_softc *aha = device_get_softc(dev); 110151497Sru int error; 111151497Sru u_long port_start; 112151497Sru int port_rid; 113151497Sru int drq; 114151497Sru int irq; 115151497Sru config_data_t config_data; 116151497Sru 117151497Sru aha->dev = dev; 118151497Sru /* Check isapnp ids */ 119151497Sru if (ISA_PNP_PROBE(device_get_parent(dev), dev, aha_ids) == ENXIO) 120151497Sru return (ENXIO); 121151497Sru 122151497Sru port_rid = 0; 123151497Sru aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 124151497Sru 0ul, ~0ul, AHA_NREGS, RF_ACTIVE); 125151497Sru 126151497Sru if (aha->port == NULL) 127151497Sru return (ENXIO); 128151497Sru 129151497Sru port_start = rman_get_start(aha->port); 130151497Sru aha_alloc(aha); 131151497Sru 132151497Sru /* See if there is really a card present */ 133151497Sru if (aha_probe(aha) || aha_fetch_adapter_info(aha)) { 134151497Sru aha_free(aha); 135151497Sru bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port); 136151497Sru return (ENXIO); 137151497Sru } 138151497Sru 139151497Sru /* 140151497Sru * Determine our IRQ, and DMA settings and 141151497Sru * export them to the configuration system. 142151497Sru */ 143151497Sru error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 144151497Sru (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 145151497Sru 146151497Sru if (error != 0) { 147151497Sru device_printf(dev, "Could not determine IRQ or DMA " 148151497Sru "settings for adapter at %#jx. Failing probe\n", 149151497Sru (uintmax_t)port_start); 150151497Sru aha_free(aha); 151151497Sru bus_release_resource(dev, SYS_RES_IOPORT, port_rid, 152151497Sru aha->port); 153151497Sru return (ENXIO); 154151497Sru } 155151497Sru 156151497Sru bus_release_resource(dev, SYS_RES_IOPORT, port_rid, aha->port); 157151497Sru aha->port = NULL; 158151497Sru 159151497Sru switch (config_data.dma_chan) { 160151497Sru case DMA_CHAN_5: 161151497Sru drq = 5; 162151497Sru break; 163151497Sru case DMA_CHAN_6: 164151497Sru drq = 6; 165151497Sru break; 166151497Sru case DMA_CHAN_7: 167151497Sru drq = 7; 168151497Sru break; 169151497Sru default: 170151497Sru device_printf(dev, "Invalid DMA setting for adapter at %#jx.", 171151497Sru (uintmax_t)port_start); 172151497Sru return (ENXIO); 173151497Sru } 174151497Sru error = bus_set_resource(dev, SYS_RES_DRQ, 0, drq, 1); 175151497Sru if (error) 176151497Sru return error; 177151497Sru 178151497Sru irq = ffs(config_data.irq) + 8; 179151497Sru error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 180151497Sru return (error); 181151497Sru} 182151497Sru 183151497Sru/* 184151497Sru * Attach all the sub-devices we can find 185151497Sru */ 186151497Srustatic int 187151497Sruaha_isa_attach(device_t dev) 188151497Sru{ 189151497Sru struct aha_softc *aha = device_get_softc(dev); 190151497Sru int error = ENOMEM; 191151497Sru 192151497Sru aha->dev = dev; 193151497Sru aha->portrid = 0; 194151497Sru aha->port = bus_alloc_resource(dev, SYS_RES_IOPORT, &aha->portrid, 195151497Sru 0ul, ~0ul, AHA_NREGS, RF_ACTIVE); 196151497Sru if (!aha->port) { 197151497Sru device_printf(dev, "Unable to allocate I/O ports\n"); 198151497Sru goto fail; 199151497Sru } 200151497Sru 201151497Sru aha->irqrid = 0; 202151497Sru aha->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &aha->irqrid, 203151497Sru RF_ACTIVE); 204151497Sru if (!aha->irq) { 205151497Sru device_printf(dev, "Unable to allocate excluse use of irq\n"); 206151497Sru goto fail; 207151497Sru } 208151497Sru 209151497Sru aha->drqrid = 0; 210151497Sru aha->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &aha->drqrid, 211151497Sru RF_ACTIVE); 212151497Sru if (!aha->drq) { 213151497Sru device_printf(dev, "Unable to allocate drq\n"); 214151497Sru goto fail; 215151497Sru } 216151497Sru 217151497Sru#if 0 /* is the drq ever unset? */ 218151497Sru if (dev->id_drq != -1) 219151497Sru isa_dmacascade(dev->id_drq); 220151497Sru#endif 221151497Sru isa_dmacascade(rman_get_start(aha->drq)); 222151497Sru 223151497Sru /* Allocate our parent dmatag */ 224151497Sru if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(dev), 225151497Sru /* alignemnt */ 1, 226151497Sru /* boundary */ 0, 227151497Sru /* lowaddr */ BUS_SPACE_MAXADDR_24BIT, 228151497Sru /* highaddr */ BUS_SPACE_MAXADDR, 229151497Sru /* filter */ NULL, 230151497Sru /* filterarg */ NULL, 231151497Sru /* maxsize */ BUS_SPACE_MAXSIZE_24BIT, 232151497Sru /* nsegments */ ~0, 233151497Sru /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 234151497Sru /* flags */ 0, 235151497Sru /* lockfunc */ NULL, 236151497Sru /* lockarg */ NULL, 237151497Sru &aha->parent_dmat) != 0) { 238151497Sru device_printf(dev, "dma tag create failed.\n"); 239151497Sru goto fail; 240151497Sru } 241151497Sru 242151497Sru if (aha_init(aha)) { 243151497Sru device_printf(dev, "init failed\n"); 244151497Sru goto fail; 245151497Sru } 246151497Sru /* 247151497Sru * The 1542A and B look the same. So we guess based on 248151497Sru * the firmware revision. It appears that only rev 0 is on 249151497Sru * the A cards. 250151497Sru */ 251151497Sru if (aha->boardid <= BOARD_1542 && aha->fw_major == 0) { 252151497Sru device_printf(dev, "154xA may not work\n"); 253151497Sru aha->ccb_sg_opcode = INITIATOR_SG_CCB; 254151497Sru aha->ccb_ccb_opcode = INITIATOR_CCB; 255151497Sru } 256151497Sru 257151497Sru error = aha_attach(aha); 258151497Sru if (error) { 259151497Sru device_printf(dev, "attach failed\n"); 260151497Sru goto fail; 261151497Sru } 262151497Sru 263151497Sru error = bus_setup_intr(dev, aha->irq, INTR_TYPE_CAM|INTR_ENTROPY| 264151497Sru INTR_MPSAFE, NULL, aha_intr, aha, &aha->ih); 265151497Sru if (error) { 266151497Sru device_printf(dev, "Unable to register interrupt handler\n"); 267151497Sru aha_detach(aha); 268151497Sru goto fail; 269151497Sru } 270151497Sru 271151497Sru return (0); 272151497Srufail: ; 273151497Sru aha_free(aha); 274151497Sru bus_free_resource(dev, SYS_RES_IOPORT, aha->port); 275151497Sru bus_free_resource(dev, SYS_RES_IRQ, aha->irq); 276151497Sru bus_free_resource(dev, SYS_RES_DRQ, aha->drq); 277151497Sru return (error); 278151497Sru} 279151497Sru 280151497Srustatic int 281151497Sruaha_isa_detach(device_t dev) 282151497Sru{ 283151497Sru struct aha_softc *aha = (struct aha_softc *)device_get_softc(dev); 284151497Sru int error; 285151497Sru 286151497Sru error = bus_teardown_intr(dev, aha->irq, aha->ih); 287151497Sru if (error) 288151497Sru device_printf(dev, "failed to unregister interrupt handler\n"); 289151497Sru 290151497Sru error = aha_detach(aha); 291151497Sru if (error) { 292151497Sru device_printf(dev, "detach failed\n"); 293151497Sru return (error); 294151497Sru } 295151497Sru aha_free(aha); 296151497Sru bus_free_resource(dev, SYS_RES_IOPORT, aha->port); 297151497Sru bus_free_resource(dev, SYS_RES_IRQ, aha->irq); 298151497Sru bus_free_resource(dev, SYS_RES_DRQ, aha->drq); 299151497Sru 300151497Sru return (0); 301151497Sru} 302151497Sru 303151497Srustatic void 304151497Sruaha_isa_identify(driver_t *driver, device_t parent) 305151497Sru{ 306151497Sru int i; 307151497Sru bus_addr_t ioport; 308151497Sru struct aha_softc aha; 309151497Sru int rid; 310151497Sru device_t child; 311151497Sru 312151497Sru /* Attempt to find an adapter */ 313151497Sru for (i = 0; i < sizeof(aha_board_ports) / sizeof(aha_board_ports[0]); 314151497Sru i++) { 315151497Sru bzero(&aha, sizeof(aha)); 316151497Sru ioport = aha_board_ports[i]; 317151497Sru /* 318151497Sru * XXX Check to see if we have a hard-wired aha device at 319151497Sru * XXX this port, if so, skip. This should also cover the 320151497Sru * XXX case where we are run multiple times due to, eg, 321151497Sru * XXX kldload/kldunload. 322151497Sru */ 323151497Sru rid = 0; 324151497Sru aha.port = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid, 325151497Sru ioport, ioport, AHA_NREGS, RF_ACTIVE); 326151497Sru if (aha.port == NULL) 327151497Sru continue; 328151497Sru aha_alloc(&aha); 329151497Sru /* See if there is really a card present */ 330151497Sru if (aha_probe(&aha) || aha_fetch_adapter_info(&aha)) 331151497Sru goto not_this_one; 332151497Sru child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "aha", -1); 333151497Sru bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, AHA_NREGS); 334151497Sru /* 335151497Sru * Could query the board and set IRQ/DRQ, but probe does 336151497Sru * that. 337151497Sru */ 338151497Sru not_this_one: 339151497Sru bus_release_resource(parent, SYS_RES_IOPORT, rid, aha.port); 340151497Sru aha_free(&aha); 341151497Sru } 342151497Sru} 343151497Sru 344151497Srustatic device_method_t aha_isa_methods[] = { 345151497Sru /* Device interface */ 346151497Sru DEVMETHOD(device_probe, aha_isa_probe), 347151497Sru DEVMETHOD(device_attach, aha_isa_attach), 348151497Sru DEVMETHOD(device_detach, aha_isa_detach), 349151497Sru DEVMETHOD(device_identify, aha_isa_identify), 350151497Sru 351151497Sru { 0, 0 } 352151497Sru}; 353151497Sru 354151497Srustatic driver_t aha_isa_driver = { 355151497Sru "aha", 356151497Sru aha_isa_methods, 357151497Sru sizeof(struct aha_softc), 358151497Sru}; 359151497Sru 360151497Srustatic devclass_t aha_devclass; 361151497Sru 362151497SruDRIVER_MODULE(aha, isa, aha_isa_driver, aha_devclass, 0, 0); 363151497SruMODULE_DEPEND(aha, isa, 1, 1, 1); 364151497Sru