patch-1.3.41 linux/drivers/scsi/aic7xxx.c
Next file: linux/drivers/scsi/aic7xxx.seq
Previous file: linux/drivers/pci/pci.c
Back to the patch index
Back to the overall index
- Lines: 1509
- Date:
Mon Nov 13 08:03:45 1995
- Orig file:
v1.3.40/linux/drivers/scsi/aic7xxx.c
- Orig date:
Wed Nov 8 07:11:34 1995
diff -u --recursive --new-file v1.3.40/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -41,7 +41,7 @@
*
* -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
*
- * $Id: aic7xxx.c,v 2.5 1995/09/20 05:18:18 deang Exp $
+ * $Id: aic7xxx.c,v 2.10 1995/11/10 10:49:14 deang Exp $
*-M*************************************************************************/
#ifdef MODULE
@@ -73,7 +73,7 @@
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
-#define AIC7XXX_C_VERSION "$Revision: 2.5 $"
+#define AIC7XXX_C_VERSION "$Revision: 2.10 $"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) ((a < b) ? a : b)
@@ -163,7 +163,7 @@
* Define this to use polling rather than using kernel support for waking
* up a waiting process.
*/
-#undef AIC7XXX_POLL
+#define AIC7XXX_POLL
/*
* Controller type and options
@@ -172,9 +172,11 @@
AIC_NONE,
AIC_274x, /* EISA aic7770 */
AIC_284x, /* VLB aic7770 */
- AIC_7870, /* PCI aic7870 */
+ AIC_7870, /* PCI aic7870/aic7871 motherboard or 294x */
AIC_7850, /* PCI aic7850 */
- AIC_7872 /* PCI aic7870 on 394x */
+ AIC_7872, /* PCI aic7870 on 394x */
+ AIC_7880, /* PCI aic7880/aic7881 motherboard or 294x Ultra */
+ AIC_7882, /* PCI aic7870 on 394x Ultra */
} aha_type;
typedef enum {
@@ -247,6 +249,21 @@
#define ENAUTOATNP 0x02
#define SCSIRSTO 0x01
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+#define SXFRCTL0(x) ((x) + 0xC01ul)
+#define DFON 0x80
+#define DFPEXP 0x40
+#define ULTRAEN 0x20
+#define CLRSTCNT 0x10
+#define SPIOEN 0x08
+#define SCAMEN 0x04
+#define CLRCHN 0x02
+/* UNUSED 0x01 */
+
/*
* SCSI Transfer Control 1 Register (pp. 3-14,15).
* Controls the SCSI module data path.
@@ -395,28 +412,6 @@
/* UNUSED 0x07 */
/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device. In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device. When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM. When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted. See aic7xxx_read_eprom for detailed information on
- * the protocol necessary to read the serial EEPROM.
- */
-#define SEECTL(x) ((x) + 0xC1Eul)
-#define EXTARBACK 0x80
-#define EXTARBREQ 0x40
-#define SEEMS 0x20
-#define SEERDY 0x10
-#define SEECS 0x08
-#define SEECK 0x04
-#define SEEDO 0x02
-#define SEEDI 0x01
-
-/*
* SCSI Block Control (p. 3-32)
* Controls Bus type and channel selection. In a twin channel configuration
* addresses 0x00-0x1E are gated to the appropriate channel based on this
@@ -425,8 +420,11 @@
*/
#define SBLKCTL(x) ((x) + 0xC1Ful)
/* UNUSED 0xC0 */
+#define DIAGLEDEN 0x80
+#define DIAGLEDON 0x40
#define AUTOFLUSHDIS 0x20 /* used for Rev C check */
/* UNUSED 0x10 */
+#define SELBUS_MASK 0x0F
#define SELBUSB 0x08
/* UNUSED 0x04 */
#define SELWIDE 0x02
@@ -503,7 +501,7 @@
#define PAUSE 0x04
#define INTEN 0x02
#define CHIPRST 0x01
-#define REQ_PAUSE IRQMS | PAUSE | INTEN
+#define REQ_PAUSE IRQMS | INTEN | PAUSE
#define UNPAUSE_274X IRQMS | INTEN
#define UNPAUSE_284X INTEN
#define UNPAUSE_294X IRQMS | INTEN
@@ -603,11 +601,64 @@
/* ---------------- END AIC-7770 Register Definitions ----------------- */
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+#define SEECTL_2840(x) ((x) + 0xCC0ul)
+/* UNUSED 0xF8 */
+#define CS_2840 0x04
+#define CK_2840 0x02
+#define DO_2840 0x01
+
+#define STATUS_2840(x) ((x) + 0xCC1ul)
+#define EEPROM_TF 0x80
+#define BIOS_SEL 0x60
+#define ADSEL 0x1E
+#define DI_2840 0x01
+
/* --------------------- AIC-7870-only definitions -------------------- */
#define DSPCISTATUS(x) ((x) + 0xC86ul)
#define DFTHRESH 0xC0
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device. In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device. When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM. When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted. See aic7xxx_read_eprom for detailed information on
+ * the protocol necessary to read the serial EEPROM.
+ */
+#define SEECTL(x) ((x) + 0xC1Eul)
+#define EXTARBACK 0x80
+#define EXTARBREQ 0x40
+#define SEEMS 0x20
+#define SEERDY 0x10
+#define SEECS 0x08
+#define SEECK 0x04
+#define SEEDO 0x02
+#define SEEDI 0x01
+
+#define DEVREVID 0x08ul
+
+#define DEVSTATUS 0x40ul
+#define MPORTMODE 0x04 /* aic7870 only */
+#define RAMPSM 0x02 /* aic7870 only */
+#define VOLSENSE 0x01
+
+#define DEVCONFIG 0x41ul
+#define SCBRAMSEL 0x80
+#define MRDCEN 0x40
+#define EXTSCBTIME 0x20 /* aic7870 only */
+#define EXTSCBPEN 0x10 /* aic7870 only */
+#define BERREN 0x08
+#define DACEN 0x04
+#define STPWLEVEL 0x02
+#define DIFACTNEGEN 0x01 /* aic7870 only */
+
/* Scratch RAM offset definitions */
/* ---------------------- Scratch RAM Offsets ------------------------- */
@@ -726,9 +777,10 @@
/*
* Host Adapter Control Bits
*/
-/* UNUSED 0x0003 */
-#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
-#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
+/* UNUSED 0x0001 */
+#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
+#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
+#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
/* UNUSED 0x0020 */
#define CFRESETB 0x0040 /* reset SCSI bus at IC initialization */
@@ -780,7 +832,7 @@
*/
#define RESTART_SEQUENCER(p) \
do { \
- outb(SEQRESET | FASTMODE, SEQCTL(p->base)); \
+ outb(SEQRESET | FASTMODE, SEQCTL(p->base)); \
} while (inb(SEQADDR0(p->base)) != 0 && \
inb(SEQADDR1(p->base)) != 0); \
UNPAUSE_SEQUENCER(p);
@@ -905,13 +957,13 @@
/*-----------------end of hardware supported fields----------------*/
struct aic7xxx_scb *next; /* next ptr when in free list */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
- int state; /* current state of scb */
#define SCB_FREE 0x00
#define SCB_ACTIVE 0x01
#define SCB_ABORTED 0x02
#define SCB_DEVICE_RESET 0x04
#define SCB_IMMED 0x08
#define SCB_SENSE 0x10
+ int state; /* current state of scb */
unsigned int position; /* Position in scb array */
struct scatterlist sg;
struct scatterlist sense_sg;
@@ -947,7 +999,7 @@
* of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
* SEQUENCER CODE IF THIS IS MODIFIED!
*/
-#define AIC7XXX_MAXSCB 16
+#define AIC7XXX_MAXSCB 255
/*
* Define a structure used for each host adapter, only one per IRQ.
@@ -958,6 +1010,8 @@
int numscb; /* current number of scbs */
int extended; /* extended xlate? */
aha_type type; /* card type */
+ int ultra_enabled; /* Ultra SCSI speed enabled */
+ int chan_num; /* for 3940/3985, channel number */
aha_bus_type bus_type; /* normal/twin/wide bus */
unsigned char a_scanned; /* 0 not scanned, 1 scanned */
unsigned char b_scanned; /* 0 not scanned, 1 scanned */
@@ -1010,7 +1064,10 @@
int scsi_id_b; /* host SCSI ID B channel for twin cards */
int extended; /* extended xlate? */
int busrtime; /* bus release time */
+ int walk_scbs; /* external SCB RAM detected; walk the scb array */
aha_type type; /* card type */
+ int ultra_enabled; /* Ultra SCSI speed enabled */
+ int chan_num; /* for 3940/3985, channel number */
aha_bus_type bus_type; /* normal/twin/wide bus */
aha_status_type parity; /* bus parity enabled/disabled */
aha_status_type low_term; /* bus termination low byte */
@@ -1024,22 +1081,30 @@
*/
static struct {
short period;
+ /* Rates in Ultra mode have bit 8 of sxfr set */
+#define ULTRA_SXFR 0x100
short rate;
const char *english;
} aic7xxx_syncrates[] = {
- { 100, 0, "10.0" },
- { 125, 1, "8.0" },
- { 150, 2, "6.67" },
- { 175, 3, "5.7" },
- { 200, 4, "5.0" },
- { 225, 5, "4.4" },
- { 250, 6, "4.0" },
- { 275, 7, "3.6" }
+ { 50, 0x100, "20.0" },
+ { 62, 0x110, "16.0" },
+ { 75, 0x120, "13.4" },
+ { 100, 0x140, "10.0" },
+ { 100, 0x000, "10.0" },
+ { 125, 0x010, "8.0" },
+ { 150, 0x020, "6.67" },
+ { 175, 0x030, "5.7" },
+ { 200, 0x040, "5.0" },
+ { 225, 0x050, "4.4" },
+ { 250, 0x060, "4.0" },
+ { 275, 0x070, "3.6" }
};
static int num_aic7xxx_syncrates =
sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
+static int number_of_3940s = 0;
+
#ifdef AIC7XXX_DEBUG
static void
@@ -1101,7 +1166,7 @@
break;
case AIC_7870:
- printk("AIC7870%s (PCI-bus):\n", BUSW[p->bus_type]);
+ printk("AIC7870/7871%s (PCI-bus):\n", BUSW[p->bus_type]);
break;
case AIC_7850:
@@ -1112,6 +1177,14 @@
printk("AIC7872%s (PCI-bus):\n", BUSW[p->bus_type]);
break;
+ case AIC_7880:
+ printk("AIC7880/7881%s (PCI-bus):\n", BUSW[p->bus_type]);
+ break;
+
+ case AIC_7882:
+ printk("AIC7882%s (PCI-bus):\n", BUSW[p->bus_type]);
+ break;
+
default:
panic("aic7xxx debug_config: internal error\n");
}
@@ -1160,6 +1233,7 @@
}
}
+#if 0
static void
debug_scb(struct aic7xxx_scb *scb)
{
@@ -1183,6 +1257,7 @@
(unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
scb->position);
}
+#endif
#else
# define debug(fmt, args...)
@@ -1195,38 +1270,48 @@
* cards in the system. This should be fixed, but then,
* does anyone really have more than one in a machine?
*/
-static int aic7xxx_extended = 0; /* extended translation on? */
-static int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
+static unsigned int aic7xxx_extended = 0; /* extended translation on? */
+static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
/*+F*************************************************************************
* Function:
* aic7xxx_setup
*
* Description:
- * Handle Linux boot parameters.
+ * Handle Linux boot parameters. This routine allows for assigning a value
+ * to a parameter with a ':' between the parameter and the value.
+ * ie. aic7xxx=unpause:0x0A,extended
*-F*************************************************************************/
void
aic7xxx_setup(char *s, int *dummy)
{
- int i;
+ int i, n;
char *p;
static struct {
const char *name;
- int *flag;
+ unsigned int *flag;
} options[] = {
{ "extended", &aic7xxx_extended },
{ "no_reset", &aic7xxx_no_reset },
- { NULL, NULL}
+ { NULL, NULL }
};
for (p = strtok(s, ","); p; p = strtok(NULL, ","))
{
for (i = 0; options[i].name; i++)
{
- if (!strcmp(options[i].name, p))
+ n = strlen(options[i].name);
+ if (!strncmp(options[i].name, p, n))
{
- *(options[i].flag) = !0;
+ if (p[n] == ':')
+ {
+ *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+ }
+ else
+ {
+ *(options[i].flag) = !0;
+ }
}
}
}
@@ -1532,8 +1617,9 @@
* Look up the valid period to SCSIRATE conversion in our table
*-F*************************************************************************/
static void
-aic7xxx_scsirate(unsigned char *scsirate, unsigned char period,
- unsigned char offset, int target, char channel)
+aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
+ unsigned char period, unsigned char offset,
+ int target, char channel)
{
int i;
@@ -1541,8 +1627,38 @@
{
if ((aic7xxx_syncrates[i].period - period) >= 0)
{
- *scsirate = (aic7xxx_syncrates[i].rate << 4) | (offset & 0x0F);
- printk("aic7xxx: target %d, channel %c, now synchronous at %sMb/s, "
+ /*
+ * Watch out for Ultra speeds when ultra is not enabled and
+ * vice-versa.
+ */
+ if (p->ultra_enabled)
+ {
+ if (! (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+ {
+ printk ("aic7xxx: target %d, channel %c, requests %sMB/s transfers, "
+ "but adapter in Ultra mode can only sync at 10MB/s or "
+ "above.\n", target, channel, aic7xxx_syncrates[i].english);
+ break; /* Use asynchronous transfers. */
+ }
+ }
+ else
+ {
+ /*
+ * Check for an Ultra device trying to negotiate an Ultra rate
+ * on an adapter with Ultra mode disabled.
+ */
+ if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+ {
+ /*
+ * This should only happen if the driver is the first to negotiate
+ * and chooses a high rate. We'll just move down the table until
+ * we hit a non Ultra speed.
+ */
+ continue;
+ }
+ }
+ *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+ printk("aic7xxx: target %d, channel %c, now synchronous at %sMB/s, "
"offset = 0x%x\n",
target, channel, aic7xxx_syncrates[i].english, offset);
return;
@@ -2079,6 +2195,7 @@
outb(sblkctl ^ SELBUSB, SBLKCTL(base));
aic7xxx_reset_current_bus(base);
outb(sblkctl, SBLKCTL(base));
+
UNPAUSE_SEQUENCER(p);
}
/*
@@ -2280,7 +2397,7 @@
{
max_offset = 0x0F;
}
- aic7xxx_scsirate(&rate, transfer, MIN(offset, max_offset), scsi_id, channel);
+ aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset), scsi_id, channel);
/*
* Preserve the wide transfer flag.
*/
@@ -3004,6 +3121,152 @@
/*+F*************************************************************************
* Function:
+ * read_2840_seeprom
+ *
+ * Description:
+ * Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
+ * not successful.
+ *
+ * See read_seeprom (for the 2940) for the instruction set of the 93C46
+ * chip.
+ *
+ * The 2840 interface to the 93C46 serial EEPROM is through the
+ * STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and
+ * DO_2840 bits of the SEECTL_2840 register are connected to the chip
+ * select, clock, and data out lines respectively of the serial EEPROM.
+ * The DI_2840 bit of the STATUS_2840 is connected to the data in line
+ * of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is
+ * useful in that it gives us an 800 nsec timer. After a read from the
+ * SEECTL_2840 register the timing flag is cleard and goes high 800 nsec
+ * later.
+ *
+ *-F*************************************************************************/
+static int
+read_2840_seeprom(int base, struct seeprom_config *sc)
+{
+ int i = 0, k = 0;
+ unsigned char temp;
+ unsigned short checksum = 0;
+ unsigned short *seeprom = (unsigned short *) sc;
+ struct seeprom_cmd {
+ unsigned char len;
+ unsigned char bits[3];
+ };
+ struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+#define CLOCK_PULSE(p) \
+ while ((inb(STATUS_2840(base)) & EEPROM_TF) == 0) \
+ { \
+ ; /* Do nothing */ \
+ } \
+ (void) inb(SEECTL_2840(base));
+
+ /*
+ * Read the first 32 registers of the seeprom. For the 2840,
+ * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
+ * but only the first 32 are used by Adaptec BIOS. The loop
+ * will range from 0 to 31.
+ */
+ for (k = 0; k < (sizeof(*sc) / 2); k++)
+ {
+ /*
+ * Send chip select for one clock cycle.
+ */
+ outb(CK_2840 | CS_2840, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+
+ /*
+ * 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++)
+ {
+ temp = CS_2840 | seeprom_read.bits[i];
+ outb(temp, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ temp = temp ^ CK_2840;
+ outb(temp, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ }
+ /*
+ * Send the 6 bit address (MSB first, LSB last).
+ */
+ for (i = 5; i >= 0; i--)
+ {
+ temp = k;
+ temp = (temp >> i) & 1; /* Mask out all but lower bit. */
+ temp = CS_2840 | temp;
+ outb(temp, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ temp = temp ^ CK_2840;
+ outb(temp, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ }
+
+ /*
+ * Now read the 16 bit register. An initial 0 precedes the
+ * register contents which begins with bit 15 (MSB) and ends
+ * with bit 0 (LSB). The initial 0 will be shifted off the
+ * top of our word as we let the loop run from 0 to 16.
+ */
+ for (i = 0; i <= 16; i++)
+ {
+ temp = CS_2840;
+ outb(temp, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ temp = temp ^ CK_2840;
+ seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840(base)) & DI_2840);
+ outb(temp, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ }
+ /*
+ * The serial EEPROM has a checksum in the last word. Keep a
+ * running checksum for all words read except for the last
+ * word. We'll verify the checksum after all words have been
+ * read.
+ */
+ if (k < (sizeof(*sc) / 2) - 1)
+ {
+ checksum = checksum + seeprom[k];
+ }
+
+ /*
+ * Reset the chip select for the next command cycle.
+ */
+ outb(0, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ outb(CK_2840, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ outb(0, SEECTL_2840(base));
+ CLOCK_PULSE(base);
+ }
+
+#if 0
+ printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+ printk("Serial EEPROM:");
+ for (k = 0; k < (sizeof(*sc) / 2); k++)
+ {
+ if (((k % 8) == 0) && (k != 0))
+ {
+ printk("\n ");
+ }
+ printk(" 0x%x", seeprom[k]);
+ }
+ printk("\n");
+#endif
+
+ if (checksum != sc->checksum)
+ {
+ printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+ return (0);
+ }
+
+ return (1);
+#undef CLOCK_PULSE
+}
+
+/*+F*************************************************************************
+ * Function:
* read_seeprom
*
* Description:
@@ -3052,9 +3315,9 @@
*
*-F*************************************************************************/
static int
-read_seeprom(int base, struct seeprom_config *sc)
+read_seeprom(int base, int offset, struct seeprom_config *sc)
{
- int i = 0, k = 0;
+ int i = 0, k;
unsigned long timeout;
unsigned char temp;
unsigned short checksum = 0;
@@ -3122,7 +3385,7 @@
*/
for (i = 5; i >= 0; i--)
{
- temp = k;
+ temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = SEEMS | SEECS | (temp << 1);
outb(temp, SEECTL(base));
@@ -3197,6 +3460,7 @@
}
return (1);
+#undef CLOCK_PULSE
}
/*+F*************************************************************************
@@ -3207,10 +3471,10 @@
* Return the maximum number of SCB's allowed for a given controller.
*-F*************************************************************************/
static int
-detect_maxscb(aha_type type, int base)
+detect_maxscb(aha_type type, int base, int walk_scbs)
{
- unsigned char sblkctl_reg;
- int maxscb = 0;
+ unsigned char sblkctl_reg, scb_byte;
+ int maxscb = 0, i;
switch (type)
{
@@ -3248,14 +3512,15 @@
break;
case AIC_7870:
+ case AIC_7880:
maxscb = 16;
break;
case AIC_7872:
+ case AIC_7882:
/*
- * Really has 255, but we'll wait to verify that we access
- * them the same way and do not have to set the card to
- * use the memory port to access external SCB RAM.
+ * Is suppose to have 255 SCBs, but we'll walk the SCBs
+ * looking for more if external RAM is detected.
*/
maxscb = 16;
break;
@@ -3266,6 +3531,26 @@
*/
break;
}
+ if (walk_scbs)
+ {
+ /*
+ * This adapter has external SCB memory.
+ * Walk the SCBs to determine how many there are.
+ */
+ i = 0;
+ while (i < AIC7XXX_MAXSCB)
+ {
+ outb(i, SCBPTR(base));
+ scb_byte = ~(inb(SCBARRAY(base))); /* complement the byte */
+ outb(scb_byte, SCBARRAY(base)); /* write it back out */
+ if (inb(SCBARRAY(base)) != scb_byte)
+ {
+ break;
+ }
+ i++;
+ }
+ maxscb = i;
+ }
return (maxscb);
}
@@ -3278,41 +3563,35 @@
* Register a Adaptec aic7xxx chip SCSI controller with the kernel.
*-F*************************************************************************/
static int
-aic7xxx_register(Scsi_Host_Template *template, aha_type type,
- int base, unsigned char irq)
+aic7xxx_register(Scsi_Host_Template *template,
+ struct aic7xxx_host_config *config)
{
- static const char * board_name[] = {"", "274x", "284x", "7870", "7850", "7872"};
+ static const char * board_name[] = {"", "274x", "284x", "7870", "7850",
+ "7872", "7881"};
int i;
unsigned char sblkctl;
int max_targets;
- int found = 1;
+ int found = 1, base;
int bios_disabled = 0;
unsigned char target_settings;
unsigned char scsi_conf, host_conf;
int have_seeprom = 0;
struct Scsi_Host *host;
struct aic7xxx_host *p;
- struct aic7xxx_host_config config;
struct seeprom_config sc;
- config.type = type;
- config.base = base;
- config.irq = irq;
- config.parity = AIC_UNKNOWN;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
- config.busrtime = 0;
+ base = config->base;
/*
* Lock out other contenders for our i/o space.
*/
request_region(MINREG(base), MAXREG(base) - MINREG(base), "aic7xxx");
- switch (type)
+ switch (config->type)
{
case AIC_274x:
#if 0
- printk("aha274x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+ printk("aha274x: HCNTRL:0x%x\n", inb(HCNTRL(base)));
#endif
/*
* For some 274x boards, we must clear the CHIPRST bit
@@ -3324,147 +3603,157 @@
* trigger type (level or edge) and use this value
* for pausing and unpausing the sequencer.
*/
- config.unpause = (inb(HCNTRL(config.base)) & IRQMS) | INTEN;
- config.pause = config.unpause | PAUSE;
- config.extended = aic7xxx_extended;
+ config->unpause = (inb(HCNTRL(base)) & IRQMS) | INTEN;
+ config->pause = config->unpause | PAUSE;
+ config->extended = aic7xxx_extended;
- /*
- * I don't think we need to kick the reset again, the initial probe
- * does a reset, it seems that this is kicking a dead horse here.
- * So... I will try to just verify that the chip has come out of the
- * reset state and continue the same as the 284x.
- * In the Calgary version of the driver:
- * 1) Chip Reset
- * 2) Set unpause to IRQMS | INTEN
- * 3) If an interrupt occured without any commands queued, the
- * unpause was set to just INTEN
- * I changed the initial reset code to just mask in the CHIPRST bit
- * and try to leave the other settings alone.
- *
- * I don't think we need the warning about chip reset not being clear.
- * On both my test machines (2842 & 2940), they work just fine with a
- * HCNTRL() of 0x5 (PAUSE | CHIPRST). Notice though, the 274x also
- * adds the INTEN flag, where neither the 284x or 294x do.
- */
- outb(config.pause | CHIPRST, HCNTRL(config.base));
+ outb(config->pause | CHIPRST, HCNTRL(base));
aic7xxx_delay(1);
- if (inb(HCNTRL(config.base)) & CHIPRST)
+ if (inb(HCNTRL(base)) & CHIPRST)
{
printk("aic7xxx_register: Chip reset not cleared; clearing manually.\n");
}
- outb(config.pause, HCNTRL(config.base));
+ outb(config->pause, HCNTRL(base));
/*
* Just to be on the safe side with the 274x, we will re-read the irq
* since there was some issue about reseting the board.
*/
- config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+ config->irq = inb(HA_INTDEF(base)) & 0x0F;
if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
{
bios_disabled = 1;
}
- host_conf = inb(HA_HOSTCONF(config.base));
- config.busrtime = host_conf & 0x3C;
+ host_conf = inb(HA_HOSTCONF(base));
+ config->busrtime = host_conf & 0x3C;
/* XXX Is this valid for motherboard based controllers? */
/* Setup the FIFO threshold and the bus off time */
- outb(host_conf & DFTHRSH, BUSSPD(config.base));
- outb((host_conf << 2) & BOFF, BUSTIME(config.base));
+ outb(host_conf & DFTHRSH, BUSSPD(base));
+ outb((host_conf << 2) & BOFF, BUSTIME(base));
/*
* A reminder until this can be detected automatically.
*/
- printk("aha274x: extended translation %sabled\n",
- config.extended ? "en" : "dis");
+ printk("aha274x: Extended translation %sabled\n",
+ config->extended ? "en" : "dis");
break;
case AIC_284x:
#if 0
- printk("aha284x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+ printk("aha284x: HCNTRL:0x%x\n", inb(HCNTRL(base)));
#endif
- outb(CHIPRST, HCNTRL(config.base));
- config.unpause = UNPAUSE_284X;
- config.pause = REQ_PAUSE; /* DWG would like to be like the rest */
- config.extended = aic7xxx_extended;
- config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+ outb(CHIPRST, HCNTRL(base));
+ config->unpause = UNPAUSE_284X;
+ config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
+ aic7xxx_delay(1);
+ outb(config->pause, HCNTRL(base));
+
+ config->extended = aic7xxx_extended;
+ config->irq = inb(HA_INTDEF(base)) & 0x0F;
if ((inb(HA_274_BIOSCTRL(base)) & BIOSMODE) == BIOSDISABLED)
{
bios_disabled = 1;
}
- host_conf = inb(HA_HOSTCONF(config.base));
- config.busrtime = host_conf & 0x3C;
+ host_conf = inb(HA_HOSTCONF(base));
+
+ printk("aha284x: Reading SEEPROM...");
+ have_seeprom = read_2840_seeprom(base, &sc);
+ if (!have_seeprom)
+ {
+ printk("aha284x: Unable to read SEEPROM\n");
+ config->busrtime = host_conf & 0x3C;
+ }
+ else
+ {
+ printk("done.\n");
+ config->extended = ((sc.bios_control & CFEXTEND) >> 7);
+ config->scsi_id = (sc.brtime_id & CFSCSIID);
+ config->parity = (sc.adapter_control & CFSPARITY) ?
+ AIC_ENABLED : AIC_DISABLED;
+ config->low_term = (sc.adapter_control & CFSTERM) ?
+ AIC_ENABLED : AIC_DISABLED;
+ config->high_term = (sc.adapter_control & CFWSTERM) ?
+ AIC_ENABLED : AIC_DISABLED;
+ config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+ }
/* XXX Is this valid for motherboard based controllers? */
/* Setup the FIFO threshold and the bus off time */
- outb(host_conf & DFTHRSH, BUSSPD(config.base));
- outb((host_conf << 2) & BOFF, BUSTIME(config.base));
+ outb(host_conf & DFTHRSH, BUSSPD(base));
+ outb((host_conf << 2) & BOFF, BUSTIME(base));
- /*
- * A reminder until this can be detected automatically.
- */
- printk("aha284x: extended translation %sabled\n",
- config.extended ? "en" : "dis");
+ printk("aha284x: Extended translation %sabled\n",
+ config->extended ? "en" : "dis");
break;
case AIC_7850:
case AIC_7870:
case AIC_7872:
+ case AIC_7880:
+ case AIC_7882:
#if 0
- printk("aic%s hcntrl=0x%x\n", board_name[type], inb(HCNTRL(config.base)));
+ printk("aic%s HCNTRL:0x%x\n", board_name[config->type], inb(HCNTRL(base)));
#endif
- outb(CHIPRST, HCNTRL(config.base));
- config.unpause = UNPAUSE_294X;
- config.pause = config.unpause | PAUSE;
- config.extended = aic7xxx_extended;
- config.scsi_id = 7;
+ outb(CHIPRST, HCNTRL(base));
+ config->unpause = UNPAUSE_294X;
+ config->pause = config->unpause | PAUSE;
+ aic7xxx_delay(1);
+ outb(config->pause, HCNTRL(base));
- printk("aic78xx: Reading SEEPROM... ");
- have_seeprom = read_seeprom(base, &sc);
+ config->extended = aic7xxx_extended;
+ config->scsi_id = 7;
+
+ printk("aic78xx: Reading SEEPROM...");
+ have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2), &sc);
if (!have_seeprom)
{
- printk("aic78xx: unable to read SEEPROM\n");
+ printk("aic78xx: Unable to read SEEPROM\n");
}
else
{
- printk("done\n");
- config.extended = ((sc.bios_control & CFEXTEND) >> 7);
- config.scsi_id = (sc.brtime_id & CFSCSIID);
- config.parity = (sc.adapter_control & CFSPARITY) ?
+ printk("done.\n");
+ config->extended = ((sc.bios_control & CFEXTEND) >> 7);
+ config->scsi_id = (sc.brtime_id & CFSCSIID);
+ config->parity = (sc.adapter_control & CFSPARITY) ?
AIC_ENABLED : AIC_DISABLED;
- config.low_term = (sc.adapter_control & CFSTERM) ?
+ config->low_term = (sc.adapter_control & CFSTERM) ?
AIC_ENABLED : AIC_DISABLED;
- config.high_term = (sc.adapter_control & CFWSTERM) ?
+ config->high_term = (sc.adapter_control & CFWSTERM) ?
AIC_ENABLED : AIC_DISABLED;
- config.busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+ config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+ if (((config->type == AIC_7880) || (config->type == AIC_7882)) &&
+ (sc.adapter_control & CFULTRAEN))
+ {
+ printk ("aic7xxx: Enabling support for Ultra SCSI speed.\n");
+ config->ultra_enabled = TRUE;
+ }
}
/*
* XXX - force data fifo threshold to 100%. Why does this
* need to be done?
*/
- outb(inb(DSPCISTATUS(config.base)) | DFTHRESH, DSPCISTATUS(config.base));
- outb(config.scsi_id | DFTHRESH, HA_SCSICONF(config.base));
+ outb(inb(DSPCISTATUS(base)) | DFTHRESH, DSPCISTATUS(base));
+ outb(config->scsi_id | DFTHRESH, HA_SCSICONF(base));
/*
* In case we are a wide card, place scsi ID in second conf byte.
*/
- outb(config.scsi_id, (HA_SCSICONF(config.base) + 1));
+ outb(config->scsi_id, (HA_SCSICONF(base) + 1));
- /*
- * A reminder until this can be detected automatically.
- */
- printk("aic%s: extended translation %sabled\n", board_name[type],
- config.extended ? "en" : "dis");
+ printk("aic%s: Extended translation %sabled\n", board_name[config->type],
+ config->extended ? "en" : "dis");
break;
default:
panic("aic7xxx_register: internal error\n");
}
- config.maxscb = detect_maxscb(type, base);
+ config->maxscb = detect_maxscb(config->type, base, config->walk_scbs);
- if ((config.type == AIC_274x) || (config.type == AIC_284x))
+ if ((config->type == AIC_274x) || (config->type == AIC_284x))
{
- if (config.pause & IRQMS)
+ if (config->pause & IRQMS)
{
printk("aic7xxx: Using Level Sensitive Interrupts\n");
}
@@ -3478,35 +3767,35 @@
* Read the bus type from the SBLKCTL register. Set the FLAGS
* register in the sequencer for twin and wide bus cards.
*/
- sblkctl = inb(SBLKCTL(base)) & 0x0F; /* mask out upper two bits */
- switch (sblkctl)
+ sblkctl = inb(SBLKCTL(base));
+ switch (sblkctl & SELBUS_MASK)
{
case SELSINGLE: /* narrow/normal bus */
- config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
- config.bus_type = AIC_SINGLE;
+ config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+ config->bus_type = AIC_SINGLE;
outb(SINGLE_BUS, HA_FLAGS(base));
break;
case SELWIDE: /* Wide bus */
- config.scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
- config.bus_type = AIC_WIDE;
+ config->scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
+ config->bus_type = AIC_WIDE;
printk("aic7xxx: Enabling wide channel of %s-Wide\n",
- board_name[config.type]);
+ board_name[config->type]);
outb(WIDE_BUS, HA_FLAGS(base));
break;
case SELBUSB: /* Twin bus */
- config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+ config->scsi_id = inb(HA_SCSICONF(base)) & 0x07;
#ifdef AIC7XXX_TWIN_SUPPORT
- config.scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
- config.bus_type = AIC_TWIN;
+ config->scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
+ config->bus_type = AIC_TWIN;
printk("aic7xxx: Enabled channel B of %s-Twin\n",
- board_name[config.type]);
+ board_name[config->type]);
outb(TWIN_BUS, HA_FLAGS(base));
#else
- config.bus_type = AIC_SINGLE;
+ config->bus_type = AIC_SINGLE;
printk("aic7xxx: Channel B of %s-Twin will be ignored\n",
- board_name[config.type]);
+ board_name[config->type]);
outb(0, HA_FLAGS(base));
#endif
break;
@@ -3519,12 +3808,11 @@
}
/*
- * Clear the upper two bits. For the 294x cards, clearing the
- * upper two bits, will take the card out of diagnostic mode
- * and make the host adatper LED follow bus activity (will not
- * always be on).
+ * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
+ * take the card out of diagnostic mode and make the host adatper
+ * LED follow bus activity (will not always be on).
*/
- outb(sblkctl, SBLKCTL(base));
+ outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL(base));
/*
* The IRQ level in i/o port 4 maps directly onto the real
@@ -3536,10 +3824,10 @@
*
* The 294x cards (PCI) get their interrupt from PCI BIOS.
*/
- if (((config.type == AIC_274x) || (config.type == AIC_284x))
- && (config.irq < 9 || config.irq > 15))
+ if (((config->type == AIC_274x) || (config->type == AIC_284x)) &&
+ (config->irq < 9 || config->irq > 15))
{
- printk("aic7xxx uses unsupported IRQ level, ignoring\n");
+ printk("aic7xxx uses unsupported IRQ level, ignoring.\n");
return (0);
}
@@ -3551,7 +3839,7 @@
* proceed.
*/
#ifndef AIC7XXX_SHARE_IRQS
- if (aic7xxx_boards[config.irq] != NULL)
+ if (aic7xxx_boards[config->irq] != NULL)
{
printk("aic7xxx_register: Sharing of IRQs is not configured.\n");
return (0);
@@ -3563,7 +3851,7 @@
* the card - a lot of registers on it can't be read
* when the sequencer is active.
*/
- debug_config(&config);
+ debug_config(config);
/*
* Before registry, make sure that the offsets of the
@@ -3579,7 +3867,7 @@
if (SG_STRUCT_CHECK(sg))
{
printk("aic7xxx warning: kernel scatter-gather "
- "structures changed, disabling it\n");
+ "structures changed, disabling it.\n");
template->sg_tablesize = SG_NONE;
}
}
@@ -3593,15 +3881,15 @@
* information when an IRQ is triggered.
*/
host = scsi_register(template, sizeof(struct aic7xxx_host));
- host->can_queue = config.maxscb;
+ host->can_queue = config->maxscb;
host->cmd_per_lun = AIC7XXX_CMDS_PER_LUN;
- host->this_id = config.scsi_id;
- host->irq = config.irq;
- if (config.bus_type == AIC_WIDE)
+ host->this_id = config->scsi_id;
+ host->irq = config->irq;
+ if (config->bus_type == AIC_WIDE)
{
host->max_id = 16;
}
- if (config.bus_type == AIC_TWIN)
+ if (config->bus_type == AIC_TWIN)
{
host->max_channel = 1;
}
@@ -3621,21 +3909,23 @@
p->isr_count = 0;
p->a_scanned = 0;
p->b_scanned = 0;
- p->base = config.base;
- p->maxscb = config.maxscb;
+ p->base = base;
+ p->maxscb = config->maxscb;
p->numscb = 0;
- p->extended = config.extended;
- p->type = config.type;
- p->bus_type = config.bus_type;
+ p->extended = config->extended;
+ p->type = config->type;
+ p->ultra_enabled = config->ultra_enabled;
+ p->chan_num = config->chan_num;
+ p->bus_type = config->bus_type;
p->have_seeprom = have_seeprom;
p->seeprom = sc;
p->free_scb = NULL;
p->next = NULL;
- p->unpause = config.unpause;
- p->pause = config.pause;
+ p->unpause = config->unpause;
+ p->pause = config->pause;
- if (aic7xxx_boards[config.irq] == NULL)
+ if (aic7xxx_boards[config->irq] == NULL)
{
/*
* Warning! This must be done before requesting the irq. It is
@@ -3644,15 +3934,15 @@
* kernel, an interrupt is triggered immediately. Therefore, we
* must ensure the board data is correctly set before the request.
*/
- aic7xxx_boards[config.irq] = host;
+ aic7xxx_boards[config->irq] = host;
/*
* Register IRQ with the kernel.
*/
- if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
+ if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
{
- printk("aic7xxx couldn't register irq %d, ignoring\n", config.irq);
- aic7xxx_boards[config.irq] = NULL;
+ printk("aic7xxx couldn't register irq %d, ignoring\n", config->irq);
+ aic7xxx_boards[config->irq] = NULL;
return (0);
}
}
@@ -3663,8 +3953,8 @@
* registered host adapter. Add this host adapter's Scsi_Host
* to the beginning of the linked list of hosts at the same IRQ.
*/
- p->next = aic7xxx_boards[config.irq];
- aic7xxx_boards[config.irq] = host;
+ p->next = aic7xxx_boards[config->irq];
+ aic7xxx_boards[config->irq] = host;
}
/*
@@ -3674,7 +3964,7 @@
* but then your mailing address is dynamically assigned
* so no one can find you anyway :-)
*/
- printk("aic7xxx: Downloading sequencer code..");
+ printk("aic7xxx: Downloading sequencer code...");
aic7xxx_loadseq(base);
/*
@@ -3690,27 +3980,37 @@
printk("done.\n");
/*
- * Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels
+ * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->bus_type == AIC_TWIN)
{
/*
- * The device is gated to channel B after a chip reset,
- * so set those values first.
+ * Select Channel B.
*/
- outb(config.scsi_id_b, SCSIID(base));
+ outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
+
+ outb(config->scsi_id_b, SCSIID(base));
scsi_conf = inb(HA_SCSICONF(base) + 1) & (ENSPCHK | STIMESEL);
outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+ if (p->ultra_enabled)
+ {
+ outb(ULTRAEN, SXFRCTL0(base));
+ }
+
/*
* Select Channel A
*/
- outb(SELSINGLE, SBLKCTL(base));
+ outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
}
- outb(config.scsi_id, SCSIID(base));
+ outb(config->scsi_id, SCSIID(base));
scsi_conf = inb(HA_SCSICONF(base)) & (ENSPCHK | STIMESEL);
outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+ if (p->ultra_enabled)
+ {
+ outb(ULTRAEN, SXFRCTL0(base));
+ }
/*
* Look at the information that board initialization or the board
@@ -3732,6 +4032,7 @@
{
max_targets = 16;
}
+
/*
* Grab the disconnection disable table and invert it for our needs
*/
@@ -3743,13 +4044,14 @@
{
if (bios_disabled)
{
- printk("aic7xxx : Host Adapter Bios disabled. Using default SCSI "
+ printk("aic7xxx : Host Adapter Bios disabled. Using default SCSI "
"device parameters\n");
p->discenable = 0xFFFF;
}
else
{
- p->discenable = ~(inw(HA_DISC_DSB(base)));
+ p->discenable = ~((inb(HA_DISC_DSB(base + 1)) << 8) |
+ inb(HA_DISC_DSB(base)));
}
}
@@ -3807,7 +4109,7 @@
* Clear the control byte for every SCB so that the sequencer
* doesn't get confused and think that one of them is valid
*/
- for (i = 0; i < config.maxscb; i++)
+ for (i = 0; i < config->maxscb; i++)
{
outb(i, SCBPTR(base));
outb(0, SCBARRAY(base));
@@ -3817,7 +4119,7 @@
* For reconnecting targets, the sequencer code needs to
* know how many SCBs it has to search through.
*/
- outb(config.maxscb, HA_SCBCOUNT(base));
+ outb(config->maxscb, HA_SCBCOUNT(base));
/*
* Clear the active flags - no targets are busy.
@@ -3846,26 +4148,31 @@
if (!aic7xxx_no_reset)
{
- printk("Resetting the SCSI bus...\n");
+ printk("aic7xxx: Resetting the SCSI bus...");
if (p->bus_type == AIC_TWIN)
{
/*
- * Select channel B.
+ * Select Channel B.
*/
- outb(SELBUSB, SBLKCTL(base));
+ outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL(base));
+
outb(SCSIRSTO, SCSISEQ(base));
udelay(1000);
outb(0, SCSISEQ(base));
+
/*
- * Select channel A.
+ * Select Channel A.
*/
- outb(SELSINGLE, SBLKCTL(base));
+ outb((sblkctl & ~SELBUS_MASK) | SELSINGLE, SBLKCTL(base));
}
outb(SCSIRSTO, SCSISEQ(base));
udelay(1000);
outb(0, SCSISEQ(base));
+
aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+ printk("done.\n");
}
/*
@@ -3891,8 +4198,10 @@
int found = 0, slot, base;
unsigned char irq = 0;
int i;
+ struct aic7xxx_host_config config;
template->proc_dir = &proc_scsi_aic7xxx;
+ config.chan_num = 0;
/*
* Since we may allow sharing of IRQs, it is imperative
@@ -3936,9 +4245,8 @@
aic7xxx_spurious_count = 1;
#if 0
- printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
+ printk("aic7xxx: HCNTRL:0x%x\n", inb(HCNTRL(base)));
outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
- irq = inb(HA_INTDEF(base)) & 0x0F;
#endif
/*
@@ -3946,7 +4254,16 @@
* signature and we can set it up and register
* it with the kernel without incident.
*/
- found += aic7xxx_register(template, type, base, irq);
+ config.type = type;
+ config.base = base;
+ config.irq = irq;
+ config.parity = AIC_UNKNOWN;
+ config.low_term = AIC_UNKNOWN;
+ config.high_term = AIC_UNKNOWN;
+ config.busrtime = 0;
+ config.walk_scbs = FALSE;
+ config.ultra_enabled = FALSE;
+ found += aic7xxx_register(template, &config);
/*
* Disallow spurious interrupts.
@@ -3957,11 +4274,6 @@
#ifdef CONFIG_PCI
-#define DEVREVID 0x08
-#define DEVCONFIG 0x40
-#define DEVSTATUS 0x41
-#define RAMPSM 0x02
-
/*
* PCI-bus probe.
*/
@@ -4001,12 +4313,35 @@
index, &pci_bus, &pci_device_fn))
{
type = AIC_7872;
+ config.chan_num = number_of_3940s & 0x1;
+ number_of_3940s++;
}
else
{
- type = AIC_NONE;
- done = 1;
- }
+ if ((!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_7881,
+ index, &pci_bus, &pci_device_fn)) ||
+ (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_7880,
+ index, &pci_bus, &pci_device_fn)))
+ {
+ type = AIC_7880;
+ }
+ else
+ {
+ if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_7882,
+ index, &pci_bus, &pci_device_fn))
+ {
+ type = AIC_7882;
+ }
+ else
+ {
+ type = AIC_NONE;
+ done = 1;
+ }
+ }
+ }
}
}
@@ -4017,7 +4352,6 @@
*/
error = pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &io_port);
-
if (error)
{
panic("aic7xxx_detect: error 0x%x reading i/o port.\n", error);
@@ -4030,42 +4364,62 @@
panic("aic7xxx_detect: error %d reading irq.\n", error);
}
- /*
- * Make the base I/O register look like EISA and VL-bus.
- */
- base = io_port - 0xC01;
-
- /*
- * I don't think we need to bother with allowing
- * spurious interrupts for the 787x/7850, but what
- * the hey.
- */
- aic7xxx_spurious_count = 1;
-
-#if 0
- printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
-#endif
- outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
-
error = pcibios_read_config_byte(pci_bus, pci_device_fn,
DEVREVID, &devrevid);
+ if (error)
+ {
+ panic("aic7xxx_detect: error %d reading device revision id.\n", error);
+ }
+
if (devrevid < 3)
{
printk("aic7xxx_detect: AIC-7870 Rev %c\n", rev_id[devrevid]);
}
+
error = pcibios_read_config_byte(pci_bus, pci_device_fn,
DEVCONFIG, &devconfig);
+ if (error)
+ {
+ panic("aic7xxx_detect: error %d reading device configuration.\n", error);
+ }
+
error = pcibios_read_config_byte(pci_bus, pci_device_fn,
DEVSTATUS, &devstatus);
+ if (error)
+ {
+ panic("aic7xxx_detect: error %d reading device status.\n", error);
+ }
+
printk("aic7xxx_detect: devconfig 0x%x, devstatus 0x%x\n",
devconfig, devstatus);
- if (devstatus & RAMPSM)
+
+ /*
+ * Make the base I/O register look like EISA and VL-bus.
+ */
+ base = io_port - 0xC01;
+
+ /*
+ * I don't think we need to bother with allowing
+ * spurious interrupts for the 787x/7850, but what
+ * the hey.
+ */
+ aic7xxx_spurious_count = 1;
+
+ config.type = type;
+ config.base = base;
+ config.irq = irq;
+ config.parity = AIC_UNKNOWN;
+ config.low_term = AIC_UNKNOWN;
+ config.high_term = AIC_UNKNOWN;
+ config.busrtime = 0;
+ config.walk_scbs = FALSE;
+ config.ultra_enabled = FALSE;
+ if ((devstatus & RAMPSM) || (devconfig & SCBRAMSEL) ||
+ (type == AIC_7872))
{
- printk("aic7xxx_detect: detected external SCB RAM, "
- "mail deang@ims.com for test patch");
+ config.walk_scbs = TRUE;
}
-
- found += aic7xxx_register(template, type, base, irq);
+ found += aic7xxx_register(template, &config);
/*
* Disable spurious interrupts.
@@ -4530,8 +4884,24 @@
save_flags(flags);
cli();
- aic7xxx_abort_scb(p, scb);
-
+ if (scb->state & SCB_ACTIVE)
+ {
+ if (scb->state & SCB_IMMED)
+ {
+ /*
+ * Don't know how set the number of retries to 0.
+ */
+ /* cmd->retries = 0; */
+ aic7xxx_done (p, scb);
+ }
+ else
+ {
+ /*
+ * Abort the operation.
+ */
+ aic7xxx_abort_scb(p, scb);
+ }
+ }
restore_flags(flags);
return (0);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this