patch-2.2.17 linux/drivers/scsi/aic7xxx.c
Next file: linux/drivers/scsi/aic7xxx_seq.c
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx.seq
Back to the patch index
Back to the overall index
- Lines: 1108
- Date:
Mon Sep 4 18:39:21 2000
- Orig file:
v2.2.16/drivers/scsi/aic7xxx.c
- Orig date:
Mon Sep 4 18:37:34 2000
diff -u --recursive --new-file v2.2.16/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -270,7 +270,7 @@
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.1.28"
+#define AIC7XXX_C_VERSION "5.1.31"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -576,7 +576,7 @@
* AIC-7770 I/O range to reserve for a card
*/
#define MINREG 0xC00
-#define MAXREG 0xCBF
+#define MAXREG 0xCFF
#define INTDEF 0x5C /* Interrupt Definition Register */
@@ -1491,10 +1491,10 @@
{
outb(val, p->base + port);
mb(); /* locked operation in order to force ordering */
- inb(p->base + HCNTRL); /* dummy read to flush the write */
}
#else
outb(val, p->base + port);
+ mb(); /* locked operation in order to force ordering */
#endif
}
@@ -1664,6 +1664,10 @@
{
;
}
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_inb(p, CCSCBCTL);
+ }
}
/*+F*************************************************************************
@@ -2133,7 +2137,7 @@
* Use async transfers for this target
*/
*options = 0;
- *period = 0;
+ *period = 255;
syncrate = NULL;
}
return (syncrate);
@@ -2901,6 +2905,7 @@
#define WIDE_INQUIRY_BITS 0x60
#define SYNC_INQUIRY_BITS 0x10
#define SCSI_VERSION_BITS 0x07
+#define SCSI_DT_BIT 0x04
if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
(p->features & AHC_WIDE) )
{
@@ -2919,61 +2924,66 @@
AHC_TRANS_CUR) );
unpause_sequencer(p, FALSE);
}
- if (buffer[7] & SYNC_INQUIRY_BITS)
+ if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+ p->transinfo[tindex].user_offset )
{
- p->needsdtr |= (1<<tindex);
- p->needsdtr_copy |= (1<<tindex);
-
p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
- if (p->transinfo[tindex].user_offset)
+ if (p->features & AHC_ULTRA2)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ else
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
+ (buffer[56] & SCSI_DT_BIT) ||
+ (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+ (p->transinfo[tindex].user_period <= 9) &&
+ (p->transinfo[tindex].user_options) )
{
- if (p->features & AHC_ULTRA2)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
- else
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ p->needppr |= (1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ }
+ else
+ {
+ p->needsdtr |= (1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ p->transinfo[tindex].goal_period =
+ MAX(10, p->transinfo[tindex].goal_period);
+ p->transinfo[tindex].goal_options = 0;
}
}
else
{
p->needsdtr &= ~(1<<tindex);
p->needsdtr_copy &= ~(1<<tindex);
- p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_period = 255;
p->transinfo[tindex].goal_offset = 0;
p->transinfo[tindex].goal_options = 0;
}
- if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+ /*
+ * This is needed to work around a sequencer bug for now. Regardless
+ * of the controller in use, if we have a Quantum drive, we need to
+ * limit the speed to 80MByte/sec. As soon as I get a fixed version
+ * of the sequencer, this code will get yanked.
+ */
+ if(!strncmp(buffer + 8, "QUANTUM", 7) &&
+ p->transinfo[tindex].goal_options )
{
- p->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);
- /*
- * This is needed to work around a sequencer bug for now. Regardless
- * of the controller in use, if we have a Quantum drive, we need to
- * limit the speed to 80MByte/sec. As soon as I get a fixed version
- * of the sequencer, this code will get yanked.
- */
- if(!strncmp(buffer + 8, "QUANTUM", 7) &&
- p->transinfo[tindex].goal_options )
- {
- p->transinfo[tindex].goal_period =
- MAX(p->transinfo[tindex].goal_period, 10);
- p->transinfo[tindex].goal_options = 0;
- }
+ p->transinfo[tindex].goal_period =
+ MAX(p->transinfo[tindex].goal_period, 10);
+ p->transinfo[tindex].goal_options = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
}
/*
* Get the INQUIRY checksum. We use this on Ultra 160/m
@@ -3003,6 +3013,7 @@
#undef WIDE_INQUIRY_BITS
#undef SYNC_INQUIRY_BITS
#undef SCSI_VERSION_BITS
+#undef SCSI_DT_BIT
}
}
else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
@@ -4639,7 +4650,9 @@
* 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.
+ * support instead of rejecting our offering or else they cause
+ * a parity error during msg_out phase to signal that they don't
+ * like our settings.
*/
p->needppr &= ~target_mask;
p->needppr_copy &= ~target_mask;
@@ -4817,51 +4830,6 @@
scb->sg_count = hscb->SG_segment_count = 1;
scb->sg_length = sizeof(cmd->sense_buffer);
scb->tag_action = 0;
- /*
- * This problem could be caused if the target has lost power
- * or found some other way to loose the negotiation settings,
- * so if needed, we'll re-negotiate while doing the sense cmd.
- * However, if this SCB already was attempting to negotiate,
- * then we assume this isn't the problem and skip this part.
- */
- if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
- (p->dev_flags[tindex] & DEVICE_SCANNED) &&
- !(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_dtr_cmnd[tindex] )
- {
- /*
- * This is already a negotiation command, so we must have
- * 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.
- */
-
- /*
- * This is the important part though. We are getting sense
- * info back from this device. It's going into a fake
- * command. We need to put that into the real command
- * instead so that the mid level SCSI code can act upon it.
- * So, when we set up these fake commands, the next pointer
- * is used to point to the real command. Use that to change
- * the address of our sense_buffer[] to the real command.
- * However, don't do this if the real command is also a
- * TEST_UNIT_READY as it will most likely pull down its own
- * SENSE information anyway.
- */
- if (cmd->next->cmnd[0] != TEST_UNIT_READY)
- {
- scb->sg_list[0].address =
- cpu_to_le32(VIRT_TO_BUS(&cmd->next->sense_buffer[0]));
- hscb->data_pointer = scb->sg_list[0].address;
- }
- }
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
@@ -4884,7 +4852,7 @@
aic7xxx_error(cmd) = DID_OK;
break;
} /* first time sense, no errors */
- aic7xxx_error(cmd) = DID_OK;
+ aic7xxx_error(cmd) = DID_ERROR;
scb->flags &= ~SCB_SENSE;
break;
@@ -5135,51 +5103,14 @@
}
else if (scb->flags & SCB_MSGOUT_PPR)
{
- unsigned int max_sync, period;
- unsigned char options = 0;
-
- 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) &&
- (p->transinfo[tindex].goal_options != 0) )
- {
- max_sync = AHC_SYNCRATE_ULTRA3;
- options = p->transinfo[tindex].goal_options;
- }
- 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->host_no, CTL_OF_SCB(scb),
+ p->transinfo[tindex].goal_period,
p->transinfo[tindex].goal_offset,
- p->transinfo[tindex].goal_width, options);
+ p->transinfo[tindex].goal_width,
+ p->transinfo[tindex].goal_options);
}
aic7xxx_construct_ppr(p, scb);
}
@@ -5225,8 +5156,7 @@
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,
+ CTL_OF_SCB(scb), period,
p->transinfo[tindex].goal_offset);
}
aic7xxx_construct_sdtr(p, period,
@@ -5339,7 +5269,7 @@
resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
(aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
- (aic_inb(p, SCB_RESID_DCNT + 2) << 24);
+ (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
index = scb->sg_count - (resid_sgcnt + 1);
native_addr = le32_to_cpu(scb->sg_list[index].address);
native_length = le32_to_cpu(scb->sg_list[index].length);
@@ -5347,7 +5277,7 @@
* Make sure this is a valid sg_seg for the given pointer
*/
if(cur_addr < native_addr ||
- cur_addr > (native_addr + native_length))
+ cur_addr > (native_addr + native_length + 1))
{
printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
p->host_no, CTL_OF_SCB(scb), cur_addr);
@@ -5364,16 +5294,31 @@
p->host_no, CTL_OF_SCB(scb),
le32_to_cpu(scb->sg_list[index + 1].address),
le32_to_cpu(scb->sg_list[index + 1].length));
+ printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n",
+ p->host_no, CTL_OF_SCB(scb),
+ cur_addr, resid_dcnt);
break;
}
- /*
- * If our current address matches the sg_seg->address then we
- * have to back up the sg array to the previous segment and set
- * it up to have only one byte of transfer left to go.
- */
- if(cur_addr == native_addr)
+ if( (resid_sgcnt == 0) &&
+ ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
{
+ /*
+ * We are at the end of the transfer and this is about a byte
+ * we ignored already (because the sequencer knew this was
+ * the last segment and set the adapter to ignore any wide
+ * residue bytes that might come through, which is only done
+ * on the last scatter gather segment of transfers).
+ */
+ break;
+ }
+ else if(cur_addr == native_addr)
+ {
+ /*
+ * If our current address matches the sg_seg->address then we
+ * have to back up the sg array to the previous segment and set
+ * it up to have only one byte of transfer left to go.
+ */
if(index == 0)
{
printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
@@ -5403,39 +5348,6 @@
aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
- /*
- * The sequencer actually wants to find the new address and byte
- * count in the SHCNT and SHADDR register sets. These registers
- * are a shadow of the regular HCNT and HADDR registers. On the
- * Ultra2 controllers, these registers are read only and the way
- * we have to set their values is to put the values we want into
- * the HCNT and HADDR registers and then output PRELOADEN into
- * the DFCNTRL register which causes the card to latch the current
- * values in the HADDR and HCNT registers and drop it through to
- * the shadow registers. On older cards we copy them directly
- * across by hand.
- */
- if(p->features & AHC_ULTRA2)
- {
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- i=0;
- udelay(1);
- while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
- {
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- udelay(1);
- }
- }
- else
- {
- aic_outb(p, 1, STCNT);
- aic_outb(p, 0, STCNT + 1);
- aic_outb(p, 0, STCNT + 2);
- aic_outb(p, cur_addr & 0xff, SHADDR);
- aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
- aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
- aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
- }
}
else
{
@@ -5455,28 +5367,46 @@
aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
- if(p->features & AHC_ULTRA2)
+ }
+ /*
+ * The sequencer actually wants to find the new address and byte
+ * count in the SHCNT and SHADDR register sets. These registers
+ * are a shadow of the regular HCNT and HADDR registers. On the
+ * Ultra2 controllers, these registers are read only and the way
+ * we have to set their values is to put the values we want into
+ * the HCNT and HADDR registers and then output PRELOADEN into
+ * the DFCNTRL register which causes the card to latch the current
+ * values in the HADDR and HCNT registers and drop it through to
+ * the shadow registers. On older cards we copy them directly
+ * across by hand.
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
{
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- i=0;
udelay(1);
- while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
- {
- aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
- udelay(1);
- }
}
- else
+ aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
+ i=0;
+ udelay(1);
+ while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
{
- aic_outb(p, resid_dcnt & 0xff, STCNT);
- aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
- aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
- aic_outb(p, cur_addr & 0xff, SHADDR);
- aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
- aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
- aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ udelay(1);
}
}
+ else
+ {
+ aic_outb(p, resid_dcnt & 0xff, STCNT);
+ aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1);
+ aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2);
+ aic_outb(p, cur_addr & 0xff, SHADDR);
+ aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+ aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+ aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+ }
}
break;
@@ -5885,6 +5815,7 @@
reply = TRUE;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_PPR;
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
{
/*
@@ -5918,7 +5849,6 @@
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)
{
@@ -5952,6 +5882,25 @@
break;
}
}
+ if ( (p->transinfo[tindex].goal_period > 9) ||
+ (p->transinfo[tindex].goal_options == 0) )
+ {
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ reject = TRUE;
+ reply = FALSE;
+ p->needppr &= ~(1 << tindex);
+ p->needppr_copy &= ~(1 << tindex);
+ if ( p->transinfo[tindex].goal_offset )
+ {
+ p->needsdtr |= (1 << tindex);
+ p->needsdtr_copy |= (1 << tindex);
+ }
+ if ( p->transinfo[tindex].goal_width )
+ {
+ p->needwdtr |= (1 << tindex);
+ p->needwdtr_copy |= (1 << tindex);
+ }
+ }
}
else
{
@@ -5959,7 +5908,7 @@
{
default:
{
- reply = TRUE;
+ reject = TRUE;
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
(aic7xxx_verbose > 0xffff)) )
@@ -5985,27 +5934,18 @@
}
}
- 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)) )
+ if ( !reject )
{
aic7xxx_set_width(p, target, channel, lun, bus_width,
- AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ 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_GOAL|AHC_TRANS_QUITE);
- reply = TRUE;
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
}
+
p->dtr_pending &= ~target_mask;
p->needppr &= ~target_mask;
if(reply)
@@ -6411,20 +6351,14 @@
/*
* Keep the sequencer from trying to restart any selections
*/
- aic_outb(p, 0, SCSISEQ);
+ aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
/*
* Make sure the data bits on the bus are released
+ * Don't do this on 7770 chipsets, it makes them give us
+ * a BRKADDRINT and kills the card.
*/
- if(p->features & AHC_WIDE)
- aic_outb(p, 0, SCSIBUSH);
- aic_outb(p, 0, SCSIBUSL);
- /*
- * Clear the target id bit from the SCSI bus
- */
- if(p->features & AHC_ULTRA2)
- aic_outb(p, aic_inb(p, SCSIID_ULTRA2) & 0x0f, SCSIID_ULTRA2);
- else
- aic_outb(p, aic_inb(p, SCSIID) & 0x0f, SCSIID);
+ if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+ aic_outb(p, 0, SCSIBUSL);
/*
* Delay for the selection timeout delay period then stop the selection
@@ -6507,7 +6441,9 @@
* 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) )
+ if( (p->features & AHC_ULTRA3) &&
+ (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);
@@ -6532,13 +6468,50 @@
p->host_no, CTL_OF_SCB(scb));
}
}
- else
+ else if( (lastphase == P_MESGOUT) &&
+ (cmd == p->dev_dtr_cmnd[tindex]) &&
+ (scb->flags & SCB_MSGOUT_PPR) )
{
- printk(WARN_LEAD "Parity error during %s phase.\n",
- p->host_no, CTL_OF_SCB(scb), phase);
+ /*
+ * 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 or else they cause
+ * a parity error during msg_out phase to signal that they don't
+ * like our settings.
+ */
+ p->needppr &= ~(1 << tindex);
+ p->needppr_copy &= ~(1 << tindex);
+ aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
+ MSG_EXT_WDTR_BUS_8_BIT,
+ (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+ aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
+ 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+ p->transinfo[tindex].goal_options = 0;
+ p->dtr_pending &= ~(1 << tindex);
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "parity error during PPR message, reverting "
+ "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
+ }
+ if ( p->transinfo[tindex].goal_width )
+ {
+ p->needwdtr |= (1 << tindex);
+ p->needwdtr_copy |= (1 << tindex);
+ }
+ if ( p->transinfo[tindex].goal_offset )
+ {
+ if( p->transinfo[tindex].goal_period <= 9 )
+ {
+ p->transinfo[tindex].goal_period = 10;
+ }
+ p->needsdtr |= (1 << tindex);
+ p->needsdtr_copy |= (1 << tindex);
+ }
+ scb = NULL;
}
-
- if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+ else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
{
struct aic7xxx_syncrate *syncrate;
unsigned int period = p->transinfo[tindex].cur_period;
@@ -6550,6 +6523,8 @@
* instead of slowing down if those exist. That's hard to do with simple
* checksums though.
*/
+ printk(WARN_LEAD "Parity error during %s phase.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
{
syncrate++;
@@ -6557,20 +6532,59 @@
(!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
{
p->transinfo[tindex].goal_period = syncrate->period;
- if( !(syncrate->sxfr_ultra2 & 0x40) )
+ if( p->transinfo[tindex].goal_period > 9 )
{
p->transinfo[tindex].goal_options = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ if (p->transinfo[tindex].goal_width)
+ {
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
+ }
+ }
+ }
+ else if (p->transinfo[tindex].goal_width)
+ {
+ p->transinfo[tindex].goal_width = 0;
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_offset =
+ p->transinfo[tindex].user_offset;
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
+ if( p->transinfo[tindex].goal_period <= 9 )
+ {
+ p->needppr |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ }
+ else
+ {
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
}
}
else
{
p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_period = 255;
p->transinfo[tindex].goal_options = 0;
+ p->transinfo[tindex].goal_width = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
}
- p->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;
}
@@ -6588,6 +6602,7 @@
if (mesg_out != MSG_NOOP)
{
aic_outb(p, mesg_out, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
scb = NULL;
}
aic_outb(p, CLRSCSIPERR, CLRSINT1);
@@ -6779,7 +6794,7 @@
{
struct aic7xxx_scb *scb = NULL;
Scsi_Cmnd *cmd;
- unsigned char scb_index;
+ unsigned char scb_index, tindex;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
@@ -6805,23 +6820,21 @@
scb_index = p->qoutfifo[p->qoutfifonext];
p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
if ( scb_index >= p->scb_data->numscbs )
- scb = NULL;
- else
- scb = p->scb_data->scb_array[scb_index];
- if (scb == NULL)
{
printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
-1, -1, -1, scb_index);
continue;
}
- else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ scb = p->scb_data->scb_array[scb_index];
+ if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
{
printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
"0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
(unsigned long) scb->cmd);
continue;
}
- else if (scb->flags & SCB_QUEUED_ABORT)
+ tindex = TARGET_INDEX(scb->cmd);
+ if (scb->flags & SCB_QUEUED_ABORT)
{
pause_sequencer(p);
if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
@@ -6844,6 +6857,43 @@
*/
scb->flags &= ~(SCB_ABORT|SCB_RESET);
}
+ else if (scb->flags & SCB_SENSE)
+ {
+ char *buffer = &scb->cmd->sense_buffer[0];
+ if (scb->cmd == p->dev_dtr_cmnd[tindex])
+ {
+ struct aic7xxx_scb *old_scb;
+ /*
+ * We have valid sense data, send it back immediately.
+ */
+ old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
+ *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
+ old_scb->hscb->target_status = scb->hscb->target_status;
+ old_scb->cmd->result = scb->hscb->target_status;
+ old_scb->cmd->result |= (DID_ERROR << 16);
+ aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
+ scbq_remove(&p->waiting_scbs, old_scb);
+ scbq_remove(&p->delayed_scbs[tindex], old_scb);
+ scb->cmd->next = NULL;
+ aic7xxx_done(p, scb);
+ aic7xxx_done(p, old_scb);
+ continue;
+ }
+ else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+ {
+ /*
+ * SCSI errors, run domain validation and re-run negotiation
+ */
+ p->needdv |= (1<<tindex);
+ /*
+ * Signal that we need to re-negotiate things, this also gets us our
+ * INQUIRY command to re-checksum off of.
+ */
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+ }
+ }
switch (status_byte(scb->hscb->target_status))
{
case QUEUE_FULL:
@@ -6973,6 +7023,13 @@
if (intstat & SEQINT)
{
+ /*
+ * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
+ */
+ if(p->features & AHC_ULTRA2)
+ {
+ aic_inb(p, CCSCBCTL);
+ }
aic7xxx_handle_seqint(p, intstat);
}
@@ -7055,7 +7112,7 @@
* with queue depths for individual devices. It also allows tagged
* queueing to be [en|dis]abled for a specific adapter.
*-F*************************************************************************/
-static void
+static int
aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
{
int default_depth = 3;
@@ -7065,6 +7122,14 @@
tindex = device->id | (device->channel << 3);
target_mask = (1 << tindex);
+ if (p->dev_max_queue_depth[tindex] > 1)
+ {
+ /*
+ * We've already scanned this device, leave it alone
+ */
+ return(p->dev_max_queue_depth[tindex]);
+ }
+
device->queue_depth = default_depth;
p->dev_temp_queue_depth[tindex] = 1;
p->dev_max_queue_depth[tindex] = 1;
@@ -7133,6 +7198,7 @@
}
}
}
+ return(p->dev_max_queue_depth[tindex]);
}
/*+F*************************************************************************
@@ -7160,8 +7226,7 @@
{
if (device->host == host)
{
- aic7xxx_device_queue_depth(p, device);
- scbnum += device->queue_depth;
+ scbnum += aic7xxx_device_queue_depth(p, device);
}
}
while (scbnum > p->scb_data->numscbs)
@@ -8371,23 +8436,8 @@
}
aic_outb(p, 0, SEQ_FLAGS);
- /*
- * We are starting to do real work on the card....it's possible we could
- * generate some spurious interrupts at this point, especially in the
- * event of a PCI error or some such. If there are other devices already
- * registered on the same interrupt as us, this could cause the machine
- * to lock up. So, we disable the interrupt this card is on until we
- * finish our card setup. We only need to do this for modules, if we are
- * compiled into the kernel then interrupts are already off during this
- * part of the code.
- */
-#ifdef MODULE
- disable_irq(p->irq);
-#endif
-
detect_maxscb(p);
-
printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
if (aic7xxx_verbose & VERBOSE_PROBE2)
{
@@ -8616,9 +8666,6 @@
printk("(scsi%d) Unable to allocate hardware SCB array; "
"failing detection.\n", p->host_no);
aic_outb(p, 0, SIMODE1);
-#ifdef MODULE
- enable_irq(p->irq);
-#endif
p->irq = 0;
return(0);
}
@@ -8796,9 +8843,6 @@
printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
"controller.\n", p->host_no, p->irq);
aic_outb(p, 0, SIMODE1);
-#ifdef MODULE
- enable_irq(p->irq);
-#endif
p->irq = 0;
return (0);
}
@@ -8808,10 +8852,6 @@
p->host_no, -1, -1 , -1);
aic7xxx_clear_intstat(p);
-#ifdef MODULE
- enable_irq(p->irq);
-#endif
-
unpause_sequencer(p, /* unpause_always */ TRUE);
return (found);
@@ -8920,7 +8960,7 @@
p->orderedtag = 0;
for (i=0; i<MAX_TARGETS; i++)
{
- p->transinfo[i].goal_period = 0;
+ p->transinfo[i].goal_period = 255;
p->transinfo[i].goal_offset = 0;
p->transinfo[i].goal_options = 0;
p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
@@ -9709,7 +9749,8 @@
{
if ( ((current_p->pci_bus == temp_p->pci_bus) &&
(current_p->pci_device_fn == temp_p->pci_device_fn)) ||
- (current_p->base == temp_p->base) )
+ (temp_p->base && (current_p->base == temp_p->base)) ||
+ (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
{
/* duplicate PCI entry, skip it */
kfree(temp_p);
@@ -9769,7 +9810,8 @@
{
if ( ((current_p->pci_bus == temp_p->pci_bus) &&
(current_p->pci_device_fn == temp_p->pci_device_fn)) ||
- (current_p->base == temp_p->base) )
+ (temp_p->base && (current_p->base == temp_p->base)) ||
+ (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
{
/* duplicate PCI entry, skip it */
kfree(temp_p);
@@ -9812,7 +9854,7 @@
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
- if(check_region(temp_p->base, MAXREG - MINREG))
+ if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
{
printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
board_names[aic_pdevs[i].board_name_index],
@@ -9843,7 +9885,7 @@
}
#ifdef MMAPIO
- if ( !(temp_p->flags & AHC_MULTI_CHANNEL) ||
+ if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
(temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
{
@@ -9881,6 +9923,18 @@
vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
#endif
temp_p->maddr = 0;
+ if(temp_p->base == 0)
+ {
+ printk("aic7xxx: <%s> at PCI %d/%d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ temp_p->pci_bus,
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+ kfree(temp_p);
+ temp_p = NULL;
+ continue;
+ }
}
}
}
@@ -9889,7 +9943,8 @@
/*
* Lock out other contenders for our i/o space.
*/
- request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+ if(temp_p->base)
+ request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
/*
* We HAVE to make sure the first pause_sequencer() and all other
@@ -10801,20 +10856,59 @@
(!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
{
p->transinfo[tindex].goal_period = syncrate->period;
- if( !(syncrate->sxfr_ultra2 & 0x40) )
+ if( p->transinfo[tindex].goal_period > 9 )
{
p->transinfo[tindex].goal_options = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
+ if (p->transinfo[tindex].goal_width)
+ {
+ p->needwdtr |= (1<<tindex);
+ p->needwdtr_copy |= (1<<tindex);
+ }
+ }
+ }
+ else if (p->transinfo[tindex].goal_width)
+ {
+ p->transinfo[tindex].goal_width = 0;
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->transinfo[tindex].goal_offset =
+ p->transinfo[tindex].user_offset;
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
+ if( p->transinfo[tindex].goal_period <= 9 )
+ {
+ p->needppr |= (1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ }
+ else
+ {
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr |= (1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy |= (1<<tindex);
}
}
else
{
p->transinfo[tindex].goal_offset = 0;
- p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_period = 255;
p->transinfo[tindex].goal_options = 0;
+ p->transinfo[tindex].goal_width = 0;
+ p->needppr &= ~(1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needwdtr &= ~(1<<tindex);
+ p->needppr_copy &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
}
- p->needppr |= (p->needppr_copy & (1<<tindex));
- p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
- p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
}
p->needdv &= ~(1<<tindex);
}
@@ -10865,8 +10959,16 @@
* and we didn't follow up with SDTR yet, then this will get it started.
* For all other cases, this should work out to be a no-op, unless we are
* doing domain validation and happen to need a new negotiation command.
+ *
+ * In case we don't want this to go any further, the cmdcmplt interrupt
+ * handler will NULL out the cmd->next entry so that the real SCSI command
+ * can be sent back to the mid layer code with SENSE data intact. We'll
+ * finish things up when the cmd gets sent back down to us, so no worries.
*/
- aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+ if(cmd->next)
+ {
+ aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+ }
return;
}
@@ -10988,13 +11090,13 @@
*/
hscb->control = 0;
scb->tag_action = 0;
+ cmd->tag = hscb->tag;
if (p->discenable & mask)
{
hscb->control |= DISCENB;
if ( (p->tagenable & mask) &&
(cmd->cmnd[0] != TEST_UNIT_READY) )
{
- cmd->tag = hscb->tag;
p->dev_commands_sent[tindex]++;
if (p->dev_commands_sent[tindex] < 200)
{
@@ -12275,7 +12377,8 @@
if(p->irq)
free_irq(p->irq, p);
- release_region(p->base, MAXREG - MINREG);
+ if(p->base)
+ release_region(p->base, MAXREG - MINREG);
#ifdef MMAPIO
if(p->maddr)
{
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)