[RFC][PATCH] Forward port of aic7xxx driver to 2.5.44 [1/3]

From: SL Baur (steve@kbuxd.necst.nec.co.jp)
Date: Thu Oct 24 2002 - 21:13:39 EST


Hi,

This patch updates the aic7xxx driver to be the same version as in
2.4.20-pre11. The version currently in 2.5.44 is too old to recognize
my controller. It compiles cleanly, but I have not yet tried to boot
with it. Would someone with experienced eyes please look it over to
be sure I didn't do anything stupid? Thanks.

===== drivers/scsi/aic7xxx/aic7xxx_proc.c 1.4 vs edited =====
--- 1.4/drivers/scsi/aic7xxx/aic7xxx_proc.c Tue Feb 5 16:53:47 2002
+++ edited/drivers/scsi/aic7xxx/aic7xxx_proc.c Thu Oct 24 13:35:09 2002
@@ -37,10 +37,11 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#13 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#19 $
  */
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
 
 static void copy_mem_info(struct info_str *info, char *data, int len);
 static int copy_info(struct info_str *info, char *fmt, ...);
@@ -51,6 +52,46 @@
                                       u_int target_id, u_int target_offset);
 static void ahc_dump_device_state(struct info_str *info,
                                       struct ahc_linux_device *dev);
+static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
+ char *buffer, int length);
+
+
+int
+ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
+{
+ int wait;
+
+ if ((ahc->features & AHC_SPIOCAP) != 0
+ && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
+ return (0);
+
+ /*
+ * Request access of the memory port. When access is
+ * granted, SEERDY will go high. We use a 1 second
+ * timeout which should be near 1 second more than
+ * is needed. Reason: after the chip reset, there
+ * should be no contention.
+ */
+ SEEPROM_OUTB(sd, sd->sd_MS);
+ wait = 1000; /* 1 second timeout in msec */
+ while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
+ ahc_delay(1000); /* delay 1 msec */
+ }
+ if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
+ SEEPROM_OUTB(sd, 0);
+ return (0);
+ }
+ return(1);
+}
+
+
+void
+ahc_release_seeprom(struct seeprom_descriptor *sd)
+{
+ /* Release access to the memory port and the serial EEPROM. */
+ SEEPROM_OUTB(sd, 0);
+}
+
 
 static void
 copy_mem_info(struct info_str *info, char *data, int len)
@@ -225,6 +266,96 @@
         copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
 }
 
+static int
+ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
+{
+ struct seeprom_descriptor sd;
+ int have_seeprom;
+ u_long s;
+ int paused;
+ int written;
+
+ /* Default to failure. */
+ written = -EINVAL;
+ ahc_lock(ahc, &s);
+ paused = ahc_is_paused(ahc);
+ if (!paused)
+ ahc_pause(ahc);
+
+ if (length != sizeof(struct seeprom_config)) {
+ printf("ahc_proc_write_seeprom: incorrect buffer size\n");
+ goto done;
+ }
+
+ have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
+ if (have_seeprom == 0) {
+ printf("ahc_proc_write_seeprom: cksum verification failed\n");
+ goto done;
+ }
+
+ sd.sd_ahc = ahc;
+ if ((ahc->chip & AHC_VL) != 0) {
+ sd.sd_control_offset = SEECTL_2840;
+ sd.sd_status_offset = STATUS_2840;
+ sd.sd_dataout_offset = STATUS_2840;
+ sd.sd_chip = C46;
+ sd.sd_MS = 0;
+ sd.sd_RDY = EEPROM_TF;
+ sd.sd_CS = CS_2840;
+ sd.sd_CK = CK_2840;
+ sd.sd_DO = DO_2840;
+ sd.sd_DI = DI_2840;
+ have_seeprom = TRUE;
+ } else {
+ sd.sd_control_offset = SEECTL;
+ sd.sd_status_offset = SEECTL;
+ sd.sd_dataout_offset = SEECTL;
+ if (ahc->flags & AHC_LARGE_SEEPROM)
+ sd.sd_chip = C56_66;
+ else
+ sd.sd_chip = C46;
+ sd.sd_MS = SEEMS;
+ sd.sd_RDY = SEERDY;
+ sd.sd_CS = SEECS;
+ sd.sd_CK = SEECK;
+ sd.sd_DO = SEEDO;
+ sd.sd_DI = SEEDI;
+ have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+ }
+
+ if (!have_seeprom) {
+ printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
+ goto done;
+ } else {
+ u_int start_addr;
+
+ if (ahc->seep_config == NULL) {
+ ahc->seep_config = malloc(sizeof(*ahc->seep_config),
+ M_DEVBUF, M_NOWAIT);
+ if (ahc->seep_config == NULL) {
+ printf("aic7xxx: Unable to allocate serial "
+ "eeprom buffer. Write failing\n");
+ goto done;
+ }
+ }
+ printf("aic7xxx: Writing Serial EEPROM\n");
+ start_addr = 32 * (ahc->channel - 'A');
+ ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
+ sizeof(struct seeprom_config)/2);
+ ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config,
+ start_addr, sizeof(struct seeprom_config)/2);
+ if ((ahc->chip & AHC_VL) == 0)
+ ahc_release_seeprom(&sd);
+ written = length;
+ }
+
+done:
+ if (!paused)
+ ahc_unpause(ahc);
+ ahc_unlock(ahc, &s);
+ return (written);
+}
+
 /*
  * Return information to handle /proc support for the driver.
  */
