📄 aic7xxx.seq
字号:
/* * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. * * Copyright (c) 1994-2001 Justin T. Gibbs. * Copyright (c) 2000-2001 Adaptec Inc. * 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. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * * $FreeBSD$ */VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $"PATCH_ARG_LIST = "struct ahc_softc *ahc"PREFIX = "ahc_"#include "aic7xxx.reg"#include "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. */bus_free_sel: /* * Turn off the selection hardware. We need to reset the * selection request in order to perform a new selection. */ and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP; and SIMODE1, ~ENBUSFREE;poll_for_work: call clear_target_state; and SXFRCTL0, ~SPIOEN; if ((ahc->features & AHC_ULTRA2) != 0) { clr SCSIBUSL; } test SCSISEQ, ENSELO jnz poll_for_selection; if ((ahc->features & AHC_TWIN) != 0) { xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ test SCSISEQ, ENSELO jnz poll_for_selection; } cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;poll_for_work_loop: if ((ahc->features & AHC_TWIN) != 0) { xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ } test SSTAT0, SELDO|SELDI jnz selection;test_queue: /* Has the driver posted any work for us? */BEGIN_CRITICAL; if ((ahc->features & AHC_QUEUE_REGS) != 0) { test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; } else { mov A, QINPOS; cmp KERNEL_QINPOS, A je poll_for_work_loop; } mov ARG_1, NEXT_QUEUED_SCB; /* * We have at least one queued SCB now and we don't have any * SCBs in the list of SCBs awaiting selection. Allocate a * card SCB for the host's SCB and get to work on it. */ if ((ahc->flags & AHC_PAGESCBS) != 0) { mov ALLZEROS call get_free_or_disc_scb; } else { /* In the non-paging case, the SCBID == hardware SCB index */ mov SCBPTR, ARG_1; } or SEQ_FLAGS2, SCB_DMA;END_CRITICAL;dma_queued_scb: /* * DMA the SCB from host ram into the current SCB location. */ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov ARG_1 call dma_scb; /* * Check one last time to see if this SCB was canceled * before we completed the DMA operation. If it was, * the QINFIFO next pointer will not match our saved * value. */ mov A, ARG_1;BEGIN_CRITICAL; cmp NEXT_QUEUED_SCB, A jne abort_qinscb; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { cmp SCB_TAG, A je . + 2; mvi SCB_MISMATCH call set_seqint; } mov NEXT_QUEUED_SCB, SCB_NEXT; mov SCB_NEXT,WAITING_SCBH; mov WAITING_SCBH, SCBPTR; if ((ahc->features & AHC_QUEUE_REGS) != 0) { mov NONE, SNSCB_QOFF; } else { inc QINPOS; } and SEQ_FLAGS2, ~SCB_DMA;END_CRITICAL;start_waiting: /* * Start the first entry on the waiting SCB list. */ mov SCBPTR, WAITING_SCBH; call start_selection;poll_for_selection: /* * Twin channel devices cannot handle things like SELTO * interrupts on the "background" channel. So, while * selecting, keep polling the current channel until * either a selection or reselection occurs. */ test SSTAT0, SELDO|SELDI jz poll_for_selection;selection: /* * We aren't expecting a bus free, so interrupt * the kernel driver if it happens. */ mvi CLRSINT1,CLRBUSFREE; if ((ahc->features & AHC_DT) == 0) { or SIMODE1, ENBUSFREE; } /* * Guard against a bus free after (re)selection * but prior to enabling the busfree interrupt. SELDI * and SELDO will be cleared in that case. */ test SSTAT0, SELDI|SELDO jz bus_free_sel; test SSTAT0,SELDO jnz select_out;select_in: if ((ahc->flags & AHC_TARGETROLE) != 0) { if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT0, TARGET jz initiator_reselect; } mvi CLRSINT0, CLRSELDI; /* * We've just been selected. Assert BSY and * setup the phase for receiving messages * from the target. */ mvi SCSISIGO, P_MESGOUT|BSYO; /* * Setup the DMA for sending the identify and * command information. */ mvi SEQ_FLAGS, CMDPHASE_PENDING; mov A, TQINPOS; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; mvi SHARED_DATA_ADDR call set_32byte_addr; mvi CCSCBCTL, CCSCBRESET; } else { mvi DINDEX, HADDR; mvi SHARED_DATA_ADDR call set_32byte_addr; mvi DFCNTRL, FIFORESET; } /* Initiator that selected us */ and SAVED_SCSIID, SELID_MASK, SELID; /* The Target ID we were selected at */ if ((ahc->features & AHC_MULTI_TID) != 0) { and A, OID, TARGIDIN; } else if ((ahc->features & AHC_ULTRA2) != 0) { and A, OID, SCSIID_ULTRA2; } else { and A, OID, SCSIID; } or SAVED_SCSIID, A; if ((ahc->features & AHC_TWIN) != 0) { test SBLKCTL, SELBUSB jz . + 2; or SAVED_SCSIID, TWIN_CHNLB; } if ((ahc->features & AHC_CMD_CHAN) != 0) { mov CCSCBRAM, SAVED_SCSIID; } else { mov DFDAT, SAVED_SCSIID; } /* * If ATN isn't asserted, the target isn't interested * in talking to us. Go directly to bus free. * XXX SCSI-1 may require us to assume lun 0 if * ATN is false. */ 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. */ 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; } and SAVED_LUN, MSG_IDENTIFY_LUNMASK, 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_msg_pending; add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; jc ident_messages_done_msg_pending; /* 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; or SEQ_FLAGS, TARGET_CMD_IS_TAGGED;ident_messages_done: /* 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; test SEQ_FLAGS2, TARGET_MSG_PENDING jnz target_mesgout_pending; test SCSISIGI, ATNI jnz target_mesgout_continue; jmp target_ITloop;ident_messages_done_msg_pending: or SEQ_FLAGS2, TARGET_MSG_PENDING; 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 HOST_MSG_LOOP call set_seqint; cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; test SSTAT0, SPIORDY jz .; jmp host_target_message_loop; }if ((ahc->flags & AHC_INITIATORROLE) != 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 */ or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; and SAVED_SCSIID, SELID_MASK, SELID; if ((ahc->features & AHC_ULTRA2) != 0) { and A, OID, SCSIID_ULTRA2; } else { and A, OID, SCSIID; } or SAVED_SCSIID, A; if ((ahc->features & AHC_TWIN) != 0) { test SBLKCTL, SELBUSB jz . + 2; or SAVED_SCSIID, TWIN_CHNLB; } mvi CLRSINT0, CLRSELDI; jmp ITloop;}abort_qinscb: call add_scb_to_free_list; jmp poll_for_work_loop;start_selection: /* * If bus reset interrupts have been disabled (from a previous * reset), re-enable them now. Resets are only of interest * when we have outstanding transactions, so we can safely * defer re-enabling the interrupt until, as an initiator, * we start sending out transactions again. */ test SIMODE1, ENSCSIRST jnz . + 3; mvi CLRSINT1, CLRSCSIRSTI; or SIMODE1, ENSCSIRST; if ((ahc->features & AHC_TWIN) != 0) { and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ test SCB_SCSIID, TWIN_CHNLB jz . + 2; or SINDEX, SELBUSB; mov SBLKCTL,SINDEX; /* select channel */ }initialize_scsiid: if ((ahc->features & AHC_ULTRA2) != 0) { mov SCSIID_ULTRA2, SCB_SCSIID; } else if ((ahc->features & AHC_TWIN) != 0) { and SCSIID, TWIN_TID|OID, SCB_SCSIID; } else { mov SCSIID, SCB_SCSIID; } if ((ahc->flags & AHC_TARGETROLE) != 0) { mov SINDEX, SCSISEQ_TEMPLATE; test SCB_CONTROL, TARGET_SCB jz . + 2; or SINDEX, TEMODE; mov SCSISEQ, SINDEX ret; } else { mov SCSISEQ, SCSISEQ_TEMPLATE ret; }/* * Initialize transfer settings with SCB provided settings. */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; }if ((ahc->flags & AHC_TARGETROLE) != 0) {/* * 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;}/* * 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, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; mov SCBPTR, WAITING_SCBH; mov WAITING_SCBH,SCB_NEXT; mov SAVED_SCSIID, SCB_SCSIID; and SAVED_LUN, LID, SCB_LUN; call set_transfer_settings; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz initiator_select;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -