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