📄 templatescsi2.c
字号:
/* templateScsi2.c - Template for a SCSI-2 driver *//* Copyright 1989-1997 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------TODO - Remove the template modification history and begin a new history starting with version 01a and growing the history upward with each revision.01d,24sep97,dat changed arguments to TEMPLATE_REG_READ.01c,20aug97,dat code review comments from Dinesh01b,11aug97,dat fixed compilation bugs.01a,01aug97,dat written (from ncr810Lib.c, ver 01p)*//*DESCRIPTIONTODO - Describe the entire chip completely. If this device is a part ofa larger ASIC, describe the complete device in a single paragraph.TODO - Describe the device completely. Describe all operating modes andcapabilties, whether used or not.TODO - Describe the modes and limitations of this driver. Describe howthis driver interacts with the chip and any limitations imposed by thesoftware. If this driver interacts with other drivers, describe thatinteraction.TODO - Update the remainder of this documentation to reflect your newdriver code.For each controller device we create a manager task to manage the threadson each bus.This driver supports multiple initiators, disconnect/reconnect, taggedcommand queueing and synchronous data transfer protocol. In general, theSCSI system and this driver will automatically choose the best combinationof these features to suit the target devices used. However, the defaultchoices may be over-ridden by using the function "scsiTargetOptionsSet()"(see scsiLib).USER-CALLABLE ROUTINESMost of the routines in this driver are accessible only through the I/Osystem. Three routines, however, must be called directly:templateCtrlCreate() to create a controller structure, and templateCtrlInit()to initialize it.There are debug variables to trace events in the driver.<scsiDebug> scsiLib debug variable, trace event in scsiLib, scsiScsiPhase(),and scsiTransact().<scsiIntsDebug> prints interrupt information.The macro SCSI_DEBUG_MSG(format,...) can be used to insert debuggingmessages anywhere in the code. The debug messages will appear only whenthe global variable scsiDebug is set to a non-zero value.INTERFACEThe BSP must connect the interrupt service routine for the controller deviceto the appropriate interrupt system. The routine to be called istemplateIntr(), and the argument is the pointer to the controller device pSiop.i.e..CS pSiop = templateCtrlCreate (...); intConnect (XXXX, templateIntr, pSiop); templateCtrlInit (pSiop, ...);.CEHARDWARE ACCESSAll hardware access is to be done through macros. The default definitionof the TEMPLATE_REG_READ() and TEMPLATE_REG_WRITE() macros assumes amemory mapped i/o model. The macros can be redefined as necessary to accomodate other models, and situations where timing and write pipeconsiderations need to be addressed.The macro TEMPLATE_REG_READ(pDev, reg,result) is used to read abyte from a specified register. The three arguments are the device structurepointer, the register id (element of the dev structure), and the variable (not a pointer) to receive the register contents.(If the third argument were a pointer, then it would affect compileroptimization and could lead to inefficient code generation).The macro TEMPLATE_REG_WRITE(pDev, reg,data) is used to write data to thespecified register address. These macros presume memory mapped i/o bydefault. Both macros can be redefined to tailor the driver to some otheri/o model.INCLUDE FILESscsiLib.h*/#define INCLUDE_SCSI2 /* This is a SCSI2 driver */#include "vxWorks.h"#include "memLib.h"#include "ctype.h"#include "stdlib.h"#include "string.h"#include "stdio.h"#include "logLib.h"#include "semLib.h"#include "intLib.h"#include "errnoLib.h"#include "cacheLib.h"#include "taskLib.h"#include "scsiLib.h"/* defines *//* state enumeration, different hardware states for the controller */typedef enum templateState /* TEMPLATE_STATE */ { TEMPLATE_STATE_IDLE = 0, /* not running any script */ TEMPLATE_STATE_PASSIVE, /* waiting for reselect or host cmd */ TEMPLATE_STATE_ACTIVE /* running a client script */ } TEMPLATE_STATE;/* Hardware specific events, supplements the SCSI_EVENT types */typedef enum templateEvent /* TEMPLATE_EVENT_TYPE, hardware events */ { TEMPLATE_SINGLE_STEP=30, /* don't conflict with SCSI_EVENTS */ TEMPLATE_ABORT, TEMPLATE_UNEXPECTED_DISCON, TEMPLATE_SCSI_TIMEOUT, TEMPLATE_HANDSHAKE_TIMEOUT, TEMPLATE_PHASE_MISMATCH, TEMPLATE_SCRIPT_ABORTED, TEMPLATE_SCSI_COMPLETE, TEMPLATE_FATAL_ERROR, TEMPLATE_MESSAGE_OUT_SENT, TEMPLATE_MESSAGE_IN_RECVD, TEMPLATE_NO_MSG_OUT, TEMPLATE_EXT_MESSAGE_SIZE, TEMPLATE_ILLEGAL_PHASE, } TEMPLATE_EVENT_TYPE;/* identifiers for the different hardware scripts the device can execute */typedef enum templateScriptEntry /* TEMPLATE_SCRIPT_ENTRY */ { TEMPLATE_SCRIPT_WAIT = 0, /* wait for re-select or host cmd */ TEMPLATE_SCRIPT_INIT_START = 1, /* start an initiator thread */ TEMPLATE_SCRIPT_INIT_CONTINUE = 2, /* continue an initiator thread */ TEMPLATE_SCRIPT_TGT_DISCONNECT = 3 /* disconnect a target thread */ } TEMPLATE_SCRIPT_ENTRY;/* The expanded EVENT structure, with add'l device specific info */typedef struct { /* TEMPLATE_EVENT, extended EVENT type */ SCSI_EVENT scsiEvent; int remCount; } TEMPLATE_EVENT;/* The expanded THREAD structure, with add'l device specific info */typedef struct templateThread /* TEMPLATE_THREAD, extended thread type */ { SCSI_THREAD scsiThread; /* generic SCSI thread structure */ /* TODO - add device specific thread info */ UINT8 nHostFlags; /* DUMMY information */ UINT8 nMsgOutState; /* DUMMY information */ UINT8 nMsgInState; /* DUMMY information */ UINT8 nBusIdBits; /* DUMMY information */ UINT8 nBusPhase; /* DUMMY information */ } TEMPLATE_THREAD;/* The expanded SCSI_CTRL structure with add'l device specific info */typedef struct { /* TEMPLATE_SCSI_CTRL */ SCSI_CTRL scsiCtrl; /* generic SCSI controller info */ /* TODO - add device specific information */ SEM_ID singleStepSem; /* use to debug script in single step mode */ /* Hardware implementation dependencies */ TEMPLATE_THREAD* pIdentThread; TEMPLATE_THREAD* pNewThread;/* DUMMY */ TEMPLATE_THREAD* pHwThread; /* DUMMY */ TEMPLATE_STATE state; /* DUMMY */ UCHAR* pCmd; /* DUMMY Device command/status register */ int devType; /* DUMMY type of device (see define's below) */ BOOL resetReportDsbl; /* DUMMY disable SCSI bus reset reporting */ BOOL parityTestMode; /* DUMMY enable parity test mode */ BOOL parityCheckEnbl; /* DUMMY to enable parity checking */ UINT clkPeriod; /* DUMMY period of ctrl clock (nsec x 100) */ UINT8 clkDiv; /* DUMMY async and sync clock divider */ BOOL cmdPending; /* DUMMY task wants to start new command */ BOOL singleStep; /* DUMMY single step mode */ } TEMPLATE_SCSI_CTRL;typedef TEMPLATE_SCSI_CTRL SIOP; /* shorthand *//* Hardware Abstraction macros hide all actual access to the chip */#define TEMPLATE_REG_READ(pSiop, reg, result) \ ((result) = *(pSiop->reg)#define TEMPLATE_REG_WRITE(pSiop, reg, data) \ (*pSiop->reg = data)/* Other miscellaneous defines */#define TEMPLATE_MAX_XFER_WIDTH 1 /* 16 bit wide transfer */#define TEMPLATE_MAX_XFER_LENGTH 0xffffff /* 16MB max transfer *//* Configurable options, scsi manager task */int templateSingleStepSemOptions = SEM_Q_PRIORITY;char* templateScsiTaskName = SCSI_DEF_TASK_NAME;int templateScsiTaskOptions = SCSI_DEF_TASK_OPTIONS;int templateScsiTaskPriority = SCSI_DEF_TASK_PRIORITY;int templateScsiTaskStackSize = SCSI_DEF_TASK_STACK_SIZE;/* forward declarations */LOCAL STATUS templateThreadActivate (SIOP* pSiop, TEMPLATE_THREAD* pThread);LOCAL void templateEvent (SIOP* pSiop, TEMPLATE_EVENT* pEvent);LOCAL STATUS templateThreadInit (SIOP* pSiop, TEMPLATE_THREAD* pThread);LOCAL STATUS templateThreadActivate (SIOP* pSiop, TEMPLATE_THREAD* pThread);LOCAL BOOL templateThreadAbort (SIOP* pSiop, TEMPLATE_THREAD* pThread);LOCAL STATUS templateScsiBusControl (SIOP* pSiop, int operation);LOCAL STATUS templateXferParamsQuery (SCSI_CTRL* pScsiCtrl, UINT8* pOffset, UINT8* pPeriod);LOCAL STATUS templateXferParamsSet (SCSI_CTRL* pScsiCtrl, UINT8 offset, UINT8 period);LOCAL STATUS templateWideXferParamsQuery (SCSI_CTRL* pScsiCtrl, UINT8* xferWidth);LOCAL STATUS templateWideXferParamsSet (SCSI_CTRL* pScsiCtrl, UINT8 xferWidth);LOCAL void templateScriptStart (SIOP* pSiop, TEMPLATE_THREAD* pThread, TEMPLATE_SCRIPT_ENTRY entryId);LOCAL int templateEventTypeGet (SIOP* pSiop);LOCAL STATUS templateThreadParamsSet (TEMPLATE_THREAD*, UINT8, UINT8);LOCAL STATUS templateActivate (SIOP* pSiop, TEMPLATE_THREAD* pThread);LOCAL void templateThreadStateSet (TEMPLATE_THREAD* pThread, SCSI_THREAD_STATE state);LOCAL void templateAbort (SIOP* pSiop);LOCAL void templateThreadEvent (TEMPLATE_THREAD* pThread, TEMPLATE_EVENT* pEvent);LOCAL void templateInitEvent (TEMPLATE_THREAD* pThread, TEMPLATE_EVENT* pEvent);LOCAL void templateThreadUpdate (TEMPLATE_THREAD* pThread);LOCAL void templateInitIdentEvent(TEMPLATE_THREAD* pThread, TEMPLATE_EVENT* pEvent);LOCAL void templateIdentInContinue (TEMPLATE_THREAD *pThread);LOCAL STATUS templateResume (SIOP* pSiop, TEMPLATE_THREAD* pThread, TEMPLATE_SCRIPT_ENTRY entryId);LOCAL void templateThreadFail (TEMPLATE_THREAD* pThread, int errNum);LOCAL void templateThreadComplete (TEMPLATE_THREAD* pThread);LOCAL void templateThreadDefer (TEMPLATE_THREAD* pThread);LOCAL STATUS templatePhaseMismatch (TEMPLATE_THREAD* pThread, int phase, UINT remCount);LOCAL void templateThreadReconnect (TEMPLATE_THREAD* pThread);/********************************************************************************* templateCtrlCreate - create a structure for a TEMPLATE device** This routine creates a SCSI Controller data structure and must be called * before using an SCSI Controller chip. It should be called once and only * once for a specified SCSI Controller controller. Since it allocates memory* for a structure needed by all routines in templateLib, it must be called* before any other routines in the library. After calling this routine,* templateCtrlInit() should be called at least once before any SCSI* transactions are initiated using the SCSI Controller.** RETURNS: A pointer to TEMPLATE_SCSI_CTRL structure, or NULL if memory * is unavailable or there are invalid parameters.*/TEMPLATE_SCSI_CTRL *templateCtrlCreate ( /* TODO - This argument list is device specific information */ UINT8* baseAdrs, /* DUMMY, base address of the SCSI Controller */ UINT clkPeriod, /* DUMMY, clock controller period (nsec*100) */ UINT16 devType /* DUMMY, SCSI device type */ ) { FAST SIOP *pSiop; /* ptr to SCSI Controller info */ SCSI_CTRL *pScsiCtrl; /* TODO - cacheDmaMalloc the controller struct and any shared data areas */ pScsiCtrl = &(pSiop->scsiCtrl); /* fill in generic SCSI info for this controller */ pScsiCtrl->eventSize = sizeof (TEMPLATE_EVENT); pScsiCtrl->threadSize = sizeof (TEMPLATE_THREAD); pScsiCtrl->maxBytesPerXfer = TEMPLATE_MAX_XFER_LENGTH; pScsiCtrl->wideXfer = FALSE; pScsiCtrl->scsiTransact = (FUNCPTR) scsiTransact; pScsiCtrl->scsiEventProc = (VOIDFUNCPTR) templateEvent; pScsiCtrl->scsiThreadInit = (FUNCPTR) templateThreadInit; pScsiCtrl->scsiThreadActivate = (FUNCPTR) templateThreadActivate; pScsiCtrl->scsiThreadAbort = (FUNCPTR) templateThreadAbort; pScsiCtrl->scsiBusControl = (FUNCPTR) templateScsiBusControl; pScsiCtrl->scsiXferParamsQuery = (FUNCPTR) templateXferParamsQuery; pScsiCtrl->scsiXferParamsSet = (FUNCPTR) templateXferParamsSet; pScsiCtrl->scsiWideXferParamsQuery = (FUNCPTR) templateWideXferParamsQuery; pScsiCtrl->scsiWideXferParamsSet = (FUNCPTR) templateWideXferParamsSet; /* TODO - fill in device specific data for this controller */ scsiCtrlInit (pScsiCtrl); /* Create synchronisation semaphore for single-step support */ pSiop->singleStepSem = semBCreate (templateSingleStepSemOptions, SEM_EMPTY); /* TODO - Initialize fields in any client shared data area */ /* spawn SCSI manager - use generic code from "scsiLib.c" */ pScsiCtrl->scsiMgrId = taskSpawn (templateScsiTaskName, templateScsiTaskPriority, templateScsiTaskOptions, templateScsiTaskStackSize, (FUNCPTR) scsiMgr, (int) pSiop, 0, 0, 0, 0, 0, 0, 0, 0, 0); return (pSiop); }/********************************************************************************* templateCtrlInit - initialize a SCSI Controller Structure.** This routine initializes an SCSI Controller structure, after the structure* is created with templateCtrlCreate(). This structure must be initialized* before the SCSI Controller can be used. It may be called more than once* if needed; however,it should only be called while there is no activity on* the SCSI interface.** RETURNS: OK, or ERROR if parameters are out of range.*/STATUS templateCtrlInit ( SIOP* pSiop, /* ptr to SCSI Controller struct */ int scsiCtrlBusId /* SCSI bus ID of this SCSI Controller */ ) { SCSI_CTRL* pScsiCtrl = &pSiop->scsiCtrl; pScsiCtrl->scsiCtrlBusId = scsiCtrlBusId; /* TODO - Initialise and reset the SCSI Controller */ templateScriptStart (pSiop, (TEMPLATE_THREAD *)pScsiCtrl->pIdentThread, TEMPLATE_SCRIPT_WAIT); pSiop->state = TEMPLATE_STATE_PASSIVE; return (OK); }/********************************************************************************* templateIntr - interrupt service routine for the SCSI Controller** The first thing to determine is if the device is generating an interrupt.* If not, then this routine must exit as quickly as possible.** Find the event type corresponding to this interrupt, and carry out any* actions which must be done before the SCSI Controller is re-started. * Determine whether or not the SCSI Controller 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 SCSI Controller wait for something * else to happen.** Notify the SCSI manager of a controller event.** RETURNS: N/A*/void templateIntr ( SIOP *pSiop ) { TEMPLATE_EVENT event; SCSI_EVENT* pScsiEvent = (SCSI_EVENT *) &event.scsiEvent; BOOL connected = TRUE; BOOL notify = TRUE; TEMPLATE_STATE oldState = (int) pSiop->state; /* TODO - If device is not interrupting, then return immediately */ /* TODO - Save (partial) Controller register context in current thread */ pScsiEvent->type = templateEventTypeGet (pSiop); /* Synchronise with single-step routine, if enabled. */ if (pSiop->singleStep) semGive (pSiop->singleStepSem); if (pScsiEvent->type == TEMPLATE_SINGLE_STEP) return; switch (pScsiEvent->type) { /* * TODO - * For events where the bus is not connected to a target, * set connected=FALSE. * * For events not requiring scsi manager, set notify = FALSE. */ /* Generic event types */ case SCSI_EVENT_SELECTED: case SCSI_EVENT_RESELECTED: case SCSI_EVENT_DISCONNECTED: case SCSI_EVENT_BUS_RESET: /* device specific events */ case TEMPLATE_ABORT: case TEMPLATE_UNEXPECTED_DISCON: case TEMPLATE_SCSI_TIMEOUT: case TEMPLATE_HANDSHAKE_TIMEOUT: case TEMPLATE_PHASE_MISMATCH: case TEMPLATE_SCRIPT_ABORTED: case TEMPLATE_SCSI_COMPLETE: case TEMPLATE_SINGLE_STEP: case TEMPLATE_FATAL_ERROR: default: connected = TRUE; notify = TRUE; } /* * 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 device idle. It will be re-started by the SCSI manager * calling "templateResume()". * * Otherwise, if there's a new SCSI thread to start (i.e., the SCSI * manager has called "threadActivate()"), start the appropriate script. * * Otherwise, start a script which puts the device 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 device 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 "templateActivate ()".) */ if (connected) { pSiop->state = TEMPLATE_STATE_IDLE; } else if (pSiop->cmdPending) { templateScriptStart (pSiop, pSiop->pNewThread, TEMPLATE_SCRIPT_INIT_START); pSiop->state = TEMPLATE_STATE_ACTIVE; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -