📄 scsimgrlib.c
字号:
** NOTE:* The thread must be a valid initiator thread (from a client request) and* must not be on either a device wait queue or a device active queue.** RETURNS: N/A*/LOCAL void scsiMgrThreadComplete ( SCSI_THREAD * pThread /* ptr to thread info */ ) { SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev; SCSI_DEBUG_MSG ("scsiMgrThreadComplete: thread 0x%08x\n", (int) pThread, 0, 0, 0, 0, 0); /* * Check for contingent allegiance condition on physical device */ if (pThread->status == OK) { UINT scsiStatus = *pThread->statusAddress; switch (scsiStatus & SCSI_STATUS_MASK) { case SCSI_STATUS_CHECK_CONDITION: case SCSI_STATUS_CMD_TERMINATED: SCSI_DEBUG_MSG ("scsiMgrThreadComplete: device 0x%08x: " "contingent allegiance detected\n", (int) pScsiPhysDev, 0, 0, 0, 0, 0); pScsiPhysDev->pendingCA = TRUE; break; default: if (pScsiPhysDev->pendingCA) { SCSI_DEBUG_MSG ("scsiMgrThreadComplete: device 0x%08x: " "contingent allegiance cleared\n", (int) pScsiPhysDev, 0, 0, 0, 0, 0); pScsiPhysDev->pendingCA = FALSE; } break; } } /* * Finish processing the client's request */ scsiMgrRequestComplete (pThread); }/******************************************************************************** scsiMgrThreadDefer - defer execution of an initiator thread** (This routine is called if a thread "loses arbitration" to reselection* during an attempt to select a target device.)** Remove the thread from its physical device's active queue and re-insert it* onto the wait queue to be re-despatched at the next opportunity.** NOTE:* The check that the thread actually was on the active queue avoids any* possibility of races with the transaction timeout mechanism.** RETURNS: N/A*/LOCAL void scsiMgrThreadDefer ( SCSI_THREAD * pThread /* ptr to thread info */ ) { SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev; SCSI_DEBUG_MSG ("scsiMgrThreadDefer: thread 0x%08x\n", (int) pThread, 0, 0, 0, 0, 0); if (scsiMgrPhysDevActiveQRemove (pScsiPhysDev, pThread) == OK) { scsiMgrPhysDevWaitQAdd (pScsiPhysDev, pThread); pThread->state = SCSI_THREAD_WAITING; } }/********************************************************************************* scsiMgrThreadActivate - start running the specified thread** Allocate a tag number (if required) for the target physical device, build* a corresponding identification message, and call the controller-specific* thread activation routine. Notify the controller and the thread of the* activation event.** RETURNS: OK, or ERROR if activation failed.*/LOCAL STATUS scsiMgrThreadActivate ( SCSI_THREAD * pThread ) { SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev; SCSI_CTRL * pScsiCtrl = pThread->pScsiCtrl; /* * Allocate a tag number according to required type */ if (pThread->tagType == SCSI_TAG_DEFAULT) pThread->tagType = pScsiPhysDev->tagType; if (scsiMgrPhysDevTagAllocate (pScsiPhysDev, pThread->tagType, &pThread->tagNumber) != OK) { SCSI_DEBUG_MSG ("scsiMgrThreadActivate: thread 0x%08x: " "can't allocate tag\n", (int) pThread, 0, 0, 0, 0, 0); return (ERROR); } /* * Build identification message using this tag */ pThread->identMsgLength = scsiIdentMsgBuild (pThread->identMsg, pScsiPhysDev, pThread->tagType, pThread->tagNumber); /* * Initialise active and saved data pointers */ pThread->activeDataLength = pThread->dataLength; pThread->activeDataAddress = pThread->dataAddress; pThread->savedDataLength = pThread->dataLength; pThread->savedDataAddress = pThread->dataAddress; /* * Activate the thread using the controller driver */ if ((*pScsiCtrl->scsiThreadActivate) (pScsiCtrl, pThread) != OK) { SCSI_DEBUG_MSG ("scsiMgrThreadActivate: thread 0x%08x: " "controller activation failed\n", (int) pThread, 0, 0, 0, 0, 0); return (ERROR); } scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_CONNECTED); scsiMgrThreadEvent (pThread, SCSI_THREAD_EVENT_ACTIVATED); return (OK); }/********************************************************************************* scsiMgrCtrlEvent - send an event to the SCSI controller state machine** This routine is called by the thread driver whenever selection,* reselection, or disconnection occurs or when a thread is activated.* It manages a simple finite-state machine for the SCSI controller.** NOTE:* This function should not be called by application programs.** RETURNS: N/A*/void scsiMgrCtrlEvent ( SCSI_CTRL * pScsiCtrl, SCSI_EVENT_TYPE eventType ) { switch (eventType) { case SCSI_EVENT_CONNECTED: pScsiCtrl->active = TRUE; break; case SCSI_EVENT_DISCONNECTED: pScsiCtrl->active = FALSE; break; default: logMsg ("scsiMgrCtrlEvent: invalid event type (%d)\n", eventType, 0, 0, 0, 0, 0); break; } }/********************************************************************************* scsiMgrThreadEvent - send an event to the thread state machine** This routine forwards an event to the thread's physical device. If the * event is completion or deferral, it frees up the tag which was allocated * when the thread was activated and either completes or defers the thread.** NOTE:* This function should not be called by application programs.** The thread passed into this function does not have to be an active client* thread (it may be an identification thread).** If the thread has no corresponding physical device, this routine does* nothing. (This occassionally occurs if an unexpected disconnection* or bus reset happens when an identification thread has not yet identified* which physical device it corresponds to.** RETURNS: N/A*/void scsiMgrThreadEvent ( SCSI_THREAD * pThread, SCSI_THREAD_EVENT_TYPE eventType ) { SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev; SCSI_TAG tagNum = pThread->tagNumber; /* * Check for threads with no associated physical device. In this case, * there is nothing to be done. */ if (pScsiPhysDev == 0) return; switch (eventType) { case SCSI_THREAD_EVENT_ACTIVATED: scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_ACTIVATED); break; case SCSI_THREAD_EVENT_DISCONNECTED: scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_DISCONNECTED); break; case SCSI_THREAD_EVENT_RECONNECTED: scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_RECONNECTED); break; case SCSI_THREAD_EVENT_COMPLETED: scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_COMPLETED); scsiMgrPhysDevTagFree (pScsiPhysDev, tagNum); if (scsiMgrPhysDevActiveQRemove (pScsiPhysDev, pThread) == OK) scsiMgrThreadComplete (pThread); break; case SCSI_THREAD_EVENT_DEFERRED: scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_COMPLETED); scsiMgrPhysDevTagFree (pScsiPhysDev, tagNum); scsiMgrThreadDefer (pThread); break; default: logMsg ("scsiMgrThreadEvent: invalid event type (%d)\n", eventType, 0, 0, 0, 0, 0); break; } }/********************************************************************************* scsiMgrPhysDevReset - reset a physical device** Clean up all threads currently in progress on the device, failing them* with an error code corresponding to SCSI bus reset.** Clean up any state variables associated with the device.** Any threads waiting for the device to become available are not affected,* and will continue to be executed normally.** NOTE: all threads are assumed to be physically disconnected (not to be* reconnected) by the target device before this routine is called.** RETURNS: N/A*/LOCAL void scsiMgrPhysDevReset ( SCSI_PHYS_DEV *pScsiPhysDev ) { SCSI_THREAD * pThread; /* * Clean up all active threads: none are connected after a reset */ while ((pThread = (SCSI_THREAD *) lstGet (&pScsiPhysDev->activeThreads)) != 0) { pThread->status = ERROR; pThread->errNum = S_scsiLib_BUS_RESET; scsiMgrThreadComplete (pThread); } /* * Re-initialise tag system */ scsiMgrPhysDevTagInit (pScsiPhysDev); /* * Reset miscellaneous state variables */ pScsiPhysDev->connected = FALSE; pScsiPhysDev->pendingCA = FALSE; pScsiPhysDev->nexus = SCSI_NEXUS_NONE; pScsiPhysDev->curTag = SCSI_TAG_NONE; pScsiPhysDev->nTaggedNexus = 0; }/********************************************************************************* scsiMgrPhysDevEvent - notify the physical device of an event** Maintain the physical device's state variables according to the type of* event and the tag involved. These state variables affect the scheduling* of new threads on the device (see "scsiMgrPhysDevRunnableThreadGet ()").** RETURNS: N/A*/LOCAL void scsiMgrPhysDevEvent ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_TAG tagNum, SCSI_DEV_EVENT_TYPE eventType ) { /* * Validate tag number */ if ((tagNum != SCSI_TAG_NONE) && (tagNum >= pScsiPhysDev->nTags)) { logMsg ("scsiMgrPhysDevEvent: device 0x%08x: invalid tag (%d)\n", (int) pScsiPhysDev, tagNum, 0, 0, 0, 0); return; } /* * Handle the event for this tag (and the device as a whole) */ switch (eventType) { case SCSI_DEV_ACTIVATED: pScsiPhysDev->curTag = tagNum; pScsiPhysDev->connected = TRUE; if (tagNum == SCSI_TAG_NONE) { if (pScsiPhysDev->pendingCA) pScsiPhysDev->savedNexus = pScsiPhysDev->nexus; pScsiPhysDev->nexus = SCSI_NEXUS_ITL; } else { pScsiPhysDev->nexus = SCSI_NEXUS_ITLQ; ++pScsiPhysDev->nTaggedNexus; } break; case SCSI_DEV_DISCONNECTED: pScsiPhysDev->curTag = SCSI_TAG_NONE; pScsiPhysDev->connected = FALSE; break; case SCSI_DEV_RECONNECTED: pScsiPhysDev->curTag = tagNum; pScsiPhysDev->connected = TRUE; break; case SCSI_DEV_COMPLETED: pScsiPhysDev->curTag = NONE; pScsiPhysDev->connected = FALSE; if (tagNum == SCSI_TAG_NONE) { pScsiPhysDev->nexus = (pScsiPhysDev->pendingCA) ? pScsiPhysDev->savedNexus : SCSI_NEXUS_NONE; } else if (--pScsiPhysDev->nTaggedNexus == 0) pScsiPhysDev->nexus = SCSI_NEXUS_NONE; break; default: logMsg ("scsiMgrPhysDevEvent: device 0x%08x: " "invalid event type (%d)\n", (int) pScsiPhysDev, eventType, 0, 0, 0, 0); break; } }/********************************************************************************* scsiMgrPhysDevWaitQAdd - add a thread to a physical device's wait queue** Insert a thread into the priority-ordered queue of pending requests for* a physical device. Requests of the same priority are queued in FIFO* order. Threads which are recovering from contingent allegiance condition* (i.e. have tag type SENSE_RECOVERY) are considered to have higher priority* than all other threads waiting for the device.** The wait queue is examined to determine the next thread that may be* despatched on the device - see "scsiMgrPhysDevRunnableThreadGet()".** NOTE:* Treating the SENSE_RECOVERY tag type as an extra-high priority is a* debatable design. It may be better to just queue it in correct priority* order and have "scsiMgrPhysDevRunnableThreadGet()" scan the wait queue for* the first thread with this tag type, when the device has a contingent* allegiance condition.** RETURNS: N/A*/LOCAL void scsiMgrPhysDevWaitQAdd ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_THREAD * pThread ) { NODE * pPrev = 0; if (pThread->tagType != SCSI_TAG_SENSE_RECOVERY) { SCSI_THREAD * pCur; for (pCur = (SCSI_THREAD *) lstFirst (&pScsiPhysDev->waitingThreads); pCur != 0; pCur = (SCSI_THREAD *) lstNext ((NODE *) pCur)) { if ((pCur->tagType != SCSI_TAG_SENSE_RECOVERY) && SCSI_IS_HIGHER_PRIORITY (pThread->priority, pCur->priority)) break; pPrev = (NODE *) pCur; } } lstInsert (&pScsiPhysDev->waitingThreads, pPrev, (NODE *) pThread); }/********************************************************************************* scsiMgrPhysDevWaitQRemove - remove a thread from a phys dev's wait queue** NOTE:* It would be nice if "lstDelete()" told you whether or not the target node* was on the list - then three would be no need to have the "lstFind" first.** RETURNS: OK, or ERROR if the thread was not on the queue.*/LOCAL STATUS scsiMgrPhysDevWaitQRemove ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_THREAD * pThread ) { if (lstFind (&pScsiPhysDev->waitingThreads, (NODE *) pThread) == ERROR) return (ERROR); lstDelete (&pScsiPhysDev->waitingThreads, (NODE *) pThread); return (OK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -