patch-2.2.10 linux/drivers/scsi/aic7xxx.c
Next file: linux/drivers/scsi/aic7xxx_proc.c
Previous file: linux/drivers/scsi/aic7xxx/scsi_message.h
Back to the patch index
Back to the overall index
- Lines: 3281
- Date:
Wed Jun 9 16:59:34 1999
- Orig file:
v2.2.9/linux/drivers/scsi/aic7xxx.c
- Orig date:
Tue Jan 19 11:32:51 1999
diff -u --recursive --new-file v2.2.9/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -171,91 +171,6 @@
*/
/*
- * AIC7XXX_FAKE_NEGOTIATION_CMDS
- * We now have two distinctly different methods of device negotiation
- * in this code. The two methods are selected by either defining or not
- * defining this option. The difference is as follows:
- *
- * With AIC7XXX_FAKE_NEGOTIATION_CMDS not set (commented out)
- * When the driver is in need of issuing a negotiation command for any
- * given device, it will add the negotiation message on to part of a
- * regular SCSI command for the device. In the process, if the device
- * is configured for and using tagged queueing, then the code will
- * also issue that single command as a non-tagged command, attach the
- * negotiation message to that one command, and use a temporary
- * queue depth of one to keep the untagged and tagged commands from
- * overlapping.
- * Pros: This doesn't use any extra SCB structures, it's simple, it
- * works most of the time (if not all of the time now), and
- * since we get the device capability info frmo the INQUIRY data
- * now, shouldn't cause any problems.
- * Cons: When we need to send a negotiation command to a device, we
- * must use a command that is being sent to LUN 0 of the device.
- * If we try sending one to high LUN numbers, then some devices
- * get noticeably upset. Since we have to wait for a command with
- * LUN == 0 to come along, we may not be able to renegotiate when
- * we want if the user is actually using say LUN 1 of a CD Changer
- * instead of using LUN 0 for an extended period of time.
- *
- * With AIC7XXX_FAKE_NEGOTIATION_CMDS defined
- * When we need to negotiate with a device, instead of attaching our
- * negotiation message to an existing command, we insert our own
- * fictional Scsi_Cmnd into the chain that has the negotiation message
- * attached to it. We send this one command as untagged regardless
- * of the device type, and we fiddle with the queue depth the same as
- * we would with the option unset to avoid overlapping commands. The
- * primary difference between this and the unset option is that the
- * negotiation message is no longer attached to a specific command,
- * instead it is its own command and is merely triggered by a
- * combination of both A) We need to negotiate and B) The mid level
- * SCSI code has sent us a command. We still don't do any negotiation
- * unless there is a valid SCSI command to be processed.
- * Pros: This fixes the problem above in the Cons section. Since we
- * issue our own fake command, we can set the LUN to 0 regardless
- * of what the LUN is in the real command. It also means that if
- * the device get's nasty over negotiation issues, it won't be
- * showing up on a regular command, so we won't get any SENSE buffer
- * data or STATUS_BYTE returns to the mid level code that are caused
- * by snits in the negotiation code.
- * Cons: We add more code, and more complexity. This means more ways
- * in which things could break. It means a larger driver. It means
- * more resource consumption for the fake commands. However, the
- * biggest problem is this. Take a system where there is a CD-ROM
- * on the SCSI bus. Someone has a CD in the CD-ROM and is using it.
- * For some reason the SCSI bus gets reset. We don't touch the
- * CD-ROM again for quite a period of time (so we don't renegotiate
- * after the reset until we do touch the CD-ROM again). In the
- * time while we aren't using the CD-ROM, the current disc is
- * removed and a new one put in. When we go to check that disc, we
- * will first have to renegotiate. In so doing, we issue our fake
- * SCSI command, which happens to be TEST_UNIT_READY. The CD-ROM
- * negotiates with us, then responds to our fake command with a
- * CHECK_CONDITION status. We REQUEST_SENSE from the CD-ROM, it
- * then sends the SENSE data to our fake command to tell it that
- * it has been through a disc change. There, now we've cleared out
- * the SENSE data along with our negotiation command, and when the
- * real command executes, it won't pick up that the CD was changed.
- * That's the biggest Con to this approach. In the future, I could
- * probably code around this problem though, so this option is still
- * viable.
- *
- * So, which command style should you use? I would appreciate it if people
- * could try out both types. I want to know about any cases where one
- * method works and the other doesn't. If one method works on significantly
- * more systems than another, then it will become the default. If the second
- * option turns out to work best, then I'll find a way to work around that
- * big con I listed.
- *
- * -- July 7, 02:33
- * OK...I just added some code that should make the Con listed for the
- * fake commands a non issue now. However, it needs testing. For now,
- * I'm going to make the default to use the fake commands, we'll see how
- * it goes.
- */
-
-#define AIC7XXX_FAKE_NEGOTIATION_CMDS
-
-/*
* AIC7XXX_STRICT_PCI_SETUP
* Should we assume the PCI config options on our controllers are set with
* sane and proper values, or should we be anal about our PCI config
@@ -336,6 +251,7 @@
#include "aic7xxx/sequencer.h"
#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
+#include <scsi/scsicam.h>
#include <linux/stat.h>
#include <linux/malloc.h> /* for kmalloc() */
@@ -354,7 +270,7 @@
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.1.10"
+#define AIC7XXX_C_VERSION "5.1.17"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -447,10 +363,10 @@
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
*/
-#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
-#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
#else
-#define AIC7XXX_CMDS_PER_LUN 24
+#define AIC7XXX_CMDS_PER_DEVICE 8
#endif
/* Set this to the delay in seconds after SCSI bus reset. */
@@ -495,7 +411,7 @@
*
* *** Determining commands per LUN ***
*
- * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
* own algorithm to determine the commands/LUN. If SCB paging is
* enabled, which is always now, the default is 8 commands per lun
* that indicates it supports tagged queueing. All non-tagged devices
@@ -513,8 +429,13 @@
* Make a define that will tell the driver not to use tagged queueing
* by default.
*/
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+ 0, 0, 0, 0, 0, 0, 0, 0}
+#else
#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
255, 255, 255, 255, 255, 255, 255, 255}
+#endif
/*
* Modify this as you see fit for your system. By setting tag_commands
@@ -553,6 +474,27 @@
};
*/
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS}
+};
+
+
/*
* Define an array of board names that can be indexed by aha_type.
* Don't forget to change this when changing the types!
@@ -579,11 +521,14 @@
"Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */
"Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */
"Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */
+ "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */
"Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */
"Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */
"Adaptec PCMCIA SCSI controller", /* card bus stuff */
+ "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */
+ "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */
};
/*
@@ -851,15 +796,17 @@
SCB_DEVICE_RESET = 0x0020,
SCB_RESET = 0x0040,
SCB_RECOVERY_SCB = 0x0080,
- SCB_WAS_BUSY = 0x0100,
+ SCB_MSGOUT_PPR = 0x0100,
SCB_MSGOUT_SENT = 0x0200,
SCB_MSGOUT_SDTR = 0x0400,
SCB_MSGOUT_WDTR = 0x0800,
- SCB_MSGOUT_BITS = SCB_MSGOUT_SENT |
+ SCB_MSGOUT_BITS = SCB_MSGOUT_PPR |
+ SCB_MSGOUT_SENT |
SCB_MSGOUT_SDTR |
SCB_MSGOUT_WDTR,
SCB_QUEUED_ABORT = 0x1000,
- SCB_QUEUED_FOR_DONE = 0x2000
+ SCB_QUEUED_FOR_DONE = 0x2000,
+ SCB_WAS_BUSY = 0x4000
} scb_flag_type;
typedef enum {
@@ -913,6 +860,8 @@
AHC_AIC7890 = 0x0006,
AHC_AIC7895 = 0x0007,
AHC_AIC7896 = 0x0008,
+ AHC_AIC7892 = 0x0009,
+ AHC_AIC7899 = 0x000a,
AHC_VL = 0x0100,
AHC_EISA = 0x0200,
AHC_PCI = 0x0400,
@@ -929,6 +878,7 @@
AHC_QUEUE_REGS = 0x0040,
AHC_SG_PRELOAD = 0x0080,
AHC_SPIOCAP = 0x0100,
+ AHC_ULTRA3 = 0x0200,
AHC_AIC7770_FE = AHC_FENONE,
AHC_AIC7850_FE = AHC_SPIOCAP,
AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP,
@@ -938,6 +888,8 @@
AHC_QUEUE_REGS|AHC_SG_PRELOAD,
AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
AHC_AIC7896_FE = AHC_AIC7890_FE,
+ AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3,
+ AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3,
} ahc_feature;
struct aic7xxx_scb {
@@ -1014,9 +966,12 @@
unsigned char goal_period;
unsigned char cur_offset;
unsigned char goal_offset;
+ unsigned char cur_options;
+ unsigned char goal_options;
unsigned char user_width;
unsigned char user_period;
unsigned char user_offset;
+ unsigned char user_options;
} transinfo_type;
/*
@@ -1045,10 +1000,11 @@
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 sdtr_pending;
volatile unsigned short needwdtr;
- volatile unsigned short wdtr_pending;
+ volatile unsigned short dtr_pending;
struct aic7xxx_cmd_queue {
Scsi_Cmnd *head;
Scsi_Cmnd *tail;
@@ -1071,9 +1027,10 @@
#define DEVICE_PRESENT 0x01
#define BUS_DEVICE_RESET_PENDING 0x02
#define DEVICE_RESET_DELAY 0x04
-#define DEVICE_PRINT_SDTR 0x08
-#define DEVICE_PRINT_WDTR 0x10
+#define DEVICE_PRINT_DTR 0x08
+#define DEVICE_PARITY_ERROR 0x10
#define DEVICE_WAS_BUSY 0x20
+#define DEVICE_SCSI_3 0x40
#define DEVICE_SCANNED 0x80
volatile unsigned char dev_flags[MAX_TARGETS];
volatile unsigned char dev_active_cmds[MAX_TARGETS];
@@ -1090,11 +1047,10 @@
#endif
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
- Scsi_Cmnd *dev_wdtr_cmnd[MAX_TARGETS];
- Scsi_Cmnd *dev_sdtr_cmnd[MAX_TARGETS];
-#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];
@@ -1102,7 +1058,7 @@
volatile scb_queue_type delayed_scbs[MAX_TARGETS];
- unsigned char msg_buf[9]; /* The message for the target */
+ unsigned char msg_buf[13]; /* The message for the target */
unsigned char msg_type;
#define MSG_TYPE_NONE 0x00
#define MSG_TYPE_INITIATOR_MSGOUT 0x01
@@ -1132,6 +1088,7 @@
int scsi_id_b; /* channel B for twin adapters */
unsigned int bios_address;
int board_name_index;
+ unsigned short needppr_copy; /* default config */
unsigned short needsdtr_copy; /* default config */
unsigned short needwdtr_copy; /* default config */
unsigned short ultraenb; /* Ultra mode target list */
@@ -1192,9 +1149,12 @@
* Provides a mapping of transfer periods in ns/4 to the proper value to
* stick in the SCSIRATE reg to use that transfer rate.
*/
-#define AHC_SYNCRATE_ULTRA2 0
-#define AHC_SYNCRATE_ULTRA 2
-#define AHC_SYNCRATE_FAST 5
+#define AHC_SYNCRATE_ULTRA3 0
+#define AHC_SYNCRATE_ULTRA2 1
+#define AHC_SYNCRATE_ULTRA 3
+#define AHC_SYNCRATE_FAST 6
+#define AHC_SYNCRATE_CRC 0x40
+#define AHC_SYNCRATE_SE 0x10
static struct aic7xxx_syncrate {
/* Rates in Ultra mode have bit 8 of sxfr set */
#define ULTRA_SXFR 0x100
@@ -1203,6 +1163,7 @@
unsigned char period;
const char *rate[2];
} aic7xxx_syncrates[] = {
+ { 0x42, 0x000, 9, {"80.0", "160.0"} },
{ 0x13, 0x000, 10, {"40.0", "80.0"} },
{ 0x14, 0x000, 11, {"33.0", "66.6"} },
{ 0x15, 0x100, 12, {"20.0", "40.0"} },
@@ -1410,35 +1371,6 @@
#endif
-/*
- * See the comments earlier in the file for what this item is all about
- * If you have more than 4 controllers, you will need to increase the
- * the number of items in the array below. Additionally, if you don't
- * want to have lilo pass a humongous config line to the aic7xxx driver,
- * then you can get in and manually adjust these instead of leaving them
- * at the default. Pay attention to the comments earlier in this file
- * concerning this array if you are going to hand modify these values.
- */
-static adapter_tag_info_t aic7xxx_tag_info[] =
-{
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS}
-};
-
#define VERBOSE_NORMAL 0x0000
#define VERBOSE_NEGOTIATION 0x0001
#define VERBOSE_SEQINT 0x0002
@@ -1920,6 +1852,7 @@
aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+ udelay(15);
break;
default:
@@ -2084,28 +2017,101 @@
*-F*************************************************************************/
static struct aic7xxx_syncrate *
aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
- unsigned int maxsync)
+ unsigned int maxsync, unsigned char *options)
{
struct aic7xxx_syncrate *syncrate;
+ int done = FALSE;
+ switch(*options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_CRC:
+ case MSG_EXT_PPR_OPTION_DT_UNITS:
+ if(!(p->features & AHC_ULTRA3))
+ {
+ *options = 0;
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ }
+ break;
+ case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+ case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+ if(!(p->features & AHC_ULTRA3))
+ {
+ *options = 0;
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ }
+ else
+ {
+ /*
+ * we don't support the Quick Arbitration variants of dual edge
+ * clocking. As it turns out, we want to send back the
+ * same basic option, but without the QA attribute.
+ * We know that we are responding because we would never set
+ * these options ourself, we would only respond to them.
+ */
+ switch(*options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+ *options = MSG_EXT_PPR_OPTION_DT_CRC;
+ break;
+ case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+ *options = MSG_EXT_PPR_OPTION_DT_UNITS;
+ break;
+ }
+ }
+ break;
+ default:
+ *options = 0;
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ break;
+ }
syncrate = &aic7xxx_syncrates[maxsync];
while ( (syncrate->rate[0] != NULL) &&
(!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
{
- if ( *period <= syncrate->period )
+ if (*period <= syncrate->period)
{
- /*
- * When responding to a target that requests sync, the requested rate
- * may fall between two rates that we can output, but still be a rate
- * that we can receive. Because of this, we want to respond with the
- * same rate that it sent to us even if the persiod we use to send
- * data to it is lower. Only lower the response period if we must.
- */
- if(syncrate == &aic7xxx_syncrates[maxsync])
+ switch(*options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_CRC:
+ case MSG_EXT_PPR_OPTION_DT_UNITS:
+ if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+ {
+ done = TRUE;
+ /*
+ * oops, we went too low for the CRC/DualEdge signalling, so
+ * clear the options byte
+ */
+ *options = 0;
+ /*
+ * We'll be sending a reply to this packet to set the options
+ * properly, so unilaterally set the period as well.
+ */
+ *period = syncrate->period;
+ }
+ else
+ {
+ done = TRUE;
+ if(syncrate == &aic7xxx_syncrates[maxsync])
+ {
+ *period = syncrate->period;
+ }
+ }
+ break;
+ default:
+ if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+ {
+ done = TRUE;
+ if(syncrate == &aic7xxx_syncrates[maxsync])
+ {
+ *period = syncrate->period;
+ }
+ }
+ break;
+ }
+ if(done)
{
- *period = syncrate->period;
+ break;
}
- break;
}
syncrate++;
}
@@ -2115,6 +2121,7 @@
/*
* Use async transfers for this target
*/
+ *options = 0;
*period = 0;
syncrate = NULL;
}
@@ -2135,7 +2142,7 @@
{
struct aic7xxx_syncrate *syncrate;
- if ((p->features & AHC_ULTRA2) != 0)
+ if (p->features & AHC_ULTRA2)
{
scsirate &= SXFR_ULTRA2;
}
@@ -2147,12 +2154,14 @@
syncrate = &aic7xxx_syncrates[maxsync];
while (syncrate->rate[0] != NULL)
{
- if ((p->features & AHC_ULTRA2) != 0)
+ if (p->features & AHC_ULTRA2)
{
if (syncrate->sxfr_ultra2 == 0)
break;
else if (scsirate == syncrate->sxfr_ultra2)
return (syncrate->period);
+ else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC))
+ return (syncrate->period);
}
else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
{
@@ -2206,11 +2215,11 @@
static void
aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
int target, int channel, unsigned int period, unsigned int offset,
- unsigned int type)
+ unsigned char options, unsigned int type)
{
unsigned char tindex;
unsigned short target_mask;
- unsigned char lun;
+ unsigned char lun, old_options;
unsigned int old_period, old_offset;
tindex = target | (channel << 3);
@@ -2225,6 +2234,7 @@
old_period = p->transinfo[tindex].cur_period;
old_offset = p->transinfo[tindex].cur_offset;
+ old_options = p->transinfo[tindex].cur_options;
if (type & AHC_TRANS_CUR)
@@ -2237,7 +2247,18 @@
scsirate &= ~SXFR_ULTRA2;
if (syncrate != NULL)
{
- scsirate |= syncrate->sxfr_ultra2;
+ switch(options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_UNITS:
+ /*
+ * mask off the CRC bit in the xfer settings
+ */
+ scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC);
+ break;
+ default:
+ scsirate |= syncrate->sxfr_ultra2;
+ break;
+ }
}
if (type & AHC_TRANS_ACTIVE)
{
@@ -2278,9 +2299,10 @@
aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
p->transinfo[tindex].cur_period = period;
p->transinfo[tindex].cur_offset = offset;
+ p->transinfo[tindex].cur_options = options;
if ( !(type & AHC_TRANS_QUITE) &&
(aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
if (offset)
{
@@ -2295,7 +2317,7 @@
printk(INFO_LEAD "Using asynchronous transfers.\n",
p->host_no, channel, target, lun);
}
- p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
}
}
@@ -2303,12 +2325,14 @@
{
p->transinfo[tindex].goal_period = period;
p->transinfo[tindex].goal_offset = offset;
+ p->transinfo[tindex].goal_options = options;
}
if (type & AHC_TRANS_USER)
{
p->transinfo[tindex].user_period = period;
p->transinfo[tindex].user_offset = offset;
+ p->transinfo[tindex].user_options = options;
}
}
@@ -2325,20 +2349,13 @@
{
unsigned char tindex;
unsigned short target_mask;
- unsigned int old_width, new_offset;
+ unsigned int old_width;
tindex = target | (channel << 3);
target_mask = 1 << tindex;
old_width = p->transinfo[tindex].cur_width;
- if (p->features & AHC_ULTRA2)
- new_offset = MAX_OFFSET_ULTRA2;
- else if (width == MSG_EXT_WDTR_BUS_16_BIT)
- new_offset = MAX_OFFSET_16BIT;
- else
- new_offset = MAX_OFFSET_8BIT;
-
if (type & AHC_TRANS_CUR)
{
unsigned char scsirate;
@@ -2356,12 +2373,12 @@
p->transinfo[tindex].cur_width = width;
- if ((aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_WDTR))
+ if ( !(type & AHC_TRANS_QUITE) &&
+ (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
- p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
}
}
@@ -2370,14 +2387,21 @@
if (type & AHC_TRANS_USER)
p->transinfo[tindex].user_width = width;
- /*
- * Having just set the width, the SDTR should come next, and we need a valid
- * offset for the SDTR. So, we make sure we put a valid one in here now as
- * the goal_offset.
- */
if (p->transinfo[tindex].goal_offset)
- p->transinfo[tindex].goal_offset = new_offset;
-
+ {
+ if (p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else if (width == MSG_EXT_WDTR_BUS_16_BIT)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
+ }
}
/*+F*************************************************************************
@@ -2543,14 +2567,6 @@
if (match != 0)
match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
- if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
- {
- printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
- " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
- scb->hscb->tag, (match) ? "matches" : "doesn't match",
- p->host_no, channel, target, lun, tag);
- }
-
return (match);
}
@@ -2584,14 +2600,13 @@
* to the free list.
*-F*************************************************************************/
static unsigned char
-aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr,
+ unsigned char prev)
{
unsigned char next;
- unsigned char prev;
aic_outb(p, scbptr, SCBPTR);
next = aic_inb(p, SCB_NEXT);
- prev = aic_inb(p, SCB_PREV);
aic7xxx_add_curscb_to_free_list(p);
if (prev != SCB_LIST_NULL)
@@ -2604,11 +2619,6 @@
aic_outb(p, next, DISCONNECTED_SCBH);
}
- if (next != SCB_LIST_NULL)
- {
- aic_outb(p, next, SCBPTR);
- aic_outb(p, prev, SCB_PREV);
- }
return next;
}
@@ -2755,7 +2765,7 @@
* Place in the scb array; never is removed
*/
p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
- scbq_insert_head(&p->scb_data->free_scbs, scbp);
+ scbq_insert_tail(&p->scb_data->free_scbs, scbp);
}
scbp->kmalloc_ptr = scb_ap;
}
@@ -2796,6 +2806,7 @@
Scsi_Cmnd *cmd;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
unsigned int cpu_flags = 0;
+#endif
DRIVER_LOCK
while (p->completeq.head != NULL)
@@ -2803,20 +2814,9 @@
cmd = p->completeq.head;
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
cmd->host_scribble = NULL;
- sti();
cmd->scsi_done(cmd);
- cli();
}
DRIVER_UNLOCK
-#else
- while (p->completeq.head != NULL)
- {
- cmd = p->completeq.head;
- p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
- cmd->host_scribble = NULL;
- cmd->scsi_done(cmd);
- }
-#endif
}
/*+F*************************************************************************
@@ -2889,16 +2889,13 @@
}
#define WIDE_INQUIRY_BITS 0x60
#define SYNC_INQUIRY_BITS 0x10
+#define SCSI_VERSION_BITS 0x07
if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
(p->features & AHC_WIDE) )
{
p->needwdtr |= (1<<tindex);
p->needwdtr_copy |= (1<<tindex);
- if ( (p->flags & AHC_SEEPROM_FOUND) &&
- (p->transinfo[tindex].user_width != MSG_EXT_WDTR_BUS_16_BIT) )
- p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
- else
- p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+ p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
}
else
{
@@ -2916,28 +2913,10 @@
p->needsdtr |= (1<<tindex);
p->needsdtr_copy |= (1<<tindex);
- if (p->flags & AHC_SEEPROM_FOUND)
+ p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+ if (p->transinfo[tindex].user_offset)
{
- p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_offset = p->transinfo[tindex].user_offset;
- }
- else
- {
- if (p->features & AHC_ULTRA2)
- {
- p->transinfo[tindex].goal_period =
- aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
- }
- else if (p->features & AHC_ULTRA)
- {
- p->transinfo[tindex].goal_period =
- aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
- }
- else
- {
- p->transinfo[tindex].goal_period =
- aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
- }
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)
@@ -2952,14 +2931,57 @@
p->needsdtr_copy &= ~(1<<tindex);
p->transinfo[tindex].goal_period = 0;
p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+ {
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ /*
+ * OK, we are a SCSI 3 device and we are in need of negotiation.
+ * Use PPR messages instead of WDTR and SDTR messages.
+ */
+ if ( (p->needsdtr & (1<<tindex)) ||
+ (p->needwdtr & (1<<tindex)) )
+ {
+ p->needppr |= (1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ }
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_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++)
+ {
+ checksum += ibuffer[i];
+ }
+ p->dev_checksum[tindex] = checksum;
+ p->dev_flags[tindex] |= DEVICE_SCANNED;
+ p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
}
- p->dev_flags[tindex] |= DEVICE_SCANNED;
- p->dev_flags[tindex] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
#undef WIDE_INQUIRY_BITS
#undef SYNC_INQUIRY_BITS
+#undef SCSI_VERSION_BITS
}
}
- else if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+ else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
{
unsigned short mask;
int message_error = FALSE;
@@ -2979,11 +3001,11 @@
if (scb->flags & SCB_MSGOUT_WDTR)
{
- p->wdtr_pending &= ~mask;
+ p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
printk(INFO_LEAD "Device failed to complete Wide Negotiation "
"processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -2991,7 +3013,6 @@
"disabling future\n", p->host_no, CTL_OF_SCB(scb));
printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
CTL_OF_SCB(scb));
- p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
}
p->needwdtr &= ~mask;
p->needwdtr_copy &= ~mask;
@@ -2999,11 +3020,11 @@
}
if (scb->flags & SCB_MSGOUT_SDTR)
{
- p->sdtr_pending &= ~mask;
+ p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
printk(INFO_LEAD "Device failed to complete Sync Negotiation "
"processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -3011,12 +3032,38 @@
"disabling future\n", p->host_no, CTL_OF_SCB(scb));
printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
CTL_OF_SCB(scb));
- p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
}
p->needsdtr &= ~mask;
p->needsdtr_copy &= ~mask;
}
}
+ if (scb->flags & SCB_MSGOUT_PPR)
+ {
+ p->dtr_pending &= ~mask;
+ if(message_error)
+ {
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+ {
+ printk(INFO_LEAD "Device failed to complete Parallel Protocol "
+ "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "returned a sense error code for invalid message, "
+ "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
+ "device.\n", p->host_no, CTL_OF_SCB(scb));
+ }
+ /*
+ * Disable PPR negotiation and revert back to WDTR and SDTR setup
+ */
+ p->needppr &= ~mask;
+ p->needppr_copy &= ~mask;
+ p->needsdtr |= mask;
+ p->needsdtr_copy |= mask;
+ p->needwdtr |= mask;
+ p->needwdtr_copy |= mask;
+ }
+ }
}
queue_depth = p->dev_temp_queue_depth[tindex];
if (queue_depth >= p->dev_active_cmds[tindex])
@@ -3058,16 +3105,6 @@
p->dev_active_cmds[tindex]--;
p->activescbs--;
- /*
- * If this was an untagged I/O, unbusy the target so the sequencer won't
- * mistake things later
- */
- if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
- scb->hscb->tag)
- {
- aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
- }
-
{
int actual;
@@ -3122,7 +3159,7 @@
#endif /* AIC7XXX_PROC_STATS */
}
#ifdef AIC7XXX_PROC_STATS
- x = -10;
+ x = -11;
while(actual)
{
actual >>= 1;
@@ -3429,11 +3466,10 @@
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;
+ p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
if ( tag == SCB_LIST_NULL )
{
- p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR |
- DEVICE_RESET_DELAY;
+ p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
p->dev_expires[i] = jiffies + (4 * HZ);
p->dev_timer_active |= (0x01 << i);
p->dev_last_queue_full_count[i] = 0;
@@ -3625,7 +3661,7 @@
if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
printk(INFO_LEAD "Cleaning disconnected scbs "
"list.\n", p->host_no, channel, target, lun);
- if (p->features & AHC_PAGESCBS)
+ if (p->flags & AHC_PAGESCBS)
{
unsigned char next, prev, scb_index;
@@ -3641,14 +3677,14 @@
printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
"numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
p->scb_data->numscbs);
- next = aic7xxx_rem_scb_from_disc_list(p, next);
+ next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
}
else
{
scbp = p->scb_data->scb_array[scb_index];
if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
{
- next = aic7xxx_rem_scb_from_disc_list(p, next);
+ next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
if (scbp->flags & SCB_WAITINGQ)
{
p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
@@ -3677,7 +3713,7 @@
* Walk the free list making sure no entries on the free list have
* a valid SCB_TAG value or SCB_CONTROL byte.
*/
- if (p->features & AHC_PAGESCBS)
+ if (p->flags & AHC_PAGESCBS)
{
unsigned char next;
@@ -3734,7 +3770,6 @@
{
aic_outb(p, SCB_LIST_NULL, SCB_TAG);
aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
- aic_outb(p, SCB_LIST_NULL, SCB_PREV);
aic_outb(p, 0, SCB_CONTROL);
aic7xxx_add_curscb_to_free_list(p);
}
@@ -3863,28 +3898,35 @@
if (channel == 1)
{
p->needsdtr |= (p->needsdtr_copy & 0xFF00);
- p->sdtr_pending &= 0x00FF;
+ p->dtr_pending &= 0x00FF;
offset_min = 8;
offset_max = 16;
}
else
{
- if (p->features & AHC_WIDE)
+ if (p->features & AHC_TWIN)
{
- p->needsdtr = p->needsdtr_copy;
- p->needwdtr = p->needwdtr_copy;
- p->sdtr_pending = 0x0;
- p->wdtr_pending = 0x0;
+ /* Channel A */
+ p->needsdtr |= (p->needsdtr_copy & 0x00FF);
+ p->dtr_pending &= 0xFF00;
offset_min = 0;
- offset_max = 16;
+ offset_max = 8;
}
else
{
- /* Channel A */
- p->needsdtr |= (p->needsdtr_copy & 0x00FF);
- p->sdtr_pending &= 0xFF00;
+ p->needppr = p->needppr_copy;
+ p->needsdtr = p->needsdtr_copy;
+ p->needwdtr = p->needwdtr_copy;
+ p->dtr_pending = 0x0;
offset_min = 0;
- offset_max = 8;
+ if (p->features & AHC_WIDE)
+ {
+ offset_max = 16;
+ }
+ else
+ {
+ offset_max = 8;
+ }
}
}
@@ -4188,6 +4230,30 @@
/*+F*************************************************************************
* Function:
+ * aic7xxx_construct_ppr
+ *
+ * Description:
+ * Build up a Parallel Protocol Request message for use with SCSI-3
+ * devices.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+ int tindex = TARGET_INDEX(scb->cmd);
+
+ p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+ p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
+ p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
+ p->msg_buf[p->msg_index++] = 0;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
+ p->msg_len += 8;
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_construct_sdtr
*
* Description:
@@ -4304,10 +4370,10 @@
/*
* Go back to async/narrow transfers and renegotiate.
*/
+ p->needppr |= (p->needppr_copy & targ_mask);
p->needsdtr |= (p->needsdtr_copy & targ_mask);
p->needwdtr |= (p->needwdtr_copy & targ_mask);
- p->sdtr_pending &= ~targ_mask;
- p->wdtr_pending &= ~targ_mask;
+ p->dtr_pending &= ~targ_mask;
aic_outb(p, 0, TARG_SCSIRATE + tindex);
if (p->features & AHC_ULTRA2)
aic_outb(p, 0, TARG_OFFSET + tindex);
@@ -4315,7 +4381,7 @@
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
target, -1);
- aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
}
/*+F*************************************************************************
@@ -4360,6 +4426,8 @@
p->host_no, channel, target, lun,
aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
(aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+ if (aic7xxx_panic_on_abort)
+ aic7xxx_panic_abort(p, NULL);
}
break;
@@ -4387,7 +4455,7 @@
lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
}
break;
@@ -4517,7 +4585,7 @@
aic7xxx_reset_device(p, target, channel, lun, i);
reset++;
}
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
}
}
aic7xxx_verbose = old_verbose;
@@ -4533,6 +4601,51 @@
aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
}
}
+ else if (scb->flags & SCB_MSGOUT_PPR)
+ {
+ /*
+ * As per the draft specs, any device capable of supporting any of
+ * the option values other than 0 are not allowed to reject the
+ * PPR message. Instead, they must negotiate out what they do
+ * support instead of rejecting our offering.
+ */
+ p->needppr &= ~target_mask;
+ p->needppr_copy &= ~target_mask;
+ aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+ (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+ p->transinfo[tindex].goal_options = 0;
+ p->dtr_pending &= ~target_mask;
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Device is rejecting PPR messages, falling "
+ "back.\n", p->host_no, channel, target, lun);
+ }
+ if ( p->transinfo[tindex].goal_width )
+ {
+ p->needwdtr |= target_mask;
+ p->needwdtr_copy |= target_mask;
+ p->dtr_pending |= target_mask;
+ scb->flags |= SCB_MSGOUT_WDTR;
+ }
+ if ( p->transinfo[tindex].goal_offset )
+ {
+ p->needsdtr |= target_mask;
+ p->needsdtr_copy |= target_mask;
+ if( !(p->dtr_pending & target_mask) )
+ {
+ p->dtr_pending |= target_mask;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ }
+ }
+ if ( p->dtr_pending & target_mask )
+ {
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+ }
+ }
else if (scb->flags & SCB_MSGOUT_WDTR)
{
/*
@@ -4540,20 +4653,18 @@
*/
p->needwdtr &= ~target_mask;
p->needwdtr_copy &= ~target_mask;
- p->wdtr_pending &= ~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));
- aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
- if ( (p->needsdtr_copy & target_mask) &&
- !(p->sdtr_pending & target_mask) )
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
- p->sdtr_pending |= target_mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- aic_outb(p, HOST_MSG, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ printk(INFO_LEAD "Device is rejecting WDTR messages, using "
+ "narrow transfers.\n", p->host_no, channel, target, lun);
}
+ p->needsdtr |= (p->needsdtr_copy & target_mask);
}
else if (scb->flags & SCB_MSGOUT_SDTR)
{
@@ -4562,10 +4673,15 @@
*/
p->needsdtr &= ~target_mask;
p->needsdtr_copy &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
+ p->dtr_pending &= ~target_mask;
scb->flags &= ~SCB_MSGOUT_SDTR;
- aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
(AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Device is rejecting SDTR messages, using "
+ "async transfers.\n", p->host_no, channel, target, lun);
+ }
}
else if (aic7xxx_verbose & VERBOSE_SEQINT)
{
@@ -4681,41 +4797,24 @@
* However, if this SCB already was attempting to negotiate,
* then we assume this isn't the problem and skip this part.
*/
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
(p->dev_flags[tindex] & DEVICE_SCANNED) &&
- !(p->wdtr_pending & target_mask) &&
- !(p->sdtr_pending & target_mask) )
+ !(p->dtr_pending & target_mask) )
{
+ p->needppr |= (p->needppr_copy & target_mask);
p->needwdtr |= (p->needwdtr_copy & target_mask);
p->needsdtr |= (p->needsdtr_copy & target_mask);
}
- else if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) ||
- (scb->cmd == p->dev_sdtr_cmnd[tindex]) )
+ else if ( scb->cmd == p->dev_dtr_cmnd[tindex] )
{
/*
* This is already a negotiation command, so we must have
- * already done either WDTR or SDTR (or maybe both). So
- * we simply check sdtr_pending and needsdtr to see if we
- * should throw out SDTR on this command.
- *
- * Note: Don't check the needsdtr_copy here, instead just
- * check to see if WDTR wiped out our SDTR and set needsdtr.
- * Even if WDTR did wipe out SDTR and set needsdtr, if
- * parse_msg() then turned around and started our SDTR
- * in back to back fasion, then conclusion of that should
- * have negated any needsdtr setting. That's why we only
- * check needsdtr and sdtr_pending.
+ * already done PPR, WDTR or SDTR. Since our negotiation
+ * could have gotten rejected, we don't really know the
+ * full state of things. Don't do anything here, and allow
+ * the negotiation_complete() handler to do the right
+ * thing.
*/
- scb->flags &= ~SCB_MSGOUT_BITS;
- if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) &&
- !(p->sdtr_pending & target_mask) &&
- (p->needsdtr & target_mask) )
- {
- p->sdtr_pending |= target_mask;
- hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_SDTR;
- }
/*
* This is the important part though. We are getting sense
@@ -4736,43 +4835,13 @@
hscb->data_pointer = scb->sg_list[0].address;
}
}
-#else
- if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
- !(scb->flags & SCB_MSGOUT_BITS) &&
- (scb->cmd->lun == 0) &&
- (p->dev_flags[TARGET_INDEX(scb->cmd)] & DEVICE_SCANNED) )
- {
- if ( (p->needwdtr_copy & target_mask) &&
- !(p->wdtr_pending & target_mask) &&
- !(p->sdtr_pending & target_mask) )
- {
- p->needwdtr |= target_mask;
- p->wdtr_pending |= target_mask;
- hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_WDTR;
- }
- if ( p->needsdtr_copy & target_mask )
- {
- p->needsdtr |= target_mask;
- if ( !(p->wdtr_pending & target_mask) &&
- !(p->sdtr_pending & target_mask) )
- {
- p->sdtr_pending |= target_mask;
- hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_SDTR;
- }
- }
- }
- else
- scb->flags &= ~SCB_MSGOUT_BITS;
-#endif /* AIC7XXX_FAKE_NEGOTIATION_CMDS */
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
* an untagged request.
*/
#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
if (scb->flags & SCB_MSGOUT_BITS)
printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
@@ -4914,7 +4983,8 @@
}
}
#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
+ (aic7xxx_verbose > 0xffff) )
{
if (queue_flag)
printk(INFO_LEAD "Queue full received; queue depth %d, "
@@ -4928,8 +4998,6 @@
#endif
if (queue_flag)
{
- p->dev_temp_queue_depth[tindex] =
- p->dev_active_cmds[tindex];
if ( p->dev_last_queue_full[tindex] !=
p->dev_active_cmds[tindex] )
{
@@ -4951,10 +5019,28 @@
p->dev_active_cmds[tindex];
p->dev_last_queue_full[tindex] = 0;
p->dev_last_queue_full_count[tindex] = 0;
+ p->dev_temp_queue_depth[tindex] =
+ p->dev_active_cmds[tindex];
+ }
+ else if (p->dev_active_cmds[tindex] == 0)
+ {
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ {
+ printk(INFO_LEAD "QUEUE_FULL status received with 0 "
+ "commands active.\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "Tagged Command Queueing disabled\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ p->dev_max_queue_depth[tindex] = 1;
+ p->dev_temp_queue_depth[tindex] = 1;
+ scb->tag_action = 0;
+ scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG);
}
else
{
p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+ p->dev_temp_queue_depth[tindex] =
+ p->dev_active_cmds[tindex];
}
}
break;
@@ -4989,7 +5075,7 @@
*/
if ( !(scb->flags & SCB_DEVICE_RESET) &&
- (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG) &&
+ (msg_out == MSG_IDENTIFYFLAG) &&
(scb->hscb->control & TAG_ENB) )
{
p->msg_buf[p->msg_index++] = scb->tag_action;
@@ -5020,34 +5106,68 @@
printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
CTL_OF_SCB(scb));
}
- else if (scb->flags & SCB_MSGOUT_WDTR)
+ else if (scb->flags & SCB_MSGOUT_PPR)
{
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
+ unsigned int max_sync, period;
+ unsigned char options = p->transinfo[tindex].goal_options;
+
+ if (p->features & AHC_ULTRA2)
+ {
+ if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+ !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+ {
+ if( (p->features & AHC_ULTRA3) &&
+ (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
+ (p->transinfo[tindex].goal_width ==
+ MSG_EXT_WDTR_BUS_16_BIT) &&
+ (options != 0) )
+ {
+ max_sync = AHC_SYNCRATE_ULTRA3;
+ }
+ else
+ {
+ max_sync = AHC_SYNCRATE_ULTRA2;
+ }
+ }
+ else
+ {
+ max_sync = AHC_SYNCRATE_ULTRA;
+ }
+ }
+ else if (p->features & AHC_ULTRA)
+ {
+ max_sync = AHC_SYNCRATE_ULTRA;
+ }
+ else
+ {
+ max_sync = AHC_SYNCRATE_FAST;
+ }
+ period = p->transinfo[tindex].goal_period;
+ aic7xxx_find_syncrate(p, &period, max_sync, &options);
+ p->transinfo[tindex].goal_period = period;
+ p->transinfo[tindex].goal_options = options;
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
+ p->host_no, CTL_OF_SCB(scb), period,
+ p->transinfo[tindex].goal_offset,
+ p->transinfo[tindex].goal_width, options);
+ }
+ aic7xxx_construct_ppr(p, scb);
+ }
+ else if (scb->flags & SCB_MSGOUT_WDTR)
+ {
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
CTL_OF_SCB(scb));
-#endif
- aic7xxx_construct_wdtr(p,
- p->transinfo[TARGET_INDEX(scb->cmd)].goal_width);
+ }
+ aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
}
else if (scb->flags & SCB_MSGOUT_SDTR)
{
unsigned int max_sync, period;
- /*
- * We need to set an accurate goal_offset instead of
- * the ridiculously high one we default to. We should
- * now know if we are wide. Plus, the WDTR code will
- * set our goal_offset for us as well.
- */
- if (p->transinfo[tindex].goal_offset)
- {
- if (p->features & AHC_ULTRA2)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- else if (p->transinfo[tindex].cur_width == MSG_EXT_WDTR_BUS_16_BIT)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
- else
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
- }
+ unsigned char options = 0;
/*
* Now that the device is selected, use the bits in SBLKCTL and
* SSTAT2 to determine the max sync rate for this device.
@@ -5073,14 +5193,14 @@
max_sync = AHC_SYNCRATE_FAST;
}
period = p->transinfo[tindex].goal_period;
- aic7xxx_find_syncrate(p, &period, max_sync);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
+ aic7xxx_find_syncrate(p, &period, max_sync, &options);
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
CTL_OF_SCB(scb),
p->transinfo[tindex].goal_period,
p->transinfo[tindex].goal_offset);
-#endif
+ }
aic7xxx_construct_sdtr(p, period,
p->transinfo[tindex].goal_offset);
}
@@ -5154,15 +5274,15 @@
#if AIC7XXX_NOT_YET
case TRACEPOINT:
{
- printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
- target, lun);
+ printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
+ channel, target, lun);
}
break;
case TRACEPOINT2:
{
- printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
- target, lun);
+ printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+ channel, target, lun);
}
break;
@@ -5237,7 +5357,7 @@
case MSG_EXT_SDTR:
{
unsigned int period, offset;
- unsigned char maxsync, saved_offset;
+ unsigned char maxsync, saved_offset, options;
struct aic7xxx_syncrate *syncrate;
if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
@@ -5253,7 +5373,13 @@
period = p->msg_buf[3];
saved_offset = offset = p->msg_buf[4];
+ options = 0;
+ /*
+ * 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) &&
@@ -5283,7 +5409,9 @@
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
{
- if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+ if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
+ !(p->needsdtr_copy & target_mask) &&
+ (p->transinfo[tindex].user_offset) )
{
/*
* Not only is the device starting this up, but it also hasn't
@@ -5295,38 +5423,49 @@
*/
p->transinfo[tindex].goal_period =
p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
+ if(p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else if (p->transinfo[tindex].cur_width)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
p->needsdtr_copy |= target_mask;
}
+ 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;
}
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+ 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, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
/*
- * Did we drop to async? If so, are we sending a reply? If we are,
+ * 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.
*/
- if ( (offset == 0) || (offset != saved_offset) ||
+ if ( (offset != saved_offset) ||
((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
{
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
- if ( offset == 0 )
- {
- p->needsdtr_copy &= ~target_mask;
- }
+ aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
+ options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
}
/*
@@ -5334,15 +5473,13 @@
* go async, then send an SDTR back to the target
*/
p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ==
- (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) &&
- (offset == saved_offset) )
- {
- scb->flags &= ~SCB_MSGOUT_BITS;
- }
- else
+ p->dtr_pending &= ~target_mask;
+ if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+ (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
+ (offset != saved_offset) )
{
+ reply = TRUE;
+ p->dtr_pending |= target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_SDTR;
aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5376,12 +5513,11 @@
{
reject = TRUE;
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- ((p->dev_flags[tindex] & DEVICE_PRINT_WDTR) ||
+ ((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));
- p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
}
} /* We fall through on purpose */
case MSG_EXT_WDTR_BUS_8_BIT:
@@ -5395,15 +5531,11 @@
break;
}
}
- scb->flags &= ~SCB_MSGOUT_BITS;
- p->wdtr_pending &= ~target_mask;
+ p->dtr_pending &= ~target_mask;
p->needwdtr &= ~target_mask;
}
else
{
- scb->flags &= ~SCB_MSGOUT_BITS;
- scb->flags |= SCB_MSGOUT_WDTR;
- reply = TRUE;
if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
{
/*
@@ -5413,13 +5545,33 @@
*/
p->transinfo[tindex].goal_period =
p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
+ if(p->transinfo[tindex].user_offset)
+ {
+ 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 )
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
+ }
p->transinfo[tindex].goal_width =
p->transinfo[tindex].user_width;
p->needwdtr_copy |= target_mask;
p->needsdtr_copy |= target_mask;
}
+ 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:
@@ -5441,8 +5593,11 @@
break;
}
}
+ reply = TRUE;
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ scb->flags |= SCB_MSGOUT_WDTR;
p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
+ p->dtr_pending |= target_mask;
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
}
@@ -5456,24 +5611,211 @@
* supports SDTR at all. Therefore, we check needsdtr_copy instead
* of needstr.
*/
- aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
- if ( (p->needsdtr_copy & target_mask) &&
- !(p->sdtr_pending & target_mask))
+ p->needsdtr |= (p->needsdtr_copy & target_mask);
+ done = TRUE;
+ break;
+ }
+ 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)
+ {
+ reject = TRUE;
+ break;
+ }
+
+ /*
+ * If we aren't on one of the new Ultra3 cards, then reject any PPR
+ * message since we can't support any option field other than 0
+ */
+ if( !(p->features & AHC_ULTRA3) )
+ {
+ reject = TRUE;
+ break;
+ }
+
+ if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
+ {
+ break;
+ }
+
+ period = p->msg_buf[3];
+ offset = saved_offset = p->msg_buf[5];
+ bus_width = p->msg_buf[6];
+ trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
+ p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
+ trans_options);
+ }
+
+ if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+ !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
{
- p->needsdtr |= target_mask;
- if ( !reject && !reply )
+ if(p->features & AHC_ULTRA3)
+ {
+ maxsync = AHC_SYNCRATE_ULTRA3;
+ }
+ else
{
- scb->flags &= ~SCB_MSGOUT_WDTR;
- if (p->transinfo[tindex].goal_period)
+ 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
+ * have a device ask for a higher speed then we want to give it
+ * in that case
+ */
+ 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;
+ if (!(p->dev_flags[tindex] & DEVICE_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.
+ */
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ if(p->transinfo[tindex].user_offset)
{
- p->sdtr_pending |= target_mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- aic_outb(p, HOST_MSG, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ 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 )
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ 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;
+ p->needppr_copy |= target_mask;
+ }
+ 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)
+ {
+ 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:
+ {
+ 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;
+ }
+ }
+ }
+ else
+ {
+ switch(bus_width)
+ {
+ default:
+ {
+ reply = 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;
}
}
}
+
+ 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);
+
+ if( (offset != saved_offset) ||
+ (trans_options != new_trans_options) ||
+ ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+ (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) )
+ {
+ aic7xxx_set_width(p, target, channel, lun, bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+ offset, new_trans_options,
+ AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ 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);
+ }
done = TRUE;
break;
}
@@ -5485,7 +5827,7 @@
} /* end of switch(p->msg_type) */
} /* end of if (!reject && (p->msg_len > 2)) */
- if (reject)
+ if (!reply && reject)
{
aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
@@ -5657,12 +5999,14 @@
if (aic7xxx_verbose & VERBOSE_RESET)
printk(WARN_LEAD "Someone else reset the channel!!\n",
p->host_no, channel, -1, -1);
+ if (aic7xxx_panic_on_abort)
+ aic7xxx_panic_abort(p, NULL);
/*
* Go through and abort all commands for the channel, but do not
* reset the channel again.
*/
aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
scb = NULL;
}
else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
@@ -5698,7 +6042,7 @@
CTL_OF_SCB(scb), scb->hscb->tag);
aic7xxx_reset_device(p, target, channel, ALL_LUNS,
(message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
scb = NULL;
printerror = 0;
}
@@ -5709,6 +6053,22 @@
printerror = 0;
}
}
+ if ( (scb != NULL) &&
+ (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+ {
+ /*
+ * 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.
+ */
+ printerror = 0;
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+ aic7xxx_run_done_queue(p, TRUE);
+ scb = NULL;
+ }
if (printerror != 0)
{
if (scb != NULL)
@@ -5724,7 +6084,12 @@
tag = SCB_LIST_NULL;
}
aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
+ }
+ else
+ {
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, TRUE);
}
printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
"SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
@@ -5829,12 +6194,26 @@
cmd->result = 0;
scb = NULL;
}
+ 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));
+ }
}
/*
* Restarting the sequencer will stop the selection and make sure devices
* are allowed to reselect in.
*/
aic_outb(p, 0, SCSISEQ);
+ aic_outb(p, CLRSELINGO, CLRSINT0);
aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
p->flags &= ~AHC_HANDLING_REQINITS;
aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
@@ -5868,6 +6247,8 @@
Scsi_Cmnd *cmd;
unsigned char mesg_out = MSG_NOOP;
unsigned char lastphase = aic_inb(p, LASTPHASE);
+ unsigned char sstat2 = aic_inb(p, SSTAT2);
+ unsigned char tindex = TARGET_INDEX(scb->cmd);
cmd = scb->cmd;
switch (lastphase)
@@ -5898,12 +6279,81 @@
break;
}
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- printk(WARN_LEAD "Parity error during %s phase.\n",
- p->host_no, CTL_OF_SCB(scb), phase);
+ /*
+ * A parity error has occurred during a data
+ * transfer phase. Flag it and continue.
+ */
+ if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) )
+ {
+ printk(WARN_LEAD "CRC error during %s phase.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
+ if(sstat2 & CRCVALERR)
+ {
+ printk(WARN_LEAD " CRC error in intermediate CRC packet.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ if(sstat2 & CRCENDERR)
+ {
+ printk(WARN_LEAD " CRC error in ending CRC packet.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ if(sstat2 & CRCREQERR)
+ {
+ printk(WARN_LEAD " Target incorrectly requested a CRC packet.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ if(sstat2 & DUAL_EDGE_ERROR)
+ {
+ printk(WARN_LEAD " Dual Edge transmission error.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ }
+ else
+ {
+ printk(WARN_LEAD "Parity error during %s phase.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
+ }
+
+ 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.
+ */
+ 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( !(syncrate->sxfr_ultra2 & 0x40) )
+ {
+ p->transinfo[tindex].goal_options = 0;
+ }
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (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
@@ -6072,13 +6522,6 @@
printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
bogus = TRUE;
}
- temp = aic_inb(p, SCB_PREV);
- if ((temp != SCB_LIST_NULL) &&
- (temp >= p->scb_data->maxhscbs))
- {
- printk("HSCB %d bad, SCB_PREV invalid(%d).\n", i, temp);
- bogus = TRUE;
- }
if (scb_status[i] == 0)
lost++;
if (lost > 1)
@@ -6163,7 +6606,7 @@
unsigned char scb_index;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if(aic7xxx_verbose > 0xffff)
+ if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
#endif
@@ -6368,7 +6811,7 @@
* Determines the queue depth for a given device. There are two ways
* a queue depth can be obtained for a tagged queueing device. One
* way is the default queue depth which is determined by whether
- * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used
+ * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used
* as the default queue depth. Otherwise, we use either 4 or 8 as the
* default queue depth (dependent on the number of hardware SCBs).
* The other way we determine queue depth is through the use of the
@@ -6396,7 +6839,7 @@
{
int tag_enabled = TRUE;
- default_depth = AIC7XXX_CMDS_PER_LUN;
+ default_depth = AIC7XXX_CMDS_PER_DEVICE;
if (!(p->discenable & target_mask))
{
@@ -6958,7 +7401,7 @@
}
printk("\n");
#endif
- if (checksum != scarray[len - 1])
+ if ( (checksum != scarray[len - 1]) || (checksum == 0) )
{
return (0);
}
@@ -7371,7 +7814,6 @@
aic_outb(p, i, SCBPTR);
aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */
aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */
- aic_outb(p, i - 1, SCB_PREV); /* Set the prev pointer. */
aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */
aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */
aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
@@ -7840,6 +8282,11 @@
*/
aic7xxx_loadseq(p);
+ /*
+ * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+ */
+ aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
{
aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */
@@ -8035,6 +8482,7 @@
{
p->transinfo[i].goal_period = 0;
p->transinfo[i].goal_offset = 0;
+ p->transinfo[i].goal_options = 0;
p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
}
DRIVER_LOCK_INIT
@@ -8090,10 +8538,14 @@
*/
for (i = 0; i < MAX_TARGETS; i++)
{
- if(p->dev_wdtr_cmnd[i])
- kfree(p->dev_wdtr_cmnd[i]);
- if(p->dev_sdtr_cmnd[i])
- kfree(p->dev_sdtr_cmnd[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]);
+ }
}
}
@@ -8184,14 +8636,16 @@
{
printk("aic7xxx: Using leftover BIOS values.\n");
}
- if ( *sxfrctl1 & STPWEN )
+ if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
{
p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
sc->adapter_control &= ~CFAUTOTERM;
sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
}
if (aic7xxx_extended)
- p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
+ p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+ else
+ p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
}
else
{
@@ -8256,8 +8710,7 @@
* Limit to 16 targets just in case. The 2842 for one is known to
* blow the max_targets setting, future cards might also.
*/
- max_targets = MIN(sc->max_targets & CFMAXTARG,
- ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8));
+ max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
if (have_seeprom)
{
@@ -8279,7 +8732,7 @@
mask = (0x01 << i);
if (!have_seeprom)
{
- if(aic_inb(p, SCSISEQ) != 0)
+ if (aic_inb(p, SCSISEQ) != 0)
{
/*
* OK...the BIOS set things up and left behind the settings we need.
@@ -8323,7 +8776,9 @@
sc->device_flags[i] = CFDISC;
if (p->features & AHC_WIDE)
sc->device_flags[i] |= CFWIDEB;
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_ULTRA3)
+ sc->device_flags[i] |= 2;
+ else if (p->features & AHC_ULTRA2)
sc->device_flags[i] |= 3;
else if (p->features & AHC_ULTRA)
sc->device_flags[i] |= CFSYNCHISULTRA;
@@ -8339,20 +8794,30 @@
}
if (p->flags & AHC_NEWEEPROM_FMT)
{
- if (sc->device_flags[i] & CFSYNCHISULTRA)
- {
- p->ultraenb |= mask;
- }
- else if (sc->device_flags[i] & CFNEWULTRAFORMAT)
+ if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+ !(p->features & AHC_ULTRA2) )
{
- if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) &&
- !(p->features & AHC_ULTRA2) )
+ /*
+ * I know of two different Ultra BIOSes that do this differently.
+ * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+ * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+ * while on the IBM Netfinity 5000 they want the same thing
+ * to be something else, while flags[i] & CFXFER == 0x03 and
+ * SYNCISULTRA false should be 40MByte/s. So, we set both to
+ * 40MByte/s and the lower speeds be damned. People will have
+ * to select around the conversely mapped lower speeds in order
+ * to select lower speeds on these boards.
+ */
+ if ((sc->device_flags[i] & (CFXFER)) == 0x03)
{
sc->device_flags[i] &= ~CFXFER;
sc->device_flags[i] |= CFSYNCHISULTRA;
- p->ultraenb |= mask;
}
}
+ if (sc->device_flags[i] & CFSYNCHISULTRA)
+ {
+ p->ultraenb |= mask;
+ }
}
else if (sc->adapter_control & CFULTRAEN)
{
@@ -8364,18 +8829,54 @@
p->ultraenb &= ~mask;
p->transinfo[i].user_offset = 0;
p->transinfo[i].user_period = 0;
+ p->transinfo[i].user_options = 0;
p->transinfo[i].cur_offset = 0;
p->transinfo[i].cur_period = 0;
+ p->transinfo[i].cur_options = 0;
p->needsdtr_copy &= ~mask;
}
else
{
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_ULTRA3)
+ {
+ p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+ p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+ if( (sc->device_flags[i] & CFXFER) < 0x03 )
+ {
+ scsirate = (sc->device_flags[i] & CFXFER);
+ p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
+ if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
+ {
+ p->transinfo[i].cur_options =
+ ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
+ MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
+ }
+ else
+ {
+ p->transinfo[i].cur_options = 0;
+ }
+ }
+ else
+ {
+ scsirate = (sc->device_flags[i] & CFXFER) |
+ ((p->ultraenb & mask) ? 0x18 : 0x10);
+ p->transinfo[i].user_options = 0;
+ p->transinfo[i].cur_options = 0;
+ }
+ p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+ AHC_SYNCRATE_ULTRA3);
+ p->transinfo[i].cur_period = aic7xxx_find_period(p,
+ aic_inb(p, TARG_SCSIRATE + i),
+ AHC_SYNCRATE_ULTRA3);
+ }
+ else if (p->features & AHC_ULTRA2)
{
p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
scsirate = (sc->device_flags[i] & CFXFER) |
((p->ultraenb & mask) ? 0x18 : 0x10);
+ p->transinfo[i].user_options = 0;
+ p->transinfo[i].cur_options = 0;
p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
AHC_SYNCRATE_ULTRA2);
p->transinfo[i].cur_period = aic7xxx_find_period(p,
@@ -8385,10 +8886,9 @@
else
{
scsirate = (sc->device_flags[i] & CFXFER) << 4;
- if (sc->device_flags[i] & CFWIDEB)
- p->transinfo[i].user_offset = MAX_OFFSET_16BIT;
- else
- p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+ p->transinfo[i].user_options = 0;
+ p->transinfo[i].cur_options = 0;
+ p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
if (p->features & AHC_ULTRA)
{
short ultraenb;
@@ -8427,9 +8927,10 @@
}
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->needwdtr = p->needwdtr_copy;
p->needsdtr = p->needsdtr_copy;
- p->wdtr_pending = p->sdtr_pending = 0;
+ p->dtr_pending = 0;
/*
* We set the p->ultraenb from the SEEPROM to begin with, but now we make
@@ -8453,6 +8954,7 @@
{
case AHC_AIC7895:
case AHC_AIC7896:
+ case AHC_AIC7899:
if (p->adapter_control & CFBPRIMARY)
p->flags |= AHC_CHANNEL_B_PRIMARY;
default:
@@ -8783,6 +9285,14 @@
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
AHC_PAGESCBS, AHC_AIC7850_FE, 6,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7860_FE, 7,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7860_FE, 7,
+ 32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7860_FE, 7,
@@ -8825,6 +9335,18 @@
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
AHC_AIC7895_FE, 19,
@@ -8833,30 +9355,66 @@
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7890_FE, 20,
32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_78902, AHC_AIC7890,
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7890_FE, 20,
32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7890_FE, 21,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7890_FE, 22,
+ 32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 22,
+ AHC_AIC7896_FE, 23,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 23,
+ AHC_AIC7896_FE, 24,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 24,
+ AHC_AIC7896_FE, 25,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 25,
+ AHC_AIC7860_FE, 26,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
};
unsigned short command;
@@ -8926,11 +9484,11 @@
}
#ifdef AIC7XXX_STRICT_PCI_SETUP
command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
- PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#else
command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#endif
+ command &= ~PCI_COMMAND_INVALIDATE;
if (aic7xxx_pci_parity == 0)
command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
pci_write_config_word(pdev, PCI_COMMAND, command);
@@ -8940,15 +9498,7 @@
{
printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
}
- devconfig |= 0x80000000;
- if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
- {
- devconfig &= ~(0x00000008);
- }
- else
- {
- devconfig |= 0x00000008;
- }
+ devconfig |= 0x80000040;
pci_write_config_dword(pdev, DEVCONFIG, devconfig);
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
@@ -8976,11 +9526,11 @@
}
#ifdef AIC7XXX_STRICT_PCI_SETUP
command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
- PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#else
command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#endif
+ command &= ~PCI_COMMAND_INVALIDATE;
if (aic7xxx_pci_parity == 0)
command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command);
@@ -8990,15 +9540,7 @@
{
printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
}
- devconfig |= 0x80000000;
- if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
- {
- devconfig &= ~(0x00000008);
- }
- else
- {
- devconfig |= 0x00000008;
- }
+ devconfig |= 0x80000040;
pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig);
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
@@ -9137,6 +9679,7 @@
case AHC_AIC7895: /* 7895 */
case AHC_AIC7896: /* 7896/7 */
+ case AHC_AIC7899: /* 7899 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
if (PCI_FUNC(temp_p->pdev->devfn) != 0)
{
@@ -9185,43 +9728,38 @@
*/
switch (temp_p->chip & AHC_CHIPID_MASK)
{
- case AHC_AIC7890:
- case AHC_AIC7896:
+ case AHC_AIC7892:
+ case AHC_AIC7899:
aic_outb(temp_p, 0, SCAMCTL);
/*
- * We used to set DPARCKEN in this register, but after talking
- * to a tech from Adaptec, I found out they don't use that
- * particular bit in their own register settings, and when you
- * combine that with the fact that I determined that we were
- * seeing Data-Path Parity Errors on things we shouldn't see
- * them on, I think there is a bug in the silicon and the way
- * to work around it is to disable this particular check. Also
- * This bug only showed up on certain commands, so it seems to
- * be pattern related or some such. The commands we would
- * typically send as a linux TEST_UNIT_READY or INQUIRY command
- * could cause it to be triggered, while regular commands that
- * actually made reasonable use of the SG array capabilities
- * seemed not to cause the problem.
+ * Switch to the alt mode of the chip...
+ */
+ aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
+ /*
+ * Set our options...the last two items set our CRC after x byte
+ * count in target mode...
*/
+ aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
+ aic_outb(temp_p, 0x00, 0x0b);
+ aic_outb(temp_p, 0x10, 0x0a);
/*
- aic_outb(temp_p, aic_inb(temp_p, DSCOMMAND0) |
- CACHETHEN | DPARCKEN | MPARCKEN |
- USCBSIZE32 | CIOPARCKEN,
- DSCOMMAND0);
+ * switch back to normal mode...
*/
+ aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
+ aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
+ TARGCRCENDEN | TARGCRCCNTEN,
+ CRCCONTROL1);
+ aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
+ MPARCKEN | CIOPARCKEN | CACHETHEN) &
+ ~DPARCKEN), DSCOMMAND0);
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ break;
+ case AHC_AIC7890:
+ case AHC_AIC7896:
+ aic_outb(temp_p, 0, SCAMCTL);
aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
CACHETHEN | MPARCKEN | USCBSIZE32 |
CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
- /* FALLTHROUGH */
- default:
- /*
- * We attempt to read a SEEPROM on *everything*. If we fail,
- * then we fail, but this covers things like 2910c cards that
- * now have SEEPROMs with their 7856 chipset that we would
- * otherwise ignore. They still don't have a BIOS, but they
- * have a SEEPROM that the SCSISelect utility on the Adaptec
- * diskettes can configure.
- */
aic7xxx_load_seeprom(temp_p, &sxfrctl1);
break;
case AHC_AIC7850:
@@ -9233,14 +9771,13 @@
aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
CACHETHEN | MPARCKEN) & ~DPARCKEN,
DSCOMMAND0);
+ /* FALLTHROUGH */
+ default:
aic7xxx_load_seeprom(temp_p, &sxfrctl1);
break;
case AHC_AIC7880:
/*
- * Only set the DSCOMMAND0 register if this is a Rev B.
- * chipset. For those, we also enable Ultra mode by
- * force due to brain-damage on the part of some BIOSes
- * We overload the devconfig variable here since we can.
+ * Check the rev of the chipset before we change DSCOMMAND0
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
@@ -9272,6 +9809,7 @@
{
case AHC_AIC7895:
case AHC_AIC7896:
+ case AHC_AIC7899:
current_p = list_p;
while(current_p != NULL)
{
@@ -9315,6 +9853,7 @@
break;
case AHC_AIC7895:
case AHC_AIC7896:
+ case AHC_AIC7899:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
#else
@@ -9364,7 +9903,7 @@
*/
if (temp_p->features & AHC_ULTRA2)
{
- aic_outb(temp_p, RD_DFTHRSH_75 | WR_DFTHRSH_75, DFF_THRSH);
+ aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
}
else
{
@@ -9512,7 +10051,7 @@
}
}
/*
- * Are we dealing with a 7985 where we need to sort the
+ * Are we dealing with a 7895/6/7/9 where we need to sort the
* channels as well, if so, the bios_address values should
* be the same
*/
@@ -9603,7 +10142,54 @@
return (found);
}
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+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:
@@ -9616,6 +10202,117 @@
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_NEGOTIATION)
+ {
+ 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( !(syncrate->sxfr_ultra2 & 0x40) )
+ {
+ p->transinfo[tindex].goal_options = 0;
+ }
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+ }
+ p->needdv &= ~(1<<tindex);
+ }
+ else
+ {
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ {
+ 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_NEGOTIATION) &&
+ (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.
+ */
+ aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
return;
}
@@ -9632,81 +10329,63 @@
int tindex)
{
- if ( (p->needwdtr & (1<<tindex)) && !(p->wdtr_pending & (1<<tindex)) )
+ if ( !(p->dtr_pending & (1<<tindex)) &&
+ ( (p->needppr & (1<<tindex)) ||
+ (p->needwdtr & (1<<tindex)) ||
+ (p->needsdtr & (1<<tindex)) ) )
{
- if(p->dev_wdtr_cmnd[tindex] == NULL)
+ if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
+ (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
{
- Scsi_Cmnd *cmd;
-
- if (!(p->dev_wdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
- {
- return;
- }
- cmd = p->dev_wdtr_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 = 0;
- cmd->request_buffer = NULL;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
+ return;
}
/*
- * Before sending this thing out, we also amke the cmd->next pointer
+ * 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
- * intp the real command instead of this fake command. This has to be
+ * 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_wdtr_cmnd[tindex]->next = old_cmd;
- aic7xxx_queue(p->dev_wdtr_cmnd[tindex],
- aic7xxx_negotiation_complete);
- }
- else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) &&
- !(p->wdtr_pending & (1<<tindex)) )
- {
- if(p->dev_sdtr_cmnd[tindex] == NULL)
+ 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);
{
- Scsi_Cmnd *cmd;
+ struct aic7xxx_scb *scb, *next;
- if (!(p->dev_sdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+ scb = p->waiting_scbs.head;
+ while(scb != NULL)
{
- return;
+ 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;
+ }
}
- cmd = p->dev_sdtr_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 = 0;
- cmd->request_buffer = NULL;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
}
- /*
- * Before sending this thing out, we also amke the cmd->next pointer
- * point to the real command so we can stuff any possible SENSE data
- * intp 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_sdtr_cmnd[tindex]->next = old_cmd;
- aic7xxx_queue(p->dev_sdtr_cmnd[tindex],
+ aic7xxx_queue(p->dev_dtr_cmnd[tindex],
aic7xxx_negotiation_complete);
}
}
-#endif
-
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*+F*************************************************************************
* Function:
@@ -9744,8 +10423,9 @@
{
unsigned short mask;
struct aic7xxx_hwscb *hscb;
+ unsigned char tindex = TARGET_INDEX(cmd);
- mask = (0x01 << TARGET_INDEX(cmd));
+ mask = (0x01 << tindex);
hscb = scb->hscb;
/*
@@ -9757,11 +10437,12 @@
if (p->discenable & mask)
{
hscb->control |= DISCENB;
- if (p->tagenable & mask)
+ if ( (p->tagenable & mask) &&
+ (cmd->cmnd[0] != TEST_UNIT_READY) )
{
cmd->tag = hscb->tag;
- p->dev_commands_sent[TARGET_INDEX(cmd)]++;
- if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
+ p->dev_commands_sent[tindex]++;
+ if (p->dev_commands_sent[tindex] < 200)
{
hscb->control |= MSG_SIMPLE_Q_TAG;
scb->tag_action = MSG_SIMPLE_Q_TAG;
@@ -9778,74 +10459,38 @@
hscb->control |= MSG_SIMPLE_Q_TAG;
scb->tag_action = MSG_SIMPLE_Q_TAG;
}
- p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
+ p->dev_commands_sent[tindex] = 0;
}
}
}
- if (p->dev_flags[TARGET_INDEX(cmd)] & DEVICE_SCANNED)
+ if ( cmd == p->dev_dtr_cmnd[tindex] )
{
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
- if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) )
+ p->dtr_pending |= mask;
+ scb->tag_action = 0;
+ if (p->dev_flags[tindex] & DEVICE_SCANNED)
{
- if (cmd == p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
+ hscb->control &= DISCENB;
+ hscb->control |= MK_MESSAGE;
+ if(p->needppr & mask)
{
- p->wdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_WDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
+ scb->flags |= SCB_MSGOUT_PPR;
}
- else
+ else if(p->needwdtr & mask)
{
- aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
+ scb->flags |= SCB_MSGOUT_WDTR;
}
- }
- else if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) &&
- !(p->wdtr_pending & mask) )
- {
- if (cmd == p->dev_sdtr_cmnd[TARGET_INDEX(cmd)])
+ else if(p->needsdtr & mask)
{
- p->sdtr_pending |= mask;
scb->flags |= SCB_MSGOUT_SDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
- }
- else if (cmd != p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
- {
- aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
}
}
-#else
- if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) &&
- !(p->sdtr_pending & mask) && (cmd->lun == 0) )
- {
- p->wdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_WDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Building WDTR command.\n", p->host_no,
- CTL_OF_CMD(cmd));
-#endif
- }
- else if ( (p->needsdtr & mask) && !(p->wdtr_pending & mask) &&
- !(p->sdtr_pending & mask) && (cmd->lun == 0) )
- {
- p->sdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Building SDTR command.\n", p->host_no,
- CTL_OF_CMD(cmd));
-#endif
- }
-#endif
+ }
+ if ( !(p->dtr_pending & mask) &&
+ ( (p->needppr & mask) ||
+ (p->needwdtr & mask) ||
+ (p->needsdtr & mask) ) )
+ {
+ aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
}
hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -9897,7 +10542,6 @@
scb->sg_count = cmd->use_sg;
hscb->SG_segment_count = cmd->use_sg;
hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
-
}
else
{
@@ -9922,12 +10566,6 @@
hscb->data_pointer = 0;
}
}
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if((cmd->cmnd[0] == TEST_UNIT_READY) && (aic7xxx_verbose & VERBOSE_PROBE2))
- {
- aic7xxx_print_scb(p, scb);
- }
-#endif
}
/*+F*************************************************************************
@@ -10262,13 +10900,14 @@
if(p->dev_flags[i] & DEVICE_PRESENT)
{
mask = (0x01 << i);
- printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
- " q_depth=%d:%d\n",
+ printk(INFO_LEAD "dev_flags=0x%x, Pending:%c, PPR:%c/%c, WDTR:%c/%c, "
+ "SDTR:%c/%c, q_depth=%d:%d\n",
p->host_no, 0, i, 0, p->dev_flags[i],
- (p->wdtr_pending & mask) ? 'Y' : 'N',
+ (p->dtr_pending & mask) ? 'Y' : 'N',
+ (p->needppr & mask) ? 'Y' : 'N',
+ (p->needppr_copy & mask) ? 'Y' : 'N',
(p->needwdtr & mask) ? 'Y' : 'N',
(p->needwdtr_copy & mask) ? 'Y' : 'N',
- (p->sdtr_pending & mask) ? 'Y' : 'N',
(p->needsdtr & mask) ? 'Y' : 'N',
(p->needsdtr_copy & mask) ? 'Y' : 'N',
p->dev_active_cmds[i],
@@ -10347,13 +10986,13 @@
* We haven't found the offending SCB yet, and it should be around
* somewhere, so go look for it in the cards SCBs.
*/
- printk("SCBPTR CONTROL TAG PREV NEXT\n");
+ printk("SCBPTR CONTROL TAG NEXT\n");
for(i=0; i<p->scb_data->maxhscbs; i++)
{
aic_outb(p, i, SCBPTR);
- printk(" %3d %02x %02x %02x %02x\n", i,
+ printk(" %3d %02x %02x %02x\n", i,
aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG),
- aic_inb(p, SCB_PREV), aic_inb(p, SCB_NEXT));
+ aic_inb(p, SCB_NEXT));
}
}
@@ -10569,21 +11208,13 @@
if ((found == 0) && (scb->flags & SCB_WAITINGQ))
{
int tindex = TARGET_INDEX(cmd);
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
unsigned short mask;
mask = (1 << tindex);
- if (p->wdtr_pending & mask)
- {
- if (p->dev_wdtr_cmnd[tindex]->next != cmd)
- found = 1;
- else
- found = 0;
- }
- else if (p->sdtr_pending & mask)
+ if (p->dtr_pending & mask)
{
- if (p->dev_sdtr_cmnd[tindex]->next != cmd)
+ if (p->dev_dtr_cmnd[tindex]->next != cmd)
found = 1;
else
found = 0;
@@ -10606,7 +11237,6 @@
DRIVER_UNLOCK
return(SCSI_ABORT_PENDING);
}
-#endif
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB found on waiting list and "
"aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -10864,6 +11494,8 @@
if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
CTL_OF_SCB(scb));
+ aic7xxx_run_done_queue(p, TRUE);
+ aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
return(SCSI_RESET_NOT_RUNNING);
@@ -11034,16 +11666,21 @@
int
aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
{
- int heads, sectors, cylinders;
+ int heads, sectors, cylinders, ret;
struct aic7xxx_host *p;
+ struct buffer_head *bh;
p = (struct aic7xxx_host *) disk->device->host->hostdata;
+ bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
- /*
- * XXX - if I could portably find the card's configuration
- * information, then this could be autodetected instead
- * of left to a boot-time switch.
- */
+ if ( bh )
+ {
+ ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+ brelse(bh);
+ if ( ret != -1 )
+ return(ret);
+ }
+
heads = 64;
sectors = 32;
cylinders = disk->capacity / (heads * sectors);
@@ -11150,6 +11787,12 @@
0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
0xfe, 0xff} },
+ {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
+ 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+ 0xe0, 0xf1, 0xf4, 0xfc} },
+ {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
+ 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+ 0xe0, 0xf1, 0xf4, 0xfc} },
};
#ifdef CONFIG_PCI
static struct register_ranges cards_ns[] = {
@@ -11164,6 +11807,10 @@
{ 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} },
{ 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47,
0xdc, 0xe3} },
+ { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+ 0xff, 0xff} },
+ { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+ 0xff, 0xff} },
{ 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
0xff, 0xff} }
};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)