@@ -235,20 +366,26 @@
         struct ahc_softc *ahc;
         struct info_str info;
         char ahc_info[256];
+ u_long s;
         u_int max_targ;
         u_int i;
+ int retval;
 
+ retval = -EINVAL;
+ ahc_list_lock(&s);
         TAILQ_FOREACH(ahc, &ahc_tailq, links) {
                 if (ahc->platform_data->host->host_no == hostno)
                         break;
         }
 
         if (ahc == NULL)
- return (-EINVAL);
+ goto done;
 
          /* Has data been written to the file? */
- if (inout == TRUE)
- return (-ENOSYS);
+ if (inout == TRUE) {
+ retval = ahc_proc_write_seeprom(ahc, buffer, length);
+ goto done;
+ }
 
         if (start)
                 *start = buffer;
@@ -261,7 +398,22 @@
         copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
                   AIC7XXX_DRIVER_VERSION);
         ahc_controller_info(ahc, ahc_info);
- copy_info(&info, "%s\n", ahc_info);
+ copy_info(&info, "%s\n\n", ahc_info);
+
+ if (ahc->seep_config == NULL)
+ copy_info(&info, "No Serial EEPROM\n");
+ else {
+ copy_info(&info, "Serial EEPROM:\n");
+ for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
+ if (((i % 8) == 0) && (i != 0)) {
+ copy_info(&info, "\n");
+ }
+ copy_info(&info, "0x%.4x ",
+ ((uint16_t*)ahc->seep_config)[i]);
+ }
+ copy_info(&info, "\n");
+ }
+ copy_info(&info, "\n");
 
         max_targ = 15;
         if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
@@ -284,5 +436,8 @@
                 ahc_dump_target_state(ahc, &info, our_id,
                                       channel, target_id, i);
         }
- return (info.pos > info.offset ? info.pos - info.offset : 0);
+ retval = info.pos > info.offset ? info.pos - info.offset : 0;
+done:
+ ahc_list_unlock(&s);
+ return (retval);
 }
===== drivers/scsi/aic7xxx/aic7xxx_pci.c 1.5 vs edited =====
--- 1.5/drivers/scsi/aic7xxx/aic7xxx_pci.c Tue Feb 5 16:53:47 2002
+++ edited/drivers/scsi/aic7xxx/aic7xxx_pci.c Thu Oct 24 13:28:07 2002
@@ -39,9 +39,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#32 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#46 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.2.2.14 2002/04/29 19:36:31 gibbs Exp $
  */
 
 #include "aic7xxx_osm.h"
@@ -207,7 +207,7 @@
          : ((id) & 0x1000) >> 12)
 /*
  * Informational only. Should use chip register to be
- * ceratian, but may be use in identification strings.
+ * certain, but may be use in identification strings.
  */
 #define SUBID_9005_CARD_SCSIWIDTH_MASK 0x2000
 #define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000
@@ -661,6 +661,8 @@
                                   int pcheck, int fast, int large);
 static void ahc_probe_ext_scbram(struct ahc_softc *ahc);
 static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1);
+static void ahc_parse_pci_eeprom(struct ahc_softc *ahc,
+ struct seeprom_config *sc);
 static void configure_termination(struct ahc_softc *ahc,
                                   struct seeprom_descriptor *sd,
                                   u_int adapter_control,
@@ -679,9 +681,6 @@
 static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
                                  int *externalcable_present,
                                  int *eeprom_present);
