| 1 | /* $NetBSD: aic7xxx_seeprom.c,v 1.13 2009/03/14 15:36:17 dsl 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.13 2009/03/14 15:36:17 dsl 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.13 2009/03/14 15:36:17 dsl Exp $" ); |
| 56 | |
| 57 | #include <sys/param.h> |
| 58 | #include <sys/systm.h> |
| 59 | #include <sys/malloc.h> |
| 60 | #include <sys/kernel.h> |
| 61 | #include <sys/queue.h> |
| 62 | #include <sys/device.h> |
| 63 | #include <sys/reboot.h> /* for AB_* needed by bootverbose */ |
| 64 | |
| 65 | #include <sys/bus.h> |
| 66 | #include <sys/intr.h> |
| 67 | |
| 68 | #include <dev/scsipi/scsi_all.h> |
| 69 | #include <dev/scsipi/scsipi_all.h> |
| 70 | #include <dev/scsipi/scsiconf.h> |
| 71 | |
| 72 | #include <dev/ic/aic7xxx_osm.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; |
| 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 | 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 | |
| 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(struct ahc_softc *ahc) |
| 736 | { |
| 737 | uint8_t brdctl; |
| 738 | uint8_t value; |
| 739 | |
| 740 | if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { |
| 741 | brdctl = BRDRW; |
| 742 | if (ahc->channel == 'B') |
| 743 | brdctl |= BRDCS; |
| 744 | } else if ((ahc->features & AHC_ULTRA2) != 0) { |
| 745 | brdctl = BRDRW_ULTRA2; |
| 746 | } else { |
| 747 | brdctl = BRDRW|BRDCS; |
| 748 | } |
| 749 | ahc_outb(ahc, BRDCTL, brdctl); |
| 750 | ahc_flush_device_writes(ahc); |
| 751 | value = ahc_inb(ahc, BRDCTL); |
| 752 | ahc_outb(ahc, BRDCTL, 0); |
| 753 | return (value); |
| 754 | } |
| 755 | |
| 756 | static int |
| 757 | verify_seeprom_cksum(struct seeprom_config *sc) |
| 758 | { |
| 759 | int i; |
| 760 | int maxaddr; |
| 761 | uint32_t checksum; |
| 762 | uint16_t *scarray; |
| 763 | |
| 764 | maxaddr = (sizeof(*sc)/2) - 1; |
| 765 | checksum = 0; |
| 766 | scarray = (uint16_t *)sc; |
| 767 | |
| 768 | for (i = 0; i < maxaddr; i++) |
| 769 | checksum = checksum + scarray[i]; |
| 770 | if (checksum == 0 |
| 771 | || (checksum & 0xFFFF) != sc->checksum) { |
| 772 | return (0); |
| 773 | } else { |
| 774 | return(1); |
| 775 | } |
| 776 | } |
| 777 | |