📄 pdma_ds5000.c
字号:
pd->targcnt += pd->pb_count[ active ]; /* update target count */ pd->pb_flags[ active ] = PB_FINISHED; /* If there is still more data that will be transfered setup the old active buffer for the next interrupt. */ if( (pd->count - pd->usercnt) != 0 ) /* still more data */ { /* Setup the count for the PDMA transfer. */ lcount = XFER_BUFCNT( pd->count - pd->usercnt ); /* how much */ pd->pb_count[ active ] = lcount; pd->usercnt += lcount; /* update count for later */ pd->pb_flags[ active ] = PB_READY; /* set to ready for data */ PRINTD(targid, 0x8000, ("ds5000_cont: (READ) more data, new pb_count = %x, usercnt = %x\n", lcount, pd->usercnt)); } } /* end of (pd->iodir == SZ_DMA_READ) */ else { /* If the operation is a DMA_OUT: the next buffer has valid data in it ready for the SCSI chip to access. The DMA is started on the next buffer. The "active" buffer, which is now CPU_ACTIVE, is filled if there is still more data to be moved from user space. */ /* Load up the SCSI chip with the address and count for the next buffer. */ /* Load addr reg, set the write direction bit. */ ascar->rambuf_dma = (DMA_ASC_WRITE | (pd->pb_offset[ next ] & 0x00ffffff)); wbflush(); ASC_LOADCNTR(ascaddr, pd->pb_count[ next ]); /* load counter */ wbflush(); /* Start the DMA operation in the ASC. */ sc->sc_asccmd = pd->opcode; ascaddr->asc_cmd = pd->opcode; wbflush(); /* clear write buffer */ /* Set the flag to inform the driver that DMA is in progress. */ pd->pb_flags[ next ] = PB_DMA_ACTIVE; sc->sc_szflags[ targid ] |= SZ_DID_DMA; /* Update the target side counter. The data has been moved to the target from the RAM buffer. */ pd->targcnt += pd->pb_count[ active ]; /* update target count */ /* Switch the "active" pipe buffer from DMA_ACTIVE to CPU_ACTIVE, the SCSI chip is done with it. */ pd->pb_flags[ active ] = PB_CPU_ACTIVE; /* Check the count value, if there is more data to be preloaded into the now CPU_ACTIVE "active" buffer move it in and set the flags. */ if( (pd->count - pd->usercnt) != 0 ) /* still more data */ { /* Setup the count for the PDMA transfer. */ int len; len = lcount = XFER_BUFCNT( pd->count - pd->usercnt ); if( (pd->usercnt + lcount) > sc->sc_b_bcount[targid] ) { /* Calc the new len to the end. */ len = sc->sc_b_bcount[targid] - pd->usercnt; /* Zero out the half of the RAM buffer, this will deal with the zero fill requirement. */ (*sc->dma_bzero) ( sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[active]), lcount); wbflush(); } /* Move the data to write into the RAM buffer. */ (*sc->dma_wbcopy)( (pd->data_addr + pd->usercnt), (sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[active])), len); wbflush(); pd->usercnt += lcount; /* update user count */ pd->pb_count[ active ] = lcount; pd->pb_flags[ active ] = PB_LOADED; } else { pd->pb_flags[ active ] = PB_FINISHED; } } /* end of else on (pd->iodir == SZ_DMA_READ) */ return( pd->targcnt ); /* return current progress */}/************************************************************************int pdma_end( sc, targid )Inputs: sz_softc *sc; pointer to the softc structure int targid; current targit ID Function: Handle the completion of the DMA operation. Free up the necessary DMA resources that were allocated in dma_setup(). Handle the final move of the data to user space if the operation was a read.Return: The number of bytes transfered over the entire DMA operation.**************************************************************************/intds5000_end( sc, targid ) struct sz_softc *sc; /* pointer to the softc structure */ int targid; /* current targit ID */{ PDMA *pd; /* pointer for the DMA control struct */ ASC_REG *ascaddr; /* pointer for the SCSI chip registers */ int ffr; /* value for the FIFO flags */ int tcount; /* corrected count for the ASC counters */ int lcount; /* local count from the transfers */ int active; /* index for the current active pipe buffer */ int next; /* index for the next pipe buffer */ int i; /* buffer loop counter */ int len; PRINTD( targid, 0x1, ("ds5000_end entry sc:%x targ:%d\n", sc, targid)); pd = &sc->pdma_ctrl[ targid ]; /* assign the pointer */ ascaddr = (ASCREG *)sc->sc_scsiaddr;/* get the chip addr */ /* Find the current active buffer in the pipe. The offset and counts are needed. The return value will not be checked. */ get_bindex( pd, &active, &next ); /* scan the buffers for DMA_ACTIVE */ /* From the active buffers count and the SCSI chips actual xfer counter register value, calc how much data was transfered. Update the working counter(s) for the return xfer count. So far the SCSI chip counters are all down counters, making the xfer count calc a simple subtaction. The counters in the ASC have to be corrected for the # of bytes left in the FIFO but not transferred when the target changed phase. */ ffr = (int)ascaddr->asc_ffss; /* get the fifo flags count */ ffr &= ASC_FIFO_MSK; /* mask off sequ step bits */ ASC_GETCNTR(ascaddr, tcount); /* get the counter value */ ASC_LOADCNTR(ascaddr, 0); /* JAG - force TC bit off */ wbflush(); if ((tcount != 0) || (ffr != 0)) { PRINTD(targid, 0x8000, ("ds5000_end: ffr = 0x%x\n", ffr)); } tcount += ffr; /* update count by whats in FIFO */ lcount = pd->pb_count[ active ] - tcount; /* keep track of total number of bytes actually transferred */ sc->sc_ascdmacount[targid] += lcount; /* If the last operation was a SZ_DMA_READ, move the data to user space. */ if( pd->iodir == SZ_DMA_READ ) { /* Switch the pipe buffer from DMA_ACTIVE to CPU_ACTIVE, the SCSI chip is done with it. */ pd->pb_flags[ active ] = PB_CPU_ACTIVE; PRINTD(targid, 0x8000, ("ds5000_end: (READ) bcopy %x bytes\n", lcount)); /* Move the READ data to user space. */ if( lcount != 0 ) /* don't bother if no data */ { len = lcount; /* Make sure we don't go beyond user's buffer */ if( sc->sc_ascdmacount[targid] > sc->sc_b_bcount[targid] ) { len = lcount - (sc->sc_ascdmacount[targid] - sc->sc_b_bcount[targid]); } (*sc->dma_rbcopy) /* move to user space */ ((sc->pdma_rambuff + RAM_ADJUST( sc, pd->pb_offset[ active ] )), (pd->data_addr + pd->targcnt), len); wbflush(); } } /* Update the target count, the data has moved between the RAM buffer and target. */ pd->targcnt += lcount; /* update working count */ /* Clean up after ourselves. Deallocate the pipe [for dynamic alloc]. Set all the flags to finished. Clear the SZ_DID_DMA flag. [What else ?] */ sc->sc_szflags[ targid ] &= ~SZ_DID_DMA; /* DID_DMA is done */ for( i = 0; i < PIPE_BUF_NUM; i++ ) { pd->pb_flags[i] = PB_FINISHED; /* just for completion */ } pd->pstate = PDMA_IDLE; /* all done */ /* Return the accumulated working count to the driver. No checking has been done to verify that all the data has been transfered. */ return( pd->targcnt );}/************************************************************************/* Support routines. *//************************************************************************/* This routine will return through the "active/next" pointers theindex of the pipe buffers that are currently "active" and which one is"next". The currently active buffer will have the PB_DMA_ACTIVE flagset in it's flags field. The "next" buffer will be the next buffer inline. There will be no checking on the state of the "next" buffer,this routine can be called for a DMA_IN or DMA_OUT phase. This routineis very tightly bound to the number of buffers in the pipe. At thistime the implementation is based on 2, PIPE_BUF_NUM, buffers per pipe.If the number of buffers per pipe changes this routine will have tochange to reflect the change. NOTE: one possible idea for multiple buffers is to find the first one that has PB_DMA_ACTIVE and for the next index increment to the following buffer checking for wrap around.**************************************************************************/int get_bindex( pd, active, next ) PDMA *pd; /* ptr for the control structure */ int *active; /* holder for the active index */ int *next; /* holder for the active index */{ /* Find the current active buffer in the pipe. The offset and counts are needed. A cascadding if/else sequence is used here, there is no reason why there cannot be more than 2 buffers w/in the pipe. For just 2 buffers this quick. */ if( pd->pb_flags[0] == PB_DMA_ACTIVE ) { *active = 0; *next = 1; } else if( pd->pb_flags[1] = PB_DMA_ACTIVE ) { *active = 1; *next = 0; } else { *active = 0; /* default error fall through */ *next = 1; return( PDMA_FAIL ); /* just in case */ } return( PDMA_SUCCESS ); /* all done and selected */ }/************************************************************************/intds5000_flush( sc, targid ) struct sz_softc *sc; /* pointer to the softc structure */ int targid; /* current targit ID */{ PDMA *pd; /* pointer for the DMA control struct */ int i; /* buffer loop counter */ PRINTD( targid, 0x1, ("ds5000_flush entry sc:%x targ:%d\n", sc, targid)); pd = &sc->pdma_ctrl[ targid ]; /* assign the pointer */ for( i = 0; i < PIPE_BUF_NUM; i++ ) { /* Flush, or zero out the pipe buffer. */ (*sc->dma_bzero) ( sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[i]), MAX_XFER_SIZE ); wbflush(); } return( PDMA_SUCCESS ); /* all done */ }/************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -