⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aic7xxx.seq

📁 linux-2.6.15.6
💻 SEQ
📖 第 1 页 / 共 5 页
字号:
	/*	 * Turn on `Bit Bucket' mode, wait until the target takes	 * us to another phase, and then notify the host.	 */	and	DMAPARAMS, DIRECTION;	mov	DFCNTRL, DMAPARAMS;	or	SXFRCTL1,BITBUCKET;	if ((ahc->features & AHC_DT) == 0) {		test	SSTAT1,PHASEMIS	jz .;	} else {		test	SCSIPHASE, DATA_PHASE_MASK jnz .;	}	and	SXFRCTL1, ~BITBUCKET;	mvi	DATA_OVERRUN call set_seqint;	jmp	ITloop;data_phase_inbounds:	if ((ahc->features & AHC_ULTRA2) != 0) {		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;		or	SINDEX, LAST_SEG;		mov	SG_CACHE_PRE, SINDEX;		mov	DFCNTRL, DMAPARAMS;ultra2_dma_loop:		call	idle_loop;		/*		 * The transfer is complete if either the last segment		 * completes or the target changes phase.		 */		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;		if ((ahc->features & AHC_DT) == 0) {			if ((ahc->flags & AHC_TARGETROLE) != 0) {				 /*				  * As a target, we control the phases,				  * so ignore PHASEMIS.				  */				test	SSTAT0, TARGET jnz ultra2_dma_loop;			}			if ((ahc->flags & AHC_INITIATORROLE) != 0) {				test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;			}		} else {			test	DFCNTRL, SCSIEN jnz ultra2_dma_loop;		}ultra2_dmafinish:		/*		 * The transfer has terminated either due to a phase		 * change, and/or the completion of the last segment.		 * We have two goals here.  Do as much other work		 * as possible while the data fifo drains on a read		 * and respond as quickly as possible to the standard		 * messages (save data pointers/disconnect and command		 * complete) that usually follow a data phase.		 */		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {			/*			 * On chips with broken auto-flush, start			 * the flushing process now.  We'll poke			 * the chip from time to time to keep the			 * flush process going as we complete the			 * data phase.			 */			or	DFCNTRL, FIFOFLUSH;		}		/*		 * We assume that, even though data may still be		 * transferring to the host, that the SCSI side of		 * the DMA engine is now in a static state.  This		 * allows us to update our notion of where we are		 * in this transfer.		 *		 * If, by chance, we stopped before being able		 * to fetch additional segments for this transfer,		 * yet the last S/G was completely exhausted,		 * call our idle loop until it is able to load		 * another segment.  This will allow us to immediately		 * pickup on the next segment on the next data phase.		 *		 * If we happened to stop on the last segment, then		 * our residual information is still correct from		 * the idle loop and there is no need to perform		 * any fixups.		 */ultra2_ensure_sg:		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;		/* Record if we've consumed all S/G entries */		test	SSTAT2, SHVALID	jnz residuals_correct;		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;		jmp	residuals_correct;ultra2_shvalid:		test	SSTAT2, SHVALID	jnz sgptr_fixup;		call	idle_loop;		jmp	ultra2_ensure_sg;sgptr_fixup:		/*		 * Fixup the residual next S/G pointer.  The S/G preload		 * feature of the chip allows us to load two elements		 * in addition to the currently active element.  We		 * store the bottom byte of the next S/G pointer in		 * the SG_CACEPTR register so we can restore the		 * correct value when the DMA completes.  If the next		 * sg ptr value has advanced to the point where higher		 * bytes in the address have been affected, fix them		 * too.		 */		test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;		test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;		add	SCB_RESIDUAL_SGPTR[1], -1;		adc	SCB_RESIDUAL_SGPTR[2], -1; 		adc	SCB_RESIDUAL_SGPTR[3], -1;sgptr_fixup_done:		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;		/* We are not the last seg */		and	SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG;residuals_correct:		/*		 * Go ahead and shut down the DMA engine now.		 * In the future, we'll want to handle end of		 * transfer messages prior to doing this, but this		 * requires similar restructuring for pre-ULTRA2		 * controllers.		 */		test	DMAPARAMS, DIRECTION jnz ultra2_fifoempty;ultra2_fifoflush:		if ((ahc->features & AHC_DT) == 0) {			if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {				/*				 * On Rev A of the aic7890, the autoflush				 * feature doesn't function correctly.				 * Perform an explicit manual flush.  During				 * a manual flush, the FIFOEMP bit becomes				 * true every time the PCI FIFO empties				 * regardless of the state of the SCSI FIFO.				 * It can take up to 4 clock cycles for the				 * SCSI FIFO to get data into the PCI FIFO				 * and for FIFOEMP to de-assert.  Here we				 * guard against this condition by making				 * sure the FIFOEMP bit stays on for 5 full				 * clock cycles.				 */				or	DFCNTRL, FIFOFLUSH;				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;			}			test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;		} else {			/*			 * We enable the auto-ack feature on DT capable			 * controllers.  This means that the controller may			 * have already transferred some overrun bytes into			 * the data FIFO and acked them on the bus.  The only			 * way to detect this situation is to wait for			 * LAST_SEG_DONE to come true on a completed transfer			 * and then test to see if the data FIFO is non-empty.			 */			test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL				jz ultra2_wait_fifoemp;			test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;			/*			 * FIFOEMP can lag LAST_SEG_DONE.  Wait a few			 * clocks before calling this an overrun.			 */			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;			/* Overrun */			jmp	data_phase_loop;ultra2_wait_fifoemp:			test	DFSTATUS, FIFOEMP jz .;		}ultra2_fifoempty:		/* Don't clobber an inprogress host data transfer */		test	DFSTATUS, MREQPEND	jnz ultra2_fifoempty;ultra2_dmahalt:		and     DFCNTRL, ~(SCSIEN|HDMAEN);		test	DFCNTRL, SCSIEN|HDMAEN jnz .;		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {			/*			 * Keep HHADDR cleared for future, 32bit addressed			 * only, DMA operations.			 *			 * Due to bayonette style S/G handling, our residual			 * data must be "fixed up" once the transfer is halted.			 * Here we fixup the HSHADDR stored in the high byte			 * of the residual data cnt.  By postponing the fixup,			 * we can batch the clearing of HADDR with the fixup.			 * If we halted on the last segment, the residual is			 * already correct.   If we are not on the last			 * segment, copy the high address directly from HSHADDR.			 * We don't need to worry about maintaining the			 * SG_LAST_SEG flag as it will always be false in the			 * case where an update is required.			 */			or	DSCOMMAND1, HADDLDSEL0;			test	SG_CACHE_SHADOW, LAST_SEG jnz . + 2;			mov	SCB_RESIDUAL_DATACNT[3], SHADDR;			clr	HADDR;			and	DSCOMMAND1, ~HADDLDSEL0;		}	} else {		/* If we are the last SG block, tell the hardware. */		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0		  && ahc->pci_cachesize != 0) {			test	MWI_RESIDUAL, 0xFF jnz dma_mid_sg;		}		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;		if ((ahc->flags & AHC_TARGETROLE) != 0) {			test	SSTAT0, TARGET jz dma_last_sg;			if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) {				test	DMAPARAMS, DIRECTION jz dma_mid_sg;			}		}dma_last_sg:		and	DMAPARAMS, ~WIDEODD;dma_mid_sg:		/* Start DMA data transfer. */		mov	DFCNTRL, DMAPARAMS;dma_loop:		if ((ahc->features & AHC_CMD_CHAN) != 0) {			call	idle_loop;		}		test	SSTAT0,DMADONE	jnz dma_dmadone;		test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */dma_phasemis:		/*		 * We will be "done" DMAing when the transfer count goes to		 * zero, or the target changes the phase (in light of this,		 * it makes sense that the DMA circuitry doesn't ACK when		 * PHASEMIS is active).  If we are doing a SCSI->Host transfer,		 * the data FIFO should be flushed auto-magically on STCNT=0		 * or a phase change, so just wait for FIFO empty status.		 */dma_checkfifo:		test	DFCNTRL,DIRECTION	jnz dma_fifoempty;dma_fifoflush:		test	DFSTATUS,FIFOEMP	jz dma_fifoflush;dma_fifoempty:		/* Don't clobber an inprogress host data transfer */		test	DFSTATUS, MREQPEND	jnz dma_fifoempty;		/*		 * Now shut off the DMA and make sure that the DMA		 * hardware has actually stopped.  Touching the DMA		 * counters, etc. while a DMA is active will result		 * in an ILLSADDR exception.		 */dma_dmadone:		and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);dma_halt:		/*		 * Some revisions of the aic78XX 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 drain		 * the prefetched but unused data from the data fifo until		 * there is space for the input latch to drain.		 */		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {			mov	NONE, DFDAT;		}		test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;		/* See if we have completed this last segment */		test	STCNT[0], 0xff	jnz data_phase_finish;		test	STCNT[1], 0xff	jnz data_phase_finish;		test	STCNT[2], 0xff	jnz data_phase_finish;		/*		 * Advance the scatter-gather pointers if needed 		 */		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0		  && ahc->pci_cachesize != 0) {			test	MWI_RESIDUAL, 0xFF jz no_mwi_resid;			/*			 * Reload HADDR from SHADDR and setup the			 * count to be the size of our residual.			 */			if ((ahc->features & AHC_CMD_CHAN) != 0) {				bmov	HADDR, SHADDR, 4;				mov	HCNT, MWI_RESIDUAL;				bmov	HCNT[1], ALLZEROS, 2;			} else {				mvi	DINDEX, HADDR;				mvi	SHADDR call bcopy_4;				mov	MWI_RESIDUAL call set_hcnt;			}			clr	MWI_RESIDUAL;			jmp	sg_load_done;no_mwi_resid:		}		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;		jmp	data_phase_finish;sg_load:		/*		 * Load the next SG element's data address and length		 * into the DMA engine.  If we don't have hardware		 * to perform a prefetch, we'll have to fetch the		 * segment from host memory first.		 */		if ((ahc->features & AHC_CMD_CHAN) != 0) {			/* Wait for the idle loop to complete */			test	CCSGCTL, CCSGEN jz . + 3;			call	idle_loop;			test	CCSGCTL, CCSGEN jnz . - 1;			bmov 	HADDR, CCSGRAM, 7;			/*			 * Workaround for flaky external SCB RAM			 * on certain aic7895 setups.  It seems			 * unable to handle direct transfers from			 * S/G ram to certain SCB locations.			 */			mov	SINDEX, CCSGRAM;			mov	SCB_RESIDUAL_DATACNT[3], SINDEX;		} else {			if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {				mov	ALLZEROS call set_hhaddr;			}			mvi	DINDEX, HADDR;			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;			mvi	SG_SIZEOF	call set_hcnt;			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;			call	dma_finish;			mvi	DINDEX, HADDR;			call	dfdat_in_7;			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;		}		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;			/*			 * The lowest address byte must be loaded			 * last as it triggers the computation of			 * some items in the PCI block.  The ULTRA2			 * chips do this on PRELOAD.			 */			mov	HADDR, HADDR;		}		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0		  && ahc->pci_cachesize != 0) {			call calc_mwi_residual;		}		/* Point to the new next sg in memory */		call	sg_advance;sg_load_done:		if ((ahc->features & AHC_CMD_CHAN) != 0) {			bmov	STCNT, HCNT, 3;		} else {			call	set_stcnt_from_hcnt;		}		if ((ahc->flags & AHC_TARGETROLE) != 0) {			test	SSTAT0, TARGET jnz data_phase_loop;		}	}data_phase_finish:	/*	 * If the target has left us in data phase, loop through	 * the dma code again.  In the case of ULTRA2 adapters,	 * we should only loop if there is a data overrun.  For	 * all other adapters, we'll loop after each S/G element	 * is loaded as well as if there is an overrun.	 */	if ((ahc->flags & AHC_TARGETROLE) != 0) {		test	SSTAT0, TARGET jnz data_phase_done;	}	if ((ahc->flags & AHC_INITIATORROLE) != 0) {		test	SSTAT1, REQINIT jz .;		if ((ahc->features & AHC_DT) == 0) {			test	SSTAT1,PHASEMIS	jz data_phase_loop;		} else {			test	SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop;		}	}data_phase_done:	/*	 * 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.	 */	if ((ahc->features & AHC_CMD_CHAN) != 0) {		/* Kill off any pending prefetch */		call	disable_ccsgen;	}	if ((ahc->features & AHC_ULTRA2) == 0) {		/*		 * Clear the high address byte so that all other DMA		 * operations, which use 32bit addressing, can assume		 * HHADDR is 0.		 */		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {			mov	ALLZEROS call set_hhaddr;		}	}	/*	 * Update our residual information before the information is	 * lost by some other type of SCSI I/O (e.g. PIO).  If we have	 * transferred all data, no update is needed.	 *	 */	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done;	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0	  && ahc->pci_cachesize != 0) {		if ((ahc->features & AHC_CMD_CHAN) != 0) {			test	MWI_RESIDUAL, 0xFF jz bmov_resid;		}		mov	A, MWI_RESIDUAL;		add	SCB_RESIDUAL_DATACNT[0], A, STCNT[0];		clr	A;		adc	SCB_RESIDUAL_DATACNT[1], A, STCNT[1];		adc	SCB_RESIDUAL_DATACNT[2], A, STCNT[2];		clr	MWI_RESIDUAL;		if ((ahc->features & AHC_CMD_CHAN) != 0) {			jmp	. + 2;bmov_resid:			bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;		}	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {		bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;	} else {		mov	SCB_RESIDUAL_DATACNT[0], STCNT[0];		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];	}residual_update_done:	/*	 * Since we've been through a data phase, the SCB_RESID* fields

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -