📄 aic79xx.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/aic79xx.seq#42 $"PATCH_ARG_LIST = "struct ahd_softc *ahd"#include "aic79xx.reg"#include "scsi_message.h"idle_loop: SET_MODE(M_SCSI, M_SCSI); test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus; test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus; cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus; /* * ENSELO is cleared by a SELDO, so we must test for SELDO * one last time. */BEGIN_CRITICAL; test SSTAT0, SELDO jnz select_out;END_CRITICAL; call start_selection;idle_loop_checkbus:BEGIN_CRITICAL; test SSTAT0, SELDO jnz select_out;END_CRITICAL; test SSTAT0, SELDI jnz select_in; test SCSIPHASE, ~DATA_PHASE_MASK jz idle_loop_check_nonpackreq; test SCSISIGO, ATNO jz idle_loop_check_nonpackreq; call unexpected_nonpkt_phase_find_ctxt;idle_loop_check_nonpackreq: test SSTAT2, NONPACKREQ jz idle_loop_scsi; call unexpected_nonpkt_phase_find_ctxt;idle_loop_scsi:BEGIN_CRITICAL; test LQISTAT2, LQIGSAVAIL jz idle_loop_service_fifos; /* * We have received good status for this transaction. There may * still be data in our FIFOs draining to the host. Setup * monitoring of the draining process or complete the SCB. */good_status_IU_done: bmov SCBPTR, GSFIFO, 2; clr SCB_SCSI_STATUS; or SCB_CONTROL, STATUS_RCVD; /* * Since this status did not consume a FIFO, we have to * be a bit more dilligent in how we check for FIFOs pertaining * to this transaction. There are three states that a FIFO still * transferring data may be in. * * 1) Configured and draining to the host, with a pending CLRCHN. * 2) Configured and draining to the host, no pending CLRCHN. * 3) Pending cfg4data, fifo not empty. * * For case 1, we assume that our DMA post of the completed command * will occur after the FIFO finishes draining due to the higher * priority of data FIFO transfers relative to command channel * transfers. * * Case 2 can be detected by noticing that a longjmp is active for the * FIFO and LONGJMP_SCB matches our SCB. In this case, we allow * the routine servicing the FIFO to complete the SCB. * * Case 3 implies either a pending or yet to occur save data * pointers for this same context in the other FIFO. So, if * we detect case 2, we will properly defer the post of the SCB * and achieve the desired result. The pending cfg4data will * notice that status has been received and complete the SCB. */ test SCB_SGPTR, SG_LIST_NULL jz good_status_check_fifos; /* * All segments have been loaded (or no data transfer), so * it is safe to complete the command. Since this was a * cheap command to check for completion, loop to see if * more entries can be removed from the GSFIFO. */ call complete;END_CRITICAL; jmp idle_loop_scsi;BEGIN_CRITICAL;good_status_check_fifos: clc; bmov ARG_1, SCBPTR, 2; SET_MODE(M_DFF0, M_DFF0); call check_fifo; jc idle_loop_service_fifos; SET_MODE(M_DFF1, M_DFF1); call check_fifo; jc idle_loop_service_fifos; SET_MODE(M_SCSI, M_SCSI); call queue_scb_completion;END_CRITICAL;idle_loop_service_fifos: SET_MODE(M_DFF0, M_DFF0); test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo; call longjmp;idle_loop_next_fifo: SET_MODE(M_DFF1, M_DFF1); test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_last_fifo_done; call longjmp;idle_loop_last_fifo_done: call idle_loop_cchan; jmp idle_loop;idle_loop_cchan: SET_MODE(M_CCHAN, M_CCHAN); test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle; test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog; test CCSCBCTL, CCSCBDONE jz return; /* FALLTHROUGH */scbdma_tohost_done: test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; /* * A complete SCB upload requires no intervention. * The SCB is already on the COMPLETE_SCB list * and its completion notification will now be * handled just like any other SCB. */ and CCSCBCTL, ~(CCARREN|CCSCBEN) ret;fill_qoutfifo_dmadone: and CCSCBCTL, ~(CCARREN|CCSCBEN); mvi INTSTAT, CMDCMPLT; mvi COMPLETE_SCB_DMAINPROG_HEAD[1], SCB_LIST_NULL; bmov QOUTFIFO_NEXT_ADDR, SCBHADDR, 4; test QOFF_CTLSTA, SDSCB_ROLLOVR jz return; bmov QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4 ret;fetch_new_scb_inprog: test CCSCBCTL, ARRDONE jz return;fetch_new_scb_done: and CCSCBCTL, ~(CCARREN|CCSCBEN); bmov REG0, SCBPTR, 2; /* Update the next SCB address to download. */ bmov NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4; mvi SCB_NEXT[1], SCB_LIST_NULL; mvi SCB_NEXT2[1], SCB_LIST_NULL; /* * SCBs that want to send messages are always * queued independently. This ensures that they * are at the head of the SCB list to select out * to a target and we will see the MK_MESSAGE flag. */ test SCB_CONTROL, MK_MESSAGE jnz first_new_target_scb; shr SINDEX, 3, SCB_SCSIID; and SINDEX, ~0x1; mvi SINDEX[1], (WAITING_SCB_TAILS >> 8); bmov DINDEX, SINDEX, 2; bmov SCBPTR, SINDIR, 2; bmov DINDIR, REG0, 2; cmp SCBPTR[1], SCB_LIST_NULL je first_new_target_scb; bmov SCB_NEXT, REG0, 2;fetch_new_scb_fini: /* Increment our position in the QINFIFO. */ mov NONE, SNSCB_QOFF ret;first_new_target_scb: cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb; bmov SCBPTR, WAITING_TID_TAIL, 2; bmov SCB_NEXT2, REG0, 2; bmov WAITING_TID_TAIL, REG0, 2; /* Increment our position in the QINFIFO. */ mov NONE, SNSCB_QOFF ret;first_new_scb: bmov WAITING_TID_HEAD, REG0, 2; bmov WAITING_TID_TAIL, REG0, 2; /* Increment our position in the QINFIFO. */ mov NONE, SNSCB_QOFF ret;scbdma_idle: /* * Give precedence to downloading new SCBs to execute * unless select-outs are currently frozen. * XXX Use a timer to prevent completion starvation. */ test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz . + 2;BEGIN_CRITICAL; test QOFF_CTLSTA, NEW_SCB_AVAIL jnz fetch_new_scb; cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne dma_complete_scb; cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL je return; /* FALLTHROUGH */fill_qoutfifo: /* * Keep track of the SCBs we are dmaing just * in case the DMA fails or is aborted. */ bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2; mvi CCSCBCTL, CCSCBRESET; bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4; bmov CCSCBRAM, COMPLETE_SCB_HEAD, 2; bmov SCBPTR, COMPLETE_SCB_HEAD, 2; jmp fill_qoutfifo_first_entry;fill_qoutfifo_loop: bmov CCSCBRAM, SCB_NEXT_COMPLETE, 2; bmov SCBPTR, SCB_NEXT_COMPLETE, 2;fill_qoutfifo_first_entry: mov NONE, SDSCB_QOFF; cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; cmp CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done; test QOFF_CTLSTA, SDSCB_ROLLOVR jz fill_qoutfifo_loop;fill_qoutfifo_done: mov SCBHCNT, CCSCBADDR; mvi CCSCBCTL, CCSCBEN|CCSCBRESET; bmov COMPLETE_SCB_HEAD, SCB_NEXT_COMPLETE, 2; mvi SCB_NEXT_COMPLETE[1], SCB_LIST_NULL ret;fetch_new_scb: bmov SCBHADDR, NEXT_QUEUED_SCB_ADDR, 4; mvi CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET jmp dma_scb;dma_complete_scb: bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2; bmov SCBHADDR, SCB_BUSADDR, 4; mvi CCARREN|CCSCBEN|CCSCBRESET call dma_scb; /* * Now that we've started the DMA, push us onto * the normal completion queue to have our SCBID * posted to the kernel. */ bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret;END_CRITICAL;/* * Either post or fetch an SCB from host memory. The caller * is responsible for polling for transfer completion. * * Prerequisits: Mode == M_CCHAN * SINDEX contains CCSCBCTL flags * SCBHADDR set to Host SCB address * SCBPTR set to SCB src location on "push" operations */SET_SRC_MODE M_CCHAN;SET_DST_MODE M_CCHAN;dma_scb: mvi SCBHCNT, SCB_TRANSFER_SIZE; mov CCSCBCTL, SINDEX; or SEQ_FLAGS2, SCB_DMA ret;BEGIN_CRITICAL;setjmp_setscb: bmov LONGJMP_SCB, SCBPTR, 2;setjmp: bmov LONGJMP_ADDR, STACK, 2 ret;setjmp_inline: bmov LONGJMP_ADDR, STACK, 2;longjmp: bmov STACK, LONGJMP_ADDR, 2 ret;END_CRITICAL;/************************ Packetized LongJmp Routines *************************//* * Must disable interrupts when setting the mode pointer * register as an interrupt occurring mid update will * fail to store the new mode value for restoration on * an iret. */set_mode_work_around: mvi SEQINTCTL, INTVEC1DSL; mov MODE_PTR, SINDEX; clr SEQINTCTL ret;SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;start_selection:BEGIN_CRITICAL; if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { /* * Razor #494 * Rev A hardware fails to update LAST/CURR/NEXTSCB * correctly after a packetized selection in several * situations: * * 1) If only one command existed in the the queue, the * LAST/CURR/NEXTSCB are unchanged. * * 2) In a non QAS, protocol allowed phase change, * the queue is shifted 1 too far. LASTSCB is * the last SCB that was correctly processed. * * 3) In the QAS case, if the full list of commands * was successfully sent, NEXTSCB is NULL and neither * CURRSCB nor LASTSCB can be trusted. We must * manually walk the list counting MAXCMDCNT elements * to find the last SCB that was sent correctly. * * To simplify the workaround for this bug in SELDO * handling, we initialize LASTSCB prior to enabling * selection so we can rely on it even for case #1 above. */ bmov LASTSCB, WAITING_TID_HEAD, 2; } bmov CURRSCB, WAITING_TID_HEAD, 2; bmov SCBPTR, WAITING_TID_HEAD, 2; shr SELOID, 4, SCB_SCSIID; /* * If we want to send a message to the device, ensure * we are selecting with atn irregardless of our packetized * agreement. Since SPI4 only allows target reset or PPR * messages if this is a packetized connection, the change * to our negotiation table entry for this selection will * be cleared when the message is acted on. */ test SCB_CONTROL, MK_MESSAGE jz . + 3; mov NEGOADDR, SELOID; or NEGCONOPTS, ENAUTOATNO; or SCSISEQ0, ENSELO ret;END_CRITICAL;/* * Allocate a FIFO for a non-packetized transaction. * For some reason unkown to me, both FIFOs must be free before we * can allocate a FIFO for a non-packetized transaction. This * may be fixed in Rev B. */allocate_fifo_loop: /* * Do whatever work is required to free a FIFO. */ SET_MODE(M_DFF0, M_DFF0); test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2; call longjmp; SET_MODE(M_DFF1, M_DFF1); test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2; call longjmp; SET_MODE(M_SCSI, M_SCSI);allocate_fifo: and A, FIFO0FREE|FIFO1FREE, DFFSTAT; cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop;take_fifo: bmov ARG_1, SCBPTR, 2; or DFFSTAT, CURRFIFO; SET_MODE(M_DFF1, M_DFF1); bmov SCBPTR, ARG_1, 2 ret;/* * We have been reselected as an initiator * or selected as a target. */SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;select_in: or SXFRCTL0, SPIOEN; and SAVED_SCSIID, SELID_MASK, SELID; and A, OID, IOWNID; or SAVED_SCSIID, A; mvi CLRSINT0, CLRSELDI; jmp ITloop;/* * We have successfully selected out. * * Clear SELDO. * Dequeue all SCBs sent from the waiting queue * Requeue all SCBs *not* sent to the tail of the waiting queue * Take Razor #494 into account for above. * * In Packetized Mode: * Return to the idle loop. Our interrupt handler will take * care of any incoming L_Qs. * * In Non-Packetize Mode: * Continue to our normal state machine. */SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;select_out:BEGIN_CRITICAL; /* Clear out all SCBs that have been successfully sent. */ if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { /* * For packetized, the LQO manager clears ENSELO on * the assertion of SELDO. If we are non-packetized, * LASTSCB and CURRSCB are acuate. */ test SCSISEQ0, ENSELO jnz use_lastscb; /* * The update is correct for LQOSTAT1 errors. All * but LQOBUSFREE are handled by kernel interrupts. * If we see LQOBUSFREE, return to the idle loop. * Once we are out of the select_out critical section, * the kernel will cleanup the LQOBUSFREE and we will * eventually restart the selection if appropriate. */ test LQOSTAT1, LQOBUSFREE jnz idle_loop; /* * On a phase change oustside of packet boundaries, * LASTSCB points to the currently active SCB context * on the bus. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -