adv_eisa.c revision 302408
1313006Scem/*- 2313006Scem * Device probe and attach routines for the following 3313006Scem * Advanced Systems Inc. SCSI controllers: 4313006Scem * 5313006Scem * Single Channel Products: 6313006Scem * ABP742 - Bus-Master EISA (240 CDB) 7313006Scem * 8313006Scem * Dual Channel Products: 9313006Scem * ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) 10313006Scem * 11313006Scem * Copyright (c) 1997 Justin Gibbs. 12313006Scem * All rights reserved. 13313006Scem * 14313006Scem * Redistribution and use in source and binary forms, with or without 15313006Scem * modification, are permitted provided that the following conditions 16313006Scem * are met: 17313006Scem * 1. Redistributions of source code must retain the above copyright 18313006Scem * notice, this list of conditions, and the following disclaimer, 19313006Scem * without modification, immediately at the beginning of the file. 20313006Scem * 2. The name of the author may not be used to endorse or promote products 21313006Scem * derived from this software without specific prior written permission. 22313006Scem * 23313006Scem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24313006Scem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25313006Scem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26313006Scem * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27313006Scem * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28313006Scem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29313006Scem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30313006Scem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31313006Scem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32313006Scem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33313006Scem * SUCH DAMAGE. 34313006Scem */ 35313006Scem 36313006Scem#include <sys/cdefs.h> 37313006Scem__FBSDID("$FreeBSD: stable/11/sys/dev/advansys/adv_eisa.c 241492 2012-10-12 21:31:44Z jhb $"); 38313006Scem 39313006Scem#include <sys/param.h> 40313006Scem#include <sys/systm.h> 41313006Scem#include <sys/kernel.h> 42313006Scem#include <sys/module.h> 43313006Scem#include <sys/lock.h> 44313006Scem#include <sys/mutex.h> 45313006Scem#include <sys/bus.h> 46313006Scem 47313006Scem#include <machine/bus.h> 48313006Scem#include <machine/resource.h> 49313006Scem#include <sys/rman.h> 50313006Scem 51313006Scem#include <dev/eisa/eisaconf.h> 52313006Scem 53313006Scem#include <dev/advansys/advansys.h> 54313006Scem 55313006Scem#define EISA_DEVICE_ID_ADVANSYS_740 0x04507400 56313006Scem#define EISA_DEVICE_ID_ADVANSYS_750 0x04507500 57313006Scem 58313006Scem#define ADV_EISA_SLOT_OFFSET 0xc00 59313006Scem#define ADV_EISA_OFFSET_CHAN1 0x30 60313006Scem#define ADV_EISA_OFFSET_CHAN2 0x50 61313006Scem#define ADV_EISA_IOSIZE 0x100 62313006Scem 63313006Scem#define ADV_EISA_ROM_BIOS_ADDR_REG 0x86 64313006Scem#define ADV_EISA_IRQ_BURST_LEN_REG 0x87 65313006Scem#define ADV_EISA_IRQ_MASK 0x07 66313006Scem#define ADV_EISA_IRQ_10 0x00 67313006Scem#define ADV_EISA_IRQ_11 0x01 68313006Scem#define ADV_EISA_IRQ_12 0x02 69313006Scem#define ADV_EISA_IRQ_14 0x04 70313006Scem#define ADV_EISA_IRQ_15 0x05 71313006Scem 72313006Scem#define ADV_EISA_MAX_DMA_ADDR (0x07FFFFFFL) 73313006Scem#define ADV_EISA_MAX_DMA_COUNT (0x07FFFFFFL) 74313006Scem 75313006Scem/* 76313006Scem * The overrun buffer shared amongst all EISA adapters. 77313006Scem */ 78313006Scemstatic void* overrun_buf; 79313006Scemstatic bus_dma_tag_t overrun_dmat; 80313006Scemstatic bus_dmamap_t overrun_dmamap; 81313006Scemstatic bus_addr_t overrun_physbase; 82313006Scem 83313006Scemstatic const char* 84313006Scemadv_eisa_match(eisa_id_t type) 85313006Scem{ 86313006Scem switch (type & ~0xF) { 87313006Scem case EISA_DEVICE_ID_ADVANSYS_740: 88313006Scem return ("AdvanSys ABP-740/742 SCSI adapter"); 89313006Scem break; 90313006Scem case EISA_DEVICE_ID_ADVANSYS_750: 91313006Scem return ("AdvanSys ABP-750/752 SCSI adapter"); 92313006Scem break; 93313006Scem default: 94313006Scem break; 95313006Scem } 96313006Scem return (NULL); 97313006Scem} 98313006Scem 99313006Scemstatic int 100313006Scemadv_eisa_probe(device_t dev) 101313006Scem{ 102313006Scem const char *desc; 103313006Scem u_int32_t iobase; 104313006Scem u_int8_t irq; 105313006Scem 106313006Scem desc = adv_eisa_match(eisa_get_id(dev)); 107313006Scem if (!desc) 108313006Scem return (ENXIO); 109313006Scem device_set_desc(dev, desc); 110313006Scem 111313006Scem iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) + ADV_EISA_SLOT_OFFSET; 112313006Scem 113313006Scem eisa_add_iospace(dev, iobase, ADV_EISA_IOSIZE, RESVADDR_NONE); 114313006Scem irq = inb(iobase + ADV_EISA_IRQ_BURST_LEN_REG); 115313006Scem irq &= ADV_EISA_IRQ_MASK; 116313006Scem switch (irq) { 117313006Scem case 0: 118313006Scem case 1: 119313006Scem case 2: 120313006Scem case 4: 121313006Scem case 5: 122313006Scem break; 123313006Scem default: 124313006Scem printf("adv at slot %d: illegal " 125313006Scem "irq setting %d\n", eisa_get_slot(dev), 126313006Scem irq); 127313006Scem return ENXIO; 128313006Scem } 129313006Scem eisa_add_intr(dev, irq + 10, EISA_TRIGGER_LEVEL); 130313006Scem 131313006Scem return 0; 132313006Scem} 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