summaryrefslogtreecommitdiff
path: root/sys/dev/aic7xxx/aic7xxx.seq
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/aic7xxx/aic7xxx.seq')
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq404
1 files changed, 185 insertions, 219 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index 3377449cd302b..c1ab64df4193e 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -1,7 +1,7 @@
/*
* Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
*
- * Copyright (c) 1994-1999 Justin Gibbs.
+ * Copyright (c) 1994-1998 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.seq,v 1.83 1998/12/17 00:06:52 gibbs Exp $
+ * $Id: aic7xxx.seq,v 1.78 1998/09/15 07:24:16 gibbs Exp $
*/
#include <dev/aic7xxx/aic7xxx.reg>
@@ -58,9 +58,12 @@
reset:
clr SCSISIGO; /* De-assert BSY */
- and SXFRCTL1, ~BITBUCKET;
/* Always allow reselection */
- and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
+ if ((ahc->flags & AHC_TARGETMODE) != 0) {
+ mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+ } else {
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP;
+ }
if ((ahc->features & AHC_CMD_CHAN) != 0) {
/* Ensure that no DMA operations are in progress */
@@ -178,12 +181,13 @@ initialize_scsiid:
and SCSIID, OID; /* Clear old target */
or SCSIID, A;
}
- mov SINDEX, SCSISEQ_TEMPLATE;
if ((ahc->flags & AHC_TARGETMODE) != 0) {
- test SCB_CONTROL, TARGET_SCB jz . + 2;
- or SINDEX, TEMODE;
+ and SINDEX, TARGET_SCB, SCB_CONTROL;
+ or SCSISEQ, ENSELO|ENAUTOATNO|ENSELI
+ |ENRSELI|ENAUTOATNP, SINDEX ret ;
+ } else {
+ mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
}
- mov SCSISEQ, SINDEX ret;
/*
* Initialize transfer settings and clear the SCSI channel.
@@ -212,26 +216,29 @@ selection:
mvi CLRSINT0, CLRSELDI;
select_in:
if ((ahc->flags & AHC_TARGETMODE) != 0) {
- if ((ahc->flags & AHC_INITIATORMODE) != 0) {
- test SSTAT0, TARGET jz initiator_reselect;
- }
-
+ test SSTAT0, TARGET jz initiator_reselect;
/*
* We've just been selected. Assert BSY and
* setup the phase for receiving messages
* from the target.
*/
mvi SCSISIGO, P_MESGOUT|BSYO;
- mvi CLRSINT1, CLRBUSFREE;
+
+ /*
+ * LAST_MSG gives an indication to the host of what
+ * went wrong should we need to terminate this selection
+ * before doing real work. Initialize it to SCB_LIST_NULL to
+ * indicate an improper initiator selection.
+ */
+ mvi LAST_MSG, SCB_LIST_NULL;
/*
* Setup the DMA for sending the identify and
- * command information.
+ * command information. We keep a count of the
+ * number of bytes to send to the host in ARG_2.
*/
or SEQ_FLAGS, CMDPHASE_PENDING;
-
- /* XXX If ring buffer is full, return busy or queue full */
- mov A, TQINPOS;
+ mov A, TMODE_CMDADDR_NEXT;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mvi DINDEX, CCHADDR;
mvi TMODE_CMDADDR call set_32byte_addr;
@@ -265,9 +272,6 @@ select_in:
}
}
- /* No tag yet */
- mvi INITIATOR_TAG, SCB_LIST_NULL;
-
/*
* If ATN isn't asserted, the target isn't interested
* in talking to us. Go directly to bus free.
@@ -279,20 +283,20 @@ select_in:
* initiator. We follow the guidlines from section 6.5
* of the SCSI-2 spec for what messages are allowed when.
*/
- call target_inb;
+ call targ_inb;
/*
* Our first message must be one of IDENTIFY, ABORT, or
* BUS_DEVICE_RESET.
*/
- /* XXX May need to be more lax here for older initiators... */
- test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
+ test DINDEX, MSG_IDENTIFYFLAG jz more_first_messages;
/* Store for host */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mov CCSCBRAM, DINDEX;
} else {
mov DFDAT, DINDEX;
}
+ mvi ARG_2, 3;
/* Remember for disconnection decision */
test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
@@ -300,7 +304,7 @@ select_in:
or SEQ_FLAGS, NO_DISCONNECT;
test SCSISIGI, ATNI jz ident_messages_done;
- call target_inb;
+ call targ_inb;
/*
* If this is a tagged request, the tagged message must
* immediately follow the identify. We test for a valid
@@ -324,39 +328,39 @@ select_in:
* free.
*/
test SCSISIGI, ATNI jz target_busfree;
-
/*
* Store the tag for the host.
*/
- call target_inb;
+ call targ_inb;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mov CCSCBRAM, DINDEX;
} else {
mov DFDAT, DINDEX;
}
- mov INITIATOR_TAG, DINDEX;
+ add ARG_2, 2;
jmp ident_messages_done;
+more_first_messages:
/*
- * Pushed message loop to allow the kernel to
- * run it's own target mode message state engine.
+ * Hmm. Now we're down to only accepting
+ * either an ABORT or BDR.
*/
-host_target_message_loop:
- mvi INTSTAT, HOST_MSG_LOOP;
- nop;
- cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop;
- test SSTAT0, SPIORDY jz .;
- jmp host_target_message_loop;
+ cmp DINDEX, MSG_ABORT je . + 2;
+ cmp DINDEX, MSG_BUS_DEV_RESET jne target_busfree;
+
+ /* Record the event and notify the host */
+ mov LAST_MSG, DINDEX;
+ jmp target_busfree;
ident_messages_done:
+ mvi LAST_MSG, MSG_NOOP; /* We are so far successful */
/* Terminate the ident list */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
mvi CCSCBRAM, SCB_LIST_NULL;
} else {
mvi DFDAT, SCB_LIST_NULL;
}
- or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
- test SCSISIGI, ATNI jnz target_mesgout_pending_msg;
+ or SEQ_FLAGS, TARG_CMD_PENDING;
jmp target_ITloop;
/*
@@ -364,20 +368,16 @@ ident_messages_done:
* message byte we receive so it can be checked prior to
* driving REQ on the bus for the next byte.
*/
-target_inb:
- /*
- * Drive REQ on the bus by enabling SCSI PIO.
- */
+targ_inb:
+ /* Drive REQ on the bus by enabling SCSI PIO */
or SXFRCTL0, SPIOEN;
/* Wait for the byte */
test SSTAT0, SPIORDY jz .;
/* Prevent our read from triggering another REQ */
and SXFRCTL0, ~SPIOEN;
- /* Save latched contents */
mov DINDEX, SCSIDATL ret;
}
-if ((ahc->flags & AHC_INITIATORMODE) != 0) {
/*
* Reselection has been initiated by a target. Make a note that we've been
* reselected, but haven't seen an IDENTIFY message from the target yet.
@@ -389,7 +389,7 @@ initiator_reselect:
test SBLKCTL, SELBUSB jz . + 2;
or SAVED_TCL, SELBUSB;
}
- or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
+ or SXFRCTL0, SPIOEN|CLRCHN;
mvi CLRSINT1,CLRBUSFREE;
or SIMODE1, ENBUSFREE; /*
* We aren't expecting a
@@ -399,7 +399,6 @@ initiator_reselect:
*/
mvi MSG_OUT, MSG_NOOP; /* No message to send */
jmp ITloop;
-}
/*
* After the selection, remove this SCB from the "waiting SCB"
@@ -409,7 +408,11 @@ initiator_reselect:
*/
select_out:
/* Turn off the selection hardware */
- and SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;
+ if ((ahc->flags & AHC_TARGETMODE) != 0) {
+ mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+ } else {
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP;
+ }
mvi CLRSINT0, CLRSELDO;
mov SCBPTR, WAITING_SCBH;
mov WAITING_SCBH,SCB_NEXT;
@@ -422,8 +425,7 @@ select_out:
* Assert BSY and setup the phase for
* sending our identify messages.
*/
- mvi P_MESGIN|BSYO call change_phase;
- mvi CLRSINT1,CLRBUSFREE;
+ mvi SCSISIGO, P_MESGIN|BSYO;
/*
* Start out with a simple identify message.
@@ -437,22 +439,19 @@ select_out:
*/
test SCB_CONTROL, TAG_ENB jz . + 3;
mvi MSG_SIMPLE_Q_TAG call target_outb;
- mov SCB_INITIATOR_TAG call target_outb;
- mov INITIATOR_TAG, SCB_INITIATOR_TAG;
+ mov SCB_TAG call target_outb;
target_synccmd:
/*
* Now determine what phases the host wants us
* to go through.
*/
mov SEQ_FLAGS, SCB_TARGET_PHASES;
-
target_ITloop:
/*
- * Start honoring ATN signals now that
- * we properly identified ourself.
+ * XXX Start honoring ATN signals now that
+ * we properly identified ourself.
*/
- test SCSISIGI, ATNI jnz target_mesgout;
test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase;
test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase;
test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase;
@@ -465,35 +464,38 @@ target_ITloop:
if ((ahc->flags & AHC_PAGESCBS) != 0) {
mov ALLZEROS call get_free_or_disc_scb;
}
- mov RETURN_1, ALLZEROS;
call complete_target_cmd;
- cmp RETURN_1, CONT_MSG_LOOP jne .;
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
mov SCB_TAG call dma_scb;
jmp target_synccmd;
-target_mesgout:
- mvi SCSISIGO, P_MESGOUT|BSYO;
- call target_inb;
- /* Local Processing goes here... */
-target_mesgout_pending_msg:
- jmp host_target_message_loop;
-
target_disconnect:
- mvi P_MESGIN|BSYO call change_phase;
- test SEQ_FLAGS, DPHASE jz . + 2;
- mvi MSG_SAVEDATAPOINTER call target_outb;
+ mvi SCSISIGO, P_MESGIN|BSYO;
mvi MSG_DISCONNECT call target_outb;
target_busfree:
+ and SXFRCTL0, ~SPIOEN;
clr SCSISIGO;
call complete_target_cmd;
+ cmp LAST_MSG, MSG_NOOP je . + 2;
+ mvi INTSTAT, TARGET_MSG_HELP;
call clear_target_state;
jmp poll_for_work;
target_cmdphase:
- mvi P_COMMAND|BSYO call change_phase;
- call target_inb;
+ /*
+ * Add one for the terminating byte
+ * and one for the command code.
+ */
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ add CCHCNT, 2, ARG_2;
+ } else {
+ add HCNT[0], 2, ARG_2;
+ clr HCNT[1];
+ clr HCNT[2];
+ }
+ mvi SCSISIGO, P_COMMAND|BSYO;
+ call targ_inb;
mov A, DINDEX;
/* Store for host */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -504,16 +506,20 @@ target_cmdphase:
/*
* Determine the number of bytes to read
- * based on the command group code via table lookup.
- * We reuse the first 8 bytes of the TARG_SCSIRATE
- * BIOS array for this table. Count is one less than
- * the total for the command since we've already fetched
- * the first byte.
+ * based on the command group code using an adding
+ * jump table. Count is one less than the total
+ * since we've already fetched the first byte.
*/
shr A, CMD_GROUP_CODE_SHIFT;
add SINDEX, TARG_SCSIRATE, A;
mov A, SINDIR;
+ if ((ahc->features & AHC_CMD_CHAN) != 0) {
+ add CCHCNT, A;
+ } else {
+ add HCNT[0], A;
+ }
+
test A, 0xFF jz command_phase_done;
command_loop:
or SXFRCTL0, SPIOEN;
@@ -537,20 +543,20 @@ target_dphase:
* Data direction flags are from the
* perspective of the initiator.
*/
+ and SXFRCTL0, ~SPIOEN;
+ or SXFRCTL0, CLRCHN;
test SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4;
+ mvi SCSISIGO, P_DATAIN|BSYO;
mvi LASTPHASE, P_DATAOUT;
- mvi P_DATAIN|BSYO call change_phase;
- jmp . + 3;
+ jmp p_data;
+ mvi SCSISIGO, P_DATAOUT|BSYO;
mvi LASTPHASE, P_DATAIN;
- mvi P_DATAOUT|BSYO call change_phase;
- mov ALLZEROS call initialize_channel;
jmp p_data;
target_sphase:
- mvi P_STATUS|BSYO call change_phase;
- mvi LASTPHASE, P_STATUS;
+ mvi SCSISIGO, P_STATUS|BSYO;
mov SCB_TARGET_STATUS call target_outb;
- /* XXX Watch for ATN or parity errors??? */
+ /* XXX Watch for ATN for parity errors??? */
mvi SCSISIGO, P_MESGIN|BSYO;
/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
mov ALLZEROS call target_outb;
@@ -560,52 +566,37 @@ complete_target_cmd:
test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2;
mov SCB_TAG jmp complete_post;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
- /* Set the valid byte */
- mvi CCSCBADDR, 24;
- mov CCSCBRAM, ALLONES;
- mvi CCHCNT, 28;
or CCSCBCTL, CCSCBEN|CCSCBRESET;
test CCSCBCTL, CCSCBDONE jz .;
clr CCSCBCTL;
} else {
- /* Set the valid byte */
- or DFCNTRL, FIFORESET;
- mvi DFWADDR, 3; /* Third 64bit word or byte 24 */
- mov DFDAT, ALLONES;
- mvi HCNT[0], 28;
- clr HCNT[1];
- clr HCNT[2];
or DFCNTRL, HDMAEN|FIFOFLUSH;
call dma_finish;
}
- inc TQINPOS;
- mvi INTSTAT,CMDCMPLT ret;
+ inc TMODE_CMDADDR_NEXT;
+ cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+ clr TMODE_CMDADDR_NEXT;
+ mvi TARGET_CMD_CMPLT jmp complete_post;
}
-
-if ((ahc->flags & AHC_INITIATORMODE) != 0) {
initiator_select:
mvi SPIOEN call initialize_channel;
-
- /*
- * We aren't expecting a bus free, so interrupt
- * the kernel driver if it happens.
- */
+/*
+ * We aren't expecting a bus free, so interrupt
+ * the kernel driver if it happens.
+ */
mvi CLRSINT1,CLRBUSFREE;
or SIMODE1, ENBUSFREE;
-
- /*
- * As soon as we get a successful selection, the target
- * should go into the message out phase since we have ATN
- * asserted.
- */
+/*
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
+ */
mvi MSG_OUT, MSG_IDENTIFYFLAG;
or SEQ_FLAGS, IDENTIFY_SEEN;
- /*
- * Main loop for information transfer phases. Wait for the
- * target to assert REQ before checking MSG, C/D and I/O for
- * the bus phase.
- */
+/*
+ * Main loop for information transfer phases. Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
+ */
ITloop:
call phase_lock;
@@ -617,7 +608,7 @@ ITloop:
cmp A,P_STATUS je p_status;
cmp A,P_MESGIN je p_mesgin;
- mvi INTSTAT,BAD_PHASE;
+ mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */
jmp ITloop; /* Try reading the bus again. */
await_busfree:
@@ -628,27 +619,20 @@ await_busfree:
test SSTAT1,REQINIT|BUSFREE jz .;
test SSTAT1, BUSFREE jnz poll_for_work;
mvi INTSTAT, BAD_PHASE;
-}
clear_target_state:
- /*
- * We assume that the kernel driver may reset us
- * at any time, even in the middle of a DMA, so
- * clear DFCNTRL too.
- */
- clr DFCNTRL;
-
- /*
- * We don't know the target we will connect to,
- * so default to narrow transfers to avoid
- * parity problems.
- */
- if ((ahc->features & AHC_ULTRA2) != 0) {
- bmov SCSIRATE, ALLZEROS, 2;
- } else {
- clr SCSIRATE;
- and SXFRCTL0, ~(FAST20);
- }
+ clr DFCNTRL; /*
+ * We assume that the kernel driver
+ * may reset us at any time, even
+ * in the middle of a DMA, so clear
+ * DFCNTRL too.
+ */
+ clr SCSIRATE; /*
+ * We don't know the target we will
+ * connect to, so default to narrow
+ * transfers to avoid parity problems.
+ */
+ and SXFRCTL0, ~(FAST20);
mvi LASTPHASE, P_BUSFREE;
/* clear target specific flags */
clr SEQ_FLAGS ret;
@@ -664,7 +648,6 @@ data_phase_reinit:
mvi DINDEX, STCNT;
mvi SCB_RESID_DCNT call bcopy_3;
}
- and DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0];
jmp data_phase_loop;
p_data:
@@ -699,7 +682,6 @@ p_data:
mvi DINDEX, HADDR;
mvi SCB_DATAPTR call bcopy_7;
}
- and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
if ((ahc->features & AHC_ULTRA2) == 0) {
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -826,10 +808,6 @@ prefetched_segs_avail:
mvi HADDR call dfdat_in_7;
}
- /* Track odd'ness */
- test HCNT[0], 0x1 jz . + 2;
- xor DATA_COUNT_ODD, 0x1;
-
if ((ahc->features & AHC_ULTRA2) == 0) {
/* Load STCNT as well. It is a mirror of HCNT */
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -844,12 +822,7 @@ prefetched_segs_avail:
add SG_NEXT[0],SG_SIZEOF;
adc SG_NEXT[1],A;
- if ((ahc->flags & AHC_TARGETMODE) != 0) {
- test SSTAT0, TARGET jnz data_phase_loop;
- }
- test SSTAT1, REQINIT jz .;
test SSTAT1,PHASEMIS jz data_phase_loop;
-
/* Ensure the last seg is visable at the shaddow layer */
if ((ahc->features & AHC_ULTRA2) != 0) {
or DFCNTRL, PRELOADEN;
@@ -878,14 +851,8 @@ data_phase_finish:
}
if ((ahc->flags & AHC_TARGETMODE) != 0) {
- test SEQ_FLAGS, DPHASE_PENDING jz ITloop;
+ test SEQ_FLAGS, DPHASE_PENDING jz . + 3;
and SEQ_FLAGS, ~DPHASE_PENDING;
- /*
- * For data-in phases, wait for any pending acks from the
- * initiator before changing phase.
- */
- test DFCNTRL, DIRECTION jz target_ITloop;
- test SSTAT1, REQINIT jnz .;
jmp target_ITloop;
}
jmp ITloop;
@@ -915,7 +882,6 @@ ultra2_dmahalt:
ret;
}
-if ((ahc->flags & AHC_INITIATORMODE) != 0) {
/*
* Command phase. Set up the DMA registers and let 'er rip.
*/
@@ -972,22 +938,17 @@ p_status:
jmp ITloop;
/*
- * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full
- * indentify message sequence and send it to the target. The host may
- * override this behavior by setting the MK_MESSAGE bit in the SCB
- * control byte. This will cause us to interrupt the host and allow
- * it to handle the message phase completely on its own. If the bit
- * associated with this target is set, we will also interrupt the host,
- * thereby allowing it to send a message on the next selection regardless
- * of the transaction being sent.
+ * Message out phase. If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target. In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
*
* If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
- * This is done to allow the host to send messages outside of an identify
+ * This is done to allow the hsot to send messages outside of an identify
* sequence while protecting the seqencer from testing the MK_MESSAGE bit
* on an SCB that might not be for the current nexus. (For example, a
* BDR message in responce to a bad reselection would leave us pointed to
* an SCB that doesn't have anything to do with the current target).
- *
* Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
* bus device reset).
*
@@ -995,29 +956,22 @@ p_status:
* in case the target decides to put us in this phase for some strange
* reason.
*/
-p_mesgout_retry:
- or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
p_mesgout:
mov SINDEX, MSG_OUT;
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
- test SCB_CONTROL,MK_MESSAGE jnz host_message_loop;
- mov FUNCTION1, SCB_TCL;
- mov A, FUNCTION1;
- mov SINDEX, TARGET_MSG_REQUEST[0];
- if ((ahc->features & AHC_TWIN) != 0) {
- /* Second Channel uses high byte bits */
- test SCB_TCL, SELBUSB jz . + 2;
- mov SINDEX, TARGET_MSG_REQUEST[1];
- } else if ((ahc->features & AHC_WIDE) != 0) {
- test SCB_TCL, 0x80 jz . + 2; /* target > 7 */
- mov SINDEX, TARGET_MSG_REQUEST[1];
- }
- test SINDEX, A jnz host_message_loop;
p_mesgout_identify:
- and SINDEX,LID,SCB_TCL; /* lun */
+ if ((ahc->features & AHC_WIDE) != 0) {
+ and SINDEX,0xf,SCB_TCL; /* lun */
+ } else {
+ and SINDEX,0x7,SCB_TCL; /* lun */
+ }
and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
or SINDEX,A; /* or in disconnect privledge */
or SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+ test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag;
+ mov SCSIDATL, SINDEX; /* Send the last byte */
+ jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */
/*
* Send a tag message if TAG_ENB is set in the SCB control block.
* Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
@@ -1032,27 +986,36 @@ p_mesgout_tag:
cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
mov SCB_TAG jmp p_mesgout_onebyte;
/*
- * Interrupt the driver, and allow it to handle this message
- * phase and any required retries.
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
*/
p_mesgout_from_host:
cmp SINDEX, HOST_MSG jne p_mesgout_onebyte;
- jmp host_message_loop;
+ mvi INTSTAT,AWAITING_MSG;
+ nop;
+ /*
+ * Did the host detect a phase change?
+ */
+ cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
p_mesgout_onebyte:
mvi CLRSINT1, CLRATNO;
mov SCSIDATL, SINDEX;
/*
- * If the next bus phase after ATN drops is message out, it means
+ * If the next bus phase after ATN drops is a message out, it means
* that the target is requesting that the last message(s) be resent.
*/
call phase_lock;
- cmp LASTPHASE, P_MESGOUT je p_mesgout_retry;
+ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+ jmp p_mesgout;
p_mesgout_done:
mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
mov LAST_MSG, MSG_OUT;
+ cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+ and SCB_CONTROL, ~MK_MESSAGE;
mvi MSG_OUT, MSG_NOOP; /* No message left */
jmp ITloop;
@@ -1067,22 +1030,19 @@ p_mesgin:
cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs;
cmp ALLZEROS,A je mesgin_complete;
cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs;
+ cmp A,MSG_EXTENDED je mesgin_extended;
+ cmp A,MSG_MESSAGE_REJECT je mesgin_reject;
cmp A,MSG_NOOP je mesgin_done;
+rej_mesgin:
/*
- * Pushed message loop to allow the kernel to
- * RUN IT's own message state engine. To avoid an
- * extra nop instruction after signaling the kernel,
- * we perform the phase_lock before checking to see
- * if we should exit the loop and skip the phase_lock
- * in the ITloop. Performing back to back phase_locks
- * shouldn't hurt, but why do it twice...
+ * We have no idea what this message in is, so we issue a message reject
+ * and hope for the best. In any case, rejection should be a rare
+ * occurrence - signal the driver when it happens.
*/
-host_message_loop:
- mvi INTSTAT, HOST_MSG_LOOP;
- call phase_lock;
- cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1;
- jmp host_message_loop;
+ mvi INTSTAT,SEND_REJECT; /* let driver know */
+
+ mvi MSG_MESSAGE_REJECT call mk_mesg;
mesgin_done:
mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
@@ -1147,7 +1107,6 @@ complete_queue:
add_to_free_list:
call add_scb_to_free_list;
jmp await_busfree;
-}
complete_post:
/* Post the SCBID in SINDEX and issue an interrupt */
@@ -1162,9 +1121,23 @@ complete_post:
if ((ahc->features & AHC_QUEUE_REGS) == 0) {
inc QOUTPOS;
}
+ if ((ahc->flags & AHC_TARGETMODE) != 0) {
+ test SEQ_FLAGS, NO_DISCONNECT jz . + 3;
+ mvi INTSTAT,TARGET_SYNC_CMD|CMDCMPLT;
+ ret;
+ }
mvi INTSTAT,CMDCMPLT ret;
-if ((ahc->flags & AHC_INITIATORMODE) != 0) {
+/*
+ * Is it an extended message? Copy the message to our message buffer and
+ * notify the host. The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * or simply to do nothing.
+ */
+mesgin_extended:
+ mvi INTSTAT,EXTENDED_MSG; /* let driver know */
+ jmp ITloop;
+
/*
* Is it a disconnect message? Set a flag in the SCB to remind us
* and await the bus going free.
@@ -1293,6 +1266,16 @@ not_found:
jmp mesgin_done;
/*
+ * Message reject? Let the kernel driver handle this. If we have an
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+ mvi INTSTAT, REJECT_MSG;
+ jmp mesgin_done;
+
+/*
* [ ADD MORE MESSAGE HANDLING HERE ]
*/
@@ -1337,35 +1320,18 @@ inb_first:
mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/
inb_last:
mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
-}
if ((ahc->flags & AHC_TARGETMODE) != 0) {
-/*
- * Change to a new phase. If we are changing the state of the I/O signal,
- * from out to in, wait an additional data release delay before continuing.
- */
-change_phase:
- and DINDEX, IOI, SCSISIGI;
- mov SCSISIGO, SINDEX;
- and A, IOI, SINDEX;
- cmp DINDEX, A je change_phase_wait;
- test SINDEX, IOI jz change_phase_wait;
- call change_phase_wait;
-change_phase_wait:
- nop;
- nop;
- nop;
- nop ret;
-
-/*
- * Send a byte to an initiator in Automatic PIO mode.
- */
+ /*
+ * Send a byte to an initiator in Automatic PIO mode.
+ * SPIOEN must be on prior to calling this routine.
+ */
target_outb:
or SXFRCTL0, SPIOEN;
test SSTAT0, SPIORDY jz .;
mov SCSIDATL, SINDEX;
test SSTAT0, SPIORDY jz .;
- and SXFRCTL0, ~SPIOEN ret;
+ ret;
}
mesgin_phasemis:
@@ -1584,8 +1550,8 @@ get_SCBID_from_host:
phase_lock:
test SSTAT1, REQINIT jz phase_lock;
test SSTAT1, SCSIPERR jnz phase_lock;
- and SCSISIGO, PHASE_MASK, SCSISIGI;
- and LASTPHASE, PHASE_MASK, SCSISIGI ret;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ mov SCSISIGO, LASTPHASE ret;
if ((ahc->features & AHC_CMD_CHAN) == 0) {
set_stcnt_from_hcnt: