📄 mb87030lib.c
字号:
/* mb87030Lib.c - Fujitsu MB87030 SCSI Protocol Controller (SPC) library *//* Copyright 1989-1996 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01u,14dec94,jds timeout too small in spcBusPhaseGet(); spr 3877 fixed01t,26mar94,ccc bus free race condition fix for spr 319701s,23feb93,jdi documentation cleanup.01r,11feb93,ccc fixed error in comment for select timeout (spr 1901).01q,26sep92,ccc renamed spcShow() to mb87030Show() and added example.01p,24sep92,ccc made change in spcManBytesIn() to handle extended message. spcShow() now returns OK or ERROR if SCSI not configured.01o,07aug92,ccc added DMA support.01n,18jul92,smb Changed errno.h to errnoLib.h.01m,26may92,rrr the tree shuffle -changed includes to have absolute path from h/01l,07oct91,rrr some forward decls01k,04oct91,rrr passed through the ansification filter -changed functions to ansi style -changed includes to have absolute path from h/ -changed VOID to void -changed copyright notice01j,05apr91,jdi documentation -- removed header parens and x-ref numbers; doc review by jcc.01i,29feb91,jaa documentation.01h,09oct90,jcc lint.01g,03oct90,jcc changed leastSigAdrsBit to regOffset in mb87030CtrlCreate(); eliminated busFreeDelay parameter to mb87030CtrlInit().01f,02oct90,jcc UTINY became UINT8; changes in sem{Give, Take}() calls since SEM_ID's became SEMAPHORE's in various structures; malloc() became calloc() in wd33c93CtrlCreate(); miscellaneous.01e,10aug90,dnw added forward declarations for void functions.01d,18jul90,jcc made semTake() calls 5.0 compatible; clean-up.01c,08jun90,jcc fixed bug in handling of incoming messages. documentation.01b,23mar90,jcc removed DMA and disconnect options from mb87030CtrlInit(). lint.01a,19jan90,jcc formerly the device specific part of spcScsiDrv.c.*//*DESCRIPTIONThis is the I/O driver for the Fujitsu MB87030 SCSI Protocol Controller(SPC) chip. It is designed to work in conjunction with scsiLib.USER-CALLABLE ROUTINESMost of the routines in this driver are accessible only through the I/Osystem. Two routines, however, must be called directly: mb87030CtrlCreate()to create a controller structure, and mb87030CtrlInit() to initializethe controller structure.INCLUDE FILESmb87030.hSEE ALSO: scsiLib,.I "Fujitsu Small Computer Systems Interface MB87030 Synchronous/Asynchronous Protocol Controller Users Manual,".pG "I/O System"*/#include "vxWorks.h"#include "drv/scsi/mb87030.h"#include "memLib.h"#include "errnoLib.h"#include "logLib.h"#include "scsiLib.h"#include "stdlib.h"#include "stdio.h"#include "sysLib.h"/* defines */#define SPC_MAX_XFER_LENGTH (UINT) (0x00800000) /* max data xfer length */#define SPC_DEF_BUS_FREE_DELAY 3 /* nominal value for bus free delay *//* macros */#define SPC_BUS_PHASE_SET(pSpc, busPhase) spcPctlSet (pSpc, -1, (UINT8)busPhase)typedef MB_87030_SCSI_CTRL SPC;IMPORT BOOL scsiDebug;IMPORT BOOL scsiIntsDebug;void spcCommand (SPC *pSpc, UINT8 cmdCode);STATUS spcProgBytesOut (SCSI_PHYS_DEV *pScsiPhysDev, UINT8 *pBuffer, int bufLength, int scsiPhase);STATUS spcProgBytesIn (SCSI_PHYS_DEV *pScsiPhysDev, UINT8 *pBuffer, int bufLength, int scsiPhase);STATUS spcXferCountSet (SPC *pSpc, int count);/* forward static functions */static STATUS spcDevSelect (SCSI_PHYS_DEV *pScsiPhysDev, SCSI_TRANSACTION *pScsiXaction);static STATUS spcMsgInAck (SCSI_CTRL *pScsiCtrl, BOOL expectDisconn);static STATUS spcBytesOut (SCSI_PHYS_DEV *pScsiPhysDev, char *pBuffer, int bufLength, int scsiPhase);static STATUS spcBytesIn (SCSI_PHYS_DEV *pScsiPhysDev, char *pBuffer, int bufLength, int scsiPhase);static STATUS spcBusPhaseGet (SCSI_CTRL *pScsiCtrl, int timeOutInUsec, int *pBusPhase);static int byteParityGet (UINT8 byte);static void spcSelTimeOutCvt (SCSI_CTRL *pScsiCtrl, UINT timeOutInUsec, UINT *pTimeOutSetting);static STATUS spcBusIdGet (SPC *pSpc, int *pBusId);static void spcIntsEnable (SPC *pSpc);static void spcIntsDisable (SPC *pSpc);static void spcScmdSet (SPC *pSpc, UINT8 cmdCode, int resetOutBit, int interceptXferBit, int prgXferBit, int termModeBit);static void spcTmodSet (SPC *pSpc, BOOL syncXfer, int maxOffset, int minPerMinusOne);static void spcPctlSet (SPC *pSpc, int busFreeIntEnblBit, UINT8 xferPhase);static void spcScsiBusReset (SPC *pSpc);static void spcHwInit (SPC *pSpc);/********************************************************************************* mb87030CtrlCreate - create a control structure for an MB87030 SPC** This routine creates a data structure that must exist before the SPC chip can* be used. This routine should be called once and only once for a specified * SPC. It should be the first routine called, since it allocates memory for* a structure needed by all other routines in the library.** After calling this routine, at least one call to mb87030CtrlInit() should* be made before any SCSI transaction is initiated using the SPC chip.** A detailed description of the input parameters follows:* .iP <spcBaseAdrs> 4* the address at which the CPU would access the lowest * register of the SPC.* .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 SPC clock input (only* used for select command timeouts).* .iP <spcDataParity>* the parity bit must be defined by one of the following constants,* according to whether the input to SPC DP is GND, +5V, or a valid* parity signal, respectively:* .nf* SPC_DATA_PARITY_LOW* SPC_DATA_PARITY_HIGH* SPC_DATA_PARITY_VALID* .fi* .iP "<spcDmaBytesIn> and <spcDmaBytesOut>"* pointers to board-specific routines to handle DMA input and output. * If these are NULL (0), SPC program transfer mode is used.* DMA is possible only during SCSI data in/out phases.* The interface to these DMA routines must be of the form:* .CS* STATUS xxDmaBytes{In, Out}* (* SCSI_PHYS_DEV *pScsiPhysDev, /@ ptr to phys dev info @/* UINT8 *pBuffer, /@ ptr to the data buffer @/* int bufLength /@ number of bytes to xfer @/* )* .CE** RETURNS: A pointer to the SPC control structure, or NULL if memory * is insufficient or parameters are invalid.*/MB_87030_SCSI_CTRL *mb87030CtrlCreate ( FAST UINT8 *spcBaseAdrs, /* base address of SPC */ int regOffset, /* addr offset between consecutive regs. */ UINT clkPeriod, /* period of controller clock (nsec) */ int spcDataParity, /* type of input to SPC DP (data parity) */ FUNCPTR spcDMABytesIn, /* SCSI DMA input function */ FUNCPTR spcDMABytesOut /* SCSI DMA output function */ ) { FAST SPC *pSpc; /* ptr to SPC info */ /* verify parameters */ if (regOffset == 0) return ((SPC *) NULL); if ((spcDataParity < SPC_DATA_PARITY_LOW) || (spcDataParity > SPC_DATA_PARITY_VALID)) return ((SPC *) NULL); /* malloc the controller info structure; return ERROR if unable */ pSpc = (SPC *) malloc (sizeof (SPC)); if (pSpc == (SPC *) NULL) return ((SPC *) NULL); /* fill in generic SCSI info for this controller */ scsiCtrlInit (&pSpc->scsiCtrl); /* fill in SPC specific data for this controller */ pSpc->pBdidReg = spcBaseAdrs; pSpc->pSctlReg = spcBaseAdrs + (0x1 * regOffset); pSpc->pScmdReg = spcBaseAdrs + (0x2 * regOffset); pSpc->pTmodReg = spcBaseAdrs + (0x3 * regOffset); pSpc->pIntsReg = spcBaseAdrs + (0x4 * regOffset); pSpc->pPsnsReg = spcBaseAdrs + (0x5 * regOffset); pSpc->pSdgcReg = spcBaseAdrs + (0x5 * regOffset); pSpc->pSstsReg = spcBaseAdrs + (0x6 * regOffset); pSpc->pSerrReg = spcBaseAdrs + (0x7 * regOffset); pSpc->pPctlReg = spcBaseAdrs + (0x8 * regOffset); pSpc->pMbcReg = spcBaseAdrs + (0x9 * regOffset); pSpc->pDregReg = spcBaseAdrs + (0xa * regOffset); pSpc->pTempReg = spcBaseAdrs + (0xb * regOffset); pSpc->pTchReg = spcBaseAdrs + (0xc * regOffset); pSpc->pTcmReg = spcBaseAdrs + (0xd * regOffset); pSpc->pTclReg = spcBaseAdrs + (0xe * regOffset); pSpc->pExbfReg = spcBaseAdrs + (0xf * regOffset); pSpc->spcDataParity = spcDataParity; pSpc->scsiCtrl.clkPeriod = clkPeriod; pSpc->scsiCtrl.maxBytesPerXfer = SPC_MAX_XFER_LENGTH; pSpc->scsiCtrl.scsiBusReset = spcScsiBusReset; pSpc->scsiCtrl.scsiTransact = scsiTransact; pSpc->scsiCtrl.scsiDevSelect = spcDevSelect; pSpc->scsiCtrl.scsiBytesIn = spcBytesIn; pSpc->scsiCtrl.scsiBytesOut = spcBytesOut; pSpc->scsiCtrl.scsiDmaBytesIn = spcDMABytesIn; pSpc->scsiCtrl.scsiDmaBytesOut = spcDMABytesOut; pSpc->scsiCtrl.scsiBusPhaseGet = spcBusPhaseGet; pSpc->scsiCtrl.scsiMsgInAck = spcMsgInAck; pSpc->scsiCtrl.scsiSelTimeOutCvt = spcSelTimeOutCvt; pSpc->pDevToSelect = (SCSI_PHYS_DEV *) NULL; return (pSpc); }/********************************************************************************* mb87030CtrlInit - initialize a control structure for an MB87030 SPC** This routine initializes an SPC control structure created by* mb87030CtrlCreate(). It must be called before the SPC 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.** Before returning, this routine pulses RST (reset) on the SCSI bus, thus* resetting all attached devices.** The input parameters are as follows:* .iP <pSpc> 4* a pointer to the MB_87030_SCSI_CTRL structure created with* mb87030CtrlCreate().* .iP <scsiCtrlBusId>* the SCSI bus ID of the SIOP, 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. The recommended value 0* specifies SCSI_DEF_SELECT_TIMEOUT (250 milliseconds).* The maximum timeout possible is approximately 3 seconds.* Values exceeding this revert to the maximum.* .iP <scsiPriority>* the priority to which a task is set when performing a SCSI* transaction. Valid priorities range from 0 to 255. Alternatively, * the value -1 specifies that the priority should not be* altered during SCSI transactions.** RETURNS: OK, or ERROR if parameters are out of range.*/STATUS mb87030CtrlInit ( FAST MB_87030_SCSI_CTRL *pSpc, /* ptr to SPC struct */ FAST int scsiCtrlBusId, /* SCSI bus ID of this SPC */ FAST UINT defaultSelTimeOut, /* default dev sel timeout (microsec) */ int scsiPriority /* priority of task doing SCSI I/O */ ) { UINT tempSelTimeOut; /* temp. value of select time-out (no units) */ int busFreeDelay = SPC_DEF_BUS_FREE_DELAY; int busFreeDelayParity; /* parity of busFreeDelay parameter */ /* verify scsiCtrlBusId and enter legal value in SPC structure */ if (scsiCtrlBusId < SCSI_MIN_BUS_ID || scsiCtrlBusId > SCSI_MAX_BUS_ID) return (ERROR); pSpc->scsiCtrl.scsiCtrlBusId = (UINT8) scsiCtrlBusId; /* verify scsiPriority and enter legal value in SPC structure */ if (scsiPriority < NONE || scsiPriority > 0xff) return (ERROR); pSpc->scsiCtrl.scsiPriority = scsiPriority; /* adjust busFreeDelay parity, and enter value in SPC structure */ if (pSpc->spcDataParity != SPC_DATA_PARITY_VALID) { busFreeDelayParity = byteParityGet ((UINT8) busFreeDelay); if (busFreeDelayParity == pSpc->spcDataParity) busFreeDelay ^= 0x1; } pSpc->busFreeDelay = busFreeDelay; /* verify defaultSelTimeOut, convert it from usec to SPC register values, * and enter value in SPC structure */ spcSelTimeOutCvt (&pSpc->scsiCtrl, defaultSelTimeOut, &tempSelTimeOut); pSpc->defaultSelTimeOut = (UINT16) tempSelTimeOut; /* disconnect not supported for now */ pSpc->scsiCtrl.disconnect = (TBOOL) FALSE; spcHwInit (pSpc); /* initialize the SPC hardware */ return (OK); }/********************************************************************************* spcDevSelect - attempt to select a SCSI physical device** This routine is intended to be called from scsiLib, not directly.** RETURNS: OK if device was successfully selected, otherwise ERROR.*/LOCAL STATUS spcDevSelect ( FAST SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to SCSI physical device info */ SCSI_TRANSACTION *pScsiXaction /* ptr to SCSI transaction info */ ) { FAST SPC *pSpc; /* ptr to SPC info */ int spcBusId; /* SCSI bus ID of the SPC */ UINT8 identMsg; /* for construction of the IDENTIFY message */ STATUS status; /* placeholder for status */ int scsiPhase; /* SCSI bus phase following the select */ pSpc = (SPC *) pScsiPhysDev->pScsiCtrl; if (spcBusIdGet (pSpc, &spcBusId) == ERROR) return (ERROR); if (spcBusId == pScsiPhysDev->scsiDevBusId) return (ERROR); pSpc->selectTempReg = (UINT8) ((1 << spcBusId) | (1 << pScsiPhysDev->scsiDevBusId)); pSpc->pDevToSelect = pScsiPhysDev; pScsiPhysDev->devStatus = SELECT_REQUESTED; *pSpc->pPctlReg |= SPC_PCTL_BF_INT_ENBL; semTake (&pScsiPhysDev->devSyncSem, WAIT_FOREVER); if (pScsiPhysDev->devStatus == SELECT_SUCCESSFUL) { if (pScsiPhysDev->useIdentify) /* send an identify message */ { if ((spcBusPhaseGet (&pSpc->scsiCtrl, 0, &scsiPhase) == ERROR) || (scsiPhase != SCSI_MSG_OUT_PHASE)) { SCSI_DEBUG_MSG ("scsiPhase = %x\n", scsiPhase, 0, 0, 0, 0, 0); return (ERROR); } identMsg = SCSI_MSG_IDENTIFY | (pSpc->scsiCtrl.disconnect ? SCSI_MSG_IDENT_DISCONNECT : 0) | (UINT8) pScsiPhysDev->scsiDevLUN; status = spcProgBytesOut (pScsiPhysDev, &identMsg, sizeof (identMsg), scsiPhase); if (status == ERROR) return (ERROR); } return (OK); } if (pScsiPhysDev->devStatus == SELECT_TIMEOUT) errnoSet (S_scsiLib_SELECT_TIMEOUT); return (ERROR); }/********************************************************************************* spcManBytesOut - output byte(s) to SCSI using manual transfer*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -