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