summaryrefslogtreecommitdiffstats
path: root/sys/dev/aic7xxx
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2002-12-01 08:13:37 +0000
committerscottl <scottl@FreeBSD.org>2002-12-01 08:13:37 +0000
commitae95356f265a1982f922e46cfab966458ef5cf73 (patch)
tree8f5f273b1ccc8f34c05265b9f4327079f55c99a0 /sys/dev/aic7xxx
parent45781e3228deefd9c61819301caa86bc57d9ab63 (diff)
downloadFreeBSD-src-ae95356f265a1982f922e46cfab966458ef5cf73.zip
FreeBSD-src-ae95356f265a1982f922e46cfab966458ef5cf73.tar.gz
Major update to the ahd driver to fix many bugs found in the previous
version, plus add support for the new features found in the Rev B version of the chip. The changelog is quite long and can be provided on request. Major features include vastly improved protocol violation handling, full support for the 7902 Rev B, better parity error handling, and better packetized overrun handling, to name a few. Approved by: re (blanket)
Diffstat (limited to 'sys/dev/aic7xxx')
-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 7762fa2..19a98c0 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 293e01c..2f9a47e 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 81f1906..7611b9a 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 e21fb60..6774896 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;
OpenPOWER on IntegriCloud