patch-2.2.19 linux/drivers/scsi/aic7xxx.c
Next file: linux/drivers/scsi/aic7xxx.h
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx_seq.c
Back to the patch index
Back to the overall index
- Lines: 2899
- Date:
Sun Mar 25 11:37:35 2001
- Orig file:
v2.2.18/drivers/scsi/aic7xxx.c
- Orig date:
Sun Mar 25 11:13:00 2001
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -246,11 +246,11 @@
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
-#include "aic7xxx.h"
+#include "aic7xxx/aic7xxx.h"
#include "aic7xxx/sequencer.h"
#include "aic7xxx/scsi_message.h"
-#include "aic7xxx_reg.h"
+#include "aic7xxx/aic7xxx_reg.h"
#include <scsi/scsicam.h>
#include <linux/stat.h>
@@ -270,7 +270,7 @@
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.1.31"
+#define AIC7XXX_C_VERSION "5.1.33"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -790,6 +790,7 @@
typedef enum {
SCB_FREE = 0x0000,
+ SCB_DTR_SCB = 0x0001,
SCB_WAITINGQ = 0x0002,
SCB_ACTIVE = 0x0004,
SCB_SENSE = 0x0008,
@@ -896,6 +897,17 @@
AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3,
} ahc_feature;
+typedef enum {
+ AHC_BUG_NONE = 0x0000,
+ AHC_BUG_TMODE_WIDEODD = 0x0001,
+ AHC_BUG_AUTOFLUSH = 0x0002,
+ AHC_BUG_CACHETHEN = 0x0004,
+ AHC_BUG_CACHETHEN_DIS = 0x0008,
+ AHC_BUG_PCI_2_1_RETRY = 0x0010,
+ AHC_BUG_PCI_MWI = 0x0020,
+ AHC_BUG_SCBCHAN_UPLOAD = 0x0040,
+} ahc_bugs;
+
struct aic7xxx_scb {
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
@@ -1004,7 +1016,6 @@
unsigned long isr_count; /* Interrupt count */
unsigned long spurious_int;
scb_data_type *scb_data;
- volatile unsigned short needdv;
volatile unsigned short needppr;
volatile unsigned short needsdtr;
volatile unsigned short needwdtr;
@@ -1032,10 +1043,9 @@
#define BUS_DEVICE_RESET_PENDING 0x02
#define DEVICE_RESET_DELAY 0x04
#define DEVICE_PRINT_DTR 0x08
-#define DEVICE_PARITY_ERROR 0x10
-#define DEVICE_WAS_BUSY 0x20
-#define DEVICE_SCSI_3 0x40
-#define DEVICE_SCANNED 0x80
+#define DEVICE_WAS_BUSY 0x10
+#define DEVICE_SCSI_3 0x20
+#define DEVICE_DTR_SCANNED 0x40
volatile unsigned char dev_flags[MAX_TARGETS];
volatile unsigned char dev_active_cmds[MAX_TARGETS];
volatile unsigned char dev_temp_queue_depth[MAX_TARGETS];
@@ -1051,10 +1061,6 @@
#endif
- Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS];
-
- unsigned int dev_checksum[MAX_TARGETS];
-
unsigned char dev_last_queue_full[MAX_TARGETS];
unsigned char dev_last_queue_full_count[MAX_TARGETS];
unsigned char dev_max_queue_depth[MAX_TARGETS];
@@ -1111,6 +1117,7 @@
int host_no; /* SCSI host number */
unsigned long mbase; /* I/O memory address */
ahc_chip chip; /* chip type */
+ ahc_bugs bugs; /* hardware bugs this chip has */
/*
* Statistics Kept:
@@ -1712,7 +1719,7 @@
* prototype, our code has to be ordered that way, it's a left-over from
* the original driver days.....I should fix it some time DL).
*/
-#include "aic7xxx_seq.c"
+#include "aic7xxx/aic7xxx_seq.c"
/*+F*************************************************************************
* Function:
@@ -2876,138 +2883,98 @@
{
p->flags &= ~AHC_ABORT_PENDING;
}
- if (scb->flags & SCB_RESET)
+ if (scb->flags & (SCB_RESET|SCB_ABORT))
{
- cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+ cmd->result |= (DID_RESET << 16);
}
- else if (scb->flags & SCB_ABORT)
- {
- cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
- }
- else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+
+ if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
{
if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
{
- char *buffer;
-
+
p->dev_flags[tindex] |= DEVICE_PRESENT;
- if(cmd->use_sg)
- {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *)cmd->request_buffer;
- buffer = (char *)sg[0].address;
- }
- else
- {
- buffer = (char *)cmd->request_buffer;
- }
#define WIDE_INQUIRY_BITS 0x60
#define SYNC_INQUIRY_BITS 0x10
#define SCSI_VERSION_BITS 0x07
#define SCSI_DT_BIT 0x04
- if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
- (p->features & AHC_WIDE) )
- {
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
- }
- else
- {
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- pause_sequencer(p);
- aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
- MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
- AHC_TRANS_GOAL |
- AHC_TRANS_CUR) );
- unpause_sequencer(p, FALSE);
- }
- if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
- p->transinfo[tindex].user_offset )
- {
- p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
- if (p->features & AHC_ULTRA2)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
+ char *buffer;
+
+ if(cmd->use_sg)
+ {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *)cmd->request_buffer;
+ buffer = (char *)sg[0].address;
+ }
+ else
+ {
+ buffer = (char *)cmd->request_buffer;
+ }
+
+
+ if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+ (p->features & AHC_WIDE) )
+ {
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
+ p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+ }
else
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
- if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
- (buffer[56] & SCSI_DT_BIT) ||
- (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
- (p->transinfo[tindex].user_period <= 9) &&
- (p->transinfo[tindex].user_options) )
{
- p->needppr |= (1<<tindex);
- p->needppr_copy |= (1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
p->needwdtr &= ~(1<<tindex);
p->needwdtr_copy &= ~(1<<tindex);
- p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ pause_sequencer(p);
+ aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+ MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+ AHC_TRANS_GOAL |
+ AHC_TRANS_CUR) );
+ unpause_sequencer(p, FALSE);
}
- else
+ if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+ p->transinfo[tindex].user_offset )
{
- p->needsdtr |= (1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- p->transinfo[tindex].goal_period =
- MAX(10, p->transinfo[tindex].goal_period);
- p->transinfo[tindex].goal_options = 0;
+ p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+ if (p->features & AHC_ULTRA2)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ else
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
+ (buffer[56] & SCSI_DT_BIT) ||
+ (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+ (p->transinfo[tindex].user_period <= 9) &&
+ (p->transinfo[tindex].user_options) )
+ {
+ p->needppr |= (1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ }
+ else
+ {
+ p->needsdtr |= (1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ p->transinfo[tindex].goal_period =
+ MAX(10, p->transinfo[tindex].goal_period);
+ p->transinfo[tindex].goal_options = 0;
+ }
}
- }
- else
- {
- p->needsdtr &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_period = 255;
- p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_options = 0;
- }
- /*
- * This is needed to work around a sequencer bug for now. Regardless
- * of the controller in use, if we have a Quantum drive, we need to
- * limit the speed to 80MByte/sec. As soon as I get a fixed version
- * of the sequencer, this code will get yanked.
- */
- if(!strncmp(buffer + 8, "QUANTUM", 7) &&
- p->transinfo[tindex].goal_options )
- {
- p->transinfo[tindex].goal_period =
- MAX(p->transinfo[tindex].goal_period, 10);
- p->transinfo[tindex].goal_options = 0;
- p->needppr &= ~(1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- }
- /*
- * Get the INQUIRY checksum. We use this on Ultra 160/m
- * and older devices both. It allows us to drop speed on any bus type
- * while at the same time giving us the needed domain validation for
- * Ultra 160/m
- *
- * Note: We only get the checksum and set the SCANNED bit if this is
- * one of our dtr commands. If we don't do this, then we end up
- * getting bad checksum results on the mid-level SCSI code's INQUIRY
- * commands.
- */
- if(p->dev_dtr_cmnd[tindex] == cmd) {
- unsigned int checksum = 0;
- int *ibuffer;
- int i=0;
-
- ibuffer = (int *)buffer;
- for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+ else
{
- checksum += ibuffer[i];
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_options = 0;
}
- p->dev_checksum[tindex] = checksum;
- p->dev_flags[tindex] |= DEVICE_SCANNED;
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
}
#undef WIDE_INQUIRY_BITS
@@ -3016,7 +2983,8 @@
#undef SCSI_DT_BIT
}
}
- else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+
+ if ((scb->flags & SCB_MSGOUT_BITS) != 0)
{
unsigned short mask;
int message_error = FALSE;
@@ -3036,7 +3004,6 @@
if (scb->flags & SCB_MSGOUT_WDTR)
{
- p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3055,7 +3022,6 @@
}
if (scb->flags & SCB_MSGOUT_SDTR)
{
- p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3075,7 +3041,6 @@
}
if (scb->flags & SCB_MSGOUT_PPR)
{
- p->dtr_pending &= ~mask;
if(message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3100,6 +3065,7 @@
}
}
}
+
queue_depth = p->dev_temp_queue_depth[tindex];
if (queue_depth >= p->dev_active_cmds[tindex])
{
@@ -3133,9 +3099,18 @@
}
}
}
- if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
+ if (!(scb->tag_action))
+ {
+ aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
+ /* unbusy */ TRUE);
+ if (p->tagenable & (1<<tindex))
+ {
+ p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+ }
+ }
+ if(scb->flags & SCB_DTR_SCB)
{
- p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+ p->dtr_pending &= ~(1 << tindex);
}
p->dev_active_cmds[tindex]--;
p->activescbs--;
@@ -3244,6 +3219,14 @@
printk(INFO_LEAD "Aborting scb %d\n",
p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
found++;
+ /*
+ * Clear any residual information since the normal aic7xxx_done() path
+ * doesn't touch the residuals.
+ */
+ scb->hscb->residual_SG_segment_count = 0;
+ scb->hscb->residual_data_count[0] = 0;
+ scb->hscb->residual_data_count[1] = 0;
+ scb->hscb->residual_data_count[2] = 0;
aic7xxx_done(p, scb);
}
}
@@ -3456,8 +3439,22 @@
active_scb = aic_inb(p, SCBPTR);
if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+ {
printk(INFO_LEAD "Reset device, active_scb %d\n",
p->host_no, channel, target, lun, active_scb);
+ printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
+ "0x%x\n",
+ p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, LASTPHASE));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+ p->host_no, channel, target, lun,
+ (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+ aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
+ printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+ p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
+ aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+ }
/*
* Deal with the busy target and linked next issues.
*/
@@ -3501,11 +3498,11 @@
if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
printk(INFO_LEAD "Cleaning up status information "
"and delayed_scbs.\n", p->host_no, channel, i, lun);
- p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
+ p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
if ( tag == SCB_LIST_NULL )
{
p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
- p->dev_expires[i] = jiffies + (4 * HZ);
+ p->dev_expires[i] = jiffies + (1 * HZ);
p->dev_timer_active |= (0x01 << i);
p->dev_last_queue_full_count[i] = 0;
p->dev_last_queue_full[i] = 0;
@@ -3550,7 +3547,7 @@
prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
}
}
- if ( j > (p->scb_data->maxscbs + 1) )
+ if ( j > (p->scb_data->numscbs + 1) )
{
if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -3611,7 +3608,7 @@
prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
}
}
- if ( j > (p->scb_data->maxscbs + 1) )
+ if ( j > (p->scb_data->numscbs + 1) )
{
if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -4375,11 +4372,25 @@
if (actual < cmd->underflow)
{
if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ {
printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
"count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
(cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
hscb->residual_SG_segment_count);
+ printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
+ hscb->target_status);
+ }
+ /*
+ * In 2.4, only send back the residual information, don't flag this
+ * as an error. Before 2.4 we had to flag this as an error because
+ * the mid layer didn't check residual data counts to see if the
+ * command needs retried.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ cmd->resid = scb->sg_length - actual;
+#else
aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+#endif
aic7xxx_status(cmd) = hscb->target_status;
}
}
@@ -4698,7 +4709,6 @@
*/
p->needwdtr &= ~target_mask;
p->needwdtr_copy &= ~target_mask;
- p->dtr_pending &= ~target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
(AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
@@ -4718,8 +4728,7 @@
*/
p->needsdtr &= ~target_mask;
p->needsdtr_copy &= ~target_mask;
- p->dtr_pending &= ~target_mask;
- scb->flags &= ~SCB_MSGOUT_SDTR;
+ scb->flags &= ~SCB_MSGOUT_BITS;
aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
(AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -4852,6 +4861,8 @@
aic7xxx_error(cmd) = DID_OK;
break;
} /* first time sense, no errors */
+ printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
+ "an error.\n", p->host_no, CTL_OF_SCB(scb));
aic7xxx_error(cmd) = DID_ERROR;
scb->flags &= ~SCB_SENSE;
break;
@@ -5214,12 +5225,21 @@
printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n",
(aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
scb->sg_length, scb->sg_count);
- for (i = 0; i < scb->sg_count; i++)
+ printk(KERN_WARNING " Raw SCSI Command: 0x");
+ for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
+ {
+ printk("%02x ", scb->cmd->cmnd[i]);
+ }
+ printk("\n");
+ if(aic7xxx_verbose > 0xffff)
{
- printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n",
+ for (i = 0; i < scb->sg_count; i++)
+ {
+ printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n",
i,
le32_to_cpu(scb->sg_list[i].address),
le32_to_cpu(scb->sg_list[i].length) );
+ }
}
aic7xxx_error(scb->cmd) = DID_ERROR;
}
@@ -5234,7 +5254,7 @@
unsigned char resid_sgcnt, index;
unsigned char scb_index = aic_inb(p, SCB_TAG);
unsigned int cur_addr, resid_dcnt;
- unsigned int native_addr, native_length;
+ unsigned int native_addr, native_length, sg_addr;
int i;
if(scb_index > p->scb_data->numscbs)
@@ -5254,6 +5274,9 @@
scb->flags, (unsigned int)scb->cmd);
break;
}
+ if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
+ "pointer.\n", p->host_no, CTL_OF_SCB(scb));
/*
* We have a valid scb to use on this WIDE_RESIDUE message, so
@@ -5266,132 +5289,87 @@
*/
cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
(aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+ sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
+ (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24);
resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
(aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
(aic_inb(p, SCB_RESID_DCNT + 2) << 16);
- index = scb->sg_count - (resid_sgcnt + 1);
+ index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
native_addr = le32_to_cpu(scb->sg_list[index].address);
native_length = le32_to_cpu(scb->sg_list[index].length);
/*
- * Make sure this is a valid sg_seg for the given pointer
+ * If resid_dcnt == native_length, then we just loaded this SG
+ * segment and we need to back it up one...
*/
- if(cur_addr < native_addr ||
- cur_addr > (native_addr + native_length + 1))
- {
- printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
- p->host_no, CTL_OF_SCB(scb), cur_addr);
- if(index > 0)
- printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n",
- p->host_no, CTL_OF_SCB(scb),
- le32_to_cpu(scb->sg_list[index - 1].address),
- le32_to_cpu(scb->sg_list[index - 1].length));
- printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n",
- p->host_no, CTL_OF_SCB(scb),
- native_addr, native_length);
- if(resid_sgcnt > 1)
- printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n",
- p->host_no, CTL_OF_SCB(scb),
- le32_to_cpu(scb->sg_list[index + 1].address),
- le32_to_cpu(scb->sg_list[index + 1].length));
- printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n",
- p->host_no, CTL_OF_SCB(scb),
- cur_addr, resid_dcnt);
- break;
- }
-
- if( (resid_sgcnt == 0) &&
- ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
+ if(resid_dcnt == native_length)
{
- /*
- * We are at the end of the transfer and this is about a byte
- * we ignored already (because the sequencer knew this was
- * the last segment and set the adapter to ignore any wide
- * residue bytes that might come through, which is only done
- * on the last scatter gather segment of transfers).
- */
- break;
- }
- else if(cur_addr == native_addr)
- {
- /*
- * If our current address matches the sg_seg->address then we
- * have to back up the sg array to the previous segment and set
- * it up to have only one byte of transfer left to go.
- */
if(index == 0)
{
- printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
- "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+ /*
+ * Oops, this isn't right, we can't back up to before the
+ * beginning. This must be a bogus message, ignore it.
+ */
break;
}
- resid_sgcnt++;
- index--;
- cur_addr = le32_to_cpu(scb->sg_list[index].address) +
- le32_to_cpu(scb->sg_list[index].length) - 1;
- native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
- | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
- native_addr -= SG_SIZEOF;
- aic_outb(p, resid_sgcnt, SG_COUNT);
- aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
- aic_outb(p, native_addr & 0xff, SG_NEXT);
- aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
- aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
- aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
- aic_outb(p, 1, SCB_RESID_DCNT);
- aic_outb(p, 0, SCB_RESID_DCNT + 1);
- aic_outb(p, 0, SCB_RESID_DCNT + 2);
- aic_outb(p, 1, HCNT);
- aic_outb(p, 0, HCNT + 1);
- aic_outb(p, 0, HCNT + 2);
- aic_outb(p, cur_addr & 0xff, HADDR);
- aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
- aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
- aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ resid_dcnt = 1;
+ resid_sgcnt += 1;
+ native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
+ native_length = le32_to_cpu(scb->sg_list[index - 1].length);
+ cur_addr = native_addr + (native_length - 1);
+ sg_addr -= sizeof(struct hw_scatterlist);
}
else
{
/*
- * Back the data pointer up by one and add one to the remaining
- * byte count. Then store that in the HCNT and HADDR registers.
+ * resid_dcnt != native_length, so we are in the middle of a SG
+ * element. Back it up one byte and leave the rest alone.
*/
- cur_addr--;
- resid_dcnt++;
- aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
- aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
- aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
- aic_outb(p, resid_dcnt & 0xff, HCNT);
- aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
- aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
- aic_outb(p, cur_addr & 0xff, HADDR);
- aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
- aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
- aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ resid_dcnt += 1;
+ cur_addr -= 1;
}
+
+ /*
+ * Output the new addresses and counts to the right places on the
+ * card.
+ */
+ aic_outb(p, resid_sgcnt, SG_COUNT);
+ aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+ aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
+ aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
+ aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
+ aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
+ aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+
/*
- * The sequencer actually wants to find the new address and byte
- * count in the SHCNT and SHADDR register sets. These registers
- * are a shadow of the regular HCNT and HADDR registers. On the
- * Ultra2 controllers, these registers are read only and the way
- * we have to set their values is to put the values we want into
- * the HCNT and HADDR registers and then output PRELOADEN into
- * the DFCNTRL register which causes the card to latch the current
- * values in the HADDR and HCNT registers and drop it through to
- * the shadow registers. On older cards we copy them directly
- * across by hand.
+ * The sequencer actually wants to find the new address
+ * in the SHADDR register set. On the Ultra2 and later controllers
+ * this register set is readonly. In order to get the right number
+ * into the register, you actually have to enter it in HADDR and then
+ * use the PRELOADEN bit of DFCNTRL to drop it through from the
+ * HADDR register to the SHADDR register. On non-Ultra2 controllers,
+ * we simply write it direct.
*/
if(p->features & AHC_ULTRA2)
{
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- i=0;
+ /*
+ * We might as well be accurate and drop both the resid_dcnt and
+ * cur_addr into HCNT and HADDR and have both of them drop
+ * through to the shadow layer together.
+ */
+ aic_outb(p, resid_dcnt & 0xff, HCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+ aic_outb(p, cur_addr & 0xff, HADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+ aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
udelay(1);
- while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
- {
- udelay(1);
- }
aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
i=0;
- udelay(1);
while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
{
udelay(1);
@@ -5399,9 +5377,6 @@
}
else
{
- aic_outb(p, resid_dcnt & 0xff, STCNT);
- aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
- aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
aic_outb(p, cur_addr & 0xff, SHADDR);
aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
@@ -5410,15 +5385,82 @@
}
break;
-
-#if AIC7XXX_NOT_YET
- case TRACEPOINT:
+ case SEQ_SG_FIXUP:
+ {
+ unsigned char scb_index, tmp;
+ int sg_addr, sg_length;
+
+ scb_index = aic_inb(p, SCB_TAG);
+
+ if(scb_index > p->scb_data->numscbs)
{
- printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
- channel, target, lun);
+ printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
+ p->host_no, -1, -1, -1);
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, -1, -1, -1,
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+ p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
+ aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+ aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+ /*
+ * XXX: Add error handling here
+ */
+ break;
}
- break;
+ scb = p->scb_data->scb_array[scb_index];
+ if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
+ "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ scb->flags, (unsigned int)scb->cmd);
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
+ aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+ aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+ break;
+ }
+ if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
+ CTL_OF_SCB(scb));
+ /*
+ * Advance the SG pointer to the next element in the list
+ */
+ tmp = aic_inb(p, SG_NEXT);
+ tmp += SG_SIZEOF;
+ aic_outb(p, tmp, SG_NEXT);
+ if( tmp < SG_SIZEOF )
+ aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
+ tmp = aic_inb(p, SG_COUNT) - 1;
+ aic_outb(p, tmp, SG_COUNT);
+ sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
+ sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
+ /*
+ * Now stuff the element we just advanced past down onto the
+ * card so it can be stored in the residual area.
+ */
+ aic_outb(p, sg_addr & 0xff, HADDR);
+ aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
+ aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
+ aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
+ aic_outb(p, sg_length & 0xff, HCNT);
+ aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
+ aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
+ aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
+ while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
+ }
+ break;
+#if AIC7XXX_NOT_YET
case TRACEPOINT2:
{
printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
@@ -5463,6 +5505,10 @@
unsigned char target_scsirate, tindex;
unsigned short target_mask;
unsigned char target, channel, lun;
+ unsigned char bus_width, new_bus_width;
+ unsigned char trans_options, new_trans_options;
+ unsigned int period, new_period, offset, new_offset, maxsync;
+ struct aic7xxx_syncrate *syncrate;
target = scb->cmd->target;
channel = scb->cmd->channel;
@@ -5486,6 +5532,35 @@
}
/*
+ * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+ * using the SDTR messages. We need the PPR messages to enable the
+ * higher speeds that include things like Dual Edge clocking.
+ */
+ if (p->features & AHC_ULTRA2)
+ {
+ if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+ !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+ {
+ if (p->features & AHC_ULTRA3)
+ maxsync = AHC_SYNCRATE_ULTRA3;
+ else
+ maxsync = AHC_SYNCRATE_ULTRA2;
+ }
+ else
+ {
+ maxsync = AHC_SYNCRATE_ULTRA;
+ }
+ }
+ else if (p->features & AHC_ULTRA)
+ {
+ maxsync = AHC_SYNCRATE_ULTRA;
+ }
+ else
+ {
+ maxsync = AHC_SYNCRATE_FAST;
+ }
+
+ /*
* Just accept the length byte outright and perform
* more checking once we know the message type.
*/
@@ -5496,9 +5571,6 @@
{
case MSG_EXT_SDTR:
{
- unsigned int period, offset;
- unsigned char maxsync, saved_offset, options;
- struct aic7xxx_syncrate *syncrate;
if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
{
@@ -5511,35 +5583,18 @@
break;
}
- period = p->msg_buf[3];
- saved_offset = offset = p->msg_buf[4];
- options = 0;
+ period = new_period = p->msg_buf[3];
+ offset = new_offset = p->msg_buf[4];
+ trans_options = new_trans_options = 0;
+ bus_width = new_bus_width = target_scsirate & WIDEXFER;
/*
- * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
- * using the SDTR messages. We need the PPR messages to enable the
- * higher speeds that include things like Dual Edge clocking.
+ * If our current max syncrate is in the Ultra3 range, bump it back
+ * down to Ultra2 since we can't negotiate DT transfers using SDTR
*/
- if (p->features & AHC_ULTRA2)
- {
- if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
- !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
- {
- maxsync = AHC_SYNCRATE_ULTRA2;
- }
- else
- {
- maxsync = AHC_SYNCRATE_ULTRA;
- }
- }
- else if (p->features & AHC_ULTRA)
- {
- maxsync = AHC_SYNCRATE_ULTRA;
- }
- else
- {
- maxsync = AHC_SYNCRATE_FAST;
- }
+ if(maxsync == AHC_SYNCRATE_ULTRA3)
+ maxsync = AHC_SYNCRATE_ULTRA2;
+
/*
* We might have a device that is starting negotiation with us
* before we can start up negotiation with it....be prepared to
@@ -5549,88 +5604,116 @@
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
{
- if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
- !(p->needsdtr_copy & target_mask) &&
- (p->transinfo[tindex].user_offset) )
+ if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
{
/*
- * Not only is the device starting this up, but it also hasn't
- * been scanned yet, so this would likely be our TUR or our
- * INQUIRY command at scan time, so we need to use the
- * settings from the SEEPROM if they existed. Of course, even
- * if we didn't find a SEEPROM, we stuffed default values into
- * the user settings anyway, so use those in all cases.
+ * We shouldn't get here unless this is a narrow drive, wide
+ * devices should trigger this same section of code in the WDTR
+ * handler first instead.
*/
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
- if(p->features & AHC_ULTRA2)
- {
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- }
- else if (p->transinfo[tindex].cur_width)
+ p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+ p->transinfo[tindex].goal_options = 0;
+ if(p->transinfo[tindex].user_offset)
{
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ p->needsdtr_copy |= target_mask;
+ p->transinfo[tindex].goal_period =
+ MAX(10,p->transinfo[tindex].user_period);
+ if(p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
}
else
{
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ p->needsdtr_copy &= ~target_mask;
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
}
- p->needsdtr_copy |= target_mask;
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+ }
+ else if ((p->needsdtr_copy & target_mask) == 0)
+ {
+ /*
+ * This is a preemptive message from the target, we've already
+ * scanned this target and set our options for it, and we
+ * don't need a WDTR with this target (for whatever reason),
+ * so reject this incoming WDTR
+ */
+ reject = TRUE;
+ break;
}
+
+ /* The device is sending this message first and we have to reply */
+ reply = TRUE;
+
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Received pre-emptive SDTR message from "
"target.\n", p->host_no, CTL_OF_SCB(scb));
}
- if ( !p->transinfo[tindex].goal_offset )
- period = 255;
- if ( p->transinfo[tindex].goal_period > period )
- period = p->transinfo[tindex].goal_period;
+ /*
+ * Validate the values the device passed to us against our SEEPROM
+ * settings. We don't have to do this if we aren't replying since
+ * the device isn't allowed to send values greater than the ones
+ * we first sent to it.
+ */
+ new_period = MAX(period, p->transinfo[tindex].goal_period);
+ new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
}
-
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
- aic7xxx_validate_offset(p, syncrate, &offset,
- target_scsirate & WIDEXFER);
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+
+ /*
+ * Use our new_period, new_offset, bus_width, and card options
+ * to determine the actual syncrate settings
+ */
+ syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+ &trans_options);
+ aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
/*
- * Did we drop to async? Or are we sending a reply? If we are,
- * then we have to make sure that the reply value reflects the proper
- * settings so we need to set the goal values according to what
- * we need to send.
+ * Did we drop to async? If so, send a reply regardless of whether
+ * or not we initiated this negotiation.
*/
- if ( (offset != saved_offset) ||
- ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
- (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
+ if ((new_offset == 0) && (new_offset != offset))
{
- aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
- options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ p->needsdtr_copy &= ~target_mask;
+ reply = TRUE;
}
/*
- * Did we start this, if not, or if we went to low and had to
+ * Did we start this, if not, or if we went too low and had to
* go async, then send an SDTR back to the target
*/
- p->needsdtr &= ~target_mask;
- p->dtr_pending &= ~target_mask;
- if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
- (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
- (offset != saved_offset) )
+ if(reply)
{
- reply = TRUE;
- p->dtr_pending |= target_mask;
+ /* when sending a reply, make sure that the goal settings are
+ * updated along with current and active since the code that
+ * will actually build the message for the sequencer uses the
+ * goal settings as its guidelines.
+ */
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, trans_options,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_SDTR;
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
}
+ else
+ {
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, trans_options,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ p->needsdtr &= ~target_mask;
+ }
done = TRUE;
break;
}
case MSG_EXT_WDTR:
{
- unsigned char bus_width;
if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
{
@@ -5643,7 +5726,8 @@
break;
}
- bus_width = p->msg_buf[3];
+ bus_width = new_bus_width = p->msg_buf[3];
+
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
(SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
{
@@ -5662,7 +5746,7 @@
} /* We fall through on purpose */
case MSG_EXT_WDTR_BUS_8_BIT:
{
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
p->needwdtr_copy &= ~target_mask;
break;
}
@@ -5671,29 +5755,40 @@
break;
}
}
- p->dtr_pending &= ~target_mask;
p->needwdtr &= ~target_mask;
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
}
else
{
- if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+ if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
{
/*
* Well, we now know the WDTR and SYNC caps of this device since
* it contacted us first, mark it as such and copy the user stuff
* over to the goal stuff.
*/
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
+ if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
+ {
+ p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+ p->needwdtr_copy |= target_mask;
+ }
+
+ /*
+ * Devices that support DT transfers don't start WDTR requests
+ */
+ p->transinfo[tindex].goal_options = 0;
+
if(p->transinfo[tindex].user_offset)
{
+ p->needsdtr_copy |= target_mask;
+ p->transinfo[tindex].goal_period =
+ MAX(10,p->transinfo[tindex].user_period);
if(p->features & AHC_ULTRA2)
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
}
- else if( p->transinfo[tindex].user_width &&
- (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
- p->features & AHC_WIDE )
+ else if( p->transinfo[tindex].goal_width )
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
}
@@ -5701,48 +5796,76 @@
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
}
+ } else {
+ p->needsdtr_copy &= ~target_mask;
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
}
- p->transinfo[tindex].goal_width =
- p->transinfo[tindex].user_width;
- p->needwdtr_copy |= target_mask;
- p->needsdtr_copy |= target_mask;
+
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
}
- if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ else if ((p->needwdtr_copy & target_mask) == 0)
{
- printk(INFO_LEAD "Received pre-emptive WDTR message from "
- "target.\n", p->host_no, CTL_OF_SCB(scb));
- }
+ /*
+ * This is a preemptive message from the target, we've already
+ * scanned this target and set our options for it, and we
+ * don't need a WDTR with this target (for whatever reason),
+ * so reject this incoming WDTR
+ */
+ reject = TRUE;
+ break;
+ }
+
+ /* The device is sending this message first and we have to reply */
+ reply = TRUE;
+
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Received pre-emptive WDTR message from "
+ "target.\n", p->host_no, CTL_OF_SCB(scb));
+ }
switch(bus_width)
{
- default:
+ case MSG_EXT_WDTR_BUS_16_BIT:
{
if ( (p->features & AHC_WIDE) &&
(p->transinfo[tindex].goal_width ==
MSG_EXT_WDTR_BUS_16_BIT) )
{
- bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
break;
}
} /* Fall through if we aren't a wide card */
+ default:
case MSG_EXT_WDTR_BUS_8_BIT:
{
p->needwdtr_copy &= ~target_mask;
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
break;
}
}
- reply = TRUE;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_WDTR;
p->needwdtr &= ~target_mask;
- p->dtr_pending |= target_mask;
+ if((p->dtr_pending & target_mask) == 0)
+ {
+ /* there is no other command with SCB_DTR_SCB already set that will
+ * trigger the release of the dtr_pending bit. Both set the bit
+ * and set scb->flags |= SCB_DTR_SCB
+ */
+ p->dtr_pending |= target_mask;
+ scb->flags |= SCB_DTR_SCB;
+ }
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ /* when sending a reply, make sure that the goal settings are
+ * updated along with current and active since the code that
+ * will actually build the message for the sequencer uses the
+ * goal settings as its guidelines.
+ */
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
}
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
/*
* By virtue of the SCSI spec, a WDTR message negates any existing
@@ -5759,10 +5882,6 @@
}
case MSG_EXT_PPR:
{
- unsigned char bus_width, trans_options, new_trans_options;
- unsigned int period, offset;
- unsigned char maxsync, saved_offset;
- struct aic7xxx_syncrate *syncrate;
if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
{
@@ -5775,9 +5894,9 @@
break;
}
- period = p->msg_buf[3];
- offset = saved_offset = p->msg_buf[5];
- bus_width = p->msg_buf[6];
+ period = new_period = p->msg_buf[3];
+ offset = new_offset = p->msg_buf[5];
+ bus_width = new_bus_width = p->msg_buf[6];
trans_options = new_trans_options = p->msg_buf[7] & 0xf;
if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -5787,22 +5906,6 @@
trans_options);
}
- if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
- !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
- {
- if(p->features & AHC_ULTRA3)
- {
- maxsync = AHC_SYNCRATE_ULTRA3;
- }
- else
- {
- maxsync = AHC_SYNCRATE_ULTRA2;
- }
- }
- else
- {
- maxsync = AHC_SYNCRATE_ULTRA;
- }
/*
* We might have a device that is starting negotiation with us
* before we can start up negotiation with it....be prepared to
@@ -5811,13 +5914,22 @@
*/
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
- {
- reply = TRUE;
- scb->flags &= ~SCB_MSGOUT_BITS;
- scb->flags |= SCB_MSGOUT_PPR;
- p->dev_flags[tindex] |= DEVICE_SCSI_3;
- if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
- {
+ {
+ /* Have we scanned the device yet? */
+ if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
+ {
+ /* The device is electing to use PPR messages, so we will too until
+ * we know better */
+ p->needppr |= target_mask;
+ p->needppr_copy |= target_mask;
+ p->needsdtr &= ~target_mask;
+ p->needsdtr_copy &= ~target_mask;
+ p->needwdtr &= ~target_mask;
+ p->needwdtr_copy &= ~target_mask;
+
+ /* We know the device is SCSI-3 compliant due to PPR */
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+
/*
* Not only is the device starting this up, but it also hasn't
* been scanned yet, so this would likely be our TUR or our
@@ -5826,15 +5938,19 @@
* if we didn't find a SEEPROM, we stuffed default values into
* the user settings anyway, so use those in all cases.
*/
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_width =
+ p->transinfo[tindex].user_width;
if(p->transinfo[tindex].user_offset)
{
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
if(p->features & AHC_ULTRA2)
{
p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
}
- else if( p->transinfo[tindex].user_width &&
+ else if( p->transinfo[tindex].goal_width &&
(bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
p->features & AHC_WIDE )
{
@@ -5845,117 +5961,142 @@
p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
}
}
- p->transinfo[tindex].goal_width =
- p->transinfo[tindex].user_width;
- p->transinfo[tindex].goal_options =
- p->transinfo[tindex].user_options;
+ else
+ {
+ p->transinfo[tindex].goal_period = 255;
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+ }
+ else if ((p->needppr_copy & target_mask) == 0)
+ {
+ /*
+ * This is a preemptive message from the target, we've already
+ * scanned this target and set our options for it, and we
+ * don't need a PPR with this target (for whatever reason),
+ * so reject this incoming PPR
+ */
+ reject = TRUE;
+ break;
}
+
+ /* The device is sending this message first and we have to reply */
+ reply = TRUE;
+
if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
printk(INFO_LEAD "Received pre-emptive PPR message from "
"target.\n", p->host_no, CTL_OF_SCB(scb));
}
- if ( !p->transinfo[tindex].goal_offset )
- period = 255;
- if ( p->transinfo[tindex].goal_period > period )
- period = p->transinfo[tindex].goal_period;
- if ( p->transinfo[tindex].goal_options == 0 )
- new_trans_options = 0;
- switch(bus_width)
+
+ }
+
+ switch(bus_width)
+ {
+ case MSG_EXT_WDTR_BUS_16_BIT:
{
- default:
- {
- if ( (p->features & AHC_WIDE) &&
- (p->transinfo[tindex].goal_width ==
- MSG_EXT_WDTR_BUS_16_BIT) )
- {
- bus_width = MSG_EXT_WDTR_BUS_16_BIT;
- break;
- }
- } /* Fall through if we aren't a wide card */
- case MSG_EXT_WDTR_BUS_8_BIT:
+ if ( (p->transinfo[tindex].goal_width ==
+ MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE)
{
- p->needwdtr_copy &= ~target_mask;
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
break;
}
}
- if ( (p->transinfo[tindex].goal_period > 9) ||
- (p->transinfo[tindex].goal_options == 0) )
+ default:
{
- scb->flags &= ~SCB_MSGOUT_BITS;
- reject = TRUE;
- reply = FALSE;
- p->needppr &= ~(1 << tindex);
- p->needppr_copy &= ~(1 << tindex);
- if ( p->transinfo[tindex].goal_offset )
- {
- p->needsdtr |= (1 << tindex);
- p->needsdtr_copy |= (1 << tindex);
- }
- if ( p->transinfo[tindex].goal_width )
- {
- p->needwdtr |= (1 << tindex);
- p->needwdtr_copy |= (1 << tindex);
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+ (aic7xxx_verbose > 0xffff)) )
+ {
+ reply = TRUE;
+ printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+ p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
}
+ } /* We fall through on purpose */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ {
+ /*
+ * According to the spec, if we aren't wide, we also can't be
+ * Dual Edge so clear the options byte
+ */
+ new_trans_options = 0;
+ new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ break;
}
}
+
+ if(reply)
+ {
+ /* when sending a reply, make sure that the goal settings are
+ * updated along with current and active since the code that
+ * will actually build the message for the sequencer uses the
+ * goal settings as its guidelines.
+ */
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+ &new_trans_options);
+ aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, new_trans_options,
+ AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ }
else
{
- switch(bus_width)
+ aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+ &new_trans_options);
+ aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+ new_offset, new_trans_options,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ }
+
+ /*
+ * As it turns out, if we don't *have* to have PPR messages, then
+ * configure ourselves not to use them since that makes some
+ * external drive chassis work (those chassis can't parse PPR
+ * messages and they mangle the SCSI bus until you send a WDTR
+ * and SDTR that they can understand).
+ */
+ if(new_trans_options == 0)
+ {
+ p->needppr &= ~target_mask;
+ p->needppr_copy &= ~target_mask;
+ if(new_offset)
{
- default:
- {
- reject = TRUE;
- if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
- (aic7xxx_verbose > 0xffff)) )
- {
- printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
- p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
- }
- } /* We fall through on purpose */
- case MSG_EXT_WDTR_BUS_8_BIT:
- {
- /*
- * According to the spec, if we aren't wide, we also can't be
- * Dual Edge so clear the options byte
- */
- new_trans_options = 0;
- bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- break;
- }
- case MSG_EXT_WDTR_BUS_16_BIT:
- {
- break;
- }
+ p->needsdtr |= target_mask;
+ p->needsdtr_copy |= target_mask;
+ }
+ if (new_bus_width)
+ {
+ p->needwdtr |= target_mask;
+ p->needwdtr_copy |= target_mask;
}
}
- if ( !reject )
+ if((new_offset == 0) && (offset != 0))
{
- aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
- &new_trans_options);
- aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, new_trans_options,
- AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ /*
+ * Oops, the syncrate went to low for this card and we fell off
+ * to async (should never happen with a device that uses PPR
+ * messages, but have to be complete)
+ */
+ reply = TRUE;
}
- p->dtr_pending &= ~target_mask;
- p->needppr &= ~target_mask;
if(reply)
{
- p->dtr_pending |= target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_PPR;
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
}
+ else
+ {
+ p->needppr &= ~target_mask;
+ }
done = TRUE;
break;
}
@@ -6193,16 +6334,14 @@
printerror = 0;
}
}
- if ( (scb != NULL) &&
- (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+ if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) )
{
/*
- * This might be a SCSI-3 device that is dropping the bus due to
- * errors and signalling that we should reduce the transfer speed.
- * All we have to do is complete this command (since it's a negotiation
- * command already) and the checksum routine should flag an error and
- * reduce the speed setting and renegotiate. We call the reset routing
- * just to clean out the hardware from this scb.
+ * Hmmm...error during a negotiation command. Either we have a
+ * borken bus, or the device doesn't like our negotiation message.
+ * Since we check the INQUIRY data of a device before sending it
+ * negotiation messages, assume the bus is borken for whatever
+ * reason. Complete the command.
*/
printerror = 0;
aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
@@ -6334,19 +6473,6 @@
cmd->result = 0;
scb = NULL;
}
- else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
- {
- /*
- * Turn off the needsdtr, needwdtr, and needppr bits since this device
- * doesn't seem to exist.
- */
- p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
- p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
- }
}
/*
* Keep the sequencer from trying to restart any selections
@@ -6469,7 +6595,6 @@
}
}
else if( (lastphase == P_MESGOUT) &&
- (cmd == p->dev_dtr_cmnd[tindex]) &&
(scb->flags & SCB_MSGOUT_PPR) )
{
/*
@@ -6488,7 +6613,6 @@
aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
p->transinfo[tindex].goal_options = 0;
- p->dtr_pending &= ~(1 << tindex);
scb->flags &= ~SCB_MSGOUT_BITS;
if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
@@ -6511,87 +6635,6 @@
}
scb = NULL;
}
- else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
- {
- struct aic7xxx_syncrate *syncrate;
- unsigned int period = p->transinfo[tindex].cur_period;
- unsigned char options = p->transinfo[tindex].cur_options;
- /*
- * oops, we had a failure, lower the transfer rate and try again. It's
- * worth noting here that it might be wise to also check for typical
- * wide setting on narrow cable type problems and try disabling wide
- * instead of slowing down if those exist. That's hard to do with simple
- * checksums though.
- */
- printk(WARN_LEAD "Parity error during %s phase.\n",
- p->host_no, CTL_OF_SCB(scb), phase);
- if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
- {
- syncrate++;
- if( (syncrate->rate[0] != NULL) &&
- (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
- {
- p->transinfo[tindex].goal_period = syncrate->period;
- if( p->transinfo[tindex].goal_period > 9 )
- {
- p->transinfo[tindex].goal_options = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- if (p->transinfo[tindex].goal_width)
- {
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- }
- }
- }
- else if (p->transinfo[tindex].goal_width)
- {
- p->transinfo[tindex].goal_width = 0;
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_options =
- p->transinfo[tindex].user_options;
- if( p->transinfo[tindex].goal_period <= 9 )
- {
- p->needppr |= (1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needppr_copy |= (1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- }
- else
- {
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- }
- }
- else
- {
- p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 255;
- p->transinfo[tindex].goal_options = 0;
- p->transinfo[tindex].goal_width = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needwdtr &= ~(1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- }
- }
- p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
- }
- else
- {
- p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
- }
/*
* We've set the hardware to assert ATN if we get a parity
@@ -6860,34 +6903,11 @@
else if (scb->flags & SCB_SENSE)
{
char *buffer = &scb->cmd->sense_buffer[0];
- if (scb->cmd == p->dev_dtr_cmnd[tindex])
- {
- struct aic7xxx_scb *old_scb;
- /*
- * We have valid sense data, send it back immediately.
- */
- old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
- *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
- old_scb->hscb->target_status = scb->hscb->target_status;
- old_scb->cmd->result = scb->hscb->target_status;
- old_scb->cmd->result |= (DID_ERROR << 16);
- aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
- scbq_remove(&p->waiting_scbs, old_scb);
- scbq_remove(&p->delayed_scbs[tindex], old_scb);
- scb->cmd->next = NULL;
- aic7xxx_done(p, scb);
- aic7xxx_done(p, old_scb);
- continue;
- }
- else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+
+ if (buffer[12] == 0x47 || buffer[12] == 0x54)
{
/*
- * SCSI errors, run domain validation and re-run negotiation
- */
- p->needdv |= (1<<tindex);
- /*
- * Signal that we need to re-negotiate things, this also gets us our
- * INQUIRY command to re-checksum off of.
+ * Signal that we need to re-negotiate things.
*/
p->needppr |= (p->needppr_copy & (1<<tindex));
p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
@@ -6900,7 +6920,18 @@
case BUSY:
scb->hscb->target_status = 0;
scb->cmd->result = 0;
+ scb->hscb->residual_SG_segment_count = 0;
+ scb->hscb->residual_data_count[0] = 0;
+ scb->hscb->residual_data_count[1] = 0;
+ scb->hscb->residual_data_count[2] = 0;
aic7xxx_error(scb->cmd) = DID_OK;
+ aic7xxx_status(scb->cmd) = 0;
+ /*
+ * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
+ * this command on a timer and allowing us to retry it. Here, we
+ * just 0 out a few values so that they don't carry through to when
+ * the command finally does complete.
+ */
break;
default:
cmd = scb->cmd;
@@ -7065,33 +7096,27 @@
if(!p)
return;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
- if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
- {
- return;
- }
spin_lock_irqsave(&io_request_lock, cpu_flags);
+ p->flags |= AHC_IN_ISR;
do
{
aic7xxx_isr(irq, dev_id, regs);
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, &p->flags);
+ p->flags &= ~AHC_IN_ISR;
spin_unlock_irqrestore(&io_request_lock, cpu_flags);
#else
- if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
- {
- return;
- }
DRIVER_LOCK
+ p->flags |= AHC_IN_ISR;
do
{
aic7xxx_isr(irq, dev_id, regs);
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
+ p->flags &= ~AHC_IN_ISR;
DRIVER_UNLOCK
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
- clear_bit(AHC_IN_ISR_BIT, (int *)&p->flags);
#endif
}
@@ -9012,22 +9037,6 @@
kfree(p->scb_data);
}
- /*
- * Free any alloced Scsi_Cmnd structures that might be around for
- * negotiation purposes....
- */
- for (i = 0; i < MAX_TARGETS; i++)
- {
- if(p->dev_dtr_cmnd[i])
- {
- if(p->dev_dtr_cmnd[i]->request_buffer)
- {
- kfree(p->dev_dtr_cmnd[i]->request_buffer);
- }
- kfree(p->dev_dtr_cmnd[i]);
- }
- }
-
}
/*+F*************************************************************************
@@ -9413,7 +9422,7 @@
}
aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
- p->needppr = p->needppr_copy = p->needdv = 0;
+ p->needppr = p->needppr_copy = 0;
p->needwdtr = p->needwdtr_copy;
p->needsdtr = p->needsdtr_copy;
p->dtr_pending = 0;
@@ -9471,53 +9480,165 @@
/*+F*************************************************************************
* Function:
- * aic7xxx_detect
+ * aic7xxx_configure_bugs
*
* Description:
- * Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
- *
- * XXX - This should really be called aic7xxx_probe(). A sequence of
- * probe(), attach()/detach(), and init() makes more sense than
- * one do-it-all function. This may be useful when (and if) the
- * mid-level SCSI code is overhauled.
+ * Take the card passed in and set the appropriate bug flags based upon
+ * the card model. Also make any changes needed to device registers or
+ * PCI registers while we are here.
*-F*************************************************************************/
-int
-aic7xxx_detect(Scsi_Host_Template *template)
+static void
+aic7xxx_configure_bugs(struct aic7xxx_host *p)
{
- struct aic7xxx_host *temp_p = NULL;
- struct aic7xxx_host *current_p = NULL;
- struct aic7xxx_host *list_p = NULL;
- int found = 0;
-#if defined(__i386__) || defined(__alpha__)
- ahc_flag_type flags = 0;
- int type;
-#endif
- unsigned char sxfrctl1;
-#if defined(__i386__) || defined(__alpha__)
- unsigned char hcntrl, hostconf;
- unsigned int slot, base;
-#endif
-
-#ifdef MODULE
- /*
- * If we are called as a module, the aic7xxx pointer may not be null
- * and it would point to our bootup string, just like on the lilo
- * command line. IF not NULL, then process this config string with
- * aic7xxx_setup
- */
- if(aic7xxx)
- aic7xxx_setup(aic7xxx, NULL);
- if(dummy_buffer[0] != 'P')
- printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
- "/scsi/README.aic7xxx\n"
- "aic7xxx: to see the proper way to specify options to the aic7xxx "
- "module\n"
- "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
- "aic7xxx: insmod or else it might trash certain memory areas.\n");
+ unsigned char pci_rev;
+ unsigned short tmp_word;
+
+ if((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+ {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
+ pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+ PCI_REVISION_ID, &pci_rev);
+#else
+ pci_read_config_byte(p->pdev, PCI_REVISION_ID, &pci_rev);
#endif
+ }
- template->proc_dir = &proc_scsi_aic7xxx;
- template->sg_tablesize = AIC7XXX_MAX_SG;
+ switch(p->chip & AHC_CHIPID_MASK)
+ {
+ case AHC_AIC7860:
+ if(pci_rev >= 1)
+ {
+ p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+ }
+ /* fall through */
+ case AHC_AIC7850:
+ case AHC_AIC7870:
+ p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+ break;
+ case AHC_AIC7880:
+ p->bugs |= AHC_BUG_TMODE_WIDEODD;
+ if(pci_rev >= 1)
+ {
+ p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+ }
+ else
+ {
+ p->bugs |= AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+ }
+ break;
+ case AHC_AIC7890:
+ if(pci_rev == 0)
+ {
+ p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
+ }
+ break;
+ case AHC_AIC7892:
+ p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+ break;
+ case AHC_AIC7895:
+ p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+ AHC_BUG_CACHETHEN;
+ if(pci_rev <= 3)
+ {
+ p->bugs |= AHC_BUG_PCI_MWI;
+ }
+ break;
+ case AHC_AIC7896:
+ p->bugs |= AHC_BUG_CACHETHEN_DIS;
+ break;
+ case AHC_AIC7899:
+ p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+ break;
+ default:
+ /* Nothing to do */
+ break;
+ }
+
+ /*
+ * Now handle the bugs that require PCI register or card register tweaks
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
+ pcibios_read_config_word(p->pci_bus, p->pci_device_fn,
+ PCI_COMMAND, &tmp_word);
+#else
+ pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
+#endif
+ if(p->bugs & AHC_BUG_PCI_MWI)
+ {
+ tmp_word &= ~PCI_COMMAND_INVALIDATE;
+ }
+ else
+ {
+ tmp_word |= PCI_COMMAND_INVALIDATE;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
+ pcibios_write_config_word(p->pci_bus, p->pci_device_fn,
+ PCI_COMMAND, tmp_word);
+#else
+ pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
+#endif
+
+ if(p->bugs & AHC_BUG_CACHETHEN)
+ {
+ aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
+ }
+ else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
+ {
+ aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
+ }
+
+ return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_detect
+ *
+ * Description:
+ * Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe(). A sequence of
+ * probe(), attach()/detach(), and init() makes more sense than
+ * one do-it-all function. This may be useful when (and if) the
+ * mid-level SCSI code is overhauled.
+ *-F*************************************************************************/
+int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+ struct aic7xxx_host *temp_p = NULL;
+ struct aic7xxx_host *current_p = NULL;
+ struct aic7xxx_host *list_p = NULL;
+ int found = 0;
+#if defined(__i386__) || defined(__alpha__)
+ ahc_flag_type flags = 0;
+ int type;
+#endif
+ unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+ unsigned char hcntrl, hostconf;
+ unsigned int slot, base;
+#endif
+
+#ifdef MODULE
+ /*
+ * If we are called as a module, the aic7xxx pointer may not be null
+ * and it would point to our bootup string, just like on the lilo
+ * command line. IF not NULL, then process this config string with
+ * aic7xxx_setup
+ */
+ if(aic7xxx)
+ aic7xxx_setup(aic7xxx, NULL);
+ if(dummy_buffer[0] != 'P')
+ printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
+ "/scsi/README.aic7xxx\n"
+ "aic7xxx: to see the proper way to specify options to the aic7xxx "
+ "module\n"
+ "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
+ "aic7xxx: insmod or else it might trash certain memory areas.\n");
+#endif
+
+ template->proc_dir = &proc_scsi_aic7xxx;
+ template->sg_tablesize = AIC7XXX_MAX_SG;
#ifdef CONFIG_PCI
@@ -10290,6 +10411,14 @@
aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
}
+ /*
+ * Call our function to fixup any bugs that exist on this chipset.
+ * This may muck with PCI settings and other device settings, so
+ * make sure it's after all the other PCI and device register
+ * tweaks so it can back out bad settings on specific broken cards.
+ */
+ aic7xxx_configure_bugs(temp_p);
+
if ( list_p == NULL )
{
list_p = current_p = temp_p;
@@ -10533,6 +10662,11 @@
}
/*
+ * All the 7770 based chipsets have this bug
+ */
+ temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
+
+ /*
* Set the FIFO threshold and the bus off time.
*/
hostconf = aic_inb(temp_p, HOSTCONF);
@@ -10751,297 +10885,6 @@
return (found);
}
-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
- Scsi_Cmnd *old_cmd, int tindex);
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_allocate_negotiation_command
- *
- * Description:
- * allocate the actual command struct and fill in the gaps...
- *-F*************************************************************************/
-static Scsi_Cmnd *
-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
- Scsi_Cmnd *old_cmd, int tindex)
-{
- Scsi_Cmnd *cmd;
- char *buffer;
-
- if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
- {
- return(NULL);
- }
- if (!(buffer = kmalloc(256, GFP_ATOMIC)))
- {
- kfree(p->dev_dtr_cmnd[tindex]);
- p->dev_dtr_cmnd[tindex] = NULL;
- return(NULL);
- }
- cmd = p->dev_dtr_cmnd[tindex];
- memset(cmd, 0, sizeof(Scsi_Cmnd));
- memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
- memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
- memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
- cmd->lun = 0;
- cmd->request_bufflen = 255;
- cmd->request_buffer = buffer;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
- cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
- cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
- cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
- cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
- cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
- cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
- return(cmd);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_negotiation_complete
- *
- * Description:
- * Handle completion events for our Negotiation commands. Clear out the
- * struct and get it ready for its next use.
- *-F*************************************************************************/
-static void
-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
-{
- unsigned int checksum;
- int i;
- int *ibuffer;
- struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
- int tindex = TARGET_INDEX(cmd);
- struct aic7xxx_syncrate *syncrate;
-
- /*
- * perform our minimalistic domain validation
- */
- if(p->dev_flags[tindex] & DEVICE_SCANNED)
- {
- ibuffer = (int *)cmd->request_buffer;
- checksum = 0;
- for(i = 0; i < (cmd->request_bufflen >> 2); i++)
- {
- checksum += ibuffer[i];
- }
- if( (checksum != p->dev_checksum[tindex]) &&
- (p->transinfo[tindex].cur_offset != 0) )
- {
- unsigned int period = p->transinfo[tindex].cur_period;
- unsigned char options = p->transinfo[tindex].cur_options;
-
- if (p->needdv & (1<<tindex))
- {
- /*
- * oops, we had a failure, lower the transfer rate and try again. It's
- * worth noting here that it might be wise to also check for typical
- * wide setting on narrow cable type problems and try disabling wide
- * instead of slowing down if those exist. That's hard to do with simple
- * checksums though.
- */
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
- {
- printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
- "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
- }
- if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
- {
- syncrate++;
- if( (syncrate->rate[0] != NULL) &&
- (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
- {
- p->transinfo[tindex].goal_period = syncrate->period;
- if( p->transinfo[tindex].goal_period > 9 )
- {
- p->transinfo[tindex].goal_options = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- if (p->transinfo[tindex].goal_width)
- {
- p->needwdtr |= (1<<tindex);
- p->needwdtr_copy |= (1<<tindex);
- }
- }
- }
- else if (p->transinfo[tindex].goal_width)
- {
- p->transinfo[tindex].goal_width = 0;
- p->needwdtr &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
- p->transinfo[tindex].goal_period =
- p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_options =
- p->transinfo[tindex].user_options;
- if( p->transinfo[tindex].goal_period <= 9 )
- {
- p->needppr |= (1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needppr_copy |= (1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- }
- else
- {
- p->needppr &= ~(1<<tindex);
- p->needsdtr |= (1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
- }
- }
- else
- {
- p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 255;
- p->transinfo[tindex].goal_options = 0;
- p->transinfo[tindex].goal_width = 0;
- p->needppr &= ~(1<<tindex);
- p->needsdtr &= ~(1<<tindex);
- p->needwdtr &= ~(1<<tindex);
- p->needppr_copy &= ~(1<<tindex);
- p->needsdtr_copy &= ~(1<<tindex);
- p->needwdtr_copy &= ~(1<<tindex);
- }
- }
- p->needdv &= ~(1<<tindex);
- }
- else
- {
- if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
- {
- printk(INFO_LEAD "Performing Domain validation.\n",
- p->host_no, CTL_OF_CMD(cmd));
- }
- /*
- * Update the checksum in case the INQUIRY data has changed, maybe
- * in relation to a change in the mode pages, or whatever.
- */
- p->dev_checksum[tindex] = checksum;
- /*
- * Signal that we are trying out the domain validation
- */
- p->needdv |= (1<<tindex);
- /*
- * Signal that we need to re-negotiate things, this also gets us our
- * INQUIRY command to re-checksum off of.
- */
- p->needppr |= (p->needppr_copy & (1<<tindex));
- p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
- p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
- }
- }
- else
- {
- if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->needdv & (1<<tindex)) )
- {
- printk(INFO_LEAD "Successfully completed Domain validation.\n",
- p->host_no, CTL_OF_CMD(cmd));
- }
- /*
- * We successfully did our checksum, so don't leave the needdv flag set
- * in case we might have set it last time through.
- */
- p->needdv &= ~(1<<tindex);
- }
- }
-
- p->dtr_pending &= ~(0x01 << tindex);
- /*
- * This looks recursive in the extreme, but if this was a WDTR negotiation
- * and we didn't follow up with SDTR yet, then this will get it started.
- * For all other cases, this should work out to be a no-op, unless we are
- * doing domain validation and happen to need a new negotiation command.
- *
- * In case we don't want this to go any further, the cmdcmplt interrupt
- * handler will NULL out the cmd->next entry so that the real SCSI command
- * can be sent back to the mid layer code with SENSE data intact. We'll
- * finish things up when the cmd gets sent back down to us, so no worries.
- */
- if(cmd->next)
- {
- aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
- }
- return;
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_build_negotiation_command
- *
- * Description:
- * Build a Scsi_Cmnd structure to perform negotiation with or else send
- * a pre-built command specifically for this purpose.
- *-F*************************************************************************/
-static void
-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
- int tindex)
-{
-
- if ( !(p->dtr_pending & (1<<tindex)) &&
- ( (p->needppr & (1<<tindex)) ||
- (p->needwdtr & (1<<tindex)) ||
- (p->needsdtr & (1<<tindex)) ) )
- {
- if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
- (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
- {
- return;
- }
- /*
- * Before sending this thing out, we also make the cmd->next pointer
- * point to the real command so we can stuff any possible SENSE data
- * into the real command instead of this fake command. This has to be
- * done each time the command is built, not just the first time, hence
- * it's outside of the above if()...
- */
- p->dev_dtr_cmnd[tindex]->next = old_cmd;
- /*
- * Clear the buffer so checksums come out right....
- */
- memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
- p->dev_dtr_cmnd[tindex]->request_bufflen);
- /*
- * Remove any commands for this particular device that might be on the
- * waiting_scbs queue or qinfifo so that this command goes out first.
- * This is vital for our implementation of domain validation.
- */
- pause_sequencer(p);
- aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
- SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
- unpause_sequencer(p, FALSE);
- {
- struct aic7xxx_scb *scb, *next;
-
- scb = p->waiting_scbs.head;
- while(scb != NULL)
- {
- if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
- ALL_LUNS, SCB_LIST_NULL) )
- {
- next = scb->q_next;
- scbq_remove(&p->waiting_scbs, scb);
- scbq_insert_tail(&p->delayed_scbs[tindex], scb);
- scb = next;
- }
- else
- {
- scb = scb->q_next;
- }
- }
- }
- aic7xxx_queue(p->dev_dtr_cmnd[tindex],
- aic7xxx_negotiation_complete);
- }
-}
-
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*+F*************************************************************************
* Function:
@@ -11090,7 +10933,7 @@
*/
hscb->control = 0;
scb->tag_action = 0;
- cmd->tag = hscb->tag;
+
if (p->discenable & mask)
{
hscb->control |= DISCENB;
@@ -11119,34 +10962,29 @@
}
}
}
- if ( cmd == p->dev_dtr_cmnd[tindex] )
+ if ( !(p->dtr_pending & mask) &&
+ ( (p->needppr & mask) ||
+ (p->needwdtr & mask) ||
+ (p->needsdtr & mask) ) &&
+ (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
{
p->dtr_pending |= mask;
scb->tag_action = 0;
- if (p->dev_flags[tindex] & DEVICE_SCANNED)
+ hscb->control &= DISCENB;
+ hscb->control |= MK_MESSAGE;
+ if(p->needppr & mask)
{
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- if(p->needppr & mask)
- {
- scb->flags |= SCB_MSGOUT_PPR;
- }
- else if(p->needwdtr & mask)
- {
- scb->flags |= SCB_MSGOUT_WDTR;
- }
- else if(p->needsdtr & mask)
- {
- scb->flags |= SCB_MSGOUT_SDTR;
- }
+ scb->flags |= SCB_MSGOUT_PPR;
}
- }
- if ( !(p->dtr_pending & mask) &&
- ( (p->needppr & mask) ||
- (p->needwdtr & mask) ||
- (p->needsdtr & mask) ) )
- {
- aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
+ else if(p->needwdtr & mask)
+ {
+ scb->flags |= SCB_MSGOUT_WDTR;
+ }
+ else if(p->needsdtr & mask)
+ {
+ scb->flags |= SCB_MSGOUT_SDTR;
+ }
+ scb->flags |= SCB_DTR_SCB;
}
hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -11285,50 +11123,58 @@
aic7xxx_allocate_scb(p);
DRIVER_UNLOCK
scb = scbq_remove_head(&p->scb_data->free_scbs);
- }
- if (scb == NULL)
- {
- printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
- CTL_OF_CMD(cmd));
- cmd->result = (DID_BUS_BUSY << 16);
+ if(scb == NULL)
+ printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+ CTL_OF_CMD(cmd));
+ }
+ while (scb == NULL)
+ {
+ /*
+ * Well, all SCBs are currently active on the bus. So, we spin here
+ * running the interrupt handler until one completes and becomes free.
+ * We can do this safely because we either A) hold the driver lock (in
+ * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
+ * kernels) and so either way, we won't take any other interrupts and
+ * the queue path will block until we release it. Also, we would worry
+ * about running the completion queues, but obviously there are plenty
+ * of commands outstanding to trigger a later interrupt that will do
+ * that for us, so skip it here.
+ */
DRIVER_LOCK
- aic7xxx_queue_cmd_complete(p, cmd);
+ aic7xxx_isr(p->irq, p, NULL);
DRIVER_UNLOCK
- return 0;
+ scb = scbq_remove_head(&p->scb_data->free_scbs);
}
- else
- {
- scb->cmd = cmd;
- aic7xxx_position(cmd) = scb->hscb->tag;
+ scb->cmd = cmd;
+ aic7xxx_position(cmd) = scb->hscb->tag;
- /*
- * Construct the SCB beforehand, so the sequencer is
- * paused a minimal amount of time.
- */
- aic7xxx_buildscb(p, cmd, scb);
+ /*
+ * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+ * is set up properly, and the parity error flag is reset, then send
+ * the SCB to the sequencer and watch the fun begin.
+ */
+ cmd->scsi_done = fn;
+ cmd->result = DID_OK;
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ aic7xxx_error(cmd) = DID_OK;
+ aic7xxx_status(cmd) = 0;
+ cmd->host_scribble = NULL;
- /*
- * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
- * is set up properly, and the parity error flag is reset, then send
- * the SCB to the sequencer and watch the fun begin.
- */
- cmd->scsi_done = fn;
- cmd->result = DID_OK;
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- aic7xxx_error(cmd) = DID_OK;
- aic7xxx_status(cmd) = 0;
- cmd->host_scribble = NULL;
+ /*
+ * Construct the SCB beforehand, so the sequencer is
+ * paused a minimal amount of time.
+ */
+ aic7xxx_buildscb(p, cmd, scb);
- scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+ scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- DRIVER_LOCK
- scbq_insert_tail(&p->waiting_scbs, scb);
- if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
- {
- aic7xxx_run_waiting_queues(p);
- }
- DRIVER_UNLOCK
+ DRIVER_LOCK
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+ {
+ aic7xxx_run_waiting_queues(p);
}
+ DRIVER_UNLOCK
return (0);
}
@@ -11394,6 +11240,12 @@
aic_inb(p, SCSISIGI),
aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
+ CTL_OF_SCB(scb),
+ (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+ aic_inb(p, SSTAT2),
+ aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
+ aic_inb(p, STCNT));
}
channel = cmd->channel;
@@ -11687,7 +11539,6 @@
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
unsigned long cpu_flags = 0;
#endif
- Scsi_Cmnd *cmd_next, *cmd_prev;
p = (struct aic7xxx_host *) cmd->host->hostdata;
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
@@ -11718,13 +11569,11 @@
{
aic7xxx_isr(p->irq, p, (void *)NULL);
pause_sequencer(p);
- aic7xxx_done_cmds_complete(p);
}
+ aic7xxx_done_cmds_complete(p);
- if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
- /* Totally bogus cmd since it points beyond our */
- { /* valid SCB range or doesn't even match it's own*/
- /* timeout serial number. */
+ if (scb == NULL)
+ {
if (aic7xxx_verbose & VERBOSE_ABORT_MID)
printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
"pointer.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11743,28 +11592,6 @@
/* finish successfully, or to indicate that we */
/* don't have this cmd any more and the mid level */
/* code needs to find it. */
- cmd_next = p->completeq.head;
- cmd_prev = NULL;
- while (cmd_next != NULL)
- {
- if (cmd_next == cmd)
- {
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "Abort called for command "
- "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
- if ( cmd_prev == NULL )
- p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
- else
- cmd_prev->host_scribble = cmd_next->host_scribble;
- cmd_next->scsi_done(cmd_next);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
- * completion */
- }
- cmd_prev = cmd_next;
- cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
- }
if (aic7xxx_verbose & VERBOSE_ABORT_MID)
printk(INFO_LEAD "Abort called for already completed"
" command.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11822,8 +11649,20 @@
found = 0;
p->flags |= AHC_IN_ABORT;
if (aic7xxx_verbose & VERBOSE_ABORT)
- printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
- p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ {
+ printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
+ "0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, LASTPHASE));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
+ aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
+ aic_inb(p, SCSISIGI));
+ printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
+ aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+ }
/*
* First, let's check to see if the currently running command is our target
@@ -11851,6 +11690,16 @@
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB is currently active. "
"Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+ "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+ aic_inb(p, SCSISIGI),
+ aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+ aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+ printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+ p->host_no, CTL_OF_SCB(scb),
+ (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+ aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+ aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
unpause_sequencer(p, FALSE);
p->flags &= ~AHC_IN_ABORT;
scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */
@@ -11866,35 +11715,7 @@
if ((found == 0) && (scb->flags & SCB_WAITINGQ))
{
int tindex = TARGET_INDEX(cmd);
- unsigned short mask;
-
- mask = (1 << tindex);
- if (p->dtr_pending & mask)
- {
- if (p->dev_dtr_cmnd[tindex]->next != cmd)
- found = 1;
- else
- found = 0;
- }
- else
- {
- found = 1;
- }
- if (found == 0)
- {
- /*
- * OK..this means the command we are currently getting an abort
- * for has an outstanding negotiation command in front of it.
- * We don't really have a way to tie back into the negotiation
- * commands, so we just send this back as pending, then it
- * will get reset in 2 seconds.
- */
- unpause_sequencer(p, TRUE);
- scb->flags |= SCB_ABORT;
- DRIVER_UNLOCK
- return(SCSI_ABORT_PENDING);
- }
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB found on waiting list and "
"aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -12051,10 +11872,8 @@
#define DEVICE_RESET 0x01
#define BUS_RESET 0x02
#define HOST_RESET 0x04
-#define FAIL 0x08
-#define RESET_DELAY 0x10
+#define RESET_DELAY 0x08
int action;
- Scsi_Cmnd *cmd_prev, *cmd_next;
if ( cmd == NULL )
@@ -12082,86 +11901,32 @@
DRIVER_LOCK
pause_sequencer(p);
- while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
- {
- aic7xxx_isr(p->irq, p, (void *)NULL );
- pause_sequencer(p);
- aic7xxx_done_cmds_complete(p);
- }
- if (scb == NULL)
+ if(flags & SCSI_RESET_SYNCHRONOUS)
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
- "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
- if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
- {
- action = HOST_RESET;
- }
- else
- {
- action = BUS_RESET;
- }
+ printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
+ "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
+ cmd->result);
+ scb = NULL;
+ action = HOST_RESET;
}
- else if (scb->cmd != cmd)
+ else if ((scb == NULL) || (scb->cmd != cmd))
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called with recycled SCB "
- "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
- cmd_prev = NULL;
- cmd_next = p->completeq.head;
- while ( cmd_next != NULL )
- {
- if (cmd_next == cmd)
- {
- if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "Reset, found cmd on completeq"
- ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_NOT_RUNNING);
- }
- cmd_prev = cmd_next;
- cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
- }
- if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
- {
- if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "Reset, cmd not found,"
- " failing.\n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_NOT_RUNNING);
- }
- else
- {
- if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called, no scb, "
- "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
- scb = NULL;
- action = HOST_RESET;
- }
+ printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+ "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
+ aic7xxx_done_cmds_complete(p);
+ aic7xxx_run_waiting_queues(p);
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_NOT_RUNNING);
}
else
{
if (aic7xxx_verbose & VERBOSE_RESET_MID)
printk(INFO_LEAD "Reset called, scb %d, flags "
"0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
- if ( aic7xxx_scb_on_qoutfifo(p, scb) )
- {
- if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
- CTL_OF_SCB(scb));
- if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
- printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
- CTL_OF_SCB(scb));
- aic7xxx_handle_command_completion_intr(p);
- aic7xxx_done_cmds_complete(p);
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_SUCCESS);
- }
if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
{
action = HOST_RESET;
@@ -12175,6 +11940,26 @@
action = DEVICE_RESET;
}
}
+
+ while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+ {
+ aic7xxx_isr(p->irq, p, (void *)NULL );
+ pause_sequencer(p);
+ }
+ aic7xxx_done_cmds_complete(p);
+
+ if(scb && (scb->cmd == NULL))
+ {
+ /*
+ * We just completed the command when we ran the isr stuff, so we no
+ * longer have it.
+ */
+ aic7xxx_run_waiting_queues(p);
+ unpause_sequencer(p, FALSE);
+ DRIVER_UNLOCK
+ return(SCSI_RESET_SUCCESS);
+ }
+
if ( (action & DEVICE_RESET) &&
(p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
{
@@ -12234,14 +12019,13 @@
switch (action)
{
case RESET_DELAY:
+ aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
- return(SCSI_RESET_PENDING);
- break;
- case FAIL:
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_ERROR);
+ if(scb == NULL)
+ return(SCSI_RESET_PUNT);
+ else
+ return(SCSI_RESET_PENDING);
break;
case DEVICE_RESET:
p->flags |= AHC_IN_RESET;
@@ -12259,7 +12043,7 @@
case HOST_RESET:
default:
p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
- p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+ p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
p->dev_timer_active |= (0x01 << p->scsi_id);
if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
@@ -12288,21 +12072,14 @@
p->msg_index = 0;
p->msg_len = 0;
}
- aic7xxx_run_done_queue(p, TRUE);
- /*
- * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
- * in need of being re-started, so send it on through to aic7xxx_queue
- * and let it set until the delay is over. This keeps it from dying
- * entirely and avoids getting a bogus dead command back through the
- * mid-level code due to too many retries.
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
- if ( flags & SCSI_RESET_SYNCHRONOUS )
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+ if(flags & SCSI_RESET_SYNCHRONOUS)
{
- cmd->result = DID_BUS_BUSY << 16;
+ cmd->result = DID_RESET << 16;
cmd->done(cmd);
}
#endif
+ aic7xxx_run_done_queue(p, TRUE);
p->flags &= ~AHC_IN_RESET;
/*
* We can't rely on run_waiting_queues to unpause the sequencer for
@@ -12313,7 +12090,10 @@
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
- return(result);
+ if(scb == NULL)
+ return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
+ else
+ return(result);
break;
}
}
@@ -12623,7 +12403,7 @@
}
-#include "aic7xxx_proc.c"
+#include "aic7xxx/aic7xxx_proc.c"
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)