-static int acquire_seeprom(struct ahc_softc *ahc,
- struct seeprom_descriptor *sd);
-static void release_seeprom(struct seeprom_descriptor *sd);
 static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
 static uint8_t read_brdctl(struct ahc_softc *ahc);
 
@@ -767,6 +766,8 @@
 ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
 {
         struct scb_data *shared_scb_data;
+ u_long l;
+ u_long s;
         u_int command;
         u_int our_id = 0;
         u_int sxfrctl1;
@@ -782,11 +783,19 @@
         ahc->chip |= AHC_PCI;
         ahc->description = entry->name;
 
+ ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+
         error = ahc_pci_map_registers(ahc);
         if (error != 0)
                 return (error);
 
- ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+ /*
+ * Before we continue probing the card, ensure that
+ * its interrupts are *disabled*. We don't want
+ * a misstep to hang the machine in an interrupt
+ * storm.
+ */
+ ahc_intr_enable(ahc, FALSE);
 
         /*
          * If we need to support high memory, enable dual
@@ -964,19 +973,23 @@
                 return (error);
 
         /*
- * Link this softc in with all other ahc instances.
- */
- ahc_softc_insert(ahc);
-
- /*
          * Allow interrupts now that we are completely setup.
          */
         error = ahc_pci_map_int(ahc);
         if (error != 0)
                 return (error);
 
+ ahc_list_lock(&l);
+ /*
+ * Link this softc in with all other ahc instances.
+ */
+ ahc_softc_insert(ahc);
+
+ ahc_lock(ahc, &s);
         ahc_intr_enable(ahc, TRUE);
+ ahc_unlock(ahc, &s);
 
+ ahc_list_unlock(&l);
         return (0);
 }
 
@@ -999,6 +1012,14 @@
 
         if ((ahc->features & AHC_ULTRA2) != 0)
                 ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0;
+ else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C)
+ /*
+ * External SCBRAM arbitration is flakey
+ * on these chips. Unfortunately this means
+ * we don't use the extra SCB ram space on the
+ * 3940AUW.
+ */
+ ramps = 0;
         else if (chip >= AHC_AIC7870)
                 ramps = (devconfig & RAMPSM) != 0;
         else
@@ -1026,6 +1047,9 @@
                 ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc));
         }
 
