patch-2.0.13 linux/drivers/scsi/aic7xxx.seq

Next file: linux/drivers/scsi/aic7xxx_proc.c
Previous file: linux/drivers/scsi/aic7xxx.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.12/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
@@ -23,15 +23,22 @@
  *
  * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
  * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
+ *
+ * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
+ *
  *-M*************************************************************************/
 
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 3.0 1996/04/16 08:52:23 deang Exp $"
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 3.1 1996/07/23 03:37:26 deang Exp $"
 
 #ifdef linux
 #include "aic7xxx_reg.h"
 #else
+#if defined(__NetBSD__)
+#include "../../../../dev/ic/aic7xxxreg.h"
+#elif defined(__FreeBSD__)
 #include "../../dev/aic7xxx/aic7xxx_reg.h"
 #endif
+#endif
 
 /*
  * We can't just use ACCUM in the sequencer code because it
@@ -67,7 +74,13 @@
  * We jump to start after every bus free.
  */
 start:
+	and	FLAGS,0x0f		/* clear target specific flags */
 	mvi	SCSISEQ,ENRSELI		/* Always allow reselection */
+	clr	SCSIRATE		/*
+					 * We don't know the target we will
+					 * connect to, so default to narrow
+					 * transfers to avoid parity problems.
+					 */
 poll_for_work:
 	/*
 	 * Are we a twin channel device?
@@ -140,7 +153,7 @@
 	or	ACTIVE_A,A
 
 start_scb:
-	mov	SCB_NEXT_WAITING,WAITING_SCBH
+	mov	SCB_NEXT,WAITING_SCBH
 	mov	WAITING_SCBH, SCBPTR
 start_scb2:
 	and	SINDEX,0xf7,SBLKCTL	/* Clear the channel select bit */
@@ -178,25 +191,24 @@
 	jmp     wait_for_selection
 
 mk_identify:
-	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privilege */
+	and	A,DISCENB,SCB_CONTROL	/* mask off disconnect privledge */
 
 	and	MSG0,0x7,SCB_TCL	/* lun */
-	or	MSG0,A			/* or in disconnect privilege */
+	or	MSG0,A			/* or in disconnect privledge */
 	or	MSG0,MSG_IDENTIFY
 	mvi	MSG_LEN, 1
 
 	test	SCB_CONTROL,0xb0 jz  !message	/* WDTR, SDTR or TAG?? */
 /*
- * Tag Message if Tag enabled in SCB control block.  Use SCBPTR as the tag
- * value
+ * 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.
  */
 
 mk_tag:
 	mvi	DINDEX, MSG1
 	test	SCB_CONTROL,TAG_ENB jz mk_tag_done
-	and	A,0x23,SCB_CONTROL
-	mov	DINDIR,A
-	mov	DINDIR,SCBPTR
+	and	DINDIR,0x23,SCB_CONTROL
+	mov	DINDIR,SCB_TAG
 
 	add	MSG_LEN,COMP_MSG0,DINDEX	/* update message length */
 
@@ -218,7 +230,6 @@
 reselect:
 	clr	MSG_LEN		/* Don't have anything in the mesg buffer */
 	mov	SELID		call initialize_scsiid
-	and	FLAGS,0x03	/* clear target specific flags */
 	or	FLAGS,RESELECTED
 	jmp	select2
 
@@ -229,8 +240,8 @@
  * SCB is used, so don't bother with it now.
  */
 select:
