patch-1.3.36 linux/drivers/scsi/aic7xxx.seq
Next file: linux/drivers/scsi/aic7xxx_asm.c
Previous file: linux/drivers/scsi/aic7xxx.h
Back to the patch index
Back to the overall index
- Lines: 931
- Date:
Mon Oct 23 13:21:53 1995
- Orig file:
v1.3.35/linux/drivers/scsi/aic7xxx.seq
- Orig date:
Wed Aug 2 13:21:07 1995
diff -u --recursive --new-file v1.3.35/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
@@ -25,9 +25,9 @@
# optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
##-M#########################################################################
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.0 1995/08/02 05:28:42 deang Exp $"
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 2.1 1995/08/30 07:47:07 deang Exp $"
-SCBMASK = 0x1f
+SCBMASK = 0xff
SCSISEQ = 0x00
ENRSELI = 0x10
@@ -48,6 +48,7 @@
SELDI = 0x20
CLRSINT1 = 0x0c
SSTAT1 = 0x0c
+PHASEMIS = 0x10
SIMODE1 = 0x11
SCSIBUSL = 0x12
SHADDR = 0x14
@@ -83,18 +84,19 @@
SCSICONF_B = 0x5b
# The two reserved bytes at SCBARRAY+1[23] are expected to be set to
-# zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
-# to indicate whether or not to reload scatter-gather parameters after
-# a disconnect. We also use bits 6 & 7 to indicate whether or not to
-# initiate SDTR or WDTR repectively when starting this command.
+# zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
+# whether or not to DMA an SCB from host ram. This flag prevents the
+# "re-fetching" of transactions that are requed because the target is
+# busy with another command. We also use bits 6 & 7 to indicate whether
+# or not to initiate SDTR or WDTR repectively when starting this command.
#
SCBARRAY+0 = 0xa0
DISCONNECTED = 0x04
NEEDDMA = 0x08
-SG_LOAD = 0x10
+NEEDSDTR = 0x10
TAG_ENB = 0x20
-NEEDSDTR = 0x40
+DISCENB = 0x40
NEEDWDTR = 0x80
SCBARRAY+1 = 0xa1
@@ -144,6 +146,7 @@
# (command was null), so tell
# it that it can fill the
# message buffer.
+IMMEDDONE = 0xb1
# The host adapter card (at least the BIOS) uses 20-2f for SCSI
@@ -153,11 +156,11 @@
# scratchspace (actually a value that can be copied directly into
# SCSIRATE). The kernel driver will enable synchronous negotiation
# for all targets that have a value other than 0 in the lower four
-# bits of the target scratch space. This should work irregardless of
-# whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top
-# two bits of the SCB control byte. The kernel driver will set these
-# when a WDTR or SDTR message should be sent to the target the SCB's
-# command references.
+# bits of the target scratch space. This should work regardless of
+# whether the bios has been installed. NEEDSDTR and NEEDWDTR are the
+# fouth and sevent bits of the SCB control byte. The kernel driver
+# will set these when a WDTR or SDTR message should be sent to the
+# target the SCB's command references.
#
# REJBYTE contains the first byte of a MESSAGE IN message, so the driver
# can report an intelligible error if a message is rejected.
@@ -168,9 +171,9 @@
# 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. FLAGS also contains
-# configuration bits so that we can optimize for TWIN and WIDE controllers
-# as well as the MAX_OFFSET bit which we set when we want to negotiate for
-# maximum sync offset irregardless of what the per target scratch space says.
+# configuration bits so that we can optimize for TWIN and WIDE controllers,
+# the MAX_OFFSET bit which we set when we want to negotiate for maximum sync
+# offset irregardless of what the per target scratch space says.
#
# Note that SG_NEXT occupies four bytes.
#
@@ -198,13 +201,9 @@
# Linux users should use 0xc (12) for SG_SIZEOF
#SG_SIZEOF = 0x8 # sizeof(struct ahc_dma)
SG_SIZEOF = 0xc # sizeof(struct scatterlist)
-# if AIC7XXX_USE_SG
-SCB_SIZEOF = 0x13 # sizeof SCB to DMA (19 bytes)
-# else
-#SCB_SIZEOF = 0x1a # sizeof SCB without SG
-# endif
+SCB_SIZEOF = 0x1a # sizeof SCB to DMA (26 bytes)
-SG_NOLOAD = 0x4c # load SG pointer/length?
+DMAPARAMS = 0x4c # Parameters for DMA
SG_COUNT = 0x4d # working value of SG count
SG_NEXT = 0x4e # working value of SG pointer
SG_NEXT+0 = 0x4e
@@ -216,6 +215,7 @@
FLAGS = 0x53 # Device configuration flags
TWIN_BUS = 0x01
WIDE_BUS = 0x02
+DPHASE = 0x04
MAX_OFFSET = 0x08
ACTIVE_MSG = 0x20
IDENTIFY_SEEN = 0x40
@@ -240,8 +240,8 @@
# 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
+# of SCBs that are awaiting selection. Since 0-0xfe are valid SCB offsets,
+# SCB_LIST_NULL is 0xff 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.
@@ -249,26 +249,22 @@
# selection
WAITING_SCBT = 0x58 # tail of list of SCBs awaiting
# selection
-SCB_LIST_NULL = 0x10
+SCB_LIST_NULL = 0xff
# Poll QINCNT for work - the lower bits contain
# the number of entries in the Queue In FIFO.
#
-start:
- 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 SSTAT0,SELDI jnz reselect
- test SSTAT0,SELDO jnz select
xor SBLKCTL,0x08 # Toggle to the original bus
start2:
test SSTAT0,SELDI jnz reselect
- test SSTAT0,SELDO jnz select
- test WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+ cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting
test QINCNT,SCBMASK jz poll_for_work
# We have at least one queued SCB now and we don't have any
@@ -300,15 +296,10 @@
# Copy the SCB from the FIFO to the SCBARRAY
mvi DINDEX, SCBARRAY+0
- call bcopy_3_dfdat
- call bcopy_4_dfdat
- call bcopy_4_dfdat
- call bcopy_4_dfdat
- call bcopy_4_dfdat
-# ifndef AIC7XXX_USE_SG
-# call bcopy_3_dfdat
-# call bcopy_4_dfdat
-# endif
+ call bcopy_5_dfdat
+ call bcopy_7_dfdat
+ call bcopy_7_dfdat
+ call bcopy_7_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
@@ -320,12 +311,12 @@
# initialization, board reset, and a target's SELTO.
test_busy:
- test SCBARRAY+0,0x20 jnz start_scb
and FUNCTION1,0x70,SCBARRAY+1
mov A,FUNCTION1
test SCBARRAY+1,0x88 jz test_a # Id < 8 && A channel
test ACTIVE_B,A jnz requeue
+ test SCBARRAY+0,TAG_ENB jnz start_scb
or ACTIVE_B,A # Mark the current target as busy
jmp start_scb
@@ -341,6 +332,7 @@
test_a:
test ACTIVE_A,A jnz requeue
+ test SCBARRAY+0,TAG_ENB jnz start_scb
or ACTIVE_A,A # Mark the current target as busy
start_scb:
@@ -358,8 +350,7 @@
start_selection:
or SCSISEQ,0x48 # ENSELO|ENAUTOATNO
mov WAITING_SCBH, SCBPTR
- clr SG_NOLOAD
- and FLAGS,0x3f # !RESELECTING
+ and FLAGS,0x3f # !RESELECTING
# As soon as we get a successful selection, the target should go
# into the message out phase since we have ATN asserted. Prepare
@@ -378,17 +369,17 @@
# so we interrupt the driver, allow it to fill the message buffer, and
# then go back into the arbitration loop
mvi INTSTAT,AWAITING_MSG
- jmp poll_for_work
+ jmp wait_for_selection
identify:
- mov SCBARRAY+1 call disconnect # disconnect ok?
+ and A,DISCENB,SCBARRAY+0 # mask off disconnect privledge
and SINDEX,0x7,SCBARRAY+1 # lun
- or SINDEX,A # return value from disconnect
+ or SINDEX,A # or in disconnect privledge
or SINDEX,0x80 call mk_mesg # IDENTIFY message
mov A,SINDEX
- test SCBARRAY+0,0xe0 jz !message # WDTR, SDTR or TAG??
+ test SCBARRAY+0,0xb0 jz !message # WDTR, SDTR or TAG??
cmp MSG_START+0,A jne !message # did driver beat us?
# Tag Message if Tag enabled in SCB control block. Use SCBPTR as the tag
@@ -408,7 +399,10 @@
mov DINDEX call mk_dtr # build DTR message if needed
!message:
- jmp poll_for_work
+wait_for_selection:
+ test SSTAT0,SELDI jnz reselect
+ test SSTAT0,SELDO jnz select
+ jmp wait_for_selection
# 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
@@ -461,78 +455,118 @@
p_dataout:
mvi 0 call scsisig # !CDO|!IOO|!MSGO
- call assert
- call sg_load
+ mvi DMAPARAMS,0x7d # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+ # DIRECTION|FIFORESET
+ jmp data_phase_init
- mvi DINDEX,HADDR
- mvi SCBARRAY+19 call bcopy_4
+# If we re-enter the data phase after going through another phase, the
+# STCNT may have been cleared, so restore it from the residual field.
+data_phase_reinit:
+ mvi DINDEX, STCNT
+ mvi SCBARRAY+15 call bcopy_3
+ jmp data_phase_loop
-# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR
- mvi SCBARRAY+23 call bcopy_3
+# Reads should not use WIDEODD since it may make the last byte for a SG segment
+# go to the next segment.
+p_datain:
+ mvi 0x40 call scsisig # !CDO|IOO|!MSGO
+ mvi DMAPARAMS,0x39 # SCSIEN|SDMAEN|HDMAEN|
+ # !DIRECTION|FIFORESET
+data_phase_init:
+ call assert
- mvi DINDEX,STCNT
- mvi SCBARRAY+23 call bcopy_3
+ test FLAGS, DPHASE jnz data_phase_reinit
+ call sg_scb2ram
+ or FLAGS, DPHASE # We have seen a data phase
+data_phase_loop:
# If we are the last SG block, don't set wideodd.
- test SCBARRAY+18,0xff jnz p_dataout_wideodd
- mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN|
- # DIRECTION|FIFORESET
- jmp p_dataout_rest
+ cmp SG_COUNT,0x01 jne data_phase_wideodd
+ and DMAPARAMS, 0xbf # Turn off WIDEODD
+data_phase_wideodd:
+ mov DMAPARAMS call dma
-p_dataout_wideodd:
- mvi 0xbd call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- # DIRECTION|FIFORESET
+# Exit if we had an underrun
+ test SSTAT0,0x04 jz data_phase_finish # underrun STCNT != 0
-p_dataout_rest:
-# After a DMA finishes, save the final transfer pointer and count
-# back into the SCB, in case a device disconnects in the middle of
-# a transfer. Use SHADDR and STCNT instead of HADDR and HCNT, since
-# it's a reflection of how many bytes were transferred on the SCSI
-# (as opposed to the host) bus.
+# Advance the scatter-gather pointers if needed
#
- mvi DINDEX,SCBARRAY+23
- mvi STCNT call bcopy_3
-
- mvi DINDEX,SCBARRAY+19
- mvi SHADDR call bcopy_4
+sg_advance:
+ dec SG_COUNT # one less segment to go
- call sg_advance
- mov SCBARRAY+18,SG_COUNT # residual S/G count
+ test SG_COUNT, 0xff jz data_phase_finish #Are we done?
- jmp ITloop
+ clr A # add sizeof(struct scatter)
+ add SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
+ adc SG_NEXT+1,A,SG_NEXT+1
+ adc SG_NEXT+2,A,SG_NEXT+2
+ adc SG_NEXT+3,A,SG_NEXT+3
-p_datain:
- mvi 0x40 call scsisig # !CDO|IOO|!MSGO
- call assert
- call sg_load
+# Load a struct scatter and set up the data address and length.
+# If the working value of the SG count is nonzero, then
+# we need to load a new set of values.
+#
+# This, like all DMA's, assumes a little-endian host data storage.
+#
+sg_load:
+ clr HCNT+2
+ clr HCNT+1
+ mvi HCNT+0,SG_SIZEOF
mvi DINDEX,HADDR
- mvi SCBARRAY+19 call bcopy_4
+ mvi SG_NEXT call bcopy_4
-# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR
- mvi SCBARRAY+23 call bcopy_3
+ mvi DFCNTRL,0xd # HDMAEN|DIRECTION|FIFORESET
- mvi DINDEX,STCNT
- mvi SCBARRAY+23 call bcopy_3
+# Wait for DMA from host memory to data FIFO to complete, then disable
+# DMA and wait for it to acknowledge that it's off.
+#
+ call dma_finish
-# If we are the last SG block, don't set wideodd.
- test SCBARRAY+18,0xff jnz p_datain_wideodd
- mvi 0x39 call dma # SCSIEN|SDMAEN|HDMAEN|
- # !DIRECTION|FIFORESET
- jmp p_datain_rest
-p_datain_wideodd:
- mvi 0xb9 call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- # !DIRECTION|FIFORESET
-p_datain_rest:
- mvi DINDEX,SCBARRAY+23
- mvi STCNT call bcopy_3
+# Copy data from FIFO into SCB data pointer and data count. This assumes
+# that the struct scatterlist has this structure (this and sizeof(struct
+# scatterlist) == 12 are asserted in aic7xxx.c):
+#
+# struct scatterlist {
+# char *address; /* four bytes, little-endian order */
+# ... /* four bytes, ignored */
+# unsigned short length; /* two bytes, little-endian order */
+# }
+#
- mvi DINDEX,SCBARRAY+19
- mvi SHADDR call bcopy_4
+# Not in FreeBSD. the scatter list entry is only 8 bytes.
+#
+# struct ahc_dma_seg {
+# physaddr addr; /* four bytes, little-endian order */
+# long len; /* four bytes, little endian order */
+# };
+#
+
+ mvi DINDEX,HADDR
+# call bcopy_7_dfdat
+
+# For Linux, we must throw away four bytes since there is a 32bit gap
+# in the middle of a struct scatterlist
+ call bcopy_4_dfdat
+ mov NONE,DFDAT
+ mov NONE,DFDAT
+ mov NONE,DFDAT
+ mov NONE,DFDAT
+ call bcopy_3_dfdat #Only support 24 bit length.
- call sg_advance
- mov SCBARRAY+18,SG_COUNT # residual S/G count
+# Load STCNT as well. It is a mirror of HCNT
+ mvi DINDEX,STCNT
+ mvi HCNT call bcopy_3
+ test SSTAT1,PHASEMIS jz data_phase_loop
+data_phase_finish:
+# After a DMA finishes, save the SG and STCNT residuals back into the SCB
+# We use STCNT instead of HCNT, since it's a reflection of how many bytes
+# were transferred on the SCSI (as opposed to the host) bus.
+#
+ mvi DINDEX,SCBARRAY+15
+ mvi STCNT call bcopy_3
+ mov SCBARRAY+18, SG_COUNT
jmp ITloop
# Command phase. Set up the DMA registers and let 'er rip - the
@@ -543,11 +577,9 @@
mvi 0x80 call scsisig # CDO|!IOO|!MSGO
call assert
+# Load HADDR and HCNT. We can do this in one bcopy since they are neighbors
mvi DINDEX,HADDR
- mvi SCBARRAY+7 call bcopy_4
-
-# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR
- mvi SCBARRAY+11 call bcopy_3
+ mvi SCBARRAY+7 call bcopy_7
mvi DINDEX,STCNT
mvi SCBARRAY+11 call bcopy_3
@@ -563,7 +595,7 @@
mvi 0xc0 call scsisig # CDO|IOO|!MSGO
mvi SCBARRAY+14 call inb_first
- jmp p_mesgin_done
+ jmp mesgin_done
# Message out phase. If there is no active message, but the target
# took us into this phase anyway, build a no-op message and send it.
@@ -651,8 +683,34 @@
mvi A call inb_first # read the 1st message byte
mvi REJBYTE,A # save it for the driver
- cmp ALLZEROS,A jne p_mesgin1
+ test A,0x80 jnz mesgin_identify # identify message?
+ cmp A,4 je mesgin_disconnect # disconnect?
+ cmp A,2 je mesgin_sdptrs # save data pointers?
+ cmp ALLZEROS,A je mesgin_complete # command complete?
+ cmp A,3 je mesgin_rdptrs # restore pointers code?
+ cmp A,1 je mesgin_extended # extended message?
+ cmp A,7 je mesgin_reject # message reject code?
+
+rej_mesgin:
+# We have no idea what this message in is, and there's no way
+# to pass it up to the kernel, so we issue a message reject and
+# hope for the best. Since we're now using manual PIO mode to
+# read in the message, there should no longer be a race condition
+# present when we assert ATN. In any case, rejection should be a
+# rare occurrence - signal the driver when it happens.
+#
+ or SINDEX,0x10,SIGSTATE # turn on ATNO
+ call scsisig
+ mvi INTSTAT,SEND_REJECT # let driver know
+
+ mvi 0x7 call mk_mesg # MESSAGE REJECT message
+
+mesgin_done:
+ call inb_last # ack & turn auto PIO back on
+ jmp ITloop
+
+mesgin_complete:
# We got a "command complete" message, so put the SCB pointer
# into the Queue Out, and trigger a completion interrupt.
# Check status for non zero return and interrupt driver if needed
@@ -669,19 +727,17 @@
# before the command complete code tried processing it.
# First check for residuals
- test SCBARRAY+15,0xff jnz resid
- test SCBARRAY+16,0xff jnz resid
- test SCBARRAY+17,0xff jnz resid
+ test SCBARRAY+18,0xff jnz resid
check_status:
test SCBARRAY+14,0xff jz status_ok # 0 Status?
mvi INTSTAT,BAD_STATUS # let driver know
test RETURN_1, 0x80 jz status_ok
- jmp p_mesgin_done
+ jmp mesgin_done
status_ok:
# First, mark this target as free.
- test SCBARRAY+0,0x20 jnz complete # Tagged command
+ test SCBARRAY+0,TAG_ENB jnz complete # Tagged command
and FUNCTION1,0x70,SCBARRAY+1
mov A,FUNCTION1
test SCBARRAY+1,0x88 jz clear_a
@@ -691,11 +747,16 @@
clear_a:
xor ACTIVE_A,A
+ test SCBARRAY+11,0xff jnz complete # Immediate message complete
+# Pause the sequencer until the driver gets around to handling the command
+# complete. This is so that any action that might require carefull timing
+# with the completion of this command can occur.
+ mvi INTSTAT,IMMEDDONE
+ jmp poll_for_work
complete:
mov QOUTFIFO,SCBPTR
mvi INTSTAT,CMDCMPLT
- test SCBARRAY+11,0xff jz start # Immediate message complete
- jmp p_mesgin_done
+ jmp mesgin_done
# If we have a residual count, interrupt and tell the host. Other
# alternatives are to pause the sequencer on all command completes (yuck),
@@ -714,21 +775,19 @@
# apparently this can be done after any message in byte, according
# to the SCSI-2 spec.
#
-p_mesgin1:
- cmp A,1 jne p_mesgin2 # extended message code?
-
+mesgin_extended:
mvi ARG_1 call inb_next # extended message length
mvi A call inb_next # extended message code
cmp A,1 je p_mesginSDTR # Syncronous negotiation message
cmp A,3 je p_mesginWDTR # Wide negotiation message
- jmp p_mesginN
+ jmp rej_mesgin
p_mesginWDTR:
- cmp ARG_1,2 jne p_mesginN # extended mesg length = 2
+ cmp ARG_1,2 jne rej_mesgin # extended mesg length=2
mvi A call inb_next # Width of bus
mvi INTSTAT,MSG_WDTR # let driver know
- test RETURN_1,0x80 jz p_mesgin_done# Do we need to send WDTR?
+ test RETURN_1,0x80 jz mesgin_done# Do we need to send WDTR?
# We didn't initiate the wide negotiation, so we must respond to the request
and RETURN_1,0x7f # Clear the SEND_WDTR Flag
@@ -737,59 +796,53 @@
mvi MSG_START+0 call mk_wdtr # build WDTR message
or SINDEX,0x10,SIGSTATE # turn on ATNO
call scsisig
- jmp p_mesgin_done
+ jmp mesgin_done
p_mesginSDTR:
- cmp ARG_1,3 jne p_mesginN # extended mesg length = 3
+ cmp ARG_1,3 jne rej_mesgin # extended mesg length=3
mvi ARG_1 call inb_next # xfer period
mvi A call inb_next # REQ/ACK offset
mvi INTSTAT,MSG_SDTR # call driver to convert
- test RETURN_1,0xc0 jz p_mesgin_done# Do we need to mk_sdtr or rej?
- test RETURN_1,0x40 jnz p_mesginN # Requested SDTR too small - rej
+ test RETURN_1,0xc0 jz mesgin_done# Do we need to mk_sdtr or rej?
+ test RETURN_1,0x40 jnz rej_mesgin # Requested SDTR too small - rej
or FLAGS,ACTIVE_MSG
mvi DINDEX, MSG_START+0
mvi MSG_START+0 call mk_sdtr
or SINDEX,0x10,SIGSTATE # turn on ATNO
call scsisig
- jmp p_mesgin_done
+ jmp mesgin_done
# Is it a disconnect message? Set a flag in the SCB to remind us
# and await the bus going free.
#
-p_mesgin2:
- cmp A,4 jne p_mesgin3 # disconnect code?
-
- or SCBARRAY+0,0x4 # set "disconnected" bit
- jmp p_mesgin_done
+mesgin_disconnect:
+ or SCBARRAY+0,DISCONNECTED
+ jmp mesgin_done
# Save data pointers message? Copy working values into the SCB,
# usually in preparation for a disconnect.
#
-p_mesgin3:
- cmp A,2 jne p_mesgin4 # save data pointers code?
-
+mesgin_sdptrs:
call sg_ram2scb
- jmp p_mesgin_done
+ jmp mesgin_done
# Restore pointers message? Data pointers are recopied from the
-# SCB anyway at the start of any DMA operation, so the only thing
-# to copy is the scatter-gather values.
-#
-p_mesgin4:
- cmp A,3 jne p_mesgin5 # restore pointers code?
-
- call sg_scb2ram
- jmp p_mesgin_done
+# 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.
+#
+mesgin_rdptrs:
+ and FLAGS,0xfb # !DPHASE we'll reload them
+ # the next time through
+ jmp mesgin_done
# Identify message? For a reconnecting target, this tells us the lun
# that the reconnection is for - find the correct SCB and switch to it,
# clearing the "disconnected" bit so we don't "find" it by accident later.
#
-p_mesgin5:
- test A,0x80 jz p_mesgin6 # identify message?
-
- test A,0x78 jnz p_mesginN # !DiscPriv|!LUNTAR|!Reserved
+mesgin_identify:
+ test A,0x78 jnz rej_mesgin # !DiscPriv|!LUNTAR|!Reserved
and A,0x07 # lun in lower three bits
or SAVED_TCL,A,SELID
@@ -802,8 +855,6 @@
and SCBARRAY+0,0xfb # clear disconnect bit in SCB
or FLAGS,IDENTIFY_SEEN # make note of IDENTIFY
- call sg_scb2ram # implied restore pointers
- # required on reselect
jmp ITloop
get_tag:
mvi A call inb_first
@@ -828,34 +879,12 @@
# the target selecting 8bit or asynchronous transfer, otherwise just ignore
# it since we have no clue what it pertains to.
#
-p_mesgin6:
- cmp A,7 jne p_mesgin7 # message reject code?
-
+mesgin_reject:
mvi INTSTAT, MSG_REJECT
- jmp p_mesgin_done
+ jmp mesgin_done
# [ ADD MORE MESSAGE HANDLING HERE ]
#
-p_mesgin7:
-
-# We have no idea what this message in is, and there's no way
-# to pass it up to the kernel, so we issue a message reject and
-# hope for the best. Since we're now using manual PIO mode to
-# read in the message, there should no longer be a race condition
-# present when we assert ATN. In any case, rejection should be a
-# rare occurrence - signal the driver when it happens.
-#
-p_mesginN:
- or SINDEX,0x10,SIGSTATE # turn on ATNO
- call scsisig
- mvi INTSTAT,SEND_REJECT # let driver know
-
- mvi 0x7 call mk_mesg # MESSAGE REJECT message
-
-p_mesgin_done:
- call inb_last # ack & turn auto PIO back on
- jmp ITloop
-
# Bus free phase. It might be useful to interrupt the device
# driver if we aren't expecting this. For now, make sure that
@@ -868,33 +897,34 @@
# if this is an immediate command, perform a psuedo command complete to
# notify the driver.
test SCBARRAY+11,0xff jz status_ok
- jmp start
+ jmp poll_for_work
# Instead of a generic bcopy routine that requires an argument, we unroll
-# the two cases that are actually used, and call them explicitly. This
-# not only reduces the overhead of doing a bcopy by 2/3rds, but ends up
-# saving space in the program since you don't have to put the argument
-# into the accumulator before the call. Both functions expect DINDEX to
-# contain the destination address and SINDEX to contain the source
-# address.
-bcopy_3:
+# the cases that are actually used, and call them explicitly. This
+# not only reduces the overhead of doing a bcopy, but ends up saving space
+# in the program since you don't have to put the argument into the accumulator
+# before the call. Both functions expect DINDEX to contain the destination
+# address and SINDEX to contain the source address.
+bcopy_7:
mov DINDIR,SINDIR
mov DINDIR,SINDIR
- mov DINDIR,SINDIR ret
-
+bcopy_5:
+ mov DINDIR,SINDIR
bcopy_4:
mov DINDIR,SINDIR
+bcopy_3:
mov DINDIR,SINDIR
mov DINDIR,SINDIR
mov DINDIR,SINDIR ret
-bcopy_3_dfdat:
+bcopy_7_dfdat:
mov DINDIR,DFDAT
mov DINDIR,DFDAT
- mov DINDIR,DFDAT ret
-
+bcopy_5_dfdat:
+ mov DINDIR,DFDAT
bcopy_4_dfdat:
mov DINDIR,DFDAT
+bcopy_3_dfdat:
mov DINDIR,DFDAT
mov DINDIR,DFDAT
mov DINDIR,DFDAT ret
@@ -962,7 +992,6 @@
dma:
mov DFCNTRL,SINDEX
dma1:
-dma2:
test SSTAT0,0x1 jnz dma3 # DMADONE
test SSTAT1,0x10 jz dma1 # PHASEMIS, ie. underrun
@@ -978,19 +1007,14 @@
dma4:
test DFSTATUS,0x1 jz dma4 # !FIFOEMP
-# Now shut the DMA enables off, and copy STCNT (ie. the underrun
-# amount, if any) to the SCB registers; SG_COUNT will get copied to
-# the SCB's residual S/G count field after sg_advance is called. Make
-# sure that the DMA enables are actually off first lest we get an ILLSADDR.
+# Now shut the DMA enables off and make sure that the DMA enables are
+# actually off first lest we get an ILLSADDR.
#
dma5:
clr DFCNTRL # disable DMA
dma6:
test DFCNTRL,0x38 jnz dma6 # SCSIENACK|SDMAENACK|HDMAENACK
- mvi DINDEX,SCBARRAY+15
- mvi STCNT call bcopy_3
-
ret
dma_finish:
@@ -1022,10 +1046,9 @@
mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN
-# Initialize scatter-gather pointers by setting up the working copy
-# in scratch RAM.
-#
- call sg_scb2ram
+# Make sure that the system knows we have not been through a DATA
+# phase.
+ and FLAGS, 0xfb # !DPHASE
# Initialize SCSIRATE with the appropriate value for this target.
#
@@ -1041,29 +1064,6 @@
mvi INTSTAT,NO_IDENT ret # no - cause a kernel panic
-# Find out if disconnection is ok from the information the BIOS has left
-# us. The tcl from SCBARRAY+1 should be in SINDEX; A will
-# contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
-# on exit.
-#
-# To allow for wide or twin busses, we check the upper bit of the target ID
-# and the channel ID and look at the appropriate disconnect register.
-#
-disconnect:
- and FUNCTION1,0x70,SINDEX # strip off extra just in case
- mov A,FUNCTION1
- test SINDEX, 0x88 jz disconnect_a
-
- test DISC_DSB_B,A jz disconnect1 # bit nonzero if DISabled
- clr A ret
-
-disconnect_a:
- test DISC_DSB_A,A jz disconnect1 # bit nonzero if DISabled
- clr A ret
-
-disconnect1:
- mvi A,0x40 ret
-
# 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
@@ -1073,7 +1073,7 @@
mov A,SAVED_TCL
mov SCBPTR,SINDEX # switch to new SCB
cmp SCBARRAY+1,A jne findSCB1 # target ID/channel/lun match?
- test SCBARRAY+0,0x4 jz findSCB1 # should be disconnected
+ test SCBARRAY+0,DISCONNECTED jz findSCB1 # should be disconnected
test SCBARRAY+0,TAG_ENB jnz get_tag
ret
@@ -1089,113 +1089,40 @@
call scsisig
ret
-# Make a working copy of the scatter-gather parameters in the SCB.
+# Make a working copy of the scatter-gather parameters from the SCB.
#
sg_scb2ram:
+ mvi DINDEX,HADDR
+ mvi SCBARRAY+19 call bcopy_7
+
+ mvi DINDEX,STCNT
+ mvi SCBARRAY+23 call bcopy_3
+
mov SG_COUNT,SCBARRAY+2
mvi DINDEX,SG_NEXT
mvi SCBARRAY+3 call bcopy_4
+ ret
- mvi SG_NOLOAD,0x80
- test SCBARRAY+0,0x10 jnz return # don't reload s/g?
- clr SG_NOLOAD ret
-
-# Copying RAM values back to SCB, for Save Data Pointers message.
+# Copying RAM values back to SCB, for Save Data Pointers message, but
+# only if we've actually been into a data phase to change them. This
+# protects against bogus data in scratch ram and the residual counts
+# since they are only initialized when we go into data_in or data_out.
#
sg_ram2scb:
+ test FLAGS, DPHASE jz return
mov SCBARRAY+2,SG_COUNT
mvi DINDEX,SCBARRAY+3
mvi SG_NEXT call bcopy_4
+
+ mvi DINDEX,SCBARRAY+19
+ mvi SHADDR call bcopy_4
- and SCBARRAY+0,0xef,SCBARRAY+0
- test SG_NOLOAD,0x80 jz return # reload s/g?
- or SCBARRAY+0,SG_LOAD ret
-
-# Load a struct scatter if needed and set up the data address and
-# length. If the working value of the SG count is nonzero, then
-# we need to load a new set of values.
-#
-# This, like the above DMA, assumes a little-endian host data storage.
-#
-sg_load:
- test SG_COUNT,0xff jz return # SG being used?
- test SG_NOLOAD,0x80 jnz return # don't reload s/g?
-
- clr HCNT+2
- clr HCNT+1
- mvi HCNT+0,SG_SIZEOF
-
- mvi DINDEX,HADDR
- mvi SG_NEXT 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.
-#
-
- call dma_finish
-
-# Copy data from FIFO into SCB data pointer and data count. This assumes
-# that the struct scatterlist has this structure (this and sizeof(struct
-# scatterlist) == 12 are asserted in aic7xxx.c):
-#
-# struct scatterlist {
-# char *address; /* four bytes, little-endian order */
-# ... /* four bytes, ignored */
-# unsigned short length; /* two bytes, little-endian order */
-# }
-#
-
-# Not in FreeBSD. the scatter list entry is only 8 bytes.
-#
-# struct ahc_dma_seg {
-# physaddr addr; /* four bytes, little-endian order */
-# long len; /* four bytes, little endian order */
-# };
-#
-
- mvi DINDEX, SCBARRAY+19
- call bcopy_4_dfdat
-
-# For Linux, we must throw away four bytes since there is a 32bit gap
-# in the middle of a struct scatterlist
- mov NONE,DFDAT
- mov NONE,DFDAT
- mov NONE,DFDAT
- mov NONE,DFDAT
-
- call bcopy_3_dfdat #Only support 24 bit length.
+# Use the residual number since STCNT is corrupted by any message transfer
+ mvi SCBARRAY+15 call bcopy_3
ret
-# Advance the scatter-gather pointers only IF NEEDED. If SG is enabled,
-# and the SCSI transfer count is zero (note that this should be called
-# right after a DMA finishes), then move the working copies of the SG
-# pointer/length along. If the SCSI transfer count is not zero, then
-# presumably the target is disconnecting - do not reload the SG values
-# next time.
-#
-sg_advance:
- test SG_COUNT,0xff jz return # s/g enabled?
-
- test STCNT+0,0xff jnz sg_advance1 # SCSI transfer count nonzero?
- test STCNT+1,0xff jnz sg_advance1
- test STCNT+2,0xff jnz sg_advance1
-
- clr SG_NOLOAD # reload s/g next time
- dec SG_COUNT # one less segment to go
-
- clr A # add sizeof(struct scatter)
- add SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
- adc SG_NEXT+1,A,SG_NEXT+1
- adc SG_NEXT+2,A,SG_NEXT+2
- adc SG_NEXT+3,A,SG_NEXT+3 ret
-
-sg_advance1:
- mvi SG_NOLOAD,0x80 ret # don't reload s/g next time
-
# Add the array base SYNCNEG to the target offset (the target address
# is in SCSIID), and return the result in SINDEX. The accumulator
# contains the 3->8 decoding of the target ID on return.
@@ -1217,7 +1144,7 @@
# reject, you wouldn't be able to tell which message was the culpret.
#
mk_dtr:
- test SCBARRAY+0,0xc0 jz return # NEEDWDTR|NEEDSDTR
+ test SCBARRAY+0,0x90 jz return # NEEDWDTR|NEEDSDTR
test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit
or FLAGS, MAX_OFFSET # Force an offset of 15 or 8 if WIDE
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this