+ ahc->flags &= ~AHC_LSCBS_ENABLED;
+ if (large)
+ ahc->flags |= AHC_LSCBS_ENABLED;
         devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
         if ((ahc->features & AHC_ULTRA2) != 0) {
                 u_int dscommand0;
@@ -1172,9 +1196,7 @@
 check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
 {
         struct seeprom_descriptor sd;
- struct seeprom_config sc;
- u_int scsi_conf;
- u_int adapter_control;
+ struct seeprom_config *sc;
         int have_seeprom;
         int have_autoterm;
 
@@ -1182,6 +1204,7 @@
         sd.sd_control_offset = SEECTL;
         sd.sd_status_offset = SEECTL;
         sd.sd_dataout_offset = SEECTL;
+ sc = ahc->seep_config;
 
         /*
          * For some multi-channel devices, the c46 is simply too
@@ -1201,7 +1224,7 @@
         sd.sd_DO = SEEDO;
         sd.sd_DI = SEEDI;
 
- have_seeprom = acquire_seeprom(ahc, &sd);
+ have_seeprom = ahc_acquire_seeprom(ahc, &sd);
         if (have_seeprom) {
 
                 if (bootverbose)
@@ -1212,11 +1235,12 @@
 
                         start_addr = 32 * (ahc->channel - 'A');
 
- have_seeprom = read_seeprom(&sd, (uint16_t *)&sc,
- start_addr, sizeof(sc)/2);
+ have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
+ start_addr,
+ sizeof(*sc)/2);
 
                         if (have_seeprom)
- have_seeprom = verify_cksum(&sc);
+ have_seeprom = ahc_verify_cksum(sc);
 
                         if (have_seeprom != 0 || sd.sd_chip == C56_66) {
                                 if (bootverbose) {
@@ -1229,7 +1253,7 @@
                         }
                         sd.sd_chip = C56_66;
                 }
- release_seeprom(&sd);
+ ahc_release_seeprom(&sd);
         }
 
         if (!have_seeprom) {
@@ -1248,7 +1272,7 @@
                         uint16_t *sc_data;
                         int i;
 
- sc_data = (uint16_t *)&sc;
+ sc_data = (uint16_t *)sc;
                         for (i = 0; i < 32; i++) {
                                 uint16_t val;
                                 int j;
@@ -1257,129 +1281,27 @@
                                 val = ahc_inb(ahc, SRAM_BASE + j)
                                     | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
                         }
- have_seeprom = verify_cksum(&sc);
+ have_seeprom = ahc_verify_cksum(sc);
+ if (have_seeprom)
+ ahc->flags |= AHC_SCB_CONFIG_USED;
                 }
+ /*
+ * Clear any SCB parity errors in case this data and
+ * its associated parity was not initialized by the BIOS
+ */
+ ahc_outb(ahc, CLRINT, CLRPARERR);
+ ahc_outb(ahc, CLRINT, CLRBRKADRINT);
         }
 
         if (!have_seeprom) {
                 if (bootverbose)
                         printf("%s: No SEEPROM available.\n", ahc_name(ahc));
                 ahc->flags |= AHC_USEDEFAULTS;
+ free(ahc->seep_config, M_DEVBUF);
+ ahc->seep_config = NULL;
+ sc = NULL;
         } else {
- /*
- * Put the data we've collected down into SRAM
- * where ahc_init will find it.
- */
- int i;
- int max_targ = sc.max_targets & CFMAXTARG;
- uint16_t discenable;
- uint16_t ultraenb;
-
- discenable = 0;
- ultraenb = 0;
- if ((sc.adapter_control & CFULTRAEN) != 0) {
- /*
- * Determine if this adapter has a "newstyle"
- * SEEPROM format.
- */
- for (i = 0; i < max_targ; i++) {
- if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0){
- ahc->flags |= AHC_NEWEEPROM_FMT;
- break;
- }
- }
- }
-
- for (i = 0; i < max_targ; i++) {
- u_int scsirate;
- uint16_t target_mask;
-
- target_mask = 0x01 << i;
- if (sc.device_flags[i] & CFDISC)
- discenable |= target_mask;
- if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
- if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0)
- ultraenb |= target_mask;
- } else if ((sc.adapter_control & CFULTRAEN) != 0) {
- ultraenb |= target_mask;
- }
- if ((sc.device_flags[i] & CFXFER) == 0x04
- && (ultraenb & target_mask) != 0) {
- /* Treat 10MHz as a non-ultra speed */
- sc.device_flags[i] &= ~CFXFER;
- ultraenb &= ~target_mask;
- }
- if ((ahc->features & AHC_ULTRA2) != 0) {
- u_int offset;
-
- if (sc.device_flags[i] & CFSYNCH)
- offset = MAX_OFFSET_ULTRA2;
- else
- offset = 0;
- ahc_outb(ahc, TARG_OFFSET + i, offset);
-
- /*
- * The ultra enable bits contain the
- * high bit of the ultra2 sync rate
- * field.
- */
- scsirate = (sc.device_flags[i] & CFXFER)
- | ((ultraenb & target_mask)
- ? 0x8 : 0x0);
- if (sc.device_flags[i] & CFWIDEB)
- scsirate |= WIDEXFER;
- } else {
- scsirate = (sc.device_flags[i] & CFXFER) << 4;
- if (sc.device_flags[i] & CFSYNCH)
- scsirate |= SOFS;
- if (sc.device_flags[i] & CFWIDEB)
- scsirate |= WIDEXFER;
- }
- ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
- }
- ahc->our_id = sc.brtime_id & CFSCSIID;
-
- scsi_conf = (ahc->our_id & 0x7);
- if (sc.adapter_control & CFSPARITY)
- scsi_conf |= ENSPCHK;
- if (sc.adapter_control & CFRESETB)
- scsi_conf |= RESET_SCSI;
-
- ahc->flags |=
- (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
-
- if (sc.bios_control & CFEXTEND)
- ahc->flags |= AHC_EXTENDED_TRANS_A;
-
- if (sc.bios_control & CFBIOSEN)
- ahc->flags |= AHC_BIOS_ENABLED;
- if (ahc->features & AHC_ULTRA
- && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
- /* Should we enable Ultra mode? */
- if (!(sc.adapter_control & CFULTRAEN))
- /* Treat us as a non-ultra card */
- ultraenb = 0;
- }
-
- if (sc.signature == CFSIGNATURE
- || sc.signature == CFSIGNATURE2) {
- uint32_t devconfig;
-
- /* Honor the STPWLEVEL settings */
- devconfig = ahc_pci_read_config(ahc->dev_softc,
- DEVCONFIG, /*bytes*/4);
- devconfig &= ~STPWLEVEL;
- if ((sc.bios_control & CFSTPWLEVEL) != 0)
- devconfig |= STPWLEVEL;
- ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
- devconfig, /*bytes*/4);
- }
- /* Set SCSICONF info */
- ahc_outb(ahc, SCSICONF, scsi_conf);
- ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
- ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
- ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
- ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
+ ahc_parse_pci_eeprom(ahc, sc);
         }
 
         /*
@@ -1389,10 +1311,6 @@
          * hasn't failed yet...
          */
         have_autoterm = have_seeprom;
- if (have_seeprom)
- adapter_control = sc.adapter_control;
- else
- adapter_control = CFAUTOTERM;
 
         /*
          * Some low-cost chips have SEEPROM and auto-term control built
@@ -1400,17 +1318,141 @@
          * if the termination logic is enabled.
          */
         if ((ahc->features & AHC_SPIOCAP) != 0) {
- if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0)
- have_autoterm = TRUE;
- else
+ if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)
                         have_autoterm = FALSE;
         }
 
         if (have_autoterm) {
- acquire_seeprom(ahc, &sd);
- configure_termination(ahc, &sd, adapter_control, sxfrctl1);
- release_seeprom(&sd);
+ ahc_acquire_seeprom(ahc, &sd);
+ configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
+ ahc_release_seeprom(&sd);
+ } else if (have_seeprom) {
+ *sxfrctl1 &= ~STPWEN;
+ if ((sc->adapter_control & CFSTERM) != 0)
+ *sxfrctl1 |= STPWEN;
+ if (bootverbose)
+ printf("%s: Low byte termination %sabled\n",
+ ahc_name(ahc),
+ (*sxfrctl1 & STPWEN) ? "en" : "dis");
+ }
+}
+
+static void
+ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc)
+{
+ /*
+ * Put the data we've collected down into SRAM
+ * where ahc_init will find it.
+ */
+ int i;
+ int max_targ = sc->max_targets & CFMAXTARG;
+ u_int scsi_conf;
+ uint16_t discenable;
+ uint16_t ultraenb;
+
+ discenable = 0;
+ ultraenb = 0;
+ if ((sc->adapter_control & CFULTRAEN) != 0) {
+ /*
+ * Determine if this adapter has a "newstyle"
+ * SEEPROM format.
+ */
+ for (i = 0; i < max_targ; i++) {
+ if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) {
+ ahc->flags |= AHC_NEWEEPROM_FMT;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < max_targ; i++) {
+ u_int scsirate;
+ uint16_t target_mask;
+
+ target_mask = 0x01 << i;
+ if (sc->device_flags[i] & CFDISC)
+ discenable |= target_mask;
+ if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
+ if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0)
+ ultraenb |= target_mask;
+ } else if ((sc->adapter_control & CFULTRAEN) != 0) {
+ ultraenb |= target_mask;
+ }
+ if ((sc->device_flags[i] & CFXFER) == 0x04
+ && (ultraenb & target_mask) != 0) {
+ /* Treat 10MHz as a non-ultra speed */
+ sc->device_flags[i] &= ~CFXFER;
+ ultraenb &= ~target_mask;
+ }
+ if ((ahc->features & AHC_ULTRA2) != 0) {
+ u_int offset;
+
+ if (sc->device_flags[i] & CFSYNCH)
+ offset = MAX_OFFSET_ULTRA2;
+ else
+ offset = 0;
+ ahc_outb(ahc, TARG_OFFSET + i, offset);
+
+ /*
+ * The ultra enable bits contain the
+ * high bit of the ultra2 sync rate
+ * field.
+ */
+ scsirate = (sc->device_flags[i] & CFXFER)
+ | ((ultraenb & target_mask) ? 0x8 : 0x0);
+ if (sc->device_flags[i] & CFWIDEB)
+ scsirate |= WIDEXFER;
+ } else {
+ scsirate = (sc->device_flags[i] & CFXFER) << 4;
+ if (sc->device_flags[i] & CFSYNCH)
+ scsirate |= SOFS;
+ if (sc->device_flags[i] & CFWIDEB)
+ scsirate |= WIDEXFER;
+ }
+ ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
+ }
+ ahc->our_id = sc->brtime_id & CFSCSIID;
+
+ scsi_conf = (ahc->our_id & 0x7);
+ if (sc->adapter_control & CFSPARITY)
+ scsi_conf |= ENSPCHK;
+ if (sc->adapter_control & CFRESETB)
+ scsi_conf |= RESET_SCSI;
+
+ ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
+
+ if (sc->bios_control & CFEXTEND)
+ ahc->flags |= AHC_EXTENDED_TRANS_A;
+
+ if (sc->bios_control & CFBIOSEN)
+ ahc->flags |= AHC_BIOS_ENABLED;
+ if (ahc->features & AHC_ULTRA
+ && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
+ /* Should we enable Ultra mode? */
+ if (!(sc->adapter_control & CFULTRAEN))
+ /* Treat us as a non-ultra card */
+ ultraenb = 0;
+ }
+
+ if (sc->signature == CFSIGNATURE
+ || sc->signature == CFSIGNATURE2) {
+ uint32_t devconfig;
+
+ /* Honor the STPWLEVEL settings */
+ devconfig = ahc_pci_read_config(ahc->dev_softc,
+ DEVCONFIG, /*bytes*/4);
+ devconfig &= ~STPWLEVEL;
+ if ((sc->bios_control & CFSTPWLEVEL) != 0)
+ devconfig |= STPWLEVEL;
+ ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+ devconfig, /*bytes*/4);
         }
