📄 templatescsi1.c
字号:
/* templateScsi1.c - template SCSI-1 driver *//* Copyright 1989-1997 Wind River Systems, Inc. *//*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 args to TEMPLATE_READ macro01c,20aug97,dat code review comments from Dinesh01b,11aug97,dat fixed compilation bugs01a,07apr97,dat written from ncr5390Lib1.c, ver 01j*//*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.USER-CALLABLE ROUTINESThe primary user routines for this driver library are templateCtrlCreate()and templateCtrlInit().TemplateCtrlCreate() is used to create a device driver structure that willrepresent and control the physical controller device. TemplateCtrlInit() is used to setup the device resetting the chip and theSCSI bus. See the synopsis for arguments.DRIVER CUSTOMIZATIONTODO - Describe all macros and constants that the user can change thatwill effect the behaviour of this driver.This template driver presumes that the device is memory mapped, and that the<regOffset> argument to templateCtrlCreate() indicates the interval betweenregisters, usually 1, 2 or 4 bytes. If the base address for the device is0x1000 and the regOffset is 4, then the CPU address of register number 3is (0x1000 + (4 * 3)) = 0x100C.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.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.INCLUDE FILEStemplateScsi1.hSEE ALSO: scsiLib,.pG "I/O System"*/#include "vxWorks.h"#include "memLib.h"#include "errnoLib.h"#include "logLib.h"#include "scsiLib.h"#include "stdlib.h"#include "stdio.h"#include "taskLib.h"#include "sysLib.h"/* defines */#define TEMPLATE_MAX_XFER_LENGTH ((UINT) (0xffff)) /* max data xfer length */#define TEMPLATE_MAX_BUS_ID (0x7)/* Dummy command codes */#define TEMPLATE_ATN_SELECT (0x1)#define TEMPLATE_STOP_SELECT (0x2)#define TEMPLATE_SELECT (0x3)#ifndef TEMPLATE_REG_READ# define TEMPLATE_REG_READ(pDev, reg,result) \ ((result) = *pDev->reg)#endif /*TEMPLATE_REG_READ*/#ifndef TEMPLATE_REG_WRITE# define TEMPLATE_REG_WRITE(pDev, reg, data) \ (*pDev->reg = data)#endif /*TEMPLATE_REG_WRITE*/typedef struct { /* TEMPLATE_DEV */ SCSI_CTRL scsiCtrl; /* generic SCSI controller info */ SEM_ID pMutexData; /* use to protect global siop data */ SCSI_PHYS_DEV *pDevToSelect;/* device to select at intr. level or NULL */ } TEMPLATE_DEV;/* globals */IMPORT BOOL scsiDebug;IMPORT BOOL scsiIntsDebug;/* forward declarations */ STATUS templateCtrlInit (TEMPLATE_DEV *, int , UINT, int); void templateIntr (TEMPLATE_DEV *);LOCAL void templateCommand (TEMPLATE_DEV *, int);LOCAL STATUS templateDevSelect (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);LOCAL STATUS templateMsgInAck (SCSI_CTRL *, BOOL);LOCAL STATUS templateBytesOut (SCSI_PHYS_DEV *, char *, int, int);LOCAL STATUS templateBytesIn (SCSI_PHYS_DEV *, char *, int, int);LOCAL STATUS templateBusPhaseGet (SCSI_CTRL *, int, int *);LOCAL void templateSelTimeOutCvt (SCSI_CTRL *, UINT , UINT *);LOCAL STATUS templateBusIdGet (TEMPLATE_DEV *, int *);LOCAL void templateScsiBusReset (TEMPLATE_DEV *);LOCAL void templateHwInit (TEMPLATE_DEV *);/* * TODO - remove or replace these macros, they are just pseudo code to allow * this template driver to compile without warnings. */#define DEVICE_IS_DISCONNECTED 0#define NOT_EXPECTED_STATE 0#define DEVICE_IS_NOT_INTERRUPTING 0#define DMA_TERMINAL_COUNT_REACHED 0#define DEVICE_FUNC_COMPLETE 0/********************************************************************************* templateCtrlCreate - create a TEMPLATE_DEV device** This routine creates a data structure that must exist before the* TEMPLATE_DEV chip can be used. This routine must be called exactly once* for a specified TEMPLATE_DEV, and must be the first routine called, since* it calloc's a structure needed by all other routines in the library.** TODO - The input arguments are device specific. The argument list must* be updated.** The device specific input parameters are as follows:* .iP <baseAdrs> 4* the address at which the CPU would access the lowest * register of the TEMPLATE_DEV.* .iP <regOffset>* the address offset (bytes) to access consecutive registers.* (This must be a power of 2, for example, 1, 2, 4, etc.)* .iP <clkPeriod>* the period, in nanoseconds, of the signal to the TEMPLATE_DEV clock input (used only* for select command timeouts).* .iP "<templateDmaBytesIn> and <templateDmaBytesOut>"* board-specific parameters to handle DMA input and output.* If these are NULL (0), TEMPLATE_DEV program mode is used.* DMA is used only during SCSI data in/out phases.* The interface to these DMA routines must be of the form:* .CS* STATUS templateDmaBytes{In, Out}* (* TEMPLATE_DEV* pScsiPhysDev, /@ ptr to phys dev info @/* UINT8* pBuffer, /@ ptr to the data buffer @/* int bufLength /@ number of bytes to xfer @/* )* .CE* .LP** After creating a device, the user will usually then initialize the* device by calling templateCtrlInit().** RETURNS: A pointer to an TEMPLATE_DEV structure,* or NULL if memory is insufficient or the parameters are invalid.*/TEMPLATE_DEV * templateCtrlCreate ( /* TODO - this argument list is device specific, change as needed */ UINT8 *baseAdrs, /* base address of TEMPLATE_DEV */ int regOffset, /* addr offset between consecutive regs. */ UINT clkPeriod, /* period of controller clock (nsec) */ FUNCPTR templateDmaBytesIn, /* SCSI DMA input function */ FUNCPTR templateDmaBytesOut /* SCSI DMA output function */ ) { TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */ /* TODO - verify parameters, return NULL if necessary */ /* calloc the controller info structure; return NULL if unable */ pDev = (TEMPLATE_DEV *) calloc (1, sizeof (TEMPLATE_DEV)); if (pDev == (TEMPLATE_DEV *) NULL) return ((TEMPLATE_DEV *) NULL); /* fill in generic SCSI info for this controller */ scsiCtrlInit (&pDev->scsiCtrl); /* fill in remainder of scsiCtrl structure */ pDev->scsiCtrl.clkPeriod = clkPeriod; pDev->scsiCtrl.maxBytesPerXfer = TEMPLATE_MAX_XFER_LENGTH; pDev->scsiCtrl.scsiBusReset = (VOIDFUNCPTR) templateScsiBusReset; pDev->scsiCtrl.scsiTransact = (FUNCPTR) scsiTransact; pDev->scsiCtrl.scsiDevSelect = (FUNCPTR) templateDevSelect; pDev->scsiCtrl.scsiBytesIn = (FUNCPTR) templateBytesIn; pDev->scsiCtrl.scsiBytesOut = (FUNCPTR) templateBytesOut; pDev->scsiCtrl.scsiDmaBytesIn = (FUNCPTR) templateDmaBytesIn; pDev->scsiCtrl.scsiDmaBytesOut = (FUNCPTR) templateDmaBytesOut; pDev->scsiCtrl.scsiBusPhaseGet = (FUNCPTR) templateBusPhaseGet; pDev->scsiCtrl.scsiMsgInAck = (FUNCPTR) templateMsgInAck; pDev->scsiCtrl.scsiSelTimeOutCvt = (VOIDFUNCPTR) templateSelTimeOutCvt; /* initialize other template_dev fields */ pDev->pDevToSelect = (SCSI_PHYS_DEV *) NULL; /* TODO - fill in device specific data for this controller */ return (pDev); }/********************************************************************************* templateCtrlInit - initialize a TEMPLATE_DEV** This routine initializes an TEMPLATE_DEV structure created by * templateCtrlCreate(). It must be called before the TEMPLATE_DEV is used.* This routine can be called more than once; however, it should be called* only while there is no activity on the SCSI interface, since the specified* configuration is written to the TEMPLATE_DEV.** Before returning, this routine pulses RST (reset) on the SCSI bus, thus* resetting all attached devices.** The input parameters are as follows:* .iP <pDev> 4* a pointer to an TEMPLATE_DEV structure created with templateCtrlCreate().* .iP <scsiCtrlBusId>* the SCSI bus ID of the TEMPLATE_DEV, in the range 0 - 7. The ID is* somewhat arbitrary; the value 7, or highest priority, is conventional.* .iP <defaultSelTimeOut>* the timeout, in microseconds, for selecting a SCSI device attached to this* controller. This value is used as a default if no timeout is specified in * scsiPhysDevCreate()). The recommended value zero (0)* specifies SCSI_DEF_SELECT_TIMEOUT (250 millisec). The maximum timeout* possible is approximately 3 seconds. Values exceeding this revert to the* maximum. For more information about chip timeouts, see the device manual.* .iP <scsiPriority>* the priority to which a task is set when performing a SCSI transaction.* Valid priorities are 0 to 255. Alternatively, the value -1 specifies * that the priority should not be altered during SCSI transactions.** RETURNS: OK, or ERROR if a parameter is out of range.** SEE ALSO: scsiPhysDevCreate(),*/STATUS templateCtrlInit ( TEMPLATE_DEV* pDev, /* ptr to TEMPLATE_DEV struct */ int scsiCtrlBusId, /* SCSI bus ID of this TEMPLATE_DEV */ UINT defaultSelTimeOut, /* default dev sel timeout (microsec) */ int scsiPriority /* priority of task doing SCSI I/O */ ) { /* verify scsiCtrlBusId and enter legal value in TEMPLATE_DEV structure */ if (scsiCtrlBusId < SCSI_MIN_BUS_ID || scsiCtrlBusId > TEMPLATE_MAX_BUS_ID) return (ERROR); pDev->scsiCtrl.scsiCtrlBusId = (UINT8) scsiCtrlBusId; /* verify scsiPriority and enter legal value in TEMPLATE_DEV structure */ if (scsiPriority < NONE || scsiPriority > 0xff) return (ERROR); pDev->scsiCtrl.scsiPriority = scsiPriority; /* TODO - if needed, issue NO-OP (required by some devices) */ /* TODO - if needed, compute and set device clocking information */ /* * TODO - verify defaultSelTimeOut, convert it from usec to TEMPLATE_DEV * register values, and enter value in TEMPLATE_DEV structure or registers. */ /* disconnect is not supported with SCSI-1, for now */ pDev->scsiCtrl.disconnect = (TBOOL) FALSE; templateHwInit (pDev); /* initialize the TEMPLATE_DEV hardware */ return (OK); }/********************************************************************************* templateDevSelect - attempt to select a SCSI physical device** This routine is called from scsiLib to select a physical device.* The driver selects the device and sends the initial MSG_OUT and CMD* bytes.** RETURNS: OK if device was successfully selected, otherwise ERROR.*/LOCAL STATUS templateDevSelect ( SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to SCSI physical device info */ SCSI_TRANSACTION *pScsiXaction /* ptr to SCSI transaction info */ ) { TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */ int templateBusId; /* SCSI bus ID of the TEMPLATE_DEV */ UINT8 identMsg; /* for construction of the IDENTIFY message */ int ix; /* loop index */ UINT8 *pCmdByte; /* ptr to a command byte */ UINT8 templateOpcode; /* TEMPLATE_DEV opcode byte */ pDev = (TEMPLATE_DEV *) pScsiPhysDev->pScsiCtrl; /* Return ERROR, if trying to select device's own id */ if ((templateBusIdGet (pDev, &templateBusId) == ERROR) || (templateBusId == pScsiPhysDev->scsiDevBusId)) { return (ERROR); } pDev->pDevToSelect = pScsiPhysDev; pScsiPhysDev->devStatus = SELECT_REQUESTED; /* TODO - issue device select command sequence */ if (pScsiPhysDev->useIdentify) /* send an identify message */ { identMsg = SCSI_MSG_IDENTIFY | (pDev->scsiCtrl.disconnect ? SCSI_MSG_IDENT_DISCONNECT : 0) | (UINT8) pScsiPhysDev->scsiDevLUN; /* TODO - send identMsg in MSG_OUT phase */ } pCmdByte = pScsiXaction->cmdAddress; for (ix = 0; ix < pScsiXaction->cmdLength; ix++) { /* TODO - send other command bytes */ ; } if (pScsiPhysDev->useIdentify) { if (pScsiPhysDev->msgLength == 0) templateOpcode = (UINT8) TEMPLATE_ATN_SELECT; else templateOpcode = (UINT8) TEMPLATE_STOP_SELECT; } else templateOpcode = (UINT8) TEMPLATE_SELECT; /* Send proper SELECT command code */ templateCommand (pDev, templateOpcode); if (semTake (&pDev->scsiCtrl.ctrlSyncSem, ((pScsiXaction->cmdTimeout / SCSI_TIMEOUT_1SEC) + 1) * sysClkRateGet()) == ERROR) { /* timeout on semaphore, didn't get an interrupt */ printErr ("templateDevSelect: No interrupt received.\n");errorRecovery: /* TODO - flush device FIFOs, if needed */ /* reset bus, delay 3 seconds to allow devices to reset */ templateScsiBusReset (pDev); taskDelay (3 * sysClkRateGet ()); /* 3 seconds */ return (ERROR); } if (!(DEVICE_IS_DISCONNECTED)) { if (NOT_EXPECTED_STATE) { printErr ("templateDevSelect: Unknown chip state.\n"); /* TODO - print error statistics */ goto errorRecovery; } else { /* TODO - flush FIFOs, if needed */ return (OK); } } else { /* simple device select timeout */ /* TODO - Flush FIFOs, if needed */ errnoSet (S_scsiLib_SELECT_TIMEOUT); return (ERROR); } }/********************************************************************************* templateMsgInAck - de-assert the ACK line to accept message** This routine should be called when an incoming message has been read and* accepted. If the incoming message did not imply an impending disconnect,* give the synchronization semaphore, so that subsequent phase can be* detected.** RETURNS: OK.*/LOCAL STATUS templateMsgInAck ( SCSI_CTRL* pScsiCtrl, /* ptr to TEMPLATE_DEV info */ BOOL expectDisconn /* whether a disconnect is expected */ ) { /* TODO - Send MSG_ACCEPTED to terminate MSG_IN phase, wait for new phase */ return (OK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -