📄 ncr810lib.c
字号:
((pHwRegs->scntl1Bit7) ? (NCR810_OUT_BYTE(pSiop->pScntl1, NCR810_IN_BYTE(pSiop->pScntl1) | SCNTL1_EXC)) : (NCR810_OUT_BYTE(pSiop->pScntl1, NCR810_IN_BYTE(pSiop->pScntl1) & ~SCNTL1_EXC))); return (OK); }/********************************************************************************* ncr810ScsiBusControl - miscellaneous low-level SCSI bus control operations** Currently supports only the SCSI_BUS_RESET operation; other operations are* not used explicitly by the driver because they are carried out automatically* by the script program.** NOTE: after the SCSI bus has been reset, the SIOP generates an interrupt* which causes an NCR810_BUS_RESET event to be sent to the SCSI manager.* See "ncr810Intr()".** RETURNS: OK, or ERROR if an invalid operation is requested.** NOMANUAL*/LOCAL STATUS ncr810ScsiBusControl ( SIOP * pSiop, /* ptr to controller info */ int operation /* bitmask for operation(s) to be performed */ ) { if ((operation & ~SCSI_BUS_RESET) != 0) return (ERROR); if (operation & SCSI_BUS_RESET) ncr810ScsiBusReset (pSiop); return (OK); }/********************************************************************************* ncr810ScsiBusReset - assert the RST line on the SCSI bus ** Issue a SCSI Bus Reset command to the NCR 810. This should put all devices* on the SCSI bus in an initial quiescent state.** The bus reset will generate an interrupt which is handled by the normal* ISR (see "ncr810Intr()").** RETURNS: N/A** NOMANUAL*/LOCAL void ncr810ScsiBusReset ( FAST SIOP *pSiop /* ptr to SIOP info */ ) { NCR810_OUT_BYTE(pSiop->pScntl1, NCR810_IN_BYTE(pSiop->pScntl1) | SCNTL1_RST); taskDelay (2); /* pause for at least 250 us */ NCR810_OUT_BYTE(pSiop->pScntl1, NCR810_IN_BYTE(pSiop->pScntl1) & ~SCNTL1_RST); }/********************************************************************************* ncr810Intr - interrupt service routine for the SIOP** Find the event type corresponding to this interrupt, and carry out any* actions which must be done before the SIOP is re-started. Determine* whether or not the SIOP is connected to the bus (depending on the event* type - see note below). If not, start a client script if possible or* else just make the SIOP wait for something else to happen.** Notify the SCSI manager of a controller event.** NOTE:* The "connected" Boolean tells whether there is a SCSI thread in progress* which must be continued before any other SCSI activity can occur. In* principle, it might seem that reading the appropriate bit in the SIOP's* SCNTL1 register would be better than inferring the value from the interrupt* code.** However, the SCNTL1 register may change between the time the script* completes (generates the interrupt) and the time it is read - for example,* if the SIOP is reselected immediately after generating a DISCONNECTED* interrupt.** Because the action taken by the ISR depends critically on what will happen* in software as a result of the current interrupt, and _not_ on the current* state of the SIOP hardware, if the hardware "connected" bit were used, the* above scenario would cause the ISR to fail to re-start a script when in* fact it should do. The result would be that the SIOP would forever remain* 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 ncr810Intr ( SIOP *pSiop ) { NCR810_EVENT event; SCSI_EVENT * pScsiEvent = (SCSI_EVENT *) &event; SCSI_CTRL * pScsiCtrl = (SCSI_CTRL *) pSiop; NCR810_THREAD * pThread = (NCR810_THREAD *) pSiop->pHwThread; BOOL connected = FALSE; BOOL notify = TRUE; int oldState = (int) pSiop->state; CACHE_PIPE_FLUSH(); /* * Save (partial) SIOP register context in current thread */ pThread->scratcha0 = NCR810_IN_BYTE(pSiop->pScratcha0); pThread->scratcha1 = NCR810_IN_BYTE(pSiop->pScratcha1); pThread->scratcha2 = NCR810_IN_BYTE(pSiop->pScratcha2); pThread->scratcha3 = NCR810_IN_BYTE(pSiop->pScratcha3); if ((pScsiEvent->type = ncr810EventTypeGet (pSiop)) == ERROR) return; SCSI_INT_DEBUG_MSG ("ncr810Intr: DSA = 0x%08x, DSP = 0x%08x, type = %d.\n", NCR810_IN_32(pSiop->pDsa), NCR810_IN_32(pSiop->pDsp), pScsiEvent->type, 0, 0, 0); /* * Synchronise with single-step routine, if enabled. */ if (pSiop->singleStep) semGive (pSiop->singleStepSem); if (pScsiEvent->type == NCR810_SINGLE_STEP) return; /* * Handle interrupt according to type. */ switch (pScsiEvent->type) { /* * Following cases result from completion of a script run. */ case NCR810_CMD_COMPLETE: case NCR810_DISCONNECTED: connected = FALSE; break; case NCR810_MESSAGE_OUT_SENT: case NCR810_MESSAGE_IN_RECVD: case NCR810_EXT_MESSAGE_SIZE: case NCR810_NO_MSG_OUT: case NCR810_SCRIPT_ABORTED: connected = TRUE; break; case NCR810_PHASE_MISMATCH: event.remCount = ncr810RemainderGet (pSiop, pThread->nBusPhase); connected = TRUE; break; /* * Following cases are asynchronous conditions, i.e. not resulting * directly from running a script. */ case NCR810_READY: connected = FALSE; notify = FALSE; break; case NCR810_SELECTED: case NCR810_RESELECTED: pScsiEvent->busId = ncr810BusIdGet (pSiop, pThread->nBusIdBits); pScsiEvent->nBytesIdent = (pThread->nHostFlags & FLAGS_IDENTIFY) ? 1 : 0; connected = TRUE; break; case NCR810_SCSI_BUS_RESET: connected = FALSE; break; /* * Following cases are error conditions (mixture of synchronous * and asynchronous). */ case NCR810_SCSI_TIMEOUT: case NCR810_HANDSHAKE_TIMEOUT: connected = FALSE; break; case NCR810_ILLEGAL_PHASE: connected = TRUE; break; case NCR810_UNEXPECTED_DISCON: connected = FALSE; break; case NCR810_NO_IDENTIFY: logMsg ("ncr810Intr: no valid IDENTIFY message at (re)select.\n", 0, 0, 0, 0, 0, 0); connected = TRUE; break; case NCR810_SPURIOUS_CMD: logMsg ("ncr810Intr: spurious command interrupt.\n", 0, 0, 0, 0, 0, 0); connected = FALSE; break; case NCR810_FATAL_ERROR: logMsg ("ncr810Intr: unrecoverable error - re-starting SIOP.\n", 0, 0, 0, 0, 0, 0); ncr810HwInit (pSiop); connected = FALSE; break; default: SCSI_INT_DEBUG_MSG ("ncr810Intr: unexpected interrupt (%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 "ncr810Resume()". * * Otherwise, if there's a new SCSI thread to start (i.e., the SCSI * manager has called "ncr810Activate()"), 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 "ncr810Activate ()".) */ if (connected) { pSiop->state = NCR810_STATE_IDLE; } else if (pSiop->cmdPending) { ncr810ScriptStart (pSiop, (NCR810_THREAD *) pSiop->pNewThread, NCR810_SCRIPT_INIT_START); pSiop->state = NCR810_STATE_ACTIVE; } else { ncr810ScriptStart (pSiop, (NCR810_THREAD *) pScsiCtrl->pIdentThread, NCR810_SCRIPT_WAIT); pSiop->state = NCR810_STATE_PASSIVE; } pSiop->cmdPending = FALSE; SCSI_INT_DEBUG_MSG ("ncr810Intr: 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)); }/********************************************************************************* ncr810BusIdGet - find bus ID of device which selected/reselected the SIOP.** Get the Bus ID of the selecting/reselecting device by looking at SSID* * RETURNS: bus ID of connected peer device** NOTE: This routine is called at interrupt level.** NOMANUAL*/LOCAL int ncr810BusIdGet ( SIOP * pSiop, /* ptr to controller info */ UINT busIdBits /* bits corresponding to bus ID */ ) { UINT8 devBusId; devBusId = NCR810_IN_BYTE(pSiop->pSsid) & ((UINT8) SSID_ENC_MASK); return (devBusId); }/********************************************************************************* ncr810RemainderGet - 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 ncr810RemainderGet ( SIOP *pSiop, /* pointer to controller info */ UINT phase /* phase terminated by mismatch */ ) { UINT remCount; UINT8 tmpCount; UINT tmpCountWord; UINT8 countFifo; UINT8 syncMode; /* determine xfer mode */ syncMode = NCR810_IN_BYTE(pSiop->pSxfer) & SXFER_OFFSET; /* * Find remaining byte count (may be corrected later). For a fuller * explanation, see Chapter 2 of the NCR 53C810 Data Manual. */ remCount = NCR810_IN_32(pSiop->pDbc) & NCR810_COUNT_MASK; /* * check for data in fifo and output registers * (SODR & SODL), count from DBC minus DFIFO count and 0x7f * (see NCR 53C810 Data Manual). */ /* look for deep fifo mode on 825/875 */ tmpCount = 0; tmpCountWord = 0; if ( ((pSiop->devType == NCR825_DEVICE_ID) || (pSiop->devType == NCR875_DEVICE_ID)) && (NCR810_IN_BYTE(pSiop->pCtest5) & CTEST5_DFS) ) { tmpCountWord = ((((UINT)NCR810_IN_BYTE(pSiop->pCtest5)) & 0x0003) << 8); tmpCountWord += (UINT)NCR810_IN_BYTE(pSiop->pDfifo); tmpCountWord -= (remCount & 0x03FF); } else { tmpCount = (UINT8)(remCount & 0x7f); countFifo = NCR810_IN_BYTE(pSiop->pDfifo) & 0x7f; tmpCount = (countFifo - tmpCount) & 0x7f; } switch (phase) { case PHASE_DATA_IN: case PHASE_MSG_IN: case PHASE_STATUS: if (!syncMode) { /* Asynchronous Read */ if (NCR810_IN_BYTE(pSiop->pSstat0) & SSTAT0_ILF) tmpCount++; /* 825/875 Extensions */ if ((pSiop->devType == NCR825_DEVICE_ID) || (pSiop->devType == NCR875_DEVICE_ID)) { if (NCR810_IN_BYTE(pSiop->pSstat0) & SSTAT0_ILF) tmpCount++; if (NCR810_IN_BYTE(pSiop->pSstat2) & SSTAT2_ILF) tmpCount++; } } else { /* Synchronous Read */ countFifo = (NCR810_IN_BYTE(pSiop->pSstat1) & FIFO_MASK) >> 4; countFifo &= 0x0f;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -