summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/aic7xxx/aic7xxx.seq199
1 files changed, 104 insertions, 95 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq
index 435da74..c5a1e9b 100644
--- a/sys/dev/aic7xxx/aic7xxx.seq
+++ b/sys/dev/aic7xxx/aic7xxx.seq
@@ -41,11 +41,12 @@
#
##-M#########################################################################
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.13 1995/04/09 06:40:16 gibbs Exp $"
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.14 1995/04/15 21:45:56 gibbs Exp $"
SCBMASK = 0x1f
SCSISEQ = 0x00
+ENRSELI = 0x10
SXFRCTL0 = 0x01
SXFRCTL1 = 0x02
SCSISIGI = 0x03
@@ -57,7 +58,10 @@ STCNT = 0x08
STCNT+0 = 0x08
STCNT+1 = 0x09
STCNT+2 = 0x0a
+CLRSINT0 = 0x0b
SSTAT0 = 0x0b
+SELDO = 0x40
+SELDI = 0x20
CLRSINT1 = 0x0c
SSTAT1 = 0x0c
SIMODE1 = 0x11
@@ -138,9 +142,10 @@ SCBARRAY+26 = 0xba
SCBARRAY+27 = 0xbb
SCBARRAY+28 = 0xbc
SCBARRAY+29 = 0xbd
+SCBARRAY+30 = 0xbe
BAD_PHASE = 0x01 # unknown scsi bus phase
-CMDCMPLT = 0x02
+CMDCMPLT = 0x02 # Command Complete
SEND_REJECT = 0x11 # sending a message reject
NO_IDENT = 0x21 # no IDENTIFY after reconnect
NO_MATCH = 0x31 # no cmd match for reconnect
@@ -164,23 +169,23 @@ ABORT_TAG = 0x91 # Sent an ABORT_TAG message
# when a WDTR or SDTR message should be sent to the target the SCB's
# command references.
#
-# The high bit of DROPATN is set if ATN should be dropped before the ACK
-# when outb is called. REJBYTE contains the first byte of a MESSAGE IN
-# message, so the driver can report an intelligible error if a message is
-# rejected.
+# REJBYTE contains the first byte of a MESSAGE IN message, so the driver
+# can report an intelligible error if a message is rejected.
#
# FLAGS's high bit is true if we are currently handling a reselect;
# its next-highest bit is true ONLY IF we've seen an IDENTIFY message
# from the reselecting target. If we haven't had IDENTIFY, then we have
# no idea what the lun is, and we can't select the right SCB register
# bank, so force a kernel panic if the target attempts a data in/out or
-# command phase instead of corrupting something.
+# command phase instead of corrupting something. FLAGS also contains
+# configuration bits so that we can optimize for TWIN and WIDE controllers
+# as well as the MAX_SYNC bit which we set when we want to negotiate for
+# 10MHz irregardless of what the per target scratch space says.
#
# Note that SG_NEXT occupies four bytes.
#
SYNCNEG = 0x20
-DROPATN = 0x30
REJBYTE = 0x31
DISC_DSB_A = 0x32
DISC_DSB_B = 0x33
@@ -218,49 +223,77 @@ FLAGS = 0x53 # Device configuration flags
TWIN_BUS = 0x01
WIDE_BUS = 0x02
MAX_SYNC = 0x08
-SENSE = 0x10
ACTIVE_MSG = 0x20
IDENTIFY_SEEN = 0x40
RESELECTED = 0x80
ACTIVE_A = 0x54
ACTIVE_B = 0x55
-SAVED_TCL = 0x56
+SAVED_TCL = 0x56 # Temporary storage for the
+ # target/channel/lun of a
+ # reconnecting target
+
+# After starting the selection hardware, we return to the "poll_for_work"
+# loop so that we can check for reconnecting targets as well as for our
+# selection to complete just in case the reselection wins bus arbitration.
+# The problem with this is that we must keep track of the SCB that we've
+# already pulled from the QINFIFO and started the selection on just in case
+# the reselection wins so that we can retry the selection at a later time.
+# This problem cannot be resolved by holding a single entry in scratch
+# ram since a reconnecting target can request sense and this will create
+# yet another SCB waiting for selection. The solution used here is to
+# use byte 31 of the SCB as a psuedo-next pointer and to thread a list
+# of SCBs that are awaiting selection. Since 0 is a valid SCB offset,
+# SCB_LIST_NULL is 0x10 which is out of range. The kernel driver must
+# add an entry to this list everytime a request sense occurs. The sequencer
+# will automatically consume the entries.
+
+WAITING_SCBH = 0x57 # head of list of SCBs awaiting
+ # selection
+WAITING_SCBT = 0x58 # tail of list of SCBs awaiting
+ # selection
+SCB_LIST_NULL = 0x10
+
+
# Poll QINCNT for work - the lower bits contain
# the number of entries in the Queue In FIFO.
#
start:
- test FLAGS,SENSE jnz start_sense
-start_nosense:
+ test WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+poll_for_work:
test FLAGS,TWIN_BUS jz start2 # Are we a twin channel device?
# For fairness, we check the other bus first, since we just finished a
# transaction on the current channel.
xor SBLKCTL,0x08 # Toggle to the other bus
- test SCSISIGI,0x4 jnz reselect # BSYI
+ test SSTAT0,SELDI jnz reselect
+ test SSTAT0,SELDO jnz select
xor SBLKCTL,0x08 # Toggle to the original bus
start2:
- test SCSISIGI,0x4 jnz reselect # BSYI
- test QINCNT,SCBMASK jz start_nosense
+ test SSTAT0,SELDI jnz reselect
+ test SSTAT0,SELDO jnz select
+ test WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+ test QINCNT,SCBMASK jz poll_for_work
-# We have at least one queued SCB now. Set the SCB pointer
-# from the FIFO so we see the right bank of SCB registers,
-# then set SCSI options and set the initiator and target
-# SCSI IDs.
+# We have at least one queued SCB now and we don't have any
+# SCBs in the list of SCBs awaiting selection. Set the SCB
+# pointer from the FIFO so we see the right bank of SCB
+# registers, then set SCSI options and set the initiator and
+# target SCSI IDs.
#
mov SCBPTR,QINFIFO
# If the control byte of this SCB has the NEEDDMA flag set, we have
# yet to DMA it from host memory
-test SCBARRAY+0,NEEDDMA jz test_busy
+test SCBARRAY+0,NEEDDMA jz test_busy
clr HCNT+2
clr HCNT+1
mvi HCNT+0,SCB_SIZEOF
- mvi DINDEX,HADDR
- mvi SCBARRAY+26 call bcopy_4
-
- mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET
+ mvi DINDEX,HADDR
+ mvi SCBARRAY+26 call bcopy_4
+
+ mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET
# Wait for DMA from host memory to data FIFO to complete, then disable
# DMA and wait for it to acknowledge that it's off.
@@ -270,12 +303,12 @@ test SCBARRAY+0,NEEDDMA jz test_busy
# Copy the SCB from the FIFO to the SCBARRAY
mvi DINDEX, SCBARRAY+0
- call bcopy_3_dfdat
- call bcopy_4_dfdat
+ call bcopy_3_dfdat
call bcopy_4_dfdat
call bcopy_4_dfdat
+ call bcopy_4_dfdat
call bcopy_4_dfdat
-
+
# See if there is not already an active SCB for this target. This code
# locks out on a per target basis instead of target/lun. Although this
# is not ideal for devices that have multiple luns active at the same
@@ -295,27 +328,35 @@ test_busy:
or ACTIVE_B,A # Mark the current target as busy
jmp start_scb
-start_sense:
-# Clear the SENSE flag first, then do a normal start_scb
- and FLAGS,0xef
- jmp start_scb
-
# Place the currently active back on the queue for later processing
requeue:
mov QINFIFO, SCBPTR
- jmp start_nosense
+ jmp poll_for_work
+
+# Pull the first entry off of the waiting for selection list
+start_waiting:
+ mov SCBPTR,WAITING_SCBH
+ jmp start_scb
test_a:
test ACTIVE_A,A jnz requeue
or ACTIVE_A,A # Mark the current target as busy
start_scb:
- or SCBARRAY+0,NEEDDMA
and SINDEX,0xf7,SBLKCTL #Clear the channel select bit
and A,0x08,SCBARRAY+1 #Get new channel bit
or SINDEX,A
mov SBLKCTL,SINDEX # select channel
- mov SCBARRAY+1 call initialize
+ mov SCBARRAY+1 call initialize_scsiid
+
+# Enable selection phase as an initiator, and do automatic ATN
+# after the selection. We do this now so that we can overlap the
+# rest of our work to set up this target with the arbitration and
+# selection bus phases.
+#
+start_selection:
+ or SCSISEQ,0x48 # ENSELO|ENAUTOATNO
+ mov WAITING_SCBH, SCBPTR
clr SG_NOLOAD
and FLAGS,0x3f # !RESELECTING
@@ -355,61 +396,30 @@ mk_tag_done:
mov DINDEX call mk_dtr # build DTR message if needed
!message:
+ jmp poll_for_work
-# Enable selection phase as an initiator, and do automatic ATN
-# after the selection.
-#
- mvi SCSISEQ,0x48 # ENSELO|ENAUTOATNO
-
-# Wait for successful arbitration. The AIC-7770 documentation says
-# that SELINGO indicates successful arbitration, and that it should
-# be used to look for SELDO. However, if the sequencer is paused at
-# just the right time - a parallel fsck(8) on two drives did it for
-# me - then SELINGO can flip back to false before we've seen it. This
-# makes the sequencer sit in the arbitration loop forever. This is
-# Not Good.
-#
-# Therefore, I've added a check in the arbitration loop for SELDO
-# too. This could arguably be made a critical section by disabling
-# pauses, but I don't want to make a potentially infinite loop a CS.
-# I suppose you could fold it into the select loop, too, but since
-# I've been hunting this bug for four days it's kinda like a trophy.
-#
-arbitrate:
- test SSTAT0,0x40 jnz *select # SELDO
- test SSTAT0,0x10 jz arbitrate # SELINGO
-
-# Wait for a successful selection. If the hardware selection
-# timer goes off, then the driver gets the interrupt, so we don't
-# need to worry about it.
-#
-select:
- test SSTAT0,0x40 jz select # SELDO
- jmp *select
-
-# Reselection is being initiated by a target - we've seen the BSY
-# line driven active, and we didn't do it! Enable the reselection
-# hardware, and wait for it to finish. Make a note that we've been
+# 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.
#
reselect:
- mvi SCSISEQ,0x10 # ENRSELI
-
-reselect1:
- test SSTAT0,0x20 jz reselect1 # SELDI
- mov SELID call initialize
-
+ mov SELID call initialize_scsiid
and FLAGS,0x3f # reselected, no IDENTIFY
- or FLAGS,RESELECTED
+ or FLAGS,RESELECTED jmp select2
-# After the [re]selection, make sure that the [re]selection enable
-# bit is off. This chip is flaky enough without extra things
-# turned on. Also clear the BUSFREE bit in SSTAT1 since we'll be
-# using it shortly.
+# After the selection, remove this SCB from the "waiting for selection"
+# list. This is achieved by simply moving our "next" pointer into
+# WAITING_SCBH and setting our next pointer to null so that the next
+# time this SCB is used, we don't get confused.
#
-*select:
- clr SCSISEQ
+select:
+ or SCBARRAY+0,NEEDDMA
+ mov WAITING_SCBH,SCBARRAY+30
+ mvi SCBARRAY+30,SCB_LIST_NULL
+select2:
+ call initialize_for_target
+ mvi SCSISEQ,ENRSELI
+ mvi CLRSINT0,0x60 # CLRSELDI|CLRSELDO
mvi CLRSINT1,0x8 # CLRBUSFREE
# Main loop for information transfer phases. If BSY is false, then
@@ -636,11 +646,12 @@ p_mesgin:
# 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 and set the SENSE sequencer flag. If the sense flag is
-# set, the sequencer imediately jumps to start working on the sense
-# command. If the kernel driver does not wish to request sense, it need
-# do nothing, and the command is allowed to complete. We don't
+# 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 imediately
+# 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.
@@ -653,7 +664,7 @@ p_mesgin:
check_status:
test SCBARRAY+14,0xff jz status_ok # 0 Status?
mvi INTSTAT,BAD_STATUS # let driver know
- test FLAGS,SENSE jz status_ok
+ test RETURN_1, 0x80 jz status_ok
jmp p_mesgin_done
status_ok:
@@ -977,23 +988,21 @@ dma_finish2:
# the target SCSI ID to be in the upper four bits of SINDEX, and A's
# contents are stomped on return.
#
-initialize:
+initialize_scsiid:
and SINDEX,0xf0 # Get target ID
and A,0x0f,SCSIID
or SINDEX,A
- mov SCSIID,SINDEX
-
-# Esundry initialization.
-#
- clr DROPATN
- clr SIGSTATE
+ mov SCSIID,SINDEX ret
+initialize_for_target:
# Turn on Automatic PIO mode now, before we expect to see a REQ
# from the target. It shouldn't hurt anything to leave it on. Set
# CLRCHN here before the target has entered a data transfer mode -
# with synchronous SCSI, if you do it later, you blow away some
# data in the SCSI FIFO that the target has already sent to you.
#
+ clr SIGSTATE
+
mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN
# Initialize scatter-gather pointers by setting up the working copy
OpenPOWER on IntegriCloud