adv_eisa.c revision 119418
1/* 2 * Device probe and attach routines for the following 3 * Advanced Systems Inc. SCSI controllers: 4 * 5 * Single Channel Products: 6 * ABP742 - Bus-Master EISA (240 CDB) 7 * 8 * Dual Channel Products: 9 * ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) 10 * 11 * Copyright (c) 1997 Justin Gibbs. 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions, and the following disclaimer, 19 * without modification, immediately at the beginning of the file. 20 * 2. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: head/sys/dev/advansys/adv_eisa.c 119418 2003-08-24 17:55:58Z obrien $"); 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42#include <sys/module.h> 43#include <sys/lock.h> 44#include <sys/mutex.h> 45#include <sys/bus.h> 46 47#include <machine/bus_pio.h> 48#include <machine/bus.h> 49#include <machine/resource.h> 50#include <sys/rman.h> 51 52#include <dev/eisa/eisaconf.h> 53 54#include <dev/advansys/advansys.h> 55 56#define EISA_DEVICE_ID_ADVANSYS_740 0x04507400 57#define EISA_DEVICE_ID_ADVANSYS_750 0x04507500 58 59#define ADV_EISA_SLOT_OFFSET 0xc00 60#define ADV_EISA_OFFSET_CHAN1 0x30 61#define ADV_EISA_OFFSET_CHAN2 0x50 62#define ADV_EISA_IOSIZE 0x100 63 64#define ADV_EISA_ROM_BIOS_ADDR_REG 0x86 65#define ADV_EISA_IRQ_BURST_LEN_REG 0x87 66#define ADV_EISA_IRQ_MASK 0x07 67#define ADV_EISA_IRQ_10 0x00 68#define ADV_EISA_IRQ_11 0x01 69#define ADV_EISA_IRQ_12 0x02 70#define ADV_EISA_IRQ_14 0x04 71#define ADV_EISA_IRQ_15 0x05 72 73#define ADV_EISA_MAX_DMA_ADDR (0x07FFFFFFL) 74#define ADV_EISA_MAX_DMA_COUNT (0x07FFFFFFL) 75 76/* 77 * The overrun buffer shared amongst all EISA adapters. 78 */ 79static u_int8_t* overrun_buf; 80static bus_dma_tag_t overrun_dmat; 81static bus_dmamap_t overrun_dmamap; 82static bus_addr_t overrun_physbase; 83 84static const char* 85adv_eisa_match(eisa_id_t type) 86{ 87 switch (type & ~0xF) { 88 case EISA_DEVICE_ID_ADVANSYS_740: 89 return ("AdvanSys ABP-740/742 SCSI adapter"); 90 break; 91 case EISA_DEVICE_ID_ADVANSYS_750: 92 return ("AdvanSys ABP-750/752 SCSI adapter"); 93 break; 94 default: 95 break; 96 } 97 return (NULL); 98} 99 100static int 101adv_eisa_probe(device_t dev) 102{ 103 const char *desc; 104 u_int32_t iobase; 105 u_int8_t irq; 106 107 desc = adv_eisa_match(eisa_get_id(dev)); 108 if (!desc) 109 return (ENXIO); 110 device_set_desc(dev, desc); 111 112 iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET; 113 114 eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE); 115 irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG); 116 irq &= ADV_EISA_IRQ_MASK; 117 switch (irq) { 118 case 0: 119 case 1: 120 case 2: 121 case 4: 122 case 5: 123 break; 124 default: 125 printf("adv at slot %d: illegal " 126 "irq setting %d\n", eisa_get_slot(dev), 127 irq); 128 return ENXIO; 129 } 130 eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL); 131 132 return 0; 133} 134 135static int 136adv_eisa_attach(device_t dev) 137{ 138 struct adv_softc *adv; 139 struct adv_softc *adv_b; 140 struct resource *io; 141 struct resource *irq; 142 int rid, error; 143 void *ih; 144 145 adv_b = NULL; 146 147 rid = 0; 148 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 149 0, ~0, 1, RF_ACTIVE); 150 if (!io) { 151 device_printf(dev, "No I/O space?!\n"); 152 return ENOMEM; 153 } 154 155 rid = 0; 156 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 157 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 158 if (!irq) { 159 device_printf(dev, "No irq?!\n"); 160 bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 161 return ENOMEM; 162 163 } 164 165 switch (eisa_get_id(dev) & ~0xF) { 166 case EISA_DEVICE_ID_ADVANSYS_750: 167 adv_b = adv_alloc(dev, rman_get_bustag(io), 168 rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN2); 169 if (adv_b == NULL) 170 goto bad; 171 172 /* 173 * Allocate a parent dmatag for all tags created 174 * by the MI portions of the advansys driver 175 */ 176 /* XXX Should be a child of the PCI bus dma tag */ 177 error = bus_dma_tag_create( 178 /* parent */ NULL, 179 /* alignment */ 1, 180 /* boundary */ 0, 181 /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 182 /* highaddr */ BUS_SPACE_MAXADDR, 183 /* filter */ NULL, 184 /* filterarg */ NULL, 185 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 186 /* nsegments */ ~0, 187 /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT, 188 /* flags */ 0, 189 /* lockfunc */ busdma_lock_mutex, 190 /* lockarg */ &Giant, 191 &adv_b->parent_dmat); 192 193 if (error != 0) { 194 printf("%s: Could not allocate DMA tag - error %d\n", 195 adv_name(adv_b), error); 196 adv_free(adv_b); 197 goto bad; 198 } 199 200 adv_b->init_level++; 201 202 /* FALLTHROUGH */ 203 case EISA_DEVICE_ID_ADVANSYS_740: 204 adv = adv_alloc(dev, rman_get_bustag(io), 205 rman_get_bushandle(io) + ADV_EISA_OFFSET_CHAN1); 206 if (adv == NULL) { 207 if (adv_b != NULL) 208 adv_free(adv_b); 209 goto bad; 210 } 211 212 /* 213 * Allocate a parent dmatag for all tags created 214 * by the MI portions of the advansys driver 215 */ 216 /* XXX Should be a child of the PCI bus dma tag */ 217 error = bus_dma_tag_create( 218 /* parent */ NULL, 219 /* alignment */ 1, 220 /* boundary */ 0, 221 /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 222 /* highaddr */ BUS_SPACE_MAXADDR, 223 /* filter */ NULL, 224 /* filterarg */ NULL, 225 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 226 /* nsegments */ ~0, 227 /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT, 228 /* flags */ 0, 229 /* lockfunc */ busdma_lock_mutex, 230 /* lockarg */ &Giant, 231 &adv->parent_dmat); 232 233 if (error != 0) { 234 printf("%s: Could not allocate DMA tag - error %d\n", 235 adv_name(adv), error); 236 adv_free(adv); 237 goto bad; 238 } 239 240 adv->init_level++; 241 break; 242 default: 243 printf("adveisaattach: Unknown device type!\n"); 244 goto bad; 245 break; 246 } 247 248 if (overrun_buf == NULL) { 249 /* Need to allocate our overrun buffer */ 250 if (bus_dma_tag_create( 251 /* parent */ adv->parent_dmat, 252 /* alignment */ 8, 253 /* boundary */ 0, 254 /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 255 /* highaddr */ BUS_SPACE_MAXADDR, 256 /* filter */ NULL, 257 /* filterarg */ NULL, 258 /* maxsize */ ADV_OVERRUN_BSIZE, 259 /* nsegments */ 1, 260 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 261 /* flags */ 0, 262 /* lockfunc */ busdma_lock_mutex, 263 /* lockarg */ &Giant, 264 &overrun_dmat) != 0) { 265 adv_free(adv); 266 goto bad; 267 } 268 if (bus_dmamem_alloc(overrun_dmat, 269 (void **)&overrun_buf, 270 BUS_DMA_NOWAIT, 271 &overrun_dmamap) != 0) { 272 bus_dma_tag_destroy(overrun_dmat); 273 adv_free(adv); 274 goto bad; 275 } 276 /* And permanently map it in */ 277 bus_dmamap_load(overrun_dmat, overrun_dmamap, 278 overrun_buf, ADV_OVERRUN_BSIZE, 279 adv_map, &overrun_physbase, 280 /*flags*/0); 281 } 282 283 /* 284 * Now that we know we own the resources we need, do the 285 * card initialization. 286 */ 287 288 /* 289 * Stop the chip. 290 */ 291 ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 292 ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 293 294 adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev)) 295 + ADV_CHIP_MIN_VER_EISA - 1; 296 297 if (adv_init(adv) != 0) { 298 adv_free(adv); 299 if (adv_b != NULL) 300 adv_free(adv_b); 301 return(-1); 302 } 303 304 adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT; 305 adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR; 306 307 if (adv_b != NULL) { 308 /* 309 * Stop the chip. 310 */ 311 ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT); 312 ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0); 313 314 adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev)) 315 + ADV_CHIP_MIN_VER_EISA - 1; 316 317 if (adv_init(adv_b) != 0) { 318 adv_free(adv_b); 319 } else { 320 adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT; 321 adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR; 322 } 323 } 324 325 /* 326 * Enable our interrupt handler. 327 */ 328 bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, adv_intr, adv, &ih); 329 330 /* Attach sub-devices - always succeeds */ 331 adv_attach(adv); 332 if (adv_b != NULL) 333 adv_attach(adv_b); 334 335 return 0; 336 337 bad: 338 bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 339 bus_release_resource(dev, SYS_RES_IRQ, 0, irq); 340 return -1; 341} 342 343static device_method_t adv_eisa_methods[] = { 344 /* Device interface */ 345 DEVMETHOD(device_probe, adv_eisa_probe), 346 DEVMETHOD(device_attach, adv_eisa_attach), 347 { 0, 0 } 348}; 349 350static driver_t adv_eisa_driver = { 351 "adv", adv_eisa_methods, sizeof(struct adv_softc) 352}; 353 354static devclass_t adv_eisa_devclass; 355DRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_eisa_devclass, 0, 0); 356