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

📄 aic79xx.seq

📁 linux-2.6.15.6
💻 SEQ
📖 第 1 页 / 共 5 页
字号:
/* * Functions to read data in Automatic PIO mode. * * An ACK is not sent on input from the target until SCSIDATL is read from. * So we wait until SCSIDATL is latched (the usual way), then read the data * byte directly off the bus using SCSIBUSL.  When we have pulled the ATN * line, or we just want to acknowledge the byte, then we do a dummy read * from SCISDATL.  The SCSI spec guarantees that the target will hold the * data byte on the bus until we send our ACK. * * The assumption here is that these are called in a particular sequence, * and that REQ is already set when inb_first is called.  inb_{first,next} * use the same calling convention as inb. */inb_next:	mov	NONE,SCSIDAT;		/*dummy read from latch to ACK*/inb_next_wait:	/*	 * If there is a parity error, wait for the kernel to	 * see the interrupt and prepare our message response	 * before continuing.	 */	test	SCSIPHASE, 0xFF jz .;	test	SSTAT1, SCSIPERR jnz inb_next_wait;inb_next_check_phase:	and	LASTPHASE, PHASE_MASK, SCSISIGI;	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;inb_first:	clr	DINDEX[1];	mov	DINDEX,SINDEX;	mov	DINDIR,SCSIBUS	ret;		/*read byte directly from bus*/inb_last:	mov	NONE,SCSIDAT ret;		/*dummy read from latch to ACK*/mk_mesg:	mvi	SCSISIGO, ATNO;	mov	MSG_OUT,SINDEX ret;SET_SRC_MODE	M_DFF1;SET_DST_MODE	M_DFF1;disable_ccsgen:	test	SG_STATE, FETCH_INPROG jz disable_ccsgen_fetch_done;	clr	CCSGCTL;disable_ccsgen_fetch_done:	clr	SG_STATE ret;service_fifo:	/*	 * Do we have any prefetch left???	 */	test	SG_STATE, SEGS_AVAIL jnz idle_sg_avail;	/*	 * Can this FIFO have access to the S/G cache yet?	 */	test	CCSGCTL, SG_CACHE_AVAIL jz return;	/* Did we just finish fetching segs? */	test	CCSGCTL, CCSGDONE jnz idle_sgfetch_complete;	/* Are we actively fetching segments? */	test	CCSGCTL, CCSGENACK jnz return;	/*	 * We fetch a "cacheline aligned" and sized amount of data	 * so we don't end up referencing a non-existant page.	 * Cacheline aligned is in quotes because the kernel will	 * set the prefetch amount to a reasonable level if the	 * cacheline size is unknown.	 */	bmov	SGHADDR, SCB_RESIDUAL_SGPTR, 4;	mvi	SGHCNT, SG_PREFETCH_CNT;	if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) {		/*		 * Need two instruction between "touches" of SGHADDR.		 */		nop;	}	and	SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;	mvi	CCSGCTL, CCSGEN|CCSGRESET;	or	SG_STATE, FETCH_INPROG ret;idle_sgfetch_complete:	/*	 * Guard against SG_CACHE_AVAIL activating during sg fetch	 * request in the other FIFO.	 */	test	SG_STATE, FETCH_INPROG jz return;	clr	CCSGCTL;	and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;	mvi	SG_STATE, SEGS_AVAIL|LOADING_NEEDED;idle_sg_avail:	/* Does the hardware have space for another SG entry? */	test	DFSTATUS, PRELOAD_AVAIL jz return;	/*	 * On the A, preloading a segment before HDMAENACK	 * comes true can clobber the shaddow address of the	 * first segment in the S/G FIFO.  Wait until it is	 * safe to proceed.	 */	if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) {		test	DFCNTRL, HDMAENACK jz return;	}	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {		bmov	HADDR, CCSGRAM, 8;	} else {		bmov 	HADDR, CCSGRAM, 4;	}	bmov	HCNT, CCSGRAM, 3;	bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;	if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {		and	HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3];	}	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {		/* Skip 4 bytes of pad. */		add	CCSGADDR, 4;	}sg_advance:	clr	A;			/* add sizeof(struct scatter) */	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;	adc	SCB_RESIDUAL_SGPTR[1],A;	adc	SCB_RESIDUAL_SGPTR[2],A;	adc	SCB_RESIDUAL_SGPTR[3],A;	mov	SINDEX, SCB_RESIDUAL_SGPTR[0];	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3;	or	SINDEX, LAST_SEG;	clr	SG_STATE;	mov	SG_CACHE_PRE, SINDEX;	if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {		/*		 * Use SCSIENWRDIS so that SCSIEN is never		 * modified by this operation.		 */		or	DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS;	} else {		or	DFCNTRL, PRELOADEN|HDMAEN;	}	/*	 * Do we have another segment in the cache?	 */	add	NONE, SG_PREFETCH_CNT_LIMIT, CCSGADDR;	jnc	return;	and	SG_STATE, ~SEGS_AVAIL ret;/* * Initialize the DMA address and counter from the SCB. */load_first_seg:	bmov	HADDR, SCB_DATAPTR, 11;	and	REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0];	test	SCB_DATACNT[3], SG_LAST_SEG jz . + 2;	or	REG_ISR, LAST_SEG;	mov	SG_CACHE_PRE, REG_ISR;	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);	/*	 * Since we've are entering a data phase, we will	 * rely on the SCB_RESID* fields.  Initialize the	 * residual and clear the full residual flag.	 */	and	SCB_SGPTR[0], ~SG_FULL_RESID;	bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;	/* If we need more S/G elements, tell the idle loop */	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz . + 2;	mvi	SG_STATE, LOADING_NEEDED ret;	clr	SG_STATE ret;p_data_handle_xfer:	call	setjmp;	test	SG_STATE, LOADING_NEEDED jnz service_fifo;p_data_clear_handler:	or	LONGJMP_ADDR[1], INVALID_ADDR ret;p_data:	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT	jz p_data_allowed;	SET_SEQINTCODE(PROTO_VIOLATION)p_data_allowed: 	test	SEQ_FLAGS, DPHASE	jz data_phase_initialize;	/*	 * If we re-enter the data phase after going through another	 * phase, our transfer location has almost certainly been	 * corrupted by the interveining, non-data, transfers.  Ask	 * the host driver to fix us up based on the transfer residual	 * unless we already know that we should be bitbucketing.	 */	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket;	SET_SEQINTCODE(PDATA_REINIT)	jmp	data_phase_inbounds;p_data_bitbucket:	/*	 * Turn on `Bit Bucket' mode, wait until the target takes	 * us to another phase, and then notify the host.	 */	mov	SAVED_MODE, MODE_PTR;	test	MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))		jnz bitbucket_not_m_dff;	/*	 * Ensure that any FIFO contents are cleared out and the	 * FIFO free'd prior to starting the BITBUCKET.  BITBUCKET	 * doesn't discard data already in the FIFO.	 */	mvi	DFFSXFRCTL, RSTCHN|CLRSHCNT;	SET_MODE(M_SCSI, M_SCSI)bitbucket_not_m_dff:	or	SXFRCTL1,BITBUCKET;	/* Wait for non-data phase. */	test	SCSIPHASE, ~DATA_PHASE_MASK jz .;	and	SXFRCTL1, ~BITBUCKET;	RESTORE_MODE(SAVED_MODE)SET_SRC_MODE	M_DFF1;SET_DST_MODE	M_DFF1;	SET_SEQINTCODE(DATA_OVERRUN)	jmp	ITloop;data_phase_initialize:	test	SCB_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket;	call	load_first_seg;data_phase_inbounds:	/* We have seen a data phase at least once. */	or	SEQ_FLAGS, DPHASE;	mov	SAVED_MODE, MODE_PTR;	test	SG_STATE, LOADING_NEEDED jz data_group_dma_loop;	call	p_data_handle_xfer;data_group_dma_loop:	/*	 * The transfer is complete if either the last segment	 * completes or the target changes phase.  Both conditions	 * will clear SCSIEN.	 */	call	idle_loop_service_fifos;	call	idle_loop_cchan;	call	idle_loop_gsfifo;	RESTORE_MODE(SAVED_MODE)	test	DFCNTRL, SCSIEN jnz data_group_dma_loop;data_group_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.	 */	call	calc_residual;	/*	 * Go ahead and shut down the DMA engine now.	 */	test	DFCNTRL, DIRECTION jnz data_phase_finish;data_group_fifoflush:	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {		or	DFCNTRL, FIFOFLUSH;	}	/*	 * We have enabled the auto-ack feature.  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.  We know there is more data yet to transfer	 * if SG_LIST_NULL is not yet set, thus there cannot be	 * an overrun.	 */	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_finish;	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;	test	DFSTATUS, FIFOEMP jnz data_phase_finish;	/* Overrun */	jmp	p_data;data_phase_finish:	/*	 * If the target has left us in data phase, loop through	 * the dma code again.  We will only loop if there is a	 * data overrun.  	 */	if ((ahd->flags & AHD_TARGETROLE) != 0) {		test	SSTAT0, TARGET jnz data_phase_done;	}	if ((ahd->flags & AHD_INITIATORROLE) != 0) {		test	SSTAT1, REQINIT jz .;		test	SCSIPHASE, DATA_PHASE_MASK jnz p_data;	}data_phase_done:	/* Kill off any pending prefetch */	call	disable_ccsgen;	or 	LONGJMP_ADDR[1], INVALID_ADDR;	if ((ahd->flags & AHD_TARGETROLE) != 0) {		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;		/*		and	SEQ_FLAGS, ~DPHASE_PENDING;		 * For data-in phases, wait for any pending acks from the		 * initiator before changing phase.  We only need to		 * send Ignore Wide Residue messages for data-in phases.		test	DFCNTRL, DIRECTION jz target_ITloop;		test	SSTAT1, REQINIT	jnz .;		test	SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop;		SET_MODE(M_SCSI, M_SCSI)		test	NEGCONOPTS, WIDEXFER jz target_ITloop;		 */		/*		 * Issue an Ignore Wide Residue Message.		mvi	P_MESGIN|BSYO call change_phase;		mvi	MSG_IGN_WIDE_RESIDUE call target_outb;		mvi	1 call target_outb;		jmp	target_ITloop;		 */	} else {		jmp	ITloop;	}/* * 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. */residual_before_last_seg:	test    MDFFSTAT, SHVALID	jnz sgptr_fixup;	/*	 * Can never happen from an interrupt as the packetized	 * hardware will only interrupt us once SHVALID or	 * LAST_SEG_DONE.	 */	call	idle_loop_service_fifos;	RESTORE_MODE(SAVED_MODE)	/* FALLTHROUGH */calc_residual:	test	SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg;	/* Record if we've consumed all S/G entries */	test	MDFFSTAT, SHVALID	jz . + 2;	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;	or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;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_CACHE_PTR 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;	clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;export timer_isr:	call	issue_cmdcmplt;	mvi	CLRSEQINTSTAT, CLRSEQ_SWTMRTO;	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {		/*		 * In H2A4, the mode pointer is not saved		 * for intvec2, but is restored on iret.		 * This can lead to the restoration of a		 * bogus mode ptr.  Manually clear the		 * intmask bits and do a normal return		 * to compensate.		 */		and	SEQINTCTL, ~(INTMASK2|INTMASK1) ret;	} else {		or	SEQINTCTL, IRET ret;	}export seq_isr:	if ((ahd->features & AHD_RTI) == 0) {		/*		 * On RevA Silicon, if the target returns us to data-out		 * after we have already trained for data-out, it is		 * possible for us to transition the free running clock to		 * data-valid before the required 100ns P1 setup time (8 P1		 * assertions in fast-160 mode).  This will only happen if		 * this L-Q is a continuation of a data transfer for which		 * we have already prefetched data into our FIFO (LQ/Data		 * followed by LQ/Data for the same write transaction).		 * This can cause some target implementations to miss the		 * first few data transfers on the bus.  We detect this		 * situation by noticing that this is the first data transfer		 * after an LQ (LQIWORKONLQ true), that the data transfer is		 * a continuation of a transfer already setup in our FIFO		 * (SAVEPTRS interrupt), and that the transaction is a write		 * (DIRECTION set in DFCNTRL). The delay is performed by		 * disabling SCSIEN until we see the first REQ from the		 * target.		 * 		 * First instruction in an ISR cannot be a branch on

⌨️ 快捷键说明

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