patch-2.0.23 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: 1392
- Date:
Sun Oct 13 13:42:28 1996
- Orig file:
v2.0.22/linux/drivers/scsi/aic7xxx.c
- Orig date:
Sat Aug 17 21:19:27 1996
diff -u --recursive --new-file v2.0.22/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -41,7 +41,7 @@
*
* -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
*
- * $Id: aic7xxx.c,v 3.4 1996/08/09 15:56:31 deang Exp $
+ * $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
*-M*************************************************************************/
#ifdef MODULE
@@ -50,6 +50,7 @@
#include <stdarg.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -66,15 +67,22 @@
#include "aic7xxx.h"
#include "aic7xxx_reg.h"
#include <linux/stat.h>
+#include <linux/malloc.h> /* for kmalloc() */
#include <linux/config.h> /* for CONFIG_PCI */
+/*
+ * To generate the correct addresses for the controller to issue
+ * on the bus. Originally added for DEC Alpha support.
+ */
+#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
+
struct proc_dir_entry proc_scsi_aic7xxx = {
PROC_SCSI_AIC7XXX, 7, "aic7xxx",
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
-#define AIC7XXX_C_VERSION "$Revision: 3.4 $"
+#define AIC7XXX_C_VERSION "$Revision: 4.0 $"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) ((a < b) ? a : b)
@@ -133,12 +141,13 @@
* o 3985 support - The 3985 adapter is much like the 3940, but
* has three 7870 controllers as opposed to two for the 3940.
* It will get probed and recognized as three different adapters,
- * but all three controllers share the same bank of 255 SCBs
- * instead of each controller having their own bank (like the
- * controllers on the 3940). For this reason, it is important
- * that all devices be resident on just one channel of the 3985.
- * In the near future, we'll modify the driver to reserve 1/3
- * of the SCBs for each controller.
+ * but all three controllers can share the same external bank of
+ * 255 SCBs. If you enable AIC7XXX_SHARE_SCBS, then the driver
+ * will attempt to share the common bank of SCBs between the three
+ * controllers of the 3985. This is experimental and hasn't
+ * been tested. By default, we do not share the bank of SCBs,
+ * and force the controllers to use their own internal bank of
+ * 16 SCBs. Please let us know if sharing the SCB array works.
*
* o SCB paging support - SCB paging is enabled by defining
* AIC7XXX_PAGE_ENABLE. Support for this was taken from the
@@ -173,6 +182,7 @@
* Uncomment the following define for collection of SCSI transfer statistics
* for the /proc filesystem.
*
+ * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
* NOTE: This does affect performance since it has to maintain statistics.
*/
/* #define AIC7XXX_PROC_STATS */
@@ -183,6 +193,12 @@
/* #define AIC7XXX_PAGE_ENABLE */
/*
+ * Uncomment the following to enable sharing of the external bank
+ * of 255 SCBs for the 3985.
+ */
+#define AIC7XXX_SHARE_SCBS
+
+/*
* For debugging the abort/reset code.
*/
#define AIC7XXX_DEBUG_ABORT
@@ -203,6 +219,7 @@
AIC_7850, /* PCI aic7850 */
AIC_7855, /* PCI aic7855 */
AIC_7860, /* PCI aic7860 (7850 Ultra) */
+ AIC_7861, /* PCI aic7861 on 2940AU */
AIC_7870, /* PCI aic7870 on motherboard */
AIC_7871, /* PCI aic7871 on 294x */
AIC_7872, /* PCI aic7872 on 3940 */
@@ -257,6 +274,7 @@
"AIC-7850", /* AIC_7850 */
"AIC-7855", /* AIC_7855 */
"AIC-7850 Ultra", /* AIC_7860 */
+ "AHA-2940A Ultra", /* AIC_7861 */
"AIC-7870", /* AIC_7870 */
"AHA-2940", /* AIC_7871 */
"AHA-3940", /* AIC_7872 */
@@ -296,7 +314,6 @@
#define MINSLOT 1
#define MAXSLOT 15
#define SLOTBASE(x) ((x) << 12)
-#define MAXIRQ 15
/*
* Standard EISA Host ID regs (Offset from slot base)
@@ -348,6 +365,18 @@
#define STPWLEVEL 0x00000002ul
#define DIFACTNEGEN 0x00000001ul /* aic7870 only */
+
+/*
+ * Define the different types of SEEPROMs on aic7xxx adapters
+ * and make it also represent the address size used in accessing
+ * its registers. The 93C46 chips have 1024 bits organized into
+ * 64 16-bit words, while the 93C56 chips have 2048 bits organized
+ * into 128 16-bit words. The C46 chips use 6 bits to address
+ * each word, while the C56 and C66 (4096 bits) use 8 bits to
+ * address each word.
+ */
+typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
+
/*
*
* Define the format of the SEEPROM registers (16 bits).
@@ -466,18 +495,6 @@
#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
/*
- * Since the sequencer code DMAs the scatter-gather structures
- * directly from memory, we use this macro to assert that the
- * kernel structure hasn't changed.
- */
-#define SG_STRUCT_CHECK(sg) \
- ((char *) &(sg).address - (char *) &(sg) != 0 || \
- (char *) &(sg).length - (char *) &(sg) != 8 || \
- sizeof((sg).address) != 4 || \
- sizeof((sg).length) != 4 || \
- sizeof(sg) != 12)
-
-/*
* "Static" structures. Note that these are NOT initialized
* to zero inside the kernel - we have to initialize them all
* explicitly.
@@ -487,7 +504,7 @@
* use the IRQ as an index into aic7xxx_boards[] to locate the card
* information.
*/
-static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
+static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
/*
* When we detect and register the card, it is possible to
@@ -526,6 +543,21 @@
* for driver level bookkeeping.
*/
+/*
+ * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
+ * in the scatter-gather lists. We need to convert the virtual
+ * addresses to physical addresses.
+ */
+struct hw_scatterlist {
+ unsigned int address;
+ unsigned int length;
+};
+
+/*
+ * Maximum number of SG segments these cards can support.
+ */
+#define MAX_SG 256
+
struct aic7xxx_scb {
/* ------------ Begin hardware supported fields ---------------- */
/* 0*/ unsigned char control;
@@ -534,9 +566,9 @@
/* 3*/ unsigned char SG_segment_count;
/* 4*/ unsigned char SG_list_pointer[4] __attribute__ ((packed));
/* 8*/ unsigned char residual_SG_segment_count;
-/* 9*/ unsigned char residual_data_count[3];
+/* 9*/ unsigned char residual_data_count[3] __attribute__ ((packed));
/*12*/ unsigned char data_pointer[4] __attribute__ ((packed));
-/*16*/ unsigned long data_count;
+/*16*/ unsigned int data_count __attribute__ ((packed)); /* must be 32 bits */
/*20*/ unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
/*24*/ unsigned char SCSI_cmd_length;
/*25*/ u_char tag; /* Index into our kernel SCB array.
@@ -566,8 +598,7 @@
SCB_WAITINGQ | SCB_ASSIGNEDQ)
int state; /* current state of scb */
unsigned int position; /* Position in scb array */
- struct scatterlist sg;
- struct scatterlist sense_sg;
+ struct hw_scatterlist sg_list[MAX_SG]; /* SG list in adapter format */
unsigned char sense_cmd[6]; /* Allocate 6 characters for sense command */
};
@@ -592,6 +623,15 @@
static unsigned char
generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
+typedef struct {
+ scb_queue_type free_scbs; /*
+ * SCBs assigned to free slot on
+ * card (no paging required)
+ */
+ int numscbs; /* current number of scbs */
+ int activescbs; /* active scbs */
+} scb_usage_type;
+
/*
* The maximum number of SCBs we could have for ANY type
* of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
@@ -608,8 +648,6 @@
int base; /* card base address */
int maxhscbs; /* hardware SCBs */
int maxscbs; /* max SCBs (including pageable) */
- int numscbs; /* current number of scbs */
- int activescbs; /* active scbs */
#define A_SCANNED 0x0001
#define B_SCANNED 0x0002
#define EXTENDED_TRANSLATION 0x0004
@@ -638,15 +676,11 @@
unsigned char qcntmask;
struct seeprom_config seeprom;
struct Scsi_Host *next; /* allow for multiple IRQs */
- struct aic7xxx_scb scb_array[AIC7XXX_MAXSCB]; /* active commands */
+ struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; /* active commands */
struct aic7xxx_scb *pagedout_ntscbs[16]; /*
* paged-out, non-tagged scbs
* indexed by target.
*/
- scb_queue_type free_scbs; /*
- * SCBs assigned to free slot on
- * card (no paging required)
- */
scb_queue_type page_scbs; /*
* SCBs that will require paging
* before use (no assigned slot)
@@ -660,6 +694,9 @@
* have now been assigned a slot
* by aic7xxx_free_scb
*/
+ scb_usage_type scb_usage;
+ scb_usage_type *scb_link;
+
struct aic7xxx_cmd_queue {
Scsi_Cmnd *head;
Scsi_Cmnd *tail;
@@ -750,6 +787,9 @@
#ifdef CONFIG_PCI
static int number_of_3940s = 0;
static int number_of_3985s = 0;
+#ifdef AIC7XXX_SHARE_SCBS
+static scb_usage_type *shared_3985_scbs = NULL;
+#endif
#endif CONFIG_PCI
#ifdef AIC7XXX_DEBUG
@@ -802,6 +842,7 @@
case AIC_7850:
case AIC_7855:
case AIC_7860:
+ case AIC_7861:
case AIC_7870:
case AIC_7871:
case AIC_7872:
@@ -877,7 +918,10 @@
scb->SCSI_cmd_length);
printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
(scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
- scb->residual_SG_segment_count, scb->residual_data_count);
+ scb->residual_SG_segment_count,
+ ((scb->residual_data_count[2] << 16) |
+ (scb->residual_data_count[1] << 8) |
+ (scb->residual_data_count[0]));
printk("data ptr 0x%x, data count %d, next waiting %d\n",
(scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
(scb->data_pointer[1] << 8) | scb->data_pointer[0],
@@ -911,6 +955,8 @@
* 0 use edge triggered
* 1 use level triggered
*/
+static int aic7xxx_enable_ultra = 0; /* enable ultra SCSI speeds */
+
/*+F*************************************************************************
* Function:
* aic7xxx_setup
@@ -933,6 +979,7 @@
{ "extended", &aic7xxx_extended },
{ "no_reset", &aic7xxx_no_reset },
{ "irq_trigger", &aic7xxx_irq_trigger },
+ { "ultra", &aic7xxx_enable_ultra },
{ NULL, NULL }
};
@@ -1123,7 +1170,7 @@
struct scatterlist *sg;
segments = cmd->use_sg - sg_last;
- sg = (struct scatterlist *) cmd->buffer;
+ sg = (struct scatterlist *) cmd->request_buffer;
if (cmd->use_sg)
{
@@ -1155,53 +1202,60 @@
unsigned long ultra_enb_addr;
unsigned char ultra_enb, sxfrctl0;
- for (i = 0; i < num_aic7xxx_syncrates; i++)
+ /*
+ * If the offset is 0, then the device is requesting asynchronous
+ * transfers.
+ */
+ if (offset != 0)
{
- if ((aic7xxx_syncrates[i].period - period) >= 0)
+ for (i = 0; i < num_aic7xxx_syncrates; i++)
{
- /*
- * Watch out for Ultra speeds when ultra is not enabled and
- * vice-versa.
- */
- if (!(p->flags & ULTRA_ENABLED) &&
- (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+ if ((aic7xxx_syncrates[i].period - period) >= 0)
{
/*
- * This should only happen if the drive is the first to negotiate
- * and chooses a high rate. We'll just move down the table until
- * we hit a non ultra speed.
+ * Watch out for Ultra speeds when ultra is not enabled and
+ * vice-versa.
*/
- continue;
- }
- *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+ if (!(p->flags & ULTRA_ENABLED) &&
+ (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+ {
+ /*
+ * This should only happen if the drive 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);
- /*
- * Ensure Ultra mode is set properly for this target.
- */
- ultra_enb_addr = ULTRA_ENB;
- if ((channel == 'B') || (target > 7))
- {
- ultra_enb_addr++;
- }
- ultra_enb = inb(p->base + ultra_enb_addr);
- sxfrctl0 = inb(p->base + SXFRCTL0);
- if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
- {
- ultra_enb |= 0x01 << (target & 0x07);
- sxfrctl0 |= ULTRAEN;
- }
- else
- {
- ultra_enb &= ~(0x01 << (target & 0x07));
- sxfrctl0 &= ~ULTRAEN;
- }
- outb(ultra_enb, p->base + ultra_enb_addr);
- outb(sxfrctl0, p->base + SXFRCTL0);
+ /*
+ * Ensure Ultra mode is set properly for this target.
+ */
+ ultra_enb_addr = ULTRA_ENB;
+ if ((channel == 'B') || (target > 7))
+ {
+ ultra_enb_addr++;
+ }
+ ultra_enb = inb(p->base + ultra_enb_addr);
+ sxfrctl0 = inb(p->base + SXFRCTL0);
+ if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+ {
+ ultra_enb |= 0x01 << (target & 0x07);
+ sxfrctl0 |= ULTRAEN;
+ }
+ else
+ {
+ ultra_enb &= ~(0x01 << (target & 0x07));
+ sxfrctl0 &= ~ULTRAEN;
+ }
+ outb(ultra_enb, p->base + ultra_enb_addr);
+ outb(sxfrctl0, p->base + SXFRCTL0);
- printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
- "offset %d.\n", p->host_no, target, channel,
- aic7xxx_syncrates[i].english, offset);
- return;
+ printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+ "offset %d.\n", p->host_no, target, channel,
+ aic7xxx_syncrates[i].english, offset);
+ return;
+ }
}
}
@@ -1433,10 +1487,10 @@
struct aic7xxx_scb *scbp = NULL;
int maxscbs;
- scbp = p->free_scbs.head;
+ scbp = p->scb_link->free_scbs.head;
if (scbp != NULL)
{
- scbq_remove_head(&p->free_scbs);
+ scbq_remove_head(&p->scb_link->free_scbs);
}
else
{
@@ -1459,23 +1513,30 @@
maxscbs = p->maxscbs;
else
maxscbs = p->maxhscbs;
- if (p->numscbs < maxscbs)
+ if (p->scb_link->numscbs < maxscbs)
{
- scbp = &(p->scb_array[p->numscbs]);
- memset(scbp, 0, sizeof(*scbp));
- scbp->tag = p->numscbs;
- if (p->numscbs < p->maxhscbs)
- scbp->position = p->numscbs;
- else
- scbp->position = SCB_LIST_NULL;
- p->numscbs++;
+ int scb_index = p->scb_link->numscbs;
+ int scb_size = sizeof(struct aic7xxx_scb);
+
+ p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
+ scbp = (p->scb_array[scb_index]);
+ if (scbp != NULL)
+ {
+ memset(scbp, 0, sizeof(*scbp));
+ scbp->tag = scb_index;
+ if (scb_index < p->maxhscbs)
+ scbp->position = scb_index;
+ else
+ scbp->position = SCB_LIST_NULL;
+ p->scb_link->numscbs++;
+ }
}
}
}
if (scbp != NULL)
{
#ifdef AIC7XXX_DEBUG
- p->activescbs++;
+ p->scb_link->activescbs++;
#endif
}
return (scbp);
@@ -1568,10 +1629,10 @@
}
else
{
- scbq_insert_head(&p->free_scbs, scb);
+ scbq_insert_head(&p->scb_link->free_scbs, scb);
}
#ifdef AIC7XXX_DEBUG
- p->activescbs--; /* For debugging purposes. */
+ p->scb_link->activescbs--; /* For debugging purposes. */
#endif
}
}
@@ -1608,9 +1669,9 @@
struct aic7xxx_scb *scb;
int i;
- for (i = 0; i < p->numscbs; i++)
+ for (i = 0; i < p->scb_link->numscbs; i++)
{
- scb = &(p->scb_array[i]);
+ scb = (p->scb_array[i]);
if (scb->state & SCB_QUEUED_FOR_DONE)
{
#ifdef AIC7XXX_DEBUG_ABORT
@@ -1749,7 +1810,7 @@
{
saved_queue[i] = inb(QINFIFO + base);
outb(saved_queue[i], SCBPTR + base);
- scb = &(p->scb_array[inb(SCB_TAG + base)]);
+ scb = (p->scb_array[inb(SCB_TAG + base)]);
if (aic7xxx_match_scb(scb, target, channel))
{
/*
@@ -1787,7 +1848,7 @@
while (next != SCB_LIST_NULL)
{
outb(next, SCBPTR + base);
- scb = &(p->scb_array[inb(SCB_TAG + base)]);
+ scb = (p->scb_array[inb(SCB_TAG + base)]);
/*
* Select the SCB.
*/
@@ -1809,9 +1870,9 @@
* for this target that are active. These are other (most likely
* tagged) commands that were disconnected when the reset occurred.
*/
- for (i = 0; i < p->numscbs; i++)
+ for (i = 0; i < p->scb_link->numscbs; i++)
{
- scb = &(p->scb_array[i]);
+ scb = (p->scb_array[i]);
if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
{
/*
@@ -1964,9 +2025,10 @@
}
/*
- * Delay by the bus settle time.
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
*/
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
/*
* Now loop through all the SCBs that have been marked for abortion,
@@ -2028,7 +2090,7 @@
aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scb;
- u_char cur_scb;
+ u_char cur_scb, intstat;
u_long base = p->base;
long flags;
@@ -2040,6 +2102,7 @@
PAUSE_SEQUENCER(p);
cur_scb = inb(SCBPTR + base);
+ intstat = inb(INTSTAT + base);
/*
* First handle SCBs that are waiting but have been assigned a slot.
@@ -2097,7 +2160,7 @@
* Find the in-core SCB for the one we're paging out.
*/
out_scbi = inb(SCB_TAG + base);
- out_scbp = &(p->scb_array[out_scbi]);
+ out_scbp = (p->scb_array[out_scbi]);
/* Do the page out and mark the paged in SCB as active. */
aic7xxx_page_scb(p, out_scbp, scb);
@@ -2132,7 +2195,15 @@
}
/* Restore old position */
outb(cur_scb, SCBPTR + base);
- UNPAUSE_SEQUENCER(p);
+
+ /*
+ * Guard against unpausing the sequencer if there is an interrupt
+ * waiting to happen.
+ */
+ if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
+ {
+ UNPAUSE_SEQUENCER(p);
+ }
restore_flags(flags);
}
@@ -2159,7 +2230,7 @@
unsigned char max_offset, rej_byte;
unsigned short target_mask;
char channel;
- void *addr;
+ unsigned int addr; /* must be 32 bits */
Scsi_Cmnd *cmd;
p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
@@ -2278,7 +2349,7 @@
scb = p->pagedout_ntscbs[index];
}
else
- scb = &(p->scb_array[arg_1]);
+ scb = (p->scb_array[arg_1]);
if (!(scb->state & SCB_PAGED_OUT))
{
@@ -2296,10 +2367,10 @@
* assigned SCB, an SCB that just completed, or the first one
* on the disconnected SCB list.
*/
- if (p->free_scbs.head != NULL)
+ if (p->scb_link->free_scbs.head != NULL)
{
- outscb = p->free_scbs.head;
- scbq_remove_head(&p->free_scbs);
+ outscb = p->scb_link->free_scbs.head;
+ scbq_remove_head(&p->scb_link->free_scbs);
scb->position = outscb->position;
outscb->position = SCB_LIST_NULL;
scbq_insert_head(&p->page_scbs, outscb);
@@ -2329,7 +2400,7 @@
{
intstat &= ~CMDCMPLT;
}
- outscb = &(p->scb_array[scb_index]);
+ outscb = (p->scb_array[scb_index]);
if (!(outscb->state & SCB_ACTIVE))
{
printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
@@ -2370,7 +2441,7 @@
{
outb(disc_scb, SCBPTR + base);
tag = inb(SCB_TAG + base);
- outscb = &(p->scb_array[tag]);
+ outscb = (p->scb_array[tag]);
next = inb(SCB_NEXT + base);
if (next != SCB_LIST_NULL)
{
@@ -2387,7 +2458,7 @@
disc_scb = inb(QINFIFO + base);
outb(disc_scb, SCBPTR + base);
tag = inb(SCB_TAG + base);
- outscb = &p->scb_array[tag];
+ outscb = (p->scb_array[tag]);
if ((outscb->control & 0x23) != TAG_ENB)
{
/*
@@ -2418,7 +2489,7 @@
outb(saved_queue[queued], SCBPTR + base);
tag = inb(SCB_TAG + base);
- outscb = &p->scb_array[tag];
+ outscb = (p->scb_array[tag]);
}
scb->position = outscb->position;
outscb->position = SCB_LIST_NULL;
@@ -2459,7 +2530,7 @@
if ((rej_byte & 0xF0) == 0x20)
{
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
printk(KERN_WARNING "scsi%d: Tagged message received without identify."
"Disabling tagged commands for target %d channel %c.\n",
p->host_no, scsi_id, channel);
@@ -2511,13 +2582,39 @@
outb(scratch, TARG_SCRATCH + base + scratch_offset);
outb(scratch, SCSIRATE + base);
if ((scratch & 0x0F) == 0)
- { /*
- * The requested rate was so low that asynchronous transfers
- * are faster (not to mention the controller won't support
- * them), so we issue a reject to ensure we go to asynchronous
- * transfers.
- */
- outb(SEND_REJ, RETURN_1 + base);
+ {
+ /*
+ * One of two things happened. Either the device requested
+ * asynchronous data transfers, or it requested a synchronous
+ * data transfer rate that was so low that asynchronous
+ * transfers are faster (not to mention the controller won't
+ * support them). In both cases the synchronous data transfer
+ * rate and the offset are set to 0 indicating asynchronous
+ * transfers.
+ *
+ * If the device requested an asynchronous transfer, then
+ * accept the request. If the device is being forced to
+ * asynchronous data transfers and this is the first time
+ * we've seen the request, accept the request. If we've
+ * already seen the request, then attempt to force
+ * asynchronous data transfers by rejecting the message.
+ */
+ if ((offset == 0) || (p->sdtr_pending & target_mask))
+ {
+ /*
+ * Device requested asynchronous transfers or we're
+ * forcing asynchronous transfers for the first time.
+ */
+ outb(0, RETURN_1 + base);
+ }
+ else
+ {
+ /*
+ * The first time in forcing asynchronous transfers
+ * failed, so we try sending a reject message.
+ */
+ outb(SEND_REJ, RETURN_1 + base);
+ }
}
else
{
@@ -2667,13 +2764,13 @@
*/
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
outb(0, RETURN_1 + base); /* CHECK_CONDITION may change this */
if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned int) scb->cmd);
+ "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
+ intstat, scb_index, scb->state, (unsigned long) scb->cmd);
}
else
{
@@ -2693,7 +2790,7 @@
if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
{
unsigned char tcl;
- void *req_buf;
+ unsigned int req_buf; /* must be 32 bits */
tcl = scb->target_channel_lun;
@@ -2707,22 +2804,23 @@
scb->sense_cmd[1] = (cmd->lun << 5);
scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
- scb->sense_sg.address = (char *) &cmd->sense_buffer;
- scb->sense_sg.length = sizeof(cmd->sense_buffer);
- req_buf = &scb->sense_sg;
+ scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
+ scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+ req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
scb->control = scb->control & DISCENB;
scb->target_channel_lun = tcl;
- addr = scb->sense_cmd;
+ addr = VIRT_TO_BUS(scb->sense_cmd);
scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
memcpy(scb->SCSI_cmd_pointer, &addr,
sizeof(scb->SCSI_cmd_pointer));
scb->SG_segment_count = 1;
memcpy(scb->SG_list_pointer, &req_buf,
- sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sense_sg.length;
- memcpy(scb->data_pointer, &(scb->sense_sg.address), 4);
+ sizeof(scb->SG_list_pointer));
+ scb->data_count = scb->sg_list[0].length;
+ memcpy(scb->data_pointer, &(scb->sg_list[0].address),
+ sizeof(scb->data_pointer));
aic7xxx_putscb(p, scb);
/*
@@ -2749,7 +2847,17 @@
p->host_no, scb->target_channel_lun);
if (!aic7xxx_error(cmd))
{
- aic7xxx_error(cmd) = DID_BUS_BUSY;
+ /* The error code here used to be DID_BUS_BUSY,
+ * but after extensive testing, it has been determined
+ * that a DID_BUS_BUSY return is a waste of time. If
+ * the problem is something that will go away, then it
+ * will, if it isn't, then you don't want the endless
+ * looping that you get with a DID_BUS_BUSY. Better
+ * to be on the safe side and specify an error condition
+ * that will eventually lead to a reset or abort of some
+ * sort instead of an endless loop.
+ */
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
}
break;
@@ -2773,12 +2881,12 @@
case RESIDUAL:
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned int) scb->cmd);
+ "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
+ intstat, scb_index, scb->state, (unsigned long) scb->cmd);
}
else
{
@@ -2816,12 +2924,12 @@
case ABORT_TAG:
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned int) scb->cmd);
+ "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
+ intstat, scb_index, scb->state, (unsigned long) scb->cmd);
}
else
{
@@ -2841,12 +2949,12 @@
case AWAITING_MSG:
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned int) scb->cmd);
+ "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
+ intstat, scb_index, scb->state, (unsigned long) scb->cmd);
}
else
{
@@ -2874,7 +2982,7 @@
case IMMEDDONE:
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
#ifdef AIC7XXX_DEBUG_ABORT
printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
scsi_id, scb_index, scb->state);
@@ -2911,7 +3019,7 @@
{
unsigned int overrun;
- scb = &p->scb_array[inb(base + SCB_TAG)];
+ scb = (p->scb_array[inb(base + SCB_TAG)]);
overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
(inb(base + STCNT2) << 16);
overrun =0x00FFFFFF - overrun;
@@ -2953,7 +3061,7 @@
}
scb_index = inb(SCB_TAG + base);
- scb = &(p->scb_array[scb_index]);
+ scb = (p->scb_array[scb_index]);
if (status & SCSIRSTI)
{
PAUSE_SEQUENCER(p);
@@ -3103,13 +3211,13 @@
do {
complete = inb(QOUTFIFO + base);
- scb = &(p->scb_array[complete]);
+ scb = (p->scb_array[complete]);
if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
- " QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%x, "
+ " QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
"pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
- inb(QINCNT + base), scb->state, (unsigned int) scb->cmd,
+ inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
scb->position);
outb(CLRCMDINT, CLRINT + base);
continue;
@@ -3201,13 +3309,12 @@
{
Scsi_Device *device = scsi_devs;
int tq_depth = 2;
+ struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
#ifdef AIC7XXX_CMDS_PER_LUN
tq_depth = AIC7XXX_CMDS_PER_LUN;
#else
{
- struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
-
if (p->maxhscbs <= 4)
{
tq_depth = 4; /* Not many SCBs to work with. */
@@ -3227,14 +3334,26 @@
#ifdef AIC7XXX_TAGGED_QUEUEING
if (device->tagged_supported)
{
- device->queue_depth = tq_depth;
- if (device->tagged_queue == 0)
+ unsigned short target_mask = (1 << device->id) | device->channel;
+
+ if (!(p->discenable & target_mask))
+ {
+ printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
+ "tagged queueing for target %d, channel %d, LUN %d.\n",
+ host->host_no, device->id, device->channel, device->lun);
+ }
+ else
{
- printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
- "channel %d, LUN %d, queue depth %d.\n", host->host_no,
- device->id, device->channel, device->lun, device->queue_depth);
- device->tagged_queue = 1;
- device->current_tag = SCB_LIST_NULL;
+ device->queue_depth = tq_depth;
+ if (device->tagged_queue == 0)
+ {
+ printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
+ "channel %d, LUN %d, queue depth %d.\n", host->host_no,
+ device->id, device->channel, device->lun,
+ device->queue_depth);
+ device->tagged_queue = 1;
+ device->current_tag = SCB_LIST_NULL;
+ }
}
}
#endif
@@ -3473,7 +3592,7 @@
* Reads the serial EEPROM and returns 1 if successful and 0 if
* not successful.
*
- * The instruction set of the 93C46 chip is as follows:
+ * The instruction set of the 93C46/56/66 chips is as follows:
*
* Start OP
* Function Bit Code Address Data Description
@@ -3489,6 +3608,8 @@
* EWDS 1 00 00XXXX Disables all programming
* instructions
* *Note: A value of X for address is a don't care condition.
+ * *Note: The 93C56 and 93C66 have 8 address bits.
+ *
*
* The 93C46 has a four wire interface: clock, chip select, data in, and
* data out. In order to perform one of the above functions, you need
@@ -3515,7 +3636,8 @@
*
*-F*************************************************************************/
static int
-read_seeprom(int base, int offset, struct seeprom_config *sc)
+read_seeprom(int base, int offset, struct seeprom_config *sc,
+ seeprom_chip_type chip)
{
int i = 0, k;
unsigned long timeout;
@@ -3583,7 +3705,7 @@
/*
* Send the 6 bit address (MSB first, LSB last).
*/
- for (i = 5; i >= 0; i--)
+ for (i = ((int) chip - 1); i >= 0; i--)
{
temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
@@ -3925,6 +4047,7 @@
break;
case AIC_7860:
+ case AIC_7861:
case AIC_7880:
case AIC_7881:
case AIC_7882:
@@ -3934,7 +4057,7 @@
* Remember if Ultra was enabled in case there is no SEEPROM.
* Fall through to the rest of the AIC_78xx code.
*/
- if (inb(SXFRCTL0 + base) & ULTRAEN)
+ if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
config->flags |= ULTRA_ENABLED;
case AIC_7850:
@@ -3957,7 +4080,16 @@
config->parity = AIC_ENABLED;
printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2), &sc);
+ if ((config->type == AIC_7873) || (config->type == AIC_7883))
+ {
+ have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
+ &sc, c56_66);
+ }
+ else
+ {
+ have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
+ &sc, c46);
+ }
if (!have_seeprom)
{
for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
@@ -4142,25 +4274,6 @@
debug_config(config);
/*
- * Before registry, make sure that the offsets of the
- * struct scatterlist are what the sequencer will expect,
- * otherwise disable scatter-gather altogether until someone
- * can fix it. This is important since the sequencer will
- * DMA elements of the SG array in while executing commands.
- */
- if (template->sg_tablesize != SG_NONE)
- {
- struct scatterlist sg;
-
- if (SG_STRUCT_CHECK(sg))
- {
- printk(KERN_WARNING "aic7xxx: Warning - Kernel scatter-gather structures "
- "changed, disabling it.\n");
- template->sg_tablesize = SG_NONE;
- }
- }
-
- /*
* Register each "host" and fill in the returned Scsi_Host
* structure as best we can. Some of the parameters aren't
* really relevant for bus types beyond ISA, and none of the
@@ -4175,7 +4288,7 @@
host->this_id = config->scsi_id;
host->io_port = config->base;
host->n_io_port = 0xFF;
- host->base = (char *)config->mbase;
+ host->base = (unsigned char *)config->mbase;
host->irq = config->irq;
if (config->bus_type == AIC_WIDE)
{
@@ -4195,18 +4308,26 @@
p->maxscbs = config->maxscbs;
p->maxhscbs = config->maxhscbs;
p->qcntmask = config->qcntmask;
- p->numscbs = 0;
p->mbase = (char *)config->mbase;
p->type = config->type;
p->chip_type = config->chip_type;
p->flags = config->flags;
p->chan_num = config->chan_num;
+ p->scb_link = &(p->scb_usage);
+#ifdef AIC7XXX_SHARE_SCBS
+ if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
+ {
+ shared_3985_scbs = &(p->scb_usage);
+ p->scb_link = &(p->scb_usage);
+ }
+#endif
+ p->scb_link->numscbs = 0;
p->bus_type = config->bus_type;
p->seeprom = sc;
p->next = NULL;
p->completeq.head = NULL;
p->completeq.tail = NULL;
- scbq_init(&p->free_scbs);
+ scbq_init(&p->scb_link->free_scbs);
scbq_init(&p->page_scbs);
scbq_init(&p->waiting_scbs);
scbq_init(&p->assigned_scbs);
@@ -4567,7 +4688,7 @@
* a NULL entry to indicate that no prior hosts have
* been found/registered for that IRQ.
*/
- for (i = 0; i <= MAXIRQ; i++)
+ for (i = 0; i <= NUMBER(aic7xxx_boards); i++)
{
aic7xxx_boards[i] = NULL;
}
@@ -4643,6 +4764,7 @@
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_785x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
@@ -4690,6 +4812,7 @@
case AIC_7850:
case AIC_7855:
case AIC_7860:
+ case AIC_7861:
config.bios = AIC_DISABLED;
config.flags |= USE_DEFAULTS;
config.bus_speed = DFTHRSH_100;
@@ -4703,7 +4826,7 @@
case AIC_7873: /* 3985 */
case AIC_7883: /* 3985-Ultra */
- config.chan_num = number_of_3985s & 0x3; /* Has 3 controllers */
+ config.chan_num = number_of_3985s; /* Has 3 controllers */
number_of_3985s++;
if (number_of_3985s == 3)
{
@@ -4773,7 +4896,12 @@
config.high_term = AIC_UNKNOWN;
if (aic7xxx_extended)
config.flags |= EXTENDED_TRANSLATION;
+#ifdef AIC7XXX_SHARE_SCBs
if (devconfig & RAMPSM)
+#else
+ if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
+ (config.type != AIC_7883))
+#endif
{
/*
* External SRAM present. The probe will walk the SCBs to see
@@ -4827,9 +4955,8 @@
aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
struct aic7xxx_scb *scb)
{
- void *addr;
+ unsigned int addr; /* must be 32 bits */
unsigned short mask;
- struct scatterlist *sg;
mask = (0x01 << TARGET_INDEX(cmd));
/*
@@ -4900,27 +5027,43 @@
* XXX - this relies on the host data being stored in a
* little-endian format.
*/
- addr = cmd->cmnd;
+ addr = VIRT_TO_BUS(cmd->cmnd);
scb->SCSI_cmd_length = cmd->cmd_len;
memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
if (cmd->use_sg)
{
+ struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */
+
+ /*
+ * We must build an SG list in adapter format, as the kernel's SG list
+ * cannot be used directly because of data field size (__alpha__)
+ * differences and the kernel SG list uses virtual addresses where
+ * we need physical addresses.
+ */
+ int i;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ for (i = 0; i < cmd->use_sg; i++)
+ {
+ scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
+ scb->sg_list[i].length = (unsigned int) sg[i].length;
+ }
scb->SG_segment_count = cmd->use_sg;
- memcpy(scb->SG_list_pointer, &cmd->request_buffer,
- sizeof(scb->SG_list_pointer));
- memcpy(&sg, &cmd->request_buffer, sizeof(sg));
- memcpy(scb->data_pointer, &(sg[0].address), sizeof(scb->data_pointer));
- scb->data_count = sg[0].length;
+ addr = VIRT_TO_BUS(scb->sg_list);
+ memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
+ memcpy(scb->data_pointer, &(scb->sg_list[0].address),
+ sizeof(scb->data_pointer));
+ scb->data_count = scb->sg_list[0].length;
#if 0
- debug("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
+ printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
#endif
}
else
{
#if 0
- debug("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
+ printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
(unsigned long) cmd->request_buffer, cmd->request_bufflen);
#endif
if (cmd->request_bufflen == 0)
@@ -4938,12 +5081,13 @@
else
{
scb->SG_segment_count = 1;
- scb->sg.address = (char *) cmd->request_buffer;
- scb->sg.length = cmd->request_bufflen;
- addr = &scb->sg;
+ scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+ scb->sg_list[0].length = cmd->request_bufflen;
+ addr = VIRT_TO_BUS(&scb->sg_list[0]);
memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg.length;
- memcpy(scb->data_pointer, &cmd->request_buffer, sizeof(scb->data_pointer));
+ scb->data_count = scb->sg_list[0].length;
+ addr = VIRT_TO_BUS(cmd->request_buffer);
+ memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
}
}
}
@@ -4958,12 +5102,17 @@
int
aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
{
- long flags;
+ long processor_flags;
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
- u_char curscb;
+ u_char curscb, intstat;
p = (struct aic7xxx_host *) cmd->host->hostdata;
+ if (p->host != cmd->host)
+ {
+ printk(KERN_INFO "scsi%d: Internal host structure != scsi.c host "
+ "structure.\n", p->host_no);
+ }
/*
* Check to see if channel was scanned.
@@ -4983,19 +5132,28 @@
}
#if 0
- debug("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
+ printk("aic7xxx: (queue) cmd(0x%x) size(%u), target %d, channel %d, lun %d.\n",
cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
cmd->lun & 0x07);
#endif
/*
- * This is a critical section, since we don't want the
- * interrupt routine mucking with the host data or the
- * card. Since the kernel documentation is vague on
- * whether or not we are in a cli/sti pair already, save
- * the flags to be on the safe side.
+ * This is a critical section, since we don't want the interrupt
+ * routine mucking with the host data or the card. For this reason
+ * it is nice to know that this function can only be called in one
+ * of two ways from scsi.c First, as part of a routine queue command,
+ * in which case, the irq for our card is disabled before this
+ * function is called. This doesn't help us if there is more than
+ * one card using more than one IRQ in our system, therefore, we
+ * should disable all interrupts on these grounds alone. Second,
+ * this can be called as part of the scsi_done routine, in which case
+ * we are in the aic7xxx_isr routine already and interrupts are
+ * disabled, therefore we should saveflags first, then disable the
+ * interrupts, do our work, then restore the CPU flags. If it weren't
+ * for the possibility of more than one card using more than one IRQ
+ * in our system, we wouldn't have to touch the interrupt flags at all.
*/
- save_flags(flags);
+ save_flags(processor_flags);
cli();
scb = aic7xxx_allocate_scb(p);
@@ -5018,7 +5176,7 @@
aic7xxx_buildscb(p, cmd, scb);
#if 0
- if (scb != &p->scb_array[scb->position])
+ if (scb != (p->scb_array[scb->position]))
{
printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
"address.\n");
@@ -5057,6 +5215,7 @@
* XXX - should the interrupts be left on while doing this?
*/
PAUSE_SEQUENCER(p);
+ intstat = inb(INTSTAT + p->base);
/*
* Save the SCB pointer and put our own pointer in - this
@@ -5071,7 +5230,14 @@
outb(scb->position, QINFIFO + p->base);
scb->state |= SCB_ACTIVE;
- UNPAUSE_SEQUENCER(p);
+ /*
+ * Guard against unpausing the sequencer if there is an interrupt
+ * waiting to happen.
+ */
+ if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
+ {
+ UNPAUSE_SEQUENCER(p);
+ }
}
}
else
@@ -5088,7 +5254,7 @@
printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
(long) cmd, (long) scb->cmd, scb->position);
#endif;
- restore_flags(flags);
+ restore_flags(processor_flags);
}
return (0);
}
@@ -5108,21 +5274,17 @@
aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
struct aic7xxx_scb *scb;
- long flags;
unsigned char bus_state;
int base, result = -1;
char channel;
- scb = &(p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
{
- save_flags(flags);
- cli();
-
if (scb->state & SCB_IN_PROGRESS)
{
/*
@@ -5203,7 +5365,7 @@
* too much time, so we try the bus device reset there first.
*/
active_scb = inb(SCBPTR + base);
- active_scbp = &(p->scb_array[inb(SCB_TAG + base)]);
+ active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
control = inb(SCB_CONTROL + base);
/*
@@ -5303,7 +5465,11 @@
}
}
}
- restore_flags(flags);
+ }
+ /* Make sure the sequencer is unpaused upon return. */
+ if (result == -1)
+ {
+ UNPAUSE_SEQUENCER(p);
}
return (result);
}
@@ -5324,7 +5490,7 @@
int base, result;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = &(p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_array[aic7xxx_position(cmd)]);
base = p->base;
#ifdef AIC7XXX_DEBUG_ABORT
@@ -5369,9 +5535,10 @@
struct aic7xxx_host *p;
int base, found, tindex, min_target, max_target, result = -1;
char channel = 'A';
+ unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = &(p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = cmd->channel ? 'B': 'A';
tindex = (cmd->channel << 4) | cmd->target;
@@ -5380,10 +5547,20 @@
printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
#endif
+ /*
+ * This routine is called by scsi.c, in which case the interrupts
+ * very well may be on when we are called. As such, we need to save
+ * the flags to be sure, then turn interrupts off, and then call our
+ * various method funtions which all assume interrupts are off.
+ */
+ save_flags(processor_flags);
+ cli();
+
if (scb->cmd != cmd)
scb = NULL;
- if (!(flags & SCSI_RESET_SUGGEST_HOST_RESET) && (scb != NULL))
+ if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
+ && (scb != NULL))
{
/*
* Attempt a bus device reset if commands have completed successfully
@@ -5439,7 +5616,8 @@
/*
* The bus device reset failed; try resetting the channel.
*/
- if (flags & SCSI_RESET_ASYNCHRONOUS)
+ if (!(flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
+ && (flags & SCSI_RESET_ASYNCHRONOUS))
{
if (scb == NULL)
{
@@ -5458,6 +5636,10 @@
if (result == -1)
{
+ /*
+ * The reset channel function assumes that the sequencer is paused.
+ */
+ PAUSE_SEQUENCER(p);
found = aic7xxx_reset_channel(p, channel, TRUE);
/*
@@ -5506,6 +5688,7 @@
result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
}
}
+ restore_flags(processor_flags);
return (result);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov