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

📄 aic7xxx.seq

📁 基于组件方式开发操作系统的OSKIT源代码
💻 SEQ
📖 第 1 页 / 共 4 页
字号:
/* * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. * * Copyright (c) 1994-1999 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products *    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  * 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 * conflict with, or are expressly prohibited by, the GPL. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	$Id: aic7xxx.seq,v 1.84.2.4 1999/05/16 00:08:46 gibbs Exp $ */#include <dev/aic7xxx/aic7xxx.reg>#include <cam/scsi/scsi_message.h>/* * A few words on the waiting SCB list: * After starting the selection hardware, we check for reconnecting targets * as well as for our selection to complete just in case the reselection wins * bus arbitration.  The problem with this is that we must keep track of the * SCB that we've already pulled from the QINFIFO and started the selection * on just in case the reselection wins so that we can retry the selection at * a later time.  This problem cannot be resolved by holding a single entry * in scratch ram since a reconnecting target can request sense and this will * create yet another SCB waiting for selection.  The solution used here is to  * use byte 27 of the SCB as a psuedo-next pointer and to thread a list * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes,  * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to * this list everytime a request sense occurs or after completing a non-tagged * command for which a second SCB has been queued.  The sequencer will * automatically consume the entries. */reset:	clr	SCSISIGO;		/* De-assert BSY */	and	SXFRCTL1, ~BITBUCKET;	/* Always allow reselection */	and	SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;	if ((ahc->features & AHC_CMD_CHAN) != 0) {		/* Ensure that no DMA operations are in progress */		clr	CCSGCTL;		clr	CCSCBCTL;	}poll_for_work:	call	clear_target_state;	and	SXFRCTL0, ~SPIOEN;	if ((ahc->features & AHC_QUEUE_REGS) == 0) {		mov	A, QINPOS;	}poll_for_work_loop:	if ((ahc->features & AHC_QUEUE_REGS) == 0) {		and	SEQCTL, ~PAUSEDIS;	}	test	SSTAT0, SELDO|SELDI	jnz selection;	test	SCSISEQ, ENSELO	jnz poll_for_work;	if ((ahc->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? */	if ((ahc->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  * SCBs in the list of SCBs awaiting selection.  If we have * any SCBs available for use, pull the tag from the QINFIFO * and get to work on it. */	if ((ahc->flags & AHC_PAGESCBS) != 0) {		mov	ALLZEROS	call	get_free_or_disc_scb;	}dequeue_scb:	add	A, -1, QINPOS;	mvi	QINFIFO_OFFSET call fetch_byte;	if ((ahc->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;	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 ((ahc->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:	/*	 * Place us on the waiting list in case our selection	 * doesn't win during bus arbitration.	 */	mov	SCB_NEXT,WAITING_SCBH;	mov	WAITING_SCBH, SCBPTR;start_waiting:	/*	 * Pull the first entry off of the waiting SCB list.	 */	mov	SCBPTR, WAITING_SCBH;	call	start_selection;	jmp	poll_for_work;start_selection:	if ((ahc->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:	mov	SINDEX, SCSISEQ_TEMPLATE;	if ((ahc->flags & AHC_TARGETMODE) != 0) {		test	SCB_CONTROL, TARGET_SCB jz . + 4;		if ((ahc->features & AHC_ULTRA2) != 0) {			mov	SCSIID_ULTRA2, SCB_CMDPTR[2];		} else {			mov	SCSIID, SCB_CMDPTR[2];		}		or	SINDEX, TEMODE;		jmp	initialize_scsiid_fini;	}	if ((ahc->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;	}initialize_scsiid_fini:	mov	SCSISEQ, SINDEX ret;/* * Initialize transfer settings and clear the SCSI channel. * SINDEX should contain any additional bit's the client wants * set in SXFRCTL0.  We also assume that the current SCB is * a valid SCB for the target we wish to talk to. */initialize_channel:	or	SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;set_transfer_settings:	if ((ahc->features & AHC_ULTRA) != 0) {		test	SCB_CONTROL, ULTRAENB jz . + 2;		or	SXFRCTL0, FAST20;	} /* * Initialize SCSIRATE with the appropriate value for this target. */	if ((ahc->features & AHC_ULTRA2) != 0) {		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;	} else {		mov	SCSIRATE, SCB_SCSIRATE ret;	}selection:	test	SSTAT0,SELDO	jnz select_out;	mvi	CLRSINT0, CLRSELDI;select_in:	if ((ahc->flags & AHC_TARGETMODE) != 0) {		if ((ahc->flags & AHC_INITIATORMODE) != 0) {			test	SSTAT0, TARGET	jz initiator_reselect;		}		/*		 * We've just been selected.  Assert BSY and		 * setup the phase for receiving messages		 * from the target.		 */		mvi	SCSISIGO, P_MESGOUT|BSYO;		mvi	CLRSINT1, CLRBUSFREE;		/*		 * Setup the DMA for sending the identify and		 * command information.		 */		or	SEQ_FLAGS, CMDPHASE_PENDING;		mov     A, TQINPOS;		if ((ahc->features & AHC_CMD_CHAN) != 0) {			mvi	DINDEX, CCHADDR;			mvi	TMODE_CMDADDR call set_32byte_addr;			mvi	CCSCBCTL, CCSCBRESET;		} else {			mvi	DINDEX, HADDR;			mvi	TMODE_CMDADDR call set_32byte_addr;			mvi	DFCNTRL, FIFORESET;		}		/* Initiator that selected us */		and	SAVED_TCL, SELID_MASK, SELID;		if ((ahc->features & AHC_CMD_CHAN) != 0) {			mov	CCSCBRAM, SAVED_TCL;		} else {			mov	DFDAT, SAVED_TCL;		}		/* The Target ID we were selected at */		if ((ahc->features & AHC_CMD_CHAN) != 0) {			if ((ahc->features & AHC_MULTI_TID) != 0) {				and	CCSCBRAM, OID, TARGIDIN;			} else if ((ahc->features & AHC_ULTRA2) != 0) {				and	CCSCBRAM, OID, SCSIID_ULTRA2;			} else {				and	CCSCBRAM, OID, SCSIID;			}		} else {			if ((ahc->features & AHC_MULTI_TID) != 0) {				and	DFDAT, OID, TARGIDIN;			} else if ((ahc->features & AHC_ULTRA2) != 0) {				and	DFDAT, OID, SCSIID_ULTRA2;			} else {				and	DFDAT, OID, SCSIID;			}		}		/* No tag yet */		mvi	INITIATOR_TAG, SCB_LIST_NULL;		/*		 * If ATN isn't asserted, the target isn't interested		 * in talking to us.  Go directly to bus free.		 */		test	SCSISIGI, ATNI	jz	target_busfree;		/*		 * Watch ATN closely now as we pull in messages from the		 * initiator.  We follow the guidlines from section 6.5		 * of the SCSI-2 spec for what messages are allowed when.		 */		call	target_inb;		/*		 * Our first message must be one of IDENTIFY, ABORT, or		 * BUS_DEVICE_RESET.		 */		/* XXX May need to be more lax here for older initiators... */		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;		/* Store for host */		if ((ahc->features & AHC_CMD_CHAN) != 0) {			mov	CCSCBRAM, DINDEX;		} else {			mov	DFDAT, DINDEX;		}		/* Remember for disconnection decision */		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;		/* XXX Honor per target settings too */		or	SEQ_FLAGS, NO_DISCONNECT;		test	SCSISIGI, ATNI	jz	ident_messages_done;		call	target_inb;		/*		 * If this is a tagged request, the tagged message must		 * immediately follow the identify.  We test for a valid		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and		 * < MSG_IGN_WIDE_RESIDUE.		 */		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;		jnc	ident_messages_done;		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;		jc	ident_messages_done;		/* Store for host */		if ((ahc->features & AHC_CMD_CHAN) != 0) {			mov	CCSCBRAM, DINDEX;		} else {			mov	DFDAT, DINDEX;		}				/*		 * If the initiator doesn't feel like providing a tag number,		 * we've got a failed selection and must transition to bus		 * free.		 */		test	SCSISIGI, ATNI	jz	target_busfree;		/*		 * Store the tag for the host.		 */		call	target_inb;		if ((ahc->features & AHC_CMD_CHAN) != 0) {			mov	CCSCBRAM, DINDEX;		} else {			mov	DFDAT, DINDEX;		}		mov	INITIATOR_TAG, DINDEX;		jmp	ident_messages_done;		/*		 * Pushed message loop to allow the kernel to		 * run it's own target mode message state engine.		 */host_target_message_loop:		mvi	INTSTAT, HOST_MSG_LOOP;		nop;		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;		test	SSTAT0, SPIORDY jz .;		jmp	host_target_message_loop;ident_messages_done:		/* If ring buffer is full, return busy or queue full */		mov	A, KERNEL_TQINPOS;		cmp	TQINPOS, A jne tqinfifo_has_space;		mvi	P_STATUS|BSYO call change_phase;		cmp	INITIATOR_TAG, SCB_LIST_NULL je . + 3;		mvi	STATUS_QUEUE_FULL call target_outb;		jmp	target_busfree_wait;		mvi	STATUS_BUSY call target_outb;		jmp	target_busfree_wait;tqinfifo_has_space:			/* Terminate the ident list */		if ((ahc->features & AHC_CMD_CHAN) != 0) {			mvi	CCSCBRAM, SCB_LIST_NULL;		} else {			mvi	DFDAT, SCB_LIST_NULL;		}		or	SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;		test	SCSISIGI, ATNI	jnz target_mesgout_pending_msg;		jmp	target_ITloop;		/* * We carefully toggle SPIOEN to allow us to return the  * message byte we receive so it can be checked prior to * driving REQ on the bus for the next byte. */target_inb:		/*		 * Drive REQ on the bus by enabling SCSI PIO.		 */		or	SXFRCTL0, SPIOEN;		/* Wait for the byte */		test	SSTAT0, SPIORDY jz .;		/* Prevent our read from triggering another REQ */		and	SXFRCTL0, ~SPIOEN;		/* Save latched contents */		mov	DINDEX, SCSIDATL ret;	}if ((ahc->flags & AHC_INITIATORMODE) != 0) {/* * 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. */initiator_reselect:	/* XXX test for and handle ONE BIT condition */	and	SAVED_TCL, SELID_MASK, SELID;	if ((ahc->features & AHC_TWIN) != 0) {		test	SBLKCTL, SELBUSB	jz . + 2;		or	SAVED_TCL, SELBUSB;	}	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;	mvi	CLRSINT1,CLRBUSFREE;	or	SIMODE1, ENBUSFREE;		/*						 * We aren't expecting a						 * bus free, so interrupt						 * the kernel driver if it						 * happens.						 */	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */	jmp	ITloop;}/* * After the selection, remove this SCB from the "waiting SCB" * list.  This is achieved by simply moving our "next" pointer into * WAITING_SCBH.  Our next pointer will be set to null the next time this * SCB is used, so don't bother with it now. */select_out:	/* Turn off the selection hardware */	and	SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ_TEMPLATE;	mvi	CLRSINT0, CLRSELDO;	mov	SCBPTR, WAITING_SCBH;	mov	WAITING_SCBH,SCB_NEXT;	mov	SAVED_TCL, SCB_TCL;	if ((ahc->flags & AHC_TARGETMODE) != 0) {		test	SSTAT0, TARGET	jz initiator_select;		/*		 * We've just re-selected an initiator.		 * Assert BSY and setup the phase for		 * sending our identify messages.		 */		mvi	P_MESGIN|BSYO call change_phase;		mvi	CLRSINT1,CLRBUSFREE;		/*		 * Start out with a simple identify message.		 */		and	A, LID, SCB_TCL;		or	A, MSG_IDENTIFYFLAG call target_outb;

⌨️ 快捷键说明

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