-	and	FLAGS,0x03		/* Clear target flags */
-	mov	WAITING_SCBH,SCB_NEXT_WAITING
+	mov	WAITING_SCBH,SCB_NEXT
+	or	FLAGS,SELECTED
 select2:
 /*
  * Set CLRCHN here before the target has entered a data transfer mode -
@@ -244,13 +255,29 @@
 	call	ndx_dtr
 	mov	SCSIRATE,SINDIR
 
+/*
+ * Initialize Ultra mode setting.
+ */
+	mov	FUNCTION1,SCSIID
+	mov	A,FUNCTION1
+	and	SINDEX,0xdf,SXFRCTL0		/* default to Ultra disabled */
+	test	SCSIID, 0x80	 jnz ultra_b	/* Target ID > 7 */
+	test	SBLKCTL, SELBUSB jnz ultra_b	/* Second channel device */
+	test	ULTRA_ENB,A	 jz  set_sxfrctl0
+	or	SINDEX, ULTRAEN  jmp set_sxfrctl0
+ultra_b:
+	test	ULTRA_ENB_B,A	 jz  set_sxfrctl0
+	or	SINDEX, ULTRAEN
+
+set_sxfrctl0:
+	mov	SXFRCTL0,SINDEX
+
 	mvi	SCSISEQ,ENAUTOATNP		/*
 						 * ATN on parity errors
 						 * for "in" phases
 						 */
 	mvi	CLRSINT1,CLRBUSFREE
 	mvi	CLRSINT0,0x60			/* CLRSELDI|CLRSELDO */
-
 /*
  * Main loop for information transfer phases.  If BSY is false, then
  * we have a bus free condition, expected or not.  Otherwise, wait
@@ -274,6 +301,7 @@
 	cmp	A,P_MESGIN	je p_mesgin
 
 	mvi	INTSTAT,BAD_PHASE	/* unknown phase - signal driver */
+	jmp	ITloop			/* Try reading the bus again. */
 
 p_dataout:
 	mvi	DMAPARAMS,0x7d			/*
@@ -305,12 +333,29 @@
 	or	FLAGS, DPHASE		/* We have seen a data phase */
 
 data_phase_loop:
+/* Guard against overruns */
+	test	SG_COUNT, 0xff jnz data_phase_inbounds
+/*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
+	or	SXFRCTL1,BITBUCKET
+	mvi	STCNT0,0xff
+	mvi	STCNT1,0xff
+	mvi	STCNT2,0xff
+
+data_phase_inbounds:
 /* If we are the last SG block, don't set wideodd. */
 	cmp	SG_COUNT,0x01 jne data_phase_wideodd
 	and	DMAPARAMS, 0xbf		/* Turn off WIDEODD */
 data_phase_wideodd:
 	mov	DMAPARAMS  call dma
 
+/* Go tell the host about any overruns */
+	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun
+
 /* Exit if we had an underrun */
 	test	SSTAT0,SDONE	jz data_phase_finish /* underrun STCNT != 0 */
 
@@ -412,16 +457,22 @@
 	mov	SCB_RESID_SGCNT, SG_COUNT
 	jmp	ITloop
 
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+	and	SXFRCTL1,0x7f		/* ~BITBUCKET */
+	mvi	INTSTAT,DATA_OVERRUN
+	jmp	ITloop
+
 /*
- * Command phase.  Set up the DMA registers and let 'er rip - the
- * two bytes after the SCB SCSI_cmd_length are zeroed by the driver,
- * so we can copy those three bytes directly into HCNT.
+ * Command phase.  Set up the DMA registers and let 'er rip.
  */
 p_command:
 	call	assert
 
 /*
- * Load HADDR and HCNT.  We can do this in one bcopy since they are neighbors
+ * Load HADDR and HCNT.
  */
 	mov	HADDR0, SCB_CMDPTR0
 	mov	HADDR1, SCB_CMDPTR1
@@ -448,7 +499,7 @@
 	jmp	mesgin_done
 
 /*
- * Message out phase.  If there is no active message, but the target
+ * Message out phase.  If there is not an active message, but the target
  * took us into this phase anyway, build a no-op message and send it.
  */
 p_mesgout:
@@ -473,6 +524,7 @@
 p_mesgout_loop:
 	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
 	test	SSTAT0,SPIORDY	jz p_mesgout_loop
+	test	SSTAT1,PHASEMIS	jnz p_mesgout_phasemis
 	cmp	DINDEX,1	jne p_mesgout_outb	/* last byte? */
 	mvi	CLRSINT1,CLRATNO			/* drop ATN */
 p_mesgout_outb:
@@ -498,7 +550,7 @@
 	jmp	ITloop
 
 p_mesgout_phasemis:
-	mvi	CLRSINT1,CLRATNO	/* Be sure turn ATNO off */
+	mvi	CLRSINT1,CLRATNO	/* Be sure to turn ATNO off */
 p_mesgout_done:
 	clr	MSG_LEN			/* no active msg */
 	jmp	ITloop
@@ -539,20 +591,20 @@
 
 mesgin_complete:
 /*
- * We got a "command complete" message, so put the SCB pointer
- * into QUEUEOUT, and trigger a completion interrupt.
- * Check status for non zero return and interrupt driver if needed
- * This allows the driver to interpret errors only when they occur
- * instead of always uploading the scb.  If the status is SCSI_CHECK,
- * the driver will download a new scb requesting sense to replace
- * the old one, modify the "waiting for selection" SCB list and set 
- * RETURN_1 to 0x80.  If RETURN_1 is set to 0x80 the sequencer immediately
- * jumps to main loop where it will run down the waiting SCB list.
- * If the kernel driver does not wish to request sense, it need
- * only clear RETURN_1, and the command is allowed to complete.  We don't 
- * bother to post to the QOUTFIFO in the error case since it would require 
- * extra work in the kernel driver to ensure that the entry was removed 
- * before the command complete code tried processing it.
+ * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
+ * and trigger a completion interrupt.  Check status for non zero return
+ * and interrupt driver if needed.  This allows the driver to interpret
+ * errors only when they occur instead of always uploading the scb.  If
+ * the status is SCSI_CHECK, the driver will download a new scb requesting
+ * sense to replace the old one, modify the "waiting for selection" SCB list
+ * and set RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE the
+ * sequencer imediately jumps to main loop where it will run down the waiting
+ * SCB list and process the sense request.  If the kernel driver does not
+ * wish to request sense, it need only clear RETURN_1, and the command is
+ * allowed to complete.  We don't bother to post to the QOUTFIFO in the
+ * error case since it would require extra work in the kernel driver to
+ * ensure that the entry was removed before the command complete code tried
+ * processing it.
  *
  * First check for residuals
  */
@@ -600,7 +652,7 @@
 	mvi	INTSTAT,IMMEDDONE
 	jmp	start
 complete:
-	mov	QOUTFIFO,SCBPTR
+	mov	QOUTFIFO,SCB_TAG
 	mvi	INTSTAT,CMDCMPLT
 	jmp	mesgin_done
 
@@ -614,10 +666,10 @@
  */
 mesgin_extended:
 	mvi	ARG_1		call inb_next	/* extended message length */
-	mvi	A		call inb_next	/* extended message code */
+	mvi	REJBYTE_EXT	call inb_next	/* extended message code */
 
-	cmp	A,MSG_SDTR	je p_mesginSDTR
-	cmp	A,MSG_WDTR	je p_mesginWDTR
+	cmp	REJBYTE_EXT,MSG_SDTR	je p_mesginSDTR
+	cmp	REJBYTE_EXT,MSG_WDTR	je p_mesginWDTR
 	jmp	rej_mesgin
 
 p_mesginWDTR:
@@ -648,6 +700,7 @@
 						 * Requested SDTR too small
 						 * Reject it.
 						 */
+	clr	ARG_1				/* Use the scratch ram rate */
 	mvi	DINDEX, MSG0
 	mvi     MSG0     call mk_sdtr
 	or	SCSISIGO,ATNO			/* turn on ATNO */
@@ -659,6 +712,22 @@
  */
 mesgin_disconnect:
 	or	SCB_CONTROL,DISCONNECTED
+	test	FLAGS, PAGESCBS jz mesgin_done
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+	mvi	SCB_PREV, SCB_LIST_NULL
+	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
+	mov	SCB_NEXT, DISCONNECTED_SCBH
+	mov	DISCONNECTED_SCBH, SCBPTR
+	cmp	SCB_NEXT,SCB_LIST_NULL je linkdone
+	mov	SCBPTR,SCB_NEXT
+	mov	SCB_PREV,DISCONNECTED_SCBH
+	mov	SCBPTR,DISCONNECTED_SCBH
+linkdone:
+	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
 	jmp	mesgin_done
 
 /*
@@ -676,7 +745,7 @@
  * code do the rest.
  */
 mesgin_rdptrs:
-	and	FLAGS,0xfb			/*
+	and	FLAGS,0xef			/*
 						 * !DPHASE we'll reload them
 						 * the next time through
 						 */
@@ -699,21 +768,19 @@
 
 /*
  * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to switch to the proper
- * SCB.  Otherwise, we just use the findSCB method.
+ * If we get one, we use the tag returned to switch to find the proper
+ * SCB.  With SCB paging, this requires using findSCB for both tagged
+ * and non-tagged transactions since the SCB may exist in any slot.
+ * If we're not using SCB paging, we can use the tag as the direct
+ * index to the SCB.
  */
+	mvi	ARG_1,SCB_LIST_NULL	/* Default to no-tag */
 snoop_tag_loop:
 	test	SSTAT1,BUSFREE	jnz use_findSCB
 	test	SSTAT1,REQINIT	jz snoop_tag_loop
 	test	SSTAT1,PHASEMIS	jnz use_findSCB
 	mvi	A		call inb_first
-	cmp	A,MSG_SIMPLE_TAG je get_tag
-use_findSCB:
-	mov	ALLZEROS	call findSCB	  /* Have to search */
-setup_SCB:
-	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
-	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
-	jmp	ITloop
+	cmp	A,MSG_SIMPLE_TAG jne use_findSCB
 get_tag:
 	mvi	ARG_1	call inb_next	/* tag value */
 /*
@@ -729,16 +796,26 @@
  * Ensure that the SCB the tag points to is for a SCB transaction
  * to the reconnecting target.
  */
+	test	FLAGS, PAGESCBS	jz index_by_tag
+	call	inb_last			/* Ack Tag */
+use_findSCB:
+	mov	ALLZEROS	call findSCB	  /* Have to search */
+setup_SCB:
+	and	SCB_CONTROL,0xfb	  /* clear disconnect bit in SCB */
+	or	FLAGS,IDENTIFY_SEEN	  /* make note of IDENTIFY */
+	jmp	ITloop
+index_by_tag:
 	mov	SCBPTR,ARG_1
 	mov	A,SAVED_TCL
 	cmp	SCB_TCL,A		jne abort_tag
 	test	SCB_CONTROL,TAG_ENB	jz  abort_tag
 	call	inb_last			/* Ack Successful tag */
 	jmp	setup_SCB
+
 abort_tag:
 	or	SCSISIGO,ATNO			/* turn on ATNO */
 	mvi	INTSTAT,ABORT_TAG 		/* let driver know */
-	mvi	0xd		call mk_mesg	/* ABORT TAG message */
+	mvi	MSG_ABORT_TAG	call mk_mesg	/* ABORT TAG message */
 	jmp	mesgin_done
 
 /*
@@ -778,7 +855,7 @@
 mk_mesg:
 	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
 	test	MSG_LEN,0xff	jz mk_mesg1	/* Should always succeed */
-
+	
 	/*
 	 * Hmmm.  For some reason the mesg buffer is in use.
 	 * Tell the driver.  It should look at SINDEX to find
@@ -817,6 +894,7 @@
 	test	SSTAT0,SPIORDY	jz inb_next_wait /* wait for next byte */
 inb_first:
 	mov	DINDEX,SINDEX
+	test	SSTAT1,PHASEMIS	jnz mesgin_phasemis
 	mov	DINDIR,SCSIBUSL	ret		/*read byte directly from bus*/
 inb_last:
 	mov	NONE,SCSIDATL ret		/*dummy read from latch to ACK*/
@@ -887,27 +965,59 @@
 	mvi	INTSTAT,NO_IDENT 	ret	/* no - cause a kernel panic */
 
 /*
- * Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch 
- * the SCB to it.  Have the kernel print a warning message if it can't be 
- * found, and generate an ABORT message to the target.  SINDEX should be
+ * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
+ * value in ARG_1.  If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
+ * SCB.  Have the kernel print a warning message if it can't be found, and
+ * generate an ABORT/ABORT_TAG message to the target.  SINDEX should be
  * cleared on call.
  */
 findSCB:
 	mov	A,SAVED_TCL