+ /* Set SCSICONF info */
+ ahc_outb(ahc, SCSICONF, scsi_conf);
+ ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+ ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+ ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
+ ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
 }
 
 static void
@@ -1453,10 +1495,10 @@
                 enablePRI_high = 0;
                 if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
                         ahc_new_term_detect(ahc, &enableSEC_low,
- &enableSEC_high,
- &enablePRI_low,
- &enablePRI_high,
- &eeprom_present);
+ &enableSEC_high,
+ &enablePRI_low,
+ &enablePRI_high,
+ &eeprom_present);
                         if ((adapter_control & CFSEAUTOTERM) == 0) {
                                 if (bootverbose)
                                         printf("%s: Manual SE Termination\n",
@@ -1534,6 +1576,15 @@
                                "Only two connectors on the "
                                "adapter may be used at a "
                                "time!\n", ahc_name(ahc));
+
+ /*
+ * Pretend there are no cables in the hope
+ * that having all of the termination on
+ * gives us a more stable bus.
+ */
+ internal50_present = 0;
+ internal68_present = 0;
+ externalcable_present = 0;
                 }
 
                 if ((ahc->features & AHC_WIDE) != 0
@@ -1696,7 +1747,12 @@
                      int *externalcable_present, int *eeprom_present)
 {
         uint8_t brdctl;
+ uint8_t spiocap;
 
+ spiocap = ahc_inb(ahc, SPIOCAP);
+ spiocap &= ~SOFTCMDEN;
+ spiocap |= EXT_BRDCTL;
+ ahc_outb(ahc, SPIOCAP, spiocap);
         ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
         ahc_outb(ahc, BRDCTL, 0);
         brdctl = ahc_inb(ahc, BRDCTL);
@@ -1706,41 +1762,6 @@
         *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
 }
         
