diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
commit | 59223edaa18759982db0a8aced0e77457d10c68e (patch) | |
tree | 89354903b01fa0a447bffeefe00df3044495db2e /drivers/scsi/aic7xxx/aic7xxx.seq | |
parent | db7d4daea91e105e3859cf461d7e53b9b77454b2 (diff) |
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7xxx.seq')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx.seq | 1000 |
1 files changed, 626 insertions, 374 deletions
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq index beae65cd2..4cb8e82c0 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.seq +++ b/drivers/scsi/aic7xxx/aic7xxx.seq @@ -1,7 +1,7 @@ /* * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. * - * Copyright (c) 1994-1997 Justin Gibbs. + * Copyright (c) 1994-1999 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -14,7 +14,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU Public License (GPL) and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that @@ -58,39 +58,57 @@ reset: clr SCSISIGO; /* De-assert BSY */ + and SXFRCTL1, ~BITBUCKET; /* Always allow reselection */ -.if ( TARGET_MODE ) - mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP; -.else - mvi SCSISEQ, ENRSELI|ENAUTOATNP; -.endif + if ((p->flags & AHC_TARGETMODE) != 0) { + mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP; + } else { + mvi SCSISEQ, ENRSELI|ENAUTOATNP; + } + + if ((p->features & AHC_CMD_CHAN) != 0) { + /* Ensure that no DMA operations are in progress */ + clr CCSGCTL; + clr CCSCBCTL; + } + call clear_target_state; - and SXFRCTL0, ~SPIOEN; poll_for_work: - mov A, QINPOS; + and SXFRCTL0, ~SPIOEN; + if ((p->features & AHC_QUEUE_REGS) == 0) { + mov A, QINPOS; + } poll_for_work_loop: - and SEQCTL, ~PAUSEDIS; - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; -.if ( TWIN_CHANNEL ) - /* - * Twin channel devices cannot handle things like SELTO - * interrupts on the "background" channel. So, if we - * are selecting, keep polling the current channel util - * either a selection or reselection occurs. - */ - xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ + if ((p->features & AHC_QUEUE_REGS) == 0) { + and SEQCTL, ~PAUSEDIS; + } test SSTAT0, SELDO|SELDI jnz selection; test SCSISEQ, ENSELO jnz poll_for_work; - xor SBLKCTL,SELBUSB; /* Toggle back */ -.endif + if ((p->features & AHC_TWIN) != 0) { + /* + * Twin channel devices cannot handle things like SELTO + * interrupts on the "background" channel. So, if we + * are selecting, keep polling the current channel util + * either a selection or reselection occurs. + */ + xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ + test SSTAT0, SELDO|SELDI jnz selection; + test SCSISEQ, ENSELO jnz poll_for_work; + xor SBLKCTL,SELBUSB; /* Toggle back */ + } cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; test_queue: /* Has the driver posted any work for us? */ - or SEQCTL, PAUSEDIS; - cmp KERNEL_QINPOS, A je poll_for_work_loop; - inc QINPOS; - and SEQCTL, ~PAUSEDIS; + if ((p->features & AHC_QUEUE_REGS) != 0) { + test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; + mov NONE, SNSCB_QOFF; + inc QINPOS; + } else { + or SEQCTL, PAUSEDIS; + cmp KERNEL_QINPOS, A je poll_for_work_loop; + inc QINPOS; + and SEQCTL, ~PAUSEDIS; + } /* * We have at least one queued SCB now and we don't have any @@ -98,26 +116,39 @@ test_queue: * any SCBs available for use, pull the tag from the QINFIFO * and get to work on it. */ -.if ( SCB_PAGING ) - mov ALLZEROS call get_free_or_disc_scb; -.endif + if ((p->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } + dequeue_scb: add A, -1, QINPOS; - mvi QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt; - mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - mov SINDEX, DFDAT; -.if !( SCB_PAGING ) - /* In the non-paging case, the SCBID == hardware SCB index */ - mov SCBPTR, SINDEX; -.endif + mvi QINFIFO_OFFSET call fetch_byte; + + if ((p->flags & AHC_PAGESCBS) == 0) { + /* In the non-paging case, the SCBID == hardware SCB index */ + mov SCBPTR, RETURN_2; + } dma_queued_scb: /* * DMA the SCB from host ram into the current SCB location. */ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - call dma_scb; + mov RETURN_2 call dma_scb; + +/* + * Preset the residual fields in case we never go through a data phase. + * This isn't done by the host so we can avoid a DMA to clear these + * fields for the normal case of I/O that completes without underrun + * or overrun conditions. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, SCB_DATACNT, 3; + } else { + mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; + mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; + mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; + } + mov SCB_RESID_SGCNT, SCB_SGCOUNT; start_scb: /* @@ -135,16 +166,22 @@ start_waiting: jmp poll_for_work; start_selection: -.if ( TWIN_CHANNEL ) - and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */ - and A,SELBUSB,SCB_TCL; /* Get new channel bit */ - or SINDEX,A; - mov SBLKCTL,SINDEX; /* select channel */ -.endif + if ((p->features & AHC_TWIN) != 0) { + and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ + and A,SELBUSB,SCB_TCL; /* Get new channel bit */ + or SINDEX,A; + mov SBLKCTL,SINDEX; /* select channel */ + } initialize_scsiid: - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID, OID; /* Clear old target */ - or SCSIID, A; + if ((p->features & AHC_ULTRA2) != 0) { + and A, TID, SCB_TCL; /* Get target ID */ + and SCSIID_ULTRA2, OID; /* Clear old target */ + or SCSIID_ULTRA2, A; + } else { + and A, TID, SCB_TCL; /* Get target ID */ + and SCSIID, OID; /* Clear old target */ + or SCSIID, A; + } mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; /* @@ -153,145 +190,155 @@ initialize_scsiid: * set in SXFRCTL0. */ initialize_channel: - or A, CLRSTCNT|CLRCHN, SINDEX; - or SXFRCTL0, A; -.if ( ULTRA ) + or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; + if ((p->features & AHC_ULTRA) != 0) { ultra: - mvi SINDEX, ULTRA_ENB+1; - test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ - dec SINDEX; + mvi SINDEX, ULTRA_ENB+1; + test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ + dec SINDEX; ultra_2: - mov FUNCTION1,SAVED_TCL; - mov A,FUNCTION1; - test SINDIR, A jz ndx_dtr; - or SXFRCTL0, FAST20; -.endif - + mov FUNCTION1,SAVED_TCL; + mov A,FUNCTION1; + test SINDIR, A jz ndx_dtr; + or SXFRCTL0, FAST20; + } /* * Initialize SCSIRATE with the appropriate value for this target. * The SCSIRATE settings for each target are stored in an array - * based at TARG_SCRATCH. + * based at TARG_SCSIRATE. */ ndx_dtr: shr A,4,SAVED_TCL; - test SBLKCTL,SELBUSB jz ndx_dtr_2; - or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */ - or A,0x08; /* Channel B entries add 8 */ + if ((p->features & AHC_TWIN) != 0) { + test SBLKCTL,SELBUSB jz ndx_dtr_2; + or SAVED_TCL, SELBUSB; + or A,0x08; /* Channel B entries add 8 */ ndx_dtr_2: - add SINDEX,TARG_SCRATCH,A; + } + + if ((p->features & AHC_ULTRA2) != 0) { + add SINDEX, TARG_OFFSET, A; + mov SCSIOFFSET, SINDIR; + } + + add SINDEX,TARG_SCSIRATE,A; mov SCSIRATE,SINDIR ret; selection: test SSTAT0,SELDO jnz select_out; select_in: -.if ( TARGET_MODE ) - test SSTAT0, TARGET jz initiator_reselect; - /* - * We've just been selected. Assert BSY and - * setup the phase for receiving the messages - * from the target. - */ - mvi SCSISIGO, P_MESGOUT|BSYO; - mvi CLRSINT0, CLRSELDO; - - /* - * If ATN isn't asserted, go directly to bus free. - */ - test SCSISIGI, ATNI jz target_busfree; - - /* - * Setup the DMA for sending the identify and - * command information. - */ - mov A, TMODE_CMDADDR_NEXT; - mvi TMODE_CMDADDR call set_32byte_haddr_and_clrcnt; - mvi DFCNTRL, FIFORESET; - - clr SINDEX; - /* Watch ATN closely now */ + if ((p->flags & AHC_TARGETMODE) != 0) { + test SSTAT0, TARGET jz initiator_reselect; + /* + * We've just been selected. Assert BSY and + * setup the phase for receiving the messages + * from the target. + */ + mvi SCSISIGO, P_MESGOUT|BSYO; + mvi CLRSINT0, CLRSELDO; + + /* + * If ATN isn't asserted, go directly to bus free. + */ + test SCSISIGI, ATNI jz target_busfree; + + /* + * Setup the DMA for sending the identify and + * command information. + */ + mov A, TMODE_CMDADDR_NEXT; + mvi DINDEX, HADDR; + mvi TMODE_CMDADDR call set_32byte_addr; + mvi DFCNTRL, FIFORESET; + + clr SINDEX; + /* Watch ATN closely now */ message_loop: - or SXFRCTL0, SPIOEN; - test SSTAT0, SPIORDY jz .; - and SXFRCTL0, ~SPIOEN; - mov DINDEX, SCSIDATL; - mov DFDAT, DINDEX; - inc SINDEX; - - /* Message Testing... */ - test DINDEX, MSG_IDENTIFYFLAG jz . + 2; - mov ARG_1, DINDEX; - - test SCSISIGI, ATNI jnz message_loop; - add A, -4, SINDEX; - jc target_cmdphase; - mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */ + or SXFRCTL0, SPIOEN; + test SSTAT0, SPIORDY jz .; + and SXFRCTL0, ~SPIOEN; + mov DINDEX, SCSIDATL; + mov DFDAT, DINDEX; + inc SINDEX; + + /* Message Testing... */ + test DINDEX, MSG_IDENTIFYFLAG jz . + 2; + mov ARG_1, DINDEX; + + test SCSISIGI, ATNI jnz message_loop; + add A, -4, SINDEX; + jc target_cmdphase; + mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */ target_cmdphase: - add HCNT[0], 1, A; - mvi SCSISIGO, P_COMMAND|BSYO; - or SXFRCTL0, SPIOEN; - test SSTAT0, SPIORDY jz .; - mov A, SCSIDATL; - mov DFDAT, A; /* Store for host */ - - /* - * Determine the number of bytes to read - * based on the command group code. Count is - * one less than the total since we've already - * fetched the first byte. - */ - clr SINDEX; - shr A, CMD_GROUP_CODE_SHIFT; - add SEQADDR0, A; - - add SINDEX, CMD_GROUP0_BYTE_DELTA; - nop; /* Group 1 and 2 are the same */ - add SINDEX, CMD_GROUP2_BYTE_DELTA; - nop; /* Group 3 is reserved */ - add SINDEX, CMD_GROUP4_BYTE_DELTA; - add SINDEX, CMD_GROUP5_BYTE_DELTA; + add HCNT[0], 1, A; + clr HCNT[1]; + clr HCNT[2]; + mvi SCSISIGO, P_COMMAND|BSYO; + or SXFRCTL0, SPIOEN; + test SSTAT0, SPIORDY jz .; + mov A, SCSIDATL; + mov DFDAT, A; /* Store for host */ + + /* + * Determine the number of bytes to read + * based on the command group code. Count is + * one less than the total since we've already + * fetched the first byte. + */ + clr SINDEX; + shr A, CMD_GROUP_CODE_SHIFT; + add SEQADDR0, A; + + add SINDEX, CMD_GROUP0_BYTE_DELTA; + nop; /* Group 1 and 2 are the same */ + add SINDEX, CMD_GROUP2_BYTE_DELTA; + nop; /* Group 3 is reserved */ + add SINDEX, CMD_GROUP4_BYTE_DELTA; + add SINDEX, CMD_GROUP5_BYTE_DELTA; /* Group 6 and 7 are not handled yet */ - mov A, SINDEX; - add HCNT[0], A; + mov A, SINDEX; + add HCNT[0], A; command_loop: - test SSTAT0, SPIORDY jz .; - cmp SINDEX, 1 jne . + 2; - and SXFRCTL0, ~SPIOEN; /* Last Byte */ - mov DFDAT, SCSIDATL; - dec SINDEX; - test SINDEX, 0xFF jnz command_loop; - - or DFCNTRL, HDMAEN|FIFOFLUSH; + test SSTAT0, SPIORDY jz .; + cmp SINDEX, 1 jne . + 2; + and SXFRCTL0, ~SPIOEN; /* Last Byte */ + mov DFDAT, SCSIDATL; + dec SINDEX; + test SINDEX, 0xFF jnz command_loop; + + or DFCNTRL, HDMAEN|FIFOFLUSH; - call dma_finish; + call dma_finish; - test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post; + test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post; - mvi SCSISIGO, P_MESGIN|BSYO; + mvi SCSISIGO, P_MESGIN|BSYO; - or SXFRCTL0, SPIOEN; + or SXFRCTL0, SPIOEN; - mvi MSG_DISCONNECT call target_outb; + mvi MSG_DISCONNECT call target_outb; selectin_post: - inc TMODE_CMDADDR_NEXT; - cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2; - clr TMODE_CMDADDR_NEXT; - mvi QOUTFIFO, SCB_LIST_NULL; - mvi INTSTAT,CMDCMPLT; + inc TMODE_CMDADDR_NEXT; + cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2; + clr TMODE_CMDADDR_NEXT; + mvi QOUTFIFO, SCB_LIST_NULL; + mvi INTSTAT,CMDCMPLT; - test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree; + test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree; - /* Busy loop on something then go to data or status phase */ + /* Busy loop on something then go to data or status phase */ target_busfree: - clr SCSISIGO; - jmp poll_for_work; + clr SCSISIGO; + jmp poll_for_work; + + } -.endif /* TARGET_MODE */ /* * 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. @@ -370,57 +417,81 @@ await_busfree: mvi INTSTAT, BAD_PHASE; clear_target_state: - clr DFCNTRL; /* - * We assume that the kernel driver - * may reset us at any time, even - * in the middle of a DMA, so clear - * DFCNTRL too. - */ - clr SCSIRATE; /* - * We don't know the target we will - * connect to, so default to narrow - * transfers to avoid parity problems. - */ - and SXFRCTL0, ~(FAST20); + /* + * We assume that the kernel driver may reset us + * at any time, even in the middle of a DMA, so + * clear DFCNTRL too. + */ + clr DFCNTRL; + + /* + * We don't know the target we will connect to, + * so default to narrow transfers to avoid + * parity problems. + */ + if ((p->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, ALLZEROS, 2; + } else { + clr SCSIRATE; + and SXFRCTL0, ~(FAST20); + } mvi LASTPHASE, P_BUSFREE; /* clear target specific flags */ - and SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret; + clr SEQ_FLAGS ret; /* * 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 SCB_RESID_DCNT call bcopy_3; + if ((p->features & AHC_CMD_CHAN) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { + bmov HCNT, SCB_RESID_DCNT, 3; + } + bmov STCNT, SCB_RESID_DCNT, 3; + } else { + mvi DINDEX, STCNT; + mvi SCB_RESID_DCNT call bcopy_3; + } jmp data_phase_loop; p_data: - mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; + if ((p->features & AHC_ULTRA2) != 0) { + mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; + } else { + mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; + } test LASTPHASE, IOI jnz . + 2; or DMAPARAMS, DIRECTION; call assert; /* * Ensure entering a data * phase is okay - seen identify, etc. */ - + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi CCSGADDR, CCSGADDR_MAX; + } test SEQ_FLAGS, DPHASE jnz data_phase_reinit; + /* We have seen a data phase */ + or SEQ_FLAGS, DPHASE; + /* * Initialize the DMA address and counter from the SCB. * Also set SG_COUNT and SG_NEXT in memory since we cannot * modify the values in the SCB itself until we see a * save data pointers message. */ - mvi DINDEX, HADDR; - mvi SCB_DATAPTR call bcopy_7; - - call set_stcnt_from_hcnt; - - mov SG_COUNT,SCB_SGCOUNT; - - mvi DINDEX, SG_NEXT; - mvi SCB_SGPTR call bcopy_4; + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SCB_DATAPTR, 7; + bmov STCNT, HCNT, 3; + bmov SG_COUNT, SCB_SGCOUNT, 5; + } else { + mvi DINDEX, HADDR; + mvi SCB_DATAPTR call bcopy_7; + call set_stcnt_from_hcnt; + mvi DINDEX, SG_COUNT; + mvi SCB_SGCOUNT call bcopy_5; + } data_phase_loop: /* Guard against overruns */ @@ -432,19 +503,39 @@ data_phase_loop: * had an overrun. */ or SXFRCTL1,BITBUCKET; - mvi HCNT[0], 0xff; - mvi HCNT[1], 0xff; - mvi HCNT[2], 0xff; - call set_stcnt_from_hcnt; and DMAPARAMS, ~(HDMAEN|SDMAEN); - + if ((p->features & AHC_CMD_CHAN) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { + bmov HCNT, ALLONES, 3; + } + bmov STCNT, ALLONES, 3; + } else { + mvi STCNT[0], 0xFF; + mvi STCNT[1], 0xFF; + mvi STCNT[2], 0xFF; + } data_phase_inbounds: -/* If we are the last SG block, ensure wideodd is off. */ +/* If we are the last SG block, tell the hardware. */ +if ((p->features & AHC_ULTRA2) == 0) { cmp SG_COUNT,0x01 jne data_phase_wideodd; and DMAPARAMS, ~WIDEODD; +} data_phase_wideodd: - mov DMAPARAMS call dma; - + if ((p->features & AHC_ULTRA2) != 0) { + mov SINDEX, ALLONES; + mov DFCNTRL, DMAPARAMS; + test SSTAT0, SDONE jnz .; +data_phase_dma_loop: + test SSTAT0, SDONE jnz data_phase_dma_done; + test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ +data_phase_dma_phasemis: + test SSTAT0,SDONE jnz . + 2; + clr SINDEX; /* Remember the phasemiss */ + } else { + mov DMAPARAMS call dma; + } + +data_phase_dma_done: /* Go tell the host about any overruns */ test SXFRCTL1,BITBUCKET jnz data_phase_overrun; @@ -458,11 +549,6 @@ sg_advance: dec SG_COUNT; /* one less segment to go */ test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ - - clr A; /* add sizeof(struct scatter) */ - add SG_NEXT[0],SG_SIZEOF; - adc SG_NEXT[1],A; - /* * Load a struct scatter and set up the data address and length. * If the working value of the SG count is nonzero, then @@ -471,49 +557,95 @@ sg_advance: * This, like all DMA's, assumes little-endian host data storage. */ sg_load: - mvi DINDEX, HADDR; - mvi SG_NEXT call bcopy_4; - - mvi HCNT[0],SG_SIZEOF; - clr HCNT[1]; - clr HCNT[2]; - - or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - -/* - * Copy data from FIFO into SCB data pointer and data count. This assumes - * that the SG segments are of the form: - * - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi HADDR call dfdat_in_7; + if ((p->features & AHC_CMD_CHAN) != 0) { + /* + * Do we have any prefetch left??? + */ + cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + + /* + * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. + */ + add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; + mvi A, CCSGADDR_MAX; + jc . + 2; + shl A, 3, SG_COUNT; + mov CCHCNT, A; + bmov CCHADDR, SG_NEXT, 4; + mvi CCSGCTL, CCSGEN|CCSGRESET; + test CCSGCTL, CCSGDONE jz .; + and CCSGCTL, ~CCSGEN; + test CCSGCTL, CCSGEN jnz .; + mvi CCSGCTL, CCSGRESET; +prefetched_segs_avail: + bmov HADDR, CCSGRAM, 8; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } + } else { + mvi DINDEX, HADDR; + mvi SG_NEXT call bcopy_4; + + mvi HCNT[0],SG_SIZEOF; + clr HCNT[1]; + clr HCNT[2]; + + or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + + call dma_finish; + + /* + * Copy data from FIFO into SCB data pointer and data count. + * This assumes that the SG segments are of the form: + * struct ahc_dma_seg { + * u_int32_t addr; four bytes, little-endian order + * u_int32_t len; four bytes, little endian order + * }; + */ + mvi HADDR call dfdat_in_7; + call set_stcnt_from_hcnt; + } + +/* Advance the SG pointer */ + clr A; /* add sizeof(struct scatter) */ + add SG_NEXT[0],SG_SIZEOF; + adc SG_NEXT[1],A; -/* Load STCNT as well. It is a mirror of HCNT */ - call set_stcnt_from_hcnt; + test SSTAT1, REQINIT jz .; test SSTAT1,PHASEMIS jz data_phase_loop; + if ((p->features & AHC_ULTRA2) != 0) { + mov DFCNTRL, DMAPARAMS; + test SSTAT0, SDONE jnz .; + } + 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. */ - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; - - /* We have seen a data phase */ - or SEQ_FLAGS, DPHASE; + if ((p->features & AHC_ULTRA2) != 0) { + call ultra2_dmafinish; + } + if ((p->features & AHC_ULTRA2) == 0) { + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + } else { + mov SCB_RESID_DCNT[0],STCNT[0]; + mov SCB_RESID_DCNT[1],STCNT[1]; + mov SCB_RESID_DCNT[2],STCNT[2]; + mov SCB_RESID_SGCNT, SG_COUNT; + } + } jmp ITloop; data_phase_overrun: + if ((p->features & AHC_ULTRA2) != 0) { + call ultra2_dmafinish; + } /* * Turn off BITBUCKET mode and notify the host */ @@ -521,6 +653,22 @@ data_phase_overrun: mvi INTSTAT,DATA_OVERRUN; jmp ITloop; +ultra2_dmafinish: + if ((p->features & AHC_ULTRA2) != 0) { + test DFCNTRL, DIRECTION jnz ultra2_dmahalt; + and DFCNTRL, ~SCSIEN; + test DFCNTRL, SCSIEN jnz .; + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz . - 1; +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, HDMAEN jnz .; + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + or SXFRCTL0, CLRSTCNT|CLRCHN; + ret; + } + /* * Command phase. Set up the DMA registers and let 'er rip. */ @@ -530,14 +678,33 @@ p_command: /* * Load HADDR and HCNT. */ - mvi DINDEX, HADDR; - mvi SCB_CMDPTR call bcopy_5; - clr HCNT[1]; - clr HCNT[2]; - - call set_stcnt_from_hcnt; - - mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SCB_CMDPTR, 5; + bmov HCNT[1], ALLZEROS, 2; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } + } else { + mvi DINDEX, HADDR; + mvi SCB_CMDPTR call bcopy_5; + clr HCNT[1]; + clr HCNT[2]; + call set_stcnt_from_hcnt; + } + + if ((p->features & AHC_ULTRA2) == 0) { + mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; + } else { + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); + test SSTAT0, SDONE jnz .; +p_command_dma_loop: + test SSTAT0, DMADONE jnz p_command_ultra2_dma_done; + test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ +p_command_ultra2_dma_done: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, HDMAEN jnz .; + or SXFRCTL0, CLRSTCNT|CLRCHN; + } jmp ITloop; /* @@ -562,7 +729,6 @@ p_status: * on an SCB that might not be for the current nexus. (For example, a * BDR message in responce to a bad reselection would leave us pointed to * an SCB that doesn't have anything to do with the current target). - * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, * bus device reset). * @@ -570,15 +736,17 @@ p_status: * in case the target decides to put us in this phase for some strange * reason. */ +p_mesgout_retry: + or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; p_mesgout_identify: -.if ( WIDE ) - and SINDEX,0xf,SCB_TCL; /* lun */ -.else - and SINDEX,0x7,SCB_TCL; /* lun */ -.endif + if ((p->features & AHC_WIDE) != 0) { + and SINDEX,0xf,SCB_TCL; /* lun */ + } else { + and SINDEX,0x7,SCB_TCL; /* lun */ + } and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ or SINDEX,A; /* or in disconnect privledge */ or SINDEX,MSG_IDENTIFYFLAG; @@ -606,6 +774,7 @@ p_mesgout_tag: p_mesgout_from_host: cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; mvi INTSTAT,AWAITING_MSG; + nop; /* * Did the host detect a phase change? */ @@ -620,9 +789,7 @@ p_mesgout_onebyte: * that the target is requesting that the last message(s) be resent. */ call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ - jmp p_mesgout; + cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; p_mesgout_done: mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ @@ -692,6 +859,7 @@ upload_scb: check_status: test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ mvi INTSTAT,BAD_STATUS; /* let driver know */ + nop; cmp RETURN_1, SEND_SENSE jne complete; /* This SCB becomes the next to execute as it will retrieve sense */ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; @@ -710,21 +878,21 @@ complete: /* If we are untagged, clear our address up in host ram */ test SCB_CONTROL, TAG_ENB jnz complete_post; mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt; - mvi DFCNTRL, FIFORESET; - mvi DFDAT, SCB_LIST_NULL; - or DFCNTRL, HDMAEN|FIFOFLUSH; - call dma_finish; + mvi UNTAGGEDSCB_OFFSET call post_byte_setup; + mvi SCB_LIST_NULL call post_byte; complete_post: /* Post the SCB and issue an interrupt */ - mov A, QOUTPOS; - mvi QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt; - mvi DFCNTRL, FIFORESET; - mov DFDAT, SCB_TAG; - or DFCNTRL, HDMAEN|FIFOFLUSH; - call dma_finish; - inc QOUTPOS; + if ((p->features & AHC_QUEUE_REGS) != 0) { + mov A, SDSCB_QOFF; + } else { + mov A, QOUTPOS; + } + mvi QOUTFIFO_OFFSET call post_byte_setup; + mov SCB_TAG call post_byte; + if ((p->features & AHC_QUEUE_REGS) == 0) { + inc QOUTPOS; + } mvi INTSTAT,CMDCMPLT; add_to_free_list: @@ -759,21 +927,23 @@ mesgin_disconnect: */ mesgin_sdptrs: test SEQ_FLAGS, DPHASE jz mesgin_done; - mov SCB_SGCOUNT,SG_COUNT; - - /* The SCB SGPTR becomes the next one we'll download */ - mvi DINDEX, SCB_SGPTR; - mvi SG_NEXT call bcopy_4; - - /* The SCB DATAPTR0 becomes the current SHADDR */ - mvi DINDEX, SCB_DATAPTR; - mvi SHADDR call bcopy_4; - -/* - * Use the residual number since STCNT is corrupted by any message transfer. - */ - mvi SCB_RESID_DCNT call bcopy_3; - + /* + * The SCB SGPTR becomes the next one we'll download, + * and the SCB DATAPTR becomes the current SHADDR. + * Use the residual number since STCNT is corrupted by + * any message transfer. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_SGCOUNT, SG_COUNT, 5; + bmov SCB_DATAPTR, SHADDR, 4; + bmov SCB_DATACNT, SCB_RESID_DCNT, 3; + } else { + mvi DINDEX, SCB_SGCOUNT; + mvi SG_COUNT call bcopy_5; + mvi DINDEX, SCB_DATAPTR; + mvi SHADDR call bcopy_4; + mvi SCB_RESID_DCNT call bcopy_3; + } jmp mesgin_done; /* @@ -796,18 +966,20 @@ mesgin_rdptrs: * clearing the "disconnected" bit so we don't "find" it by accident later. */ mesgin_identify: -.if ( WIDE ) - and A,0x0f; /* lun in lower four bits */ -.else - and A,0x07; /* lun in lower three bits */ -.endif + + if ((p->features & AHC_WIDE) != 0) { + and A,0x0f; /* lun in lower four bits */ + } else { + and A,0x07; /* lun in lower three bits */ + } or SAVED_TCL,A; /* SAVED_TCL should be complete now */ + mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ call get_untagged_SCBID; cmp ARG_1, SCB_LIST_NULL je snoop_tag; -.if ( SCB_PAGING ) - test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; -.endif + if ((p->flags & AHC_PAGESCBS) != 0) { + test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; + } /* * If the SCB was found in the disconnected list (as is * always the case in non-paging scenarios), SCBPTR is already @@ -833,19 +1005,8 @@ snoop_tag_loop: get_tag: mvi ARG_1 call inb_next; /* tag value */ -.if ! ( SCB_PAGING ) -index_by_tag: - mov SCBPTR,ARG_1; - test SCB_CONTROL,TAG_ENB jz not_found; - mov SCBPTR call rem_scb_from_disc_list; -.else -/* - * Ensure that the SCB the tag points to is for an SCB transaction - * to the reconnecting target. - */ use_retrieveSCB: call retrieveSCB; -.endif setup_SCB: mov A, SAVED_TCL; cmp SCB_TCL, A jne not_found_cleanup_scb; @@ -924,16 +1085,16 @@ inb_first: inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ -.if ( TARGET_MODE ) -/* - * Send a byte to an initiator in Automatic PIO mode. - * SPIOEN must be on prior to calling this routine. - */ +if ((p->flags & AHC_TARGETMODE) != 0) { + /* + * Send a byte to an initiator in Automatic PIO mode. + * SPIOEN must be on prior to calling this routine. + */ target_outb: mov SCSIDATL, SINDEX; test SSTAT0, SPIORDY jz .; ret; -.endif +} mesgin_phasemis: /* @@ -948,6 +1109,7 @@ mesgin_phasemis: * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared * during initialization. */ +if ((p->features & AHC_ULTRA2) == 0) { dma: mov DFCNTRL,SINDEX; dma_loop: @@ -980,7 +1142,16 @@ dma_fifoempty: dma_dmadone: and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); dma_halt: - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; + /* + * Some revisions of the aic7880 have a problem where, if the + * data fifo is full, but the PCI input latch is not empty, + * HDMAEN cannot be cleared. The fix used here is to attempt + * to drain the data fifo until there is space for the input + * latch to drain and HDMAEN de-asserts. + */ + mov NONE, DFDAT; + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; +} return: ret; @@ -1009,6 +1180,7 @@ findSCB_by_SCBID: mov A, ARG_1; /* Tag passed in ARG_1 */ mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ findSCB_next: + mov ARG_2, SCBPTR; cmp SCB_NEXT, SCB_LIST_NULL je notFound; mov SCBPTR,SCB_NEXT; dec SINDEX; /* Last comparison moved us too far */ @@ -1032,19 +1204,15 @@ retrieveSCB: /* * This routine expects SINDEX to contain the index of the SCB to be - * removed and SCBPTR to be pointing to that SCB. + * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the + * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL + * if it is at the head. */ rem_scb_from_disc_list: /* Remove this SCB from the disconnection list */ - cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; - mov DINDEX, SCB_PREV; - mov SCBPTR, SCB_NEXT; - mov SCB_PREV, DINDEX; - mov SCBPTR, SINDEX; -unlink_prev: - cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ + cmp ARG_2, SCB_LIST_NULL je rHead; mov DINDEX, SCB_NEXT; - mov SCBPTR, SCB_PREV; + mov SCBPTR, ARG_2; mov SCB_NEXT, DINDEX; mov SCBPTR, SINDEX ret; rHead: @@ -1079,25 +1247,75 @@ get_untagged_SCBID: mov ARG_1, SCB_TAG ret; mvi ARG_1, SCB_LIST_NULL ret; -set_SCBID_host_addr_and_cnt: - mov DINDEX, SINDEX; - mvi SCBID_ADDR call set_1byte_haddr_and_clrcnt; - mvi HCNT[0], 1 ret; +/* + * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) + * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. + */ +fetch_byte: + mov ARG_2, SINDEX; + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi CCHCNT, 1; + mvi CCSGCTL, CCSGEN|CCSGRESET; + test CCSGCTL, CCSGDONE jz .; + mvi CCSGCTL, CCSGRESET; + bmov RETURN_2, CCSGRAM, 1 ret; + } else { + mvi DINDEX, HADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi HCNT[0], 1; + clr HCNT[1]; + clr HCNT[2]; + mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + call dma_finish; + mov RETURN_2, DFDAT ret; + } + +/* + * Prepare the hardware to post a byte to host memory given an + * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. + */ +post_byte_setup: + mov ARG_2, SINDEX; + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi CCHCNT, 1; + mvi CCSCBCTL, CCSCBRESET ret; + } else { + mvi DINDEX, HADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi HCNT[0], 1; + clr HCNT[1]; + clr HCNT[2]; + mvi DFCNTRL, FIFORESET ret; + } + +post_byte: + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov CCSCBRAM, SINDEX, 1; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + clr CCSCBCTL ret; + } else { + mov DFDAT, SINDEX; + or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; + } get_SCBID_from_host: mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt; - mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - mov ARG_1, DFDAT ret; + mvi UNTAGGEDSCB_OFFSET call fetch_byte; + mov RETURN_1, RETURN_2 ret; phase_lock: test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock; - and LASTPHASE, PHASE_MASK, SCSISIGI; - mov SCSISIGO, LASTPHASE ret; + and SCSISIGO, PHASE_MASK, SCSISIGI; + and LASTPHASE, PHASE_MASK, SCSISIGI ret; +if ((p->features & AHC_CMD_CHAN) == 0) { set_stcnt_from_hcnt: mov STCNT[0], HCNT[0]; mov STCNT[1], HCNT[1]; @@ -1114,87 +1332,127 @@ bcopy_3: mov DINDIR, SINDIR; mov DINDIR, SINDIR; mov DINDIR, SINDIR ret; +} /* - * Setup haddr and count assuming that A is an - * index into an array of 32byte objects. + * Setup addr assuming that A is an index into + * an array of 32byte objects, SINDEX contains + * the base address of that array, and DINDEX + * contains the base address of the location + * to store the indexed address. */ -set_32byte_haddr_and_clrcnt: - shr DINDEX, 3, A; +set_32byte_addr: + shr ARG_2, 3, A; shl A, 5; -set_1byte_haddr_and_clrcnt: /* DINDEX must be 0 upon call */ - add HADDR[0], A, SINDIR; - mov A, DINDEX; - adc HADDR[1], A, SINDIR; +/* + * Setup addr assuming that A + (ARG_1 * 256) is an + * index into an array of 1byte objects, SINDEX contains + * the base address of that array, and DINDEX contains + * the base address of the location to store the computed + * address. + */ +set_1byte_addr: + add DINDIR, A, SINDIR; + mov A, ARG_2; + adc DINDIR, A, SINDIR; clr A; - adc HADDR[2], A, SINDIR; - adc HADDR[3], A, SINDIR; - /* Clear Count */ - clr HCNT[1]; - clr HCNT[2] ret; + adc DINDIR, A, SINDIR; + adc DINDIR, A, SINDIR ret; +/* + * Either post or fetch and SCB from host memory based on the + * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. + */ dma_scb: - /* - * SCB index is in SINDEX. Determine the physical address in - * the host where this SCB is located and load HADDR with it. - */ mov A, SINDEX; - mvi HSCB_ADDR call set_32byte_haddr_and_clrcnt; - mvi HCNT[0], 28; - mov DFCNTRL, DMAPARAMS; - test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; - /* Fill it with the SCB data */ + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi HSCB_ADDR call set_32byte_addr; + mov CCSCBPTR, SCBPTR; + mvi CCHCNT, 32; + test DMAPARAMS, DIRECTION jz dma_scb_tohost; + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; + jmp dma_scb_finish; +dma_scb_tohost: + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + mvi CCSCBCTL, CCSCBRESET; + bmov CCSCBRAM, SCB_CONTROL, 32; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + } else { + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } +dma_scb_finish: + clr CCSCBCTL; + test CCSCBCTL, CCARREN|CCSCBEN jnz .; + ret; + } else { + mvi DINDEX, HADDR; + mvi HSCB_ADDR call set_32byte_addr; + mvi HCNT[0], 32; + clr HCNT[1]; + clr HCNT[2]; + mov DFCNTRL, DMAPARAMS; + test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; + /* Fill it with the SCB data */ copy_scb_tofifo: - mvi SINDEX, SCB_CONTROL; - add A, 28, SINDEX; + mvi SINDEX, SCB_CONTROL; + add A, 32, SINDEX; copy_scb_tofifo_loop: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - cmp SINDEX, A jne copy_scb_tofifo_loop; - or DFCNTRL, HDMAEN|FIFOFLUSH; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + cmp SINDEX, A jne copy_scb_tofifo_loop; + or DFCNTRL, HDMAEN|FIFOFLUSH; dma_scb_fromhost: - call dma_finish; - /* If we were putting the SCB, we are done */ - test DMAPARAMS, DIRECTION jz return; - mvi SCB_CONTROL call dfdat_in_7; - call dfdat_in_7_continued; - call dfdat_in_7_continued; - jmp dfdat_in_7_continued; + call dma_finish; + /* If we were putting the SCB, we are done */ + test DMAPARAMS, DIRECTION jz return; + mvi SCB_CONTROL call dfdat_in_7; + call dfdat_in_7_continued; + call dfdat_in_7_continued; + jmp dfdat_in_7_continued; dfdat_in_7: - mov DINDEX,SINDEX; + mov DINDEX,SINDEX; dfdat_in_7_continued: - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT ret; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT ret; + } + /* * Wait for DMA from host memory to data FIFO to complete, then disable * DMA and wait for it to acknowledge that it's off. */ +if ((p->features & AHC_CMD_CHAN) == 0) { dma_finish: test DFSTATUS,HDONE jz dma_finish; /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; ret; +} add_scb_to_free_list: -.if ( SCB_PAGING ) - mov SCB_NEXT, FREE_SCBH; - mov FREE_SCBH, SCBPTR; -.endif + if ((p->flags & AHC_PAGESCBS) != 0) { + mov SCB_NEXT, FREE_SCBH; + mov FREE_SCBH, SCBPTR; + } mvi SCB_TAG, SCB_LIST_NULL ret; -.if ( SCB_PAGING ) +if ((p->flags & AHC_PAGESCBS) != 0) { get_free_or_disc_scb: cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; @@ -1206,12 +1464,11 @@ dma_up_scb: mvi DMAPARAMS, FIFORESET; mov SCB_TAG call dma_scb; unlink_disc_scb: - /* jmp instead of call since we want to return anyway */ - mov SCBPTR jmp rem_scb_from_disc_list; + mov DISCONNECTED_SCBH, SCB_NEXT ret; dequeue_free_scb: mov SCBPTR, FREE_SCBH; mov FREE_SCBH, SCB_NEXT ret; -.endif +} add_scb_to_disc_list: /* @@ -1219,10 +1476,5 @@ add_scb_to_disc_list: * 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; mov SCB_NEXT, DISCONNECTED_SCBH; - mov DISCONNECTED_SCBH, SCBPTR; - cmp SCB_NEXT,SCB_LIST_NULL je return; - mov SCBPTR,SCB_NEXT; - mov SCB_PREV,DISCONNECTED_SCBH; - mov SCBPTR,DISCONNECTED_SCBH ret; + mov DISCONNECTED_SCBH, SCBPTR ret; |