aic7xxx_seeprom.c revision 1.14 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