1 /* $OpenBSD: aic7xxx_seeprom.c,v 1.10 2024/09/01 03:08:56 jsg Exp $ */ 2 /* $NetBSD: aic7xxx_seeprom.c,v 1.8 2003/05/02 19:12:19 dyoung Exp $ */ 3 4 /* 5 * Product specific probe and attach routines for: 6 * 3940, 2940, aic7895, aic7890, aic7880, 7 * aic7870, aic7860 and aic7850 SCSI controllers 8 * 9 * Copyright (c) 1994-2001 Justin T. Gibbs. 10 * Copyright (c) 2000-2001 Adaptec Inc. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions, and the following disclaimer, 18 * without modification. 19 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 20 * substantially similar to the "NO WARRANTY" disclaimer below 21 * ("Disclaimer") and any redistribution must be conditioned upon 22 * including a substantially similar Disclaimer requirement for further 23 * binary redistribution. 24 * 3. Neither the names of the above-listed copyright holders nor the names 25 * of any contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * Alternatively, this software may be distributed under the terms of the 29 * GNU General Public License ("GPL") version 2 as published by the Free 30 * Software Foundation. 31 * 32 * NO WARRANTY 33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 34 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 35 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 36 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 37 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 42 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 * POSSIBILITY OF SUCH DAMAGES. 44 * 45 * This file was originally split off from the PCI code by 46 * Jason Thorpe <thorpej@netbsd.org>. This version was split off 47 * from the FreeBSD source file aic7xxx_pci.c by Frank van der Linden 48 * <fvdl@netbsd.org> 49 * 50 * $Id: aic7xxx_seeprom.c,v 1.10 2024/09/01 03:08:56 jsg Exp $ 51 * 52 * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $ 53 */ 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/malloc.h> 58 #include <sys/kernel.h> 59 #include <sys/queue.h> 60 #include <sys/device.h> 61 #include <sys/reboot.h> /* for AB_* needed by bootverbose */ 62 63 #include <machine/intr.h> 64 65 #include <scsi/scsi_all.h> 66 #include <scsi/scsiconf.h> 67 68 #include <dev/ic/aic7xxx_openbsd.h> 69 #include <dev/ic/aic7xxx_inline.h> 70 71 #include <dev/ic/smc93cx6var.h> 72 73 #define DEVCONFIG 0x40 74 #define STPWLEVEL 0x00000002 75 76 static void configure_termination(struct ahc_softc *, 77 struct seeprom_descriptor *, u_int, u_int *); 78 static int verify_seeprom_cksum(struct seeprom_config *sc); 79 80 static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *, 81 int *, int *); 82 static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *, 83 int *); 84 static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *); 85 static void write_brdctl(struct ahc_softc *, u_int8_t); 86 static u_int8_t read_brdctl(struct ahc_softc *); 87 static void ahc_parse_pci_eeprom(struct ahc_softc *, struct seeprom_config *); 88 89 /* 90 * Check the external port logic for a serial eeprom 91 * and termination/cable detection controls. 92 */ 93 void 94 ahc_check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) 95 { 96 struct seeprom_descriptor sd; 97 struct seeprom_config *sc; 98 int have_seeprom; 99 int have_autoterm; 100 101 sd.sd_tag = ahc->tag; 102 sd.sd_bsh = ahc->bsh; 103 sd.sd_regsize = 1; 104 sd.sd_control_offset = SEECTL; 105 sd.sd_status_offset = SEECTL; 106 sd.sd_dataout_offset = SEECTL; 107 sc = ahc->seep_config; 108 109 /* 110 * For some multi-channel devices, the c46 is simply too 111 * small to work. For the other controller types, we can 112 * get our information from either SEEPROM type. Set the 113 * type to start our probe with accordingly. 114 */ 115 if (ahc->flags & AHC_LARGE_SEEPROM) 116 sd.sd_chip = C56_66; 117 else 118 sd.sd_chip = C46; 119 120 sd.sd_MS = SEEMS; 121 sd.sd_RDY = SEERDY; 122 sd.sd_CS = SEECS; 123 sd.sd_CK = SEECK; 124 sd.sd_DO = SEEDO; 125 sd.sd_DI = SEEDI; 126 127 have_seeprom = ahc_acquire_seeprom(ahc, &sd); 128 if (have_seeprom) { 129 130 if (bootverbose) 131 printf("%s: Reading SEEPROM...", ahc_name(ahc)); 132 133 for (;;) { 134 u_int start_addr; 135 136 start_addr = 32 * (ahc->channel - 'A'); 137 have_seeprom = read_seeprom(&sd, (uint16_t *)sc, 138 start_addr, 139 sizeof(*sc)/2); 140 141 if (have_seeprom) 142 have_seeprom = verify_seeprom_cksum(sc); 143 144 if (have_seeprom != 0 || sd.sd_chip == C56_66) { 145 if (bootverbose) { 146 if (have_seeprom == 0) 147 printf ("checksum error\n"); 148 else 149 printf ("done.\n"); 150 } 151 break; 152 } 153 sd.sd_chip = C56_66; 154 } 155 ahc_release_seeprom(&sd); 156 } 157 158 if (!have_seeprom) { 159 /* 160 * Pull scratch ram settings and treat them as 161 * if they are the contents of an seeprom if 162 * the 'ADPT' signature is found in SCB2. 163 * We manually compose the data as 16bit values 164 * to avoid endian issues. 165 */ 166 ahc_outb(ahc, SCBPTR, 2); 167 if (ahc_inb(ahc, SCB_BASE) == 'A' 168 && ahc_inb(ahc, SCB_BASE + 1) == 'D' 169 && ahc_inb(ahc, SCB_BASE + 2) == 'P' 170 && ahc_inb(ahc, SCB_BASE + 3) == 'T') { 171 uint16_t *sc_data; 172 int i; 173 174 sc_data = (uint16_t *)sc; 175 for (i = 0; i < 32; i++, sc_data++) { 176 int j; 177 178 j = i * 2; 179 *sc_data = ahc_inb(ahc, SRAM_BASE + j) 180 | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; 181 } 182 have_seeprom = verify_seeprom_cksum(sc); 183 if (have_seeprom) 184 ahc->flags |= AHC_SCB_CONFIG_USED; 185 } 186 /* 187 * Clear any SCB parity errors in case this data and 188 * its associated parity was not initialized by the BIOS 189 */ 190 ahc_outb(ahc, CLRINT, CLRPARERR); 191 ahc_outb(ahc, CLRINT, CLRBRKADRINT); 192 } 193 194 if (!have_seeprom) { 195 if (bootverbose) 196 printf("%s: No SEEPROM available.\n", ahc_name(ahc)); 197 ahc->flags |= AHC_USEDEFAULTS | AHC_NO_BIOS_INIT; 198 free(ahc->seep_config, M_DEVBUF, sizeof(*ahc->seep_config)); 199 ahc->seep_config = NULL; 200 sc = NULL; 201 } else { 202 ahc_parse_pci_eeprom(ahc, sc); 203 } 204 205 /* 206 * Cards that have the external logic necessary to talk to 207 * a SEEPROM, are almost certain to have the remaining logic 208 * necessary for auto-termination control. This assumption 209 * hasn't failed yet... 210 */ 211 have_autoterm = have_seeprom; 212 213 /* 214 * Some low-cost chips have SEEPROM and auto-term control built 215 * in, instead of using a GAL. They can tell us directly 216 * if the termination logic is enabled. 217 */ 218 if ((ahc->features & AHC_SPIOCAP) != 0) { 219 if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0) 220 have_autoterm = FALSE; 221 } 222 223 if (have_autoterm) { 224 ahc_acquire_seeprom(ahc, &sd); 225 configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1); 226 ahc_release_seeprom(&sd); 227 } else if (have_seeprom) { 228 *sxfrctl1 &= ~STPWEN; 229 if ((sc->adapter_control & CFSTERM) != 0) 230 *sxfrctl1 |= STPWEN; 231 if (bootverbose) 232 printf("%s: Low byte termination %sabled\n", 233 ahc_name(ahc), 234 (*sxfrctl1 & STPWEN) ? "en" : "dis"); 235 } 236 } 237 238 static void 239 ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc) 240 { 241 /* 242 * Put the data we've collected down into SRAM 243 * where ahc_init will find it. 244 */ 245 int i; 246 int max_targ = sc->max_targets & CFMAXTARG; 247 u_int scsi_conf; 248 uint16_t discenable; 249 uint16_t ultraenb; 250 251 discenable = 0; 252 ultraenb = 0; 253 if ((sc->adapter_control & CFULTRAEN) != 0) { 254 /* 255 * Determine if this adapter has a "newstyle" 256 * SEEPROM format. 257 */ 258 for (i = 0; i < max_targ; i++) { 259 if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) { 260 ahc->flags |= AHC_NEWEEPROM_FMT; 261 break; 262 } 263 } 264 } 265 266 for (i = 0; i < max_targ; i++) { 267 u_int scsirate; 268 uint16_t target_mask; 269 270 target_mask = 0x01 << i; 271 if (sc->device_flags[i] & CFDISC) 272 discenable |= target_mask; 273 if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) { 274 if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) 275 ultraenb |= target_mask; 276 } else if ((sc->adapter_control & CFULTRAEN) != 0) { 277 ultraenb |= target_mask; 278 } 279 if ((sc->device_flags[i] & CFXFER) == 0x04 280 && (ultraenb & target_mask) != 0) { 281 /* Treat 10MHz as a non-ultra speed */ 282 sc->device_flags[i] &= ~CFXFER; 283 ultraenb &= ~target_mask; 284 } 285 if ((ahc->features & AHC_ULTRA2) != 0) { 286 u_int offset; 287 288 if (sc->device_flags[i] & CFSYNCH) 289 offset = MAX_OFFSET_ULTRA2; 290 else 291 offset = 0; 292 ahc_outb(ahc, TARG_OFFSET + i, offset); 293 294 /* 295 * The ultra enable bits contain the 296 * high bit of the ultra2 sync rate 297 * field. 298 */ 299 scsirate = (sc->device_flags[i] & CFXFER) 300 | ((ultraenb & target_mask) ? 0x8 : 0x0); 301 if (sc->device_flags[i] & CFWIDEB) 302 scsirate |= WIDEXFER; 303 } else { 304 scsirate = (sc->device_flags[i] & CFXFER) << 4; 305 if (sc->device_flags[i] & CFSYNCH) 306 scsirate |= SOFS; 307 if (sc->device_flags[i] & CFWIDEB) 308 scsirate |= WIDEXFER; 309 } 310 ahc_outb(ahc, TARG_SCSIRATE + i, scsirate); 311 } 312 ahc->our_id = sc->brtime_id & CFSCSIID; 313 314 scsi_conf = (ahc->our_id & 0x7); 315 if (sc->adapter_control & CFSPARITY) 316 scsi_conf |= ENSPCHK; 317 if (sc->adapter_control & CFRESETB) 318 scsi_conf |= RESET_SCSI; 319 320 ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; 321 322 if (sc->bios_control & CFEXTEND) 323 ahc->flags |= AHC_EXTENDED_TRANS_A; 324 325 if (sc->bios_control & CFBIOSEN) 326 ahc->flags |= AHC_BIOS_ENABLED; 327 if (ahc->features & AHC_ULTRA 328 && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) { 329 /* Should we enable Ultra mode? */ 330 if (!(sc->adapter_control & CFULTRAEN)) 331 /* Treat us as a non-ultra card */ 332 ultraenb = 0; 333 } 334 335 if (sc->signature == CFSIGNATURE 336 || sc->signature == CFSIGNATURE2) { 337 uint32_t devconfig; 338 339 /* Honor the STPWLEVEL settings */ 340 devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG); 341 devconfig &= ~STPWLEVEL; 342 if ((sc->bios_control & CFSTPWLEVEL) != 0) 343 devconfig |= STPWLEVEL; 344 pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig); 345 } 346 /* Set SCSICONF info */ 347 ahc_outb(ahc, SCSICONF, scsi_conf); 348 ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); 349 ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); 350 ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff); 351 ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff); 352 } 353 354 static void 355 configure_termination(struct ahc_softc *ahc, 356 struct seeprom_descriptor *sd, 357 u_int adapter_control, 358 u_int *sxfrctl1) 359 { 360 uint8_t brddat; 361 362 brddat = 0; 363 364 /* 365 * Update the settings in sxfrctl1 to match the 366 * termination settings 367 */ 368 *sxfrctl1 = 0; 369 370 /* 371 * SEECS must be on for the GALS to latch 372 * the data properly. Be sure to leave MS 373 * on or we will release the seeprom. 374 */ 375 SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); 376 if ((adapter_control & CFAUTOTERM) != 0 377 || (ahc->features & AHC_NEW_TERMCTL) != 0) { 378 int internal50_present; 379 int internal68_present; 380 int externalcable_present; 381 int eeprom_present; 382 int enableSEC_low; 383 int enableSEC_high; 384 int enablePRI_low; 385 int enablePRI_high; 386 int sum; 387 388 enableSEC_low = 0; 389 enableSEC_high = 0; 390 enablePRI_low = 0; 391 enablePRI_high = 0; 392 if ((ahc->features & AHC_NEW_TERMCTL) != 0) { 393 ahc_new_term_detect(ahc, &enableSEC_low, 394 &enableSEC_high, 395 &enablePRI_low, 396 &enablePRI_high, 397 &eeprom_present); 398 if ((adapter_control & CFSEAUTOTERM) == 0) { 399 if (bootverbose) 400 printf("%s: Manual SE Termination\n", 401 ahc_name(ahc)); 402 enableSEC_low = (adapter_control & CFSELOWTERM); 403 enableSEC_high = 404 (adapter_control & CFSEHIGHTERM); 405 } 406 if ((adapter_control & CFAUTOTERM) == 0) { 407 if (bootverbose) 408 printf("%s: Manual LVD Termination\n", 409 ahc_name(ahc)); 410 enablePRI_low = (adapter_control & CFSTERM); 411 enablePRI_high = (adapter_control & CFWSTERM); 412 } 413 /* Make the table calculations below happy */ 414 internal50_present = 0; 415 internal68_present = 1; 416 externalcable_present = 1; 417 } else if ((ahc->features & AHC_SPIOCAP) != 0) { 418 aic785X_cable_detect(ahc, &internal50_present, 419 &externalcable_present, 420 &eeprom_present); 421 /* Can never support a wide connector. */ 422 internal68_present = 0; 423 } else { 424 aic787X_cable_detect(ahc, &internal50_present, 425 &internal68_present, 426 &externalcable_present, 427 &eeprom_present); 428 } 429 430 if ((ahc->features & AHC_WIDE) == 0) 431 internal68_present = 0; 432 433 if (bootverbose 434 && (ahc->features & AHC_ULTRA2) == 0) { 435 printf("%s: internal 50 cable %s present", 436 ahc_name(ahc), 437 internal50_present ? "is":"not"); 438 439 if ((ahc->features & AHC_WIDE) != 0) 440 printf(", internal 68 cable %s present", 441 internal68_present ? "is":"not"); 442 printf("\n%s: external cable %s present\n", 443 ahc_name(ahc), 444 externalcable_present ? "is":"not"); 445 } 446 if (bootverbose) 447 printf("%s: BIOS eeprom %s present\n", 448 ahc_name(ahc), eeprom_present ? "is" : "not"); 449 450 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { 451 /* 452 * The 50 pin connector is a separate bus, 453 * so force it to always be terminated. 454 * In the future, perform current sensing 455 * to determine if we are in the middle of 456 * a properly terminated bus. 457 */ 458 internal50_present = 0; 459 } 460 461 /* 462 * Now set the termination based on what 463 * we found. 464 * Flash Enable = BRDDAT7 465 * Secondary High Term Enable = BRDDAT6 466 * Secondary Low Term Enable = BRDDAT5 (7890) 467 * Primary High Term Enable = BRDDAT4 (7890) 468 */ 469 if ((ahc->features & AHC_ULTRA2) == 0 470 && (internal50_present != 0) 471 && (internal68_present != 0) 472 && (externalcable_present != 0)) { 473 printf("%s: Illegal cable configuration!!. " 474 "Only two connectors on the " 475 "adapter may be used at a " 476 "time!\n", ahc_name(ahc)); 477 478 /* 479 * Pretend there are no cables in the hope 480 * that having all of the termination on 481 * gives us a more stable bus. 482 */ 483 internal50_present = 0; 484 internal68_present = 0; 485 externalcable_present = 0; 486 } 487 488 if ((ahc->features & AHC_WIDE) != 0 489 && ((externalcable_present == 0) 490 || (internal68_present == 0) 491 || (enableSEC_high != 0))) { 492 brddat |= BRDDAT6; 493 if (bootverbose) { 494 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) 495 printf("%s: 68 pin termination " 496 "Enabled\n", ahc_name(ahc)); 497 else 498 printf("%s: %sHigh byte termination " 499 "Enabled\n", ahc_name(ahc), 500 enableSEC_high ? "Secondary " 501 : ""); 502 } 503 } 504 505 sum = internal50_present + internal68_present 506 + externalcable_present; 507 if (sum < 2 || (enableSEC_low != 0)) { 508 if ((ahc->features & AHC_ULTRA2) != 0) 509 brddat |= BRDDAT5; 510 else 511 *sxfrctl1 |= STPWEN; 512 if (bootverbose) { 513 if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) 514 printf("%s: 50 pin termination " 515 "Enabled\n", ahc_name(ahc)); 516 else 517 printf("%s: %sLow byte termination " 518 "Enabled\n", ahc_name(ahc), 519 enableSEC_low ? "Secondary " 520 : ""); 521 } 522 } 523 524 if (enablePRI_low != 0) { 525 *sxfrctl1 |= STPWEN; 526 if (bootverbose) 527 printf("%s: Primary Low Byte termination " 528 "Enabled\n", ahc_name(ahc)); 529 } 530 531 /* 532 * Setup STPWEN before setting up the rest of 533 * the termination per the tech note on the U160 cards. 534 */ 535 ahc_outb(ahc, SXFRCTL1, *sxfrctl1); 536 537 if (enablePRI_high != 0) { 538 brddat |= BRDDAT4; 539 if (bootverbose) 540 printf("%s: Primary High Byte " 541 "termination Enabled\n", 542 ahc_name(ahc)); 543 } 544 545 write_brdctl(ahc, brddat); 546 547 } else { 548 if ((adapter_control & CFSTERM) != 0) { 549 *sxfrctl1 |= STPWEN; 550 551 if (bootverbose) 552 printf("%s: %sLow byte termination Enabled\n", 553 ahc_name(ahc), 554 (ahc->features & AHC_ULTRA2) ? "Primary " 555 : ""); 556 } 557 558 if ((adapter_control & CFWSTERM) != 0 559 && (ahc->features & AHC_WIDE) != 0) { 560 brddat |= BRDDAT6; 561 if (bootverbose) 562 printf("%s: %sHigh byte termination Enabled\n", 563 ahc_name(ahc), 564 (ahc->features & AHC_ULTRA2) 565 ? "Secondary " : ""); 566 } 567 568 /* 569 * Setup STPWEN before setting up the rest of 570 * the termination per the tech note on the U160 cards. 571 */ 572 ahc_outb(ahc, SXFRCTL1, *sxfrctl1); 573 574 if ((ahc->features & AHC_WIDE) != 0) 575 write_brdctl(ahc, brddat); 576 } 577 SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */ 578 } 579 580 static void 581 ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low, 582 int *enableSEC_high, int *enablePRI_low, 583 int *enablePRI_high, int *eeprom_present) 584 { 585 uint8_t brdctl; 586 587 /* 588 * BRDDAT7 = Eeprom 589 * BRDDAT6 = Enable Secondary High Byte termination 590 * BRDDAT5 = Enable Secondary Low Byte termination 591 * BRDDAT4 = Enable Primary high byte termination 592 * BRDDAT3 = Enable Primary low byte termination 593 */ 594 brdctl = read_brdctl(ahc); 595 *eeprom_present = brdctl & BRDDAT7; 596 *enableSEC_high = (brdctl & BRDDAT6); 597 *enableSEC_low = (brdctl & BRDDAT5); 598 *enablePRI_high = (brdctl & BRDDAT4); 599 *enablePRI_low = (brdctl & BRDDAT3); 600 } 601 602 static void 603 aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, 604 int *internal68_present, int *externalcable_present, 605 int *eeprom_present) 606 { 607 uint8_t brdctl; 608 609 /* 610 * First read the status of our cables. 611 * Set the rom bank to 0 since the 612 * bank setting serves as a multiplexor 613 * for the cable detection logic. 614 * BRDDAT5 controls the bank switch. 615 */ 616 write_brdctl(ahc, 0); 617 618 /* 619 * Now read the state of the internal 620 * connectors. BRDDAT6 is INT50 and 621 * BRDDAT7 is INT68. 622 */ 623 brdctl = read_brdctl(ahc); 624 *internal50_present = (brdctl & BRDDAT6) ? 0 : 1; 625 *internal68_present = (brdctl & BRDDAT7) ? 0 : 1; 626 627 /* 628 * Set the rom bank to 1 and determine 629 * the other signals. 630 */ 631 write_brdctl(ahc, BRDDAT5); 632 633 /* 634 * Now read the state of the external 635 * connectors. BRDDAT6 is EXT68 and 636 * BRDDAT7 is EPROMPS. 637 */ 638 brdctl = read_brdctl(ahc); 639 *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; 640 *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0; 641 } 642 643 static void 644 aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, 645 int *externalcable_present, int *eeprom_present) 646 { 647 uint8_t brdctl; 648 uint8_t spiocap; 649 650 spiocap = ahc_inb(ahc, SPIOCAP); 651 spiocap &= ~SOFTCMDEN; 652 spiocap |= EXT_BRDCTL; 653 ahc_outb(ahc, SPIOCAP, spiocap); 654 ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); 655 ahc_outb(ahc, BRDCTL, 0); 656 brdctl = ahc_inb(ahc, BRDCTL); 657 *internal50_present = (brdctl & BRDDAT5) ? 0 : 1; 658 *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; 659 660 *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; 661 } 662 663 int 664 ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) 665 { 666 int wait; 667 668 if ((ahc->features & AHC_SPIOCAP) != 0 669 && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0) 670 return (0); 671 672 /* 673 * Request access of the memory port. When access is 674 * granted, SEERDY will go high. We use a 1 second 675 * timeout which should be near 1 second more than 676 * is needed. Reason: after the chip reset, there 677 * should be no contention. 678 */ 679 SEEPROM_OUTB(sd, sd->sd_MS); 680 wait = 1000; /* 1 second timeout in msec */ 681 while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) { 682 aic_delay(1000); /* delay 1 msec */ 683 } 684 if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) { 685 SEEPROM_OUTB(sd, 0); 686 return (0); 687 } 688 return(1); 689 } 690 691 void 692 ahc_release_seeprom(struct seeprom_descriptor *sd) 693 { 694 /* Release access to the memory port and the serial EEPROM. */ 695 SEEPROM_OUTB(sd, 0); 696 } 697 698 static void 699 write_brdctl(struct ahc_softc *ahc, uint8_t value) 700 { 701 uint8_t brdctl; 702 703 if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { 704 brdctl = BRDSTB; 705 if (ahc->channel == 'B') 706 brdctl |= BRDCS; 707 } else if ((ahc->features & AHC_ULTRA2) != 0) { 708 brdctl = 0; 709 } else { 710 brdctl = BRDSTB|BRDCS; 711 } 712 ahc_outb(ahc, BRDCTL, brdctl); 713 ahc_flush_device_writes(ahc); 714 brdctl |= value; 715 ahc_outb(ahc, BRDCTL, brdctl); 716 ahc_flush_device_writes(ahc); 717 if ((ahc->features & AHC_ULTRA2) != 0) 718 brdctl |= BRDSTB_ULTRA2; 719 else 720 brdctl &= ~BRDSTB; 721 ahc_outb(ahc, BRDCTL, brdctl); 722 ahc_flush_device_writes(ahc); 723 if ((ahc->features & AHC_ULTRA2) != 0) 724 brdctl = 0; 725 else 726 brdctl &= ~BRDCS; 727 ahc_outb(ahc, BRDCTL, brdctl); 728 } 729 730 static uint8_t 731 read_brdctl(struct ahc_softc *ahc) 732 { 733 uint8_t brdctl; 734 uint8_t value; 735 736 if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { 737 brdctl = BRDRW; 738 if (ahc->channel == 'B') 739 brdctl |= BRDCS; 740 } else if ((ahc->features & AHC_ULTRA2) != 0) { 741 brdctl = BRDRW_ULTRA2; 742 } else { 743 brdctl = BRDRW|BRDCS; 744 } 745 ahc_outb(ahc, BRDCTL, brdctl); 746 ahc_flush_device_writes(ahc); 747 value = ahc_inb(ahc, BRDCTL); 748 ahc_outb(ahc, BRDCTL, 0); 749 return (value); 750 } 751 752 static int 753 verify_seeprom_cksum(struct seeprom_config *sc) 754 { 755 int i; 756 int maxaddr; 757 uint32_t checksum; 758 uint16_t *scarray; 759 760 maxaddr = (sizeof(*sc)/2) - 1; 761 checksum = 0; 762 scarray = (uint16_t *)sc; 763 764 for (i = 0; i < maxaddr; i++) 765 checksum = checksum + scarray[i]; 766 if (checksum == 0 767 || (checksum & 0xFFFF) != sc->checksum) { 768 return (0); 769 } else { 770 return(1); 771 } 772 } 773