-	mov	SCBPTR,SINDEX			/* switch to new SCB */
+	mov	SCBPTR,SINDEX			/* switch to next SCB */
+	mvi	SEQCTL,0x50			/* PAUSEDIS|FASTMODE */
 	cmp	SCB_TCL,A	jne findSCB1 /* target ID/channel/lun match? */
 	test	SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
-	ret
+	test	SCB_CONTROL,TAG_ENB jnz findTaggedSCB
+	cmp	ARG_1,SCB_LIST_NULL je foundSCB
+	jmp	findSCB1
+findTaggedSCB:
+	mov	A, ARG_1			/* Tag passed in ARG_1 */
+	cmp	SCB_TAG,A	jne findSCB1	/* Found it? */
+foundSCB:
+	test	FLAGS,PAGESCBS	jz foundSCB_ret
+/* Remove this SCB from the disconnection list */
+	cmp	SCB_NEXT,SCB_LIST_NULL je unlink_prev
+	mov	SAVED_LINKPTR, SCB_PREV
+	mov	SCBPTR, SCB_NEXT
+	mov	SCB_PREV, SAVED_LINKPTR
+	mov	SCBPTR, SINDEX
+unlink_prev:
+	cmp	SCB_PREV,SCB_LIST_NULL	je rHead/* At the head of the list */
+	mov	SAVED_LINKPTR, SCB_NEXT
+	mov	SCBPTR, SCB_PREV
+	mov	SCB_NEXT, SAVED_LINKPTR
+	mov	SCBPTR, SINDEX
+	mvi	SEQCTL,0x10	ret		/* !PAUSEDIS|FASTMODE */
+rHead:
+	mov	DISCONNECTED_SCBH,SCB_NEXT
+foundSCB_ret:
+	mvi	SEQCTL,0x10	ret		/* !PAUSEDIS|FASTMODE */
 
 findSCB1:
+	mvi	SEQCTL,0x10			/* !PAUSEDIS|FASTMODE */
 	inc	SINDEX
 	mov	A,SCBCOUNT
 	cmp	SINDEX,A	jne findSCB
 
 	mvi	INTSTAT,NO_MATCH		/* not found - signal kernel */
-	mvi	MSG_ABORT	call mk_mesg	/* ABORT message */
-
-	or	SCSISIGO,ATNO	ret		/* assert ATNO */
+	cmp	RETURN_1,SCB_PAGEDIN je return
+	or	SCSISIGO,ATNO			/* assert ATNO */
+	cmp	ARG_1,SCB_LIST_NULL jne find_abort_tag
+	mvi	MSG_ABORT	call mk_mesg
+	jmp	ITloop
+find_abort_tag:
+	mvi	MSG_ABORT_TAG	call mk_mesg
+	jmp	ITloop
 
 /*
  * Make a working copy of the scatter-gather parameters from the SCB.
@@ -980,7 +1090,7 @@
  */
 mk_dtr:
 	test	SCB_CONTROL,NEEDWDTR jnz  mk_wdtr_16bit
-	or	FLAGS, MAXOFFSET	/* Force an offset of 15 or 8 if WIDE */
+	mvi	ARG_1, MAXOFFSET	/* Force an offset of 15 or 8 if WIDE */
 
 mk_sdtr:
 	mvi	DINDIR,1		/* extended message */
@@ -988,7 +1098,7 @@
 	mvi	DINDIR,1		/* SDTR code */
 	call	sdtr_to_rate
 	mov	DINDIR,RETURN_1		/* REQ/ACK transfer period */
-	test	FLAGS, MAXOFFSET jnz mk_sdtr_max_offset
+	cmp	ARG_1, MAXOFFSET je mk_sdtr_max_offset
 	and	DINDIR,0x0f,SINDIR	/* Sync Offset */
 
 mk_sdtr_done:
@@ -998,8 +1108,6 @@
 /*
  * We're initiating sync negotiation, so request the max offset we can (15 or 8)
  */
-	xor	FLAGS, MAXOFFSET
-
 	/* Talking to a WIDE device? */
 	test	SCSIRATE, WIDEXFER	jnz wmax_offset	
 	mvi	DINDIR, MAX_OFFSET_8BIT

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov