📄 pdma_ds5000.c
字号:
if( sc->dma_pflags & PDMA_PREFLUSH ) { for( i = 0; i < PIPE_BUF_NUM; i++ ) { (*sc->dma_bzero) ( sc->pdma_rambuff + RAM_ADJUST(sc, pd->pb_offset[i]), MAX_XFER_SIZE ); wbflush(); pd->pb_flags[i] = PB_READY; /* set to ready for data */ } } /* If the I/O direction is a READ, load the two pipe buffer counters. By definition buffer 0 will take presidence over buffer 1. Buffer 0 will be filled first the total count will also be decremented. */ if( dir == SZ_DMA_READ ) { for( i = 0; i < PIPE_BUF_NUM; i++ ) { lcount = XFER_BUFCNT( pd->count - pd->usercnt ); /* how much */ pd->usercnt += lcount; /* update count for later */ pd->pb_count[i] = lcount; /* load the count expected */ pd->pb_flags[i] = PB_LOADED;/* loaded for a READ :-) */ if( pd->usercnt == pd->count ) /* stop if no more data */ { break; /* drop out of the for loop */ } } } else { /* If the I/O direction is a WRITE, pre fill the pipe buffers. By definition buffer 0 will take presidence over buffer 1. Buffer 0 will be filled/emptied first. */ for( i = 0; i < PIPE_BUF_NUM; i++ ) { 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[i]), 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[i] )), len); wbflush(); pd->usercnt += lcount; /* update user space count */ pd->pb_count[i] = lcount; /* load the count for this buffer */ pd->pb_flags[i] = PB_LOADED; if( pd->usercnt == pd->count ) /* stop if all data moved */ { break; /* drop out of the for loop */ } } } return( PDMA_SUCCESS ); /* ready */}/************************************************************************int pdma_start( sc, targid, opcode )Inputs: sz_softc *sc; pointer to the softc structure int targid; current targit ID int opcode; value to start the dma oper in the chip Function: This routine is fairly straight forward. It is responsible for loading what ever is necessary into the DMA engine and the SCSI chip. The dma control structure for the target should contain all the information. The SZ_DID_DMA flag in the softc structure will be set. This informs the driver that data xfers are taking place. NOTE: Most of the SCSI chips with the RAM buffer use offsets into the buffer for the location of the data. This is the reason for storing the offsets instead of pointers. NOTE: An opcode argument is passed to this routine mostly for the 3max/NCR 53c94. In the SII, 5380 machines the sequence is fairly "canned" to start up dma for the data phases. However the 3max plans to use these routines for all information phases.Return: PDMA_SUCCESS all is ready and ok PDMA_FAIL a fatal(?) problem has occured **************************************************************************/intds5000_start( sc, targid, opcode ) struct sz_softc *sc; /* pointer to the softc structure */ int targid; /* current targit ID */ int opcode; /* value to start the dma oper in the chip */{ PDMA *pd; /* pointer for the DMA control struct */ ASC_REG *ascaddr; /* pointer for the SCSI chip registers */ DMA_AR *ascar; /* pointer for the SCSI DMA engine register */ PRINTD( targid, 0x1, ("ds5000_start entry sc:%x targ:%d op:%x\n", sc, targid, opcode )); /* Initialize local variables. */ pd = &sc->pdma_ctrl[ targid ]; /* assign the pointer */ ascaddr = (ASCREG *)sc->sc_scsiaddr;/* get the chip addr */ ascar = (DMAAR *)sc->pdma_addrreg; /* engine address */ pd->opcode = opcode; /* save for later use */ /* Load the information from the dma control structure for buffer 0 into the SCSI chip and DMA engine. */ ascar->rambuf_dma = /* load addr reg */ (((pd->iodir == SZ_DMA_WRITE) ? DMA_ASC_WRITE : 0 ) | (pd->pb_offset[0] & 0x00ffffff)); wbflush(); ASC_LOADCNTR(ascaddr, pd->pb_count[0]); /* load counter */ wbflush(); /* Start the DMA operation in the ASC. */ /* NOTE: for the 3max all this will not be necessary, probably just load passed opcode ? */ sc->sc_asccmd = pd->opcode; ascaddr->asc_cmd = pd->opcode; wbflush(); /* clear write buffer */ /* Set the pstate to inform the driver that DMA is in progress. */ pd->pstate = PDMA_ACTIVE; pd->pb_flags[0] = PB_DMA_ACTIVE; sc->sc_szflags[ targid ] |= SZ_DID_DMA; return( PDMA_SUCCESS );}/************************************************************************int pdma_cont( sc, targid )Inputs: sz_softc *sc; pointer to the softc structure int targid; current targit ID Function: Handle intermediate DMA functions during the transfer. In the case of pipe buffers the SCSI chip/Engine will reach terminal count whenever one of the buffers is filled/emptied. The active buffer for a DATA_IN will have the data moved to user space. For a DMA_OUT the next buffer will be given to the SCSI chip, and the previous buffer will be filled to get ready for the next pdma_cont() call. NOTE: An assupmtion is made that for a DMA_OUT the next buffer is always ready with valid data, if necessary. NOTE: In the CMAX case the SII has a limitation in the data counter. It can only xfer 8k bytes with one DMA operation. This routine would only have to kick start the SII again. Question: Is it fair to assume that this routine will only get called on TC and not phase change? There is no checking on the current counter within the SCSI chip.Return: The number of bytes transfered sofar for this DMA operation.**************************************************************************/intds5000_cont( sc, targid ) struct sz_softc *sc; /* pointer to the softc structure */ int targid; /* current target ID */{ PDMA *pd; /* pointer for the DMA control struct */ ASC_REG *ascaddr; /* pointer for the SCSI chip registers */ DMA_AR *ascar; /* pointer for the SCSI DMA engine register */ 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 active pipe buffer */ PRINTD( targid, 0x1, ("ds5000_cont 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 */ ascar = (DMAAR *)sc->pdma_addrreg; /* engine address */ /* 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 */ /* Do a quick check to determine there is still data that needs to be "continued". If the Target is slow in changing phase from DATA, the terminal count interrupt will occur before the phase change interrupt. This routine could be called and later a phase change occurs. If there is no more data left to transfer just return the target count. When the phase change interrupt finially happens the pdma_end() routine will clean up. */ if( (pd->targcnt + pd->pb_count[ active ]) == pd->count ) { PRINTD(targid, 0x1, ("dma_cont: returning (no i/o), targcnt = 0x%x\n", pd->targcnt)); return( pd->targcnt ); /* nothing done */ } /* 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. Q: What if SCSI cntr != 0? [pdma_end should be called ?] */ 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(); /* debug - since we only call this routine when the phase is the same AND when TC is set, I believe that both of these should be zero. */ if ((tcount != 0) || (ffr != 0)) { PRINTD(targid, 0x8000, ("ds5000_cont: tcount = %x, ffr = %x\n", tcount, ffr)); } if( pd->iodir == SZ_DMA_WRITE ) tcount += ffr; /* update count by whats in FIFO on writes */ lcount = pd->pb_count[ active ] - tcount; /* keep track of total number of bytes actually transferred */ sc->sc_ascdmacount[targid] += lcount; /* Check the direction flag to determine what has to be done with the pipe buffers. */ if( pd->iodir == SZ_DMA_READ ) { /* If the operation is a DMA_IN: swap the buffers if there is more data that has to come in, startup the DMA, and then move the data from the now idle buffer to user space. */ /* Load up the SCSI chip with the address and count for the next buffer. */ /* Load addr reg, no need to set the write bit. */ ascar->rambuf_dma = (pd->pb_offset[ next ] & 0x00ffffff); wbflush(); ASC_LOADCNTR(ascaddr, pd->pb_count[ next ]); /* load counter */ wbflush(); PRINTD(targid, 0x8000, ("ds5000_cont: (READ) starting new dma %x bytes\n", pd->pb_count[next])); /* 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; /* Switch the "active" pipe buffer from DMA_ACTIVE to CPU_ACTIVE, the SCSI chip is done with it. Move the data into user space. */ pd->pb_flags[ active ] = PB_CPU_ACTIVE; PRINTD(targid, 0x8000, ("ds5000_cont: (READ) bcopying %x bytes to user space\n", pd->pb_count[active])); if( pd->pb_count[active] != 0 ) /* don't bother if no data */ { (*sc->dma_rbcopy) /* move the data */ ((sc->pdma_rambuff + RAM_ADJUST( sc, pd->pb_offset[ active ] )), (pd->data_addr + pd->targcnt), pd->pb_count[ active ] ); wbflush(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -