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