📄 templatescsi2.c
字号:
** templateThreadDefer - defer execution of a thread** Set the thread's state to INACTIVE and notify the SCSI manager of the* deferral event.** This routine is invoked when a re-selection event occurs.** RETURNS: N/A*/LOCAL void templateThreadDefer ( TEMPLATE_THREAD * pThread ) { SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_DEBUG_MSG ("templateThreadDefer: thread 0x%08x deferred\n", (int) pThread, 0, 0, 0, 0, 0); templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE); scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_DEFERRED); } /********************************************************************************* templateThreadFail - complete execution of a thread, with error status** Set the thread's status and errno according to the type of error. Set* the thread's state to INACTIVE, and notify the SCSI manager of the* completion event.** RETURNS: N/A*/LOCAL void templateThreadFail ( TEMPLATE_THREAD * pThread, int errNum ) { SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_DEBUG_MSG ("templateThreadFail: thread 0x%08x failed (errno = %d)\n", (int) pThread, errNum, 0, 0, 0, 0); pScsiThread->status = ERROR; if (pScsiThread->state == SCSI_THREAD_ABORTING) pScsiThread->errNum = S_scsiLib_ABORTED; else pScsiThread->errNum = errNum; templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE); scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED); } /******************************************************************************** templateThreadStateSet - set the state of a thread** This is really just a place-holder for debugging and possible future* enhancements such as state-change logging.** RETURNS: N/A*/LOCAL void templateThreadStateSet ( TEMPLATE_THREAD * pThread, /* ptr to thread info */ SCSI_THREAD_STATE state ) { SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_DEBUG_MSG ("templateThreadStateSet: thread 0x%08x: %d -> %d\n", (int) pThread, pScsiThread->state, state, 0, 0, 0); pScsiThread->state = state; }/********************************************************************************* templatePhaseMismatch - recover from a SCSI bus phase mismatch** This routine does whatever is required to keep the pointers, counts, etc.* used by task-level software in step when a SCSI phase mismatch occurs.** The interrupt-level mismatch processing has stored the phase of the* information transfer before the mismatch, and the number of bytes* remaining to be transferred. See "templateRemainderGet()".** Note that the only phase mismatches supported at this level are:** 1) during data in/out phases - presumably because the target has* transferred as much data as it intends to before sending a message* in (typically DISCONNECT or COMMAND COMPLETE). Recovery consists* of updating the active data pointer/count according to the number* of data bytes actually transferred before the mismatch.** 2) during a message out phase - presumably because the target does not* understand our outgoing message and is sending a MESSAGE REJECT* message, or similar. No recovery is needed here - it's all done* when the MESSAGE REJECT message has been received (see routine* "scsiMsgOutReject()").** 3) during a message in phase - presumably because we have asserted ATN* to abort or reject an incoming message. No recovery is needed here -* it's done by the thread management code, which should have enough* state information to know what to do.** RETURNS: OK, or ERROR for an unsupported or invalid phase** NOMANUAL*/LOCAL STATUS templatePhaseMismatch ( TEMPLATE_THREAD * pThread, /* ptr to thread info */ int phase, /* bus phase before mismatch */ UINT remCount /* # bytes not yet transferred */ ) { SCSI_THREAD *pScsiThread = (SCSI_THREAD *) pThread; UINT xferCount; /* TODO - compute nbr of bytes actually transferred. */ xferCount = 1024 - remCount; /* DUMMY CODE */ switch (phase) { case SCSI_DATA_IN_PHASE: case SCSI_DATA_OUT_PHASE: pScsiThread->activeDataAddress += xferCount; pScsiThread->activeDataLength -= xferCount; SCSI_DEBUG_MSG ("templatePhaseMismatch: data transfer aborted " "(%d bytes transferred).\n", xferCount, 0, 0, 0, 0, 0); break; case SCSI_MSG_OUT_PHASE: SCSI_DEBUG_MSG("templatePhaseMismatch: message out aborted " "(%d of %d bytes sent).\n", pScsiThread->pScsiCtrl->msgOutLength, pScsiThread->pScsiCtrl->msgOutLength - remCount, 0, 0, 0, 0); break; case SCSI_MSG_IN_PHASE: SCSI_DEBUG_MSG("templatePhaseMismatch: message in aborted " "(%d bytes received).\n", pScsiThread->pScsiCtrl->msgInLength, 0, 0, 0, 0, 0); break; case SCSI_COMMAND_PHASE: case SCSI_STATUS_PHASE: SCSI_ERROR_MSG ("templatePhaseMismatch: unsupported phase (%d).\n", phase, 0, 0, 0, 0, 0); return (ERROR); default: logMsg ("templatePhaseMismatch: invalid phase (%d).\n", phase, 0, 0, 0, 0, 0); return (ERROR); } return (OK); }/********************************************************************************* templateInitIdentEvent - identification thread event processing ** Parse the event type and handle it accordingly. This may result in state* changes for the thread, state variables being updated, etc.** RETURNS: N/A*/LOCAL void templateInitIdentEvent ( TEMPLATE_THREAD * pThread, TEMPLATE_EVENT * pEvent ) { SCSI_EVENT * pScsiEvent = (SCSI_EVENT *) pEvent; SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_CTRL * pScsiCtrl = pScsiThread->pScsiCtrl; /* Update controller msg in/out state after script completes */ pScsiCtrl->msgOutState = pThread->nMsgOutState; pScsiCtrl->msgInState = pThread->nMsgInState; /* Parse script exit status; handle as necessary */ switch (pScsiEvent->type) { case SCSI_EVENT_RESELECTED: pScsiThread->nBytesIdent = pScsiEvent->nBytesIdent; bcopy ((char *) pScsiCtrl->identBuf, (char *) pScsiThread->identMsg, pScsiThread->nBytesIdent); templateThreadStateSet (pThread, SCSI_THREAD_IDENT_IN); templateIdentInContinue (pThread); break; case TEMPLATE_MESSAGE_OUT_SENT: /* * This will be after we have sent an "ABORT (TAG)" msg. * The target will disconnect any time; it may have already * done so, in which case we won't be able to resume the * thread, but no matter. */ break; case TEMPLATE_MESSAGE_IN_RECVD: /* * Continue parsing the identification message. It * should by now be complete. * * First byte of ident msg is already in ident buffer. * Remaining bytes are in the normal message input buffer. * This should always be a two-byte message (viz. QUEUE TAG); * it would be nicer if there were a way to avoid hard-coding * this. */ bcopy ((char *) pScsiCtrl->msgInBuf, (char *) pScsiThread->identMsg + pScsiThread->nBytesIdent, 2); pScsiThread->nBytesIdent += 2; templateIdentInContinue (pThread); break; case TEMPLATE_SCRIPT_ABORTED: SCSI_DEBUG_MSG ("templateInitIdentEvent: thread 0x%08x: aborted\n", (int) pThread, 0, 0, 0, 0, 0); break; case SCSI_EVENT_DISCONNECTED: SCSI_DEBUG_MSG ("templateInitIdentEvent: thread 0x%08x:" "disconnected\n", (int) pThread, 0, 0, 0, 0, 0); templateThreadFail (pThread, S_scsiLib_DISCONNECTED); break; case SCSI_EVENT_BUS_RESET: SCSI_DEBUG_MSG ("templateInitIdentEvent: thread 0x%08x: bus reset\n", (int) pThread, 0, 0, 0, 0, 0); /* Do not try to resume this thread. SCSI mgr will tidy up. */ templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE); break; case TEMPLATE_UNEXPECTED_DISCON: /* not really unexpected after an abort message ... */ SCSI_ERROR_MSG ("templateInitIdentEvent: thread 0x%08x: " "unexpected disconnection\n", (int) pThread, 0, 0, 0, 0, 0); templateThreadFail (pThread, S_scsiLib_DISCONNECTED); break; case TEMPLATE_ILLEGAL_PHASE: SCSI_ERROR_MSG ("templateInitIdentEvent: thread 0x%08x: " "illegal phase requested.\n", (int) pThread, 0, 0, 0, 0, 0); templateThreadFail (pThread, S_scsiLib_INVALID_PHASE); break; default: logMsg ("templateInitIdentEvent: invalid event type (%d)\n", pScsiEvent->type, 0, 0, 0, 0, 0); break; } } /********************************************************************************* templateResume - resume a script corresponding to a suspended thread** NOTE: the script can only be resumed if the controller is currently idle.* To avoid races, interrupts must be locked while this is checked and the* script re-started.** Reasons why the controller might not be idle include SCSI bus reset and* unexpected disconnection, both of which might occur in practice. Hence* this is not considered to be a major software error.** RETURNS: OK, or ERROR if the controller is in an invalid state (this* should not be treated as a major software failure).*/LOCAL STATUS templateResume ( SIOP * pSiop, /* ptr to controller info */ TEMPLATE_THREAD* pThread, /* ptr to thread info */ TEMPLATE_SCRIPT_ENTRY entryId /* entry point of script to resume */ ) { STATUS status; int key; /* Check validity of connection and start script if OK */ key = intLock (); switch (pSiop->state) { case TEMPLATE_STATE_IDLE: SCSI_INT_DEBUG_MSG ("templateResume: thread: 0x%08x:" " state %d -> %d\n", (int) pThread, TEMPLATE_STATE_IDLE, TEMPLATE_STATE_ACTIVE, 0, 0, 0); templateScriptStart (pSiop, pThread, entryId); pSiop->state = TEMPLATE_STATE_ACTIVE; status = OK; break; case TEMPLATE_STATE_PASSIVE: case TEMPLATE_STATE_ACTIVE: default: status = ERROR; break; } intUnlock (key); return (status); }/********************************************************************************* templateIdentInContinue - continue incoming identification** Parse the message built up so far. If it is not yet complete, do nothing.* If the message is complete, attempt to reconnect the thread it identifies,* and deactivate this thread (the identification thread is no longer active).* Otherwise (identification has failed), abort the identification sequence.** RETURNS: N/A*/LOCAL void templateIdentInContinue ( TEMPLATE_THREAD * pThread ) { SCSI_THREAD * pNewThread; SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_CTRL * pScsiCtrl = pScsiThread->pScsiCtrl; SCSI_IDENT_STATUS status; SCSI_THREAD_STATE state; status = scsiIdentMsgParse (pScsiCtrl, pScsiThread->identMsg, pScsiThread->nBytesIdent, &pScsiThread->pScsiPhysDev, &pScsiThread->tagNumber); switch (status) { case SCSI_IDENT_INCOMPLETE: state = SCSI_THREAD_IDENT_IN; break; case SCSI_IDENT_COMPLETE: scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_RECONNECTED); if ((pNewThread = scsiMgrPhysDevActiveThreadFind ( pScsiThread->pScsiPhysDev, pScsiThread->tagNumber)) == 0) { state = SCSI_THREAD_IDENT_ABORTING; } else { templateThreadReconnect ((TEMPLATE_THREAD *) pNewThread); state = SCSI_THREAD_INACTIVE; } break; case SCSI_IDENT_FAILED: state = SCSI_THREAD_IDENT_ABORTING; break; default: logMsg ("templateIdentInContinue: invalid ident status (%d)\n", status, 0, 0, 0, 0, 0); state = SCSI_THREAD_INACTIVE; break; } if (state == SCSI_THREAD_IDENT_ABORTING) templateThreadAbort ((SIOP *) pScsiCtrl, pThread); templateThreadStateSet (pThread, state); }/********************************************************************************* templateThreadReconnect - reconnect a thread** Restore the SCSI pointers for the thread (this really should be in a more* generic section of code - perhaps part of the SCSI manager's thread event* procesing ?). Update the newly-connected thread's context (including* shared memory area) and resume it. Set the thread's state to ESTABLISHED.** RETURNS: N/A** NOMANUAL*/LOCAL void templateThreadReconnect ( TEMPLATE_THREAD * pThread ) { SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_CTRL * pScsiCtrl = pScsiThread->pScsiCtrl; SIOP * pSiop = (SIOP *) pScsiCtrl; SCSI_DEBUG_MSG ("templateThreadReconnect: reconnecting thread 0x%08x\n", (int) pThread, 0, 0, 0, 0, 0); pScsiCtrl->pThread = pScsiThread; /* Implied RESTORE POINTERS action: see "scsiMsgInComplete ()" */ pScsiThread->activeDataAddress = pScsiThread->savedDataAddress; pScsiThread->activeDataLength = pScsiThread->savedDataLength; templateThreadUpdate (pThread); if (templateResume (pSiop, pThread, TEMPLATE_SCRIPT_INIT_CONTINUE) != OK) { SCSI_ERROR_MSG ("templateThreadReconnect: failed to resume thread.\n", 0, 0, 0, 0, 0, 0); templateThreadFail (pThread, S_scsiLib_DISCONNECTED); return; } templateThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -