adv_eisa.c revision 112782
1252190Srpaulo/* 2252190Srpaulo * Device probe and attach routines for the following 3252190Srpaulo * Advanced Systems Inc. SCSI controllers: 4252190Srpaulo * 5252190Srpaulo * Single Channel Products: 6252190Srpaulo * ABP742 - Bus-Master EISA (240 CDB) 7252190Srpaulo * 8252190Srpaulo * Dual Channel Products: 9252190Srpaulo * ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) 10252190Srpaulo * 11252190Srpaulo * Copyright (c) 1997 Justin Gibbs. 12252190Srpaulo * All rights reserved. 13252190Srpaulo * 14252190Srpaulo * Redistribution and use in source and binary forms, with or without 15252190Srpaulo * modification, are permitted provided that the following conditions 16252190Srpaulo * are met: 17252190Srpaulo * 1. Redistributions of source code must retain the above copyright 18252190Srpaulo * notice, this list of conditions, and the following disclaimer, 19252190Srpaulo * without modification, immediately at the beginning of the file. 20252190Srpaulo * 2. The name of the author may not be used to endorse or promote products 21252190Srpaulo * derived from this software without specific prior written permission. 22252190Srpaulo * 23252190Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24252190Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25252190Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26252190Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27252190Srpaulo * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28252190Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29252190Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30252190Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31252190Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32252190Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33252190Srpaulo * SUCH DAMAGE. 34252190Srpaulo * 35252190Srpaulo * $FreeBSD: head/sys/dev/advansys/adv_eisa.c 112782 2003-03-29 09:46:10Z mdodd $ 36252190Srpaulo */ 37252190Srpaulo 38252190Srpaulo#include <sys/param.h> 39252190Srpaulo#include <sys/systm.h> 40252190Srpaulo#include <sys/kernel.h> 41252190Srpaulo#include <sys/module.h> 42252190Srpaulo#include <sys/bus.h> 43252190Srpaulo 44252190Srpaulo#include <machine/bus_pio.h> 45252190Srpaulo#include <machine/bus.h> 46252190Srpaulo#include <machine/resource.h> 47252190Srpaulo#include <sys/rman.h> 48252190Srpaulo 49252190Srpaulo#include <dev/eisa/eisaconf.h> 50252190Srpaulo 51252190Srpaulo#include <dev/advansys/advansys.h> 52252190Srpaulo 53252190Srpaulo#define EISA_DEVICE_ID_ADVANSYS_740 0x04507400 54252190Srpaulo#define EISA_DEVICE_ID_ADVANSYS_750 0x04507500 55252190Srpaulo 56252190Srpaulo#define ADV_EISA_SLOT_OFFSET 0xc00 57252190Srpaulo#define ADV_EISA_OFFSET_CHAN1 0x30 58252190Srpaulo#define ADV_EISA_OFFSET_CHAN2 0x50 59252190Srpaulo#define ADV_EISA_IOSIZE 0x100 60252190Srpaulo 61252190Srpaulo#define ADV_EISA_ROM_BIOS_ADDR_REG 0x86 62252190Srpaulo#define ADV_EISA_IRQ_BURST_LEN_REG 0x87 63252190Srpaulo#define ADV_EISA_IRQ_MASK 0x07 64252190Srpaulo#define ADV_EISA_IRQ_10 0x00 65252190Srpaulo#define ADV_EISA_IRQ_11 0x01 66252190Srpaulo#define ADV_EISA_IRQ_12 0x02 67252190Srpaulo#define ADV_EISA_IRQ_14 0x04 68252190Srpaulo#define ADV_EISA_IRQ_15 0x05 69252190Srpaulo 70252190Srpaulo#define ADV_EISA_MAX_DMA_ADDR (0x07FFFFFFL) 71252190Srpaulo#define ADV_EISA_MAX_DMA_COUNT (0x07FFFFFFL) 72252190Srpaulo 73252190Srpaulo/* 74252190Srpaulo * The overrun buffer shared amongst all EISA adapters. 75252190Srpaulo */ 76252190Srpaulostatic u_int8_t* overrun_buf; 77252190Srpaulostatic bus_dma_tag_t overrun_dmat; 78252190Srpaulostatic bus_dmamap_t overrun_dmamap; 79252190Srpaulostatic bus_addr_t overrun_physbase; 80252190Srpaulo 81252190Srpaulostatic const char* 82252190Srpauloadv_eisa_match(eisa_id_t type) 83252190Srpaulo{ 84252190Srpaulo switch (type & ~0xF) { 85252190Srpaulo case EISA_DEVICE_ID_ADVANSYS_740: 86252190Srpaulo return ("AdvanSys ABP-740/742 SCSI adapter"); 87252190Srpaulo break; 88252190Srpaulo case EISA_DEVICE_ID_ADVANSYS_750: 89252190Srpaulo return ("AdvanSys ABP-750/752 SCSI adapter"); 90252190Srpaulo break; 91252190Srpaulo default: 92252190Srpaulo break; 93252190Srpaulo } 94252190Srpaulo return (NULL); 95252190Srpaulo} 96252190Srpaulo 97252190Srpaulostatic int 98252190Srpauloadv_eisa_probe(device_t dev) 99252190Srpaulo{ 100252190Srpaulo const char *desc; 101252190Srpaulo u_int32_t iobase; 102252190Srpaulo u_int8_t irq; 103252190Srpaulo 104252190Srpaulo desc = adv_eisa_match(eisa_get_id(dev)); 105252190Srpaulo if (!desc) 106252190Srpaulo return (ENXIO); 107252190Srpaulo device_set_desc(dev, desc); 108252190Srpaulo 109252190Srpaulo iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET; 110252190Srpaulo 111252190Srpaulo eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE); 112252190Srpaulo irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG); 113252190Srpaulo irq &= ADV_EISA_IRQ_MASK; 114252190Srpaulo switch (irq) { 115252190Srpaulo case 0: 116252190Srpaulo case 1: 117252190Srpaulo case 2: 118252190Srpaulo case 4: 119252190Srpaulo case 5: 120252190Srpaulo break; 121252190Srpaulo default: 122252190Srpaulo printf("adv at slot %d: illegal " 123252190Srpaulo "irq setting %d\n", eisa_get_slot(dev), 124252190Srpaulo irq); 125252190Srpaulo return ENXIO; 126252190Srpaulo } 127252190Srpaulo eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL); 128252190Srpaulo 129252190Srpaulo return 0; 130252190Srpaulo} 131252190Srpaulo 132252190Srpaulostatic int 133252190Srpauloadv_eisa_attach(device_t dev) 134252190Srpaulo{ 135252190Srpaulo struct adv_softc *adv; 136252190Srpaulo struct adv_softc *adv_b; 137252190Srpaulo struct resource *io; 138252190Srpaulo struct resource *irq; 139252190Srpaulo int rid, error; 140252190Srpaulo void *ih; 141252190Srpaulo 142252190Srpaulo adv_b = NULL; 143252190Srpaulo 144252190Srpaulo rid = 0; 145252190Srpaulo io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 146252190Srpaulo 0, ~0, 1, RF_ACTIVE); 147252190Srpaulo if (!io) { 148252190Srpaulo device_printf(dev, "No I/O space?!\n"); 149252190Srpaulo return ENOMEM; 150252190Srpaulo } 151252190Srpaulo 152252190Srpaulo rid = 0; 153252190Srpaulo irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 154252190Srpaulo 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 155252190Srpaulo if (!irq) { 156252190Srpaulo device_printf(dev, "No irq?!\n"); 157252190Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 158252190Srpaulo return ENOMEM; 159252190Srpaulo 160252190Srpaulo } 161252190Srpaulo 162252190Srpaulo switch (eisa_get_id(dev) & ~0xF) { 163252190Srpaulo case EISA_DEVICE_ID_ADVANSYS_750: 164252190Srpaulo adv_b = adv_alloc(dev, rman_get_bustag(io), 165252190Srpaulo rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN2); 166252190Srpaulo if (adv_b == NULL) 167252190Srpaulo goto bad; 168252190Srpaulo 169252190Srpaulo /* 170252190Srpaulo * Allocate a parent dmatag for all tags created 171252190Srpaulo * by the MI portions of the advansys driver 172252190Srpaulo */ 173252190Srpaulo /* XXX Should be a child of the PCI bus dma tag */ 174252190Srpaulo error = bus_dma_tag_create( 175252190Srpaulo /* parent */ NULL, 176252190Srpaulo /* alignment */ 1, 177252190Srpaulo /* boundary */ 0, 178252190Srpaulo /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 179252190Srpaulo /* highaddr */ BUS_SPACE_MAXADDR, 180252190Srpaulo /* filter */ NULL, 181252190Srpaulo /* filterarg */ NULL, 182252190Srpaulo /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 183252190Srpaulo /* nsegments */ ~0, 184252190Srpaulo /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT, 185252190Srpaulo /* flags */ 0, 186252190Srpaulo &adv_b->parent_dmat); 187252190Srpaulo 188252190Srpaulo if (error != 0) { 189252190Srpaulo printf("%s: Could not allocate DMA tag - error %d\n", 190252190Srpaulo adv_name(adv_b), error); 191252190Srpaulo adv_free(adv_b); 192252190Srpaulo goto bad; 193252190Srpaulo } 194252190Srpaulo 195252190Srpaulo adv_b->init_level++; 196252190Srpaulo 197252190Srpaulo /* FALLTHROUGH */ 198252190Srpaulo case EISA_DEVICE_ID_ADVANSYS_740: 199252190Srpaulo adv = adv_alloc(dev, rman_get_bustag(io), 200252190Srpaulo rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN1); 201252190Srpaulo if (adv == NULL) { 202252190Srpaulo if (adv_b != NULL) 203252190Srpaulo adv_free(adv_b); 204252190Srpaulo goto bad; 205252190Srpaulo } 206252190Srpaulo 207252190Srpaulo /* 208252190Srpaulo * Allocate a parent dmatag for all tags created 209252190Srpaulo * by the MI portions of the advansys driver 210252190Srpaulo */ 211252190Srpaulo /* XXX Should be a child of the PCI bus dma tag */ 212252190Srpaulo error = bus_dma_tag_create( 213252190Srpaulo /* parent */ NULL, 214252190Srpaulo /* alignment */ 1, 215252190Srpaulo /* boundary */ 0, 216252190Srpaulo /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 217252190Srpaulo /* highaddr */ BUS_SPACE_MAXADDR, 218252190Srpaulo /* filter */ NULL, 219252190Srpaulo /* filterarg */ NULL, 220252190Srpaulo /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 221252190Srpaulo /* nsegments */ ~0, 222252190Srpaulo /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT, 223252190Srpaulo /* flags */ 0, 224252190Srpaulo &adv->parent_dmat); 225252190Srpaulo 226252190Srpaulo if (error != 0) { 227252190Srpaulo printf("%s: Could not allocate DMA tag - error %d\n", 228252190Srpaulo adv_name(adv), error); 229252190Srpaulo adv_free(adv); 230252190Srpaulo goto bad; 231252190Srpaulo } 232252190Srpaulo 233252190Srpaulo adv->init_level++; 234252190Srpaulo break; 235252190Srpaulo default: 236252190Srpaulo printf("adveisaattach: Unknown device type!\n"); 237252190Srpaulo goto bad; 238252190Srpaulo break; 239252190Srpaulo } 240252190Srpaulo 241252190Srpaulo if (overrun_buf == NULL) { 242252190Srpaulo /* Need to allocate our overrun buffer */ 243252190Srpaulo if (bus_dma_tag_create( 244252190Srpaulo /* parent */ adv->parent_dmat, 245252190Srpaulo /* alignment */ 8, 246252190Srpaulo /* boundary */ 0, 247252190Srpaulo /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 248252190Srpaulo /* highaddr */ BUS_SPACE_MAXADDR, 249252190Srpaulo /* filter */ NULL, 250252190Srpaulo /* filterarg */ NULL, 251252190Srpaulo /* maxsize */ ADV_OVERRUN_BSIZE, 252252190Srpaulo /* nsegments */ 1, 253252190Srpaulo /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 254252190Srpaulo /* flags */ 0, 255252190Srpaulo &overrun_dmat) != 0) { 256252190Srpaulo adv_free(adv); 257252190Srpaulo goto bad; 258252190Srpaulo } 259252190Srpaulo if (bus_dmamem_alloc(overrun_dmat, 260252190Srpaulo (void **)&overrun_buf, 261252190Srpaulo BUS_DMA_NOWAIT, 262252190Srpaulo &overrun_dmamap) != 0) { 263252190Srpaulo bus_dma_tag_destroy(overrun_dmat); 264252190Srpaulo adv_free(adv); 265252190Srpaulo goto bad; 266252190Srpaulo } 267252190Srpaulo /* And permanently map it in */ 268252190Srpaulo bus_dmamap_load(overrun_dmat, overrun_dmamap, 269252190Srpaulo overrun_buf, ADV_OVERRUN_BSIZE, 270252190Srpaulo adv_map, &overrun_physbase, 271252190Srpaulo /*flags*/0); 272252190Srpaulo } 273252190Srpaulo 274252190Srpaulo /* 275252190Srpaulo * Now that we know we own the resources we need, do the 276252190Srpaulo * card initialization. 277252190Srpaulo */ 278252190Srpaulo 279252190Srpaulo /* 280252190Srpaulo * Stop the chip. 281252190Srpaulo */ 282252190Srpaulo ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 283252190Srpaulo ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 284252190Srpaulo 285252190Srpaulo adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev)) 286252190Srpaulo + ADV_CHIP_MIN_VER_EISA - 1; 287252190Srpaulo 288252190Srpaulo if (adv_init(adv) != 0) { 289252190Srpaulo adv_free(adv); 290252190Srpaulo if (adv_b != NULL) 291252190Srpaulo adv_free(adv_b); 292252190Srpaulo return(-1); 293252190Srpaulo } 294252190Srpaulo 295252190Srpaulo adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT; 296252190Srpaulo adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR; 297252190Srpaulo 298252190Srpaulo if (adv_b != NULL) { 299252190Srpaulo /* 300252190Srpaulo * Stop the chip. 301252190Srpaulo */ 302252190Srpaulo ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT); 303252190Srpaulo ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0); 304252190Srpaulo 305252190Srpaulo adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev)) 306252190Srpaulo + ADV_CHIP_MIN_VER_EISA - 1; 307252190Srpaulo 308252190Srpaulo if (adv_init(adv_b) != 0) { 309252190Srpaulo adv_free(adv_b); 310252190Srpaulo } else { 311252190Srpaulo adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT; 312252190Srpaulo adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR; 313252190Srpaulo } 314252190Srpaulo } 315252190Srpaulo 316252190Srpaulo /* 317252190Srpaulo * Enable our interrupt handler. 318252190Srpaulo */ 319252190Srpaulo bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih); 320252190Srpaulo 321252190Srpaulo /* Attach sub-devices - always succeeds */ 322252190Srpaulo adv_attach(adv); 323252190Srpaulo if (adv_b != NULL) 324252190Srpaulo adv_attach(adv_b); 325252190Srpaulo 326252190Srpaulo return 0; 327252190Srpaulo 328252190Srpaulo bad: 329252190Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 330252190Srpaulo bus_release_resource(dev, SYS_RES_IRQ, 0, irq); 331252190Srpaulo return -1; 332252190Srpaulo} 333252190Srpaulo 334252190Srpaulostatic device_method_t adv_eisa_methods[] = { 335252190Srpaulo /* Device interface */ 336252190Srpaulo DEVMETHOD(device_probe, adv_eisa_probe), 337252190Srpaulo DEVMETHOD(device_attach, adv_eisa_attach), 338252190Srpaulo { 0, 0 } 339252190Srpaulo}; 340252190Srpaulo 341252190Srpaulostatic driver_t adv_eisa_driver = { 342252190Srpaulo "adv", adv_eisa_methods, sizeof(struct adv_softc) 343252190Srpaulo}; 344252190Srpaulo 345252190Srpaulostatic devclass_t adv_eisa_devclass; 346252190SrpauloDRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_eisa_devclass, 0, 0); 347252190Srpaulo