⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsimgrlib.c

📁 the vxworks system kernel souce packeg.there may be something you need .
💻 C
📖 第 1 页 / 共 4 页
字号:
/* scsiMgrLib.c - SCSI manager library (SCSI-2) *//* Copyright 1989-1996 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------03d,10jul97,dds  added library support for adaptec chips.01c,29oct96,dgp  doc: editing for newly published SCSI libraries01b,21oct96,dds  removed NOMANUAL from functions called by                  the driver interface.01a,12sep96,dds  added the scsiMgr routines from scsi2Lib.c*//*DESCRIPTIONThis SCSI-2 library implements the SCSI manager.  The purpose of the SCSImanager is to manage SCSI threads between requesting VxWorks tasks and theSCSI controller.  The SCSI manager handles SCSI events and SCSI threadsbut allocation and de-allocation of SCSI threads is not the manager'sresponsiblity.  SCSI thread management includes despatching threads andscheduling multiple threads (which are performed by the SCSI manager, plusallocation and de-allocation of threads (which are performed by routines inscsi2Lib).The SCSI manager is spawned as a VxWorks task upon initializationof the SCSI interface within VxWorks. The entry point of the SCSI manager taskis scsiMgr(). The SCSI manager task is usually spawned during initialization of the SCSI controller driver. The driver's xxxCtrlCreateScsi2() routine is typically responsible for such SCSI interfaceinitializations.Once the SCSI manager has been initialized, it is ready to handle SCSIrequests from VxWorks tasks. The SCSI manager has the following resposibilities:.iPIt processes requests from client tasks. .iPIt activates a SCSI transaction thread by appending it to the targetdevice's wait queue and allocating a specified time periodto execute a transaction..iPIt handles timeout events which cause threads to be aborted..iPIt receives event notifications from the SCSI driver interrupt serviceroutine (ISR) and processes the event..iPIt responds to events generated by the controller hardware, such asdisconnection and information transfer requests..iPIt replies to clients when their requests have completed oraborted..LPOne SCSI manager task must be spawned per SCSI controller. Thus, if a particular hardware platform contains more than one SCSI controller thenthat number of SCSI manager tasks must be spawned by the controller-driverintialization routine.INCLUDE FILESscsiLib.h, scsi2Lib.hSEE ALSO: scsiLib, scsi2Lib, scsiCommonLib, scsiDirectLib, scsiSeqLib, scsiCtrlLib,.I  "American National Standard for Information Systems - Small Computer".I  "System Interface (SCSI-2), ANSI X3T9,".pG "I/O System, Local File Systems"*/#define  INCLUDE_SCSI2#include "vxWorks.h"#include "ioLib.h"#include "intLib.h"#include "ctype.h"#include "cacheLib.h"#include "stdlib.h"#include "errnoLib.h"#include "taskLib.h"#include "lstLib.h"#include "logLib.h"#include "msgQLib.h"#include "string.h"#include "stdio.h"#include "sysLib.h"#include "scsiLib.h"#include "wdLib.h"/* globals variables */int scsiMgrActionSemOptions = SEM_Q_FIFO;   /* only one task waits on it */int scsiThreadReplyQOptions = MSG_Q_FIFO;   /* only one task waits on it */int scsiMgrEventQSize       = SCSI_DEF_EVENT_Q_SIZE;int scsiMgrTimeoutQSize     = SCSI_DEF_TIMEOUT_Q_SIZE;int scsiMgrRequestQSize     = SCSI_DEF_REQUEST_Q_SIZE;int scsiMgrReplyQSize       = SCSI_DEF_REPLY_Q_SIZE;/* global functions */STATUS 	    scsiMgrRequestExecute  (SCSI_CTRL    * pScsiCtrl,				    SCSI_REQUEST * pRequest,				    SCSI_REPLY   * pReply);VOID        scsiMgrPhysDevTagInit  (SCSI_PHYS_DEV * pScsiPhysDev);/*  SCSI system manager functions */LOCAL BOOL   	    scsiMgrMsgGet (RING_ID queueId, void * buffer, int length);LOCAL void   	    scsiMgrEventProc   (SCSI_CTRL  * pScsiCtrl, 					SCSI_EVENT * pEvent);LOCAL void   	    scsiMgrTimeoutProc (SCSI_CTRL * pScsiCtrl, 						SCSI_TIMEOUT * pTimeout);LOCAL void   	    scsiMgrRequestProc (SCSI_CTRL * pScsiCtrl, 						SCSI_REQUEST * pRequest);LOCAL void   	    scsiMgrReplyProc   (SCSI_CTRL *  pScsiCtrl, 					SCSI_REPLY * pReply);LOCAL void   	    scsiMgrActivateRequest (SCSI_REQUEST * pRequest);LOCAL void   	    scsiMgrRequestComplete (SCSI_THREAD  * pThread);LOCAL void   	    scsiMgrCompleteReply   (SCSI_REPLY   * pReply);LOCAL void   	    scsiMgrTimeoutNotify   (SCSI_THREAD  * pThread);LOCAL SCSI_THREAD * scsiMgrRunnableThreadGet (SCSI_CTRL * pScsiCtrl);LOCAL void    	    scsiMgrThreadDespatch (SCSI_THREAD * pThread);LOCAL void    	    scsiMgrThreadComplete (SCSI_THREAD * pThread);LOCAL void    	    scsiMgrThreadDefer    (SCSI_THREAD * pThread);LOCAL STATUS  	    scsiMgrThreadActivate (SCSI_THREAD * pThread);LOCAL void    	    scsiMgrPhysDevReset (SCSI_PHYS_DEV * pScsiPhysDev);LOCAL void    	    scsiMgrPhysDevEvent (SCSI_PHYS_DEV      * pScsiPhysDev,				   	  SCSI_TAG            tagNum,				   	  SCSI_DEV_EVENT_TYPE type);LOCAL SCSI_THREAD *scsiMgrPhysDevRunnableThreadGet 					       (SCSI_PHYS_DEV * pScsiPhysDev);LOCAL void         scsiMgrPhysDevWaitQAdd      (SCSI_PHYS_DEV * pScsiPhysDev,						SCSI_THREAD   * pThread);LOCAL STATUS       scsiMgrPhysDevWaitQRemove   (SCSI_PHYS_DEV * pScsiPhysDev,						SCSI_THREAD   * pThread);LOCAL void         scsiMgrPhysDevActiveQAdd    (SCSI_PHYS_DEV * pScsiPhysDev,						SCSI_THREAD   * pThread);LOCAL STATUS       scsiMgrPhysDevActiveQRemove (SCSI_PHYS_DEV * pScsiPhysDev,						SCSI_THREAD   * pThread);LOCAL STATUS       scsiMgrPhysDevTagAllocate   (SCSI_PHYS_DEV * pScsiPhysDev,						SCSI_TAG_TYPE   tagType,						SCSI_TAG      * pTagNum);LOCAL void         scsiMgrPhysDevTagFree       (SCSI_PHYS_DEV * pScsiPhysDev,						SCSI_TAG       tagNum);LOCAL STATUS       scsiMgrPhysDevTagTypeValidate (SCSI_PHYS_DEV * pScsiPhysDev,						  SCSI_TAG_TYPE  tagType,						  BOOL          * pTagged);/********************************************************************************* scsiMgr - SCSI system manager** Manage a SCSI (bus interface) controller.  This entails:**   -	carrying out requests on behalf of client tasks to perform SCSI*   	operations on threads, such as executing a transaction**   -	responding to events generated by the controller hardware, such as*   	disconnection, information transfer request, etc.**   -	handling timeout events which cause threads to be aborted**   -	replying to clients when their requests have been completed or*   	aborted.** NOTE* This function should not be called by application programs.  It is normally* spawned automatically by the controller driver to form a SCSI manager task* for each SCSI interface.** INTERNAL** The details of controller event handling are hardware-specific.  The event* message and event handling routines are made "virtual", i.e. implemented* by the controller driver.** The order in which the various events and requests are processed is* important and must not be changed.  Reasons for this vary from obvious to* pretty subtle - see comments for other "scsiMgr...()" functions for further* information.** RETURNS: this function does not normally return** NOMANUAL*/void scsiMgr    (    SCSI_CTRL * pScsiCtrl		/* SCSI controller to be used */    )    {    SCSI_REQUEST  request;    SCSI_REPLY    reply;    SCSI_TIMEOUT  timeout;    SCSI_EVENT  * pEvent;    SCSI_THREAD * pThread;        /* initialise */    pEvent = malloc (pScsiCtrl->eventSize);    if (pEvent == NULL)	return;    /*     *	Service loop     */    while (TRUE)	{	/*	 *  Wait for an event, timeout or client request to be posted	 */	semTake (pScsiCtrl->actionSem, WAIT_FOREVER);	/*	 *  Service all controller events ...	 */	while (scsiMgrMsgGet (pScsiCtrl->eventQ, pEvent, pScsiCtrl->eventSize))	    {	    scsiMgrEventProc (pScsiCtrl, pEvent);	    }	/*	 *  Service any timeouts ...	 */	while (scsiMgrMsgGet (pScsiCtrl->timeoutQ, &timeout, sizeof (timeout)))	    {	    scsiMgrTimeoutProc (pScsiCtrl, &timeout);	    }	/*	 *  Service any client requests ...	 */	while (scsiMgrMsgGet (pScsiCtrl->requestQ, &request, sizeof (request)))	    {	    scsiMgrRequestProc (pScsiCtrl, &request);	    }	/*	 *  Forward any replies to clients ...	 */	while (scsiMgrMsgGet (pScsiCtrl->replyQ, &reply, sizeof (reply)))	    {	    scsiMgrReplyProc (pScsiCtrl, &reply);	    }	/*	 *  ... finally, despatch the highest priority request if possible	 */	if ((pThread = scsiMgrRunnableThreadGet (pScsiCtrl)) != 0)	    {    	    scsiMgrThreadDespatch (pThread);	    }	}    }/********************************************************************************* scsiMgrMsgGet - get the next message, if any, from a SCSI manager msg queue** Extract the next message, if any is available, from the specified queue and* copy it into the specified buffer.  If no message is available, do not wait.** NOTE:* SCSI manager message queues are implemented using ring buffers because there* is a separate mechanism for synchronisation.  This code is careful to* always read complete messages from the ring buffer.  A single reader (i.e.,* the SCSI manager task) is assumed.*/LOCAL BOOL scsiMgrMsgGet    (    RING_ID queue,			/* SCSI manager msg queue to read */    void *  buffer,			/* buffer to copy msg into        */    int     length			/* (exact) length of msg expected */    )    {    if (rngNBytes (queue) < length)	return (FALSE);    if (rngBufGet (queue, buffer, length) != length)	{	logMsg ("scsiMgrMsgGet: rngBufGet failed\n", 0, 0, 0, 0, 0, 0);	return (FALSE);	}        return (TRUE);    }/********************************************************************************* scsiMgrEventProc - process a SCSI controller event** Call the appropriate controller-specific function to process the event.** NOTE:* This function exists primarily as a place-holder for debugging and possible* future enhancements such as event logging.*/LOCAL void scsiMgrEventProc    (    SCSI_CTRL *  pScsiCtrl,    SCSI_EVENT * pEvent    )    {    (*pScsiCtrl->scsiEventProc) (pScsiCtrl, pEvent);    }/********************************************************************************* scsiMgrTimeoutProc - process a request timeout event** First try to remove the thread from the device's wait queue.  If it was* on the queue, simply complete the request (with a timeout error) because* it has not yet had a tag allocated, etc.** If the thread wasn't on the device's wait queue, see whether its tag number* corresponds to a current thread.  If not, the thread must have completed,* so the timeout request can be ignored.** If the tag number corresponds to an in-progress thread, call the controller* thread abort routine.  If this returns TRUE, the thread is currently active* on the controller, which will manage the abort process.  Otherwise (the* thread is not currently active on the controller) abort it here.** Possible race conditions and how they are avoided:**   1)	thread completes "just before" the watchdog expires.  The following*   	cases may occur:**   	a)  thread completion event and timeout event are processed in the*   	    same SCSI manager activation cycle.  In this case, the thread's*   	    tag number must be free (timeouts are processed before any new*   	    threads are started) and the timeout will be ignored.**   	b)  thread completion event is processed but no timeout event occurs*   	    in the same activation cycle.  In this case, a new thread using*   	    the same tag number may have been started by the time the next*   	    activation cycle occurs.  However, since the first thread's*   	    watchdog is cancelled during completion processing in the first*   	    cycle, if a timeout event has not occurred by the end of that*   	    cycle, it can never occur and the newly activated thread is safe.**   2)	thread completion occurs "just after" the watchdog expires.  In this*   	case, the completion event will not be processed until the next*   	activation cycle at the earliest.  There are two cases:**   	a)  the thread is currently active on the controller when the timeout*   	    is processed: in this case, the controller driver's abort routine*   	    must ensure that the thread is (possibly) aborted and (definitely)*   	    completed, in that order.  It doesn't necessarily do this in a*   	    single activation cycle.**   	b)  the thread is not currently active on the controller when the*   	    timeout occurs: in this case, the request is completed with a*   	    timeout error and the tag is marked aborted in the first cycle.*   	    When an attempt is later made to re-establish this thread, the*   	    identification will fail due to the aborted state of the tag.*   	    The controller driver must detect this and force the connected*   	    device to disconnect, after which it must free up the tag for*   	    re-use by another thread.** NOTE:* This routine is complex because completion of the thread (i.e. replying to* the client) must be decoupled from what is happening on the SCSI bus, if* the timeout is to be useful.  This implies that even after the thread has* been completed, the corresponding nexus may continue to exist on the* target device.  This is sorted out by the physical device event processing* (see "scsiMgrPhysDevEvent ()").** RETURNS: N/A*/LOCAL void scsiMgrTimeoutProc    (    SCSI_CTRL *    pScsiCtrl,    SCSI_TIMEOUT * pTimeout    )    {    SCSI_THREAD   * pThread      = pTimeout->thread;    SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;    SCSI_TAG        tagNum       = pThread->tagNumber;    BOOL doAbort;    SCSI_DEBUG_MSG ("scsiMgrTimeoutProc: thread 0x%08x (state = %d) timed out\n"    				, (int) pThread, pThread->state, 0, 0, 0, 0);    /*     *	Ensure thread is not in device's wait queue     */    if (scsiMgrPhysDevWaitQRemove (pScsiPhysDev, pThread) == OK)	{	doAbort = TRUE;	}    /*     *	Thread is either current or completed: look up tag to decide     */    else if (scsiMgrPhysDevActiveThreadFind (pScsiPhysDev, tagNum) != pThread)	{	doAbort = FALSE;	}    /*     *	Thread is current: call controller to abort if connected.     */    else if ((*pScsiCtrl->scsiThreadAbort) (pScsiCtrl, pThread))	{	doAbort = FALSE;	}    /*     *	Thread is current, but not connected.  Remove thread from active     *	list and complete the request.  Tag completion will be handled     *	by controller driver when reconnection occurs.     */    else	{	if (scsiMgrPhysDevActiveQRemove (pScsiPhysDev, pThread) != OK)	    {	    logMsg ("scsiMgrTimeoutProc: thread not on active queue !\n",		    0, 0, 0, 0, 0, 0);	    return;	    }	doAbort = TRUE;	}    /*     *	If "doAbort" is true, the thread must be completed now and it has     *	been removed from the device's wait or active queue.  If "doAbort"     *  is false, either the thread has already been completed or the     *  controller driver will complete it in due course.     */    if (doAbort)	{    	pThread->status = ERROR;    	pThread->errNum = S_scsiLib_ABORTED;    	scsiMgrThreadComplete (pThread);	}    }/********************************************************************************* scsiMgrRequestProc - process a client request** Parse the request type and act accordingly.** NOTE* Currently only one request type (activate a transaction) is accepted,* however this routine is intended to allow other request types in future* (e.g., to support SCSI target mode).** RETURNS: N/A*/LOCAL void scsiMgrRequestProc    (    SCSI_CTRL *    pScsiCtrl,    SCSI_REQUEST * pRequest    )    {    SCSI_REQUEST_TYPE type = pRequest->type;    SCSI_DEBUG_MSG ("scsiMgrRequestProc: client request: %d\n",		    type, 0, 0, 0, 0, 0);		        switch (type)	{    	case SCSI_REQUEST_ACTIVATE:	    scsiMgrActivateRequest (pRequest);	    break;    	default:	    logMsg ("scsiMgrRequestProc: invalid action (%d) requested\n",		    type, 0, 0, 0, 0, 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -