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 | |