📄 sym895lib.c
字号:
/* * For events where the bus is not connected to a target, * set connected=FALSE. * For events where the Thread is disconnected / completed * set isThreadRunning = FALSE else set it to TRUE * For events not requiring scsi manager, set notify = FALSE. */ /* The following are the events generated by the Scripts */ case SYM895_CMD_COMPLETE : case SYM895_DISCONNECTED : connected = FALSE; break; case SYM895_MESSAGE_OUT_SENT : case SYM895_MESSAGE_IN_RECVD : case SYM895_EXT_MESSAGE_SIZE : case SYM895_NO_MSG_OUT : case SYM895_SCRIPT_ABORTED : connected = TRUE; break; case SYM895_PHASE_MISMATCH : event.remCount = sym895RemainderGet (pSiop, pThread->busPhase); connected = TRUE; break; /* * Folowing result from asynchronous conditions. Not directly from * SCRIPTS */ case SYM895_READY : connected = FALSE; notify = FALSE; break; case SYM895_SELECTED : case SYM895_RESELECTED : pScsiEvent->busId = (pThread->targetId) & SYM895_SSID_ENC_MASK; pScsiEvent->nBytesIdent = (pThread->nHostFlags & SYM895_FLAGS_IDENTIFY) ? 1 : 0; connected = TRUE; break; case SYM895_SCSI_BUS_RESET : connected = FALSE; break; case SYM895_BUSMODE_CHANGED : /* Don't run the scripts until, Bus Mode is set properly */ connected = TRUE; /* * Wait for 100 ms before deciding that SCSI bus mode has * really changed.It would have been ideal had it been implemented * in Hardware.The GEN timer in STIME1 is used for 100ms. */ /* First, reset the timer */ stime1 = SYM895_REG8_READ (pSiop, SYM895_OFF_STIME1); stime1 &= ~SYM895_STIME1_GEN_MASK; SYM895_REG8_WRITE (pSiop,SYM895_OFF_STIME1, stime1); /* Now, set the timer for 100 MS */ stime1 |= SYM895_GEN_128MS; SYM895_REG8_WRITE (pSiop,SYM895_OFF_STIME1, stime1); /* Now wait for the Timer interrupt */ /* * If another Bus mode change interrupt occurs before * the timer expires, re-initialize the timer . */ notify = FALSE; break; case SYM895_GEN_TIMER_EXPIRED : /* Change the Bus mode. */ tempBusMode = (SYM895_REG8_READ (pSiop, SYM895_OFF_STEST4) & SYM895_STEST4_SMODE_MASK)>>SYM895_BUSMODE_SHIFT; if (tempBusMode == SYM895_BUSMODE_HVD) SYM895_REG8_WRITE (pSiop, SYM895_OFF_STEST2, SYM895_REG8_READ (pSiop, SYM895_OFF_STEST2) | SYM895_STEST2_DIF); else if( curBusMode == SYM895_BUSMODE_HVD) SYM895_REG8_WRITE (pSiop, SYM895_OFF_STEST2, SYM895_REG8_READ (pSiop, SYM895_OFF_STEST2) & ~SYM895_STEST2_DIF); curBusMode = tempBusMode; /* Please refer to page 2-16, 2-17 of data manual */ SYM895_REG8_WRITE( pSiop, SYM895_OFF_STEST0, SYM895_REG8_READ (pSiop, SYM895_OFF_STEST0) | (tempBusMode << SYM895_BUSMODE_SHIFT)); /* Now the Bus Mode is set properly.*/ /* reset the timer */ stime1 = SYM895_REG8_READ (pSiop, SYM895_OFF_STIME1); stime1 &= ~SYM895_STIME1_GEN_MASK; SYM895_REG8_WRITE (pSiop,SYM895_OFF_STIME1, stime1); /* * If curBusMode is Single-ended check for the register bits * for Quadrupler, Ultra Enable . As these features are valid * for LVD and HVD, these should be disabled for Single-Ended * devices. Also, lower down the asynchronous * transfer rate. */ if (curBusMode == SYM895_BUSMODE_SE) { if ((SYM895_REG8_READ (pSiop, SYM895_OFF_STEST1) & SYM895_STEST1_QEN)) { /* Disable Clock Quadrupler */ SYM895_REG8_WRITE (pSiop, SYM895_OFF_STEST1, SYM895_REG8_READ (pSiop, SYM895_OFF_STEST1) & (~(SYM895_STEST1_QEN | SYM895_STEST1_QSEL))); } /* * Ultra SCSI transfer rates are not possible with * single-ended devices. So lower the async. clock * conversion factor by hard coding to 40Mhz. */ pSiop->clkPeriod = SYM895_40MHZ; pSiop->clkDiv = SYM895_3750MHZ_ASYNC_DIV; SYM895_REG8_WRITE (pSiop,SYM895_OFF_SCNTL3, SYM895_REG8_READ (pSiop, SYM895_OFF_SCNTL3) | pSiop->clkDiv); } /* SYM895_BUSMODE_SE */ /* If the current bus mode is HVD, Bit5 in STEST2 should be set */ else if (curBusMode == SYM895_BUSMODE_HVD) { SYM895_REG8_WRITE (pSiop,SYM895_OFF_STEST2, SYM895_REG8_READ (pSiop, SYM895_OFF_STEST2)| SYM895_STEST2_DIF); } /* run the scripts now */ connected = FALSE; notify = FALSE; break; /* Following are error conditions, both asynchronous and synchronous */ case SYM895_SCSI_TIMEOUT : case SYM895_HANDSHAKE_TIMEOUT : connected = FALSE; break; case SYM895_ILLEGAL_PHASE : connected = TRUE; break; case SYM895_UNEXPECTED_DISCON : connected = FALSE; break; case SYM895_NO_IDENTIFY : SCSI_MSG ("sym895Intr: No Valid Identify message at (re)select. \n", 0, 0, 0, 0, 0, 0); connected = TRUE; break; case SYM895_SPURIOUS_CMD : SCSI_MSG(" sym895Intr: Spurious Command Interrupt. \n", 0, 0, 0, 0, 0, 0); connected = FALSE; break; case SYM895_FATAL_ERROR : SCSI_MSG (" sym895Intr: Fatal Error, Restarting SIOP... \n", 0, 0, 0, 0, 0, 0); sym895HwInit (pSiop); connected = FALSE; break; default : SCSI_MSG ("sym895Intr: Un known interrupt (%d) \n", pScsiEvent->type, 0 ,0 ,0 ,0 ,0); connected = FALSE; break; } /* * Controller is now idle if possible, make it run a script. * * If a SCSI thread is suspended and must be processed at task-level, * leave the device idle. It will be re-started by the SCSI manager * calling "sym895Resume()". * * Otherwise, if there's a new SCSI thread to start (i.e., the SCSI * manager has called "sym895Activate()"), start the appropriate script. * * Otherwise, start a script which puts the device into passive mode * waiting for re-selection, selection or a host command. * * In all cases, clear any request to start a new thread. The only * tricky case is when there was a request pending and the device is * left IDLE. This should only ever occur when the current event is * selection or reselection, in which case the SCSI manager will retry * the activation request. (Also see "sym895Activate ()".) */ if (connected) { pSiop->state = SYM895_STATE_IDLE; } else if (pSiop->isCmdPending) { sym895ScriptStart (pSiop, pSiop->pNewThread, SYM895_SCRIPT_INIT_START); pSiop->state = SYM895_STATE_ACTIVE; } else { sym895ScriptStart (pSiop, (SYM895_THREAD *) pScsiCtrl->pIdentThread, SYM895_SCRIPT_WAIT); pSiop->state = SYM895_STATE_PASSIVE; } pSiop->isCmdPending = FALSE; SYM895_SCSI_DEBUG_MSG ("sym895Intr state %d -> %d\n", oldState, pSiop->state, 0, 0, 0, 0); /* Send the event to the SCSI manager to be processed. */ if (notify) scsiMgrEventNotify ((SCSI_CTRL *) pSiop, pScsiEvent, sizeof (event)); }/********************************************************************************* sym895RemainderGet - get the number of bytes remaining in "Data Path" because of* phase mismatch.** The Information transfer phase which halted because of the mismatch has been* saved as a part of the SIOP's register context.* * 895 has few registers helping us out in calculating how many bytes are * left not transferred because of some error condition.* The Registers are.. DFIFO, DBC, SSAT0, SSAT1, SIDx, SODx.** DFIFO register contains the number of bytes transferred between DMA core and* the SCSI Bus. The DBC register contains the number of bytes transferred * across the HostBus. The difference between these two will give the number of * bytes in the DMA Fifo....But hold on..There are more issues involved.* Please refer to chapter 2 of the 895 data manual.** RETURNS: number of bytes remained in the data path.** Note : This function is called at interrupt level.** NOMANUAL*/LOCAL UINT sym895RemainderGet ( SIOP * pSiop, /* pointer to controller information */ UINT phase /* phase, terminated by mismatch */ ) { UINT remCount; UINT16 tmpCount; UINT16 countFifo; UINT16 fifoMask; /* Read the Number of bytes transferred across the host bus */ remCount = SYM895_REG32_READ (pSiop,SYM895_OFF_DBC) & SYM895_COUNT_MASK; /* * check if the dma fifo is 816 bytes or 112 bytes. * accordingly the mask being applied will change */ if (SYM895_REG8_READ (pSiop,SYM895_OFF_CTEST5) & SYM895_CTEST5_BL2) fifoMask = SYM895_FIFO_816_MASK; else fifoMask = SYM895_FIFO_112_MASK; tmpCount = (remCount & fifoMask); countFifo = SYM895_REG8_READ (pSiop,SYM895_OFF_DFIFO); if (fifoMask == SYM895_FIFO_816_MASK) /* Fifo size is 816 bytes */ { /* Extract b0,b1 from CTEST5 and concatenate with countfifo.*/ countFifo |= ((UINT16)(SYM895_REG8_READ (pSiop, SYM895_OFF_CTEST5) & 0x03) << 8); } countFifo &= fifoMask; /* Now DMA FIFO byte offset counter is in "countFifo" */ tmpCount = (countFifo - remCount) & fifoMask; /* byte count is in "tmpCount" now */ /* * Now it depends on the direction of transfer. To know the direction * of transfer, check the phase. */ switch (phase) { case PHASE_DATA_OUT : case PHASE_MSG_OUT : case PHASE_COMMAND : /* Output phases : Check for data in output registers (SODx) */ /* * check the SSTAT0 and SSTAT2 registers to check if any bytes * are left in the SODL/SODR registers. */ /* Check to see any data is there in SODL register */ if (SYM895_REG8_READ (pSiop, SYM895_OFF_SSTAT0) & SYM895_SSTAT0_OLF) tmpCount++; if (SYM895_REG8_READ (pSiop, SYM895_OFF_SSTAT2) & SYM895_SSTAT2_OLF1) tmpCount++; /* * Check to see any data is there in SODR register * Note that SODR reg. is bypassed for asynchronous transfers */ /* if synchronous Send */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -