adv_eisa.c revision 241492
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 241492 2012-10-12 21:31:44Z jhb $"); 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.h> 48#include <machine/resource.h> 49#include <sys/rman.h> 50 51#include <dev/eisa/eisaconf.h> 52 53#include <dev/advansys/advansys.h> 54 55#define EISA_DEVICE_ID_ADVANSYS_740 0x04507400 56#define EISA_DEVICE_ID_ADVANSYS_750 0x04507500 57 58#define ADV_EISA_SLOT_OFFSET 0xc00 59#define ADV_EISA_OFFSET_CHAN1 0x30 60#define ADV_EISA_OFFSET_CHAN2 0x50 61#define ADV_EISA_IOSIZE 0x100 62 63#define ADV_EISA_ROM_BIOS_ADDR_REG 0x86 64#define ADV_EISA_IRQ_BURST_LEN_REG 0x87 65#define ADV_EISA_IRQ_MASK 0x07 66#define ADV_EISA_IRQ_10 0x00 67#define ADV_EISA_IRQ_11 0x01 68#define ADV_EISA_IRQ_12 0x02 69#define ADV_EISA_IRQ_14 0x04 70#define ADV_EISA_IRQ_15 0x05 71 72#define ADV_EISA_MAX_DMA_ADDR (0x07FFFFFFL) 73#define ADV_EISA_MAX_DMA_COUNT (0x07FFFFFFL) 74 75/* 76 * The overrun buffer shared amongst all EISA adapters. 77 */ 78static void* overrun_buf; 79static bus_dma_tag_t overrun_dmat; 80static bus_dmamap_t overrun_dmamap; 81static bus_addr_t overrun_physbase; 82 83static const char* 84adv_eisa_match(eisa_id_t type) 85{ 86 switch (type & ~0xF) { 87 case EISA_DEVICE_ID_ADVANSYS_740: 88 return ("AdvanSys ABP-740/742 SCSI adapter"); 89 break; 90 case EISA_DEVICE_ID_ADVANSYS_750: 91 return ("AdvanSys ABP-750/752 SCSI adapter"); 92 break; 93 default: 94 break; 95 } 96 return (NULL); 97} 98 99static int 100adv_eisa_probe(device_t dev) 101{ 102 const char *desc; 103 u_int32_t iobase; 104 u_int8_t irq; 105 106 desc = adv_eisa_match(eisa_get_id(dev)); 107 if (!desc) 108 return (ENXIO); 109 device_set_desc(dev, desc); 110 111 iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET; 112 113 eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE); 114 irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG); 115 irq &= ADV_EISA_IRQ_MASK; 116 switch (irq) { 117 case 0: 118 case 1: 119 case 2: 120 case 4: 121 case 5: 122 break; 123 default: 124 printf("adv at slot %d: illegal " 125 "irq setting %d\n", eisa_get_slot(dev), 126 irq); 127 return ENXIO; 128 } 129 eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL); 130 131 return 0; 132} 133 134/* 135 * The adv_b stuff to handle twin-channel cards will not work in its current 136 * incarnation. It tries to reuse the same softc since adv_alloc() doesn't 137 * actually allocate a softc. It also tries to reuse the same unit number 138 * for both sims. This can be re-enabled if someone fixes it properly. 139 */ 140static int 141adv_eisa_attach(device_t dev) 142{ 143 struct adv_softc *adv; 144#if 0 145 struct adv_softc *adv_b; 146#endif 147 struct resource *io; 148 struct resource *irq; 149 int rid, error; 150 void *ih; 151 152#if 0 153 adv_b = NULL; 154#endif 155 156 rid = 0; 157 io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 158 if (!io) { 159 device_printf(dev, "No I/O space?!\n"); 160 return ENOMEM; 161 } 162 163 rid = 0; 164 irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 165 RF_SHAREABLE | RF_ACTIVE); 166 if (!irq) { 167 device_printf(dev, "No irq?!\n"); 168 bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 169 return ENOMEM; 170 171 } 172 173 switch (eisa_get_id(dev) & ~0xF) { 174 case EISA_DEVICE_ID_ADVANSYS_750: 175#if 0 176 adv_b = adv_alloc(dev, io, ADV_EISA_OFFSET_CHAN2); 177 if (adv_b == NULL) 178 goto bad; 179 180 /* 181 * Allocate a parent dmatag for all tags created 182 * by the MI portions of the advansys driver 183 */ 184 error = bus_dma_tag_create( 185 /* parent */ bus_get_dma_tag(dev), 186 /* alignment */ 1, 187 /* boundary */ 0, 188 /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 189 /* highaddr */ BUS_SPACE_MAXADDR, 190 /* filter */ NULL, 191 /* filterarg */ NULL, 192 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 193 /* nsegments */ ~0, 194 /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT, 195 /* flags */ 0, 196 /* lockfunc */ NULL, 197 /* lockarg */ NULL, 198 &adv_b->parent_dmat); 199 200 if (error != 0) { 201 device_printf(dev, "Could not allocate DMA tag - error %d\n", 202 error); 203 adv_free(adv_b); 204 goto bad; 205 } 206 207 adv_b->init_level++; 208#endif 209 210 /* FALLTHROUGH */ 211 case EISA_DEVICE_ID_ADVANSYS_740: 212 adv = adv_alloc(dev, io, ADV_EISA_OFFSET_CHAN1); 213 if (adv == NULL) { 214#if 0 215 if (adv_b != NULL) 216 adv_free(adv_b); 217#endif 218 goto bad; 219 } 220 221 /* 222 * Allocate a parent dmatag for all tags created 223 * by the MI portions of the advansys driver 224 */ 225 error = bus_dma_tag_create( 226 /* parent */ bus_get_dma_tag(dev), 227 /* alignment */ 1, 228 /* boundary */ 0, 229 /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 230 /* highaddr */ BUS_SPACE_MAXADDR, 231 /* filter */ NULL, 232 /* filterarg */ NULL, 233 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 234 /* nsegments */ ~0, 235 /* maxsegsz */ ADV_EISA_MAX_DMA_COUNT, 236 /* flags */ 0, 237 /* lockfunc */ NULL, 238 /* lockarg */ NULL, 239 &adv->parent_dmat); 240 241 if (error != 0) { 242 device_printf(dev, "Could not allocate DMA tag - error %d\n", 243 error); 244 adv_free(adv); 245 goto bad; 246 } 247 248 adv->init_level++; 249 break; 250 default: 251 printf("adveisaattach: Unknown device type!\n"); 252 goto bad; 253 break; 254 } 255 256 if (overrun_buf == NULL) { 257 /* Need to allocate our overrun buffer */ 258 if (bus_dma_tag_create( 259 /* parent */ bus_get_dma_tag(dev), 260 /* alignment */ 8, 261 /* boundary */ 0, 262 /* lowaddr */ ADV_EISA_MAX_DMA_ADDR, 263 /* highaddr */ BUS_SPACE_MAXADDR, 264 /* filter */ NULL, 265 /* filterarg */ NULL, 266 /* maxsize */ ADV_OVERRUN_BSIZE, 267 /* nsegments */ 1, 268 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 269 /* flags */ 0, 270 /* lockfunc */ NULL, 271 /* lockarg */ NULL, 272 &overrun_dmat) != 0) { 273 adv_free(adv); 274 goto bad; 275 } 276 if (bus_dmamem_alloc(overrun_dmat, 277 &overrun_buf, 278 BUS_DMA_NOWAIT, 279 &overrun_dmamap) != 0) { 280 bus_dma_tag_destroy(overrun_dmat); 281 adv_free(adv); 282 goto bad; 283 } 284 /* And permanently map it in */ 285 bus_dmamap_load(overrun_dmat, overrun_dmamap, 286 overrun_buf, ADV_OVERRUN_BSIZE, 287 adv_map, &overrun_physbase, 288 /*flags*/0); 289 } 290 291 /* 292 * Now that we know we own the resources we need, do the 293 * card initialization. 294 */ 295 296 /* 297 * Stop the chip. 298 */ 299 ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 300 ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 301 302 adv->chip_version = EISA_REVISION_ID(eisa_get_id(dev)) 303 + ADV_CHIP_MIN_VER_EISA - 1; 304 305 if (adv_init(adv) != 0) { 306 adv_free(adv); 307#if 0 308 if (adv_b != NULL) 309 adv_free(adv_b); 310#endif 311 goto bad; 312 } 313 314 adv->max_dma_count = ADV_EISA_MAX_DMA_COUNT; 315 adv->max_dma_addr = ADV_EISA_MAX_DMA_ADDR; 316 317#if 0 318 if (adv_b != NULL) { 319 /* 320 * Stop the chip. 321 */ 322 ADV_OUTB(adv_b, ADV_CHIP_CTRL, ADV_CC_HALT); 323 ADV_OUTW(adv_b, ADV_CHIP_STATUS, 0); 324 325 adv_b->chip_version = EISA_REVISION_ID(eisa_get_id(dev)) 326 + ADV_CHIP_MIN_VER_EISA - 1; 327 328 if (adv_init(adv_b) != 0) { 329 adv_free(adv_b); 330 } else { 331 adv_b->max_dma_count = ADV_EISA_MAX_DMA_COUNT; 332 adv_b->max_dma_addr = ADV_EISA_MAX_DMA_ADDR; 333 } 334 } 335#endif 336 337 /* 338 * Enable our interrupt handler. 339 */ 340 if (bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY|INTR_MPSAFE, NULL, 341 adv_intr, adv, &ih) != 0) { 342 adv_free(adv); 343 goto bad; 344 } 345 346 /* Attach sub-devices */ 347 if (adv_attach(adv) != 0) { 348 adv_free(adv); 349 goto bad; 350 } 351#if 0 352 if (adv_b != NULL) 353 adv_attach(adv_b); 354#endif 355 356 return 0; 357 358 bad: 359 bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 360 bus_release_resource(dev, SYS_RES_IRQ, 0, irq); 361 return ENXIO; 362} 363 364static device_method_t adv_eisa_methods[] = { 365 /* Device interface */ 366 DEVMETHOD(device_probe, adv_eisa_probe), 367 DEVMETHOD(device_attach, adv_eisa_attach), 368 { 0, 0 } 369}; 370 371static driver_t adv_eisa_driver = { 372 "adv", adv_eisa_methods, sizeof(struct adv_softc) 373}; 374 375static devclass_t adv_eisa_devclass; 376DRIVER_MODULE(adv, eisa, adv_eisa_driver, adv_eisa_devclass, 0, 0); 377MODULE_DEPEND(adv, eisa, 1, 1, 1); 378