aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorScott Long <scottl@FreeBSD.org>2002-12-01 08:13:37 +0000
committerScott Long <scottl@FreeBSD.org>2002-12-01 08:13:37 +0000
commit0c5aa4c57b9874b8ae016bb722deaaf4b6278068 (patch)
tree8f5f273b1ccc8f34c05265b9f4327079f55c99a0 /sys
parent454bf1693ad2014f7c1a7251d40ad6fb7400ddc1 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/aic7xxx/aic79xx.c701
-rw-r--r--sys/dev/aic7xxx/aic79xx.h204
-rw-r--r--sys/dev/aic7xxx/aic79xx.reg130
-rw-r--r--sys/dev/aic7xxx/aic79xx.seq286
4 files changed, 949 insertions, 372 deletions
diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c
index 7762fa2e479c..19a98c0db27b 100644
--- a/sys/dev/aic7xxx/aic79xx.c
+++ b/sys/dev/aic7xxx/aic79xx.c
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#113 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#139 $
*
* $FreeBSD$
*/
@@ -135,8 +135,6 @@ static void ahd_update_neg_table(struct ahd_softc *ahd,
static void ahd_update_pending_scbs(struct ahd_softc *ahd);
static void ahd_fetch_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo);
-static void ahd_print_devinfo(struct ahd_softc *ahd,
- struct ahd_devinfo *devinfo);
static void ahd_scb_devinfo(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
struct scb *scb);
@@ -224,6 +222,7 @@ static u_int ahd_resolve_seqaddr(struct ahd_softc *ahd,
u_int address);
static void ahd_download_instr(struct ahd_softc *ahd,
u_int instrptr, uint8_t *dconsts);
+static int ahd_probe_stack_size(struct ahd_softc *ahd);
#ifdef AHD_TARGET_MODE
static void ahd_queue_lstate_event(struct ahd_softc *ahd,
struct ahd_tmode_lstate *lstate,
@@ -429,6 +428,18 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
*/
seqintcode = ahd_inb(ahd, SEQINTCODE);
ahd_outb(ahd, CLRINT, CLRSEQINT);
+ if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+ /*
+ * Unpause the sequencer and let it clear
+ * SEQINT by writing NO_SEQINT to it. This
+ * will cause the sequencer to be paused again,
+ * which is the expected state of this routine.
+ */
+ ahd_unpause(ahd);
+ while (!ahd_is_paused(ahd))
+ ;
+ ahd_outb(ahd, CLRINT, CLRSEQINT);
+ }
ahd_update_modes(ahd);
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
@@ -464,16 +475,22 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
* CRC error with P0 asserted on last
* packet.
*/
- printf("Assuming LQIPHASE_NLQ with P0 assertion\n");
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+ printf("%s: Assuming LQIPHASE_NLQ with "
+ "P0 assertion\n", ahd_name(ahd));
+#endif
}
- printf("Entering NONPACK\n");
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+ printf("%s: Entering NONPACK\n", ahd_name(ahd));
+#endif
break;
}
case INVALID_SEQINT:
printf("%s: Invalid Sequencer interrupt occurred.\n",
ahd_name(ahd));
ahd_dump_card_state(ahd);
- printf("invalid seqint");
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
break;
case STATUS_OVERRUN:
@@ -601,16 +618,51 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
ahd_outb(ahd, CLRLQOINT1, 0);
}
- printf("Continuing non-pack processing...\n");
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+ ahd_print_path(ahd, scb);
+ printf("Unexpected command phase from "
+ "packetized target\n");
+ }
+#endif
break;
}
}
break;
}
case CFG4OVERRUN:
- printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
- ahd_inb(ahd, MODE_PTR));
+ {
+ struct scb *scb;
+ u_int scb_index;
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+ printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
+ ahd_inb(ahd, MODE_PTR));
+ }
+#endif
+ scb_index = ahd_get_scbptr(ahd);
+ scb = ahd_lookup_scb(ahd, scb_index);
+ if (scb == NULL) {
+ /*
+ * Attempt to transfer to an SCB that is
+ * not outstanding.
+ */
+ ahd_assert_atn(ahd);
+ ahd_outb(ahd, MSG_OUT, HOST_MSG);
+ ahd->msgout_buf[0] = MSG_ABORT_TASK;
+ ahd->msgout_len = 1;
+ ahd->msgout_index = 0;
+ ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+ /*
+ * Clear status received flag to prevent any
+ * attempt to complete this bogus SCB.
+ */
+ ahd_outb(ahd, SCB_CONTROL,
+ ahd_inb(ahd, SCB_CONTROL) & ~STATUS_RCVD);
+ }
break;
+ }
case DUMP_CARD_STATE:
{
ahd_dump_card_state(ahd);
@@ -618,10 +670,14 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
}
case PDATA_REINIT:
{
- printf("%s: PDATA_REINIT - DFCNTRL = 0x%x "
- "SG_CACHE_SHADOW = 0x%x\n",
- ahd_name(ahd), ahd_inb(ahd, DFCNTRL),
- ahd_inb(ahd, SG_CACHE_SHADOW));
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+ printf("%s: PDATA_REINIT - DFCNTRL = 0x%x "
+ "SG_CACHE_SHADOW = 0x%x\n",
+ ahd_name(ahd), ahd_inb(ahd, DFCNTRL),
+ ahd_inb(ahd, SG_CACHE_SHADOW));
+ }
+#endif
ahd_reinitialize_dataptrs(ahd);
break;
}
@@ -650,8 +706,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
if (bus_phase != P_MESGIN
&& bus_phase != P_MESGOUT) {
printf("ahd_intr: HOST_MSG_LOOP bad "
- "phase 0x%x\n",
- bus_phase);
+ "phase 0x%x\n", bus_phase);
/*
* Probably transitioned to bus free before
* we got here. Just punt the message.
@@ -780,20 +835,29 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
* no way of knowing how large the overrun was.
*/
struct scb *scb;
- u_int scbindex = ahd_get_scbptr(ahd);
- u_int lastphase = ahd_inb(ahd, LASTPHASE);
+ u_int scbindex;
+#ifdef AHD_DEBUG
+ u_int lastphase;
+#endif
+ scbindex = ahd_get_scbptr(ahd);
scb = ahd_lookup_scb(ahd, scbindex);
- ahd_print_path(ahd, scb);
- printf("data overrun detected %s."
- " Tag == 0x%x.\n",
- ahd_lookup_phase_entry(lastphase)->phasemsg,
- SCB_GET_TAG(scb));
- ahd_print_path(ahd, scb);
- printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n",
- ahd_inb(ahd, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
- ahd_get_transfer_length(scb), scb->sg_count);
- ahd_dump_sglist(scb);
+#ifdef AHD_DEBUG
+ lastphase = ahd_inb(ahd, LASTPHASE);
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+ ahd_print_path(ahd, scb);
+ printf("data overrun detected %s. Tag == 0x%x.\n",
+ ahd_lookup_phase_entry(lastphase)->phasemsg,
+ SCB_GET_TAG(scb));
+ ahd_print_path(ahd, scb);
+ printf("%s seen Data Phase. Length = %ld. "
+ "NumSGs = %d.\n",
+ ahd_inb(ahd, SEQ_FLAGS) & DPHASE
+ ? "Have" : "Haven't",
+ ahd_get_transfer_length(scb), scb->sg_count);
+ ahd_dump_sglist(scb);
+ }
+#endif
/*
* Set this and it will take effect when the
@@ -831,6 +895,18 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
ahd_inb(ahd, SCB_CONTROL) & ~MK_MESSAGE);
break;
}
+ case TRACEPOINT0:
+ case TRACEPOINT1:
+ case TRACEPOINT2:
+ case TRACEPOINT3:
+ printf("%s: Tracepoint %d\n", ahd_name(ahd),
+ seqintcode - TRACEPOINT0);
+ break;
+ case NO_SEQINT:
+ break;
+ case SAW_HWERR:
+ ahd_handle_hwerrint(ahd);
+ break;
default:
printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),
seqintcode);
@@ -854,6 +930,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
u_int lqistat1;
u_int lqostat0;
u_int scbid;
+ u_int busfreetime;
ahd_update_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
@@ -863,6 +940,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
lqistat1 = ahd_inb(ahd, LQISTAT1);
lqostat0 = ahd_inb(ahd, LQOSTAT0);
+ busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
if ((status0 & (SELDI|SELDO)) != 0) {
u_int simode0;
@@ -910,7 +988,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
ahd_outb(ahd, CLRLQOINT1, 0);
}
} else if ((status & SELTO) != 0) {
- u_int scbid;
+ u_int scbid;
/* Stop the selection */
ahd_outb(ahd, SCSISEQ0, 0);
@@ -938,8 +1016,8 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
"valid during SELTO scb(0x%x)\n",
ahd_name(ahd), scbid);
ahd_dump_card_state(ahd);
- panic("For diagnostics");
} else {
+ struct ahd_devinfo devinfo;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_SELTO) != 0) {
ahd_print_path(ahd, scb);
@@ -947,6 +1025,17 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
scbid);
}
#endif
+ /*
+ * Force a renegotiation with this target just in
+ * case the cable was pulled and will later be
+ * re-attached. The target may forget its negotiation
+ * settings with us should it attempt to reselect
+ * during the interruption. The target will not issue
+ * a unit attention in this case, so we must always
+ * renegotiate.
+ */
+ ahd_scb_devinfo(ahd, &devinfo, scb);
+ ahd_force_renegotiation(ahd, &devinfo);
ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahd_freeze_devq(ahd, scb);
}
@@ -963,7 +1052,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
ahd_handle_lqiphase_error(ahd, lqistat1);
} else if ((status & BUSFREE) != 0) {
- u_int busfreetime;
u_int lqostat1;
int restart;
int clear_fifo;
@@ -983,7 +1071,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
* the busfree.
*/
mode = AHD_MODE_SCSI;
- ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
lqostat1 = ahd_inb(ahd, LQOSTAT1);
switch (busfreetime) {
@@ -1075,6 +1162,8 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
static void
ahd_handle_transmission_error(struct ahd_softc *ahd)
{
+ struct scb *scb;
+ u_int scbid;
u_int lqistat1;
u_int lqistat2;
u_int msg_out;
@@ -1083,6 +1172,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
u_int perrdiag;
u_int cur_col;
+ scb = NULL;
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ);
lqistat2 = ahd_inb(ahd, LQISTAT2);
@@ -1094,8 +1184,12 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
lqistate = ahd_inb(ahd, LQISTATE);
if ((lqistate >= 0x1E && lqistate <= 0x24)
|| (lqistate == 0x29)) {
- printf("%s: NLQCRC found via LQISTATE\n",
- ahd_name(ahd));
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+ printf("%s: NLQCRC found via LQISTATE\n",
+ ahd_name(ahd));
+ }
+#endif
lqistat1 |= LQICRCI_NLQ;
}
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
@@ -1146,9 +1240,6 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
ahd_outb(ahd, LQCTL2, LQIRETRY);
printf("LQIRetry for LQICRCI_LQ to release ACK\n");
} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
- u_int scbid;
- struct scb *scb;
-
/*
* We detected a CRC error in a NON-LQ packet.
* The hardware has varying behavior in this situation
@@ -1188,7 +1279,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
* MSGOUT in or after a packet where P0 is not
* asserted, the hardware will assert LQIPHASE_NLQ.
* We should respond to the LQIPHASE_NLQ with an
- * LQICONTINUE. Should the target stay in a non-pkt
+ * LQIRETRY. Should the target stay in a non-pkt
* phase after we send our message, the hardware
* will assert LQIPHASE_LQ. Recovery is then just as
* listed above for the read streaming with P0 asserted.
@@ -1204,12 +1295,13 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
return;
}
- scb->flags |= SCB_TRANSMISSION_ERROR;
} else if ((lqistat1 & LQIBADLQI) != 0) {
printf("Need to handle BADLQI!\n");
ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
return;
} else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) {
+ scbid = ahd_get_scbptr(ahd);
+ scb = ahd_lookup_scb(ahd, scbid);
if ((curphase & ~P_DATAIN_DT) != 0) {
/* Ack the byte. So we can continue. */
printf("Acking %s to clear perror\n",
@@ -1229,6 +1321,8 @@ ahd_handle_transmission_error(struct ahd_softc *ahd)
* mesg_out to something other than MSG_NOP.
*/
ahd->send_msg_perror = msg_out;
+ if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR)
+ scb->flags |= SCB_TRANSMISSION_ERROR;
ahd_outb(ahd, MSG_OUT, HOST_MSG);
ahd_outb(ahd, CLRINT, CLRSCSIINT);
ahd_unpause(ahd);
@@ -1258,7 +1352,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1)
printf("LQIRETRY for LQIPHASE_LQ\n");
ahd_outb(ahd, LQCTL2, LQIRETRY);
} else if ((lqistat1 & LQIPHASE_NLQ) != 0) {
- printf("LQICONTINUE for LQIPHASE_NLQ\n");
+ printf("LQIRETRY for LQIPHASE_NLQ\n");
ahd_outb(ahd, LQCTL2, LQIRETRY);
} else
panic("ahd_handle_lqiphase_error: No phase errors\n");
@@ -1316,9 +1410,6 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
scb = ahd_lookup_scb(ahd, scbid);
if (scb == NULL)
panic("SCB not valid during LQOBUSFREE");
- ahd_print_path(ahd, scb);
- printf("Probable outgoing LQ CRC error. Retrying command\n");
-
/*
* Return the LQO manager to its idle loop. It will
* not do this automatically if the busfree occurs
@@ -1357,6 +1448,33 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
ahd_outw(ahd, SCB_NEXT2, next);
}
ahd_set_scbptr(ahd, saved_scbptr);
+ if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) {
+ ahd_print_path(ahd, scb);
+ printf("Probable outgoing LQ CRC error. "
+ "Retrying command\n");
+ scb->crc_retry_count++;
+ } else {
+ ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
+ ahd_freeze_scb(scb);
+ ahd_freeze_devq(ahd, scb);
+ }
+ /* Return unpausing the sequencer. */
+ return (0);
+ } else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) {
+ /*
+ * Ignore what are really parity errors that
+ * occur on the last REQ of a free running
+ * clock prior to going busfree. Some drives
+ * do not properly active negate just before
+ * going busfree resulting in a parity glitch.
+ */
+ ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE);
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0)
+ printf("%s: Parity on last REQ detected "
+ "during busfree phase.\n",
+ ahd_name(ahd));
+#endif
/* Return unpausing the sequencer. */
return (0);
}
@@ -1395,6 +1513,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
u_int target;
u_int initiator_role_id;
u_int scbid;
+ u_int ppr_busfree;
int printerror;
/*
@@ -1417,6 +1536,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
&& (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
scb = NULL;
+ ppr_busfree = (ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0;
if (lastphase == P_MESGOUT) {
u_int tag;
@@ -1482,7 +1602,8 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
"Bus Device Reset",
/*verbose_level*/0);
printerror = 0;
- } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE)) {
+ } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE)
+ && ppr_busfree == 0) {
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
@@ -1490,6 +1611,10 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
* PPR Rejected. Try non-ppr negotiation
* and retry command.
*/
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+ printf("PPR negotiation rejected busfree.\n");
+#endif
tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
devinfo.our_scsiid,
devinfo.target, &tstate);
@@ -1498,12 +1623,17 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
tinfo->goal.ppr_options = 0;
ahd_qinfifo_requeue_tail(ahd, scb);
printerror = 0;
- } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE)
- || ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)) {
+ } else if ((ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE)
+ || ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE))
+ && ppr_busfree == 0) {
/*
* Negotiation Rejected. Go-async and
* retry command.
*/
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+ printf("Negotiation rejected busfree.\n");
+#endif
ahd_set_width(ahd, &devinfo,
MSG_EXT_WDTR_BUS_8_BIT,
AHD_TRANS_CUR|AHD_TRANS_GOAL,
@@ -1524,6 +1654,15 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
printf("Expected IDE Busfree\n");
#endif
printerror = 0;
+ } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE)
+ && ahd_sent_msg(ahd, AHDMSG_1B,
+ MSG_MESSAGE_REJECT, TRUE)) {
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+ printf("Expected QAS Reject Busfree\n");
+#endif
+ printerror = 0;
}
}
@@ -1651,7 +1790,8 @@ ahd_handle_proto_violation(struct ahd_softc *ahd)
ahd_dump_card_state(ahd);
}
}
- if ((lastphase & ~P_DATAIN_DT) == 0) {
+ if ((lastphase & ~P_DATAIN_DT) == 0
+ || lastphase == P_COMMAND) {
proto_violation_reset:
/*
* Target either went directly to data
@@ -1697,16 +1837,19 @@ ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
struct ahd_initiator_tinfo *targ_info;
struct ahd_tmode_tstate *tstate;
- printf("Forcing renegotiation (%d:%c:%d)\n",
- devinfo->our_scsiid, devinfo->channel,
- devinfo->target);
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+ ahd_print_devinfo(ahd, devinfo);
+ printf("Forcing renegotiation\n");
+ }
+#endif
targ_info = ahd_fetch_transinfo(ahd,
devinfo->channel,
devinfo->our_scsiid,
devinfo->target,
&tstate);
ahd_update_neg_request(ahd, devinfo, tstate,
- targ_info, /*force*/TRUE);
+ targ_info, AHD_NEG_IF_NON_ASYNC);
}
#define AHD_MAX_STEPS 2000
@@ -1716,12 +1859,28 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
ahd_mode_state saved_modes;
int stepping;
int steps;
+ int first_instr;
+ u_int simode0;
+ u_int simode1;
+ u_int simode3;
+ u_int lqimode0;
+ u_int lqimode1;
+ u_int lqomode0;
+ u_int lqomode1;
if (ahd->num_critical_sections == 0)
return;
stepping = FALSE;
steps = 0;
+ first_instr = 0;
+ simode0 = 0;
+ simode1 = 0;
+ simode3 = 0;
+ lqimode0 = 0;
+ lqimode1 = 0;
+ lqomode0 = 0;
+ lqomode1 = 0;
saved_modes = ahd_save_modes(ahd);
for (;;) {
struct cs *cs;
@@ -1743,19 +1902,44 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
break;
if (steps > AHD_MAX_STEPS) {
- printf("%s: Infinite loop in critical section\n",
- ahd_name(ahd));
+ printf("%s: Infinite loop in critical section\n"
+ "%s: First Instruction 0x%x now 0x%x\n",
+ ahd_name(ahd), ahd_name(ahd), first_instr,
+ seqaddr);
ahd_dump_card_state(ahd);
panic("critical section loop");
}
steps++;
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MISC) != 0)
+ printf("%s: Single stepping at 0x%x\n", ahd_name(ahd),
+ seqaddr);
+#endif
if (stepping == FALSE) {
+ first_instr = seqaddr;
+ ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+ simode0 = ahd_inb(ahd, SIMODE0);
+ simode3 = ahd_inb(ahd, SIMODE3);
+ lqimode0 = ahd_inb(ahd, LQIMODE0);
+ lqimode1 = ahd_inb(ahd, LQIMODE1);
+ lqomode0 = ahd_inb(ahd, LQOMODE0);
+ lqomode1 = ahd_inb(ahd, LQOMODE1);
+ ahd_outb(ahd, SIMODE0, 0);
+ ahd_outb(ahd, SIMODE3, 0);
+ ahd_outb(ahd, LQIMODE0, 0);
+ ahd_outb(ahd, LQIMODE1, 0);
+ ahd_outb(ahd, LQOMODE0, 0);
+ ahd_outb(ahd, LQOMODE1, 0);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+ simode1 = ahd_inb(ahd, SIMODE1);
+ ahd_outb(ahd, SIMODE1, ENBUSFREE);
ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP);
stepping = TRUE;
}
+ ahd_outb(ahd, CLRSINT1, CLRBUSFREE);
+ ahd_outb(ahd, CLRINT, CLRSCSIINT);
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
ahd_outb(ahd, HCNTRL, ahd->unpause);
do {
@@ -1764,8 +1948,16 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
ahd_update_modes(ahd);
}
if (stepping) {
+ ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+ ahd_outb(ahd, SIMODE0, simode0);
+ ahd_outb(ahd, SIMODE3, simode3);
+ ahd_outb(ahd, LQIMODE0, lqimode0);
+ ahd_outb(ahd, LQIMODE1, lqimode1);
+ ahd_outb(ahd, LQOMODE0, lqomode0);
+ ahd_outb(ahd, LQOMODE1, lqomode1);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP);
+ ahd_outb(ahd, SIMODE1, simode1);
}
ahd_restore_modes(ahd, saved_modes);
}
@@ -1795,7 +1987,8 @@ ahd_clear_intstat(struct ahd_softc *ahd)
ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR);
ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
|CLRBUSFREE|CLRSCSIPERR|CLRREQINIT);
- ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO|CLRIOERR);
+ ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO
+ |CLRIOERR|CLROVERRUN);
ahd_outb(ahd, CLRINT, CLRSCSIINT);
}
@@ -1975,6 +2168,8 @@ ahd_devlimited_syncrate(struct ahd_softc *ahd,
else
transinfo = &tinfo->goal;
*ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN);
+ if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT)
+ maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2);
if (transinfo->period == 0) {
*period = 0;
*ppr_options = 0;
@@ -2014,6 +2209,9 @@ ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
*period = 0;
/* Honor PPR option conformance rules. */
+ if (*period > AHD_SYNCRATE_PACED)
+ *ppr_options &= ~MSG_EXT_PPR_RTI;
+
if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0)
*ppr_options &= (MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_QAS_REQ);
@@ -2036,10 +2234,13 @@ ahd_validate_offset(struct ahd_softc *ahd,
/* Limit offset to what we can do */
if (period == 0)
maxoffset = 0;
- else if (period <= AHD_SYNCRATE_PACED)
- maxoffset = MAX_OFFSET_PACED;
- else
- maxoffset = MAX_OFFSET;
+ else if (period <= AHD_SYNCRATE_PACED) {
+ if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0)
+ maxoffset = MAX_OFFSET_PACED_BUG;
+ else
+ maxoffset = MAX_OFFSET_PACED;
+ } else
+ maxoffset = MAX_OFFSET_NON_PACED;
*offset = MIN(*offset, maxoffset);
if (tinfo != NULL) {
if (role == ROLE_TARGET)
@@ -2086,17 +2287,29 @@ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
int
ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
struct ahd_tmode_tstate *tstate,
- struct ahd_initiator_tinfo *tinfo, int force)
+ struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type)
{
u_int auto_negotiate_orig;
auto_negotiate_orig = tstate->auto_negotiate;
+ if (neg_type == AHD_NEG_ALWAYS) {
+ /*
+ * Force our "current" settings to be
+ * unknown so that unless a bus reset
+ * occurs the need to renegotiate is
+ * recorded persistently.
+ */
+ tinfo->curr.period = AHD_PERIOD_UNKNOWN;
+ tinfo->curr.width = AHD_WIDTH_UNKNOWN;
+ tinfo->curr.offset = AHD_OFFSET_UNKNOWN;
+ tinfo->curr.ppr_options = AHD_OFFSET_UNKNOWN;
+ }
if (tinfo->curr.period != tinfo->goal.period
|| tinfo->curr.width != tinfo->goal.width
|| tinfo->curr.offset != tinfo->goal.offset
|| tinfo->curr.ppr_options != tinfo->goal.ppr_options
- || (force
- && (tinfo->goal.period != 0
+ || (neg_type == AHD_NEG_IF_NON_ASYNC
+ && (tinfo->goal.offset != 0
|| tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
|| tinfo->goal.ppr_options != 0)))
tstate->auto_negotiate |= devinfo->target_mask;
@@ -2200,8 +2413,10 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
if ((old_ppr & MSG_EXT_PPR_IU_REQ)
!= (ppr_options & MSG_EXT_PPR_IU_REQ)) {
#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+ ahd_print_devinfo(ahd, devinfo);
printf("Expecting IU Change busfree\n");
+ }
#endif
ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE
| MSG_FLAG_IU_REQ_CHANGED;
@@ -2217,7 +2432,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
}
update_needed += ahd_update_neg_request(ahd, devinfo, tstate,
- tinfo, /*force*/FALSE);
+ tinfo, AHD_NEG_TO_GOAL);
if (update_needed && active)
ahd_update_pending_scbs(ahd);
@@ -2276,7 +2491,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
}
update_needed += ahd_update_neg_request(ahd, devinfo, tstate,
- tinfo, /*force*/FALSE);
+ tinfo, AHD_NEG_TO_GOAL);
if (update_needed && active)
ahd_update_pending_scbs(ahd);
@@ -2303,7 +2518,7 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int ppr_opts;
u_int con_opts;
u_int offset;
- u_int precomp;
+ uint8_t iocell_opts[sizeof(ahd->iocell_opts)];
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
@@ -2311,42 +2526,66 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd_outb(ahd, NEGOADDR, devinfo->target);
period = tinfo->period;
offset = tinfo->offset;
- precomp = 0;
+ memcpy(iocell_opts, ahd->iocell_opts, sizeof(ahd->iocell_opts));
+ ppr_opts = tinfo->ppr_options & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ
+ |MSG_EXT_PPR_IU_REQ|MSG_EXT_PPR_RTI);
+ con_opts = 0;
if (period == 0)
period = AHD_SYNCRATE_ASYNC;
if (period == AHD_SYNCRATE_160) {
- period = AHD_SYNCRATE_REVA_160;
- precomp = 0;
- if ((ahd->flags & AHD_CPQ_BOARD) == 0)
- precomp |= AHD_PRECOMP_FASTSLEW;
- if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) != 0)
- precomp |= AHD_PRECOMP_CUTBACK_29;
+
+ if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) {
+ /*
+ * When the SPI4 spec was finalized, PACE transfers
+ * was not made a configurable option in the PPR
+ * message. Instead it is assumed to be enabled for
+ * any syncrate faster than 80MHz. Nevertheless,
+ * Harpoon2A4 allows this to be configurable.
+ *
+ * Harpoon2A4 also assumes at most 2 data bytes per
+ * negotiated REQ/ACK offset. Paced transfers take
+ * 4, so we must adjust our offset.
+ */
+ ppr_opts |= PPROPT_PACE;
+ offset *= 2;
+
+ /*
+ * Harpoon2A assumed that there would be a
+ * fallback rate between 160MHz and 80Mhz,
+ * so 7 is used as the period factor rather
+ * than 8 for 160MHz.
+ */
+ period = AHD_SYNCRATE_REVA_160;
+ }
+ if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) == 0)
+ iocell_opts[AHD_PRECOMP_SLEW_INDEX] &=
+ ~AHD_PRECOMP_MASK;
+ } else {
+ /*
+ * Precomp should be disabled for non-paced transfers.
+ */
+ iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK;
+
+ if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0
+ && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0) {
+ /*
+ * Slow down our CRC interval to be
+ * compatible with devices that can't
+ * handle a CRC at full speed.
+ */
+ con_opts |= ENSLOWCRC;
+ }
}
- ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP);
- ahd_outb(ahd, ANNEXDAT, precomp);
+
+ ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW);
+ ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_PRECOMP_SLEW_INDEX]);
+ ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_AMPLITUDE);
+ ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_AMPLITUDE_INDEX]);
ahd_outb(ahd, NEGPERIOD, period);
- ppr_opts = tinfo->ppr_options
- & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_IU_REQ);
- /*
- * When the SPI4 spec was finalized, PACE transfers
- * was not made a configurable option in the PPR message.
- * Instead it is assumed to be enabled for any
- * syncrate faster than 80MHz. Nevertheless, Harpoon
- * allows this to be configurable.
- *
- * Harpoon also assumes at most 2 data bytes per negotiated
- * REQ/ACK offset. Paced transfers take 4, so we must
- * adjust our offset.
- */
- if (period <= AHD_SYNCRATE_PACED) {
- ppr_opts |= PPROPT_PACE;
- offset *= 2;
- }
ahd_outb(ahd, NEGPPROPTS, ppr_opts);
ahd_outb(ahd, NEGOFFSET, offset);
- con_opts = 0;
if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT)
con_opts |= WIDEXFER;
@@ -2490,10 +2729,10 @@ ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
ahd_restore_modes(ahd, saved_modes);
}
-static void
+void
ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
{
- printf("%s:%c:%d:%d:", ahd_name(ahd), 'A',
+ printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A',
devinfo->target, devinfo->lun);
}
@@ -2573,7 +2812,10 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
ahd->msgout_buf[ahd->msgout_index++] = ahd->send_msg_perror;
ahd->msgout_len++;
ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
- printf("Setting up for Parity Error delivery\n");
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+ printf("Setting up for Parity Error delivery\n");
+#endif
return;
} else if (scb == NULL) {
printf("%s: WARNING. No pending message for "
@@ -2683,7 +2925,6 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
int dowide;
int dosync;
int doppr;
- int use_ppr;
u_int period;
u_int ppr_options;
u_int offset;
@@ -2705,23 +2946,36 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
&ppr_options, devinfo->role);
dowide = tinfo->curr.width != tinfo->goal.width;
dosync = tinfo->curr.period != period;
- doppr = tinfo->curr.ppr_options != ppr_options;
+ /*
+ * Only use PPR if we have options that need it, even if the device
+ * claims to support it. There might be an expander in the way
+ * that doesn't.
+ */
+ doppr = ppr_options != 0;
if (!dowide && !dosync && !doppr) {
dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
dosync = tinfo->goal.period != 0;
- doppr = tinfo->goal.ppr_options != 0;
}
if (!dowide && !dosync && !doppr) {
- panic("ahd_intr: AWAITING_MSG for negotiation, "
- "but no negotiation needed\n");
- }
+ /*
+ * Force async with a WDTR message if we have a wide bus,
+ * or just issue an SDTR with a 0 offset.
+ */
+ if ((ahd->features & AHD_WIDE) != 0)
+ dowide = 1;
+ else
+ dosync = 1;
- use_ppr = (tinfo->curr.transport_version >= 3) || doppr;
+ if (bootverbose) {
+ ahd_print_devinfo(ahd, devinfo);
+ printf("Ensuring async\n");
+ }
+ }
/* Target initiated PPR is not allowed in the SCSI spec */
if (devinfo->role == ROLE_TARGET)
- use_ppr = 0;
+ doppr = 0;
/*
* Both the PPR message and SDTR message require the
@@ -2731,14 +2985,14 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
* Regardless, guarantee that if we are using WDTR and SDTR
* messages that WDTR comes first.
*/
- if (use_ppr || (dosync && !dowide)) {
+ if (doppr || (dosync && !dowide)) {
offset = tinfo->goal.offset;
ahd_validate_offset(ahd, tinfo, period, &offset,
- use_ppr ? tinfo->goal.width
- : tinfo->curr.width,
+ doppr ? tinfo->goal.width
+ : tinfo->curr.width,
devinfo->role);
- if (use_ppr) {
+ if (doppr) {
ahd_construct_ppr(ahd, devinfo, period, offset,
tinfo->goal.width, ppr_options);
} else {
@@ -2757,6 +3011,8 @@ static void
ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
u_int period, u_int offset)
{
+ if (offset == 0)
+ period = AHD_ASYNC_XFER_PERIOD;
ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR_LEN;
ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR;
@@ -2806,6 +3062,8 @@ ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
*/
if (period <= AHD_SYNCRATE_PACED)
ppr_options |= MSG_EXT_PPR_PCOMP_EN;
+ if (offset == 0)
+ period = AHD_ASYNC_XFER_PERIOD;
ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR_LEN;
ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR;
@@ -3605,8 +3863,12 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
}
#endif
case MSG_QAS_REQUEST:
- printf("%s: QAS request. SCSISIGI == 0x%x\n",
- ahd_name(ahd), ahd_inb(ahd, SCSISIGI));
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+ printf("%s: QAS request. SCSISIGI == 0x%x\n",
+ ahd_name(ahd), ahd_inb(ahd, SCSISIGI));
+#endif
+ ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE;
/* FALLTHROUGH */
case MSG_TERM_IO_PROC:
default:
@@ -3660,19 +3922,38 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
last_msg = ahd_inb(ahd, LAST_MSG);
if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) {
- /*
- * Target does not support the PPR message.
- * Attempt to negotiate SPI-2 style.
- */
- if (bootverbose) {
- printf("(%s:%c:%d:%d): PPR Rejected. "
- "Trying WDTR/SDTR\n",
- ahd_name(ahd), devinfo->channel,
- devinfo->target, devinfo->lun);
+ if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/TRUE)
+ && tinfo->goal.period <= AHD_SYNCRATE_PACED) {
+ /*
+ * Target may not like our SPI-4 PPR Options.
+ * Attempt to negotiate 80MHz which will turn
+ * off these options.
+ */
+ if (bootverbose) {
+ printf("(%s:%c:%d:%d): PPR Rejected. "
+ "Trying simple U160 PPR\n",
+ ahd_name(ahd), devinfo->channel,
+ devinfo->target, devinfo->lun);
+ }
+ tinfo->goal.period = AHD_SYNCRATE_DT;
+ tinfo->goal.ppr_options &= MSG_EXT_PPR_IU_REQ
+ | MSG_EXT_PPR_QAS_REQ
+ | MSG_EXT_PPR_DT_REQ;
+ } else {
+ /*
+ * Target does not support the PPR message.
+ * Attempt to negotiate SPI-2 style.
+ */
+ if (bootverbose) {
+ printf("(%s:%c:%d:%d): PPR Rejected. "
+ "Trying WDTR/SDTR\n",
+ ahd_name(ahd), devinfo->channel,
+ devinfo->target, devinfo->lun);
+ }
+ tinfo->goal.ppr_options = 0;
+ tinfo->curr.transport_version = 2;
+ tinfo->goal.transport_version = 2;
}
- tinfo->goal.ppr_options = 0;
- tinfo->curr.transport_version = 2;
- tinfo->goal.transport_version = 2;
ahd->msgout_index = 0;
ahd->msgout_len = 0;
ahd_build_transfer_msg(ahd, devinfo);
@@ -3963,7 +4244,8 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
saved_modes = ahd_save_modes(ahd);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, DFFSTAT,
- ahd_inb(ahd, DFFSTAT) | (saved_modes == 0x11 ? CURRFIFO : 0));
+ ahd_inb(ahd, DFFSTAT)
+ | (saved_modes == 0x11 ? CURRFIFO_1 : CURRFIFO_0));
/*
* Determine initial values for data_addr and data_cnt
@@ -4373,6 +4655,8 @@ ahd_free(struct ahd_softc *ahd)
free(ahd->name, M_DEVBUF);
if (ahd->seep_config != NULL)
free(ahd->seep_config, M_DEVBUF);
+ if (ahd->saved_stack != NULL)
+ free(ahd->saved_stack, M_DEVBUF);
#ifndef __FreeBSD__
free(ahd, M_DEVBUF);
#endif
@@ -5187,6 +5471,12 @@ ahd_init(struct ahd_softc *ahd)
AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+ ahd->stack_size = ahd_probe_stack_size(ahd);
+ ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t),
+ M_DEVBUF, M_NOWAIT);
+ if (ahd->saved_stack == NULL)
+ return (ENOMEM);
+
/*
* Verify that the compiler hasn't over-agressively
* padded important structures.
@@ -5301,6 +5591,13 @@ ahd_init(struct ahd_softc *ahd)
if ((ahd->flags & AHD_INITIATORROLE) == 0)
ahd->flags &= ~AHD_RESET_BUS_A;
+ /*
+ * Before committing these settings to the chip, give
+ * the OSM one last chance to modify our configuration.
+ */
+ ahd_platform_init(ahd);
+
+ /* Bring up the chip. */
ahd_chip_init(ahd);
AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
@@ -5455,6 +5752,7 @@ ahd_chip_init(struct ahd_softc *ahd)
} else {
ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE);
}
+ ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN);
if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX)
/*
* Do not issue a target abort when a split completion
@@ -5463,18 +5761,21 @@ ahd_chip_init(struct ahd_softc *ahd)
*/
ahd_outb(ahd, PCIXCTL, ahd_inb(ahd, PCIXCTL) | SPLTSTADIS);
+ if ((ahd->bugs & AHD_LQOOVERRUN_BUG) != 0)
+ ahd_outb(ahd, LQOSCSCTL, LQONOCHKOVER);
+
/*
* Tweak IOCELL settings.
*/
- if ((ahd->flags & AHD_CPQ_BOARD) != 0) {
+ if ((ahd->flags & AHD_HP_BOARD) != 0) {
for (i = 0; i < NUMDSPS; i++) {
ahd_outb(ahd, DSPSELECT, i);
- ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_CPQ_DEFAULT);
+ ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_HP_DEFAULT);
}
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_MISC) != 0)
printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
- WRTBIASCTL_CPQ_DEFAULT);
+ WRTBIASCTL_HP_DEFAULT);
#endif
}
ahd_setup_iocell_workaround(ahd);
@@ -5534,17 +5835,32 @@ ahd_chip_init(struct ahd_softc *ahd)
ahd_outb(ahd, MULTARGID + 1, 0);
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
- /*
- * Clear the spare bytes in the neg table to avoid
- * spurious parity errors.
- */
+ /* Initialize the negotiation table. */
+ if ((ahd->features & AHD_NEW_IOCELL_OPTS) == 0) {
+ /*
+ * Clear the spare bytes in the neg table to avoid
+ * spurious parity errors.
+ */
+ for (target = 0; target < AHD_NUM_TARGETS; target++) {
+ ahd_outb(ahd, NEGOADDR, target);
+ ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PER_DEV0);
+ for (i = 0; i < AHD_NUM_PER_DEV_ANNEXCOLS; i++)
+ ahd_outb(ahd, ANNEXDAT, 0);
+ }
+ }
for (target = 0; target < AHD_NUM_TARGETS; target++) {
+ struct ahd_devinfo devinfo;
+ struct ahd_initiator_tinfo *tinfo;
+ struct ahd_tmode_tstate *tstate;
- ahd_outb(ahd, NEGOADDR, target);
- ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP);
- for (i = 0; i < AHD_NUM_ANNEXCOLS; i++)
- ahd_outb(ahd, ANNEXDAT, 0);
+ tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+ target, &tstate);
+ ahd_compile_devinfo(&devinfo, ahd->our_id,
+ target, CAM_LUN_WILDCARD,
+ 'A', ROLE_INITIATOR);
+ ahd_update_neg_table(ahd, &devinfo, &tinfo->curr);
}
+
ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR);
ahd_outb(ahd, CLRINT, CLRSCSIINT);
@@ -5633,15 +5949,6 @@ ahd_chip_init(struct ahd_softc *ahd)
}
/*
- * Always enable abort on incoming L_Qs if this feature is
- * supported. We use this to catch invalid SCB references.
- */
- if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0)
- ahd_outb(ahd, LQCTL1, ABORTPENDING);
- else
- ahd_outb(ahd, LQCTL1, 0);
-
- /*
* Initialize the group code to command length table.
* Vendor Unique codes are set to 0 so we only capture
* the first byte of the cdb. These can be overridden
@@ -5731,6 +6038,8 @@ ahd_default_config(struct ahd_softc *ahd)
| MSG_EXT_PPR_IU_REQ
| MSG_EXT_PPR_QAS_REQ
| MSG_EXT_PPR_DT_REQ;
+ if ((ahd->features & AHD_RTI) != 0)
+ tinfo->user.ppr_options |= MSG_EXT_PPR_RTI;
tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
@@ -5751,13 +6060,6 @@ ahd_default_config(struct ahd_softc *ahd)
ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0,
/*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL,
/*paused*/TRUE);
- /*
- * The neg table must be initialized even if the
- * new settings above are the same as those from
- * when our xfer info data structures were allocated
- * and initialized.
- */
- ahd_update_neg_table(ahd, &devinfo, &tinfo->curr);
}
return (0);
}
@@ -5832,11 +6134,14 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
user_tinfo->period = AHD_SYNCRATE_DT;
#endif
- if ((sc->device_flags[targ] & CFPACKETIZED) != 0)
+ if ((sc->device_flags[targ] & CFPACKETIZED) != 0) {
user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM
| MSG_EXT_PPR_WR_FLOW
| MSG_EXT_PPR_HOLD_MCS
| MSG_EXT_PPR_IU_REQ;
+ if ((ahd->features & AHD_RTI) != 0)
+ user_tinfo->ppr_options |= MSG_EXT_PPR_RTI;
+ }
if ((sc->device_flags[targ] & CFQAS) != 0)
user_tinfo->ppr_options |= MSG_EXT_PPR_QAS_REQ;
@@ -5868,13 +6173,6 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0,
/*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL,
/*paused*/TRUE);
- /*
- * The neg table must be initialized even if the
- * new settings above are the same as those from
- * when our xfer info data structures were allocated
- * and initialized.
- */
- ahd_update_neg_table(ahd, &devinfo, &tinfo->curr);
}
ahd->flags &= ~AHD_SPCHK_ENB_A;
@@ -6204,8 +6502,11 @@ ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
void
ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb)
{
- struct scb *prev_scb;
+ struct scb *prev_scb;
+ ahd_mode_state saved_modes;
+ saved_modes = ahd_save_modes(ahd);
+ ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
prev_scb = NULL;
if (ahd_qinfifo_count(ahd) != 0) {
u_int prev_tag;
@@ -6217,6 +6518,7 @@ ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb)
}
ahd_qinfifo_requeue(ahd, prev_scb, scb);
ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+ ahd_restore_modes(ahd, saved_modes);
}
static void
@@ -6762,8 +7064,11 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
* actively connected).
*/
next_fifo = fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO;
+ if (next_fifo > CURRFIFO_1)
+ /* If disconneced, arbitrarily start with FIFO1. */
+ next_fifo = fifo = 0;
do {
- next_fifo = next_fifo ^ CURRFIFO;
+ next_fifo ^= CURRFIFO_1;
ahd_set_modes(ahd, next_fifo, next_fifo);
ahd_outb(ahd, DFCNTRL,
ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN));
@@ -6775,7 +7080,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
ahd_outb(ahd, DFFSTAT, next_fifo);
} while (next_fifo != fifo);
-
/*
* Reset the bus if we are initiating this reset
*/
@@ -6977,7 +7281,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
siu = (struct scsi_status_iu_header *)scb->sense_data;
ahd_set_scsi_status(scb, siu->status);
#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_SENSE) != 0)
+ if ((ahd_debug & AHD_SHOW_SENSE) != 0) {
ahd_print_path(ahd, scb);
printf("SCB 0x%x Received PKT Status of 0x%x\n",
SCB_GET_TAG(scb), siu->status);
@@ -6985,6 +7289,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
"pktfail = 0x%x\n",
siu->flags, scsi_4btoul(siu->sense_length),
scsi_4btoul(siu->pkt_failures_length));
+ }
#endif
if ((siu->flags & SIU_RSPVALID) != 0) {
ahd_print_path(ahd, scb);
@@ -7105,7 +7410,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
if (ahd_get_residual(scb) == ahd_get_transfer_length(scb)) {
ahd_update_neg_request(ahd, &devinfo,
tstate, targ_info,
- /*force*/TRUE);
+ AHD_NEG_IF_NON_ASYNC);
}
if (tstate->auto_negotiate & devinfo.target_mask) {
hscb->control |= MK_MESSAGE;
@@ -7117,16 +7422,11 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
ahd_setup_data_scb(ahd, scb);
scb->flags |= SCB_SENSE;
ahd_queue_scb(ahd, scb);
-#ifdef __FreeBSD__
/*
* Ensure we have enough time to actually
* retrieve the sense.
*/
- untimeout(ahd_timeout, (caddr_t)scb,
- scb->io_ctx->ccb_h.timeout_ch);
- scb->io_ctx->ccb_h.timeout_ch =
- timeout(ahd_timeout, (caddr_t)scb, 5 * hz);
-#endif
+ ahd_scb_timer_reset(scb, 5 * 1000000);
break;
}
case SCSI_STATUS_OK:
@@ -7643,6 +7943,41 @@ ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts)
}
}
+static int
+ahd_probe_stack_size(struct ahd_softc *ahd)
+{
+ int last_probe;
+
+ last_probe = 0;
+ while (1) {
+ int i;
+
+ /*
+ * We avoid using 0 as a pattern to avoid
+ * confusion if the stack implementation
+ * "back-fills" with zeros when "poping'
+ * entries.
+ */
+ for (i = 1; i <= last_probe+1; i++) {
+ ahd_outb(ahd, STACK, i & 0xFF);
+ ahd_outb(ahd, STACK, (i >> 8) & 0xFF);
+ }
+
+ /* Verify */
+ for (i = last_probe+1; i > 0; i--) {
+ u_int stack_entry;
+
+ stack_entry = ahd_inb(ahd, STACK)
+ |(ahd_inb(ahd, STACK) << 8);
+ if (stack_entry != i)
+ goto sized;
+ }
+ last_probe++;
+ }
+sized:
+ return (last_probe);
+}
+
void
ahd_dump_all_cards_state()
{
@@ -7661,7 +7996,7 @@ ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
int printed;
u_int printed_mask;
- if (*cur_column >= wrap_point) {
+ if (cur_column != NULL && *cur_column >= wrap_point) {
printf("\n");
*cur_column = 0;
}
@@ -7696,7 +8031,8 @@ ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
printed += printf(") ");
else
printed += printf(" ");
- *cur_column += printed;
+ if (cur_column != NULL)
+ *cur_column += printed;
return (printed);
}
@@ -7709,8 +8045,8 @@ ahd_dump_card_state(struct ahd_softc *ahd)
int paused;
u_int scb_index;
u_int saved_scb_index;
- u_int i;
u_int cur_col;
+ int i;
if (ahd_is_paused(ahd)) {
paused = 1;
@@ -7732,15 +8068,19 @@ ahd_dump_card_state(struct ahd_softc *ahd)
* Mode independent registers.
*/
cur_col = 0;
- ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50);
- ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50);
- ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50);
+ ahd_saved_mode_print(ahd_inb(ahd, SAVED_MODE), &cur_col, 50);
+ ahd_dffstat_print(ahd_inb(ahd, DFFSTAT), &cur_col, 50);
ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50);
ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50);
ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50);
ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50);
+ ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50);
+ ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50);
+ ahd_seqctl0_print(ahd_inb(ahd, SEQCTL0), &cur_col, 50);
+ ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50);
ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50);
ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50);
+ ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50);
ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50);
ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50);
ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50);
@@ -7866,7 +8206,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
printf("\n");
cur_col = 0;
}
- cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x",
+ cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ",
ahd_inl(ahd, HADDR+4),
ahd_inl(ahd, HADDR),
(ahd_inb(ahd, HCNT)
@@ -7892,6 +8232,8 @@ ahd_dump_card_state(struct ahd_softc *ahd)
printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT),
ahd_inb(ahd, MAXCMDCNT));
+ ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50);
+ printf("\n");
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n",
ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX),
@@ -7907,8 +8249,15 @@ ahd_dump_card_state(struct ahd_softc *ahd)
ahd_inb(ahd, SCB_CDB_STORE+4),
ahd_inb(ahd, SCB_CDB_STORE+5));
printf("STACK:");
- for(i = 0; i < SEQ_STACK_SIZE; i++)
- printf(" 0x%x", ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8));
+ for (i = 0; i < ahd->stack_size; i++) {
+ ahd->saved_stack[i] =
+ ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8);
+ printf(" 0x%x", ahd->saved_stack[i]);
+ }
+ for (i = ahd->stack_size-1; i >= 0; i--) {
+ ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF);
+ ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF);
+ }
printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
ahd_platform_dump_card_state(ahd);
ahd_restore_modes(ahd, saved_modes);
diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h
index 293e01caffcb..2f9a47e49e5c 100644
--- a/sys/dev/aic7xxx/aic79xx.h
+++ b/sys/dev/aic7xxx/aic79xx.h
@@ -37,7 +37,7 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#61 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#73 $
*
* $FreeBSD$
*/
@@ -213,14 +213,17 @@ typedef enum {
* Features available in each chip type.
*/
typedef enum {
- AHD_FENONE = 0x00000,
- AHD_WIDE = 0x00001, /* Wide Channel */
- AHD_MULTI_FUNC = 0x00100, /* Multi-Function Twin Channel Device */
- AHD_TARGETMODE = 0x01000, /* Has tested target mode support */
- AHD_MULTIROLE = 0x02000, /* Space for two roles at a time */
- AHD_REMOVABLE = 0x00000, /* Hot-Swap supported - None so far*/
- AHD_AIC7901_FE = AHD_FENONE,
- AHD_AIC7902_FE = AHD_MULTI_FUNC
+ AHD_FENONE = 0x00000,
+ AHD_WIDE = 0x00001,/* Wide Channel */
+ AHD_MULTI_FUNC = 0x00100,/* Multi-Function/Channel Device */
+ AHD_TARGETMODE = 0x01000,/* Has tested target mode support */
+ AHD_MULTIROLE = 0x02000,/* Space for two roles at a time */
+ AHD_RTI = 0x04000,/* Retained Training Support */
+ AHD_NEW_IOCELL_OPTS = 0x08000,/* More Signal knobs in the IOCELL */
+ AHD_NEW_DFCNTRL_OPTS = 0x10000,/* SCSIENWRDIS bit */
+ AHD_REMOVABLE = 0x00000,/* Hot-Swap supported - None so far*/
+ AHD_AIC7901_FE = AHD_FENONE,
+ AHD_AIC7902_FE = AHD_MULTI_FUNC
} ahd_feature;
/*
@@ -228,26 +231,77 @@ typedef enum {
*/
typedef enum {
AHD_BUGNONE = 0x0000,
+ /*
+ * Rev A hardware fails to update LAST/CURR/NEXTSCB
+ * correctly in certain packetized selection cases.
+ */
AHD_SENT_SCB_UPDATE_BUG = 0x0001,
+ /* The wrong SCB is accessed to check the abort pending bit. */
AHD_ABORT_LQI_BUG = 0x0002,
+ /* Packetized bitbucket crosses packet boundaries. */
AHD_PKT_BITBUCKET_BUG = 0x0004,
+ /* The selection timer runs twice as long as its setting. */
AHD_LONG_SETIMO_BUG = 0x0008,
+ /* The Non-LQ CRC error status is delayed until phase change. */
AHD_NLQICRC_DELAYED_BUG = 0x0010,
+ /* The chip must be reset for all outgoing bus resets. */
AHD_SCSIRST_BUG = 0x0020,
+ /* Some PCIX fields must be saved and restored across chip reset. */
AHD_PCIX_CHIPRST_BUG = 0x0040,
+ /* MMAPIO is not functional in PCI-X mode. */
AHD_PCIX_MMAPIO_BUG = 0x0080,
/* Bug workarounds that can be disabled on non-PCIX busses. */
AHD_PCIX_BUG_MASK = AHD_PCIX_CHIPRST_BUG
| AHD_PCIX_MMAPIO_BUG,
+ /*
+ * LQOSTOP0 status set even for forced selections with ATN
+ * to perform non-packetized message delivery.
+ */
AHD_LQO_ATNO_BUG = 0x0100,
+ /* FIFO auto-flush does not always trigger. */
AHD_AUTOFLUSH_BUG = 0x0200,
+ /* The CLRLQO registers are not self-clearing. */
AHD_CLRLQO_AUTOCLR_BUG = 0x0400,
+ /* The PACKETIZED status bit refers to the previous connection. */
AHD_PKTIZED_STATUS_BUG = 0x0800,
+ /* "Short Luns" are not placed into outgoing LQ packets correctly. */
AHD_PKT_LUN_BUG = 0x1000,
- AHD_MDFF_WSCBPTR_BUG = 0x2000,
- AHD_REG_SLOW_SETTLE_BUG = 0x4000,
- AHD_SET_MODE_BUG = 0x8000,
- AHD_BUSFREEREV_BUG = 0x10000
+ /*
+ * Only the FIFO allocated to the non-packetized connection may
+ * be in use during a non-packetzied connection.
+ */
+ AHD_NONPACKFIFO_BUG = 0x2000,
+ /*
+ * Writing to a DFF SCBPTR register may fail if concurent with
+ * a hardware write to the other DFF SCBPTR register. This is
+ * not currently a concern in our sequencer since all chips with
+ * this bug have the AHD_NONPACKFIFO_BUG and all writes of concern
+ * occur in non-packetized connections.
+ */
+ AHD_MDFF_WSCBPTR_BUG = 0x4000,
+ /* SGHADDR updates are slow. */
+ AHD_REG_SLOW_SETTLE_BUG = 0x8000,
+ /*
+ * Changing the MODE_PTR coincident with an interrupt that
+ * switches to a different mode will cause the interrupt to
+ * be in the mode written outside of interrupt context.
+ */
+ AHD_SET_MODE_BUG = 0x10000,
+ /* Non-packetized busfree revision does not work. */
+ AHD_BUSFREEREV_BUG = 0x20000,
+ /*
+ * Paced transfers are indicated with a non-standard PPR
+ * option bit in the neg table, 160MHz is indicated by
+ * sync factor 0x7, and the offset if off by a factor of 2.
+ */
+ AHD_PACED_NEGTABLE_BUG = 0x40000,
+ /* LQOOVERRUN false positives. */
+ AHD_LQOOVERRUN_BUG = 0x80000,
+ /*
+ * Controller write to INTSTAT will lose to a host
+ * write to CLRINT.
+ */
+ AHD_INTCOLLISION_BUG = 0x100000
} ahd_bug;
/*
@@ -293,7 +347,7 @@ typedef enum {
AHD_64BIT_ADDRESSING = 0x20000,/* Use 64 bit addressing scheme. */
AHD_CURRENT_SENSING = 0x40000,
AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */
- AHD_CPQ_BOARD = 0x100000,
+ AHD_HP_BOARD = 0x100000,
AHD_RESET_POLL_ACTIVE = 0x200000
} ahd_flag;
@@ -500,13 +554,13 @@ typedef enum {
SCB_AUTO_NEGOTIATE = 0x00040,/* Negotiate to achieve goal. */
SCB_NEGOTIATE = 0x00080,/* Negotiation forced for command. */
SCB_ABORT = 0x00100,
- SCB_ACTIVE = 0x00400,
- SCB_TARGET_IMMEDIATE = 0x00800,
- SCB_PACKETIZED = 0x01000,
- SCB_EXPECT_PPR_BUSFREE = 0x02000,
- SCB_PKT_SENSE = 0x04000,
- SCB_CMDPHASE_ABORT = 0x08000,
- SCB_ON_COL_LIST = 0x10000
+ SCB_ACTIVE = 0x00200,
+ SCB_TARGET_IMMEDIATE = 0x00400,
+ SCB_PACKETIZED = 0x00800,
+ SCB_EXPECT_PPR_BUSFREE = 0x01000,
+ SCB_PKT_SENSE = 0x02000,
+ SCB_CMDPHASE_ABORT = 0x04000,
+ SCB_ON_COL_LIST = 0x08000
} scb_flag;
struct scb {
@@ -539,6 +593,8 @@ struct scb {
bus_addr_t sg_list_busaddr;
bus_addr_t sense_busaddr;
u_int sg_count;/* How full ahd_dma_seg is */
+#define AHD_MAX_LQ_CRC_ERRORS 5
+ u_int crc_retry_count;
};
TAILQ_HEAD(scb_tailq, scb);
@@ -654,6 +710,11 @@ struct ahd_tmode_lstate;
#define AHD_PERIOD_ASYNC 0xFF
#define AHD_PERIOD_10MHz 0x19
+#define AHD_WIDTH_UNKNOWN 0xFF
+#define AHD_PERIOD_UNKNOWN 0xFF
+#define AHD_OFFSET_UNKNOWN 0x0
+#define AHD_PPR_OPTS_UNKNOWN 0xFF
+
/*
* Transfer Negotiation Information.
*/
@@ -708,6 +769,9 @@ struct ahd_tmode_tstate {
#define AHD_SYNCRATE_MIN 0x60
#define AHD_SYNCRATE_ASYNC 0xFF
+/* Safe and valid period for async negotiations. */
+#define AHD_ASYNC_XFER_PERIOD 0x44
+
/*
* In RevA, the synctable uses a 120MHz rate for the period
* factor 8 and 160MHz for the period factor 7. The 120MHz
@@ -852,7 +916,8 @@ typedef enum {
MSG_FLAG_EXPECT_PPR_BUSFREE = 0x01,
MSG_FLAG_IU_REQ_CHANGED = 0x02,
MSG_FLAG_EXPECT_IDE_BUSFREE = 0x04,
- MSG_FLAG_PACKETIZED = 0x08
+ MSG_FLAG_EXPECT_QASREJ_BUSFREE = 0x08,
+ MSG_FLAG_PACKETIZED = 0x10
} ahd_msg_flags;
typedef enum {
@@ -1023,11 +1088,6 @@ struct ahd_softc {
uint8_t our_id;
/*
- * PCI error detection.
- */
- int unsolicited_ints;
-
- /*
* Target incoming command FIFO.
*/
struct target_cmd *targetcmds;
@@ -1066,6 +1126,12 @@ struct ahd_softc {
/* PCI cacheline size. */
u_int pci_cachesize;
+ /* IO Cell Parameters */
+ uint8_t iocell_opts[AHD_NUM_PER_DEV_ANNEXCOLS];
+
+ u_int stack_size;
+ uint16_t *saved_stack;
+
/* Per-Unit descriptive information */
const char *description;
const char *bus_description;
@@ -1082,6 +1148,34 @@ struct ahd_softc {
TAILQ_HEAD(ahd_softc_tailq, ahd_softc);
extern struct ahd_softc_tailq ahd_tailq;
+/*************************** IO Cell Configuration ****************************/
+#define AHD_PRECOMP_SLEW_INDEX \
+ (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0)
+
+#define AHD_AMPLITUDE_INDEX \
+ (AHD_ANNEXCOL_AMPLITUDE - AHD_ANNEXCOL_PER_DEV0)
+
+#define AHD_SET_SLEWRATE(ahd, new_slew) \
+do { \
+ (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_SLEWRATE_MASK; \
+ (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |= \
+ (((new_slew) << AHD_SLEWRATE_SHIFT) & AHD_SLEWRATE_MASK); \
+} while (0)
+
+#define AHD_SET_PRECOMP(ahd, new_pcomp) \
+do { \
+ (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; \
+ (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |= \
+ (((new_pcomp) << AHD_PRECOMP_SHIFT) & AHD_PRECOMP_MASK); \
+} while (0)
+
+#define AHD_SET_AMPLITUDE(ahd, new_amp) \
+do { \
+ (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] &= ~AHD_AMPLITUDE_MASK; \
+ (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] |= \
+ (((new_amp) << AHD_AMPLITUDE_SHIFT) & AHD_AMPLITUDE_MASK); \
+} while (0)
+
/************************ Active Device Information ***************************/
typedef enum {
ROLE_UNKNOWN,
@@ -1144,14 +1238,10 @@ ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
}
/***************************** PCI Front End *********************************/
-struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
-int ahd_pci_config(struct ahd_softc *,
- struct ahd_pci_identity *);
-
-/*************************** EISA/VL Front End ********************************/
-struct aic7770_identity *aic7770_find_device(uint32_t);
-int aic7770_config(struct ahd_softc *ahd,
- struct aic7770_identity *);
+struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
+int ahd_pci_config(struct ahd_softc *,
+ struct ahd_pci_identity *);
+int ahd_pci_test_register_access(struct ahd_softc *);
/************************** SCB and SCB queue management **********************/
int ahd_probe_scbs(struct ahd_softc *);
@@ -1249,11 +1339,20 @@ void ahd_validate_width(struct ahd_softc *ahd,
struct ahd_initiator_tinfo *tinfo,
u_int *bus_width,
role_t role);
+/*
+ * Negotiation types. These are used to qualify if we should renegotiate
+ * even if our goal and current transport parameters are identical.
+ */
+typedef enum {
+ AHD_NEG_TO_GOAL, /* Renegotiate only if goal and curr differ. */
+ AHD_NEG_IF_NON_ASYNC, /* Renegotiate so long as goal is non-async. */
+ AHD_NEG_ALWAYS /* Renegotiat even if goal is async. */
+} ahd_neg_type;
int ahd_update_neg_request(struct ahd_softc*,
struct ahd_devinfo*,
struct ahd_tmode_tstate*,
struct ahd_initiator_tinfo*,
- int /*force*/);
+ ahd_neg_type);
void ahd_set_width(struct ahd_softc *ahd,
struct ahd_devinfo *devinfo,
u_int width, u_int type, int paused);
@@ -1290,22 +1389,27 @@ cam_status ahd_find_tmode_devs(struct ahd_softc *ahd,
/******************************* Debug ***************************************/
#ifdef AHD_DEBUG
extern uint32_t ahd_debug;
-#define AHD_SHOW_MISC 0x0001
-#define AHD_SHOW_SENSE 0x0002
-#define AHD_DUMP_SEEPROM 0x0004
-#define AHD_SHOW_TERMCTL 0x0008
-#define AHD_SHOW_MEMORY 0x0010
-#define AHD_SHOW_MESSAGES 0x0020
-#define AHD_SHOW_MODEPTR 0x0040
-#define AHD_SHOW_SELTO 0x0080
-#define AHD_SHOW_FIFOS 0x0100
-#define AHD_SHOW_QFULL 0x0200
-#define AHD_SHOW_QUEUE 0x0400
-#define AHD_SHOW_TQIN 0x0800
-#define AHD_SHOW_SG 0x1000
-#define AHD_DEBUG_SEQUENCER 0x2000
+#define AHD_SHOW_MISC 0x00001
+#define AHD_SHOW_SENSE 0x00002
+#define AHD_SHOW_RECOVERY 0x00004
+#define AHD_DUMP_SEEPROM 0x00008
+#define AHD_SHOW_TERMCTL 0x00010
+#define AHD_SHOW_MEMORY 0x00020
+#define AHD_SHOW_MESSAGES 0x00040
+#define AHD_SHOW_MODEPTR 0x00080
+#define AHD_SHOW_SELTO 0x00100
+#define AHD_SHOW_FIFOS 0x00200
+#define AHD_SHOW_QFULL 0x00400
+#define AHD_SHOW_DV 0x00800
+#define AHD_SHOW_MASKED_ERRORS 0x01000
+#define AHD_SHOW_QUEUE 0x02000
+#define AHD_SHOW_TQIN 0x04000
+#define AHD_SHOW_SG 0x08000
+#define AHD_DEBUG_SEQUENCER 0x10000
#endif
void ahd_print_scb(struct scb *scb);
+void ahd_print_devinfo(struct ahd_softc *ahd,
+ struct ahd_devinfo *devinfo);
void ahd_dump_sglist(struct scb *scb);
void ahd_dump_all_cards_state(void);
void ahd_dump_card_state(struct ahd_softc *ahd);
diff --git a/sys/dev/aic7xxx/aic79xx.reg b/sys/dev/aic7xxx/aic79xx.reg
index 81f19067b0f1..7611b9aa0d0b 100644
--- a/sys/dev/aic7xxx/aic79xx.reg
+++ b/sys/dev/aic7xxx/aic79xx.reg
@@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#45 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#55 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@@ -72,6 +72,19 @@ VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#45 $"
xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); \
}
+#define RESTORE_MODE(mode) \
+ if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \
+ mov mode call set_mode_work_around; \
+ } else { \
+ mov MODE_PTR, mode; \
+ }
+
+#define SET_SEQINTCODE(code) \
+ if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { \
+ mvi code call set_seqint_work_around; \
+ } else { \
+ mvi SEQINTCODE, code; \
+ }
/*
* Mode Pointer
@@ -114,7 +127,8 @@ register SEQINTCODE {
address 0x002
access_mode RW
field {
- BAD_PHASE 1, /* unknown scsi bus phase */
+ NO_SEQINT, /* No seqint pending. */
+ BAD_PHASE, /* unknown scsi bus phase */
SEND_REJECT, /* sending a message reject */
PROTO_VIOLATION, /* Protocol Violation */
NO_MATCH, /* no cmd match for reconnect */
@@ -158,7 +172,12 @@ register SEQINTCODE {
CFG4ISTAT_INTR,
STATUS_OVERRUN,
CFG4OVERRUN,
- ENTERING_NONPACK
+ ENTERING_NONPACK,
+ TRACEPOINT0,
+ TRACEPOINT1,
+ TRACEPOINT2,
+ TRACEPOINT3,
+ SAW_HWERR
}
}
@@ -366,6 +385,7 @@ register DFCNTRL {
access_mode RW
modes M_DFF0, M_DFF1
field PRELOADEN 0x80
+ field SCSIENWRDIS 0x40 /* Rev B only. */
field SCSIEN 0x20
field SCSIENACK 0x20
field HDMAEN 0x08
@@ -463,6 +483,17 @@ register HODMAADR {
}
/*
+ * PCI PLL Delay.
+ */
+register PLLDELAY {
+ address 0x070
+ access_mode RW
+ size 1
+ modes M_CFG
+ field SPLIT_DROP_REQ 0x80
+}
+
+/*
* Data Channel Host Count
*/
register HCNT {
@@ -1561,9 +1592,24 @@ register DFFSTAT {
modes M_SCSI
field FIFO1FREE 0x20
field FIFO0FREE 0x10
- field CURRFIFO 0x01
+ /*
+ * On the B, this enum only works
+ * in the read direction. For writes,
+ * you must use the B version of the
+ * CURRFIFO_0 definition which is defined
+ * as a constant outside of this register
+ * definition to avoid confusing the
+ * register pretty printing code.
+ */
+ enum CURRFIFO 0x03 {
+ CURRFIFO_0,
+ CURRFIFO_1,
+ CURRFIFO_NONE 0x3
+ }
}
+const B_CURRFIFO_0 0x2
+
/*
* SCSI Bus Target IDs
* Bitmask of observed targets on the bus.
@@ -2208,6 +2254,7 @@ register DFFSXFRCTL {
address 0x05A
access_mode RW
modes M_DFF0, M_DFF1
+ field DFFBITBUCKET 0x08
field CLRSHCNT 0x04
field CLRCHN 0x02
field RSTCHN 0x01
@@ -2222,7 +2269,17 @@ register NEXTSCB {
size 2
modes M_SCSI
}
-
+
+/* Rev B only. */
+register LQOSCSCTL {
+ address 0x05A
+ access_mode RW
+ size 1
+ modes M_CFG
+ field LQOH2A_VERSION 0x80
+ field LQONOCHKOVER 0x01
+}
+
/*
* SEQ Interrupts
*/
@@ -2427,7 +2484,10 @@ register NEGCONOPTS {
address 0x064
access_mode RW
modes M_SCSI
- field ENAIP 0x08
+ field ENSNAPSHOT 0x40
+ field RTI_WRTDIS 0x20
+ field RTI_OVRDTRN 0x10
+ field ENSLOWCRC 0x08
field ENAUTOATNI 0x04
field ENAUTOATNO 0x02
field WIDEXFER 0x01
@@ -2447,7 +2507,7 @@ register SCSCHKN {
access_mode RW
modes M_CFG
field STSELSKIDDIS 0x40
- field CURFIFODEF 0x20
+ field CURRFIFODEF 0x20
field WIDERESEN 0x10
field SDONEMSKDIS 0x08
field DFFACTCLR 0x04
@@ -2455,13 +2515,28 @@ register SCSCHKN {
field LSTSGCLRDIS 0x01
}
-const AHD_ANNEXCOL_PRECOMP 4
+const AHD_ANNEXCOL_PER_DEV0 4
+const AHD_NUM_PER_DEV_ANNEXCOLS 4
+const AHD_ANNEXCOL_PRECOMP_SLEW 4
const AHD_PRECOMP_MASK 0x07
+const AHD_PRECOMP_SHIFT 0
const AHD_PRECOMP_CUTBACK_17 0x04
const AHD_PRECOMP_CUTBACK_29 0x06
const AHD_PRECOMP_CUTBACK_37 0x07
-const AHD_PRECOMP_FASTSLEW 0x40
-const AHD_NUM_ANNEXCOLS 4
+const AHD_SLEWRATE_MASK 0x78
+const AHD_SLEWRATE_SHIFT 3
+/*
+ * Rev A has only a single bit of slew adjustment.
+ * Rev B has 4 bits.
+ */
+const AHD_SLEWRATE_DEF_REVA 0x01
+const AHD_SLEWRATE_DEF_REVB 0x08
+
+/* Rev A does not have any amplitude setting. */
+const AHD_ANNEXCOL_AMPLITUDE 6
+const AHD_AMPLITUDE_MASK 0x7
+const AHD_AMPLITUDE_SHIFT 0
+const AHD_AMPLITUDE_DEF 0x7
/*
* Negotiation Table Annex Data Port.
@@ -2689,7 +2764,8 @@ register CCSGCTL {
modes M_DFF0, M_DFF1
field CCSGDONE 0x80
field SG_CACHE_AVAIL 0x10
- field CCSGEN 0x08
+ field CCSGENACK 0x08
+ mask CCSGEN 0x0C
field SG_FETCH_REQ 0x02
field CCSGRESET 0x01
}
@@ -2983,7 +3059,10 @@ register WRTBIASCTL {
field XMITMANVAL 0x3F
}
-const WRTBIASCTL_CPQ_DEFAULT 0x97
+/*
+ * Currently the WRTBIASCTL is the same as the default.
+ */
+const WRTBIASCTL_HP_DEFAULT 0x0
/*
* Receiver Bias Control
@@ -3447,7 +3526,7 @@ scratch_ram {
size 2
}
/*
- * Mode to restore on idle_loop exit.
+ * Mode to restore on legacy idle loop exit.
*/
SAVED_MODE {
size 1
@@ -3518,6 +3597,13 @@ scratch_ram {
}
}
/*
+ * Value to "or" into the SCBPTR[1] value to
+ * indicate that an entry in the QINFIFO is valid.
+ */
+ QOUTFIFO_ENTRY_VALID_TAG {
+ size 1
+ }
+ /*
* Base address of our shared data with the kernel driver in host
* memory. This includes the qoutfifo and target mode
* incoming command queue.
@@ -3533,13 +3619,6 @@ scratch_ram {
size 4
}
/*
- * Value to "or" into the SCBPTR[1] value to
- * indicate that an entry in the QINFIFO is valid.
- */
- QOUTFIFO_ENTRY_VALID_TAG {
- size 1
- }
- /*
* Kernel and sequencer offsets into the queue of
* incoming target mode command descriptors. The
* queue is full when the KERNEL_TQINPOS == TQINPOS.
@@ -3722,7 +3801,6 @@ scb {
}
/*********************************** Constants ********************************/
-const SEQ_STACK_SIZE 8
const MK_MESSAGE_BIT_OFFSET 4
const TID_SHIFT 4
const TARGET_CMD_CMPLT 0xfe
@@ -3746,7 +3824,15 @@ const BUS_32_BIT 0x02
/* Offset maximums */
const MAX_OFFSET 0xfe
-const MAX_OFFSET_PACED 0x7f
+const MAX_OFFSET_PACED 0xfe
+const MAX_OFFSET_PACED_BUG 0x7f
+/*
+ * Some 160 devices incorrectly accept 0xfe as a
+ * sync offset, but will overrun this value. Limit
+ * to 0x7f for speed lower than U320 which will
+ * avoid the persistent sync offset overruns.
+ */
+const MAX_OFFSET_NON_PACED 0x7f
const HOST_MSG 0xff
/*
diff --git a/sys/dev/aic7xxx/aic79xx.seq b/sys/dev/aic7xxx/aic79xx.seq
index e21fb601662f..6774896a1419 100644
--- a/sys/dev/aic7xxx/aic79xx.seq
+++ b/sys/dev/aic7xxx/aic79xx.seq
@@ -40,14 +40,31 @@
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#60 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#72 $"
PATCH_ARG_LIST = "struct ahd_softc *ahd"
PREFIX = "ahd_"
#include "aic79xx.reg"
#include "scsi_message.h"
+restart:
+if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+ test SEQINTCODE, 0xFF jz idle_loop;
+ SET_SEQINTCODE(NO_SEQINT)
+}
+
idle_loop:
+
+ if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+ /*
+ * Convert ERROR status into a sequencer
+ * interrupt to handle the case of an
+ * interrupt collision on the hardware
+ * setting of HWERR.
+ */
+ test ERROR, 0xFF jz . + 2;
+ SET_SEQINTCODE(SAW_HWERR)
+ }
SET_MODE(M_SCSI, M_SCSI)
test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus;
test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus;
@@ -69,11 +86,18 @@ END_CRITICAL;
test SCSISIGO, ATNO jz idle_loop_check_nonpackreq;
call unexpected_nonpkt_phase_find_ctxt;
idle_loop_check_nonpackreq:
- test SSTAT2, NONPACKREQ jz idle_loop_scsi;
+ test SSTAT2, NONPACKREQ jz . + 2;
call unexpected_nonpkt_phase_find_ctxt;
-idle_loop_scsi:
+ call idle_loop_gsfifo_in_scsi_mode;
+ call idle_loop_service_fifos;
+ call idle_loop_cchan;
+ jmp idle_loop;
+
BEGIN_CRITICAL;
- test LQISTAT2, LQIGSAVAIL jz idle_loop_service_fifos;
+idle_loop_gsfifo:
+ SET_MODE(M_SCSI, M_SCSI)
+idle_loop_gsfifo_in_scsi_mode:
+ test LQISTAT2, LQIGSAVAIL jz return;
/*
* We have received good status for this transaction. There may
* still be data in our FIFOs draining to the host. Setup
@@ -113,31 +137,29 @@ good_status_IU_done:
*/
call complete;
END_CRITICAL;
- jmp idle_loop_scsi;
+ jmp idle_loop_gsfifo_in_scsi_mode;
BEGIN_CRITICAL;
good_status_check_fifos:
clc;
bmov ARG_1, SCBPTR, 2;
SET_MODE(M_DFF0, M_DFF0)
call check_fifo;
- jc idle_loop_service_fifos;
+ jc return;
SET_MODE(M_DFF1, M_DFF1)
call check_fifo;
- jc idle_loop_service_fifos;
+ jc return;
SET_MODE(M_SCSI, M_SCSI)
- call queue_scb_completion;
+ jmp queue_scb_completion;
END_CRITICAL;
+
idle_loop_service_fifos:
SET_MODE(M_DFF0, M_DFF0)
test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo;
call longjmp;
idle_loop_next_fifo:
SET_MODE(M_DFF1, M_DFF1)
- test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_last_fifo_done;
- call longjmp;
-idle_loop_last_fifo_done:
- call idle_loop_cchan;
- jmp idle_loop;
+ test LONGJMP_ADDR[1], INVALID_ADDR jz longjmp;
+ ret;
idle_loop_cchan:
SET_MODE(M_CCHAN, M_CCHAN)
@@ -175,6 +197,8 @@ fetch_new_scb_done:
bmov NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4;
mvi SCB_NEXT[1], SCB_LIST_NULL;
mvi SCB_NEXT2[1], SCB_LIST_NULL;
+ /* Increment our position in the QINFIFO. */
+ mov NONE, SNSCB_QOFF;
/*
* SCBs that want to send messages are always
* queued independently. This ensures that they
@@ -189,22 +213,15 @@ fetch_new_scb_done:
bmov SCBPTR, SINDIR, 2;
bmov DINDIR, REG0, 2;
cmp SCBPTR[1], SCB_LIST_NULL je first_new_target_scb;
- bmov SCB_NEXT, REG0, 2;
-fetch_new_scb_fini:
- /* Increment our position in the QINFIFO. */
- mov NONE, SNSCB_QOFF ret;
+ bmov SCB_NEXT, REG0, 2 ret;
first_new_target_scb:
cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb;
bmov SCBPTR, WAITING_TID_TAIL, 2;
bmov SCB_NEXT2, REG0, 2;
- bmov WAITING_TID_TAIL, REG0, 2;
- /* Increment our position in the QINFIFO. */
- mov NONE, SNSCB_QOFF ret;
+ bmov WAITING_TID_TAIL, REG0, 2 ret;
first_new_scb:
bmov WAITING_TID_HEAD, REG0, 2;
- bmov WAITING_TID_TAIL, REG0, 2;
- /* Increment our position in the QINFIFO. */
- mov NONE, SNSCB_QOFF ret;
+ bmov WAITING_TID_TAIL, REG0, 2 ret;
END_CRITICAL;
scbdma_idle:
@@ -228,19 +245,16 @@ fill_qoutfifo:
bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2;
mvi CCSCBCTL, CCSCBRESET;
bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4;
- mov CCSCBRAM, COMPLETE_SCB_HEAD;
- or CCSCBRAM, A, COMPLETE_SCB_HEAD[1];
bmov SCBPTR, COMPLETE_SCB_HEAD, 2;
- jmp fill_qoutfifo_first_entry;
fill_qoutfifo_loop:
- mov CCSCBRAM, SCB_NEXT_COMPLETE;
- or CCSCBRAM, A, SCB_NEXT_COMPLETE[1];
- bmov SCBPTR, SCB_NEXT_COMPLETE, 2;
-fill_qoutfifo_first_entry:
+ mov CCSCBRAM, SCBPTR;
+ or CCSCBRAM, A, SCBPTR[1];
mov NONE, SDSCB_QOFF;
cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done;
cmp CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done;
- test QOFF_CTLSTA, SDSCB_ROLLOVR jz fill_qoutfifo_loop;
+ test QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done;
+ bmov SCBPTR, SCB_NEXT_COMPLETE, 2;
+ jmp fill_qoutfifo_loop;
fill_qoutfifo_done:
mov SCBHCNT, CCSCBADDR;
mvi CCSCBCTL, CCSCBEN|CCSCBRESET;
@@ -290,7 +304,7 @@ longjmp:
bmov STACK, LONGJMP_ADDR, 2 ret;
END_CRITICAL;
-/************************ Packetized LongJmp Routines *************************/
+/*************************** Chip Bug Work Arounds ****************************/
/*
* Must disable interrupts when setting the mode pointer
* register as an interrupt occurring mid update will
@@ -309,6 +323,14 @@ toggle_dff_mode_work_around:
clr SEQINTCTL ret;
}
+
+if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+set_seqint_work_around:
+ mov SEQINTCODE, SINDEX;
+ mvi SEQINTCODE, NO_SEQINT ret;
+}
+
+/************************ Packetized LongJmp Routines *************************/
SET_SRC_MODE M_SCSI;
SET_DST_MODE M_SCSI;
start_selection:
@@ -358,26 +380,30 @@ END_CRITICAL;
/*
* Allocate a FIFO for a non-packetized transaction.
- * For some reason unkown to me, both FIFOs must be free before we
- * can allocate a FIFO for a non-packetized transaction. This
- * may be fixed in Rev B.
+ * In RevA hardware, both FIFOs must be free before we
+ * can allocate a FIFO for a non-packetized transaction.
*/
allocate_fifo_loop:
/*
* Do whatever work is required to free a FIFO.
*/
- SET_MODE(M_DFF0, M_DFF0)
- test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2;
- call longjmp;
- SET_MODE(M_DFF1, M_DFF1)
- test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2;
- call longjmp;
+ call idle_loop_service_fifos;
SET_MODE(M_SCSI, M_SCSI)
allocate_fifo:
- and A, FIFO0FREE|FIFO1FREE, DFFSTAT;
- cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop;
-take_fifo:
- or DFFSTAT, CURRFIFO;
+ if ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0) {
+ and A, FIFO0FREE|FIFO1FREE, DFFSTAT;
+ cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop;
+ } else {
+ test DFFSTAT, FIFO1FREE jnz allocate_fifo1;
+ test DFFSTAT, FIFO0FREE jz allocate_fifo_loop;
+ mvi DFFSTAT, B_CURRFIFO_0;
+ SET_MODE(M_DFF0, M_DFF0)
+ bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret;
+ }
+SET_SRC_MODE M_SCSI;
+SET_DST_MODE M_SCSI;
+allocate_fifo1:
+ mvi DFFSTAT, CURRFIFO_1;
SET_MODE(M_DFF1, M_DFF1)
bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret;
@@ -485,6 +511,7 @@ curscb_ww_done:
*/
bmov SCBPTR, CURRSCB, 2;
}
+
/*
* Requeue any SCBs not sent, to the tail of the waiting Q.
*/
@@ -518,9 +545,7 @@ select_out_inc_tid_q:
mvi WAITING_TID_TAIL[1], SCB_LIST_NULL;
bmov SCBPTR, CURRSCB, 2;
END_CRITICAL;
-
mvi CLRSINT0, CLRSELDO;
-
test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase;
test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase;
@@ -583,15 +608,16 @@ ITloop:
cmp A,P_STATUS je p_status;
cmp A,P_MESGIN je p_mesgin;
- mvi SEQINTCODE, BAD_PHASE;
+ SET_SEQINTCODE(BAD_PHASE)
jmp ITloop; /* Try reading the bus again. */
/*
* Command phase. Set up the DMA registers and let 'er rip.
*/
p_command:
-SET_SRC_MODE M_DFF1;
-SET_DST_MODE M_DFF1;
+ test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay;
+ SET_SEQINTCODE(PROTO_VIOLATION)
+p_command_okay:
test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
jnz p_command_allocate_fifo;
/*
@@ -599,32 +625,34 @@ SET_DST_MODE M_DFF1;
* re-allocate a FIFO so transfer state is
* reset.
*/
+SET_SRC_MODE M_DFF1;
+SET_DST_MODE M_DFF1;
mvi DFFSXFRCTL, RSTCHN|CLRSHCNT;
+ SET_MODE(M_SCSI, M_SCSI)
p_command_allocate_fifo:
bmov ALLOCFIFO_SCBPTR, SCBPTR, 2;
call allocate_fifo;
+SET_SRC_MODE M_DFF1;
+SET_DST_MODE M_DFF1;
add NONE, -17, SCB_CDB_LEN;
jnc p_command_embedded;
p_command_from_host:
bmov HADDR[0], SCB_CDB_PTR, 11;
mvi SG_CACHE_PRE, LAST_SEG;
mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
- jmp p_command_loop;
+ jmp p_command_xfer;
p_command_embedded:
bmov SHCNT[0], SCB_CDB_LEN, 1;
- bmov SHCNT[1], ALLZEROS, 2;
bmov DFDAT, SCB_CDB_STORE, 16;
mvi DFCNTRL, SCSIEN;
-p_command_loop:
- test DFCNTRL, SCSIEN jnz p_command_loop;
+p_command_xfer:
+ and SEQ_FLAGS, ~NO_CDB_SENT;
+ test DFCNTRL, SCSIEN jnz .;
/*
* DMA Channel automatically disabled.
* Don't allow a data phase if the command
- * was not fully transferred. Make sure that
- * we clear the IDENTIFY SEEN flag if a retry
- * falls short too.
+ * was not fully transferred.
*/
- and SEQ_FLAGS, ~NO_CDB_SENT;
test SSTAT2, SDONE jnz ITloop;
or SEQ_FLAGS, NO_CDB_SENT;
jmp ITloop;
@@ -637,9 +665,7 @@ p_command_loop:
SET_SRC_MODE M_SCSI;
SET_DST_MODE M_SCSI;
p_status:
- test SEQ_FLAGS,NOT_IDENTIFIED jz p_status_okay;
- mvi SEQINTCODE, PROTO_VIOLATION;
- jmp mesgin_done;
+ test SEQ_FLAGS,NOT_IDENTIFIED jnz mesgin_proto_violation;
p_status_okay:
mov SCB_SCSI_STATUS, SCSIDAT;
or SCB_CONTROL, STATUS_RCVD;
@@ -744,7 +770,7 @@ p_mesgin:
*/
host_message_loop:
call phase_lock; /* Benign the first time through. */
- mvi SEQINTCODE, HOST_MSG_LOOP;
+ SET_SEQINTCODE(HOST_MSG_LOOP)
cmp RETURN_1, EXIT_MSG_LOOP je ITloop;
cmp RETURN_1, CONT_MSG_LOOP_WRITE jne . + 3;
mov SCSIDAT, RETURN_2;
@@ -761,9 +787,12 @@ mesgin_ign_wide_residue:
cmp REG0, 0x01 jne mesgin_reject;
test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
test DATA_COUNT_ODD, 0x1 jz mesgin_done;
- mvi SEQINTCODE, IGN_WIDE_RES;
+ SET_SEQINTCODE(IGN_WIDE_RES)
jmp mesgin_done;
+mesgin_proto_violation:
+ SET_SEQINTCODE(PROTO_VIOLATION)
+ jmp mesgin_done;
mesgin_reject:
mvi MSG_MESSAGE_REJECT call mk_mesg;
mesgin_done:
@@ -851,11 +880,11 @@ setup_SCB_disconnected:
jmp mesgin_done;
not_found:
- mvi SEQINTCODE, NO_MATCH;
+ SET_SEQINTCODE(NO_MATCH)
jmp mesgin_done;
not_found_ITloop:
- mvi SEQINTCODE, NO_MATCH;
+ SET_SEQINTCODE(NO_MATCH)
jmp ITloop;
/*
@@ -871,9 +900,6 @@ not_found_ITloop:
* it to the QINFIFO and tell us not to post to the QOUTFIFO by setting
* RETURN_1 to SEND_SENSE.
*/
-mesgin_complete_proto_violation:
- mvi SEQINTCODE, PROTO_VIOLATION;
- jmp mesgin_done;
mesgin_complete:
/*
@@ -891,34 +917,28 @@ mesgin_complete:
* If we are identified and have successfully sent the CDB,
* any status will do. Optimize this fast path.
*/
- test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jnz . + 2;
- test SCB_CONTROL, STATUS_RCVD jnz complete_accepted;
+ test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation;
+ test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted;
/*
* If the target never sent an identify message but instead went
* to mesgin to give an invalid message, let the host abort us.
*/
- test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_complete_proto_violation;
-
- /*
- * If the target never gave us status information, have
- * the host abort the command.
- */
- test SCB_CONTROL, STATUS_RCVD jz mesgin_complete_proto_violation;
+ test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
/*
* If we recevied good status but never successfully sent the
* cdb, abort the command.
*/
test SCB_SCSI_STATUS,0xff jnz complete_accepted;
- test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_complete_proto_violation;
+ test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation;
complete_accepted:
/*
* See if we attempted to deliver a message but the target ingnored us.
*/
test SCB_CONTROL, MK_MESSAGE jz . + 2;
- mvi SEQINTCODE, MKMSG_FAILED;
+ SET_SEQINTCODE(MKMSG_FAILED)
call queue_scb_completion;
jmp await_busfree;
@@ -937,6 +957,14 @@ queue_arg1_scb_completion:
SET_MODE(M_SCSI, M_SCSI)
bmov SCBPTR, ARG_1, 2;
queue_scb_completion:
+ if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) {
+ /*
+ * Set MK_MESSAGE to trigger an abort should this SCB
+ * be referenced by a target even though it is not currently
+ * active.
+ */
+ or SCB_CONTROL, MK_MESSAGE;
+ }
test SCB_SCSI_STATUS,0xff jnz bad_status;
/*
* Check for residuals
@@ -971,10 +999,8 @@ mesgin_disconnect:
* XXX - Wait for more testing.
test SCSISIGI, ATNI jnz mesgin_done;
*/
- test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz disconnect_allowed;
- mvi SEQINTCODE, PROTO_VIOLATION;
- jmp mesgin_done;
-disconnect_allowed:
+ test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT
+ jnz mesgin_proto_violation;
or SCB_CONTROL,DISCONNECTED;
test SCB_CONTROL, TAG_ENB jnz await_busfree;
queue_disc_scb:
@@ -1005,7 +1031,7 @@ await_busfree_not_m_dff:
call clear_target_state;
test SSTAT1,REQINIT|BUSFREE jz .;
test SSTAT1, BUSFREE jnz idle_loop;
- mvi SEQINTCODE, MISSED_BUSFREE;
+ SET_SEQINTCODE(MISSED_BUSFREE)
/*
@@ -1047,12 +1073,13 @@ save_pointers_full:
* SCB anytime we enter a data phase for the first time, so all
* we need to do is clear the DPHASE flag and let the data phase
* code do the rest. We also reset/reallocate the FIFO to make
- * sure we have a clean start for the next data phase.
+ * sure we have a clean start for the next data or command phase.
*/
mesgin_rdptrs:
and SEQ_FLAGS, ~DPHASE;
test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz msgin_rdptrs_get_fifo;
mvi DFFSXFRCTL, RSTCHN|CLRSHCNT;
+ SET_MODE(M_SCSI, M_SCSI)
msgin_rdptrs_get_fifo:
call allocate_fifo;
jmp mesgin_done;
@@ -1064,6 +1091,7 @@ clear_target_state:
phase_lock:
test SCSIPHASE, 0xFF jz .;
+ test SSTAT1, SCSIPERR jnz phase_lock;
phase_lock_latch_phase:
and LASTPHASE, PHASE_MASK, SCSISIGI ret;
@@ -1090,6 +1118,7 @@ inb_next_wait:
* before continuing.
*/
test SCSIPHASE, 0xFF jz .;
+ test SSTAT1, SCSIPERR jnz inb_next_wait;
inb_next_check_phase:
and LASTPHASE, PHASE_MASK, SCSISIGI;
cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;
@@ -1112,20 +1141,6 @@ disable_ccsgen:
disable_ccsgen_fetch_done:
clr SG_STATE ret;
-data_group_idle_loop:
- mov SAVED_MODE, MODE_PTR;
- test SG_STATE, LOADING_NEEDED jz . + 2;
- call service_fifo;
- TOGGLE_DFF_MODE
- test SG_STATE, LOADING_NEEDED jz . + 2;
- call service_fifo;
- call idle_loop_cchan;
- if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {
- mov SAVED_MODE jmp set_mode_work_around;
- } else {
- mov MODE_PTR, SAVED_MODE ret;
- }
-
service_fifo:
/*
* Do we have any prefetch left???
@@ -1138,11 +1153,10 @@ service_fifo:
test CCSGCTL, SG_CACHE_AVAIL jz return;
/* Did we just finish fetching segs? */
- cmp CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGDONE
- je idle_sgfetch_complete;
+ test CCSGCTL, CCSGDONE jnz idle_sgfetch_complete;
/* Are we actively fetching segments? */
- test CCSGCTL, CCSGEN jnz return;
+ test CCSGCTL, CCSGENACK jnz return;
/*
* We fetch a "cacheline aligned" and sized amount of data
@@ -1151,17 +1165,15 @@ service_fifo:
* set the prefetch amount to a reasonable level if the
* cacheline size is unknown.
*/
- and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
+ bmov SGHADDR, SCB_RESIDUAL_SGPTR, 4;
mvi SGHCNT, SG_PREFETCH_CNT;
if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) {
/*
* Need two instruction between "touches" of SGHADDR.
- * Note the setting of SGHCNT counts as one of
- * these two instructions.
*/
nop;
}
- bmov SGHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
+ and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
mvi CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET;
or SG_STATE, FETCH_INPROG ret;
idle_sgfetch_complete:
@@ -1215,7 +1227,15 @@ sg_advance:
* de-asserts and we don't want to accidentally
* re-enable it.
*/
- or DFCNTRL, PRELOADEN|HDMAEN;
+ if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {
+ /*
+ * Use SCSIENWRDIS so that SCSIEN is never
+ * modified by this operation.
+ */
+ or DFCNTRL, PRELOADEN|SCSIENWRDIS|HDMAEN;
+ } else {
+ or DFCNTRL, PRELOADEN|HDMAEN;
+ }
/*
* Do we have another segment in the cache?
*/
@@ -1248,9 +1268,15 @@ load_first_seg:
mvi SG_STATE, LOADING_NEEDED ret;
clr SG_STATE ret;
+p_data_handle_xfer:
+ call setjmp_setscb;
+ test SG_STATE, LOADING_NEEDED jnz service_fifo;
+p_data_clear_handler:
+ or LONGJMP_ADDR[1], INVALID_ADDR ret;
+
p_data:
test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed;
- mvi SEQINTCODE, PROTO_VIOLATION;
+ SET_SEQINTCODE(PROTO_VIOLATION)
p_data_allowed:
test SEQ_FLAGS, DPHASE jz data_phase_initialize;
@@ -1263,14 +1289,15 @@ p_data_allowed:
* unless we already know that we should be bitbucketing.
*/
test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket;
- mvi SEQINTCODE, PDATA_REINIT;
- jmp data_group_dma_loop;
+ SET_SEQINTCODE(PDATA_REINIT)
+ jmp data_phase_inbounds;
p_data_bitbucket:
/*
* Turn on `Bit Bucket' mode, wait until the target takes
* us to another phase, and then notify the host.
*/
+ mov SAVED_MODE, MODE_PTR;
test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
jnz bitbucket_not_m_dff;
/*
@@ -1285,8 +1312,10 @@ bitbucket_not_m_dff:
/* Wait for non-data phase. */
test SCSIPHASE, ~DATA_PHASE_MASK jz .;
and SXFRCTL1, ~BITBUCKET;
- SET_MODE(M_DFF1, M_DFF1)
- mvi SEQINTCODE, DATA_OVERRUN;
+ RESTORE_MODE(SAVED_MODE)
+SET_SRC_MODE M_DFF1;
+SET_DST_MODE M_DFF1;
+ SET_SEQINTCODE(DATA_OVERRUN)
jmp ITloop;
data_phase_initialize:
@@ -1295,13 +1324,19 @@ data_phase_initialize:
data_phase_inbounds:
/* We have seen a data phase at least once. */
or SEQ_FLAGS, DPHASE;
+ mov SAVED_MODE, MODE_PTR;
+ test SG_STATE, LOADING_NEEDED jz data_group_dma_loop;
+ call p_data_handle_xfer;
data_group_dma_loop:
/*
* The transfer is complete if either the last segment
* completes or the target changes phase. Both conditions
* will clear SCSIEN.
*/
- call data_group_idle_loop;
+ call idle_loop_service_fifos;
+ call idle_loop_cchan;
+ call idle_loop_gsfifo;
+ RESTORE_MODE(SAVED_MODE)
test DFCNTRL, SCSIEN jnz data_group_dma_loop;
data_group_dmafinish:
@@ -1357,6 +1392,7 @@ data_phase_finish:
data_phase_done:
/* Kill off any pending prefetch */
call disable_ccsgen;
+ or LONGJMP_ADDR[1], INVALID_ADDR;
if ((ahd->flags & AHD_TARGETROLE) != 0) {
test SEQ_FLAGS, DPHASE_PENDING jz ITloop;
@@ -1414,7 +1450,8 @@ residual_before_last_seg:
* hardware will only interrupt us once SHVALID or
* LAST_SEG_DONE.
*/
- call data_group_idle_loop;
+ call idle_loop_service_fifos;
+ RESTORE_MODE(SAVED_MODE)
jmp calc_residual;
sgptr_fixup:
@@ -1448,7 +1485,7 @@ export seq_isr:
test SEQINTSRC, CFG4DATA jnz cfg4data_intr;
test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr;
test SEQINTSRC, CFG4ICMD jnz cfg4icmd_intr;
- mvi SEQINTCODE, INVALID_SEQINT;
+ SET_SEQINTCODE(INVALID_SEQINT)
/*
* There are two types of save pointers interrupts:
@@ -1486,7 +1523,7 @@ cfg4istat_intr:
/*
* Host sets up address/count and enables transfer.
*/
- mvi SEQINTCODE, CFG4ISTAT_INTR;
+ SET_SEQINTCODE(CFG4ISTAT_INTR)
jmp cfg4istat_setup_handler;
cfg4istat_have_sense_addr:
bmov HADDR, SCB_SENSE_BUSADDR, 4;
@@ -1635,7 +1672,7 @@ END_CRITICAL;
check_status_overrun:
test SHCNT[2], 0xFF jz status_IU_done;
- mvi SEQINTCODE, STATUS_OVERRUN;
+ SET_SEQINTCODE(STATUS_OVERRUN)
jmp status_IU_done;
pkt_handle_status:
call setjmp_setscb;
@@ -1694,11 +1731,11 @@ SET_DST_MODE M_DFF0;
mvi DFFSXFRCTL, CLRCHN;
mvi CLRSINT2, CLRNONPACKREQ;
test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase;
- mvi SEQINTCODE, ENTERING_NONPACK;
+ SET_SEQINTCODE(ENTERING_NONPACK)
jmp ITloop;
illegal_phase:
- mvi SEQINTCODE, ILLEGAL_PHASE;
+ SET_SEQINTCODE(ILLEGAL_PHASE)
jmp ITloop;
/*
@@ -1708,11 +1745,10 @@ illegal_phase:
* BITBUCKET.
*/
pkt_handle_overrun:
- mvi SEQINTCODE, CFG4OVERRUN;
+ SET_SEQINTCODE(CFG4OVERRUN)
call freeze_queue;
if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) {
- SET_MODE(M_SCSI, M_SCSI)
- or SXFRCTL1,BITBUCKET;
+ or DFFSXFRCTL, DFFBITBUCKET;
SET_SRC_MODE M_DFF1;
SET_DST_MODE M_DFF1;
} else {
@@ -1721,12 +1757,14 @@ SET_DST_MODE M_DFF1;
}
call setjmp;
if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
- test DFSTATUS, PKT_PRELOAD_AVAIL jz overrun_load_done;
+ test DFSTATUS, PRELOAD_AVAIL jz overrun_load_done;
call load_overrun_buf;
or DFCNTRL, PRELOADEN;
overrun_load_done:
+ test SEQINTSRC, CTXTDONE jnz pkt_overrun_end;
+ } else {
+ test DFFSXFRCTL, DFFBITBUCKET jz pkt_overrun_end;
}
- test SEQINTSRC, CTXTDONE jnz pkt_overrun_end;
test SSTAT2, NONPACKREQ jz return;
pkt_overrun_end:
or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;