summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/aic7xxx/aic7xxx.c418
-rw-r--r--sys/dev/aic7xxx/aic7xxx.h51
-rw-r--r--sys/dev/aic7xxx/aic7xxx.reg8
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq107
4 files changed, 435 insertions, 149 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c
index a63000b..93c6261 100644
--- a/sys/dev/aic7xxx/aic7xxx.c
+++ b/sys/dev/aic7xxx/aic7xxx.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/aic7xxx.c#80 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#100 $
*
* $FreeBSD$
*/
@@ -161,8 +161,6 @@ static struct ahc_syncrate*
static void ahc_update_pending_scbs(struct ahc_softc *ahc);
static void ahc_fetch_devinfo(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo);
-static void ahc_print_devinfo(struct ahc_softc *ahc,
- struct ahc_devinfo *devinfo);
static void ahc_scb_devinfo(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
struct scb *scb);
@@ -183,6 +181,7 @@ static void ahc_construct_ppr(struct ahc_softc *ahc,
u_int period, u_int offset,
u_int bus_width, u_int ppr_options);
static void ahc_clear_msg_state(struct ahc_softc *ahc);
+static void ahc_handle_proto_violation(struct ahc_softc *ahc);
static void ahc_handle_message_phase(struct ahc_softc *ahc);
typedef enum {
AHCMSG_1B,
@@ -231,6 +230,7 @@ static int ahc_check_patch(struct ahc_softc *ahc,
u_int start_instr, u_int *skip_addr);
static void ahc_download_instr(struct ahc_softc *ahc,
u_int instrptr, uint8_t *dconsts);
+static int ahc_probe_stack_size(struct ahc_softc *ahc);
#ifdef AHC_TARGET_MODE
static void ahc_queue_lstate_event(struct ahc_softc *ahc,
struct ahc_tmode_lstate *lstate,
@@ -547,7 +547,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
== ahc_get_transfer_length(scb)) {
ahc_update_neg_request(ahc, &devinfo,
tstate, targ_info,
- /*force*/TRUE);
+ AHC_NEG_IF_NON_ASYNC);
}
if (tstate->auto_negotiate & devinfo.target_mask) {
hscb->control |= MK_MESSAGE;
@@ -563,16 +563,11 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
scb->flags |= SCB_SENSE;
ahc_qinfifo_requeue_tail(ahc, scb);
ahc_outb(ahc, RETURN_1, SEND_SENSE);
-#ifdef __FreeBSD__
/*
* Ensure we have enough time to actually
* retrieve the sense.
*/
- untimeout(ahc_timeout, (caddr_t)scb,
- scb->io_ctx->ccb_h.timeout_ch);
- scb->io_ctx->ccb_h.timeout_ch =
- timeout(ahc_timeout, (caddr_t)scb, 5 * hz);
-#endif
+ ahc_scb_timer_reset(scb, 5 * 1000000);
break;
}
default:
@@ -626,27 +621,10 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
break;
}
- case NO_IDENT:
+ case PROTO_VIOLATION:
{
- /*
- * The reconnecting target either did not send an identify
- * message, or did, but we didn't find an SCB to match and
- * before it could respond to our ATN/abort, it hit a dataphase.
- * The only safe thing to do is to blow it away with a bus
- * reset.
- */
- int found;
-
- printf("%s:%c:%d: Target did not send an IDENTIFY message. "
- "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n",
- ahc_name(ahc), devinfo.channel, devinfo.target,
- ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID));
- found = ahc_reset_channel(ahc, devinfo.channel,
- /*initiate reset*/TRUE);
- printf("%s: Issued Channel %c Bus Reset. "
- "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel,
- found);
- return;
+ ahc_handle_proto_violation(ahc);
+ break;
}
case IGN_WIDE_RES:
ahc_handle_ign_wide_residue(ahc, &devinfo);
@@ -774,7 +752,44 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
ahc_outb(ahc, LASTPHASE, curphase);
ahc_outb(ahc, SCSISIGO, curphase);
}
- ahc_inb(ahc, SCSIDATL);
+ if ((ahc_inb(ahc, SCSISIGI) & (CDI|MSGI)) == 0) {
+ int wait;
+
+ /*
+ * In a data phase. Faster to bitbucket
+ * the data than to individually ack each
+ * byte. This is also the only strategy
+ * that will work with AUTOACK enabled.
+ */
+ ahc_outb(ahc, SXFRCTL1,
+ ahc_inb(ahc, SXFRCTL1) | BITBUCKET);
+ wait = 5000;
+ while (--wait != 0) {
+ if ((ahc_inb(ahc, SCSISIGI)
+ & (CDI|MSGI)) != 0)
+ break;
+ ahc_delay(100);
+ }
+ ahc_outb(ahc, SXFRCTL1,
+ ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
+ if (wait == 0) {
+ struct scb *scb;
+ u_int scb_index;
+
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("Unable to clear parity error. "
+ "Resetting bus.\n");
+ scb_index = ahc_inb(ahc, SCB_TAG);
+ scb = ahc_lookup_scb(ahc, scb_index);
+ if (scb != NULL)
+ ahc_set_transaction_status(scb,
+ CAM_UNCOR_PARITY);
+ ahc_reset_channel(ahc, devinfo.channel,
+ /*init reset*/TRUE);
+ }
+ } else {
+ ahc_inb(ahc, SCSIDATL);
+ }
}
break;
}
@@ -944,9 +959,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
char cur_channel;
char intr_channel;
- /* Make sure the sequencer is in a safe location. */
- ahc_clear_critical_section(ahc);
-
if ((ahc->features & AHC_TWIN) != 0
&& ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0))
cur_channel = 'B';
@@ -975,10 +987,13 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
}
}
+ /* Make sure the sequencer is in a safe location. */
+ ahc_clear_critical_section(ahc);
+
scb_index = ahc_inb(ahc, SCB_TAG);
scb = ahc_lookup_scb(ahc, scb_index);
if (scb != NULL
- && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0)
+ && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
scb = NULL;
if ((ahc->features & AHC_ULTRA2) != 0
@@ -1052,9 +1067,10 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
break;
}
mesg_out = ahc_phase_table[i].mesg_out;
- if (scb != NULL)
+ if (scb != NULL) {
ahc_print_path(ahc, scb);
- else
+ scb->flags |= SCB_TRANSMISSION_ERROR;
+ } else
printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
scsirate = ahc_inb(ahc, SCSIRATE);
@@ -1137,7 +1153,18 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
printf("%s: ahc_intr - referenced scb not "
"valid during SELTO scb(%d, %d)\n",
ahc_name(ahc), scbptr, scb_index);
+ ahc_dump_card_state(ahc);
} else {
+ /*
+ * 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.
+ */
+ ahc_force_renegotiation(ahc);
ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
ahc_freeze_devq(ahc, scb);
#ifdef AHC_DEBUG
@@ -1149,16 +1176,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
#endif
}
ahc_outb(ahc, CLRINT, CLRSCSIINT);
- /*
- * 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.
- */
- ahc_force_renegotiation(ahc);
ahc_restart(ahc);
} else if ((status & BUSFREE) != 0
&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
@@ -1357,7 +1374,7 @@ ahc_force_renegotiation(struct ahc_softc *ahc)
devinfo.target,
&tstate);
ahc_update_neg_request(ahc, &devinfo, tstate,
- targ_info, /*force*/TRUE);
+ targ_info, AHC_NEG_IF_NON_ASYNC);
}
#define AHC_MAX_STEPS 2000
@@ -1420,11 +1437,26 @@ ahc_clear_critical_section(struct ahc_softc *ahc)
simode0 = ahc_inb(ahc, SIMODE0);
ahc_outb(ahc, SIMODE0, 0);
simode1 = ahc_inb(ahc, SIMODE1);
- ahc_outb(ahc, SIMODE1, 0);
+ if ((ahc->features & AHC_DT) != 0)
+ /*
+ * On DT class controllers, we
+ * use the enhanced busfree logic.
+ * Unfortunately we cannot re-enable
+ * busfree detection within the
+ * current connection, so we must
+ * leave it on while single stepping.
+ */
+ ahc_outb(ahc, SIMODE1, ENBUSFREE);
+ else
+ ahc_outb(ahc, SIMODE1, 0);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP);
stepping = TRUE;
}
+ if ((ahc->features & AHC_DT) != 0) {
+ ahc_outb(ahc, CLRSINT1, CLRBUSFREE);
+ ahc_outb(ahc, CLRINT, CLRSCSIINT);
+ }
ahc_outb(ahc, HCNTRL, ahc->unpause);
while (!ahc_is_paused(ahc))
ahc_delay(200);
@@ -1573,7 +1605,7 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
* by the capabilities of the bus connectivity of and sync settings for
* the target.
*/
-static struct ahc_syncrate *
+struct ahc_syncrate *
ahc_devlimited_syncrate(struct ahc_softc *ahc,
struct ahc_initiator_tinfo *tinfo,
u_int *period, u_int *ppr_options, role_t role)
@@ -1786,16 +1818,28 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
int
ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
struct ahc_tmode_tstate *tstate,
- struct ahc_initiator_tinfo *tinfo, int force)
+ struct ahc_initiator_tinfo *tinfo, ahc_neg_type neg_type)
{
u_int auto_negotiate_orig;
auto_negotiate_orig = tstate->auto_negotiate;
+ if (neg_type == AHC_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 = AHC_PERIOD_UNKNOWN;
+ tinfo->curr.width = AHC_WIDTH_UNKNOWN;
+ tinfo->curr.offset = AHC_OFFSET_UNKNOWN;
+ tinfo->curr.ppr_options = AHC_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
+ || (neg_type == AHC_NEG_IF_NON_ASYNC
&& (tinfo->goal.offset != 0
|| tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
|| tinfo->goal.ppr_options != 0)))
@@ -1927,7 +1971,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
}
update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
- tinfo, /*force*/FALSE);
+ tinfo, AHC_NEG_TO_GOAL);
if (update_needed)
ahc_update_pending_scbs(ahc);
@@ -1989,7 +2033,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
}
update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
- tinfo, /*force*/FALSE);
+ tinfo, AHC_NEG_TO_GOAL);
if (update_needed)
ahc_update_pending_scbs(ahc);
}
@@ -2154,10 +2198,10 @@ ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
devinfo->target_mask = (0x01 << devinfo->target_offset);
}
-static void
+void
ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
{
- printf("%s:%c:%d:%d:", ahc_name(ahc), devinfo->channel,
+ printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
devinfo->target, devinfo->lun);
}
@@ -2170,7 +2214,7 @@ ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
our_id = SCSIID_OUR_ID(scb->hscb->scsiid);
role = ROLE_INITIATOR;
- if ((scb->hscb->control & TARGET_SCB) != 0)
+ if ((scb->flags & SCB_TARGET_SCB) != 0)
role = ROLE_TARGET;
ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb),
SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role);
@@ -2295,7 +2339,6 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
int dowide;
int dosync;
int doppr;
- int use_ppr;
u_int period;
u_int ppr_options;
u_int offset;
@@ -2317,23 +2360,37 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_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.offset != 0;
- doppr = tinfo->goal.ppr_options != 0;
}
if (!dowide && !dosync && !doppr) {
- panic("ahc_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 ((ahc->features & AHC_WIDE) != 0)
+ dowide = 1;
+ else
+ dosync = 1;
+
+ if (bootverbose) {
+ ahc_print_devinfo(ahc, devinfo);
+ printf("Ensuring async\n");
+ }
}
- use_ppr = (tinfo->curr.transport_version >= 3) || doppr;
/* 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
@@ -2343,14 +2400,14 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_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;
ahc_validate_offset(ahc, tinfo, rate, &offset,
- use_ppr ? tinfo->goal.width
- : tinfo->curr.width,
+ doppr ? tinfo->goal.width
+ : tinfo->curr.width,
devinfo->role);
- if (use_ppr) {
+ if (doppr) {
ahc_construct_ppr(ahc, devinfo, period, offset,
tinfo->goal.width, ppr_options);
} else {
@@ -2369,6 +2426,8 @@ static void
ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
u_int period, u_int offset)
{
+ if (offset == 0)
+ period = AHC_ASYNC_XFER_PERIOD;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
@@ -2411,6 +2470,8 @@ ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
u_int period, u_int offset, u_int bus_width,
u_int ppr_options)
{
+ if (offset == 0)
+ period = AHC_ASYNC_XFER_PERIOD;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
@@ -2449,6 +2510,100 @@ ahc_clear_msg_state(struct ahc_softc *ahc)
ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING);
}
+static void
+ahc_handle_proto_violation(struct ahc_softc *ahc)
+{
+ struct ahc_devinfo devinfo;
+ struct scb *scb;
+ u_int scbid;
+ u_int seq_flags;
+ u_int curphase;
+ u_int lastphase;
+ int found;
+
+ ahc_fetch_devinfo(ahc, &devinfo);
+ scbid = ahc_inb(ahc, SCB_TAG);
+ scb = ahc_lookup_scb(ahc, scbid);
+ seq_flags = ahc_inb(ahc, SEQ_FLAGS);
+ curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+ lastphase = ahc_inb(ahc, LASTPHASE);
+ if ((seq_flags & NOT_IDENTIFIED) != 0) {
+
+ /*
+ * The reconnecting target either did not send an
+ * identify message, or did, but we didn't find an SCB
+ * to match.
+ */
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("Target did not send an IDENTIFY message. "
+ "LASTPHASE = 0x%x.\n", lastphase);
+ scb = NULL;
+ } else if (scb == NULL) {
+ /*
+ * We don't seem to have an SCB active for this
+ * transaction. Print an error and reset the bus.
+ */
+ ahc_print_devinfo(ahc, &devinfo);
+ printf("No SCB found during protocol violation\n");
+ goto proto_violation_reset;
+ } else {
+ ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
+ if ((seq_flags & NO_CDB_SENT) != 0) {
+ ahc_print_path(ahc, scb);
+ printf("No or incomplete CDB sent to device.\n");
+ } else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) {
+ /*
+ * The target never bothered to provide status to
+ * us prior to completing the command. Since we don't
+ * know the disposition of this command, we must attempt
+ * to abort it. Assert ATN and prepare to send an abort
+ * message.
+ */
+ ahc_print_path(ahc, scb);
+ printf("Completed command without status.\n");
+ } else {
+ ahc_print_path(ahc, scb);
+ printf("Unknown protocol violation.\n");
+ ahc_dump_card_state(ahc);
+ }
+ }
+ if ((lastphase & ~P_DATAIN_DT) == 0
+ || lastphase == P_COMMAND) {
+proto_violation_reset:
+ /*
+ * Target either went directly to data/command
+ * phase or didn't respond to our ATN.
+ * The only safe thing to do is to blow
+ * it away with a bus reset.
+ */
+ found = ahc_reset_channel(ahc, 'A', TRUE);
+ printf("%s: Issued Channel %c Bus Reset. "
+ "%d SCBs aborted\n", ahc_name(ahc), 'A', found);
+ } else {
+ /*
+ * Leave the selection hardware off in case
+ * this abort attempt will affect yet to
+ * be sent commands.
+ */
+ ahc_outb(ahc, SCSISEQ,
+ ahc_inb(ahc, SCSISEQ) & ~ENSELO);
+ ahc_assert_atn(ahc);
+ ahc_outb(ahc, MSG_OUT, HOST_MSG);
+ if (scb == NULL) {
+ ahc_print_devinfo(ahc, &devinfo);
+ ahc->msgout_buf[0] = MSG_ABORT_TASK;
+ ahc->msgout_len = 1;
+ ahc->msgout_index = 0;
+ ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+ } else {
+ ahc_print_path(ahc, scb);
+ scb->flags |= SCB_ABORT;
+ }
+ printf("Protocol violation %s. Attempting to abort.\n",
+ ahc_lookup_phase_entry(curphase)->phasemsg);
+ }
+}
+
/*
* Manual message loop handler.
*/
@@ -3829,6 +3984,8 @@ ahc_free(struct ahc_softc *ahc)
free(ahc->name, M_DEVBUF);
if (ahc->seep_config != NULL)
free(ahc->seep_config, M_DEVBUF);
+ if (ahc->saved_stack != NULL)
+ free(ahc->saved_stack, M_DEVBUF);
#ifndef __FreeBSD__
free(ahc, M_DEVBUF);
#endif
@@ -4364,6 +4521,12 @@ ahc_init(struct ahc_softc *ahc)
size_t driver_data_size;
uint32_t physaddr;
+ ahc->stack_size = ahc_probe_stack_size(ahc);
+ ahc->saved_stack = malloc(ahc->stack_size * sizeof(uint16_t),
+ M_DEVBUF, M_NOWAIT);
+ if (ahc->saved_stack == NULL)
+ return (ENOMEM);
+
#ifdef AHC_DEBUG_SEQUENCER
ahc->flags |= AHC_SEQUENCER_DEBUG;
#endif
@@ -6471,6 +6634,41 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
}
}
+static int
+ahc_probe_stack_size(struct ahc_softc *ahc)
+{
+ 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++) {
+ ahc_outb(ahc, STACK, i & 0xFF);
+ ahc_outb(ahc, STACK, (i >> 8) & 0xFF);
+ }
+
+ /* Verify */
+ for (i = last_probe+1; i > 0; i--) {
+ u_int stack_entry;
+
+ stack_entry = ahc_inb(ahc, STACK)
+ |(ahc_inb(ahc, STACK) << 8);
+ if (stack_entry != i)
+ goto sized;
+ }
+ last_probe++;
+ }
+sized:
+ return (last_probe);
+}
+
int
ahc_print_register(ahc_reg_parse_entry_t *table, u_int num_entries,
const char *name, u_int address, u_int value,
@@ -6479,7 +6677,7 @@ ahc_print_register(ahc_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;
}
@@ -6514,18 +6712,20 @@ ahc_print_register(ahc_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);
}
void
ahc_dump_card_state(struct ahc_softc *ahc)
{
- struct scb *scb;
- struct scb_tailq *untagged_q;
- int target;
- int maxtarget;
- int i;
+ struct scb *scb;
+ struct scb_tailq *untagged_q;
+ u_int cur_col;
+ int target;
+ int maxtarget;
+ int i;
uint8_t last_phase;
uint8_t qinpos;
uint8_t qintail;
@@ -6544,22 +6744,34 @@ ahc_dump_card_state(struct ahc_softc *ahc)
ahc_inb(ahc, ARG_2));
printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
ahc_inb(ahc, SCBPTR));
- printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n",
- ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL));
- printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n",
- ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS));
- printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n",
- last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0));
- printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n",
- ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1));
+ cur_col = 0;
if ((ahc->features & AHC_DT) != 0)
- printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE));
- printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n",
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
- ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8));
- printf("SCB count = %d\n", ahc->scb_data->numscbs);
+ ahc_scsisigi_print(ahc_inb(ahc, SCSISIGI), &cur_col, 50);
+ ahc_scsiphase_print(ahc_inb(ahc, SCSIPHASE), &cur_col, 50);
+ ahc_scsibusl_print(ahc_inb(ahc, SCSIBUSL), &cur_col, 50);
+ ahc_lastphase_print(ahc_inb(ahc, LASTPHASE), &cur_col, 50);
+ ahc_scsiseq_print(ahc_inb(ahc, SCSISEQ), &cur_col, 50);
+ ahc_sblkctl_print(ahc_inb(ahc, SBLKCTL), &cur_col, 50);
+ ahc_seqctl_print(ahc_inb(ahc, SEQCTL), &cur_col, 50);
+ ahc_seq_flags_print(ahc_inb(ahc, SEQ_FLAGS), &cur_col, 50);
+ ahc_sstat0_print(ahc_inb(ahc, SSTAT0), &cur_col, 50);
+ ahc_sstat1_print(ahc_inb(ahc, SSTAT1), &cur_col, 50);
+ ahc_sstat2_print(ahc_inb(ahc, SSTAT2), &cur_col, 50);
+ ahc_sstat3_print(ahc_inb(ahc, SSTAT3), &cur_col, 50);
+ ahc_simode0_print(ahc_inb(ahc, SIMODE0), &cur_col, 50);
+ ahc_simode1_print(ahc_inb(ahc, SIMODE1), &cur_col, 50);
+ ahc_sxfrctl0_print(ahc_inb(ahc, SXFRCTL0), &cur_col, 50);
+ ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50);
+ ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50);
+ if (cur_col != 0)
+ printf("\n");
+ printf("STACK:");
+ for (i = 0; i < ahc->stack_size; i++) {
+ ahc->saved_stack[i] =
+ ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8);
+ printf(" 0x%x", ahc->saved_stack[i]);
+ }
+ printf("\nSCB count = %d\n", ahc->scb_data->numscbs);
printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
/* QINFIFO */
@@ -6619,11 +6831,12 @@ ahc_dump_card_state(struct ahc_softc *ahc)
printf("Sequencer SCB Info: ");
for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
ahc_outb(ahc, SCBPTR, i);
- printf("%d(c 0x%x, s 0x%x, l %d, t 0x%x) ",
- i, ahc_inb(ahc, SCB_CONTROL),
- ahc_inb(ahc, SCB_SCSIID),
- ahc_inb(ahc, SCB_LUN),
- ahc_inb(ahc, SCB_TAG));
+ cur_col = printf("\n%3d ", i);
+
+ ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60);
+ ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60);
+ ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60);
+ ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
}
printf("\n");
@@ -6632,14 +6845,17 @@ ahc_dump_card_state(struct ahc_softc *ahc)
LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
if (i++ > 256)
break;
- if (scb != LIST_FIRST(&ahc->pending_scbs))
- printf(", ");
- printf("%d(c 0x%x, s 0x%x, l %d)", scb->hscb->tag,
- scb->hscb->control, scb->hscb->scsiid, scb->hscb->lun);
+ cur_col = printf("\n%3d ", scb->hscb->tag);
+ ahc_scb_control_print(scb->hscb->control, &cur_col, 60);
+ ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60);
+ ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60);
if ((ahc->flags & AHC_PAGESCBS) == 0) {
ahc_outb(ahc, SCBPTR, scb->hscb->tag);
- printf("(0x%x, 0x%x)", ahc_inb(ahc, SCB_CONTROL),
- ahc_inb(ahc, SCB_TAG));
+ printf("(");
+ ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL),
+ &cur_col, 60);
+ ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
+ printf(")");
}
}
printf("\n");
diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h
index 054512a..12acab3 100644
--- a/sys/dev/aic7xxx/aic7xxx.h
+++ b/sys/dev/aic7xxx/aic7xxx.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/aic7xxx.h#51 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#62 $
*
* $FreeBSD$
*/
@@ -534,10 +534,21 @@ typedef enum {
SCB_RECOVERY_SCB = 0x0020,
SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */
SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */
- SCB_ABORT = 0x1000,
- SCB_UNTAGGEDQ = 0x2000,
- SCB_ACTIVE = 0x4000,
- SCB_TARGET_IMMEDIATE = 0x8000
+ SCB_ABORT = 0x0100,
+ SCB_UNTAGGEDQ = 0x0200,
+ SCB_ACTIVE = 0x0400,
+ SCB_TARGET_IMMEDIATE = 0x0800,
+ SCB_TRANSMISSION_ERROR = 0x1000,/*
+ * We detected a parity or CRC
+ * error that has effected the
+ * payload of the command. This
+ * flag is checked when normal
+ * status is returned to catch
+ * the case of a target not
+ * responding to our attempt
+ * to report the error.
+ */
+ SCB_TARGET_SCB = 0x2000
} scb_flag;
struct scb {
@@ -662,6 +673,11 @@ struct ahc_tmode_lstate;
#define AHC_TRANS_GOAL 0x04 /* Modify negotiation goal */
#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */
+#define AHC_WIDTH_UNKNOWN 0xFF
+#define AHC_PERIOD_UNKNOWN 0xFF
+#define AHC_OFFSET_UNKNOWN 0x0
+#define AHC_PPR_OPTS_UNKNOWN 0xFF
+
/*
* Transfer Negotiation Information.
*/
@@ -716,6 +732,10 @@ struct ahc_syncrate {
char *rate;
};
+/* Safe and valid period for async negotiations. */
+#define AHC_ASYNC_XFER_PERIOD 0x44
+#define AHC_ULTRA2_XFER_PERIOD 0x0a
+
/*
* Indexes into our table of syncronous transfer rates.
*/
@@ -797,7 +817,7 @@ struct seeprom_config {
#define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/
#define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */
#define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */
-#define CFDOMAINVAL 0x4000 /* Perform Domain Validation*/
+#define CFENABLEDV 0x4000 /* Perform Domain Validation*/
/*
* Bus Release Time, Host Adapter ID
@@ -864,6 +884,7 @@ struct ahc_suspend_state {
};
typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
+typedef void ahc_callback_t (void *);
struct ahc_softc {
bus_space_tag_t tag;
@@ -1016,6 +1037,9 @@ struct ahc_softc {
/* PCI cacheline size. */
u_int pci_cachesize;
+ u_int stack_size;
+ uint16_t *saved_stack;
+
/* Per-Unit descriptive information */
const char *description;
char *name;
@@ -1088,6 +1112,7 @@ void ahc_busy_tcl(struct ahc_softc *ahc,
struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *);
+int ahc_pci_test_register_access(struct ahc_softc *);
/*************************** EISA/VL Front End ********************************/
struct aic7770_identity *aic7770_find_device(uint32_t);
@@ -1186,11 +1211,20 @@ void ahc_validate_width(struct ahc_softc *ahc,
struct ahc_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 {
+ AHC_NEG_TO_GOAL, /* Renegotiate only if goal and curr differ. */
+ AHC_NEG_IF_NON_ASYNC, /* Renegotiate so long as goal is non-async. */
+ AHC_NEG_ALWAYS /* Renegotiat even if goal is async. */
+} ahc_neg_type;
int ahc_update_neg_request(struct ahc_softc*,
struct ahc_devinfo*,
struct ahc_tmode_tstate*,
struct ahc_initiator_tinfo*,
- int /*force*/);
+ ahc_neg_type);
void ahc_set_width(struct ahc_softc *ahc,
struct ahc_devinfo *devinfo,
u_int width, u_int type, int paused);
@@ -1234,6 +1268,7 @@ extern uint32_t ahc_debug;
#define AHC_SHOW_TERMCTL 0x0008
#define AHC_SHOW_MEMORY 0x0010
#define AHC_SHOW_MESSAGES 0x0020
+#define AHC_SHOW_DV 0x0040
#define AHC_SHOW_SELTO 0x0080
#define AHC_SHOW_QFULL 0x0200
#define AHC_SHOW_QUEUE 0x0400
@@ -1241,6 +1276,8 @@ extern uint32_t ahc_debug;
#define AHC_DEBUG_SEQUENCER 0x1000
#endif
void ahc_print_scb(struct scb *scb);
+void ahc_print_devinfo(struct ahc_softc *ahc,
+ struct ahc_devinfo *dev);
void ahc_dump_card_state(struct ahc_softc *ahc);
int ahc_print_register(ahc_reg_parse_entry_t *table,
u_int num_entries,
diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg
index eef3b13..b3e4456 100644
--- a/sys/dev/aic7xxx/aic7xxx.reg
+++ b/sys/dev/aic7xxx/aic7xxx.reg
@@ -39,7 +39,7 @@
*
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#34 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#35 $"
/*
* This file is processed by the aic7xxx_asm utility for use in assembling
@@ -804,7 +804,7 @@ register INTSTAT {
field SEQINT 0x01
mask BAD_PHASE SEQINT /* unknown scsi bus phase */
mask SEND_REJECT 0x10|SEQINT /* sending a message reject */
- mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
+ mask PROTO_VIOLATION 0x20|SEQINT /* SCSI protocol violation */
mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */
mask PDATA_REINIT 0x50|SEQINT /*
@@ -1062,6 +1062,7 @@ scb {
SCB_CONTROL {
size 1
field TARGET_SCB 0x80
+ field STATUS_RCVD 0x80
field DISCENB 0x40
field TAG_ENB 0x20
field MK_MESSAGE 0x10
@@ -1335,7 +1336,8 @@ scratch_ram {
}
SEQ_FLAGS {
size 1
- field IDENTIFY_SEEN 0x80
+ field NOT_IDENTIFIED 0x80
+ field NO_CDB_SENT 0x40
field TARGET_CMD_IS_TAGGED 0x40
field DPHASE 0x20
/* Target flags */
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index cf850c3..b784635 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -40,7 +40,7 @@
* $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#50 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#52 $"
PATCH_ARG_LIST = "struct ahc_softc *ahc"
PREFIX = "ahc_"
@@ -306,7 +306,7 @@ ident_messages_done:
} else {
mvi DFDAT, SCB_LIST_NULL;
}
- or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
+ mvi SEQ_FLAGS, TARG_CMD_PENDING;
test SEQ_FLAGS2, TARGET_MSG_PENDING
jnz target_mesgout_pending;
test SCSISIGI, ATNI jnz target_mesgout_continue;
@@ -648,7 +648,7 @@ initiator_select:
* asserted.
*/
mvi MSG_OUT, MSG_IDENTIFYFLAG;
- or SEQ_FLAGS, IDENTIFY_SEEN;
+ mvi SEQ_FLAGS, NO_CDB_SENT;
mvi CLRSINT0, CLRSELDO;
/*
@@ -707,7 +707,7 @@ clear_target_state:
}
mvi LASTPHASE, P_BUSFREE;
/* clear target specific flags */
- clr SEQ_FLAGS ret;
+ mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
sg_advance:
clr A; /* add sizeof(struct scatter) */
@@ -821,9 +821,9 @@ calc_mwi_residual_final:
}
p_data:
- test SEQ_FLAGS,IDENTIFY_SEEN jnz p_data_okay;
- mvi NO_IDENT jmp set_seqint;
-p_data_okay:
+ test SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed;
+ mvi PROTO_VIOLATION call set_seqint;
+p_data_allowed:
if ((ahc->features & AHC_ULTRA2) != 0) {
mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
} else {
@@ -1367,8 +1367,8 @@ if ((ahc->flags & AHC_INITIATORROLE) != 0) {
* Command phase. Set up the DMA registers and let 'er rip.
*/
p_command:
- test SEQ_FLAGS,IDENTIFY_SEEN jnz p_command_okay;
- mvi NO_IDENT jmp set_seqint;
+ test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay;
+ mvi PROTO_VIOLATION call set_seqint;
p_command_okay:
if ((ahc->features & AHC_ULTRA2) != 0) {
@@ -1400,7 +1400,7 @@ p_command_from_host:
}
mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
}
- jmp p_command_loop;
+ jmp p_command_xfer;
p_command_embedded:
/*
* The data fifo seems to require 4 byte aligned
@@ -1438,24 +1438,28 @@ p_command_embedded:
call copy_to_fifo_6;
or DFCNTRL, FIFOFLUSH;
}
-p_command_loop:
+p_command_xfer:
+ and SEQ_FLAGS, ~NO_CDB_SENT;
if ((ahc->features & AHC_DT) == 0) {
test SSTAT0, SDONE jnz . + 2;
- test SSTAT1, PHASEMIS jz p_command_loop;
+ test SSTAT1, PHASEMIS jz . - 1;
/*
* Wait for our ACK to go-away on it's own
* instead of being killed by SCSIEN getting cleared.
*/
test SCSISIGI, ACKI jnz .;
} else {
- test DFCNTRL, SCSIEN jnz p_command_loop;
+ test DFCNTRL, SCSIEN jnz .;
}
+ test SSTAT0, SDONE jnz p_command_successful;
+ /*
+ * Don't allow a data phase if the command
+ * was not fully transferred.
+ */
+ or SEQ_FLAGS, NO_CDB_SENT;
+p_command_successful:
and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
- if ((ahc->features & AHC_ULTRA2) != 0) {
- /* Drop any residual from the S/G Preload queue */
- or SXFRCTL0, CLRSTCNT;
- }
jmp ITloop;
/*
@@ -1463,10 +1467,10 @@ p_command_loop:
* and store it into the SCB.
*/
p_status:
- test SEQ_FLAGS,IDENTIFY_SEEN jnz p_status_okay;
- mvi NO_IDENT jmp set_seqint;
+ test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
p_status_okay:
mov SCB_SCSI_STATUS, SCSIDATL;
+ or SCB_CONTROL, STATUS_RCVD;
jmp ITloop;
/*
@@ -1587,13 +1591,15 @@ if ((ahc->features & AHC_WIDE) != 0) {
jmp mesgin_done;
}
+mesgin_proto_violation:
+ mvi PROTO_VIOLATION call set_seqint;
+ jmp mesgin_done;
mesgin_reject:
mvi MSG_MESSAGE_REJECT call mk_mesg;
mesgin_done:
mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
jmp ITloop;
-mesgin_complete:
/*
* We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO,
* and trigger a completion interrupt. Before doing so, check to see if there
@@ -1606,27 +1612,49 @@ mesgin_complete:
* it to the QINFIFO and tell us not to post to the QOUTFIFO by setting
* RETURN_1 to SEND_SENSE.
*/
+mesgin_complete:
-/*
- * If ATN is raised, we still want to give the target a message.
- * Perhaps there was a parity error on this last message byte.
- * Either way, the target should take us to message out phase
- * and then attempt to complete the command again. We should use a
- * critical section here to guard against a timeout triggering
- * for this command and setting ATN while we are still processing
- * the completion.
+ /*
+ * If ATN is raised, we still want to give the target a message.
+ * Perhaps there was a parity error on this last message byte.
+ * Either way, the target should take us to message out phase
+ * and then attempt to complete the command again. We should use a
+ * critical section here to guard against a timeout triggering
+ * for this command and setting ATN while we are still processing
+ * the completion.
test SCSISIGI, ATNI jnz mesgin_done;
- */
+ */
-/*
- * See if we attempted to deliver a message but the target ingnored us.
- */
+ /*
+ * If we are identified and have successfully sent the CDB,
+ * any status will do. Optimize this fast path.
+ */
+ 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_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_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 MKMSG_FAILED call set_seqint;
-/*
- * Check for residuals
- */
+ /*
+ * Check for residuals
+ */
test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
@@ -1679,7 +1707,8 @@ mesgin_disconnect:
* XXX - Wait for more testing.
test SCSISIGI, ATNI jnz mesgin_done;
*/
-
+ test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT
+ jnz mesgin_proto_violation;
or SCB_CONTROL,DISCONNECTED;
if ((ahc->flags & AHC_PAGESCBS) != 0) {
call add_scb_to_disc_list;
@@ -1747,7 +1776,8 @@ mesgin_sdptrs_full:
* Restore pointers message? Data pointers are recopied from the
* 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.
+ * code do the rest. We also reset/reallocate the FIFO to make
+ * sure we have a clean start for the next data or command phase.
*/
mesgin_rdptrs:
and SEQ_FLAGS, ~DPHASE; /*
@@ -1755,6 +1785,7 @@ mesgin_rdptrs:
* the next time through
* the dataphase.
*/
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
jmp mesgin_done;
/*
@@ -1903,7 +1934,7 @@ setup_SCB_id_lun_okay:
mov SCBPTR, A;
}
setup_SCB_tagged:
- mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
+ clr SEQ_FLAGS; /* make note of IDENTIFY */
call set_transfer_settings;
/* See if the host wants to send a message upon reconnection */
test SCB_CONTROL, MK_MESSAGE jz mesgin_done;
OpenPOWER on IntegriCloud