📄 ncr710lib2.c
字号:
* IDLE, and the SCSI system would become deadlocked. (I've seen it happen !)** One disadvantage is that the ISR has to know a little too much about the* semantics of the interrupt codes - an improvement might be to have a* distinguishing feature (e.g. bit set) in the interrupt code to indicate* whether or not to start a new script.** RETURNS: N/A** NOMANUAL*/void ncr710IntrScsi2 ( SIOP *pSiop ) { NCR710_EVENT event; SCSI_EVENT * pScsiEvent = (SCSI_EVENT *) &event; SCSI_CTRL * pScsiCtrl = (SCSI_CTRL *) pSiop; NCR710_THREAD * pThread = (NCR710_THREAD *) pSiop->pHwThread; BOOL connected = FALSE; BOOL notify = TRUE; int oldState = (int) pSiop->state; /* * Save (partial) SIOP register context in current thread */ pThread->scratch0 = *pSiop->pScratch0; pThread->scratch1 = *pSiop->pScratch1; pThread->scratch2 = *pSiop->pScratch2; pThread->scratch3 = *pSiop->pScratch3; pScsiEvent->type = ncr710EventTypeGet (pSiop); SCSI_INT_DEBUG_MSG ("ncr710Intr: DSA = 0x%08x, DSP = 0x%08x, type = %d.\n", *pSiop->pDsa, *pSiop->pDsp, pScsiEvent->type, 0, 0, 0); /* * Synchronise with single-step routine, if enabled. */ if (pSiop->singleStep) semGive (pSiop->singleStepSem); if (pScsiEvent->type == NCR710_SINGLE_STEP) return; /* * Handle interrupt according to type. */ switch (pScsiEvent->type) { /* * Following cases result from completion of a script run. */ case NCR710_CMD_COMPLETE: case NCR710_DISCONNECTED: connected = FALSE; break; case NCR710_MESSAGE_OUT_SENT: case NCR710_MESSAGE_IN_RECVD: case NCR710_EXT_MESSAGE_SIZE: case NCR710_NO_MSG_OUT: case NCR710_SCRIPT_ABORTED: connected = TRUE; break; case NCR710_PHASE_MISMATCH: event.remCount = ncr710RemainderGet (pSiop, pThread->nBusPhase); connected = TRUE; break; /* * Following cases are asynchronous conditions, i.e. not resulting * directly from running a script. */ case NCR710_READY: connected = FALSE; notify = FALSE; break; case NCR710_SELECTED: case NCR710_RESELECTED: pScsiEvent->busId = ncr710BusIdGet (pSiop, pThread->nBusIdBits); pScsiEvent->nBytesIdent = (pThread->nHostFlags & FLAGS_IDENTIFY) ? 1 : 0; connected = TRUE; break; case NCR710_SCSI_BUS_RESET: connected = FALSE; break; /* * Following cases are error conditions (mixture of synchronous * and asynchronous). */ case NCR710_SCSI_TIMEOUT: connected = FALSE; break; case NCR710_ILLEGAL_PHASE: connected = TRUE; break; case NCR710_UNEXPECTED_DISCON: connected = FALSE; break; case NCR710_NO_IDENTIFY: logMsg ("ncr710Intr: no valid IDENTIFY message at (re)select.\n", 0, 0, 0, 0, 0, 0); connected = TRUE; break; case NCR710_SPURIOUS_CMD: logMsg ("ncr710Intr: spurious command interrupt.\n", 0, 0, 0, 0, 0, 0); connected = FALSE; break; case NCR710_FATAL_ERROR: logMsg ("ncr710Intr: unrecoverable error - re-starting SIOP.\n", 0, 0, 0, 0, 0, 0); ncr710HwInit (pSiop); connected = FALSE; break; default: logMsg ("ncr710Intr: unexpected interrupt status (%d).\n", pScsiEvent->type, 0, 0, 0, 0, 0); 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 SIOP idle. It will be re-started by the SCSI manager * calling "ncr710Resume()". * * Otherwise, if there's a new SCSI thread to start (i.e., the SCSI * manager has called "ncr710Activate()"), start the appropriate script. * * Otherwise, start a script which puts the SIOP 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 SIOP 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 "ncr710Activate ()".) */ if (connected) { pSiop->state = NCR710_STATE_IDLE; } else if (pSiop->cmdPending) { ncr710ScriptStart (pSiop, (NCR710_THREAD *) pSiop->pNewThread, NCR710_SCRIPT_INIT_START); pSiop->state = NCR710_STATE_ACTIVE; } else { ncr710ScriptStart (pSiop, (NCR710_THREAD *) pScsiCtrl->pIdentThread, NCR710_SCRIPT_WAIT); pSiop->state = NCR710_STATE_PASSIVE; } pSiop->cmdPending = FALSE; SCSI_INT_DEBUG_MSG ("ncr710Intr: 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)); }/********************************************************************************* ncr710BusIdGet - find bus ID of device which selected/reselected the SIOP.** Calculate bus ID of SCSI peer which (re)selected the SIOP; "busIdBits"* contains a copy of the LCRC register, i.e. an image of the data bits* asserted on the SCSI bus during (re)selection. Extract the peer's ID* by masking out the bit corresponding to our bus ID then shifting until* we find a bit set.* * RETURNS: bus ID of connected peer device** NOTE: This routine is called at interrupt level.** NOMANUAL*/LOCAL int ncr710BusIdGet ( SIOP * pSiop, /* ptr to controller info */ UINT busIdBits /* bits corresponding to bus ID */ ) { UINT8 devBusId; busIdBits &= ~(*pSiop->pScid); for (devBusId = 0; devBusId <= SCSI_MAX_BUS_ID; ++devBusId) { if (busIdBits & (1 << devBusId)) break; } return (devBusId); }/********************************************************************************* ncr710RemainderGet - get remaining xfer count and clean up after mismatch** Clean up the SIOP's data path and calculate the number of bytes which* were expected to be, but have not been transferred.** The information transfer phase which halted because of the mismatch has* been saved as part of the SIOP's register context.** RETURNS: number of bytes not transferred** NOTE: This routine is called at interrupt level.** NOMANUAL*/LOCAL UINT ncr710RemainderGet ( SIOP *pSiop, /* pointer to controller info */ UINT phase /* phase terminated by mismatch */ ) { UINT remCount; UINT8 tmpCount; UINT8 countFifo; /* * Find remaining byte count (may be corrected later). For a fuller * explanation, see Chapter 2 of the NCR 53C710 Data Manual. */ remCount = *pSiop->pDbc & NCR710_COUNT_MASK; switch (phase) { case PHASE_DATA_IN: case PHASE_MSG_IN: case PHASE_STATUS: /* * Input phases: check for pending byte to store, update * buffer if there is one. */ if (*pSiop->pSstat1 & B_ILF) { *((UINT8 *)pSiop->pDnad) = *pSiop->pSidl; remCount--; } break; case PHASE_DATA_OUT: case PHASE_MSG_OUT: case PHASE_COMMAND: /* * Output phases: check for data in fifo and output registers * (SODR & SODL), count from DBC minus DFIFO count and 0x7f * (see NCR 53C710 Data Manual). */ tmpCount = (UINT8)(remCount & 0x7f); countFifo = *pSiop->pDfifo & 0x7f; tmpCount = (countFifo - tmpCount) & 0x7f; if (*pSiop->pSstat1 & B_OLF) tmpCount++; if (*pSiop->pSstat1 & B_ORF) tmpCount++; remCount += tmpCount; break; default: logMsg ("ncr710RemainderGet: invalid phase.\n", 0, 0, 0, 0, 0, 0); break; } /* * Clear data FIFOs */ *pSiop->pCtest8 |= B_CLF; return (remCount); }/******************************************************************************** ncr710EventTypeGet - parse SCSI and DMA status registers at interrupt time** NOTE* Only status bits which have corresponding interrupts enabled are checked !** RETURNS: an interrupt (event) type code** NOMANUAL*/LOCAL int ncr710EventTypeGet ( SIOP * pSiop ) { UINT intrRegs; UINT8 scsiStatus; UINT8 dmaStatus; /* * Read interrupt status registers * * Note: read as a long word to avoid requirement for a delay when * SCSI status and DMA status registers are read individually. */ scsiStatus = dmaStatus = 0; *pSiop->pIstat &= ~B_ABORT; while ((*pSiop->pIstat & (B_SIP | B_DIP)) != 0) {#if _BYTE_ORDER==_BIG_ENDIAN intrRegs = *((UINT *)pSiop->pSstat2); scsiStatus |= (UINT8)((intrRegs >> 8) & 0x0FF); dmaStatus |= (UINT8)( intrRegs & 0x0FF);#else intrRegs = *((UINT *)pSiop->pDstat); scsiStatus |= (UINT8)((intrRegs >> 16) & 0x0FF); dmaStatus |= (UINT8)((intrRegs >> 24) & 0x0FF);#endif } SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: SCSI status = 0x%02x, " "DMA status = 0x%02x\n", scsiStatus, dmaStatus, 0, 0, 0, 0); /* * Check for fatal errors (first !) */ if (scsiStatus & B_SGE) { logMsg ("ncr710: SCSI bus gross error.\n", 0, 0, 0, 0, 0, 0); return (NCR710_FATAL_ERROR); } if (scsiStatus & B_PAR) { logMsg ("ncr710: parity error.\n", 0, 0, 0, 0, 0, 0); return (NCR710_FATAL_ERROR); } if (dmaStatus & B_IID) { logMsg ("ncr710: illegal instruction (DSP = 0x%08x).\n", *pSiop->pDsp, 0, 0, 0, 0, 0); return (NCR710_FATAL_ERROR); } if (dmaStatus & B_BF) { logMsg ("ncr710: bus fault (DSP = 0x%08x).\n", *pSiop->pDsp, 0, 0, 0, 0, 0); return (NCR710_FATAL_ERROR); } if (dmaStatus & B_WTD) { logMsg ("ncr710: watchdog timeout (DSP = 0x%08x).\n", *pSiop->pDsp, 0, 0, 0, 0, 0); return (NCR710_FATAL_ERROR); } /* * No fatal errors; try the rest (NB order of tests is important !) */ if (scsiStatus & B_RSTE) { SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: SCSI bus reset.\n", 0, 0, 0, 0, 0, 0); *pSiop->pCtest8 |= B_CLF; /* clear FIFOs */ return (NCR710_SCSI_BUS_RESET); } if (scsiStatus & B_UDC) { SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: unexpected disconnection.\n", 0, 0, 0, 0, 0, 0); *pSiop->pCtest8 |= B_CLF; /* clear FIFOs */ return (NCR710_UNEXPECTED_DISCON); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -