Annotation of sys/dev/ic/aic7xxx_seeprom.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: aic7xxx_seeprom.c,v 1.3 2004/10/24 04:28:33 krw 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.3 2004/10/24 04:28:33 krw 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/cdefs.h>
! 56: /* __KERNEL_RCSID(0, "$NetBSD: aic7xxx_seeprom.c,v 1.8 2003/05/02 19:12:19 dyoung Exp $"); */
! 57:
! 58: #include <sys/param.h>
! 59: #include <sys/systm.h>
! 60: #include <sys/malloc.h>
! 61: #include <sys/kernel.h>
! 62: #include <sys/queue.h>
! 63: #include <sys/device.h>
! 64: #include <sys/reboot.h> /* for AB_* needed by bootverbose */
! 65:
! 66: #include <machine/bus.h>
! 67: #include <machine/intr.h>
! 68:
! 69: #include <scsi/scsi_all.h>
! 70: #include <scsi/scsiconf.h>
! 71:
! 72: #include <dev/ic/aic7xxx_openbsd.h>
! 73: #include <dev/ic/aic7xxx_inline.h>
! 74:
! 75: #include <dev/ic/smc93cx6var.h>
! 76:
! 77: #define DEVCONFIG 0x40
! 78: #define STPWLEVEL 0x00000002
! 79:
! 80: static void configure_termination(struct ahc_softc *,
! 81: struct seeprom_descriptor *, u_int, u_int *);
! 82: static int verify_seeprom_cksum(struct seeprom_config *sc);
! 83:
! 84: static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *,
! 85: int *, int *);
! 86: static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *,
! 87: int *);
! 88: static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *);
! 89: static void write_brdctl(struct ahc_softc *, u_int8_t);
! 90: static u_int8_t read_brdctl(struct ahc_softc *);
! 91: static 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: */
! 97: void
! 98: ahc_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 | AHC_NO_BIOS_INIT;
! 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:
! 242: static void
! 243: ahc_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:
! 358: static void
! 359: configure_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:
! 584: static void
! 585: ahc_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:
! 606: static void
! 607: aic787X_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:
! 647: static void
! 648: aic785X_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:
! 667: int
! 668: ahc_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: aic_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:
! 695: void
! 696: ahc_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:
! 702: static void
! 703: write_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:
! 734: static uint8_t
! 735: read_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:
! 757: static int
! 758: verify_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: }
CVSweb