📄 scsimgrlib.c
字号:
}/********************************************************************************* scsiMgrPhysDevRunnableThreadGet - find a runnable thread on this phys dev** If the physical device is connected, no new thread can be started.* Otherwise, the thread at the front of the wait queue is the only thread to* consider (it is the highest priority thread waiting for access to this* device). If there is such a thread, consider its tag type and the current* nexus type on the physical device to determine whether or not the thread* can be started.** Essentially, if the device currently has an ITL nexus it cannot have any* new threads started. If it has an ITLQ nexus, another tagged thread can be* started provided there is a tag available, or a sense recovery (untagged)* thread can be started.** RETURNS: the highest priority thread which can be started on this device,* or 0 if no threads are available or the device can't start a new thread.*/LOCAL SCSI_THREAD * scsiMgrPhysDevRunnableThreadGet ( SCSI_PHYS_DEV * pScsiPhysDev ) { BOOL canStart; SCSI_THREAD * pThread; if (pScsiPhysDev->connected) return (NULL); pThread = (SCSI_THREAD *) lstFirst (&pScsiPhysDev->waitingThreads); if (pThread == 0) return (NULL); switch (pScsiPhysDev->nexus) { case SCSI_NEXUS_NONE: canStart = TRUE; break; case SCSI_NEXUS_ITL: canStart = FALSE; break; case SCSI_NEXUS_ITLQ: canStart = (pScsiPhysDev->nFreeTags != 0) || (pThread->tagType == SCSI_TAG_SENSE_RECOVERY); break; default: logMsg ("scsiMgrPhysDevRunnableThreadGet: device 0x%08x: " "invalid nexus (%d)\n", (int) pScsiPhysDev, pScsiPhysDev->nexus, 0, 0, 0, 0); canStart = FALSE; break; } return (canStart ? pThread : 0); }/********************************************************************************* scsiMgrPhysDevActiveQAdd - add a thread to a phys dev's active queue** Simply insert the thread onto the list. The list is unordered.** RETURNS: N/A*/LOCAL void scsiMgrPhysDevActiveQAdd ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_THREAD * pThread ) { lstInsert (&pScsiPhysDev->activeThreads, 0, (NODE *) pThread); }/********************************************************************************* scsiMgrPhysDevActiveQRemove - remove a thread from a phys dev's active 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 scsiMgrPhysDevActiveQRemove ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_THREAD * pThread ) { if (lstFind (&pScsiPhysDev->activeThreads, (NODE *) pThread) == ERROR) return (ERROR); lstDelete (&pScsiPhysDev->activeThreads, (NODE *) pThread); return (OK); }/********************************************************************************* scsiMgrPhysDevActiveThreadFind - find thread corresponding to tag on phys dev** Search the physical device's active thread list to find one corresponding to* the given tag number.** NOTE:* This function should not be called by application programs.** RETURNS: thread ptr, or 0 if no active thread corresponding to this tag** NOMANUAL*/SCSI_THREAD * scsiMgrPhysDevActiveThreadFind ( SCSI_PHYS_DEV * pScsiPhysDev, /* physical device to search */ SCSI_TAG tagNum /* tag number, or SCSI_TAG_NONE */ ) { SCSI_THREAD * pThread; for (pThread = (SCSI_THREAD *) lstFirst (&pScsiPhysDev->activeThreads); pThread != 0; pThread = (SCSI_THREAD *) lstNext ((NODE *) pThread)) { if (pThread->tagNumber == tagNum) return (pThread); } return (0); }/********************************************************************************* scsiMgrPhysDevTagInit - initialise tag table for a physical device** Set all tags not in use; reset the free tag count and next free tag number.** RETURNS: N/A** NOMANUAL*/VOID scsiMgrPhysDevTagInit ( SCSI_PHYS_DEV * pScsiPhysDev ) { UINT nTags = pScsiPhysDev->nTags; SCSI_TAG tagNum; /* * Initialise "dummy" tag used for untagged threads */ pScsiPhysDev->untagged.inUse = FALSE; /* * Set all real tags to "available" */ for (tagNum = 0; tagNum < nTags; ++tagNum) { SCSI_TAG_INFO * pTag = pScsiPhysDev->pTagInfo + tagNum; pTag->inUse = FALSE; } pScsiPhysDev->nFreeTags = nTags; pScsiPhysDev->nextTag = (nTags == 0) ? SCSI_TAG_NONE : 0; }/********************************************************************************* scsiMgrPhysDevTagAllocate - allocate a tag number on the physical device** Validate the requested tag type; if it is tagged, allocate a tag number* on the physical device.** The actual tag number allocated has no significance other than that it* identifies an active thread on the physical device. In particular, it has* no bearing on the order in which the target executes the command. Thus the* choice of tag number is somewhat arbitrary; however, this routine attempts* to use tags in rotation rather than continually re-using the same tag* numbers. (This is primarily because it makes debugging somewhat easier.)** NOTE:* An incorrect tag type can result from a bad choice by the client, however* unavailability of free tags can only result from software failure (the SCSI* manager should not be activating a thread on a device which has no tags* free !)** The search for a free tag could get quite slow when the device supports a* large number of tags and they are nearly all in use. In practice this is* not likely to cause problems even with the simple scheme used currently.* A more sophisticated approach would be to store free tag numbers on a* list or queue, however this would use substantial amounts of memory (up to* 256 free tags per physical device).** RETURNS: OK, or ERROR if no tags available*/LOCAL STATUS scsiMgrPhysDevTagAllocate ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_TAG_TYPE tagType, SCSI_TAG * pTagNum ) { BOOL tagged; SCSI_TAG tagNum; SCSI_TAG_INFO * pTag = 0; /* initialise to avoid warning */ if (scsiMgrPhysDevTagTypeValidate (pScsiPhysDev, tagType, &tagged) != OK) return (ERROR); if (!tagged) { tagNum = SCSI_TAG_NONE; pTag = &pScsiPhysDev->untagged; } else { int i; if (pScsiPhysDev->nFreeTags == 0) { logMsg ("scsiMgrPhysDevTagAllocate: device 0x%08x: no free tags\n", (int) pScsiPhysDev, 0, 0, 0, 0, 0); errnoSet (S_scsiLib_SOFTWARE_ERROR); return (ERROR); } --pScsiPhysDev->nFreeTags; /* * Search for a free tag; starting at one after we last used */ tagNum = pScsiPhysDev->nextTag; for (i = 0; i < pScsiPhysDev->nTags; ++i) { pTag = (pScsiPhysDev->pTagInfo + tagNum); if (!pTag->inUse) break; if (++tagNum >= pScsiPhysDev->nTags) tagNum = 0; } if (i == pScsiPhysDev->nTags) { logMsg ("scsiMgrPhysDevTagAllocate: device 0x%08x: " "tag not found (%d free)\n", (int) pScsiPhysDev, pScsiPhysDev->nTags, 0, 0, 0, 0); errnoSet (S_scsiLib_SOFTWARE_ERROR); return (ERROR); } if ((pScsiPhysDev->nextTag = tagNum + 1) == pScsiPhysDev->nTags) pScsiPhysDev->nextTag = 0; } pTag->inUse = TRUE; *pTagNum = tagNum; return (OK); }/********************************************************************************* scsiMgrPhysDevTagFree - free a tag for the physical device.** Mark the specified tag not in use.** RETURNS: OK, or ERROR if no tags available*/LOCAL void scsiMgrPhysDevTagFree ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_TAG tagNum ) { SCSI_TAG_INFO * pTag; if (tagNum == SCSI_TAG_NONE) { pTag = &pScsiPhysDev->untagged; } else { ++pScsiPhysDev->nFreeTags; pTag = (pScsiPhysDev->pTagInfo + tagNum); } pTag->inUse = FALSE; }/********************************************************************************* scsiMgrPhysDevTagTypeValidate - validate requested tag type for phys dev** Check the requested tag type is valid given the current nexus type of the* device. Note the special cases which allow an untagged sense recovery* command to be started when the device has tagged nexuses active, provided* it is in a contingent allegiance condition.** RETURNS: OK, or ERROR if the requested tag type is (currently) invalid*/LOCAL STATUS scsiMgrPhysDevTagTypeValidate ( SCSI_PHYS_DEV * pScsiPhysDev, SCSI_TAG_TYPE tagType, BOOL * pTagged ) { BOOL valid; BOOL tagged; switch (tagType) { case SCSI_TAG_UNTAGGED: valid = (pScsiPhysDev->nexus != SCSI_NEXUS_ITLQ); tagged = FALSE; break; case SCSI_TAG_SENSE_RECOVERY: valid = (pScsiPhysDev->nexus != SCSI_NEXUS_ITLQ) || pScsiPhysDev->pendingCA; tagged = FALSE; break; case SCSI_TAG_SIMPLE: case SCSI_TAG_ORDERED: case SCSI_TAG_HEAD_OF_Q: valid = (pScsiPhysDev->nexus != SCSI_NEXUS_ITL) && (pScsiPhysDev->tagType != SCSI_TAG_UNTAGGED); tagged = TRUE; break; default: valid = FALSE; tagged = FALSE; break; } if (!valid) { SCSI_DEBUG_MSG ("scsiPhysDevTagTypeValidate: invalid tag type (%d) " "for device 0x%08x\n", tagType, (int) pScsiPhysDev, 0, 0, 0, 0); errnoSet (S_scsiLib_INVALID_TAG_TYPE); return (ERROR); } *pTagged = tagged; return (OK); }/********************************************************************************* scsiMgrShow - show status information for the SCSI manager** This routine shows the current state of the SCSI manager for the specified* controller, including the total number of threads created and the number of* threads currently free.** Optionally, this routine also shows details for all created physical devices * on this controller and all threads for which SCSI requests are outstanding.* It also shows the IDs of all free threads.** NOTE: The information displayed is volatile; this routine is best used when* there is no activity on the SCSI bus. Threads allocated by a client but* for which there are no outstanding SCSI requests are not shown.** RETURNS: N/A*/void scsiMgrShow ( SCSI_CTRL * pScsiCtrl, /* SCSI controller to use */ BOOL showPhysDevs, /* TRUE => show phys dev details */ BOOL showThreads, /* TRUE => show thread details */ BOOL showFreeThreads /* TRUE => show free thread IDs */ ) { char * state; int nFree; if (pScsiCtrl == NULL) pScsiCtrl = pSysScsiCtrl; if (pScsiCtrl == NULL) { printf ("No SCSI controller specified.\n"); return; } state = pScsiCtrl->active ? "active" : "inactive"; nFree = lstCount (&pScsiCtrl->freeThreads); printf ("Controller State # Threads (tot/free)\n"); printf ("---------- -------- --------------------\n"); printf ("0x%08x %-8s %3d %3d\n", (int) pScsiCtrl, state, pScsiCtrl->nThreads, nFree); if (showPhysDevs) { BOOL noHeader = FALSE; int i; printf ("\n"); for (i = 0; i < SCSI_MAX_PHYS_DEVS; ++i) { SCSI_PHYS_DEV * pScsiPhysDev = pScsiCtrl->physDevArr[i]; if (pScsiPhysDev != 0) { scsiPhysDevShow (pScsiPhysDev, FALSE, noHeader); noHeader = TRUE; } } } if (showThreads) { /* * This is crude. A better approach would be to collect all * the thread IDs into a buffer, then sort by priority before * calling "scsiThreadShow" for each thread. */ int i; printf ("\n"); for (i = 0; i < SCSI_MAX_PHYS_DEVS; ++i) { SCSI_PHYS_DEV * pScsiPhysDev = pScsiCtrl->physDevArr[i]; if (pScsiPhysDev != 0) { scsiThreadListShow (&pScsiPhysDev->activeThreads); scsiThreadListShow (&pScsiPhysDev->waitingThreads); } } } if (showFreeThreads && (nFree != 0)) { printf ("\nFree threads:\n"); scsiThreadListIdShow (&pScsiCtrl->freeThreads); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -