1 /* $NetBSD: aic7xxx_seeprom.c,v 1.12 2007/10/19 11:59:46 ad Exp $ */
4 * Product specific probe and attach routines for:
5 * 3940, 2940, aic7895, aic7890, aic7880,
6 * aic7870, aic7860 and aic7850 SCSI controllers
8 * Copyright (c) 1994-2001 Justin T. Gibbs.
9 * Copyright (c) 2000-2001 Adaptec Inc.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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.
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.
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
49 * $Id: aic7xxx_seeprom.c,v 1.13 2009/03/14 15:36:17 dsl Exp $
51 * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $
54 #include <sys/cdefs.h>
55 __KERNEL_RCSID(0, "$NetBSD: aic7xxx_seeprom.c,v 1.12 2007/10/19 11:59:46 ad Exp $");
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 */
68 #include <dev/scsipi/scsi_all.h>
69 #include <dev/scsipi/scsipi_all.h>
70 #include <dev/scsipi/scsiconf.h>
72 #include <dev/ic/aic7xxx_osm.h>
73 #include <dev/ic/aic7xxx_inline.h>
75 #include <dev/ic/smc93cx6var.h>
77 #define DEVCONFIG 0x40
78 #define STPWLEVEL 0x00000002
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
);
84 static void ahc_new_term_detect(struct ahc_softc
*, int *, int *, int *,
86 static void aic787X_cable_detect(struct ahc_softc
*, int *, int *, 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
*);
94 * Check the external port logic for a serial eeprom
95 * and termination/cable detection contrls.
98 ahc_check_extport(struct ahc_softc
*ahc
, u_int
*sxfrctl1
)
100 struct seeprom_descriptor sd
;
101 struct seeprom_config
*sc
;
105 sd
.sd_tag
= ahc
->tag
;
106 sd
.sd_bsh
= ahc
->bsh
;
108 sd
.sd_control_offset
= SEECTL
;
109 sd
.sd_status_offset
= SEECTL
;
110 sd
.sd_dataout_offset
= SEECTL
;
111 sc
= ahc
->seep_config
;
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.
119 if (ahc
->flags
& AHC_LARGE_SEEPROM
)
131 have_seeprom
= ahc_acquire_seeprom(ahc
, &sd
);
135 printf("%s: Reading SEEPROM...", ahc_name(ahc
));
140 start_addr
= 32 * (ahc
->channel
- 'A');
141 have_seeprom
= read_seeprom(&sd
, (uint16_t *)sc
,
146 have_seeprom
= verify_seeprom_cksum(sc
);
148 if (have_seeprom
!= 0 || sd
.sd_chip
== C56_66
) {
150 if (have_seeprom
== 0)
151 printf ("checksum error\n");
159 ahc_release_seeprom(&sd
);
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.
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') {
178 sc_data
= (uint16_t *)sc
;
179 for (i
= 0; i
< 32; i
++, sc_data
++) {
183 *sc_data
= ahc_inb(ahc
, SRAM_BASE
+ j
)
184 | ahc_inb(ahc
, SRAM_BASE
+ j
+ 1) << 8;
186 have_seeprom
= verify_seeprom_cksum(sc
);
188 ahc
->flags
|= AHC_SCB_CONFIG_USED
;
191 * Clear any SCB parity errors in case this data and
192 * its associated parity was not initialized by the BIOS
194 ahc_outb(ahc
, CLRINT
, CLRPARERR
);
195 ahc_outb(ahc
, CLRINT
, CLRBRKADRINT
);
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
;
206 ahc_parse_pci_eeprom(ahc
, sc
);
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...
215 have_autoterm
= have_seeprom
;
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.
222 if ((ahc
->features
& AHC_SPIOCAP
) != 0) {
223 if ((ahc_inb(ahc
, SPIOCAP
) & SSPIOCPS
) == 0)
224 have_autoterm
= FALSE
;
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)
236 printf("%s: Low byte termination %sabled\n",
238 (*sxfrctl1
& STPWEN
) ? "en" : "dis");
243 ahc_parse_pci_eeprom(struct ahc_softc
*ahc
, struct seeprom_config
*sc
)
246 * Put the data we've collected down into SRAM
247 * where ahc_init will find it.
250 int max_targ
= sc
->max_targets
& CFMAXTARG
;
257 if ((sc
->adapter_control
& CFULTRAEN
) != 0) {
259 * Determine if this adapter has a "newstyle"
262 for (i
= 0; i
< max_targ
; i
++) {
263 if ((sc
->device_flags
[i
] & CFSYNCHISULTRA
) != 0) {
264 ahc
->flags
|= AHC_NEWEEPROM_FMT
;
270 for (i
= 0; i
< max_targ
; i
++) {
272 uint16_t target_mask
;
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
;
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
;
289 if ((ahc
->features
& AHC_ULTRA2
) != 0) {
292 if (sc
->device_flags
[i
] & CFSYNCH
)
293 offset
= MAX_OFFSET_ULTRA2
;
296 ahc_outb(ahc
, TARG_OFFSET
+ i
, offset
);
299 * The ultra enable bits contain the
300 * high bit of the ultra2 sync rate
303 scsirate
= (sc
->device_flags
[i
] & CFXFER
)
304 | ((ultraenb
& target_mask
) ? 0x8 : 0x0);
305 if (sc
->device_flags
[i
] & CFWIDEB
)
306 scsirate
|= WIDEXFER
;
308 scsirate
= (sc
->device_flags
[i
] & CFXFER
) << 4;
309 if (sc
->device_flags
[i
] & CFSYNCH
)
311 if (sc
->device_flags
[i
] & CFWIDEB
)
312 scsirate
|= WIDEXFER
;
314 ahc_outb(ahc
, TARG_SCSIRATE
+ i
, scsirate
);
316 ahc
->our_id
= sc
->brtime_id
& CFSCSIID
;
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
;
324 ahc
->flags
|= (sc
->adapter_control
& CFBOOTCHAN
) >> CFBOOTCHANSHIFT
;
326 if (sc
->bios_control
& CFEXTEND
)
327 ahc
->flags
|= AHC_EXTENDED_TRANS_A
;
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 */
339 if (sc
->signature
== CFSIGNATURE
340 || sc
->signature
== CFSIGNATURE2
) {
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
);
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);
359 configure_termination(struct ahc_softc
*ahc
,
360 struct seeprom_descriptor
*sd
,
361 u_int adapter_control
,
369 * Update the settings in sxfrctl1 to match the
370 * termination settings
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.
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
;
396 if ((ahc
->features
& AHC_NEW_TERMCTL
) != 0) {
397 ahc_new_term_detect(ahc
, &enableSEC_low
,
402 if ((adapter_control
& CFSEAUTOTERM
) == 0) {
404 printf("%s: Manual SE Termination\n",
406 enableSEC_low
= (adapter_control
& CFSELOWTERM
);
408 (adapter_control
& CFSEHIGHTERM
);
410 if ((adapter_control
& CFAUTOTERM
) == 0) {
412 printf("%s: Manual LVD Termination\n",
414 enablePRI_low
= (adapter_control
& CFSTERM
);
415 enablePRI_high
= (adapter_control
& CFWSTERM
);
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
,
425 /* Can never support a wide connector. */
426 internal68_present
= 0;
428 aic787X_cable_detect(ahc
, &internal50_present
,
430 &externalcable_present
,
434 if ((ahc
->features
& AHC_WIDE
) == 0)
435 internal68_present
= 0;
438 && (ahc
->features
& AHC_ULTRA2
) == 0) {
439 printf("%s: internal 50 cable %s present",
441 internal50_present
? "is":"not");
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",
448 externalcable_present
? "is":"not");
451 printf("%s: BIOS eeprom %s present\n",
452 ahc_name(ahc
), eeprom_present
? "is" : "not");
454 if ((ahc
->flags
& AHC_INT50_SPEEDFLEX
) != 0) {
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.
462 internal50_present
= 0;
466 * Now set the termination based on what
468 * Flash Enable = BRDDAT7
469 * Secondary High Term Enable = BRDDAT6
470 * Secondary Low Term Enable = BRDDAT5 (7890)
471 * Primary High Term Enable = BRDDAT4 (7890)
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
));
483 * Pretend there are no cables in the hope
484 * that having all of the termination on
485 * gives us a more stable bus.
487 internal50_present
= 0;
488 internal68_present
= 0;
489 externalcable_present
= 0;
492 if ((ahc
->features
& AHC_WIDE
) != 0
493 && ((externalcable_present
== 0)
494 || (internal68_present
== 0)
495 || (enableSEC_high
!= 0))) {
498 if ((ahc
->flags
& AHC_INT50_SPEEDFLEX
) != 0)
499 printf("%s: 68 pin termination "
500 "Enabled\n", ahc_name(ahc
));
502 printf("%s: %sHigh byte termination "
503 "Enabled\n", ahc_name(ahc
),
504 enableSEC_high
? "Secondary "
509 sum
= internal50_present
+ internal68_present
510 + externalcable_present
;
511 if (sum
< 2 || (enableSEC_low
!= 0)) {
512 if ((ahc
->features
& AHC_ULTRA2
) != 0)
517 if ((ahc
->flags
& AHC_INT50_SPEEDFLEX
) != 0)
518 printf("%s: 50 pin termination "
519 "Enabled\n", ahc_name(ahc
));
521 printf("%s: %sLow byte termination "
522 "Enabled\n", ahc_name(ahc
),
523 enableSEC_low
? "Secondary "
528 if (enablePRI_low
!= 0) {
531 printf("%s: Primary Low Byte termination "
532 "Enabled\n", ahc_name(ahc
));
536 * Setup STPWEN before setting up the rest of
537 * the termination per the tech note on the U160 cards.
539 ahc_outb(ahc
, SXFRCTL1
, *sxfrctl1
);
541 if (enablePRI_high
!= 0) {
544 printf("%s: Primary High Byte "
545 "termination Enabled\n",
549 write_brdctl(ahc
, brddat
);
552 if ((adapter_control
& CFSTERM
) != 0) {
556 printf("%s: %sLow byte termination Enabled\n",
558 (ahc
->features
& AHC_ULTRA2
) ? "Primary "
562 if ((adapter_control
& CFWSTERM
) != 0
563 && (ahc
->features
& AHC_WIDE
) != 0) {
566 printf("%s: %sHigh byte termination Enabled\n",
568 (ahc
->features
& AHC_ULTRA2
)
569 ? "Secondary " : "");
573 * Setup STPWEN before setting up the rest of
574 * the termination per the tech note on the U160 cards.
576 ahc_outb(ahc
, SXFRCTL1
, *sxfrctl1
);
578 if ((ahc
->features
& AHC_WIDE
) != 0)
579 write_brdctl(ahc
, brddat
);
581 SEEPROM_OUTB(sd
, sd
->sd_MS
); /* Clear CS */
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
)
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
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
);
607 aic787X_cable_detect(struct ahc_softc
*ahc
, int *internal50_present
,
608 int *internal68_present
, int *externalcable_present
,
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.
620 write_brdctl(ahc
, 0);
623 * Now read the state of the internal
624 * connectors. BRDDAT6 is INT50 and
627 brdctl
= read_brdctl(ahc
);
628 *internal50_present
= (brdctl
& BRDDAT6
) ? 0 : 1;
629 *internal68_present
= (brdctl
& BRDDAT7
) ? 0 : 1;
632 * Set the rom bank to 1 and determine
635 write_brdctl(ahc
, BRDDAT5
);
638 * Now read the state of the external
639 * connectors. BRDDAT6 is EXT68 and
640 * BRDDAT7 is EPROMPS.
642 brdctl
= read_brdctl(ahc
);
643 *externalcable_present
= (brdctl
& BRDDAT6
) ? 0 : 1;
644 *eeprom_present
= (brdctl
& BRDDAT7
) ? 1 : 0;
648 aic785X_cable_detect(struct ahc_softc
*ahc
, int *internal50_present
,
649 int *externalcable_present
, int *eeprom_present
)
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;
664 *eeprom_present
= (ahc_inb(ahc
, SPIOCAP
) & EEPROM
) ? 1 : 0;
668 ahc_acquire_seeprom(struct ahc_softc
*ahc
, struct seeprom_descriptor
*sd
)
672 if ((ahc
->features
& AHC_SPIOCAP
) != 0
673 && (ahc_inb(ahc
, SPIOCAP
) & SEEPROM
) == 0)
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.
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 */
688 if ((SEEPROM_STATUS_INB(sd
) & sd
->sd_RDY
) == 0) {
696 ahc_release_seeprom(struct seeprom_descriptor
*sd
)
698 /* Release access to the memory port and the serial EEPROM. */
703 write_brdctl(struct ahc_softc
*ahc
, uint8_t value
)
707 if ((ahc
->chip
& AHC_CHIPID_MASK
) == AHC_AIC7895
) {
709 if (ahc
->channel
== 'B')
711 } else if ((ahc
->features
& AHC_ULTRA2
) != 0) {
714 brdctl
= BRDSTB
|BRDCS
;
716 ahc_outb(ahc
, BRDCTL
, brdctl
);
717 ahc_flush_device_writes(ahc
);
719 ahc_outb(ahc
, BRDCTL
, brdctl
);
720 ahc_flush_device_writes(ahc
);
721 if ((ahc
->features
& AHC_ULTRA2
) != 0)
722 brdctl
|= BRDSTB_ULTRA2
;
725 ahc_outb(ahc
, BRDCTL
, brdctl
);
726 ahc_flush_device_writes(ahc
);
727 if ((ahc
->features
& AHC_ULTRA2
) != 0)
731 ahc_outb(ahc
, BRDCTL
, brdctl
);
735 read_brdctl(struct ahc_softc
*ahc
)
740 if ((ahc
->chip
& AHC_CHIPID_MASK
) == AHC_AIC7895
) {
742 if (ahc
->channel
== 'B')
744 } else if ((ahc
->features
& AHC_ULTRA2
) != 0) {
745 brdctl
= BRDRW_ULTRA2
;
747 brdctl
= BRDRW
|BRDCS
;
749 ahc_outb(ahc
, BRDCTL
, brdctl
);
750 ahc_flush_device_writes(ahc
);
751 value
= ahc_inb(ahc
, BRDCTL
);
752 ahc_outb(ahc
, BRDCTL
, 0);
757 verify_seeprom_cksum(struct seeprom_config
*sc
)
764 maxaddr
= (sizeof(*sc
)/2) - 1;
766 scarray
= (uint16_t *)sc
;
768 for (i
= 0; i
< maxaddr
; i
++)
769 checksum
= checksum
+ scarray
[i
];
771 || (checksum
& 0xFFFF) != sc
->checksum
) {