patch-2.4.22 linux-2.4.22/drivers/scsi/aic7xxx/aic7xxx.seq
Next file: linux-2.4.22/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
Previous file: linux-2.4.22/drivers/scsi/aic7xxx/aic7xxx.reg
Back to the patch index
Back to the overall index
- Lines: 499
- Date:
2003-08-25 04:44:42.000000000 -0700
- Orig file:
linux-2.4.21/drivers/scsi/aic7xxx/aic7xxx.seq
- Orig date:
2002-08-02 17:39:44.000000000 -0700
diff -urN linux-2.4.21/drivers/scsi/aic7xxx/aic7xxx.seq linux-2.4.22/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -37,11 +37,12 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.94.2.16 2002/04/29 19:36:30 gibbs Exp $
+ * $FreeBSD$
*/
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#43 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $"
PATCH_ARG_LIST = "struct ahc_softc *ahc"
+PREFIX = "ahc_"
#include "aic7xxx.reg"
#include "scsi_message.h"
@@ -69,7 +70,7 @@
* Turn off the selection hardware. We need to reset the
* selection request in order to perform a new selection.
*/
- and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
+ and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP;
and SIMODE1, ~ENBUSFREE;
poll_for_work:
call clear_target_state;
@@ -192,7 +193,7 @@
* Setup the DMA for sending the identify and
* command information.
*/
- or SEQ_FLAGS, CMDPHASE_PENDING;
+ mvi SEQ_FLAGS, CMDPHASE_PENDING;
mov A, TQINPOS;
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -305,7 +306,7 @@
} else {
mvi DFDAT, SCB_LIST_NULL;
}
- or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
+ or SEQ_FLAGS, TARG_CMD_PENDING;
test SEQ_FLAGS2, TARGET_MSG_PENDING
jnz target_mesgout_pending;
test SCSISIGI, ATNI jnz target_mesgout_continue;
@@ -389,13 +390,8 @@
}
/*
- * Initialize transfer settings and clear the SCSI channel.
- * SINDEX should contain any additional bit's the client wants
- * set in SXFRCTL0. We also assume that the current SCB is
- * a valid SCB for the target we wish to talk to.
+ * Initialize transfer settings with SCB provided settings.
*/
-initialize_channel:
- or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
set_transfer_settings:
if ((ahc->features & AHC_ULTRA) != 0) {
test SCB_CONTROL, ULTRAENB jz . + 2;
@@ -441,11 +437,19 @@
mov SCBPTR, WAITING_SCBH;
mov WAITING_SCBH,SCB_NEXT;
mov SAVED_SCSIID, SCB_SCSIID;
- mov SAVED_LUN, SCB_LUN;
- call initialize_channel;
+ and SAVED_LUN, LID, SCB_LUN;
+ call set_transfer_settings;
if ((ahc->flags & AHC_TARGETROLE) != 0) {
test SSTAT0, TARGET jz initiator_select;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
+
+ /*
+ * Put tag in connonical location since not
+ * all connections have an SCB.
+ */
+ mov INITIATOR_TAG, SCB_TARGET_ITAG;
+
/*
* We've just re-selected an initiator.
* Assert BSY and setup the phase for
@@ -457,7 +461,7 @@
/*
* Start out with a simple identify message.
*/
- or SCB_LUN, MSG_IDENTIFYFLAG call target_outb;
+ or SAVED_LUN, MSG_IDENTIFYFLAG call target_outb;
/*
* If we are the result of a tagged command, send
@@ -491,15 +495,16 @@
* on the state of NO_DISCONNECT.
*/
test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect;
- mov RETURN_1, ALLZEROS;
+ mvi TARG_IMMEDIATE_SCB, SCB_LIST_NULL;
call complete_target_cmd;
- cmp RETURN_1, CONT_MSG_LOOP jne .;
if ((ahc->flags & AHC_PAGESCBS) != 0) {
mov ALLZEROS call get_free_or_disc_scb;
}
+ cmp TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .;
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
- mov SCB_TAG call dma_scb;
+ mov TARG_IMMEDIATE_SCB call dma_scb;
call set_transfer_settings;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
jmp target_synccmd;
target_mesgout:
@@ -507,6 +512,7 @@
target_mesgout_continue:
call target_inb;
target_mesgout_pending:
+ and SEQ_FLAGS2, ~TARGET_MSG_PENDING;
/* Local Processing goes here... */
jmp host_target_message_loop;
@@ -636,13 +642,14 @@
if ((ahc->flags & AHC_INITIATORROLE) != 0) {
initiator_select:
+ or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
/*
* 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;
+ mvi SEQ_FLAGS, NO_CDB_SENT;
mvi CLRSINT0, CLRSELDO;
/*
@@ -701,7 +708,7 @@
}
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) */
@@ -761,16 +768,12 @@
/* Does the hardware have space for another SG entry? */
test DFSTATUS, PRELOAD_AVAIL jz return;
bmov HADDR, CCSGRAM, 7;
- test HCNT[0], 0x1 jz . + 2;
- xor DATA_COUNT_ODD, 0x1;
bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
}
call sg_advance;
mov SINDEX, SCB_RESIDUAL_SGPTR[0];
- test DATA_COUNT_ODD, 0x1 jz . + 2;
- or SINDEX, ODD_SEG;
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
or SINDEX, LAST_SEG;
mov SG_CACHE_PRE, SINDEX;
@@ -815,9 +818,9 @@
}
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 {
@@ -868,7 +871,6 @@
call calc_mwi_residual;
}
and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
- and DATA_COUNT_ODD, 0x1, HCNT[0];
if ((ahc->features & AHC_ULTRA2) == 0) {
if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -903,8 +905,6 @@
mov SINDEX, SCB_RESIDUAL_SGPTR[0];
test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
or SINDEX, LAST_SEG;
- test DATA_COUNT_ODD, 0x1 jz . + 2;
- or SINDEX, ODD_SEG;
mov SG_CACHE_PRE, SINDEX;
mov DFCNTRL, DMAPARAMS;
ultra2_dma_loop:
@@ -999,10 +999,8 @@
adc SCB_RESIDUAL_SGPTR[3], -1;
sgptr_fixup_done:
and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
- clr DATA_COUNT_ODD;
- test SG_CACHE_SHADOW, ODD_SEG jz . + 2;
- or DATA_COUNT_ODD, 0x1;
- clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
+ /* We are not the last seg */
+ and SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG;
residuals_correct:
/*
* Go ahead and shut down the DMA engine now.
@@ -1046,11 +1044,19 @@
* LAST_SEG_DONE to come true on a completed transfer
* and then test to see if the data FIFO is non-empty.
*/
- test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4;
+ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL
+ jz ultra2_wait_fifoemp;
test SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
+ /*
+ * FIFOEMP can lag LAST_SEG_DONE. Wait a few
+ * clocks before calling this an overrun.
+ */
+ test DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
+ test DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
test DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
/* Overrun */
jmp data_phase_loop;
+ultra2_wait_fifoemp:
test DFSTATUS, FIFOEMP jz .;
}
ultra2_fifoempty:
@@ -1239,9 +1245,6 @@
} else {
call set_stcnt_from_hcnt;
}
- /* Track odd'ness */
- test HCNT[0], 0x1 jz . + 2;
- xor DATA_COUNT_ODD, 0x1;
if ((ahc->flags & AHC_TARGETROLE) != 0) {
test SSTAT0, TARGET jnz data_phase_loop;
@@ -1343,7 +1346,7 @@
*/
test DFCNTRL, DIRECTION jz target_ITloop;
test SSTAT1, REQINIT jnz .;
- test DATA_COUNT_ODD, 0x1 jz target_ITloop;
+ test SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop;
test SCSIRATE, WIDEXFER jz target_ITloop;
/*
* Issue an Ignore Wide Residue Message.
@@ -1361,8 +1364,8 @@
* 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) {
@@ -1394,7 +1397,7 @@
}
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
@@ -1432,24 +1435,28 @@
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;
/*
@@ -1457,10 +1464,10 @@
* 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;
/*
@@ -1499,7 +1506,7 @@
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
test SCB_CONTROL,MK_MESSAGE jnz host_message_loop;
p_mesgout_identify:
- or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
+ or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN;
test SCB_CONTROL, DISCENB jnz . + 2;
and SINDEX, ~DISCENB;
/*
@@ -1576,18 +1583,20 @@
mvi ARG_1 call inb_next;
cmp ARG_1, 0x01 jne mesgin_reject;
test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
- test DATA_COUNT_ODD, 0x1 jz mesgin_done;
+ test SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done;
mvi IGN_WIDE_RES call set_seqint;
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
@@ -1600,27 +1609,49 @@
* 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;
@@ -1673,14 +1704,15 @@
* 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;
}
test SCB_CONTROL, TAG_ENB jnz await_busfree;
mov ARG_1, SCB_TAG;
- mov SAVED_LUN, SCB_LUN;
+ and SAVED_LUN, LID, SCB_LUN;
mov SCB_SCSIID call set_busy_target;
jmp await_busfree;
@@ -1741,7 +1773,8 @@
* 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; /*
@@ -1749,6 +1782,7 @@
* the next time through
* the dataphase.
*/
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
jmp mesgin_done;
/*
@@ -1776,7 +1810,7 @@
* transactions by first looking at the transaction stored in
* the busy target array. If there is no untagged transaction
* for this target or the transaction is for a different lun, then
- * this must be an untagged transaction.
+ * this must be a tagged transaction.
*/
shr SINDEX, 4, SAVED_SCSIID;
and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
@@ -1821,7 +1855,7 @@
* at a time. So, if the lun doesn't match, look
* for a tag message.
*/
- mov A, SCB_LUN;
+ and A, LID, SCB_LUN;
cmp SAVED_LUN, A je setup_SCB_id_lun_okay;
if ((ahc->flags & AHC_PAGESCBS) != 0) {
/*
@@ -1879,7 +1913,7 @@
or SEQ_FLAGS, 0x8;
}
setup_SCB_id_okay:
- mov A, SCB_LUN;
+ and A, LID, SCB_LUN;
cmp SAVED_LUN, A jne not_found_cleanup_scb;
setup_SCB_id_lun_okay:
if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
@@ -1897,7 +1931,7 @@
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;
@@ -2218,9 +2252,9 @@
* available data to force the chip to
* continue the transfer. This does not
* happen for SCSI transfers as the SCSI module
- * will drain the FIFO as data is made available.
+ * will drain the FIFO as data are made available.
* When the hang occurs, we know that a multiple
- * of 8 bytes are in the FIFO because the PCI
+ * of 8 bytes is in the FIFO because the PCI
* module has an 8 byte input latch that only
* dumps to the FIFO when HCNT == 0 or the
* latch is full.
@@ -2257,7 +2291,6 @@
} else {
call dma_finish;
}
- /* If we were putting the SCB, we are done */
call dfdat_in_8;
call dfdat_in_8;
call dfdat_in_8;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)