1 /* $NetBSD: aic7xxx_seeprom.c,v 1.6 2001/11/13 13:14:34 lukem Exp $ */ 2 3 /* 4 * Product specific probe and attach routines for: 5 * 3940, 2940, aic7895, aic7890, aic7880, 6 * aic7870, aic7860 and aic7850 SCSI controllers 7 * 8 * These are the SEEPROM-reading functions only. They were split off from 9 * the PCI-specific support by Jason R. Thorpe <thorpej@netbsd.org>. 10 * 11 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. 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. 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 * Alternatively, this software may be distributed under the terms of the 24 * the GNU Public License ("GPL"). 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * $FreeBSD: src/sys/dev/aic7xxx/ahc_pci.c,v 1.27 2000/01/10 01:47:51 gibbs Exp 39 $ 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: aic7xxx_seeprom.c,v 1.6 2001/11/13 13:14:34 lukem Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/malloc.h> 48 #include <sys/kernel.h> 49 #include <sys/queue.h> 50 #include <sys/device.h> 51 #include <sys/reboot.h> /* for AB_* needed by bootverbose */ 52 53 #include <machine/bus.h> 54 #include <machine/intr.h> 55 56 #include <dev/scsipi/scsi_all.h> 57 #include <dev/scsipi/scsipi_all.h> 58 #include <dev/scsipi/scsiconf.h> 59 60 #include <dev/microcode/aic7xxx/aic7xxx_reg.h> 61 #include <dev/ic/aic7xxxvar.h> 62 #include <dev/ic/smc93cx6var.h> 63 64 static void configure_termination(struct ahc_softc *, 65 struct seeprom_descriptor *, u_int, u_int *); 66 67 static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *, 68 int *, int *); 69 static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *, 70 int *); 71 static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *); 72 static int acquire_seeprom(struct ahc_softc *, struct seeprom_descriptor *); 73 static void release_seeprom(struct seeprom_descriptor *); 74 static void write_brdctl(struct ahc_softc *, u_int8_t); 75 static u_int8_t read_brdctl(struct ahc_softc *); 76 77 /* 78 * Check the external port logic for a serial eeprom 79 * and termination/cable detection contrls. 80 */ 81 void 82 check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) 83 { 84 struct seeprom_descriptor sd; 85 struct seeprom_config sc; 86 u_int scsi_conf; 87 u_int adapter_control; 88 int have_seeprom; 89 int have_autoterm; 90 91 sd.sd_tag = ahc->tag; 92 sd.sd_bsh = ahc->bsh; 93 sd.sd_control_offset = SEECTL; 94 sd.sd_status_offset = SEECTL; 95 sd.sd_dataout_offset = SEECTL; 96 97 /* 98 * For some multi-channel devices, the c46 is simply too 99 * small to work. For the other controller types, we can 100 * get our information from either SEEPROM type. Set the 101 * type to start our probe with accordingly. 102 */ 103 if (ahc->flags & AHC_LARGE_SEEPROM) 104 sd.sd_chip = C56_66; 105 else 106 sd.sd_chip = C46; 107 108 sd.sd_MS = SEEMS; 109 sd.sd_RDY = SEERDY; 110 sd.sd_CS = SEECS; 111 sd.sd_CK = SEECK; 112 sd.sd_DO = SEEDO; 113 sd.sd_DI = SEEDI; 114 115 have_seeprom = acquire_seeprom(ahc, &sd); 116 if (have_seeprom) { 117 118 if (bootverbose) 119 printf("%s: Reading SEEPROM...", ahc_name(ahc)); 120 121 for (;;) { 122 bus_size_t start_addr; 123 124 start_addr = 32 * (ahc->channel - 'A'); 125 126 have_seeprom = read_seeprom(&sd, (u_int16_t *)&sc, 127 start_addr, sizeof(sc)/2); 128 129 if (have_seeprom) { 130 /* Check checksum */ 131 int i; 132 int maxaddr; 133 u_int32_t checksum; 134 u_int16_t *scarray; 135 136 maxaddr = (sizeof(sc)/2) - 1; 137 checksum = 0; 138 scarray = (u_int16_t *)≻ 139 140 for (i = 0; i < maxaddr; i++) 141 checksum = checksum + scarray[i]; 142 if (checksum == 0 143 || (checksum & 0xFFFF) != sc.checksum) { 144 if (bootverbose && sd.sd_chip == C56_66) 145 printf ("checksum error\n"); 146 have_seeprom = 0; 147 } else { 148 if (bootverbose) 149 printf("done.\n"); 150 break; 151 } 152 } 153 154 if (sd.sd_chip == C56_66) 155 break; 156 sd.sd_chip = C56_66; 157 } 158 } 159 160 if (!have_seeprom) { 161 if (bootverbose) 162 printf("%s: No SEEPROM available\n", ahc_name(ahc)); 163 ahc->flags |= AHC_USEDEFAULTS; 164 } else { 165 /* 166 * Put the data we've collected down into SRAM 167 * where ahc_init will find it. 168 */ 169 int i; 170 int max_targ = sc.max_targets & CFMAXTARG; 171 u_int16_t discenable; 172 u_int16_t ultraenb; 173 174 discenable = 0; 175 ultraenb = 0; 176 if ((sc.adapter_control & CFULTRAEN) != 0) { 177 /* 178 * Determine if this adapter has a "newstyle" 179 * SEEPROM format. 180 */ 181 for (i = 0; i < max_targ; i++) { 182 if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0){ 183 ahc->flags |= AHC_NEWEEPROM_FMT; 184 break; 185 } 186 } 187 } 188 189 for (i = 0; i < max_targ; i++) { 190 u_int scsirate; 191 u_int16_t target_mask; 192 193 target_mask = 0x01 << i; 194 if (sc.device_flags[i] & CFDISC) 195 discenable |= target_mask; 196 if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) { 197 if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0) 198 ultraenb |= target_mask; 199 } else if ((sc.adapter_control & CFULTRAEN) != 0) { 200 ultraenb |= target_mask; 201 } 202 if ((sc.device_flags[i] & CFXFER) == 0x04 203 && (ultraenb & target_mask) != 0) { 204 /* Treat 10MHz as a non-ultra speed */ 205 sc.device_flags[i] &= ~CFXFER; 206 ultraenb &= ~target_mask; 207 } 208 if ((ahc->features & AHC_ULTRA2) != 0) { 209 u_int offset; 210 211 if (sc.device_flags[i] & CFSYNCH) 212 offset = MAX_OFFSET_ULTRA2; 213 else 214 offset = 0; 215 ahc_outb(ahc, TARG_OFFSET + i, offset); 216 217 scsirate = (sc.device_flags[i] & CFXFER) 218 | ((ultraenb & target_mask) 219 ? 0x8 : 0x0); 220 if (sc.device_flags[i] & CFWIDEB) 221 scsirate |= WIDEXFER; 222 } else { 223 scsirate = (sc.device_flags[i] & CFXFER) << 4; 224 if (sc.device_flags[i] & CFSYNCH) 225 scsirate |= SOFS; 226 if (sc.device_flags[i] & CFWIDEB) 227 scsirate |= WIDEXFER; 228 } 229 ahc_outb(ahc, TARG_SCSIRATE + i, scsirate); 230 } 231 ahc->our_id = sc.brtime_id & CFSCSIID; 232 233 scsi_conf = (ahc->our_id & 0x7); 234 if (sc.adapter_control & CFSPARITY) 235 scsi_conf |= ENSPCHK; 236 if (sc.adapter_control & CFRESETB) 237 scsi_conf |= RESET_SCSI; 238 239 if (sc.bios_control & CFEXTEND) 240 ahc->flags |= AHC_EXTENDED_TRANS_A; 241 if (ahc->features & AHC_ULTRA 242 && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) { 243 /* Should we enable Ultra mode? */ 244 if (!(sc.adapter_control & CFULTRAEN)) 245 /* Treat us as a non-ultra card */ 246 ultraenb = 0; 247 } 248 /* Set SCSICONF info */ 249 ahc_outb(ahc, SCSICONF, scsi_conf); 250 ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); 251 ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); 252 ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff); 253 ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff); 254 } 255 256 /* 257 * Cards that have the external logic necessary to talk to 258 * a SEEPROM, are almost certain to have the remaining logic 259 * necessary for auto-termination control. This assumption 260 * hasn't failed yet... 261 */ 262 have_autoterm = have_seeprom; 263 if (have_seeprom) 264 adapter_control = sc.adapter_control; 265 else 266 adapter_control = CFAUTOTERM; 267 268 /* 269 * Some low-cost chips have SEEPROM and auto-term control built 270 * in, instead of using a GAL. They can tell us directly 271 * if the termination logic is enabled. 272 */ 273 if ((ahc->features & AHC_SPIOCAP) != 0) { 274 if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0) 275 have_autoterm = TRUE; 276 else 277 have_autoterm = FALSE; 278 } 279 280 if (have_autoterm) 281 configure_termination(ahc, &sd, adapter_control, sxfrctl1); 282 283 release_seeprom(&sd); 284 } 285 286 static void 287 configure_termination(struct ahc_softc *ahc, 288 struct seeprom_descriptor *sd, 289 u_int adapter_control, 290 u_int *sxfrctl1) 291 { 292 u_int8_t brddat; 293 294 brddat = 0; 295 296 /* 297 * Update the settings in sxfrctl1 to match the 298 * termination settings 299 */ 300 *sxfrctl1 = 0; 301 302 /* 303 * SEECS must be on for the GALS to latch 304 * the data properly. Be sure to leave MS 305 * on or we will release the seeprom. 306 */ 307 SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); 308 if ((adapter_control & CFAUTOTERM) != 0 309 || (ahc->features & AHC_NEW_TERMCTL) != 0) { 310 int internal50_present; 311 int internal68_present; 312 int externalcable_present; 313 int eeprom_present; 314 int enableSEC_low; 315 int enableSEC_high; 316 int enablePRI_low; 317 int enablePRI_high; 318 319 enableSEC_low = 0; 320 enableSEC_high = 0; 321 enablePRI_low = 0; 322 enablePRI_high = 0; 323 if ((ahc->features & AHC_NEW_TERMCTL) != 0) { 324 ahc_new_term_detect(ahc, &enableSEC_low, 325 &enableSEC_high, 326 &enablePRI_low, 327 &enablePRI_high, 328 &eeprom_present); 329 if ((adapter_control & CFSEAUTOTERM) == 0) { 330 if (bootverbose) 331 printf("%s: Manual SE Termination\n", 332 ahc_name(ahc)); 333 enableSEC_low = (adapter_control & CFSTERM); 334 enableSEC_high = (adapter_control & CFWSTERM); 335 } 336 if ((adapter_control & CFAUTOTERM) == 0) { 337 if (bootverbose) 338 printf("%s: Manual LVD Termination\n", 339 ahc_name(ahc)); 340 enablePRI_low = enablePRI_high = 341 (adapter_control & CFLVDSTERM); 342 } 343 /* Make the table calculations below happy */ 344 internal50_present = 0; 345 internal68_present = 1; 346 externalcable_present = 1; 347 } else if ((ahc->features & AHC_SPIOCAP) != 0) { 348 aic785X_cable_detect(ahc, &internal50_present, 349 &externalcable_present, 350 &eeprom_present); 351 } else { 352 aic787X_cable_detect(ahc, &internal50_present, 353 &internal68_present, 354 &externalcable_present, 355 &eeprom_present); 356 } 357 358 if ((ahc->features & AHC_WIDE) == 0) 359 internal68_present = 0; 360 361 if (bootverbose) { 362 if ((ahc->features & AHC_ULTRA2) == 0) { 363 printf("%s: internal 50 cable %s present, " 364 "internal 68 cable %s present\n", 365 ahc_name(ahc), 366 internal50_present ? "is":"not", 367 internal68_present ? "is":"not"); 368 369 printf("%s: external cable %s present\n", 370 ahc_name(ahc), 371 externalcable_present ? "is":"not"); 372 } 373 printf("%s: BIOS eeprom %s present\n", 374 ahc_name(ahc), eeprom_present ? "is" : "not"); 375 } 376 377 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { 378 /* 379 * The 50 pin connector is a separate bus, 380 * so force it to always be terminated. 381 * In the future, perform current sensing 382 * to determine if we are in the middle of 383 * a properly terminated bus. 384 */ 385 internal50_present = 0; 386 } 387 388 /* 389 * Now set the termination based on what 390 * we found. 391 * Flash Enable = BRDDAT7 392 * Secondary High Term Enable = BRDDAT6 393 * Secondary Low Term Enable = BRDDAT5 (7890) 394 * Primary High Term Enable = BRDDAT4 (7890) 395 */ 396 if ((ahc->features & AHC_ULTRA2) == 0 397 && (internal50_present != 0) 398 && (internal68_present != 0) 399 && (externalcable_present != 0)) { 400 printf("%s: Illegal cable configuration!!. " 401 "Only two connectors on the " 402 "adapter may be used at a " 403 "time!\n", ahc_name(ahc)); 404 } 405 406 if ((ahc->features & AHC_WIDE) != 0 407 && ((externalcable_present == 0) 408 || (internal68_present == 0) 409 || (enableSEC_high != 0))) { 410 brddat |= BRDDAT6; 411 if (bootverbose) { 412 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) 413 printf("%s: 68 pin termination " 414 "Enabled\n", ahc_name(ahc)); 415 else 416 printf("%s: %sHigh byte termination " 417 "Enabled\n", ahc_name(ahc), 418 enableSEC_high ? "Secondary " 419 : ""); 420 } 421 } 422 423 if (((internal50_present ? 1 : 0) 424 + (internal68_present ? 1 : 0) 425 + (externalcable_present ? 1 : 0)) <= 1 426 || (enableSEC_low != 0)) { 427 if ((ahc->features & AHC_ULTRA2) != 0) 428 brddat |= BRDDAT5; 429 else 430 *sxfrctl1 |= STPWEN; 431 if (bootverbose) { 432 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) 433 printf("%s: 50 pin termination " 434 "Enabled\n", ahc_name(ahc)); 435 else 436 printf("%s: %sLow byte termination " 437 "Enabled\n", ahc_name(ahc), 438 enableSEC_low ? "Secondary " 439 : ""); 440 } 441 } 442 443 if (enablePRI_low != 0) { 444 *sxfrctl1 |= STPWEN; 445 if (bootverbose) 446 printf("%s: Primary Low Byte termination " 447 "Enabled\n", ahc_name(ahc)); 448 } 449 450 /* 451 * Setup STPWEN before setting up the rest of 452 * the termination per the tech note on the U160 cards. 453 */ 454 ahc_outb(ahc, SXFRCTL1, *sxfrctl1); 455 456 if (enablePRI_high != 0) { 457 brddat |= BRDDAT4; 458 if (bootverbose) 459 printf("%s: Primary High Byte " 460 "termination Enabled\n", 461 ahc_name(ahc)); 462 } 463 464 write_brdctl(ahc, brddat); 465 466 } else { 467 if ((adapter_control & CFSTERM) != 0) { 468 *sxfrctl1 |= STPWEN; 469 470 if (bootverbose) 471 printf("%s: %sLow byte termination Enabled\n", 472 ahc_name(ahc), 473 (ahc->features & AHC_ULTRA2) ? "Primary " 474 : ""); 475 } 476 477 if ((adapter_control & CFWSTERM) != 0) { 478 brddat |= BRDDAT6; 479 if (bootverbose) 480 printf("%s: %sHigh byte termination Enabled\n", 481 ahc_name(ahc), 482 (ahc->features & AHC_ULTRA2) 483 ? "Secondary " : ""); 484 } 485 486 /* 487 * Setup STPWEN before setting up the rest of 488 * the termination per the tech note on the U160 cards. 489 */ 490 ahc_outb(ahc, SXFRCTL1, *sxfrctl1); 491 492 write_brdctl(ahc, brddat); 493 } 494 SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */ 495 } 496 497 static void 498 ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low, 499 int *enableSEC_high, int *enablePRI_low, 500 int *enablePRI_high, int *eeprom_present) 501 { 502 u_int8_t brdctl; 503 504 /* 505 * BRDDAT7 = Eeprom 506 * BRDDAT6 = Enable Secondary High Byte termination 507 * BRDDAT5 = Enable Secondary Low Byte termination 508 * BRDDAT4 = Enable Primary high byte termination 509 * BRDDAT3 = Enable Primary low byte termination 510 */ 511 brdctl = read_brdctl(ahc); 512 *eeprom_present = brdctl & BRDDAT7; 513 *enableSEC_high = (brdctl & BRDDAT6); 514 *enableSEC_low = (brdctl & BRDDAT5); 515 *enablePRI_high = (brdctl & BRDDAT4); 516 *enablePRI_low = (brdctl & BRDDAT3); 517 } 518 519 static void 520 aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, 521 int *internal68_present, int *externalcable_present, 522 int *eeprom_present) 523 { 524 u_int8_t brdctl; 525 526 /* 527 * First read the status of our cables. 528 * Set the rom bank to 0 since the 529 * bank setting serves as a multiplexor 530 * for the cable detection logic. 531 * BRDDAT5 controls the bank switch. 532 */ 533 write_brdctl(ahc, 0); 534 535 /* 536 * Now read the state of the internal 537 * connectors. BRDDAT6 is INT50 and 538 * BRDDAT7 is INT68. 539 */ 540 brdctl = read_brdctl(ahc); 541 *internal50_present = !(brdctl & BRDDAT6); 542 *internal68_present = !(brdctl & BRDDAT7); 543 544 /* 545 * Set the rom bank to 1 and determine 546 * the other signals. 547 */ 548 write_brdctl(ahc, BRDDAT5); 549 550 /* 551 * Now read the state of the external 552 * connectors. BRDDAT6 is EXT68 and 553 * BRDDAT7 is EPROMPS. 554 */ 555 brdctl = read_brdctl(ahc); 556 *externalcable_present = !(brdctl & BRDDAT6); 557 *eeprom_present = brdctl & BRDDAT7; 558 } 559 560 static void 561 aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, 562 int *externalcable_present, int *eeprom_present) 563 { 564 u_int8_t brdctl; 565 566 ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); 567 ahc_outb(ahc, BRDCTL, 0); 568 brdctl = ahc_inb(ahc, BRDCTL); 569 *internal50_present = !(brdctl & BRDDAT5); 570 *externalcable_present = !(brdctl & BRDDAT6); 571 572 *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) != 0; 573 } 574 575 static int 576 acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) 577 { 578 int wait; 579 580 if ((ahc->features & AHC_SPIOCAP) != 0 581 && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0) 582 return (0); 583 584 /* 585 * Request access of the memory port. When access is 586 * granted, SEERDY will go high. We use a 100 msec 587 * timeout which should be near 100 msecs more than 588 * is needed. Reason: after the chip reset, there 589 * should be no contention. 590 */ 591 SEEPROM_OUTB(sd, sd->sd_MS); 592 wait = 100; /* 100 msec timeout */ 593 while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) { 594 DELAY(1000); /* delay 1 msec */ 595 } 596 if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) { 597 SEEPROM_OUTB(sd, 0); 598 return (0); 599 } 600 return(1); 601 } 602 603 static void 604 release_seeprom(struct seeprom_descriptor *sd) 605 { 606 /* Release access to the memory port and the serial EEPROM. */ 607 SEEPROM_OUTB(sd, 0); 608 } 609 610 static void 611 write_brdctl(struct ahc_softc *ahc, u_int8_t value) 612 { 613 u_int8_t brdctl; 614 615 if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { 616 brdctl = BRDSTB; 617 if (ahc->channel == 'B') 618 brdctl |= BRDCS; 619 } else if ((ahc->features & AHC_ULTRA2) != 0) { 620 brdctl = 0; 621 } else { 622 brdctl = BRDSTB|BRDCS; 623 } 624 ahc_outb(ahc, BRDCTL, brdctl); 625 DELAY(20); 626 brdctl |= value; 627 ahc_outb(ahc, BRDCTL, brdctl); 628 DELAY(20); 629 if ((ahc->features & AHC_ULTRA2) != 0) 630 brdctl |= BRDSTB_ULTRA2; 631 else 632 brdctl &= ~BRDSTB; 633 ahc_outb(ahc, BRDCTL, brdctl); 634 DELAY(20); 635 if ((ahc->features & AHC_ULTRA2) != 0) 636 brdctl = 0; 637 else 638 brdctl &= ~BRDCS; 639 ahc_outb(ahc, BRDCTL, brdctl); 640 } 641 642 static u_int8_t 643 read_brdctl(struct ahc_softc *ahc) 644 { 645 u_int8_t brdctl; 646 u_int8_t value; 647 648 if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { 649 brdctl = BRDRW; 650 if (ahc->channel == 'B') 651 brdctl |= BRDCS; 652 } else if ((ahc->features & AHC_ULTRA2) != 0) { 653 brdctl = BRDRW_ULTRA2; 654 } else { 655 brdctl = BRDRW|BRDCS; 656 } 657 ahc_outb(ahc, BRDCTL, brdctl); 658 DELAY(20); 659 value = ahc_inb(ahc, BRDCTL); 660 ahc_outb(ahc, BRDCTL, 0); 661 return (value); 662 } 663