-static int
-acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
-{
- int wait;
-
- if ((ahc->features & AHC_SPIOCAP) != 0
- && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
- return (0);
-
- /*
- * Request access of the memory port. When access is
- * granted, SEERDY will go high. We use a 1 second
- * timeout which should be near 1 second more than
- * is needed. Reason: after the chip reset, there
- * should be no contention.
- */
- SEEPROM_OUTB(sd, sd->sd_MS);
- wait = 1000; /* 1 second timeout in msec */
- while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
- ahc_delay(1000); /* delay 1 msec */
- }
- if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
- SEEPROM_OUTB(sd, 0);
- return (0);
- }
- return(1);
-}
-
-static void
-release_seeprom(struct seeprom_descriptor *sd)
-{
- /* Release access to the memory port and the serial EEPROM. */
- SEEPROM_OUTB(sd, 0);
-}
-
 static void
 write_brdctl(struct ahc_softc *ahc, uint8_t value)
 {
===== drivers/scsi/aic7xxx/scsi_message.h 1.2 vs edited =====
--- 1.2/drivers/scsi/aic7xxx/scsi_message.h Tue Feb 5 16:38:15 2002
+++ edited/drivers/scsi/aic7xxx/scsi_message.h Thu Oct 24 14:18:15 2002
@@ -46,7 +46,7 @@
 #define MSG_IDENTIFY_DISCFLAG 0x40
 #define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
 #define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG)
-#define MSG_IDENTIFY_LUNMASK 0x03F
+#define MSG_IDENTIFY_LUNMASK 0x3F
 
 /* Extended messages (opcode and length) */
 #define MSG_EXT_SDTR 0x01
@@ -60,6 +60,11 @@
 
 #define MSG_EXT_PPR 0x04 /* SPI3 */
 #define MSG_EXT_PPR_LEN 0x06
-#define MSG_EXT_PPR_QAS_REQ 0x04
-#define MSG_EXT_PPR_DT_REQ 0x02
+#define MSG_EXT_PPR_PCOMP_EN 0x80
+#define MSG_EXT_PPR_RTI 0x40
+#define MSG_EXT_PPR_RD_STRM 0x20
+#define MSG_EXT_PPR_WR_FLOW 0x10
+#define MSG_EXT_PPR_HOLD_MCS 0x08
+#define MSG_EXT_PPR_QAS_REQ 0x04
+#define MSG_EXT_PPR_DT_REQ 0x02
 #define MSG_EXT_PPR_IU_REQ 0x01
===== drivers/scsi/aic7xxx/aic7xxx_93cx6.h 1.2 vs edited =====
--- 1.2/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Tue Feb 5 16:53:47 2002
+++ edited/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Wed Oct 23 16:13:40 2002
@@ -38,9 +38,9 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#7 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#10 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.8 2000/11/10 20:13:41 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.7.2.3 2002/04/29 19:36:31 gibbs Exp $
  */
 #ifndef _AIC7XXX_93CX6_H_
 #define _AIC7XXX_93CX6_H_
@@ -93,8 +93,10 @@
 #define SEEPROM_DATA_INB(sd) \
         ahc_inb(sd->sd_ahc, sd->sd_dataout_offset)
 
-int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
- u_int start_addr, u_int count);
-int verify_cksum(struct seeprom_config *sc);
+int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+ u_int start_addr, u_int count);
+int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+ u_int start_addr, u_int count);
+int ahc_verify_cksum(struct seeprom_config *sc);
 
 #endif /* _AIC7XXX_93CX6_H_ */
===== drivers/scsi/aic7xxx/aic7xxx_93cx6.c 1.4 vs edited =====
--- 1.4/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Tue Feb 5 16:53:47 2002
+++ edited/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Wed Oct 23 16:12:20 2002
@@ -28,9 +28,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#10 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#15 $
  *
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.9 2000/11/10 20:13:41 gibbs Exp $
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.8.2.5 2002/04/29 19:36:31 gibbs Exp $
  */
 
 /*
@@ -77,9 +77,13 @@
  */
 static struct seeprom_cmd {
           uint8_t len;
- uint8_t bits[3];
+ uint8_t bits[9];
 } seeprom_read = {3, {1, 1, 0}};
 
+static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
+
 /*
  * Wait for the SEERDY to go high; about 800 ns.
  */
@@ -90,15 +94,55 @@
         (void)SEEPROM_INB(sd); /* Clear clock */
 
 /*
+ * Send a START condition and the given command
+ */
+static void
+send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd)
+{
+ uint8_t temp;
+ int i = 0;
+
+ /* Send chip select for one clock cycle. */
+ temp = sd->sd_MS ^ sd->sd_CS;
+ SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+
+ for (i = 0; i < cmd->len; i++) {
+ if (cmd->bits[i] != 0)
+ temp ^= sd->sd_DO;
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ if (cmd->bits[i] != 0)
+ temp ^= sd->sd_DO;
+ }
+}
+
+/*
+ * Clear CS put the chip in the reset state, where it can wait for new commands.
+ */
+static void
+reset_seeprom(struct seeprom_descriptor *sd)
+{
+ uint8_t temp;
+
+ temp = sd->sd_MS;
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+}
+
+/*
  * Read the serial EEPROM and returns 1 if successful and 0 if
  * not successful.
  */
 int
