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