mb87030Lib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:51k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* mb87030Lib.c - Fujitsu MB87030 SCSI Protocol Controller (SPC) library */
  2. /* Copyright 1989-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01u,14dec94,jds  timeout too small in spcBusPhaseGet(); spr 3877 fixed
  8. 01t,26mar94,ccc  bus free race condition fix for spr 3197
  9. 01s,23feb93,jdi  documentation cleanup.
  10. 01r,11feb93,ccc  fixed error in comment for select timeout (spr 1901).
  11. 01q,26sep92,ccc  renamed spcShow() to mb87030Show() and added example.
  12. 01p,24sep92,ccc  made change in spcManBytesIn() to handle extended message.
  13.  spcShow() now returns OK or ERROR if SCSI not configured.
  14. 01o,07aug92,ccc  added DMA support.
  15. 01n,18jul92,smb  Changed errno.h to errnoLib.h.
  16. 01m,26may92,rrr  the tree shuffle
  17.   -changed includes to have absolute path from h/
  18. 01l,07oct91,rrr  some forward decls
  19. 01k,04oct91,rrr  passed through the ansification filter
  20.                   -changed functions to ansi style
  21.   -changed includes to have absolute path from h/
  22.   -changed VOID to void
  23.   -changed copyright notice
  24. 01j,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  25.  doc review by jcc.
  26. 01i,29feb91,jaa  documentation.
  27. 01h,09oct90,jcc  lint.
  28. 01g,03oct90,jcc  changed leastSigAdrsBit to regOffset in mb87030CtrlCreate();
  29.  eliminated busFreeDelay parameter to mb87030CtrlInit().
  30. 01f,02oct90,jcc  UTINY became UINT8; changes in sem{Give, Take}() calls
  31.  since SEM_ID's became SEMAPHORE's in various structures;
  32.  malloc() became calloc() in wd33c93CtrlCreate(); miscellaneous.
  33. 01e,10aug90,dnw  added forward declarations for void functions.
  34. 01d,18jul90,jcc  made semTake() calls 5.0 compatible; clean-up.
  35. 01c,08jun90,jcc  fixed bug in handling of incoming messages. documentation.
  36. 01b,23mar90,jcc  removed DMA and disconnect options from mb87030CtrlInit().
  37.  lint.
  38. 01a,19jan90,jcc  formerly the device specific part of spcScsiDrv.c.
  39. */
  40. /*
  41. DESCRIPTION
  42. This is the I/O driver for the Fujitsu MB87030 SCSI Protocol Controller
  43. (SPC) chip.  It is designed to work in conjunction with scsiLib.
  44. USER-CALLABLE ROUTINES
  45. Most of the routines in this driver are accessible only through the I/O
  46. system.  Two routines, however, must be called directly:  mb87030CtrlCreate()
  47. to create a controller structure, and mb87030CtrlInit() to initialize
  48. the controller structure.
  49. INCLUDE FILES
  50. mb87030.h
  51. SEE ALSO: scsiLib,
  52. .I "Fujitsu Small Computer Systems Interface MB87030 Synchronous/Asynchronous Protocol Controller Users Manual,"
  53. .pG "I/O System"
  54. */
  55. #include "vxWorks.h"
  56. #include "drv/scsi/mb87030.h"
  57. #include "memLib.h"
  58. #include "errnoLib.h"
  59. #include "logLib.h"
  60. #include "scsiLib.h"
  61. #include "stdlib.h"
  62. #include "stdio.h"
  63. #include "sysLib.h"
  64. /* defines */
  65. #define SPC_MAX_XFER_LENGTH   (UINT) (0x00800000) /* max data xfer length */
  66. #define SPC_DEF_BUS_FREE_DELAY  3 /* nominal value for bus free delay */
  67. /* macros */
  68. #define SPC_BUS_PHASE_SET(pSpc, busPhase) spcPctlSet (pSpc, -1, (UINT8)busPhase)
  69. typedef MB_87030_SCSI_CTRL SPC;
  70. IMPORT BOOL scsiDebug;
  71. IMPORT BOOL scsiIntsDebug;
  72. void spcCommand (SPC *pSpc, UINT8 cmdCode);
  73. STATUS spcProgBytesOut (SCSI_PHYS_DEV *pScsiPhysDev, UINT8 *pBuffer,
  74.      int bufLength, int scsiPhase);
  75. STATUS spcProgBytesIn (SCSI_PHYS_DEV *pScsiPhysDev, UINT8 *pBuffer,
  76.      int bufLength, int scsiPhase);
  77. STATUS spcXferCountSet (SPC *pSpc, int count);
  78. /* forward static functions */
  79. static STATUS spcDevSelect (SCSI_PHYS_DEV *pScsiPhysDev, SCSI_TRANSACTION
  80. *pScsiXaction);
  81. static STATUS spcMsgInAck (SCSI_CTRL *pScsiCtrl, BOOL expectDisconn);
  82. static STATUS spcBytesOut (SCSI_PHYS_DEV *pScsiPhysDev, char *pBuffer, int
  83. bufLength, int scsiPhase);
  84. static STATUS spcBytesIn (SCSI_PHYS_DEV *pScsiPhysDev, char *pBuffer, int
  85. bufLength, int scsiPhase);
  86. static STATUS spcBusPhaseGet (SCSI_CTRL *pScsiCtrl, int timeOutInUsec, int
  87. *pBusPhase);
  88. static int byteParityGet (UINT8 byte);
  89. static void spcSelTimeOutCvt (SCSI_CTRL *pScsiCtrl, UINT timeOutInUsec, UINT
  90. *pTimeOutSetting);
  91. static STATUS spcBusIdGet (SPC *pSpc, int *pBusId);
  92. static void spcIntsEnable (SPC *pSpc);
  93. static void spcIntsDisable (SPC *pSpc);
  94. static void spcScmdSet (SPC *pSpc, UINT8 cmdCode, int resetOutBit, int
  95. interceptXferBit, int prgXferBit, int termModeBit);
  96. static void spcTmodSet (SPC *pSpc, BOOL syncXfer, int maxOffset, int
  97. minPerMinusOne);
  98. static void spcPctlSet (SPC *pSpc, int busFreeIntEnblBit, UINT8 xferPhase);
  99. static void spcScsiBusReset (SPC *pSpc);
  100. static void spcHwInit (SPC *pSpc);
  101. /*******************************************************************************
  102. *
  103. * mb87030CtrlCreate - create a control structure for an MB87030 SPC
  104. *
  105. * This routine creates a data structure that must exist before the SPC chip can
  106. * be used.  This routine should be called once and only once for a specified 
  107. * SPC.  It should be the first routine called, since it allocates memory for
  108. * a structure needed by all other routines in the library.
  109. *
  110. * After calling this routine, at least one call to mb87030CtrlInit() should
  111. * be made before any SCSI transaction is initiated using the SPC chip.
  112. *
  113. * A detailed description of the input parameters follows:
  114. * .iP <spcBaseAdrs> 4
  115. * the address at which the CPU would access the lowest 
  116. * register of the SPC.
  117. * .iP <regOffset>
  118. * the address offset (bytes) to access consecutive registers.
  119. * (This must be a power of 2, for example, 1, 2, 4, etc.)
  120. * .iP <clkPeriod>
  121. * the period in nanoseconds of the signal to the SPC clock input (only
  122. * used for select command timeouts).
  123. * .iP <spcDataParity>
  124. * the parity bit must be defined by one of the following constants,
  125. * according to whether the input to SPC DP is GND, +5V, or a valid
  126. * parity signal, respectively:
  127. * .nf
  128. *     SPC_DATA_PARITY_LOW
  129. *     SPC_DATA_PARITY_HIGH
  130. *     SPC_DATA_PARITY_VALID
  131. * .fi
  132. * .iP "<spcDmaBytesIn> and <spcDmaBytesOut>"
  133. * pointers to board-specific routines to handle DMA input and output.  
  134. * If these are NULL (0), SPC program transfer mode is used.
  135. * DMA is possible only during SCSI data in/out phases.
  136. * The interface to these DMA routines must be of the form:
  137. * .CS
  138. *     STATUS xxDmaBytes{In, Out}
  139. *         (
  140. *         SCSI_PHYS_DEV  *pScsiPhysDev,  /@ ptr to phys dev info    @/
  141. *         UINT8          *pBuffer,       /@ ptr to the data buffer  @/
  142. *         int            bufLength       /@ number of bytes to xfer @/
  143. *         )
  144. * .CE
  145. *
  146. * RETURNS: A pointer to the SPC control structure, or NULL if memory 
  147. * is insufficient or parameters are invalid.
  148. */
  149. MB_87030_SCSI_CTRL *mb87030CtrlCreate
  150.     (
  151.     FAST UINT8 *spcBaseAdrs,    /* base address of SPC */
  152.     int regOffset,              /* addr offset between consecutive regs. */
  153.     UINT clkPeriod,             /* period of controller clock (nsec) */
  154.     int spcDataParity,          /* type of input to SPC DP (data parity) */
  155.     FUNCPTR spcDMABytesIn,      /* SCSI DMA input function */
  156.     FUNCPTR spcDMABytesOut      /* SCSI DMA output function */
  157.     )
  158.     {
  159.     FAST SPC *pSpc; /* ptr to SPC info */
  160.     /* verify parameters */
  161.     if (regOffset == 0)
  162. return ((SPC *) NULL);
  163.     if ((spcDataParity < SPC_DATA_PARITY_LOW) ||
  164. (spcDataParity > SPC_DATA_PARITY_VALID))
  165. return ((SPC *) NULL);
  166.     /* malloc the controller info structure; return ERROR if unable */
  167.     pSpc = (SPC *) malloc (sizeof (SPC));
  168.     if (pSpc == (SPC *) NULL)
  169.         return ((SPC *) NULL);
  170.     /* fill in generic SCSI info for this controller */
  171.     scsiCtrlInit (&pSpc->scsiCtrl);
  172.     /* fill in SPC specific data for this controller */
  173.     pSpc->pBdidReg = spcBaseAdrs;
  174.     pSpc->pSctlReg = spcBaseAdrs + (0x1 * regOffset);
  175.     pSpc->pScmdReg = spcBaseAdrs + (0x2 * regOffset);
  176.     pSpc->pTmodReg = spcBaseAdrs + (0x3 * regOffset);
  177.     pSpc->pIntsReg = spcBaseAdrs + (0x4 * regOffset);
  178.     pSpc->pPsnsReg = spcBaseAdrs + (0x5 * regOffset);
  179.     pSpc->pSdgcReg = spcBaseAdrs + (0x5 * regOffset);
  180.     pSpc->pSstsReg = spcBaseAdrs + (0x6 * regOffset);
  181.     pSpc->pSerrReg = spcBaseAdrs + (0x7 * regOffset);
  182.     pSpc->pPctlReg = spcBaseAdrs + (0x8 * regOffset);
  183.     pSpc->pMbcReg  = spcBaseAdrs + (0x9 * regOffset);
  184.     pSpc->pDregReg = spcBaseAdrs + (0xa * regOffset);
  185.     pSpc->pTempReg = spcBaseAdrs + (0xb * regOffset);
  186.     pSpc->pTchReg  = spcBaseAdrs + (0xc * regOffset);
  187.     pSpc->pTcmReg  = spcBaseAdrs + (0xd * regOffset);
  188.     pSpc->pTclReg  = spcBaseAdrs + (0xe * regOffset);
  189.     pSpc->pExbfReg = spcBaseAdrs + (0xf * regOffset);
  190.     pSpc->spcDataParity = spcDataParity;
  191.     pSpc->scsiCtrl.clkPeriod = clkPeriod;
  192.     pSpc->scsiCtrl.maxBytesPerXfer = SPC_MAX_XFER_LENGTH;
  193.     pSpc->scsiCtrl.scsiBusReset      = spcScsiBusReset;
  194.     pSpc->scsiCtrl.scsiTransact      = scsiTransact;
  195.     pSpc->scsiCtrl.scsiDevSelect     = spcDevSelect;
  196.     pSpc->scsiCtrl.scsiBytesIn       = spcBytesIn;
  197.     pSpc->scsiCtrl.scsiBytesOut      = spcBytesOut;
  198.     pSpc->scsiCtrl.scsiDmaBytesIn    = spcDMABytesIn;
  199.     pSpc->scsiCtrl.scsiDmaBytesOut   = spcDMABytesOut;
  200.     pSpc->scsiCtrl.scsiBusPhaseGet   = spcBusPhaseGet;
  201.     pSpc->scsiCtrl.scsiMsgInAck      = spcMsgInAck;
  202.     pSpc->scsiCtrl.scsiSelTimeOutCvt = spcSelTimeOutCvt;
  203.     pSpc->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  204.     return (pSpc);
  205.     }
  206. /*******************************************************************************
  207. *
  208. * mb87030CtrlInit - initialize a control structure for an MB87030 SPC
  209. *
  210. * This routine initializes an SPC control structure created by
  211. * mb87030CtrlCreate().  It must be called before the SPC is used.  This
  212. * routine can be called more than once; however, it should be
  213. * called only while there is no activity on the SCSI interface.
  214. *
  215. * Before returning, this routine pulses RST (reset) on the SCSI bus, thus
  216. * resetting all attached devices.
  217. *
  218. * The input parameters are as follows:
  219. * .iP <pSpc> 4
  220. * a pointer to the MB_87030_SCSI_CTRL structure created with
  221. * mb87030CtrlCreate().
  222. * .iP <scsiCtrlBusId>
  223. * the SCSI bus ID of the SIOP, in the range 0 - 7.  The ID is somewhat 
  224. * arbitrary; the value 7, or highest priority, is conventional.
  225. * .iP <defaultSelTimeOut>
  226. * the timeout, in microseconds, for selecting a SCSI device
  227. * attached to this controller.  The recommended value 0
  228. * specifies SCSI_DEF_SELECT_TIMEOUT (250 milliseconds).
  229. * The maximum timeout possible is approximately 3 seconds.
  230. * Values exceeding this revert to the maximum.
  231. * .iP <scsiPriority>
  232. * the priority to which a task is set when performing a SCSI
  233. * transaction.  Valid priorities range from 0 to 255.  Alternatively, 
  234. * the value -1 specifies that the priority should not be
  235. * altered during SCSI transactions.
  236. *
  237. * RETURNS: OK, or ERROR if parameters are out of range.
  238. */
  239. STATUS mb87030CtrlInit
  240.     (
  241.     FAST MB_87030_SCSI_CTRL *pSpc, /* ptr to SPC struct */
  242.     FAST int scsiCtrlBusId,        /* SCSI bus ID of this SPC */
  243.     FAST UINT defaultSelTimeOut,   /* default dev sel timeout (microsec) */
  244.     int scsiPriority               /* priority of task doing SCSI I/O */
  245.     )
  246.     {
  247.     UINT tempSelTimeOut; /* temp. value of select time-out (no units) */
  248.     int busFreeDelay = SPC_DEF_BUS_FREE_DELAY;
  249.     int busFreeDelayParity; /* parity of busFreeDelay parameter */
  250.     /* verify scsiCtrlBusId and enter legal value in SPC structure */
  251.     if (scsiCtrlBusId < SCSI_MIN_BUS_ID || scsiCtrlBusId > SCSI_MAX_BUS_ID)
  252. return (ERROR);
  253.     pSpc->scsiCtrl.scsiCtrlBusId = (UINT8) scsiCtrlBusId;
  254.     /* verify scsiPriority and enter legal value in SPC structure */
  255.     if (scsiPriority < NONE || scsiPriority > 0xff)
  256. return (ERROR);
  257.    pSpc->scsiCtrl.scsiPriority = scsiPriority;
  258.     /* adjust busFreeDelay parity, and enter value in SPC structure */
  259.     if (pSpc->spcDataParity != SPC_DATA_PARITY_VALID)
  260.         {
  261.         busFreeDelayParity = byteParityGet ((UINT8) busFreeDelay);
  262.         if (busFreeDelayParity == pSpc->spcDataParity)
  263.             busFreeDelay ^= 0x1;
  264.         }
  265.     pSpc->busFreeDelay = busFreeDelay;
  266.     /* verify defaultSelTimeOut, convert it from usec to SPC register values,
  267.      * and enter value in SPC structure
  268.      */
  269.     spcSelTimeOutCvt (&pSpc->scsiCtrl, defaultSelTimeOut, &tempSelTimeOut);
  270.     pSpc->defaultSelTimeOut = (UINT16) tempSelTimeOut;
  271.     /* disconnect not supported for now */
  272.     pSpc->scsiCtrl.disconnect = (TBOOL) FALSE;
  273.     spcHwInit (pSpc);  /* initialize the SPC hardware */
  274.     return (OK);
  275.     }
  276. /*******************************************************************************
  277. *
  278. * spcDevSelect - attempt to select a SCSI physical device
  279. *
  280. * This routine is intended to be called from scsiLib, not directly.
  281. *
  282. * RETURNS: OK if device was successfully selected, otherwise ERROR.
  283. */
  284. LOCAL STATUS spcDevSelect
  285.     (
  286.     FAST SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical device info */
  287.     SCSI_TRANSACTION *pScsiXaction      /* ptr to SCSI transaction info */
  288.     )
  289.     {
  290.     FAST SPC *pSpc; /* ptr to SPC info */
  291.     int spcBusId;               /* SCSI bus ID of the SPC */
  292.     UINT8 identMsg; /* for construction of the IDENTIFY message */
  293.     STATUS status; /* placeholder for status */
  294.     int scsiPhase; /* SCSI bus phase following the select */
  295.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  296.     if (spcBusIdGet (pSpc, &spcBusId) == ERROR)
  297.         return (ERROR);
  298.     if (spcBusId == pScsiPhysDev->scsiDevBusId)
  299.         return (ERROR);
  300.     pSpc->selectTempReg = (UINT8) ((1 << spcBusId) |
  301.    (1 << pScsiPhysDev->scsiDevBusId));
  302.     pSpc->pDevToSelect  = pScsiPhysDev;
  303.     pScsiPhysDev->devStatus = SELECT_REQUESTED;
  304.     *pSpc->pPctlReg |= SPC_PCTL_BF_INT_ENBL;
  305.     semTake (&pScsiPhysDev->devSyncSem, WAIT_FOREVER);
  306.     if (pScsiPhysDev->devStatus == SELECT_SUCCESSFUL)
  307. {
  308. if (pScsiPhysDev->useIdentify)  /* send an identify message */
  309.          {
  310.     if ((spcBusPhaseGet (&pSpc->scsiCtrl, 0,
  311.  &scsiPhase) == ERROR) ||
  312. (scsiPhase != SCSI_MSG_OUT_PHASE))
  313. {
  314. SCSI_DEBUG_MSG ("scsiPhase = %xn", scsiPhase,
  315. 0, 0, 0, 0, 0);
  316. return (ERROR);
  317. }
  318.             identMsg = SCSI_MSG_IDENTIFY |
  319.        (pSpc->scsiCtrl.disconnect ?
  320. SCSI_MSG_IDENT_DISCONNECT : 0) |
  321.        (UINT8) pScsiPhysDev->scsiDevLUN;
  322.     status = spcProgBytesOut (pScsiPhysDev, &identMsg,
  323.       sizeof (identMsg), scsiPhase);
  324.     if (status == ERROR)
  325. return (ERROR);
  326.             }
  327.         return (OK);
  328. }
  329.     if (pScsiPhysDev->devStatus == SELECT_TIMEOUT)
  330. errnoSet (S_scsiLib_SELECT_TIMEOUT);
  331.     return (ERROR);
  332.     }
  333. /*******************************************************************************
  334. *
  335. * spcManBytesOut - output byte(s) to SCSI using manual transfer
  336. *
  337. * RETURNS: OK.
  338. *
  339. * NOMANUAL
  340. */
  341. STATUS spcManBytesOut
  342.     (
  343.     FAST SPC *pSpc,             /* ptr to SPC info */
  344.     FAST UINT8 *pBuffer,        /* ptr to the output buffer */
  345.     FAST int bufLength,         /* length of the output buffer */
  346.     BOOL atnReset               /* whether ATN should be reset on last byte */
  347.     )
  348.     {
  349.     FAST int ix;
  350.     for (ix = 0; ix < bufLength; ix++)
  351. {
  352.         while (!(*pSpc->pPsnsReg & SPC_PSNS_REQ))
  353.             ;
  354.         if (atnReset && (ix == bufLength - 1))
  355.             spcCommand (pSpc, SPC_SCMD_RESET_ATN);
  356.         *pSpc->pTempReg = *pBuffer++;
  357.         spcCommand (pSpc, SPC_SCMD_SET_ACK_REQ);
  358.         while (*pSpc->pPsnsReg & SPC_PSNS_REQ)
  359.             ;
  360.         spcCommand (pSpc, SPC_SCMD_RESET_ACK_REQ);
  361. }
  362.     return (OK);
  363.     }
  364. /*******************************************************************************
  365. *
  366. * spcManBytesIn - input byte(s) from SCSI using manual transfer
  367. *
  368. * RETURNS: OK.
  369. *
  370. * NOMANUAL
  371. */
  372. STATUS spcManBytesIn
  373.     (
  374.     FAST SPC *pSpc,             /* ptr to SPC info */
  375.     FAST UINT8 *pBuffer,        /* ptr to the input buffer */
  376.     FAST int bufLength          /* length of the input buffer */
  377.     )
  378.     {
  379.     FAST int ix;
  380.     for (ix = 0; ix < bufLength; ix++)
  381. {
  382.         while (!(*pSpc->pPsnsReg & SPC_PSNS_REQ))
  383.             ;
  384.         spcCommand (pSpc, SPC_SCMD_SET_ACK_REQ);
  385.         while (*pSpc->pPsnsReg & SPC_PSNS_REQ)
  386.             ;
  387.         *pBuffer++ = *pSpc->pTempReg;
  388. spcCommand (pSpc, SPC_SCMD_RESET_ACK_REQ);
  389. }
  390.     semGive (&pSpc->scsiCtrl.ctrlSyncSem);
  391.     return (OK);
  392.     }
  393. /*******************************************************************************
  394. *
  395. * spcMsgInAck - de-assert the ACK line to accept message
  396. *
  397. * This routine should be called when an incoming message has been read and
  398. * accepted.  If the incoming message did not imply an impending disconnect,
  399. * give the synchronization semaphore, so that subsequent phase can be
  400. * detected.
  401. *
  402. * RETURNS: OK.
  403. */
  404. LOCAL STATUS spcMsgInAck
  405.     (
  406.     FAST SCSI_CTRL *pScsiCtrl,  /* ptr to SPC info */
  407.     BOOL expectDisconn          /* whether a disconnect is expected */
  408.     )
  409.     {
  410.     spcCommand ((SPC *) pScsiCtrl, SPC_SCMD_RESET_ACK_REQ);
  411.     if (!expectDisconn)
  412. semGive (&pScsiCtrl->ctrlSyncSem);
  413.     return (OK);
  414.     }
  415. /*******************************************************************************
  416. *
  417. * spcProgBytesOut - output bytes to SCSI using 'program' transfer
  418. *
  419. * RETURNS: OK if successful, otherwise ERROR.
  420. *
  421. * INTERNAL
  422. * Error handling is inadequate.
  423. *
  424. * NOMANUAL
  425. */
  426. STATUS spcProgBytesOut
  427.     (
  428.     SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to physical device info */
  429.     FAST UINT8 *pBuffer,         /* ptr to the data buffer */
  430.     FAST int bufLength,          /* number of bytes to be transferred */
  431.     int scsiPhase                /* phase of the transfer */
  432.     )
  433.     {
  434.     FAST SPC *pSpc; /* ptr to SPC info */
  435.     SCSI_DEBUG_MSG ("spcProgBytesOut: bufLength = %d, scsiPhase = %dn",
  436.     bufLength, scsiPhase, 0, 0, 0, 0);
  437.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  438.     spcIntsDisable (pSpc);
  439.     if (spcXferCountSet (pSpc, bufLength) == ERROR)
  440. return (ERROR);
  441.     SPC_BUS_PHASE_SET(pSpc, scsiPhase);
  442.     if (scsiPhase == SCSI_COMMAND_PHASE)
  443.         spcTmodSet (pSpc, pScsiPhysDev->syncXfer, 0, 0);
  444.     spcScmdSet (pSpc, SPC_SCMD_XFER, 0, 0, 1, 0);
  445.     while (!(*pSpc->pSstsReg & SPC_SSTS_XFER))
  446.         ;
  447.     while (bufLength >= 8)
  448. {
  449.         while (!(*pSpc->pSstsReg & SPC_SSTS_DREG_EMPTY))
  450.             ;
  451.         *pSpc->pDregReg = *pBuffer++;
  452.         *pSpc->pDregReg = *pBuffer++;
  453.         *pSpc->pDregReg = *pBuffer++;
  454.         *pSpc->pDregReg = *pBuffer++;
  455.         *pSpc->pDregReg = *pBuffer++;
  456.         *pSpc->pDregReg = *pBuffer++;
  457.         *pSpc->pDregReg = *pBuffer++;
  458.         *pSpc->pDregReg = *pBuffer++;
  459. bufLength -= 8;
  460.         }
  461.     while (!(*pSpc->pSstsReg & SPC_SSTS_DREG_EMPTY))
  462.         ;
  463.     while (bufLength > 0)
  464.         {
  465.         *pSpc->pDregReg = *pBuffer++;
  466. bufLength--;
  467.         }
  468.     spcIntsEnable (pSpc);
  469.     return (OK);
  470.     }
  471. /*******************************************************************************
  472. *
  473. * spcProgBytesIn - input bytes from SCSI using 'program' transfer
  474. *
  475. * RETURNS: OK if successful, otherwise ERROR.
  476. *
  477. * INTERNAL
  478. * Error handling is inadequate.
  479. *
  480. * NOMANUAL
  481. */
  482. STATUS spcProgBytesIn
  483.     (
  484.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to physical device info */
  485.     FAST UINT8 *pBuffer,                /* ptr to the data buffer */
  486.     FAST int bufLength,                 /* number of bytes to be transferred */
  487.     int scsiPhase                       /* phase of the transfer */
  488.     )
  489.     {
  490.     FAST SPC *pSpc; /* ptr to SPC info */
  491.     SCSI_DEBUG_MSG ("spcProgBytesIn: bufLength = %d, scsiPhase = %dn",
  492.     bufLength, scsiPhase, 0, 0, 0, 0);
  493.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  494.     spcIntsDisable (pSpc);
  495.     if (spcXferCountSet (pSpc, bufLength) == ERROR)
  496. return (ERROR);
  497.     SPC_BUS_PHASE_SET(pSpc, scsiPhase);
  498.     spcScmdSet (pSpc, SPC_SCMD_XFER, 0, 0, 1, 0);
  499.     while (!(*pSpc->pSstsReg & SPC_SSTS_XFER))
  500.         ;
  501.     while (bufLength >= 8)
  502. {
  503.         while (!(*pSpc->pSstsReg & SPC_SSTS_DREG_FULL))
  504.             ;
  505.         *pBuffer++ = *pSpc->pDregReg;
  506.         *pBuffer++ = *pSpc->pDregReg;
  507.         *pBuffer++ = *pSpc->pDregReg;
  508.         *pBuffer++ = *pSpc->pDregReg;
  509.         *pBuffer++ = *pSpc->pDregReg;
  510.         *pBuffer++ = *pSpc->pDregReg;
  511.         *pBuffer++ = *pSpc->pDregReg;
  512.         *pBuffer++ = *pSpc->pDregReg;
  513. bufLength -= 8;
  514.         }
  515.     while (bufLength > 0)
  516.         {
  517.         while (*pSpc->pSstsReg & SPC_SSTS_DREG_EMPTY)
  518.             ;
  519.         *pBuffer++ = *pSpc->pDregReg;
  520. bufLength--;
  521.         }
  522.     spcIntsEnable (pSpc);
  523.     return (OK);
  524.     }
  525. /******************************************************************************
  526. *
  527. * spcDmaBytesOut - Setup DMA transfer on the device
  528. *
  529. * RETURNS: OK, or ERROR if the count is not set properly.
  530. */
  531. LOCAL STATUS spcDmaBytesOut
  532.     (
  533.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to phys dev info    */
  534.     UINT8 *pBuffer,                     /* prt to the data buffer  */
  535.     int    bufLength,                   /* nubmer of bytes to xfer */
  536.     int    scsiPhase
  537.     )
  538.     {
  539.     FAST SPC *pSpc;             /* ptr to SPC info */
  540.     SCSI_DEBUG_MSG ("spcDmaBytesOut: bufLength = %d, Address = %08xn",
  541.                     bufLength, (int) &pBuffer, 0, 0, 0, 0);
  542.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  543.     spcIntsDisable (pSpc);
  544.     if (spcXferCountSet (pSpc, bufLength) == ERROR)
  545.         return (ERROR);
  546.     SPC_BUS_PHASE_SET(pSpc, scsiPhase);
  547.     if (scsiPhase == SCSI_COMMAND_PHASE)
  548.         spcTmodSet (pSpc, pScsiPhysDev->syncXfer, 0, 0);
  549.     spcScmdSet (pSpc, SPC_SCMD_XFER, 0, 0, 0, 0);
  550.     return ((pSpc->scsiCtrl.scsiDmaBytesOut)
  551.             (pScsiPhysDev, (UINT8 *) pBuffer, bufLength));
  552.     }
  553.  
  554. /*******************************************************************************
  555. *
  556. * spcBytesOut - branch to the appropriate output routine dependent on SCSI phase
  557. *
  558. * RETURNS: OK if specified bytes were output successfully, otherwise ERROR.
  559. */
  560. LOCAL STATUS spcBytesOut
  561.     (
  562.     FAST SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical dev info */
  563.     FAST char *pBuffer,                 /* ptr to byte buffer for output */
  564.     int bufLength,                      /* number of bytes to be transferred */
  565.     int scsiPhase                       /* SCSI bus phase of the transfer */
  566.     )
  567.     {
  568.     FAST SPC *pSpc; /* ptr to SPC info */
  569.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  570.     if ((scsiPhase != SCSI_DATA_OUT_PHASE) ||
  571. (pSpc->scsiCtrl.scsiDmaBytesOut == NULL) ||
  572. (bufLength < 10))
  573. return (spcProgBytesOut (pScsiPhysDev, (UINT8 *) pBuffer,
  574.  bufLength, scsiPhase));
  575.     else
  576. return ((spcDmaBytesOut)
  577. (pScsiPhysDev, (UINT8 *) pBuffer, bufLength, scsiPhase));
  578.     }
  579. /******************************************************************************
  580. *
  581. * spcDmaBytesIn - Setup DMA transfer on the device
  582. *
  583. * RETURNS: OK, or ERROR if the count is not set properly.
  584. */
  585. LOCAL STATUS spcDmaBytesIn
  586.     (
  587.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to phys dev info    */
  588.     UINT8 *pBuffer,                     /* prt to the data buffer  */
  589.     int    bufLength,                   /* nubmer of bytes to xfer */
  590.     int    scsiPhase
  591.     )
  592.     {
  593.     FAST SPC *pSpc;             /* ptr to SPC info */
  594.     SCSI_DEBUG_MSG ("spcDmaBytesIn: bufLength = %d, Addr = %08xn",
  595.                     bufLength, (int) &pBuffer, 0, 0, 0, 0);
  596.  
  597.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  598.     spcIntsDisable (pSpc);
  599.     if (spcXferCountSet (pSpc, bufLength) == ERROR)
  600.         return (ERROR);
  601.     SPC_BUS_PHASE_SET(pSpc, scsiPhase);
  602.     spcScmdSet (pSpc, SPC_SCMD_XFER, 0, 0, 0, 0);
  603.     return ((pSpc->scsiCtrl.scsiDmaBytesIn)
  604.             (pScsiPhysDev, (UINT8 *) pBuffer, bufLength));
  605.     }
  606. /*******************************************************************************
  607. *
  608. * spcBytesIn - branch to the appropriate input routine dependent on SCSI phase
  609. *
  610. * RETURNS: OK if requested bytes were input successfully, otherwise ERROR.
  611. */
  612. LOCAL STATUS spcBytesIn
  613.     (
  614.     FAST SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical dev info */
  615.     FAST char *pBuffer,                 /* ptr to byte buffer for output */
  616.     int bufLength,                      /* number of bytes to be transferred */
  617.     int scsiPhase                       /* SCSI bus phase of the transfer */
  618.     )
  619.     {
  620.     FAST SPC *pSpc; /* ptr to SPC info */
  621.     pSpc = (SPC *) pScsiPhysDev->pScsiCtrl;
  622.     switch (scsiPhase)
  623. {
  624. case SCSI_DATA_IN_PHASE:
  625.     if ((pSpc->scsiCtrl.scsiDmaBytesIn == NULL) ||
  626. (bufLength < 10))
  627. return (spcProgBytesIn (pScsiPhysDev, (UINT8 *) pBuffer,
  628.         bufLength, scsiPhase));
  629.     else
  630. return (spcDmaBytesIn (pScsiPhysDev, (UINT8 *) pBuffer,
  631.      bufLength, scsiPhase));
  632. case SCSI_STATUS_PHASE:
  633.     return (spcProgBytesIn (pScsiPhysDev, (UINT8 *) pBuffer,
  634.     bufLength, scsiPhase));
  635. case SCSI_MSG_IN_PHASE:
  636.     return (spcManBytesIn (pSpc, (UINT8 *) pBuffer, bufLength));
  637. }
  638.     return (ERROR);
  639.     }
  640. #define CYCLES_PER_USEC  1
  641. /*******************************************************************************
  642. *
  643. * spcBusPhaseGet - return the current SCSI bus phase in *pBusPhase
  644. *
  645. * INTERNAL
  646. * Should do an errnoSet.
  647. */
  648. LOCAL STATUS spcBusPhaseGet
  649.     (
  650.     FAST SCSI_CTRL *pScsiCtrl,  /* ptr to SCSI controller info */
  651.     int timeOutInUsec,          /* timeout in usec (0 == infinity) */
  652.     int *pBusPhase              /* ptr to returned bus phase */
  653.     )
  654.     {
  655.     FAST int ix = 0; /* loop index */
  656.     FAST SPC *pSpc; /* ptr to SPC info */
  657.     FAST int maxCycles; /* maximum cycles to wait for REQ signal */
  658.     pSpc = (SPC *) pScsiCtrl;
  659.     maxCycles = timeOutInUsec * CYCLES_PER_USEC;
  660.     if (semTake (&pScsiCtrl->ctrlSyncSem, sysClkRateGet() * 5) == ERROR)
  661. {
  662. spcScsiBusReset (pSpc); /* the bus is hung(?), reset it */
  663. return (ERROR);
  664. }
  665.     while (!(*pSpc->pPsnsReg & SPC_PSNS_REQ) &&
  666.    (pScsiCtrl->scsiBusPhase != SCSI_BUS_FREE_PHASE))
  667. {
  668. if ((maxCycles > 0) && (ix++ == maxCycles))
  669.     {
  670.     if (scsiDebug)
  671.         logMsg ("spcBusPhaseGet: timed-out waiting for REQn",
  672. 0, 0, 0, 0, 0, 0);
  673.     spcScsiBusReset (pSpc); /* the bus is hung(?), reset it */
  674.     return (ERROR);
  675.     }
  676. }
  677.     if (pScsiCtrl->scsiBusPhase == SCSI_BUS_FREE_PHASE)
  678.         {
  679.         *pBusPhase = SCSI_BUS_FREE_PHASE;
  680.         pScsiCtrl->scsiBusPhase = NONE;
  681.         return (OK);
  682.         }
  683.     *pBusPhase = pScsiCtrl->scsiBusPhase =
  684. (int) (*pSpc->pPsnsReg & SPC_PSNS_PHASE_MASK);
  685.     SCSI_DEBUG_MSG ("scsiPhase = %xn", *pBusPhase, 0, 0, 0, 0, 0);
  686.     return (OK);
  687.     }
  688. /*******************************************************************************
  689. *
  690. * byteParityGet - return the parity of a given byte
  691. *
  692. * RETURNS: 1 for odd parity, 0 for even parity.
  693. */
  694. LOCAL int byteParityGet
  695.     (
  696.     FAST UINT8 byte             /* byte for which to report parity */
  697.     )
  698.     {
  699.     FAST int result = 0; /* cumulative parity of byte */
  700.     FAST int ix; /* loop variable */
  701.     for (ix = 0; ix < 8; ix++)
  702. {
  703. if (byte & ((UINT8) (1 << ix)))
  704.     result ^= 0x1;
  705. }
  706.     return (result);
  707.     }
  708. /*******************************************************************************
  709. *
  710. * spcSelTimeOutCvt - convert a select time-out in microseconds to its
  711. *      equivalent SPC setting
  712. *
  713. * The conversion formula is given on p. 4-8 of the 1988 Fujitsu SCSI Product
  714. * Profiles manual.  The additive constant 15 has been omitted here since it is
  715. * trivial.  Note that 0 translates to the standard setting of 250 usec.  Also,
  716. * the SPC accepts up to a 16 bit time-out, so a maximum value of 0xffff is
  717. * returned in *pTimeOutSetting.
  718. */
  719. LOCAL void spcSelTimeOutCvt
  720.     (
  721.     FAST SCSI_CTRL *pScsiCtrl,          /* ptr to SCSI controller info */
  722.     FAST UINT timeOutInUsec,            /* time-out in microsecs */
  723.     FAST UINT *pTimeOutSetting          /* time-out equivalent setting */
  724.     )
  725.     {
  726.     FAST SPC *pSpc = (SPC *) pScsiCtrl; /* ptr to SPC info */
  727.     FAST UINT tempSelTimeOut; /* temp. select time-out setting */
  728.     int msbParity; /* parity of MSB of tempSelTimeOut */
  729.     int lsbParity; /* parity of LSB of tempSelTimeOut */
  730.     if (timeOutInUsec == 0)
  731. timeOutInUsec = SCSI_DEF_SELECT_TIMEOUT;
  732.     tempSelTimeOut = (((timeOutInUsec * 1000) >> 9) / pScsiCtrl->clkPeriod) + 1;
  733.     if (tempSelTimeOut > 0xffff)
  734. tempSelTimeOut = 0xffff;
  735.     if (pSpc->spcDataParity != SPC_DATA_PARITY_VALID)
  736. {
  737. msbParity = byteParityGet ((UINT8) MSB(tempSelTimeOut));
  738. lsbParity = byteParityGet ((UINT8) LSB(tempSelTimeOut));
  739. if (msbParity == pSpc->spcDataParity)
  740.     tempSelTimeOut ^= 0x100;
  741. if (lsbParity == pSpc->spcDataParity)
  742.     tempSelTimeOut ^= 0x1;
  743. }
  744.     *pTimeOutSetting = tempSelTimeOut;
  745.     }
  746. /*******************************************************************************
  747. *
  748. * spcBusIdGet - get the current SCSI bus ID of the SPC.
  749. *
  750. * Copies the bus ID to <pBusId>.
  751. *
  752. * RETURNS:
  753. * OK if Bus ID register holds a legal value, otherwise ERROR.
  754. */
  755. LOCAL STATUS spcBusIdGet
  756.     (
  757.     FAST SPC *pSpc,             /* ptr to SPC info */
  758.     FAST int *pBusId            /* ptr to returned bus ID */
  759.     )
  760.     {
  761.     FAST UINT8 tempReg;  /* local copy of bus device ID register */
  762.     FAST int ix; /* count index */
  763.     tempReg = *pSpc->pBdidReg;
  764.     for (ix = SCSI_MIN_BUS_ID; ix <= SCSI_MAX_BUS_ID; ix++)
  765. {
  766. if (tempReg == (UINT8) (1 << ix))
  767.     {
  768.     *pBusId = ix;
  769.     return (OK);
  770.     }
  771. }
  772.     *pBusId = NONE;
  773.     return (ERROR);
  774.     }
  775. /*******************************************************************************
  776. *
  777. * spcXferCountSet - load the SPC transfer counter with the specified count
  778. *
  779. * RETURNS:
  780. * OK if count is in range 0 - 0xffffff, otherwise ERROR.
  781. *
  782. * NOMANUAL
  783. */
  784. STATUS spcXferCountSet
  785.     (
  786.     FAST SPC *pSpc,     /* ptr to SPC info */
  787.     FAST int count      /* count value to load */
  788.     )
  789.     {
  790.     if (count < 0 || count > SPC_MAX_XFER_LENGTH)
  791.         return (ERROR);
  792.     else
  793.         {
  794.         *pSpc->pTchReg = (UINT8) ((count >> 16) & 0xff);
  795.         *pSpc->pTcmReg = (UINT8) ((count >>  8) & 0xff);
  796.         *pSpc->pTclReg = (UINT8)  (count   & 0xff);
  797.         return (OK);
  798.         }
  799.     }
  800. /*******************************************************************************
  801. *
  802. * spcXferCountGet - fetch the SPC transfer count
  803. *
  804. * RETURNS: The value of the transfer counter is returned in *pCount.
  805. *
  806. * NOMANUAL
  807. */
  808. void spcXferCountGet
  809.     (
  810.     FAST SPC *pSpc,             /* ptr to SPC info */
  811.     FAST int *pCount            /* ptr to returned value */
  812.     )
  813.     {
  814.     FAST UINT tempCount = 0;
  815.     tempCount |=  (UINT) *pSpc->pTclReg;
  816.     tempCount |= ((UINT) *pSpc->pTcmReg) << 8;
  817.     tempCount |= ((UINT) *pSpc->pTchReg) << 16;
  818.     *pCount = tempCount;
  819.     }
  820. /*******************************************************************************
  821. *
  822. * spcIntsEnable - enable the SPC to assert interrupts
  823. *
  824. * This routine sets the INT Enable bit in the SPC Control register.
  825. */
  826. LOCAL void spcIntsEnable
  827.     (
  828.     FAST SPC *pSpc      /* ptr to SPC info */
  829.     )
  830.     {
  831.     *pSpc->pSctlReg |= SPC_SCTL_INT_ENBL;
  832.     }
  833. /*******************************************************************************
  834. *
  835. * spcIntsDisable - disable the SPC to assert interrupts
  836. *
  837. * This routine resets the INT Enable bit in the SPC Control register.
  838. */
  839. LOCAL void spcIntsDisable
  840.     (
  841.     FAST SPC *pSpc      /* ptr to SPC info */
  842.     )
  843.     {
  844.     *pSpc->pSctlReg &= ~SPC_SCTL_INT_ENBL;
  845.     }
  846. /*******************************************************************************
  847. *
  848. * spcScmdSet - write to the SPC Command Register
  849. *
  850. * Provides maximum flexibility in controlling the options of the Command Reg.
  851. * The passed parameter for each bit should be set to SPC_RESET_BIT (0),
  852. * SPC_SET_BIT (1), or SPC_PRESERVE_BIT (-1).  In the case of the command code,
  853. * either the desired command code or SPC_PRESERVE_FIELD (0xff) should be passed.
  854. */
  855. LOCAL void spcScmdSet
  856.     (
  857.     FAST SPC *pSpc,         /* ptr to SPC info */
  858.     FAST UINT8 cmdCode,     /* new command code or SPC_PRESERVE_FIELD */
  859.     int resetOutBit,        /* set, reset, or preserve "reset out" bit */
  860.     int interceptXferBit,   /* set, reset, or preserve "intercept xfer" bit */
  861.     int prgXferBit,         /* set, reset, or preserve "program transfer" bit */
  862.     int termModeBit         /* set, reset, or preserve "termination mode" bit */
  863.     )
  864.     {
  865.     FAST UINT8 tempScmd;    /* temporary copy of SPC Command register */
  866.     tempScmd = *pSpc->pScmdReg;
  867.     if (cmdCode != SPC_PRESERVE_FIELD)
  868.         {
  869.         tempScmd &= ~SPC_SCMD_CMD_MASK;     /* clear existing command code */
  870.                                             /* fill in the desired command */
  871.         tempScmd |= (cmdCode & SPC_SCMD_CMD_MASK);
  872.         }
  873.     switch (resetOutBit)
  874.         {
  875.         case SPC_PRESERVE_BIT:  break;
  876.         case SPC_SET_BIT:       tempScmd |= SPC_SCMD_RESET_OUT; break;
  877.         case SPC_RESET_BIT:     tempScmd &= ~SPC_SCMD_RESET_OUT; break;
  878.         }
  879.     switch (interceptXferBit)
  880.         {
  881.         case SPC_PRESERVE_BIT:  break;
  882.         case SPC_SET_BIT:       tempScmd |= SPC_SCMD_INTERCEPT_XFER; break;
  883.         case SPC_RESET_BIT:     tempScmd &= ~SPC_SCMD_INTERCEPT_XFER; break;
  884.         }
  885.     switch (prgXferBit)
  886.         {
  887.         case SPC_PRESERVE_BIT:  break;
  888.         case SPC_SET_BIT:       tempScmd |= SPC_SCMD_PRG_XFER; break;
  889.         case SPC_RESET_BIT:     tempScmd &= ~SPC_SCMD_PRG_XFER; break;
  890.         }
  891.     switch (termModeBit)
  892.         {
  893.         case SPC_PRESERVE_BIT:  break;
  894.         case SPC_SET_BIT:       tempScmd |= SPC_SCMD_TERM_MODE; break;
  895.         case SPC_RESET_BIT:     tempScmd &= ~SPC_SCMD_TERM_MODE; break;
  896.         }
  897.     *pSpc->pScmdReg = tempScmd;
  898.     }
  899. /*******************************************************************************
  900. *
  901. * spcCommand - write a command code to the SPC Command Register
  902. *
  903. * NOMANUAL
  904. */
  905. void spcCommand
  906.     (
  907.     FAST SPC *pSpc,     /* ptr to SPC info */
  908.     FAST UINT8 cmdCode      /* new command code */
  909.     )
  910.     {
  911.     FAST UINT8 tempScmd;    /* temporary copy of SPC Command register */
  912.     tempScmd = *pSpc->pScmdReg;
  913.     tempScmd &= ~SPC_SCMD_CMD_MASK;        /* clear existing command code */
  914.     tempScmd |= (cmdCode & SPC_SCMD_CMD_MASK); /* fill in the desired command */
  915.     *pSpc->pScmdReg = tempScmd;
  916.     }
  917. /*******************************************************************************
  918. *
  919. * spcTmodSet - write to the SPC Transfer Mode Register
  920. *
  921. * Used to set up SPC for synchronous or asynchronous data transfers. maxOffset
  922. * and minPeriod parameters may be specified as legal values:
  923. *           maxOffset:          1 - 8       (see Fujitsu documentation)
  924. *           minPerMinusOne:     0 - 3       (see Fujitsu documentation)
  925. * or as SPC_PRESERVE_FIELD (0xff).  They will be ignored if syncXfer is FALSE,
  926. * since they are only relevant to synchronous transfer mode.  Illegal values
  927. * will merely be masked into legality.
  928. */
  929. LOCAL void spcTmodSet
  930.     (
  931.     FAST SPC *pSpc,     /* ptr to SPC info */
  932.     BOOL syncXfer,              /* TRUE for synch. xfer, FALSE for asynch. */
  933.     FAST int maxOffset,         /* maximum transfer offset */
  934.     FAST int minPerMinusOne     /* minimum transfer period minus one */
  935.     )
  936.     {
  937.     FAST UINT8 tempTmod;    /* temporary copy of SPC Transfer Mode register */
  938.     tempTmod = *pSpc->pTmodReg;
  939.     if (syncXfer == FALSE)
  940.         tempTmod &= ~SPC_TMOD_SYNC_XFER;
  941.     else
  942.         {
  943.         tempTmod |= SPC_TMOD_SYNC_XFER;
  944.         if (maxOffset != SPC_PRESERVE_FIELD)
  945.             {
  946.             tempTmod &= ~SPC_TMOD_MAX_OFFSET_MASK;  /* clear existing offset */
  947.                                                     /* set the desired offset */
  948.             tempTmod |= ((maxOffset << 4) & SPC_TMOD_MAX_OFFSET_MASK);
  949.             }
  950.         if (minPerMinusOne != SPC_PRESERVE_FIELD)
  951.             {
  952.             tempTmod &= ~SPC_TMOD_MIN_PERIOD_MASK;  /* clear existing period */
  953.                                                     /* set the desired period */
  954.             tempTmod |= ((minPerMinusOne << 2) & SPC_TMOD_MIN_PERIOD_MASK);
  955.             }
  956.         }
  957.     *pSpc->pTmodReg = tempTmod;
  958.     }
  959. /*******************************************************************************
  960. *
  961. * spcPctlSet - write to the SPC Phase Control Register
  962. *
  963. * Provides flexibility in controlling the options of the Phase Control Reg.
  964. * The passed parameter for the busFreeIntEnbl bit should be set to
  965. * SPC_RESET_BIT (0), SPC_SET_BIT (1), or SPC_PRESERVE_BIT (-1).  In the case
  966. * of the transfer phase, either the desired phase or SPC_PRESERVE_FIELD
  967. * (0xff) should be passed.
  968. */
  969. LOCAL void spcPctlSet
  970.     (
  971.     FAST SPC *pSpc,         /* ptr to SPC info */
  972.     int busFreeIntEnblBit,  /* set, reset, or preserve "bus free int." bit */
  973.     FAST UINT8 xferPhase    /* new transfer phase or SPC_PRESERVE_FIELD */
  974.     )
  975.     {
  976.     FAST UINT8 tempPctl;    /* temporary copy of SPC Pctl register */
  977.     tempPctl = *pSpc->pPctlReg;
  978.     switch (busFreeIntEnblBit)
  979.         {
  980.         case SPC_PRESERVE_BIT:  break;
  981.         case SPC_SET_BIT:       tempPctl |= SPC_PCTL_BF_INT_ENBL; break;
  982.         case SPC_RESET_BIT:     tempPctl &= ~SPC_PCTL_BF_INT_ENBL; break;
  983.         }
  984.     if (xferPhase != SPC_PRESERVE_FIELD)
  985.         {
  986.         tempPctl &= ~SPC_PCTL_PHASE_MASK;   /* clear existing xfer phase */
  987.                                             /* fill in the new phase */
  988.         tempPctl |= (xferPhase & SPC_PCTL_PHASE_MASK);
  989.         }
  990.     *pSpc->pPctlReg = tempPctl;
  991.     }
  992. /*******************************************************************************
  993. *
  994. * spcScsiBusReset - assert the RST line on the SCSI bus
  995. *
  996. * Asserts the RST line on SCSI which should cause all connected devices to
  997. * return to a quiescent state.
  998. * JCC Timing delays should be made prettier and more precise.
  999. */
  1000. LOCAL void spcScsiBusReset
  1001.     (
  1002.     FAST SPC *pSpc      /* ptr to SPC info */
  1003.     )
  1004.     {
  1005.     int delayVar; /* delay loop counter */
  1006.     spcScmdSet (pSpc,
  1007.                 SPC_SCMD_BUS_RELEASE,
  1008.                 SPC_SET_BIT,
  1009.                 SPC_PRESERVE_BIT,
  1010.                 SPC_PRESERVE_BIT,
  1011.                 SPC_PRESERVE_BIT);
  1012.     for (delayVar = 0; delayVar < 0x1000; delayVar++)
  1013. ;
  1014.     spcScmdSet (pSpc,
  1015.                 SPC_PRESERVE_FIELD,
  1016.                 SPC_RESET_BIT,
  1017.                 SPC_PRESERVE_BIT,
  1018.                 SPC_PRESERVE_BIT,
  1019.                 SPC_PRESERVE_BIT);
  1020.     for (delayVar = 0; delayVar < 0x2000; delayVar++)
  1021. ;
  1022.     }
  1023. LOCAL BOOL spcHardErrPrint = FALSE;
  1024. LOCAL int hardErrors = 0;
  1025. /*******************************************************************************
  1026. *
  1027. * spcIntr - interrupt service routine for the SPC
  1028. *
  1029. * NOMANUAL
  1030. */
  1031. void spcIntr
  1032.     (
  1033.     SPC *pSpc          /* ptr to SPC info */
  1034.     )
  1035.     {
  1036.     FAST SCSI_PHYS_DEV *pDevToSelect;
  1037.     FAST UINT8 tempInts;
  1038.     FAST UINT8 tempSerr;
  1039.     tempInts = *pSpc->pIntsReg;
  1040.     tempSerr = *pSpc->pSerrReg;
  1041.     if (scsiIntsDebug)
  1042.         logMsg ("*** SPC INTERRUPT: Ints %08x, Serr %08x", tempInts, tempSerr,
  1043. 0, 0, 0, 0);
  1044.     if (tempInts & SPC_INTS_SELECTED)
  1045.         {
  1046. /* this is currently not supported */
  1047.         *pSpc->pIntsReg = SPC_INTS_SELECTED;
  1048. if (scsiIntsDebug)
  1049.             logMsg ("Selected ", 0, 0, 0, 0, 0, 0);
  1050.         }
  1051.     if (tempInts & SPC_INTS_RESELECTED)
  1052.         {
  1053.         *pSpc->pIntsReg = SPC_INTS_RESELECTED;
  1054. if (scsiIntsDebug)
  1055.             logMsg ("Reselected ", 0, 0, 0, 0, 0, 0);
  1056.      /* if a selection attempt has been made, report lost arbitration */
  1057. if (((pDevToSelect = pSpc->pDevToSelect) != (SCSI_PHYS_DEV *) NULL) &&
  1058.     (pDevToSelect->devStatus == SELECT_IN_PROGRESS))
  1059.     {
  1060.     pDevToSelect->devStatus = SELECT_LOST_ARBIT;
  1061.     pSpc->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  1062.     semGive (&pDevToSelect->devSyncSem);
  1063.     }
  1064.         }
  1065.     if (tempInts & SPC_INTS_COM_COMPLETE)
  1066.         {
  1067.         *pSpc->pIntsReg = SPC_INTS_COM_COMPLETE;
  1068. if (scsiIntsDebug)
  1069.             logMsg ("commComplete ", 0, 0, 0, 0, 0, 0);
  1070.      /* if a selection attempt has been made, report success */
  1071. if (((pDevToSelect = pSpc->pDevToSelect) != (SCSI_PHYS_DEV *) NULL) &&
  1072.     (pDevToSelect->devStatus == SELECT_IN_PROGRESS))
  1073.     {
  1074.     pDevToSelect->devStatus = SELECT_SUCCESSFUL;
  1075.     pSpc->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  1076.     semGive (&pDevToSelect->devSyncSem);
  1077.     }
  1078. semGive (&pSpc->scsiCtrl.ctrlSyncSem);
  1079.         }
  1080.     if (tempInts & SPC_INTS_TIMEOUT)
  1081.         {
  1082.         *pSpc->pIntsReg = SPC_INTS_TIMEOUT;
  1083. if (scsiIntsDebug)
  1084.             logMsg ("Timeout ", 0, 0, 0, 0, 0, 0);
  1085.      /* if a selection attempt has been made, report the time-out */
  1086. if (((pDevToSelect = pSpc->pDevToSelect) != (SCSI_PHYS_DEV *) NULL) &&
  1087.     (pDevToSelect->devStatus == SELECT_IN_PROGRESS))
  1088.     {
  1089.     pDevToSelect->devStatus = SELECT_TIMEOUT;
  1090.     pSpc->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  1091.     semGive (&pDevToSelect->devSyncSem);
  1092.     }
  1093.         }
  1094.     if (tempInts & SPC_INTS_DISCONNECT)
  1095.         {
  1096. spcPctlSet (pSpc, SPC_RESET_BIT, SPC_PCTL_SELECT);
  1097.         *pSpc->pIntsReg = SPC_INTS_DISCONNECT;
  1098. if (scsiIntsDebug)
  1099.             logMsg ("Disconnect ", 0, 0, 0, 0, 0, 0);
  1100.      /* if a device is to be selected, do so now */
  1101. if (((pDevToSelect = pSpc->pDevToSelect) != (SCSI_PHYS_DEV *) NULL) &&
  1102.          (pDevToSelect->devStatus == SELECT_REQUESTED))
  1103.     {
  1104.     if (pDevToSelect->useIdentify)
  1105. {
  1106.         spcCommand (pSpc, SPC_SCMD_SET_ATN);
  1107. }
  1108.     *pSpc->pTempReg = pSpc->selectTempReg;
  1109.     (void) spcXferCountSet (pSpc,
  1110.     (int) (pDevToSelect->selTimeOut << 8) |
  1111.       (pSpc->busFreeDelay));
  1112.     spcCommand (pSpc, SPC_SCMD_SELECT);
  1113.     pDevToSelect->devStatus = SELECT_IN_PROGRESS;
  1114.     }
  1115. else
  1116.     {
  1117.     pSpc->scsiCtrl.scsiBusPhase = SCSI_BUS_FREE_PHASE;
  1118.     semGive (&pSpc->scsiCtrl.ctrlSyncSem);
  1119.     }
  1120.         }
  1121.     if (tempInts & SPC_INTS_SERVICE_REQ)
  1122.         {
  1123.         *pSpc->pIntsReg = SPC_INTS_SERVICE_REQ;
  1124. if (scsiIntsDebug)
  1125.     {
  1126.             logMsg ("serviceReq (sstsReg = 0x%02x) ", *pSpc->pSstsReg,
  1127. 0, 0, 0, 0, 0);
  1128.     }
  1129.         }
  1130.     if (tempInts & SPC_INTS_HARD_ERROR)
  1131.         {
  1132.         *pSpc->pIntsReg = SPC_INTS_HARD_ERROR;
  1133. if (scsiIntsDebug)
  1134.     {
  1135.             hardErrors++;
  1136.             if (spcHardErrPrint)
  1137.                 {
  1138.                 logMsg ("hardError (serrReg = 0x%02x) ", tempSerr,
  1139. 0, 0, 0, 0, 0);
  1140.                 }
  1141.     }
  1142.         }
  1143.     /* the following condition should not attain under allowable SCSI
  1144.      * configurations (i.e., vxWorks target is the sole initiator)
  1145.      */
  1146.     if (tempInts & SPC_INTS_RESET_COND)
  1147.         {
  1148.         *pSpc->pIntsReg = SPC_INTS_RESET_COND;
  1149. if (scsiIntsDebug)
  1150.             logMsg ("Reset (unexpected, multiple intiators not supported)",
  1151. 0, 0, 0, 0, 0, 0);
  1152.         }
  1153.     if (scsiIntsDebug)
  1154. logMsg ("n", 0, 0, 0, 0, 0, 0);
  1155.     }
  1156. /*******************************************************************************
  1157. *
  1158. * spcHwInit - initialize the SPC chip to a known state
  1159. *
  1160. * This routine puts the SPC into a known quiescent state and issues a reset
  1161. * to the SCSI Bus if any signals are active, thus putting target devices in
  1162. * some presumably known state.  Currently the initial state is not configurable
  1163. * and does not enable reselection.
  1164. *
  1165. * INTERNAL
  1166. * Needs to handle parity enable
  1167. */
  1168. LOCAL void spcHwInit
  1169.     (
  1170.     SPC *pSpc          /* ptr to an SPC info structure */
  1171.     )
  1172.     {
  1173.     UINT8 tempSctl;
  1174.     tempSctl = SPC_SCTL_RESET_AND_DSBL | SPC_SCTL_INT_ENBL;
  1175.     if (pSpc->scsiCtrl.disconnect)
  1176. tempSctl |= (SPC_SCTL_ARBIT_ENBL | SPC_SCTL_RESELECT_ENBL);
  1177.     *pSpc->pSctlReg = tempSctl;
  1178.     /* set SCSI bus ID of controller */
  1179.     *pSpc->pBdidReg = pSpc->scsiCtrl.scsiCtrlBusId;
  1180.     *pSpc->pScmdReg = (UINT8) 0; /* set cmd to 'bus release' */
  1181.     *pSpc->pTmodReg = (UINT8) 0; /* asynch data transfer initially */
  1182.     *pSpc->pPctlReg = (UINT8) 0; /* bus free int disabled, no phase */
  1183.     (void) spcXferCountSet (pSpc, 0x00); /* clear xfer counter */
  1184.     *pSpc->pSctlReg &= ~SPC_SCTL_RESET_AND_DSBL;
  1185.     spcScsiBusReset (pSpc);
  1186.     }
  1187. /*******************************************************************************
  1188. *
  1189. * mb87030Show - display the values of all readable MB87030 SPC registers
  1190. *
  1191. * This routine displays the state of the SPC registers in a user-friendly 
  1192. * manner.  It is useful primarily for debugging.
  1193. *
  1194. * EXAMPLE:
  1195. * .CS
  1196. *     -> mb87030Show
  1197. *     SCSI Bus ID: 7    
  1198. *     SCTL (0x01): intsEnbl  
  1199. *     SCMD (0x00): busRlease 
  1200. *     TMOD (0x00): asyncMode 
  1201. *     INTS (0x00):            
  1202. *     PSNS (0x00): req0 ack0 atn0 sel0 bsy0 msg0 c_d0 i_o0 
  1203. *     SSTS (0x05): noConIdle xferCnt=0 dregEmpty 
  1204. *     SERR (0x00): noParErr  
  1205. *     PCTL (0x00): bfIntDsbl phDataOut 
  1206. *     MBC  (0x00): 0         
  1207. *     XFER COUNT : 0x000000 =         0
  1208. * .CE
  1209. *
  1210. * RETURNS: OK, or ERROR if <pScsiCtrl> and <pSysScsiCtrl> are both NULL.
  1211. */
  1212. STATUS mb87030Show
  1213.     (
  1214.     FAST SCSI_CTRL *pScsiCtrl /* ptr to SCSI controller info */
  1215.     )
  1216.     {
  1217.     int busId;
  1218.     FAST UINT8 tempReg;
  1219.     FAST SPC *pSpc; /* ptr to SPC info */
  1220.     int xferCount;
  1221.     if (pScsiCtrl == NULL)
  1222. {
  1223. if (pSysScsiCtrl == NULL)
  1224.     {
  1225.     printErr ("No SCSI controller specified.n");
  1226.     return (ERROR);
  1227.     }
  1228. pScsiCtrl = pSysScsiCtrl;
  1229. }
  1230.     pSpc = (MB_87030_SCSI_CTRL *) pScsiCtrl;
  1231.     /* Display current SCSI Bus ID */
  1232.     if (spcBusIdGet (pSpc, &busId) == OK)
  1233.         printf ("SCSI Bus ID: %-5dn", busId);
  1234.     else
  1235.         printf ("SCSI Bus ID: ERRORn");
  1236.     /* Display SPC Control Register */
  1237.     tempReg = *pSpc->pSctlReg;
  1238.     printf ("SCTL (0x%02x): ", (int) tempReg);
  1239.     printf ("%s", (tempReg & SPC_SCTL_RESET_AND_DSBL) ? "spcDisabl " : "");
  1240.     printf ("%s", (tempReg & SPC_SCTL_CTRL_RESET)     ? "ctrlReset " : "");
  1241.     printf ("%s", (tempReg & SPC_SCTL_DIAG_MODE)      ? "diagMode  " : "");
  1242.     printf ("%s", (tempReg & SPC_SCTL_ARBIT_ENBL)     ? "arbitEnbl " : "");
  1243.     printf ("%s", (tempReg & SPC_SCTL_PARITY_ENBL)    ? "paritEnbl " : "");
  1244.     printf ("%s", (tempReg & SPC_SCTL_SELECT_ENBL)    ? "selecEnbl " : "");
  1245.     printf ("%s", (tempReg & SPC_SCTL_RESELECT_ENBL)  ? "reselEnbl " : "");
  1246.     printf ("%s", (tempReg & SPC_SCTL_INT_ENBL)       ? "intsEnbl  " : "");
  1247.     printf ("n");
  1248.     /* Display Command Register */
  1249.     tempReg = *pSpc->pScmdReg;
  1250.     printf ("SCMD (0x%02x): ", (int) tempReg);
  1251.     switch (tempReg & SPC_SCMD_CMD_MASK)
  1252.         {
  1253.         case SPC_SCMD_BUS_RELEASE:   printf ("busRlease "); break;
  1254.         case SPC_SCMD_SELECT:        printf ("select    "); break;
  1255.         case SPC_SCMD_RESET_ATN:     printf ("resetAtn  "); break;
  1256.         case SPC_SCMD_SET_ATN:       printf ("setAtn    "); break;
  1257.         case SPC_SCMD_XFER:          printf ("transfer  "); break;
  1258.         case SPC_SCMD_XFER_PAUSE:    printf ("xferPause "); break;
  1259.         case SPC_SCMD_RESET_ACK_REQ: printf ("resAckReq "); break;
  1260.         case SPC_SCMD_SET_ACK_REQ:   printf ("setAckReq "); break;
  1261.         }
  1262.     printf ("%s", (tempReg & SPC_SCMD_RESET_OUT)       ? "resetOut  " : "");
  1263.     printf ("%s", (tempReg & SPC_SCMD_INTERCEPT_XFER)  ? "intcptXfr " : "");
  1264.     printf ("%s", (tempReg & SPC_SCMD_PRG_XFER)        ? "progXfer  " : "");
  1265.     printf ("%s", (tempReg & SPC_SCMD_TERM_MODE)       ? "termMode  " : "");
  1266.     printf ("n");
  1267.     /* Display Transfer Mode Register */
  1268.     tempReg = *pSpc->pTmodReg;
  1269.     printf ("TMOD (0x%02x): ", (int) tempReg);
  1270.     printf ("%s", (tempReg & SPC_TMOD_SYNC_XFER) ? "syncMode  " :
  1271.                                                    "asyncMode ");
  1272.     /* JCC Should display offset and period params also
  1273.     */
  1274.     printf ("n");
  1275.     /* Display Interrupt Sense Register */
  1276.     tempReg = *pSpc->pIntsReg;
  1277.     printf ("INTS (0x%02x): ", (int) tempReg);
  1278.     printf ("%s", (tempReg & SPC_INTS_SELECTED)     ? "selected  " : "");
  1279.     printf ("%s", (tempReg & SPC_INTS_RESELECTED)   ? "reselect  " : "");
  1280.     printf ("%s", (tempReg & SPC_INTS_DISCONNECT)   ? "disconnct " : "");
  1281.     printf ("%s", (tempReg & SPC_INTS_COM_COMPLETE) ? "comComplt " : "");
  1282.     printf ("%s", (tempReg & SPC_INTS_SERVICE_REQ)  ? "servReq   " : "");
  1283.     printf ("%s", (tempReg & SPC_INTS_TIMEOUT)      ? "timeout   " : "");
  1284.     printf ("%s", (tempReg & SPC_INTS_HARD_ERROR)   ? "hardError " : "");
  1285.     printf ("%s", (tempReg & SPC_INTS_RESET_COND)   ? "resetCond " : "");
  1286.     printf ("n");
  1287.     /* Display Phase Sense Register */
  1288.     tempReg = *pSpc->pPsnsReg;
  1289.     printf ("PSNS (0x%02x): ", (int) tempReg);
  1290.     printf ("%s", (tempReg & SPC_PSNS_REQ) ? "REQ1 " : "req0 ");
  1291.     printf ("%s", (tempReg & SPC_PSNS_ACK) ? "ACK1 " : "ack0 ");
  1292.     printf ("%s", (tempReg & SPC_PSNS_ATN) ? "ATN1 " : "atn0 ");
  1293.     printf ("%s", (tempReg & SPC_PSNS_SEL) ? "SEL1 " : "sel0 ");
  1294.     printf ("%s", (tempReg & SPC_PSNS_BSY) ? "BSY1 " : "bsy0 ");
  1295.     printf ("%s", (tempReg & SPC_PSNS_MSG) ? "MSG1 " : "msg0 ");
  1296.     printf ("%s", (tempReg & SPC_PSNS_C_D) ? "C_D1 " : "c_d0 ");
  1297.     printf ("%s", (tempReg & SPC_PSNS_I_O) ? "I_O1 " : "i_o0 ");
  1298.     printf ("n");
  1299.     /* Display SPC Status Register */
  1300.     tempReg = *pSpc->pSstsReg;
  1301.     printf ("SSTS (0x%02x): ", (int) tempReg);
  1302.     switch (tempReg & SPC_SSTS_OPER_STAT_MASK)
  1303.         {
  1304.         case SPC_SSTS_NO_CONNECT_IDLE:  printf ("noConIdle "); break;
  1305.         case SPC_SSTS_SELECT_WAIT:      printf ("waitSelec "); break;
  1306.         case SPC_SSTS_TARGET_MANUAL:    printf ("trgManual "); break;
  1307.         case SPC_SSTS_RESELECT_EXEC:    printf ("reselExec "); break;
  1308.         case SPC_SSTS_TARGET_XFER:      printf ("targXfer  "); break;
  1309.         case SPC_SSTS_INITIATOR_MANUAL: printf ("iniManual "); break;
  1310.         case SPC_SSTS_INITIATOR_WAIT:   printf ("iniWait   "); break;
  1311.         case SPC_SSTS_SELECT_EXEC:      printf ("selecExec "); break;
  1312.         case SPC_SSTS_INITIATOR_XFER:   printf ("iniXfer   "); break;
  1313.         default:                        printf ("operUndef "); break;
  1314.         }
  1315.     printf ("%s", (tempReg & SPC_SSTS_SCSI_RESET) ? "scsiReset " : "");
  1316.     printf ("%s", (tempReg & SPC_SSTS_TC_0)       ? "xferCnt=0 " : "");
  1317.     switch (tempReg & SPC_SSTS_DREG_STAT_MASK)
  1318.         {
  1319.         case SPC_SSTS_DREG_EMPTY:   printf ("dregEmpty "); break;
  1320.         case SPC_SSTS_DREG_PARTIAL: printf ("dregPartl "); break;
  1321.         case SPC_SSTS_DREG_FULL:    printf ("dregFull  "); break;
  1322.         default:                    printf ("dregUndef "); break;
  1323.         }
  1324.     printf ("n");
  1325.     /* Display SPC Error Status Register */
  1326.     tempReg = *pSpc->pSerrReg;
  1327.     printf ("SERR (0x%02x): ", (int) tempReg);
  1328.     switch (tempReg & SPC_SERR_PAR_ERROR_MASK)
  1329.         {
  1330.         case SPC_SERR_NO_PAR_ERROR:  printf ("noParErr  "); break;
  1331.         case SPC_SERR_PAR_ERROR_OUT: printf ("outParErr "); break;
  1332.         case SPC_SERR_PAR_ERROR_IN:  printf ("inpParErr "); break;
  1333.         default:                      printf ("pErrUndef "); break;
  1334.         }
  1335.     printf ("%s", (tempReg & SPC_SERR_TC_PARITY)    ? "tcParErr  " : "");
  1336.     printf ("%s", (tempReg & SPC_SERR_PHASE_ERROR)  ? "phaseErr  " : "");
  1337.     printf ("%s", (tempReg & SPC_SERR_SHORT_PERIOD) ? "shortPeri " : "");
  1338.     printf ("%s", (tempReg & SPC_SERR_OFFSET_ERROR) ? "offsetErr " : "");
  1339.     printf ("n");
  1340.     /* Display Phase Control Register */
  1341.     tempReg = *pSpc->pPctlReg;
  1342.     printf ("PCTL (0x%02x): ", (int) tempReg);
  1343.     printf ("%s", (tempReg & SPC_PCTL_BF_INT_ENBL) ? "bfIntEnbl " :
  1344.                                                      "bfIntDsbl ");
  1345.     switch (tempReg & SPC_PCTL_PHASE_MASK)
  1346.         {
  1347.         case SPC_PCTL_DATA_OUT:  printf ("phDataOut "); break;
  1348.         case SPC_PCTL_DATA_IN:   printf ("phDataIn  "); break;
  1349.         case SPC_PCTL_COMMAND:   printf ("phCommand "); break;
  1350.         case SPC_PCTL_STATUS:    printf ("phStatus  "); break;
  1351.         case SPC_PCTL_UNUSED_0:  printf ("phUnused0 "); break;
  1352.         case SPC_PCTL_UNUSED_1:  printf ("phUnused1 "); break;
  1353.         case SPC_PCTL_MESS_OUT:  printf ("phMessOut "); break;
  1354.         case SPC_PCTL_MESS_IN:   printf ("phMessIn  "); break;
  1355.         }
  1356.     printf ("n");
  1357.     /* Display Modified Byte Counter */
  1358.     tempReg = *pSpc->pMbcReg;
  1359.     printf ("MBC  (0x%02x): ", (int) tempReg);
  1360.     printf ("%-10d", (int) tempReg);
  1361.     printf ("n");
  1362.     /* Display Transfer Counter */
  1363.     spcXferCountGet (pSpc, &xferCount);
  1364.     printf ("XFER COUNT : ");
  1365.     printf ("0x%06x =%10d", xferCount, xferCount);
  1366.     printf ("n");
  1367.     return (OK);
  1368.     }