-read_seeprom(sd, buf, start_addr, count)
- struct seeprom_descriptor *sd;
- uint16_t *buf;
- u_int start_addr;
- u_int count;
+ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+ u_int start_addr, u_int count)
 {
         int i = 0;
         u_int k = 0;
@@ -110,26 +154,14 @@
          * will range from 0 to count-1.
          */
         for (k = start_addr; k < count + start_addr; k++) {
- /* Send chip select for one clock cycle. */
- temp = sd->sd_MS ^ sd->sd_CS;
- SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
- CLOCK_PULSE(sd, sd->sd_RDY);
-
                 /*
                  * Now we're ready to send the read command followed by the
                  * address of the 16-bit register we want to read.
                  */
- for (i = 0; i < seeprom_read.len; i++) {
- if (seeprom_read.bits[i] != 0)
- temp ^= sd->sd_DO;
- SEEPROM_OUTB(sd, temp);
- CLOCK_PULSE(sd, sd->sd_RDY);
- SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
- CLOCK_PULSE(sd, sd->sd_RDY);
- if (seeprom_read.bits[i] != 0)
- temp ^= sd->sd_DO;
- }
+ send_seeprom_cmd(sd, &seeprom_read);
+
                 /* Send the 6 or 8 bit address (MSB first, LSB last). */
+ temp = sd->sd_MS ^ sd->sd_CS;
                 for (i = (sd->sd_chip - 1); i >= 0; i--) {
                         if ((k & (1 << i)) != 0)
                                 temp ^= sd->sd_DO;
@@ -161,13 +193,7 @@
                 buf[k - start_addr] = v;
 
                 /* Reset the chip select for the next command cycle. */
- temp = sd->sd_MS;
- SEEPROM_OUTB(sd, temp);
- CLOCK_PULSE(sd, sd->sd_RDY);
- SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
- CLOCK_PULSE(sd, sd->sd_RDY);
- SEEPROM_OUTB(sd, temp);
- CLOCK_PULSE(sd, sd->sd_RDY);
+ reset_seeprom(sd);
         }
 #ifdef AHC_DUMP_EEPROM
         printf("\nSerial EEPROM:\n\t");
@@ -182,8 +208,77 @@
         return (1);
 }
 
+/*
+ * Write the serial EEPROM and return 1 if successful and 0 if
+ * not successful.
+ */
+int
+ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+ u_int start_addr, u_int count)
+{
+ uint16_t v;
+ uint8_t temp;
+ int i, k;
+
+ /* Place the chip into write-enable mode */
+ send_seeprom_cmd(sd, &seeprom_ewen);
+ reset_seeprom(sd);
+
+ /* Write all requested data out to the seeprom. */
+ temp = sd->sd_MS ^ sd->sd_CS;
+ for (k = start_addr; k < count + start_addr; k++) {
+ /* Send the write command */
+ send_seeprom_cmd(sd, &seeprom_write);
+
+ /* Send the 6 or 8 bit address (MSB first). */
+ for (i = (sd->sd_chip - 1); i >= 0; i--) {
+ if ((k & (1 << i)) != 0)
+ temp ^= sd->sd_DO;
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ if ((k & (1 << i)) != 0)
+ temp ^= sd->sd_DO;
+ }
+
+ /* Write the 16 bit value, MSB first */
+ v = buf[k - start_addr];
+ for (i = 15; i >= 0; i--) {
+ if ((v & (1 << i)) != 0)
+ temp ^= sd->sd_DO;
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ if ((v & (1 << i)) != 0)
+ temp ^= sd->sd_DO;
+ }
+
+ /* Wait for the chip to complete the write */
+ temp = sd->sd_MS;
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ temp = sd->sd_MS ^ sd->sd_CS;
+ do {
+ SEEPROM_OUTB(sd, temp);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+ CLOCK_PULSE(sd, sd->sd_RDY);
+ } while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0);
+
+ reset_seeprom(sd);
+ }
+
+ /* Put the chip back into write-protect mode */
+ send_seeprom_cmd(sd, &seeprom_ewds);
+ reset_seeprom(sd);
+
+ return (1);
+}
+
 int
-verify_cksum(struct seeprom_config *sc)
+ahc_verify_cksum(struct seeprom_config *sc)
 {
         int i;
         int maxaddr;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Oct 31 2002 - 22:00:26 EST