1 /* $NetBSD: ahc_eisa.c,v 1.12 1997/05/08 04:39:35 thorpej Exp $ */ 2 3 /* 4 * Product specific probe and attach routines for: 5 * 27/284X and aic7770 motherboard SCSI controllers 6 * 7 * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice immediately at the beginning of the file, without modification, 15 * this list of conditions, and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 26 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from Id: aic7770.c,v 1.29 1996/05/30 07:18:52 gibbs Exp 35 */ 36 37 #if defined(__FreeBSD__) 38 #include <eisa.h> 39 #endif 40 #if NEISA > 0 || defined(__NetBSD__) 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #if defined(__FreeBSD__) 45 #include <sys/devconf.h> 46 #endif 47 #include <sys/kernel.h> 48 49 #if defined(__NetBSD__) 50 #include <sys/device.h> 51 #include <machine/bus.h> 52 #include <machine/intr.h> 53 #endif /* defined(__NetBSD__) */ 54 55 #include <scsi/scsi_all.h> 56 #include <scsi/scsiconf.h> 57 58 #if defined(__FreeBSD__) 59 60 #include <machine/clock.h> 61 62 #include <i386/eisa/eisaconf.h> 63 #include <i386/scsi/aic7xxx.h> 64 #include <dev/aic7xxx/aic7xxx_reg.h> 65 66 #define EISA_DEVICE_ID_ADAPTEC_AIC7770 0x04907770 67 #define EISA_DEVICE_ID_ADAPTEC_274x 0x04907771 68 #define EISA_DEVICE_ID_ADAPTEC_284xB 0x04907756 /* BIOS enabled */ 69 #define EISA_DEVICE_ID_ADAPTEC_284x 0x04907757 /* BIOS disabled*/ 70 71 #elif defined(__NetBSD__) 72 73 #include <dev/eisa/eisareg.h> 74 #include <dev/eisa/eisavar.h> 75 #include <dev/eisa/eisadevs.h> 76 77 #include <dev/ic/aic7xxxreg.h> 78 #include <dev/ic/aic7xxxvar.h> 79 80 #endif /* defined(__NetBSD__) */ 81 82 #define AHC_EISA_SLOT_OFFSET 0xc00 83 #define AHC_EISA_IOSIZE 0x100 84 #define INTDEF 0x5cul /* Interrupt Definition Register */ 85 86 #if defined(__FreeBSD__) 87 88 static int aic7770probe __P((void)); 89 static int aic7770_attach __P((struct eisa_device *e_dev)); 90 91 static struct eisa_driver ahc_eisa_driver = { 92 "ahc", 93 aic7770probe, 94 aic7770_attach, 95 /*shutdown*/NULL, 96 &ahc_unit 97 }; 98 99 DATA_SET (eisadriver_set, ahc_eisa_driver); 100 101 static struct kern_devconf kdc_aic7770 = { 102 0, 0, 0, /* filled in by dev_attach */ 103 "ahc", 0, { MDDT_EISA, 0, "bio" }, 104 eisa_generic_externalize, 0, 0, EISA_EXTERNALLEN, 105 &kdc_eisa0, /* parent */ 106 0, /* parentdata */ 107 DC_UNCONFIGURED, /* always start out here */ 108 NULL, 109 DC_CLS_MISC /* host adapters aren't special */ 110 }; 111 112 113 static char *aic7770_match __P((eisa_id_t type)); 114 115 static char* 116 aic7770_match(type) 117 eisa_id_t type; 118 { 119 switch(type) { 120 case EISA_DEVICE_ID_ADAPTEC_AIC7770: 121 return ("Adaptec aic7770 SCSI host adapter"); 122 break; 123 case EISA_DEVICE_ID_ADAPTEC_274x: 124 return ("Adaptec 274X SCSI host adapter"); 125 break; 126 case EISA_DEVICE_ID_ADAPTEC_284xB: 127 case EISA_DEVICE_ID_ADAPTEC_284x: 128 return ("Adaptec 284X SCSI host adapter"); 129 break; 130 default: 131 break; 132 } 133 return (NULL); 134 } 135 136 static int 137 aic7770probe(void) 138 { 139 u_long iobase; 140 char intdef; 141 u_long irq; 142 struct eisa_device *e_dev = NULL; 143 int count; 144 145 count = 0; 146 while ((e_dev = eisa_match_dev(e_dev, aic7770_match))) { 147 iobase = (e_dev->ioconf.slot * EISA_SLOT_SIZE) 148 + AHC_EISA_SLOT_OFFSET; 149 ahc_reset(iobase); 150 151 eisa_add_iospace(e_dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE); 152 intdef = inb(INTDEF + iobase); 153 switch (intdef & 0xf) { 154 case 9: 155 irq = 9; 156 break; 157 case 10: 158 irq = 10; 159 break; 160 case 11: 161 irq = 11; 162 break; 163 case 12: 164 irq = 12; 165 break; 166 case 14: 167 irq = 14; 168 break; 169 case 15: 170 irq = 15; 171 break; 172 default: 173 printf("aic7770 at slot %d: illegal " 174 "irq setting %d\n", e_dev->ioconf.slot, 175 intdef); 176 continue; 177 } 178 eisa_add_intr(e_dev, irq); 179 eisa_registerdev(e_dev, &ahc_eisa_driver, &kdc_aic7770); 180 if(e_dev->id == EISA_DEVICE_ID_ADAPTEC_284xB 181 || e_dev->id == EISA_DEVICE_ID_ADAPTEC_284x) { 182 /* Our real parent is the isa bus. Say so. */ 183 e_dev->kdc->kdc_parent = &kdc_isa0; 184 } 185 count++; 186 } 187 return count; 188 } 189 190 #elif defined(__NetBSD__) 191 192 /* 193 * Under normal circumstances, these messages are unnecessary 194 * and not terribly cosmetic. 195 */ 196 #ifdef DEBUG 197 #define bootverbose 1 198 #else 199 #define bootverbose 0 200 #endif 201 202 int ahc_eisa_irq __P((bus_space_tag_t, bus_space_handle_t)); 203 #ifdef __BROKEN_INDIRECT_CONFIG 204 int ahc_eisa_match __P((struct device *, void *, void *)); 205 #else 206 int ahc_eisa_match __P((struct device *, struct cfdata *, void *)); 207 #endif 208 void ahc_eisa_attach __P((struct device *, struct device *, void *)); 209 210 211 struct cfattach ahc_eisa_ca = { 212 sizeof(struct ahc_data), ahc_eisa_match, ahc_eisa_attach 213 }; 214 215 /* 216 * Return irq setting of the board, otherwise -1. 217 */ 218 int 219 ahc_eisa_irq(iot, ioh) 220 bus_space_tag_t iot; 221 bus_space_handle_t ioh; 222 { 223 int irq; 224 u_char intdef; 225 226 ahc_reset("ahc_eisa", iot, ioh); 227 intdef = bus_space_read_1(iot, ioh, INTDEF); 228 switch (irq = (intdef & 0xf)) { 229 case 9: 230 case 10: 231 case 11: 232 case 12: 233 case 14: 234 case 15: 235 break; 236 default: 237 printf("ahc_eisa_irq: illegal irq setting %d\n", intdef); 238 return -1; 239 } 240 241 /* Note that we are going and return (to probe) */ 242 return irq; 243 } 244 245 /* 246 * Check the slots looking for a board we recognise 247 * If we find one, note it's address (slot) and call 248 * the actual probe routine to check it out. 249 */ 250 int 251 ahc_eisa_match(parent, match, aux) 252 struct device *parent; 253 #ifdef __BROKEN_INDIRECT_CONFIG 254 void *match; 255 #else 256 struct cfdata *match; 257 #endif 258 void *aux; 259 { 260 struct eisa_attach_args *ea = aux; 261 bus_space_tag_t iot = ea->ea_iot; 262 bus_space_handle_t ioh; 263 int irq; 264 265 /* must match one of our known ID strings */ 266 if (strcmp(ea->ea_idstring, "ADP7770") && 267 strcmp(ea->ea_idstring, "ADP7771") 268 #if 0 269 && strcmp(ea->ea_idstring, "ADP7756") /* not EISA, but VL */ 270 && strcmp(ea->ea_idstring, "ADP7757") /* not EISA, but VL */ 271 #endif 272 ) 273 return (0); 274 275 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 276 AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh)) 277 return (0); 278 279 irq = ahc_eisa_irq(iot, ioh); 280 281 bus_space_unmap(iot, ioh, AHC_EISA_IOSIZE); 282 283 return (irq >= 0); 284 } 285 286 #endif /* defined(__NetBSD__) */ 287 288 #if defined(__FreeBSD__) 289 static int 290 aic7770_attach(e_dev) 291 struct eisa_device *e_dev; 292 #elif defined(__NetBSD__) 293 void 294 ahc_eisa_attach(parent, self, aux) 295 struct device *parent, *self; 296 void *aux; 297 #endif 298 { 299 ahc_type type; 300 301 #if defined(__FreeBSD__) 302 struct ahc_data *ahc; 303 resvaddr_t *iospace; 304 int unit = e_dev->unit; 305 int irq = ffs(e_dev->ioconf.irq) - 1; 306 307 iospace = e_dev->ioconf.ioaddrs.lh_first; 308 309 if(!iospace) 310 return -1; 311 312 switch(e_dev->id) { 313 case EISA_DEVICE_ID_ADAPTEC_AIC7770: 314 type = AHC_AIC7770; 315 break; 316 case EISA_DEVICE_ID_ADAPTEC_274x: 317 type = AHC_274; 318 break; 319 case EISA_DEVICE_ID_ADAPTEC_284xB: 320 case EISA_DEVICE_ID_ADAPTEC_284x: 321 type = AHC_284; 322 break; 323 default: 324 printf("aic7770_attach: Unknown device type!\n"); 325 return -1; 326 break; 327 } 328 329 if(!(ahc = ahc_alloc(unit, iospace->addr, type, AHC_FNONE))) 330 return -1; 331 332 eisa_reg_start(e_dev); 333 if(eisa_reg_iospace(e_dev, iospace)) { 334 ahc_free(ahc); 335 return -1; 336 } 337 338 /* 339 * The IRQMS bit enables level sensitive interrupts. Only allow 340 * IRQ sharing if it's set. 341 */ 342 if(eisa_reg_intr(e_dev, irq, ahc_intr, (void *)ahc, &bio_imask, 343 /*shared ==*/ahc->pause & IRQMS)) { 344 ahc_free(ahc); 345 return -1; 346 } 347 eisa_reg_end(e_dev); 348 349 #elif defined(__NetBSD__) 350 351 struct ahc_data *ahc = (void *)self; 352 struct eisa_attach_args *ea = aux; 353 bus_space_tag_t iot = ea->ea_iot; 354 bus_space_handle_t ioh; 355 int irq; 356 eisa_chipset_tag_t ec = ea->ea_ec; 357 eisa_intr_handle_t ih; 358 const char *model, *intrstr; 359 360 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 361 AHC_EISA_SLOT_OFFSET, AHC_EISA_IOSIZE, 0, &ioh)) 362 panic("ahc_eisa_attach: could not map I/O addresses"); 363 if ((irq = ahc_eisa_irq(iot, ioh)) < 0) 364 panic("ahc_eisa_attach: ahc_eisa_irq failed!"); 365 366 if (strcmp(ea->ea_idstring, "ADP7770") == 0) { 367 model = EISA_PRODUCT_ADP7770; 368 type = AHC_AIC7770; 369 } else if (strcmp(ea->ea_idstring, "ADP7771") == 0) { 370 model = EISA_PRODUCT_ADP7771; 371 type = AHC_274; 372 #if 0 373 } else if (strcmp(ea->ea_idstring, "ADP7756") == 0) { 374 model = EISA_PRODUCT_ADP7756; 375 type = AHC_284; 376 } else if (strcmp(ea->ea_idstring, "ADP7757") == 0) { 377 model = EISA_PRODUCT_ADP7757; 378 type = AHC_284; 379 #endif 380 } else { 381 panic("ahc_eisa_attach: Unknown device type %s\n", 382 ea->ea_idstring); 383 } 384 printf(": %s\n", model); 385 386 ahc_construct(ahc, iot, ioh, type, AHC_FNONE); 387 if (eisa_intr_map(ec, irq, &ih)) { 388 printf("%s: couldn't map interrupt (%d)\n", 389 ahc->sc_dev.dv_xname, irq); 390 return; 391 } 392 #endif /* defined(__NetBSD__) */ 393 394 /* 395 * Tell the user what type of interrupts we're using. 396 * usefull for debugging irq problems 397 */ 398 if(bootverbose) { 399 printf("%s: Using %s Interrupts\n", 400 ahc_name(ahc), 401 ahc->pause & IRQMS ? "Level Sensitive" : "Edge Triggered"); 402 } 403 404 /* 405 * Now that we know we own the resources we need, do the 406 * card initialization. 407 * 408 * First, the aic7770 card specific setup. 409 */ 410 switch( ahc->type ) { 411 case AHC_AIC7770: 412 case AHC_274: 413 { 414 u_char biosctrl = AHC_INB(ahc, HA_274_BIOSCTRL); 415 416 /* Get the primary channel information */ 417 ahc->flags |= (biosctrl & CHANNEL_B_PRIMARY); 418 419 if((biosctrl & BIOSMODE) == BIOSDISABLED) 420 ahc->flags |= AHC_USEDEFAULTS; 421 break; 422 } 423 case AHC_284: 424 { 425 /* XXX 426 * All values are automagically intialized at 427 * POST for these cards, so we can always rely 428 * on the Scratch Ram values. However, we should 429 * read the SEEPROM here (Dan has the code to do 430 * it) so we can say what kind of translation the 431 * BIOS is using. Printing out the geometry could 432 * save a lot of users the grief of failed installs. 433 */ 434 break; 435 } 436 default: 437 break; 438 } 439 440 /* 441 * See if we have a Rev E or higher aic7770. Anything below a 442 * Rev E will have a R/O autoflush disable configuration bit. 443 * It's still not clear exactly what is differenent about the Rev E. 444 * We think it allows 8 bit entries in the QOUTFIFO to support 445 * "paging" SCBs so you can have more than 4 commands active at 446 * once. 447 */ 448 { 449 char *id_string; 450 u_char sblkctl; 451 u_char sblkctl_orig; 452 453 sblkctl_orig = AHC_INB(ahc, SBLKCTL); 454 sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; 455 AHC_OUTB(ahc, SBLKCTL, sblkctl); 456 sblkctl = AHC_INB(ahc, SBLKCTL); 457 if(sblkctl != sblkctl_orig) 458 { 459 id_string = "aic7770 >= Rev E, "; 460 /* 461 * Ensure autoflush is enabled 462 */ 463 sblkctl &= ~AUTOFLUSHDIS; 464 AHC_OUTB(ahc, SBLKCTL, sblkctl); 465 466 /* Allow paging on this adapter */ 467 ahc->flags |= AHC_PAGESCBS; 468 } 469 else 470 id_string = "aic7770 <= Rev C, "; 471 472 printf("%s: %s", ahc_name(ahc), id_string); 473 } 474 475 /* Setup the FIFO threshold and the bus off time */ 476 { 477 u_char hostconf = AHC_INB(ahc, HOSTCONF); 478 AHC_OUTB(ahc, BUSSPD, hostconf & DFTHRSH); 479 AHC_OUTB(ahc, BUSTIME, (hostconf << 2) & BOFF); 480 } 481 482 /* 483 * Generic aic7xxx initialization. 484 */ 485 if(ahc_init(ahc)){ 486 #if defined(__FreeBSD__) 487 ahc_free(ahc); 488 /* 489 * The board's IRQ line is not yet enabled so it's safe 490 * to release the irq. 491 */ 492 eisa_release_intr(e_dev, irq, ahc_intr); 493 return -1; 494 #elif defined(__NetBSD__) 495 ahc_free(ahc); 496 return; 497 #endif 498 } 499 500 /* 501 * Enable the board's BUS drivers 502 */ 503 AHC_OUTB(ahc, BCTL, ENABLE); 504 505 #if defined(__FreeBSD__) 506 /* 507 * Enable our interrupt handler. 508 */ 509 if(eisa_enable_intr(e_dev, irq)) { 510 ahc_free(ahc); 511 eisa_release_intr(e_dev, irq, ahc_intr); 512 return -1; 513 } 514 515 e_dev->kdc->kdc_state = DC_BUSY; /* host adapters always busy */ 516 #elif defined(__NetBSD__) 517 intrstr = eisa_intr_string(ec, ih); 518 /* 519 * The IRQMS bit enables level sensitive interrupts only allow 520 * IRQ sharing if its set. 521 */ 522 ahc->sc_ih = eisa_intr_establish(ec, ih, 523 ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, ahc_intr, ahc); 524 if (ahc->sc_ih == NULL) { 525 printf("%s: couldn't establish interrupt", 526 ahc->sc_dev.dv_xname); 527 if (intrstr != NULL) 528 printf(" at %s", intrstr); 529 printf("\n"); 530 ahc_free(ahc); 531 return; 532 } 533 if (intrstr != NULL) 534 printf("%s: interrupting at %s\n", ahc->sc_dev.dv_xname, 535 intrstr); 536 #endif /* defined(__NetBSD__) */ 537 538 /* Attach sub-devices - always succeeds */ 539 ahc_attach(ahc); 540 541 #if defined(__FreeBSD__) 542 return 0; 543 #endif 544 } 545 546 #endif /* NEISA > 0 */ 547