📄 aic79xx.seq
字号:
/* * Adaptec U320 device driver firmware for Linux and FreeBSD. * * Copyright (c) 1994-2001 Justin T. Gibbs. * Copyright (c) 2000-2002 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#99 $"PATCH_ARG_LIST = "struct ahd_softc *ahd"PREFIX = "ahd_"#include "aic79xx.reg"#include "scsi_message.h"restart:if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { test SEQINTCODE, 0xFF jz idle_loop; SET_SEQINTCODE(NO_SEQINT)}idle_loop: if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { /* * Convert ERROR status into a sequencer * interrupt to handle the case of an * interrupt collision on the hardware * setting of HWERR. */ test ERROR, 0xFF jz no_error_set; SET_SEQINTCODE(SAW_HWERR)no_error_set: } 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 . + 2; call unexpected_nonpkt_phase_find_ctxt; if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { and A, FIFO0FREE|FIFO1FREE, DFFSTAT; cmp A, FIFO0FREE|FIFO1FREE jne . + 3; and SBLKCTL, ~DIAGLEDEN|DIAGLEDON; jmp . + 2; or SBLKCTL, DIAGLEDEN|DIAGLEDON; } call idle_loop_gsfifo_in_scsi_mode; call idle_loop_service_fifos; call idle_loop_cchan; jmp idle_loop;BEGIN_CRITICAL;idle_loop_gsfifo: SET_MODE(M_SCSI, M_SCSI)idle_loop_gsfifo_in_scsi_mode: test LQISTAT2, LQIGSAVAIL jz return; /* * We have received good status for this transaction. There may * still be data in our FIFOs draining to the host. Complete * the SCB only if all data has transferred to the host. */good_status_IU_done: bmov SCBPTR, GSFIFO, 2; clr SCB_SCSI_STATUS; /* * If a command completed before an attempted task management * function completed, notify the host after disabling any * pending select-outs. */ test SCB_TASK_MANAGEMENT, 0xFF jz gsfifo_complete_normally; test SSTAT0, SELDO|SELINGO jnz . + 2; and SCSISEQ0, ~ENSELO; SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY)gsfifo_complete_normally: 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 two states that a FIFO still * transferring data may be in. * * 1) Configured and draining to the host, with a FIFO handler. * 2) Pending cfg4data, fifo not empty. * * Case 1 can be detected by noticing a non-zero FIFO active * count in the SCB. In this case, we allow the routine servicing * the FIFO to complete the SCB. * * Case 2 implies either a pending or yet to occur save data * pointers for this same context in the other FIFO. So, if * we detect case 1, 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_FIFO_USE_COUNT, 0xFF jnz idle_loop_gsfifo_in_scsi_mode; call complete;END_CRITICAL; jmp idle_loop_gsfifo_in_scsi_mode;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 jz longjmp;return: ret;idle_loop_cchan: SET_MODE(M_CCHAN, M_CCHAN) test QOFF_CTLSTA, HS_MAILBOX_ACT jz hs_mailbox_empty; or QOFF_CTLSTA, HS_MAILBOX_ACT; mov LOCAL_HS_MAILBOX, HS_MAILBOX;hs_mailbox_empty:BEGIN_CRITICAL; test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle; test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog; test CCSCBCTL, CCSCBDONE jz return;END_CRITICAL; /* FALLTHROUGH */scbdma_tohost_done: test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; /* * An SCB has been succesfully uploaded to the host. * If the SCB was uploaded for some reason other than * bad SCSI status (currently only for underruns), we * queue the SCB for normal completion. Otherwise, we * wait until any select-out activity has halted, and * then notify the host so that the transaction can be * dealt with. */ test SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host; and CCSCBCTL, ~(CCARREN|CCSCBEN); bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret;scbdma_notify_host: SET_MODE(M_SCSI, M_SCSI) test SCSISEQ0, ENSELO jnz return; test SSTAT0, (SELDO|SELINGO) jnz return; SET_MODE(M_CCHAN, M_CCHAN) /* * Remove SCB and notify host. */ and CCSCBCTL, ~(CCARREN|CCSCBEN); bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; SET_SEQINTCODE(BAD_SCB_STATUS) ret;fill_qoutfifo_dmadone: and CCSCBCTL, ~(CCARREN|CCSCBEN); call qoutfifo_updated; 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; xor QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret;qoutfifo_updated: /* * If there are more commands waiting to be dma'ed * to the host, always coalesce. Otherwise honor the * host's wishes. */ cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; test LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt; /* * If we have relatively few commands outstanding, don't * bother waiting for another command to complete. */ test CMDS_PENDING[1], 0xFF jnz coalesce_by_count; /* Add -1 so that jnc means <= not just < */ add A, -1, INT_COALESCING_MINCMDS; add NONE, A, CMDS_PENDING; jnc issue_cmdcmplt; /* * If coalescing, only coalesce up to the limit * provided by the host driver. */coalesce_by_count: mov A, INT_COALESCING_MAXCMDS; add NONE, A, INT_COALESCING_CMDCOUNT; jc issue_cmdcmplt; /* * If the timer is not currently active, * fire it up. */ test INTCTL, SWTMINTMASK jz return; bmov SWTIMER, INT_COALESCING_TIMER, 2; mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; or INTCTL, SWTMINTEN|SWTIMER_START; and INTCTL, ~SWTMINTMASK ret;issue_cmdcmplt: mvi INTSTAT, CMDCMPLT; clr INT_COALESCING_CMDCOUNT; or INTCTL, SWTMINTMASK ret;BEGIN_CRITICAL;fetch_new_scb_inprog: test CCSCBCTL, ARRDONE jz return;fetch_new_scb_done: and CCSCBCTL, ~(CCARREN|CCSCBEN); bmov REG0, SCBPTR, 2; clr A; add CMDS_PENDING, 1; adc CMDS_PENDING[1], A; if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { /* * "Short Luns" are not placed into outgoing LQ * packets in the correct byte order. Use a full * sized lun field instead and fill it with the * one byte of lun information we support. */ mov SCB_PKT_LUN[6], SCB_LUN; } /* * The FIFO use count field is shared with the * tag set by the host so that our SCB dma engine * knows the correct location to store the SCB. * Set it to zero before processing the SCB. */ clr SCB_FIFO_USE_COUNT; /* 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; /* Increment our position in the QINFIFO. */ mov NONE, SNSCB_QOFF; /* * 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 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 ret;first_new_scb: bmov WAITING_TID_HEAD, REG0, 2; bmov WAITING_TID_TAIL, REG0, 2 ret;END_CRITICAL;scbdma_idle: /* * Give precedence to downloading new SCBs to execute * unless select-outs are currently frozen. */ 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. */ mov A, QOUTFIFO_ENTRY_VALID_TAG; bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2; mvi CCSCBCTL, CCSCBRESET; bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4; bmov SCBPTR, COMPLETE_SCB_HEAD, 2;fill_qoutfifo_loop: mov CCSCBRAM, SCBPTR; or CCSCBRAM, A, SCBPTR[1]; mov NONE, SDSCB_QOFF; inc INT_COALESCING_CMDCOUNT; add CMDS_PENDING, -1; adc CMDS_PENDING[1], -1; 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 jnz fill_qoutfifo_done; bmov SCBPTR, SCB_NEXT_COMPLETE, 2; jmp 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 jmp dma_scb;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 ret;BEGIN_CRITICAL;setjmp: bmov LONGJMP_ADDR, STACK, 2 ret;setjmp_inline: bmov LONGJMP_ADDR, STACK, 2;longjmp: bmov STACK, LONGJMP_ADDR, 2 ret;END_CRITICAL;/*************************** Chip Bug Work Arounds ****************************//* * 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. */if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {set_mode_work_around: mvi SEQINTCTL, INTVEC1DSL; mov MODE_PTR, SINDEX; clr SEQINTCTL ret;toggle_dff_mode_work_around: mvi SEQINTCTL, INTVEC1DSL; xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); clr SEQINTCTL ret;}if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {set_seqint_work_around: mov SEQINTCODE, SINDEX; mvi SEQINTCODE, NO_SEQINT ret;}/************************ Packetized LongJmp Routines *************************/SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;start_selection:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -