diff options
author | gibbs <gibbs@FreeBSD.org> | 1995-03-31 14:06:02 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1995-03-31 14:06:02 +0000 |
commit | 1b4e85be4d3be5e5d02468984dad59b5a9e53815 (patch) | |
tree | a703bfc7d6268466b7b8a4bf506a8c18de71675a /sys/dev/aic7xxx | |
parent | ead8e4d3beaeb057b1148e64b8a9ee444a7ba52a (diff) | |
download | FreeBSD-src-1b4e85be4d3be5e5d02468984dad59b5a9e53815.zip FreeBSD-src-1b4e85be4d3be5e5d02468984dad59b5a9e53815.tar.gz |
Major overhaul of the aic7xxx driver:
- Report valid residual byte counts. We actually pause the sequencer
when the residual is non-zero. I thought about using DMA to do this,
bus sequencer program space is tight.
- Fix embarassing off by one error in the computation of a 2's
compliment variable. This was most likely the cause of the
many problems reported with the tagged queuing code.
- Handle "MAX_SYNC" as a special case (ie we are the ones starting
the sync negotiation sequence). This was done so that the target
scratch area can be initialed to 0 offset (asyncronous transfers)
safely. The initialization to 0 (was 15) is necessary since in
some cases a Wide negotiation could run into problems if SCSIRATE
was set wrong and we went into data(in/out).
- Trim the DMA routines a little by using some procedures. Net
effect is more functionality with 3 less instructions after this
update.
- Toggle the WIDEODD bit of the DFCNTRL whenever this is not the
last SG block. It has no effect in the 8bit bus configuration,
but in the Wide configuration ensures that the overlap byte is
held in the SCSI block if the transfer is odd so it will end
up in the next SG (the correct behavior).
Diffstat (limited to 'sys/dev/aic7xxx')
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx.seq | 195 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic7xxx_asm.c | 7 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aicasm.c | 7 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aicasm/aicasm.c | 7 |
4 files changed, 126 insertions, 90 deletions
diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index d328693..42d0d82 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -22,7 +22,7 @@ # optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org) # -VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.9 1995/03/07 09:00:44 gibbs Exp $" +VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.10 1995/03/17 23:54:17 gibbs Exp $" SCBMASK = 0x1f @@ -56,6 +56,9 @@ SINDIR = 0x6c DINDIR = 0x6d FUNCTION1 = 0x6e HADDR = 0x88 +HADDR+1 = 0x89 +HADDR+2 = 0x8a +HADDR+3 = 0x8b HCNT = 0x8c HCNT+0 = 0x8c HCNT+1 = 0x8d @@ -113,8 +116,12 @@ SCBARRAY+23 = 0xb7 SCBARRAY+24 = 0xb8 SCBARRAY+25 = 0xb9 SCBARRAY+26 = 0xba +SCBARRAY+27 = 0xbb +SCBARRAY+28 = 0xbc +SCBARRAY+29 = 0xbd BAD_PHASE = 0x01 # unknown scsi bus phase +CMDCMPLT = 0x02 SEND_REJECT = 0x11 # sending a message reject NO_IDENT = 0x21 # no IDENTIFY after reconnect NO_MATCH = 0x31 # no cmd match for reconnect @@ -122,6 +129,7 @@ MSG_SDTR = 0x41 # SDTR message recieved MSG_WDTR = 0x51 # WDTR message recieved MSG_REJECT = 0x61 # Reject message recieved BAD_STATUS = 0x71 # Bad status from target +RESIDUAL = 0x81 # Residual byte count != 0 # The host adapter card (at least the BIOS) uses 20-2f for SCSI # device information, 32-33 and 5a-5f as well. As it turns out, the @@ -164,7 +172,7 @@ MSG_START+2 = 0x37 MSG_START+3 = 0x38 MSG_START+4 = 0x39 MSG_START+5 = 0x3a --MSG_START+0 = 0xcb # 2's complement of MSG_START+0 +-MSG_START+0 = 0xcc # 2's complement of MSG_START+0 ARG_1 = 0x4a # sdtr conversion args & return BUS_16_BIT = 0x01 @@ -189,6 +197,7 @@ SCBCOUNT = 0x52 # the actual number of SCBs FLAGS = 0x53 # Device configuration flags TWIN_BUS = 0x01 WIDE_BUS = 0x02 +MAX_SYNC = 0x08 SENSE = 0x10 ACTIVE_MSG = 0x20 IDENTIFY_SEEN = 0x40 @@ -236,34 +245,16 @@ test SCBARRAY+0,NEEDDMA jz test_busy # Wait for DMA from host memory to data FIFO to complete, then disable # DMA and wait for it to acknowledge that it's off. # -scb_load1: - test DFSTATUS,0x8 jz scb_load1 # HDONE - - clr DFCNTRL # disable DMA -scb_load2: - test DFCNTRL,0x8 jnz scb_load2 # HDMAENACK + call dma_finish # Copy the SCB from the FIFO to the SCBARRAY - mov SCBARRAY+0, DFDAT - mov SCBARRAY+1, DFDAT - mov SCBARRAY+2, DFDAT - mov SCBARRAY+3, DFDAT - mov SCBARRAY+4, DFDAT - mov SCBARRAY+5, DFDAT - mov SCBARRAY+6, DFDAT - mov SCBARRAY+7, DFDAT - mov SCBARRAY+8, DFDAT - mov SCBARRAY+9, DFDAT - mov SCBARRAY+10, DFDAT - mov SCBARRAY+11, DFDAT - mov SCBARRAY+12, DFDAT - mov SCBARRAY+13, DFDAT - mov SCBARRAY+14, DFDAT - mov SCBARRAY+15, DFDAT - mov SCBARRAY+16, DFDAT - mov SCBARRAY+17, DFDAT - mov SCBARRAY+18, DFDAT + mvi DINDEX, SCBARRAY+0 + 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 @@ -338,7 +329,6 @@ mk_tag: mov DINDIR,SCBPTR add MSG_LEN,-MSG_START+0,DINDEX # update message length - jmp !message # Can't do DTR when taged mk_tag_done: @@ -441,9 +431,17 @@ p_dataout: mvi DINDEX,STCNT mvi SCBARRAY+23 call bcopy_3 +# 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 + +p_dataout_wideodd: + mvi 0xbd call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN| + # DIRECTION|FIFORESET +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 @@ -475,8 +473,15 @@ p_datain: mvi DINDEX,STCNT mvi SCBARRAY+23 call bcopy_3 +# 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 @@ -611,21 +616,25 @@ p_mesgin: # 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 the sequencer code will imediately jump to start -# working on it. If the kernel driver does not wish to request sense, -# the sequencer program counter is incremented by 1, preventing another run -# on the current SCB and the command is allowed to complete. We don't +# 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 # 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. + test SCBARRAY+15,0xff jnz resid + test SCBARRAY+16,0xff jnz resid + test SCBARRAY+17,0xff jnz resid + +check_status: test SCBARRAY+14,0xff jz status_ok # 0 Status? mvi INTSTAT,BAD_STATUS # let driver know test FLAGS,SENSE jz status_ok jmp p_mesgin_done status_ok: - # First, mark this target as free. test SCBARRAY+0,0x20 jnz complete # Tagged command and FUNCTION1,0x70,SCBARRAY+1 @@ -639,9 +648,20 @@ clear_a: complete: mov QOUTFIFO,SCBPTR - mvi INTSTAT,0x02 # CMDCMPLT + mvi INTSTAT,CMDCMPLT jmp p_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), +# dma the resid directly to the host (slick, but a ton of instructions), or +# have the sequencer pause itself when it encounters a non-zero resid +# (unecessary pause just to flag the command -- yuck, but takes few instructions +# and since it shouldn't happen that offten is good enough for our purposes). + +resid: + mvi INTSTAT,RESIDUAL + jmp check_status + # Is it an extended message? We only support the synchronous and wide data # transfer request messages, which will probably be in response to # WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it - @@ -836,6 +856,16 @@ bcopy_4: mov DINDIR,SINDIR mov DINDIR,SINDIR ret +bcopy_3_dfdat: + mov DINDIR,DFDAT + mov DINDIR,DFDAT + mov DINDIR,DFDAT ret + +bcopy_4_dfdat: + mov DINDIR,DFDAT + mov DINDIR,DFDAT + mov DINDIR,DFDAT + mov DINDIR,DFDAT ret # Locking the driver out, build a one-byte message passed in SINDEX # if there is no active message already. SINDEX is returned intact. @@ -966,6 +996,14 @@ dma6: ret +dma_finish: + test DFSTATUS,0x8 jz dma_finish # HDONE + + clr DFCNTRL # disable DMA +dma_finish2: + test DFCNTRL,0x8 jnz dma_finish2 # HDMAENACK + ret + # Common SCSI initialization for selection and reselection. Expects # the target SCSI ID to be in the upper four bits of SINDEX, and A's # contents are stomped on return. @@ -1003,13 +1041,10 @@ initialize: # message. # assert: - test FLAGS,RESELECTED jz assert1 # reselected? - test FLAGS,IDENTIFY_SEEN jnz assert1 # seen IDENTIFY? - - mvi INTSTAT,NO_IDENT # no - cause a kernel panic + test FLAGS,RESELECTED jz return # reselected? + test FLAGS,IDENTIFY_SEEN jnz return # seen IDENTIFY? -assert1: - ret + 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 @@ -1067,11 +1102,8 @@ sg_scb2ram: mvi SCBARRAY+3 call bcopy_4 mvi SG_NOLOAD,0x80 - test SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g? - clr SG_NOLOAD - -sg_scb2ram1: - ret + 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. # @@ -1082,11 +1114,8 @@ sg_ram2scb: mvi SG_NEXT call bcopy_4 and SCBARRAY+0,0xef,SCBARRAY+0 - test SG_NOLOAD,0x80 jz sg_ram2scb1 # reload s/g? - or SCBARRAY+0,SG_LOAD - -sg_ram2scb1: - ret + 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 @@ -1095,8 +1124,8 @@ sg_ram2scb1: # This, like the above DMA, assumes a little-endian host data storage. # sg_load: - test SG_COUNT,0xff jz sg_load3 # SG being used? - test SG_NOLOAD,0x80 jnz sg_load3 # don't reload s/g? + 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 @@ -1110,12 +1139,8 @@ sg_load: # Wait for DMA from host memory to data FIFO to complete, then disable # DMA and wait for it to acknowledge that it's off. # -sg_load1: - test DFSTATUS,0x8 jz sg_load1 # HDONE - clr DFCNTRL # disable DMA -sg_load2: - test DFCNTRL,0x8 jnz sg_load2 # HDMAENACK + 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 @@ -1128,7 +1153,7 @@ sg_load2: # } # -# Not in FreeBSD. the scatter list is only 8 bytes. +# Not in FreeBSD. the scatter list entry is only 8 bytes. # # struct ahc_dma_seg { # physaddr addr; /* four bytes, little-endian order */ @@ -1136,10 +1161,8 @@ sg_load2: # }; # - mov SCBARRAY+19,DFDAT # new data address - mov SCBARRAY+20,DFDAT - mov SCBARRAY+21,DFDAT - mov SCBARRAY+22,DFDAT + 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 @@ -1148,11 +1171,7 @@ sg_load2: # mov NONE,DFDAT # mov NONE,DFDAT - mov SCBARRAY+23,DFDAT - mov SCBARRAY+24,DFDAT - mov SCBARRAY+25,DFDAT #Only support 24 bit length. - -sg_load3: + call bcopy_3_dfdat #Only support 24 bit length. ret # Advance the scatter-gather pointers only IF NEEDED. If SG is enabled, @@ -1163,7 +1182,7 @@ sg_load3: # next time. # sg_advance: - test SG_COUNT,0xff jz sg_advance2 # s/g enabled? + 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 @@ -1179,9 +1198,7 @@ sg_advance: adc SG_NEXT+3,A,SG_NEXT+3 ret sg_advance1: - mvi SG_NOLOAD,0x80 # don't reload s/g next time -sg_advance2: - ret + 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 @@ -1204,31 +1221,38 @@ ndx_dtr_2: # reject, you wouldn't be able to tell which message was the culpret. # mk_dtr: - mov DINDEX,SINDEX # save SINDEX - + test SCBARRAY+0,0xc0 jz return # NEEDWDTR|NEEDSDTR test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit - jmp mk_sdtr - -mk_wdtr_16bit: - mvi ARG_1,BUS_16_BIT -mk_wdtr: - mvi DINDIR,1 # extended message - mvi DINDIR,2 # extended message length = 2 - mvi DINDIR,3 # WDTR code - mov DINDIR,ARG_1 # bus width + or FLAGS, MAX_SYNC # Force an offset of 15 - add MSG_LEN,-MSG_START+0,DINDEX ret # update message length - mk_sdtr: mvi DINDIR,1 # extended message mvi DINDIR,3 # extended message length = 3 mvi DINDIR,1 # SDTR code call sdtr_to_rate mov DINDIR,RETURN_1 # REQ/ACK transfer period + test FLAGS, MAX_SYNC jnz mk_sdtr_max_sync and DINDIR,0xf,SINDIR # Sync Offset +mk_sdtr_done: add MSG_LEN,-MSG_START+0,DINDEX ret # update message length +mk_sdtr_max_sync: +# We're initiating sync negotiation, so request the max offset we can (15) + mvi DINDIR, 0x0f + xor FLAGS, MAX_SYNC + jmp mk_sdtr_done + +mk_wdtr_16bit: + mvi ARG_1,BUS_16_BIT +mk_wdtr: + mvi DINDIR,1 # extended message + mvi DINDIR,2 # extended message length = 2 + mvi DINDIR,3 # WDTR code + mov DINDIR,ARG_1 # bus width + + add MSG_LEN,-MSG_START+0,DINDEX ret # update message length + # Set SCSI bus control signal state. This also saves the last-written # value into a location where the higher-level driver can read it - if # it has to send an ABORT or RESET message, then it needs to know this @@ -1254,3 +1278,6 @@ sdtr_to_rate_loop: sdtr_to_rate_done: shr RETURN_1,0x2 add RETURN_1,0x18 ret + +return: + ret diff --git a/sys/dev/aic7xxx/aic7xxx_asm.c b/sys/dev/aic7xxx/aic7xxx_asm.c index 9eb9630..48f4f67 100644 --- a/sys/dev/aic7xxx/aic7xxx_asm.c +++ b/sys/dev/aic7xxx/aic7xxx_asm.c @@ -26,7 +26,7 @@ * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas * are token separators. * - * $Id: aic7xxx.c,v 1.5 1995/01/22 00:46:52 gibbs Exp $ + * $Id: aic7xxx.c,v 1.6 1995/03/17 23:54:16 gibbs Exp $ */ /* #define _POSIX_SOURCE 1 */ @@ -38,7 +38,7 @@ #include <stdlib.h> #include <unistd.h> -#define MEMORY 512 /* 2^9 29-bit words */ +#define MEMORY 448 #define MAXLINE 1024 #define MAXTOKEN 32 #define ADOTOUT "a.out" @@ -480,6 +480,9 @@ int crack(char **a, int n) I_dest = eval_sdi(a, instr[i].dest); I_addr = eval_addr(a, instr[i].addr); + if( LC >= MEMORY ) + error("Memory exhausted!\n"); + switch (instr[i].fmt) { case 1: case 2: diff --git a/sys/dev/aic7xxx/aicasm.c b/sys/dev/aic7xxx/aicasm.c index 9eb9630..48f4f67 100644 --- a/sys/dev/aic7xxx/aicasm.c +++ b/sys/dev/aic7xxx/aicasm.c @@ -26,7 +26,7 @@ * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas * are token separators. * - * $Id: aic7xxx.c,v 1.5 1995/01/22 00:46:52 gibbs Exp $ + * $Id: aic7xxx.c,v 1.6 1995/03/17 23:54:16 gibbs Exp $ */ /* #define _POSIX_SOURCE 1 */ @@ -38,7 +38,7 @@ #include <stdlib.h> #include <unistd.h> -#define MEMORY 512 /* 2^9 29-bit words */ +#define MEMORY 448 #define MAXLINE 1024 #define MAXTOKEN 32 #define ADOTOUT "a.out" @@ -480,6 +480,9 @@ int crack(char **a, int n) I_dest = eval_sdi(a, instr[i].dest); I_addr = eval_addr(a, instr[i].addr); + if( LC >= MEMORY ) + error("Memory exhausted!\n"); + switch (instr[i].fmt) { case 1: case 2: diff --git a/sys/dev/aic7xxx/aicasm/aicasm.c b/sys/dev/aic7xxx/aicasm/aicasm.c index 9eb9630..48f4f67 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm.c +++ b/sys/dev/aic7xxx/aicasm/aicasm.c @@ -26,7 +26,7 @@ * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas * are token separators. * - * $Id: aic7xxx.c,v 1.5 1995/01/22 00:46:52 gibbs Exp $ + * $Id: aic7xxx.c,v 1.6 1995/03/17 23:54:16 gibbs Exp $ */ /* #define _POSIX_SOURCE 1 */ @@ -38,7 +38,7 @@ #include <stdlib.h> #include <unistd.h> -#define MEMORY 512 /* 2^9 29-bit words */ +#define MEMORY 448 #define MAXLINE 1024 #define MAXTOKEN 32 #define ADOTOUT "a.out" @@ -480,6 +480,9 @@ int crack(char **a, int n) I_dest = eval_sdi(a, instr[i].dest); I_addr = eval_addr(a, instr[i].addr); + if( LC >= MEMORY ) + error("Memory exhausted!\n"); + switch (instr[i].fmt) { case 1: case 2: |