diff options
| author | David Greenman <dg@FreeBSD.org> | 1995-08-23 03:52:27 +0000 |
|---|---|---|
| committer | David Greenman <dg@FreeBSD.org> | 1995-08-23 03:52:27 +0000 |
| commit | c95597a8e9d2aebd3284ef5ec2fda7028c488c9a (patch) | |
| tree | 3dab148965a48e8768f045759cbb565b7c8527a4 /sys/dev | |
| parent | 1c02e34bd6ae920cba02ec508c83cb31a4890e62 (diff) | |
Notes
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/aic7xxx/aic7xxx.seq | 535 |
1 files changed, 234 insertions, 301 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index 3338c1c98ec0..9b1a4d0dc45e 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -41,9 +41,9 @@ # ##-M######################################################################### -VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.16 1995/05/17 07:05:49 davidg Exp $" +VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.16.4.1 1995/07/22 04:24:39 davidg Exp $" -SCBMASK = 0x1f +SCBMASK = 0xff SCSISEQ = 0x00 ENRSELI = 0x10 @@ -64,6 +64,7 @@ SELDO = 0x40 SELDI = 0x20 CLRSINT1 = 0x0c SSTAT1 = 0x0c +PHASEMIS = 0x10 SIMODE1 = 0x11 SCSIBUSL = 0x12 SHADDR = 0x14 @@ -99,18 +100,19 @@ SCSICONF_A = 0x5a 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 @@ -160,6 +162,7 @@ AWAITING_MSG = 0xa1 # Kernel requested to specify # (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 @@ -169,11 +172,11 @@ AWAITING_MSG = 0xa1 # Kernel requested to specify # 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. @@ -184,9 +187,9 @@ AWAITING_MSG = 0xa1 # Kernel requested to specify # 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. # @@ -214,9 +217,9 @@ SIGSTATE = 0x4b # value written to SCSISIGO # Linux users should use 0xc (12) for SG_SIZEOF SG_SIZEOF = 0x8 # sizeof(struct ahc_dma) #SG_SIZEOF = 0xc # sizeof(struct scatterlist) -SCB_SIZEOF = 0x13 # sizeof SCB to DMA (19 bytes) +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 @@ -228,6 +231,7 @@ SCBCOUNT = 0x52 # the actual number of SCBs FLAGS = 0x53 # Device configuration flags TWIN_BUS = 0x01 WIDE_BUS = 0x02 +DPHASE = 0x04 MAX_OFFSET = 0x08 ACTIVE_MSG = 0x20 IDENTIFY_SEEN = 0x40 @@ -241,7 +245,6 @@ ACTIVE_B = 0x55 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. @@ -267,19 +270,15 @@ SCB_LIST_NULL = 0xff # Poll QINCNT for work - the lower bits contain # the number of entries in the Queue In FIFO. # -start: - cmp WAITING_SCBH,SCB_LIST_NULL jne 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 cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting test QINCNT,SCBMASK jz poll_for_work @@ -312,11 +311,10 @@ 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_4_dfdat - call bcopy_4_dfdat - call bcopy_4_dfdat + 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 @@ -333,7 +331,7 @@ test_busy: test SCBARRAY+1,0x88 jz test_a # Id < 8 && A channel test ACTIVE_B,A jnz requeue - test SCBARRAY+0,0x20 jnz start_scb + test SCBARRAY+0,TAG_ENB jnz start_scb or ACTIVE_B,A # Mark the current target as busy jmp start_scb @@ -349,7 +347,7 @@ start_waiting: test_a: test ACTIVE_A,A jnz requeue - test SCBARRAY+0,0x20 jnz start_scb + test SCBARRAY+0,TAG_ENB jnz start_scb or ACTIVE_A,A # Mark the current target as busy start_scb: @@ -367,8 +365,7 @@ start_scb: 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 @@ -387,17 +384,17 @@ start_selection: # 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 @@ -417,7 +414,10 @@ mk_tag_done: 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 @@ -470,78 +470,118 @@ ITloop: 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 @@ -552,11 +592,9 @@ p_command: 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 @@ -572,7 +610,7 @@ p_status: 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. @@ -660,8 +698,34 @@ p_mesgin: 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 @@ -678,19 +742,17 @@ p_mesgin: # 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 @@ -700,11 +762,16 @@ status_ok: 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), @@ -723,21 +790,19 @@ resid: # 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 @@ -746,59 +811,53 @@ p_mesginWDTR: 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. +# 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. # -p_mesgin4: - cmp A,3 jne p_mesgin5 # restore pointers code? - - call sg_scb2ram - jmp p_mesgin_done +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 @@ -811,8 +870,6 @@ setup_SCB: 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 @@ -837,34 +894,12 @@ abort_tag: # 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 @@ -877,33 +912,34 @@ p_busfree: # 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 @@ -971,7 +1007,6 @@ inb_last1: dma: mov DFCNTRL,SINDEX dma1: -dma2: test SSTAT0,0x1 jnz dma3 # DMADONE test SSTAT1,0x10 jz dma1 # PHASEMIS, ie. underrun @@ -987,19 +1022,14 @@ dma3: 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: @@ -1031,10 +1061,9 @@ initialize_for_target: 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. # @@ -1050,29 +1079,6 @@ assert: 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 @@ -1082,7 +1088,7 @@ findSCB: 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 @@ -1098,113 +1104,40 @@ findSCB1: 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. @@ -1226,7 +1159,7 @@ ndx_dtr_2: # 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 |
