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

VxWorks

开发平台:

C/C++

  1. /* wd33c93Lib1.c - WD33C93 SCSI-Bus Interface Controller library (SCSI-1) */
  2. /* Copyright 1989-1995 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01w,06may96,jds  yet more doc tweaks
  8. 01v,01may96,jds  more doc cleanup
  9. 01u,03feb95,rhp  documentation cleanup
  10. 01t,10oct93,jds  fixed for SCSI1 and SCSI2 compatability
  11. 01s,24feb93,jdi  documentation cleanup.
  12. 01r,19feb93,ccc  removed bypass of DMA routine if DMA is included.
  13. 01q,26sep92,ccc  changed sbicShow() to wd33c93Show() and added example.
  14. 01p,24sep92,ccc  fixed timeout in sbicBusPhaseGet().
  15. 01o,20jul92,gae  fixed parameters to logMsg().
  16. 01n,18jul92,smb  Changed errno.h to errnoLib.h.
  17. 01m,12jul92,ccc  added reset of SCSI bus if timed out (bus hung).
  18. 01l,04jun92,ccc  added timeout to semTake()s.
  19. 01k,26may92,rrr  the tree shuffle
  20.   -changed includes to have absolute path from h/
  21. 01j,20apr92,ccc  fixed warnings.
  22. 01i,07oct91,rrr  some forward decls
  23. 01h,04oct91,rrr  passed through the ansification filter
  24.                   -changed functions to ansi style
  25.   -changed includes to have absolute path from h/
  26.   -changed VOID to void
  27.   -changed copyright notice
  28. 01g,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  29.  doc review by jcc.
  30. 01f,01feb91,jaa  documentation.
  31. 01e,02oct90,jcc  UTINY became UINT8; changes in sem{Give, Take}() calls
  32.  since SEM_ID's became SEMAPHORE's in various structures;
  33.  malloc() became calloc() in wd33c93CtrlCreate(); miscellaneous.
  34. 01d,21sep90,jcc  misc. cleanup for 5.0 release.
  35. 01c,10aug90,dnw  added forward declarations for void functions.
  36. 01b,18jul90,jcc  made semTake() calls 5.0 compatible; clean-up.
  37. 01a,28feb90,jcc  written
  38. */
  39. /*
  40. DESCRIPTION
  41. This library contains part of the I/O driver for the
  42. Western Digital WD33C93 and WD33C93A SCSI-Bus Interface Controllers
  43. (SBIC).  The driver routines in this library depend on the SCSI-1 
  44. version of the SCSI standard; for driver routines that do not depend
  45. on SCSI-1 or SCSI-2, and for overall SBIC driver documentation, see
  46. wd33c93Lib.
  47. USER-CALLABLE ROUTINES
  48. Most of the routines in this driver are accessible only through the
  49. I/O system.  The only exception in this portion of the driver is
  50. wd33c93CtrlCreate(), which creates a controller structure.
  51. INCLUDE FILES
  52. wd33c93.h, wd33c93_1.h
  53. SEE ALSO: scsiLib, scsi1Lib, wd33c93Lib
  54. */
  55. #include "vxWorks.h"
  56. #define WD33C93_1_LOCAL_FUNCS
  57. #include "drv/scsi/wd33c93_1.h"
  58. #undef  WD33C93_1_LOCAL_FUNCS
  59. #include "memLib.h"
  60. #include "logLib.h"
  61. #include "scsiLib.h"
  62. #include "stdlib.h"
  63. #include "errnoLib.h"
  64. #include "stdio.h"
  65. #include "sysLib.h"
  66. #define WD_33C93_MAX_BYTES_PER_XFER  ((UINT) 0xffffff)
  67. typedef WD_33C93_SCSI_CTRL SBIC;
  68. /* imported functions */
  69. IMPORT STATUS scsiTransact ();
  70. IMPORT STATUS scsiCtrlInit ();
  71. /* forward static functions */
  72. LOCAL STATUS sbicDevSelect (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);
  73. LOCAL STATUS sbicMsgInAck (SCSI_CTRL *, BOOL);
  74. LOCAL STATUS sbicBytesOut (SCSI_PHYS_DEV *, char *, int, int);
  75. LOCAL STATUS sbicBytesIn (SCSI_PHYS_DEV *, char *, int, int);
  76. LOCAL STATUS sbicBusPhaseGet (SCSI_CTRL *, int, int *);
  77. LOCAL void sbicSelTimeOutCvt (SCSI_CTRL *, UINT, UINT *);
  78. LOCAL void sbicScsiBusReset (SBIC *);
  79. LOCAL void sbicHwInit (SBIC *);
  80. WD_33C93_SCSI_CTRL *wd33c93CtrlCreate (FAST UINT8 *, int, UINT, int,
  81.      FUNCPTR, FUNCPTR, FUNCPTR);
  82. LOCAL STATUS wd33c93CtrlInit (FAST SBIC *, FAST int, FAST UINT, int);
  83. LOCAL STATUS sbicXferCountSet (FAST SBIC *, FAST UINT);
  84. LOCAL void sbicXferCountGet (FAST SBIC *, FAST int *);
  85. LOCAL void sbicCommand (SBIC *, UINT8);
  86. LOCAL void sbicIntr (SBIC *);
  87. LOCAL void sbicRegRead (SBIC *, UINT8, int *);
  88. LOCAL void sbicRegWrite (SBIC *, UINT8, UINT8);
  89. LOCAL STATUS wd33c93Show (FAST SCSI_CTRL *);
  90. /*******************************************************************************
  91. *
  92. * wd33c93Scsi1IfInit - initialize the SCSI-2 interface to wd33c93
  93. *
  94. * NOMANUAL
  95. */
  96. void wd33c93Scsi1IfInit ()
  97.     {
  98.     /* create table */
  99.     wd33c93IfTblInit ();
  100.     /* initialize table */
  101.     pWd33c93IfTbl->sbicCommand       = (FUNCPTR) sbicCommand;
  102.     pWd33c93IfTbl->sbicIntr          = (FUNCPTR) sbicIntr;
  103.     pWd33c93IfTbl->sbicRegRead       = (FUNCPTR) sbicRegRead;
  104.     pWd33c93IfTbl->sbicRegWrite      = (FUNCPTR) sbicRegWrite;
  105.     pWd33c93IfTbl->sbicXferCountGet  = (FUNCPTR) sbicXferCountGet;
  106.     pWd33c93IfTbl->sbicXferCountSet  = (FUNCPTR) sbicXferCountSet;
  107.     pWd33c93IfTbl->wd33c93CtrlInit   = (FUNCPTR) wd33c93CtrlInit;
  108.     pWd33c93IfTbl->wd33c93Show       = (FUNCPTR) wd33c93Show;
  109.     }
  110. /*******************************************************************************
  111. *
  112. * wd33c93CtrlCreate - create and partially initialize a WD33C93 SBIC structure
  113. *
  114. * This routine creates an SBIC data structure and must be called before using
  115. * an SBIC chip.  It should be called once and only once for a specified SBIC.  
  116. * Since it allocates memory for a structure needed by all routines in
  117. * wd33c93Lib, it must be called before any other routines in the library.
  118. * After calling this routine, at least one call to wd33c93CtrlInit() should
  119. * be made before any SCSI transaction is initiated using the SBIC.
  120. *
  121. * Note that only the non-multiplexed processor interface is supported.
  122. *
  123. * The input parameters are as follows:
  124. * .iP <sbicBaseAdrs> 4
  125. * the address where the CPU accesses the lowest register of
  126. * the SBIC.
  127. * .iP <regOffset>
  128. * the address offset (in bytes) to access consecutive registers.  (This must
  129. * be a power of 2; for example, 1, 2, 4, etc.)
  130. * .iP <clkPeriod>
  131. * the period, in nanoseconds, of the signal-to-SBIC clock input used only for
  132. * select command timeouts.
  133. * .iP <devType>
  134. * a constant corresponding to the type (part number) of this controller; 
  135. * possible options are enumerated in wd33c93.h under the heading "SBIC 
  136. * device type."
  137. * .iP <sbicScsiReset>
  138. * a board-specific routine to assert the RST line on the SCSI bus, which causes
  139. * all connected devices to return to a known quiescent state.
  140. * .iP "<spcDmaBytesIn> and <spcDmaBytesOut>"
  141. * board-specific routines to handle DMA input and output.  
  142. * If these are NULL (0), SBIC program transfer mode is used.
  143. * DMA is implemented only during SCSI data in/out phases.
  144. * The interface to these DMA routines must be of the form:
  145. * .CS
  146. *     STATUS xxDmaBytes{In, Out}
  147. *         (
  148. *         SCSI_PHYS_DEV  *pScsiPhysDev,  /@ ptr to phys dev info    @/
  149. *         UINT8          *pBuffer,       /@ ptr to the data buffer @/
  150. *         int            bufLength       /@ number of bytes to xfer @/
  151. *         )
  152. * .CE
  153. *
  154. * RETURNS: A pointer to the SBIC control structure,
  155. * or NULL if memory is insufficient or parameters are invalid.
  156. *
  157. * SEE ALSO: wd33c93.h
  158. */
  159. WD_33C93_SCSI_CTRL *wd33c93CtrlCreate 
  160.     (
  161.     FAST UINT8 *sbicBaseAdrs,   /* base address of SBIC */
  162.     int         regOffset,      /* addr offset between consecutive regs. */
  163.     UINT        clkPeriod,      /* period of controller clock (nsec) */
  164.     int         devType,        /* SBIC device type */
  165.     FUNCPTR     sbicScsiReset,  /* SCSI bus reset function */
  166.     FUNCPTR     sbicDmaBytesIn, /* SCSI DMA input function */
  167.     FUNCPTR     sbicDmaBytesOut /* SCSI DMA output function */
  168.     )
  169.     {
  170.     FAST SBIC *pSbic; /* ptr to SBIC info */
  171.     /* initialize the driver function table */
  172.     wd33c93Scsi1IfInit ();
  173.     /* verify input parameters */
  174.     if (regOffset == 0)
  175.         return ((SBIC *) NULL);
  176.     /* calloc the controller info structure; return NULL if unable */
  177.     if ((pSbic = (SBIC *) calloc (1, sizeof (SBIC))) == NULL)
  178.         return ((SBIC *) NULL);
  179.     /* fill in generic SCSI info for this controller */
  180.     scsiCtrlInit (&pSbic->scsiCtrl);
  181.     /* fill in SBIC specific data for this controller */
  182.     pSbic->pAdrsReg    = sbicBaseAdrs;
  183.     pSbic->pAuxStatReg = sbicBaseAdrs;
  184.     pSbic->pRegFile    = sbicBaseAdrs + regOffset;
  185.     pSbic->devType     = devType;
  186.     pSbic->scsiCtrl.clkPeriod = clkPeriod;
  187.     pSbic->scsiCtrl.maxBytesPerXfer = WD_33C93_MAX_BYTES_PER_XFER;
  188.     /* fill in board-specific SCSI bus reset routine */
  189.     pSbic->scsiCtrl.scsiBusReset      = sbicScsiBusReset;
  190.     /* fill in driver-specific routines for scsiLib interface */
  191.     pSbic->scsiCtrl.scsiTransact      = scsiTransact;
  192.     pSbic->scsiCtrl.scsiDevSelect     = sbicDevSelect;
  193.     pSbic->scsiCtrl.scsiBytesIn       = sbicBytesIn;
  194.     pSbic->scsiCtrl.scsiBytesOut      = sbicBytesOut;
  195.     pSbic->scsiCtrl.scsiDmaBytesIn    = sbicDmaBytesIn;
  196.     pSbic->scsiCtrl.scsiDmaBytesOut   = sbicDmaBytesOut;
  197.     pSbic->scsiCtrl.scsiBusPhaseGet   = sbicBusPhaseGet;
  198.     pSbic->scsiCtrl.scsiMsgInAck      = sbicMsgInAck;
  199.     pSbic->scsiCtrl.scsiSelTimeOutCvt = sbicSelTimeOutCvt;
  200.     pSbic->sbicScsiReset = sbicScsiReset;
  201.     return (pSbic);
  202.     }
  203. /*******************************************************************************
  204. *
  205. * wd33c93CtrlInit - initialize the user-specified fields in a WD33C93 SBIC structure
  206. *
  207. * This routine initializes an SBIC structure, after the structure is created
  208. * with wd33c93CtrlCreate().  This structure must be initialized before the SBIC
  209. * can be used.  It may be called more than once; however, it should
  210. * be called only while there is no activity on the SCSI interface.
  211. *
  212. * Before returning, this routine pulses RST (reset) on the SCSI bus, thus
  213. * resetting all attached devices.
  214. *
  215. * The input parameters are as follows:
  216. * .iP <pSbic> 4
  217. * a pointer to the WD_33C93_SCSI_CTRL structure created with
  218. * wd33c93CtrlCreate().
  219. * .iP <scsiCtrlBusId>
  220. * the SCSI bus ID of the SBIC, in the range 0 - 7.  The ID is somewhat 
  221. * arbitrary; the value 7, or highest priority, is conventional.
  222. * .iP <defaultSelTimeOut>
  223. * the timeout, in microseconds, for selecting a SCSI device attached to this
  224. * controller.  This value is used as a default if no timeout is specified in
  225. * scsiPhysDevCreate().  The recommended value zero (0) specifies
  226. * SCSI_DEF_SELECT_TIMEOUT (250 millisec).  The maximum timeout possible is
  227. * approximately 2 seconds.  Values exceeding this revert to the
  228. * maximum.  For more information about chip timeouts, see the manuals
  229. * .I "Western Digital WD33C92/93 SCSI-Bus Interface Controller,"
  230. * .I "Western Digital WD33C92A/93A SCSI-Bus Interface Controller."
  231. * .iP <scsiPriority>
  232. * the priority to which a task is set when performing a SCSI
  233. * transaction.  Valid priorities are 0 to 255.  Alternatively, the value -1 
  234. * specifies that the priority should not be altered during SCSI transactions.
  235. *
  236. * RETURNS: OK, or ERROR if a parameter is out of range.
  237. *
  238. * SEE ALSO: scsiPhysDevCreate(),
  239. * .I "Western Digital WD33C92/93 SCSI-Bus Interface Controller,"
  240. * .I "Western Digital WD33C92A/93A SCSI-Bus Interface Controller"
  241. */
  242. LOCAL STATUS wd33c93CtrlInit
  243.     (
  244.     FAST SBIC *pSbic,             /* ptr to SBIC info                       */
  245.     FAST int   scsiCtrlBusId,     /* SCSI bus ID of this SBIC               */
  246.     FAST UINT  defaultSelTimeOut, /* default dev. select timeout (microsec) */
  247.     int        scsiPriority       /* priority of task when doing SCSI I/O   */
  248.     )
  249.     {
  250.     UINT tempSelTimeOut; /* temp. value of select timeout (no units) */
  251.     /* verify scsiCtrlBusId and enter legal value in SBIC structure */
  252.     SCSI_DEBUG_MSG ("scsiCtrlBusId = %dn", scsiCtrlBusId, 0, 0, 0, 0, 0);
  253.     if (scsiCtrlBusId < SCSI_MIN_BUS_ID || scsiCtrlBusId > SCSI_MAX_BUS_ID)
  254. return (ERROR);
  255.     pSbic->scsiCtrl.scsiCtrlBusId = scsiCtrlBusId;
  256.     if (scsiPriority < NONE || scsiPriority > 0xff)
  257.         return (ERROR);
  258.     pSbic->scsiCtrl.scsiPriority = scsiPriority;
  259.     /* verify defaultSelTimeOut, convert it from usec to SBIC register values,
  260.      * and enter value in SBIC structure
  261.      */
  262.     sbicSelTimeOutCvt (&pSbic->scsiCtrl, defaultSelTimeOut, &tempSelTimeOut);
  263.     pSbic->defaultSelTimeOut = (UINT8) tempSelTimeOut;
  264.     /* disconnect not supported for now */
  265.     pSbic->scsiCtrl.disconnect = (TBOOL) FALSE;
  266.     sbicHwInit (pSbic);  /* initialize the SBIC hardware */
  267.     return (OK);
  268.     }
  269. /*******************************************************************************
  270. *
  271. * sbicDevSelect - attempt to select a SCSI device
  272. *
  273. * This routine is intended to be called from scsiLib, not directly.
  274. *
  275. * RETURNS: OK if the device was successfully selected, otherwise ERROR.
  276. */
  277. LOCAL STATUS sbicDevSelect
  278.     (
  279.     FAST SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical device info */
  280.     SCSI_TRANSACTION   *pScsiXaction    /* ptr to SCSI transaction info     */
  281.     )
  282.     {
  283.     FAST SBIC *pSbic; /* ptr to SBIC info */
  284.     int sbicBusId; /* SCSI bus ID of the SBIC */
  285.     UINT8 identMsg; /* for construction of the IDENTIFY message */
  286.     STATUS status; /* placeholder for status */
  287.     int scsiPhase; /* SCSI bus phase following the select */
  288.     pSbic = (SBIC *) pScsiPhysDev->pScsiCtrl;
  289.     sbicRegRead (pSbic, SBIC_REG_OWN_ID, &sbicBusId);
  290.     if (sbicBusId == pScsiPhysDev->scsiDevBusId)
  291. {
  292. errnoSet (S_scsiLib_ILLEGAL_BUS_ID);
  293.         return (ERROR);
  294. }
  295.     sbicRegWrite (pSbic, SBIC_REG_DEST_ID, (UINT8) pScsiPhysDev->scsiDevBusId);
  296.     sbicRegWrite (pSbic, SBIC_REG_TO_PERIOD, (UINT8) pScsiPhysDev->selTimeOut);
  297.     pSbic->pDevToSelect = pScsiPhysDev;
  298.     sbicCommand (pSbic, pScsiPhysDev->useIdentify ?
  299.    SBIC_CMD_SEL_ATN :
  300.    SBIC_CMD_SELECT);
  301.     semTake (&pScsiPhysDev->devSyncSem, WAIT_FOREVER);
  302.     if (pScsiPhysDev->devStatus == SELECT_SUCCESSFUL)
  303. {
  304. if (pScsiPhysDev->useIdentify)  /* send an identify message */
  305.          {
  306.     if ((sbicBusPhaseGet (&pSbic->scsiCtrl, 0, &scsiPhase) == ERROR) ||
  307. (scsiPhase != SCSI_MSG_OUT_PHASE))
  308. return (ERROR);
  309.             identMsg = SCSI_MSG_IDENTIFY |
  310.        (pSbic->scsiCtrl.disconnect ?
  311. SCSI_MSG_IDENT_DISCONNECT : 0) |
  312.        (UINT8) pScsiPhysDev->scsiDevLUN;
  313.     status = sbicProgBytesOut (pScsiPhysDev, &identMsg,
  314.        sizeof (identMsg), SCSI_MSG_OUT_PHASE);
  315.     if (status == ERROR)
  316. return (ERROR);
  317.             }
  318.         return (OK);
  319. }
  320.     if (pScsiPhysDev->devStatus == SELECT_TIMEOUT)
  321. errnoSet (S_scsiLib_SELECT_TIMEOUT);
  322.     return (ERROR);
  323.     }
  324. /*******************************************************************************
  325. *
  326. * sbicMsgInAck - issue a NEG_ACK command thereby accepting an incoming message
  327. *
  328. * This routine should be called when an incoming message has been read and
  329. * accepted.  If the incoming message did not imply an impending disconnect,
  330. * give the synchronization semaphore, so that subsequent phase can be detected.
  331. *
  332. * RETURNS: OK.
  333. */
  334. LOCAL STATUS sbicMsgInAck
  335.     (
  336.     FAST SCSI_CTRL *pScsiCtrl,  /* ptr to SBIC info                 */
  337.     BOOL expectDisconn          /* whether a disconnect is expected */
  338.     )
  339.     {
  340.     sbicCommand ((SBIC *) pScsiCtrl, SBIC_CMD_NEG_ACK);
  341.     if (!expectDisconn)
  342.         semGive (&pScsiCtrl->ctrlSyncSem);
  343.     return (OK);
  344.     }
  345. /*******************************************************************************
  346. *
  347. * sbicProgBytesOut - output data bytes to SCSI using 'program' transfer
  348. *
  349. * This routine transfers the data from the data buffer into the
  350. * chip's data register.
  351. *
  352. * RETURNS: OK, or ERROR if <bufLength> is out of range.
  353. *
  354. * NOMANUAL
  355. */
  356. STATUS sbicProgBytesOut
  357.     (
  358.     SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to drive info in SBIC       */
  359.     FAST UINT8 *pBuffer,         /* pointer to the data buffer       */
  360.     FAST int bufLength,          /* number of bytes to be transferred */
  361.     int scsiPhase                /* phase of the transfer       */
  362.     )
  363.     {
  364.     FAST SBIC *pSbic; /* ptr to SBIC info */
  365.     SCSI_DEBUG_MSG ("sbicProgBytesOut: bufLength = %d, scsiPhase = %dn",
  366.     bufLength, scsiPhase, 0, 0, 0, 0);
  367.     pSbic = (SBIC *) pScsiPhysDev->pScsiCtrl;
  368.     if (bufLength != 1)
  369. {
  370.         if (sbicXferCountSet (pSbic, (UINT) bufLength) == ERROR)
  371.     return (ERROR);
  372.         sbicCommand (pSbic, SBIC_CMD_XFER_INFO);
  373. }
  374.     else
  375.         sbicCommand (pSbic, SBIC_CMD_XFER_INFO | SBIC_CMD_SING_BYTE_XFER);
  376.     *pSbic->pAdrsReg = SBIC_REG_DATA;
  377.     while (bufLength-- > 0)
  378. {
  379. while (!(*pSbic->pAuxStatReg & SBIC_AUX_STAT_DBUF_READY))
  380.     ;
  381. *pSbic->pRegFile = *pBuffer++;
  382. }
  383.     return (OK);
  384.     }
  385. /*******************************************************************************
  386. *
  387. * sbicProgBytesIn - input data bytes from SCSI using 'program' transfer
  388. *
  389. * This routine transfers data into the data buffer from the chip's
  390. * data register.
  391. *
  392. * RETURNS: OK, or ERROR if <bufLength> is out of range.
  393. *
  394. * NOMANUAL
  395. */
  396. STATUS sbicProgBytesIn
  397.     (
  398.     SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to drive info in SBIC         */
  399.     FAST UINT8    *pBuffer,        /* pointer to the data buffer        */
  400.     FAST int       bufLength,      /* number of bytes to be transferred */
  401.     int            scsiPhase       /* phase of the transfer             */
  402.     )
  403.     {
  404.     FAST SBIC *pSbic; /* ptr to SBIC info */
  405.     SCSI_DEBUG_MSG ("sbicProgBytesIn: bufLength = %d, scsiPhase = %dn",
  406.     bufLength, scsiPhase, 0, 0, 0, 0);
  407.     pSbic = (SBIC *) pScsiPhysDev->pScsiCtrl;
  408.     if (bufLength != 1)
  409. {
  410.         if (sbicXferCountSet (pSbic, (UINT) bufLength) == ERROR)
  411.     return (ERROR);
  412.         sbicCommand (pSbic, SBIC_CMD_XFER_INFO);
  413. }
  414.     else
  415.         sbicCommand (pSbic, SBIC_CMD_XFER_INFO | SBIC_CMD_SING_BYTE_XFER);
  416.     *pSbic->pAdrsReg = SBIC_REG_DATA;
  417.     while (bufLength-- > 0)
  418. {
  419. while (!(*pSbic->pAuxStatReg & SBIC_AUX_STAT_DBUF_READY))
  420.     ;
  421. *pBuffer++ = *pSbic->pRegFile;
  422. }
  423.     if (scsiPhase == SCSI_MSG_IN_PHASE)
  424. {
  425. semTake (&pSbic->scsiCtrl.ctrlSyncSem, WAIT_FOREVER);
  426. sbicMsgInAck ((SCSI_CTRL *) pScsiPhysDev->pScsiCtrl, TRUE);
  427. }
  428.     return (OK);
  429.     }
  430. /*******************************************************************************
  431. *
  432. * sbicBytesOut - switch to appropriate output routine
  433. *
  434. * This routine executes the scsiDmaBytesOut() routine if not NULL, otherwise
  435. * sbicProgBytesOut() is run.
  436. *
  437. * RETURNS: The return value from the called routine.
  438. */
  439. LOCAL STATUS sbicBytesOut 
  440.     (
  441.     FAST SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical dev info     */
  442.     FAST char          *pBuffer,        /* ptr to byte buffer for output     */
  443.     int                 bufLength,      /* number of bytes to be transferred */
  444.     int                 scsiPhase       /* SCSI bus phase of the transfer    */
  445.     )
  446.     {
  447.     FAST SBIC *pSbic; /* ptr to SBIC info */
  448.     pSbic = (SBIC *) pScsiPhysDev->pScsiCtrl;
  449.     if ((scsiPhase != SCSI_DATA_OUT_PHASE) ||
  450.         (pSbic->scsiCtrl.scsiDmaBytesOut == NULL))
  451. {
  452.         return (sbicProgBytesOut (pScsiPhysDev, (UINT8 *) pBuffer,
  453.                                   bufLength, scsiPhase));
  454. }
  455.     else
  456. {
  457.         return ((pSbic->scsiCtrl.scsiDmaBytesOut)
  458.                 (pScsiPhysDev, (UINT8 *) pBuffer, bufLength));
  459. }
  460.     }
  461. /*******************************************************************************
  462. *
  463. * sbicBytesIn - switch to appropriate input routine
  464. *
  465. * This routine executes the scsiDmaBytesIn() routine if not NULL, otherwise
  466. * sbicPorgBytesIn() is run.
  467. *
  468. * RETURNS: The return value from the called routine.
  469. */
  470. LOCAL STATUS sbicBytesIn 
  471.     (
  472.     FAST SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical dev info     */
  473.     FAST char          *pBuffer,        /* ptr to byte buffer for output     */
  474.     int                 bufLength,      /* number of bytes to be transferred */
  475.     int                 scsiPhase       /* SCSI bus phase of the transfer    */
  476.     )
  477.     {
  478.     FAST SBIC *pSbic;                   /* ptr to SBIC info */
  479.     pSbic = (SBIC *) pScsiPhysDev->pScsiCtrl;
  480.     if ((scsiPhase != SCSI_DATA_IN_PHASE) ||
  481.         (pSbic->scsiCtrl.scsiDmaBytesIn == NULL))
  482. {
  483.         return (sbicProgBytesIn (pScsiPhysDev, (UINT8 *) pBuffer,
  484.                                   bufLength, scsiPhase));
  485. }
  486.     else
  487. {
  488.         return ((pSbic->scsiCtrl.scsiDmaBytesIn)
  489.                 (pScsiPhysDev, (UINT8 *) pBuffer, bufLength));
  490. }
  491.     }
  492. /*******************************************************************************
  493. *
  494. * sbicBusPhaseGet - return the current SCSI bus phase in *pBusPhase
  495. *
  496. * This routine gets the value of the current SCSI bus phase.
  497. *
  498. * RETURNS: OK, or ERROR if no phase is detected.
  499. */
  500. LOCAL STATUS sbicBusPhaseGet
  501.     (
  502.     FAST SCSI_CTRL *pScsiCtrl,     /* ptr to SCSI controller info     */
  503.     int             timeOutInUsec, /* timeout in usec (0 == infinity) */
  504.     FAST int       *pBusPhase      /* ptr to returned bus phase       */
  505.     )
  506.     {
  507.     FAST SBIC * pSbic; /* ptr to SBIC info */
  508.     int timeOut;
  509.     pSbic = (SBIC *) pScsiCtrl;
  510.     if (timeOutInUsec > SCSI_TIMEOUT_5SEC)
  511. timeOut = ((timeOutInUsec / SCSI_TIMEOUT_1SEC) * sysClkRateGet ());
  512.     else
  513. timeOut = ((timeOutInUsec * sysClkRateGet()) / SCSI_TIMEOUT_1SEC);
  514.     if (timeOut == 0)
  515. timeOut = WAIT_FOREVER;
  516.     if (semTake (&pScsiCtrl->ctrlSyncSem, timeOut) == ERROR)
  517. {
  518. sbicScsiBusReset (pSbic); /* the bus is hung(?), reset it */
  519. return (ERROR);
  520. }
  521.     if (pSbic->scsiCtrl.scsiBusPhase == NONE)
  522. return (ERROR);
  523.     *pBusPhase = pSbic->scsiCtrl.scsiBusPhase;
  524.     return (OK);
  525.     }
  526. /*******************************************************************************
  527. *
  528. * sbicSelTimeOutCvt - convert a select timeout from usec to SBIC units
  529. *
  530. * The conversion formula is given on p. 11 of the Western Digital WD33C93
  531. * manual.  Note that 0 specifies the default setting of 250 usec.  Also,
  532. * the SBIC accepts up to a 8-bit timeout, so a maximum value of 0xff is
  533. * returned in *pTimeOutSetting.
  534. *
  535. * RETURNS: N/A.
  536. */
  537. LOCAL void sbicSelTimeOutCvt
  538.     (
  539.     FAST SCSI_CTRL *pScsiCtrl,          /* ptr to SCSI controller info */
  540.     FAST UINT       timeOutInUsec,      /* timeout in microsecs        */
  541.     FAST UINT      *pTimeOutSetting     /* ptr to result               */
  542.     )
  543.     {
  544.     FAST UINT tempSelTimeOut; /* temp. select timeout setting */
  545.     if (timeOutInUsec == (UINT) 0)
  546. timeOutInUsec = SCSI_DEF_SELECT_TIMEOUT;
  547.     tempSelTimeOut = (timeOutInUsec / (80 * pScsiCtrl->clkPeriod)) + 1;
  548.     if (tempSelTimeOut > 0xff)
  549. tempSelTimeOut = 0xff;
  550.     *pTimeOutSetting = tempSelTimeOut;
  551.     }
  552. /*******************************************************************************
  553. *
  554. * sbicXferCountSet - load the SBIC transfer counter with the specified count
  555. *
  556. * RETURNS: OK, or ERROR if <count> is not in the
  557. * range 0 - WD_33C93_MAX_BYTES_PER_XFER.
  558. *
  559. * NOMANUAL
  560. */
  561. STATUS sbicXferCountSet
  562.     (
  563.     FAST SBIC *pSbic,   /* ptr to SBIC info    */
  564.     FAST UINT  count    /* count value to load */
  565.     )
  566.     {
  567.     int nbits = 24;
  568.     if (count > WD_33C93_MAX_BYTES_PER_XFER)
  569.         return (ERROR);
  570.     *pSbic->pAdrsReg = (SBIC_REG_XFER_COUNT_MSB);
  571.     while (nbits)
  572.         {
  573.         *pSbic->pRegFile = (UINT8) ((count >> (nbits - 8)) & 0xff);
  574.         nbits -= 8;
  575.         }
  576.     return (OK);
  577.     }
  578. /*******************************************************************************
  579. *
  580. * sbicXferCountGet - fetch the SBIC transfer count
  581. *
  582. * The value of the transfer counter is copied to *pCount.
  583. *
  584. * RETURNS: N/A.
  585. *
  586. * NOMANUAL
  587. */
  588. void sbicXferCountGet
  589.     (
  590.     FAST SBIC *pSbic,   /* ptr to SBIC info      */
  591.     FAST int  *pCount   /* ptr to returned value */
  592.     )
  593.     {
  594.     FAST UINT tempCount = (UINT) 0;
  595.     *pSbic->pAdrsReg = SBIC_REG_XFER_COUNT_MSB;
  596.     tempCount |= ((UINT) *pSbic->pRegFile) << 16;
  597.     tempCount |= ((UINT) *pSbic->pRegFile) << 8;
  598.     tempCount |=  (UINT) *pSbic->pRegFile;
  599.     *pCount = (int) tempCount;
  600.     }
  601. /*******************************************************************************
  602. *
  603. * sbicCommand - write a command code to the SBIC Command Register
  604. *
  605. * RETURNS: N/A.
  606. *
  607. * NOMANUAL
  608. */
  609. void sbicCommand
  610.     (
  611.     SBIC *pSbic,        /* ptr to SBIC info */
  612.     UINT8 cmdCode       /* new command code */
  613.     )
  614.     {
  615.     /* delay until previous command has been interpretted */
  616.     while (*pSbic->pAuxStatReg & SBIC_AUX_STAT_CMD_IN_PROG)
  617. ;
  618.     /* load new command */
  619.     *pSbic->pAdrsReg = SBIC_REG_COMMAND;
  620.     *pSbic->pRegFile = cmdCode;
  621.     }
  622. /*******************************************************************************
  623. *
  624. * sbicScsiBusReset - assert the RST line on the SCSI bus
  625. *
  626. * This routine asserts the RST line on the SCSI bus, which should cause
  627. * all connected devices to return to a known quiescent state.
  628. *
  629. * RETURNS: N/A.
  630. */
  631. LOCAL void sbicScsiBusReset
  632.     (
  633.     FAST SBIC *pSbic    /* ptr to SBIC info */
  634.     )
  635.     {
  636.     (*pSbic->sbicScsiReset) (pSbic);
  637.     }
  638. /*******************************************************************************
  639. *
  640. * sbicIntr - interrupt service routine for the SBIC
  641. *
  642. * RETURNS: N/A.
  643. *
  644. * NOMANUAL
  645. */
  646. LOCAL void sbicIntr
  647.     (
  648.     SBIC *pSbic          /* ptr to SBIC info */
  649.     )
  650.     {
  651.     FAST UINT8 scsiStatus;
  652.     FAST UINT8 statusGroup;
  653.     /* read 'SCSI Status' Reg. and determine status group and code */
  654.     *pSbic->pAdrsReg = SBIC_REG_SCSI_STATUS;
  655.     scsiStatus = pSbic->scsiStatusCode = *pSbic->pRegFile;
  656.     statusGroup = STAT_GROUP(scsiStatus);
  657.     SCSI_INT_DEBUG_MSG ("*** SBIC INTERRUPT *** ", 0, 0, 0, 0, 0, 0);
  658.     switch (statusGroup)
  659. {
  660. case STAT_GROUP_RESET:
  661.     SCSI_INT_DEBUG_MSG ("SBIC Reset interrupt, Code = 0x%xn",
  662. scsiStatus, 0, 0, 0, 0, 0);
  663.     break;
  664. case STAT_GROUP_SUCCESSFUL:
  665.     SCSI_INT_DEBUG_MSG ("SBIC Successful Completion interrupt, 
  666. Code = 0x%xn", scsiStatus, 0, 0, 0, 0, 0);
  667.     switch (scsiStatus)
  668. {
  669. case STAT_SUCC_SELECT:
  670.     pSbic->pDevToSelect->devStatus = SELECT_SUCCESSFUL;
  671.     semGive (&pSbic->pDevToSelect->devSyncSem);
  672.     break;
  673. }
  674.     break;
  675. case STAT_GROUP_PAUSE_ABORTED:
  676.     SCSI_INT_DEBUG_MSG ("SBIC Aborted interrupt, Code = 0x%xn",
  677. scsiStatus, 0, 0, 0, 0, 0);
  678.     switch (scsiStatus)
  679. {
  680. case STAT_PAUSE_MSG_IN:
  681.     semGive (&pSbic->scsiCtrl.ctrlSyncSem);
  682.     break;
  683. }
  684.     break;
  685. case STAT_GROUP_TERMINATED:
  686.     SCSI_INT_DEBUG_MSG ("SBIC Terminated interrupt, Code = 0x%xn",
  687. scsiStatus, 0, 0, 0, 0, 0);
  688.     switch (scsiStatus)
  689. {
  690. case STAT_TERM_TIMEOUT:
  691.     pSbic->pDevToSelect->devStatus = SELECT_TIMEOUT;
  692.     semGive (&pSbic->pDevToSelect->devSyncSem);
  693.     break;
  694. }
  695.     break;
  696. case STAT_GROUP_SERVICE_REQ:
  697.     SCSI_INT_DEBUG_MSG ("SBIC Serv. Req. interrupt, Code = 0x%xn",
  698. scsiStatus, 0, 0, 0, 0, 0);
  699.     switch (scsiStatus)
  700. {
  701. case STAT_SERV_REQ_DISCON:
  702.     pSbic->scsiCtrl.scsiBusPhase = SCSI_BUS_FREE_PHASE;
  703.     semGive (&pSbic->scsiCtrl.ctrlSyncSem);
  704.     break;
  705. }
  706.     break;
  707. default:
  708.     SCSI_INT_DEBUG_MSG ("SBIC << Unrecognized >> interrupt, 
  709. Code = 0x%xn", scsiStatus, 0, 0, 0, 0, 0);
  710. }
  711.     if (scsiStatus & STAT_PHASE_REQ)
  712. {
  713. pSbic->scsiCtrl.scsiBusPhase = (int) (scsiStatus & STAT_MCI_BITS);
  714. semGive (&pSbic->scsiCtrl.ctrlSyncSem);
  715. }
  716.     }
  717. /*******************************************************************************
  718. *
  719. * sbicHwInit - initialize the SBIC to a known state
  720. *
  721. * This routine puts the SBIC into a known quiescent state and issues a reset
  722. * to the SCSI bus if any signals are active, thus putting target devices in
  723. * some presumably known state.  Currently the initial state is not configurable
  724. * and does not enable reselection.
  725. *
  726. * RETURNS: N/A.
  727. */
  728. LOCAL void sbicHwInit
  729.     (
  730.     SBIC *pSbic                 /* ptr to an SBIC structure */
  731.     )
  732.     {
  733.     int tempOwnIdReg = 0; /* where to form value for "own ID" reg */
  734.     if (pSbic->devType == SBIC_WD33C93A)
  735. {
  736. if (pSbic->scsiCtrl.clkPeriod >= 100)
  737.     tempOwnIdReg = SBIC_FREQ_SELECT_LOW;
  738. else if (pSbic->scsiCtrl.clkPeriod >= 66)
  739.     tempOwnIdReg = SBIC_FREQ_SELECT_MID;
  740. else
  741.     tempOwnIdReg = SBIC_FREQ_SELECT_HIGH;
  742. }
  743.     tempOwnIdReg |= pSbic->scsiCtrl.scsiCtrlBusId;
  744.     sbicScsiBusReset (pSbic);
  745.     sbicRegWrite(pSbic, SBIC_REG_OWN_ID, (UINT8) tempOwnIdReg);
  746.     sbicCommand (pSbic, SBIC_CMD_RESET);
  747.     }
  748. /*******************************************************************************
  749. *
  750. * sbicRegRead - Get the contents of a specified SBIC register
  751. *
  752. * RETURNS: N/A.
  753. *
  754. * NOMANUAL
  755. */
  756. LOCAL void sbicRegRead
  757.     (
  758.     SBIC *pSbic,         /* ptr to an SBIC structure */
  759.     UINT8 regAdrs,       /* register to read         */
  760.     int  *pDatum         /* put data here            */
  761.     )
  762.     {
  763.     *pSbic->pAdrsReg = regAdrs;
  764.     *pDatum = (int) *pSbic->pRegFile;
  765.     }
  766. /*******************************************************************************
  767. *
  768. * sbicRegWrite - write a value to a specified SBIC register
  769. *
  770. * RETURNS: N/A.
  771. *
  772. * NOMANUAL
  773. */
  774. LOCAL void sbicRegWrite
  775.     (
  776.     SBIC *pSbic,         /* ptr to an SBIC structure */
  777.     UINT8 regAdrs,       /* register to write        */
  778.     UINT8 datum          /* data to write            */
  779.     )
  780.     {
  781.     *pSbic->pAdrsReg = regAdrs;
  782.     *pSbic->pRegFile = datum;
  783.     }
  784. /*******************************************************************************
  785. *
  786. * wd33c93Show - display the values of all readable WD33C93 chip registers
  787. *
  788. * This routine displays the state of the SBIC registers in a user-friendly
  789. * manner.  It is useful primarily for debugging.  It should not be invoked 
  790. * while another running process is accessing the SCSI controller.
  791. *
  792. * EXAMPLE:
  793. * .CS
  794. *     -> sbicShow
  795. *     REG #00 (Own ID         ) = 0x07
  796. *     REG #01 (Control        ) = 0x00
  797. *     REG #02 (Timeout Period ) = 0x20
  798. *     REG #03 (Sectors        ) = 0x00
  799. *     REG #04 (Heads          ) = 0x00
  800. *     REG #05 (Cylinders MSB  ) = 0x00 
  801. *     REG #06 (Cylinders LSB  ) = 0x00
  802. *     REG #07 (Log. Addr. MSB ) = 0x00
  803. *     REG #08 (Log. Addr. 2SB ) = 0x00
  804. *     REG #09 (Log. Addr. 3SB ) = 0x00
  805. *     REG #0a (Log. Addr. LSB ) = 0x00
  806. *     REG #0b (Sector Number  ) = 0x00
  807. *     REG #0c (Head Number    ) = 0x00 
  808. *     REG #0d (Cyl. Number MSB) = 0x00
  809. *     REG #0e (Cyl. Number LSB) = 0x00
  810. *     REG #0f (Target LUN     ) = 0x00
  811. *     REG #10 (Command Phase  ) = 0x00
  812. *     REG #11 (Synch. Transfer) = 0x00
  813. *     REG #12 (Xfer Count MSB ) = 0x00
  814. *     REG #13 (Xfer Count 2SB ) = 0x00
  815. *     REG #14 (Xfer Count LSB ) = 0x00
  816. *     REG #15 (Destination ID ) = 0x03
  817. *     REG #16 (Source ID      ) = 0x00
  818. *     REG #17 (SCSI Status    ) = 0x42
  819. *     REG #18 (Command        ) = 0x07
  820. * .CE
  821. *
  822. * RETURNS: OK, or ERROR if <pScsiCtrl> and <pSysScsiCtrl> are both NULL.
  823. */
  824. LOCAL STATUS wd33c93Show
  825.     (
  826.     FAST SCSI_CTRL *pScsiCtrl   /* ptr to SCSI controller info */
  827.     )
  828.     {
  829.     FAST int ix;
  830.     FAST SBIC *pSbic; /* ptr to SBIC info */
  831.     LOCAL char * regName [] =
  832. {
  833. "Own ID         ",
  834. "Control        ",
  835. "Timeout Period ",
  836. "Sectors        ",
  837. "Heads          ",
  838. "Cylinders MSB  ",
  839. "Cylinders LSB  ",
  840. "Log. Addr. MSB ",
  841. "Log. Addr. 2SB ",
  842. "Log. Addr. 3SB ",
  843. "Log. Addr. LSB ",
  844. "Sector Number  ",
  845. "Head Number    ",
  846. "Cyl. Number MSB",
  847. "Cyl. Number LSB",
  848. "Target LUN     ",
  849. "Command Phase  ",
  850. "Synch. Transfer",
  851. "Xfer Count MSB ",
  852. "Xfer Count 2SB ",
  853. "Xfer Count LSB ",
  854. "Destination ID ",
  855. "Source ID      ",
  856. "SCSI Status    ",
  857. "Command        "
  858. };
  859.     if (pScsiCtrl == NULL)
  860.         {
  861. if (pSysScsiCtrl == NULL)
  862.     {
  863.     printErr ("No SCSI controller specified.n");
  864.     return (ERROR);
  865.     }
  866.         pScsiCtrl = pSysScsiCtrl;
  867.         }
  868.     pSbic = (SBIC *) pScsiCtrl;
  869.     for (ix = SBIC_REG_OWN_ID; ix <= SBIC_REG_COMMAND; ix++)
  870. {
  871.         *pSbic->pAdrsReg = (UINT8) ix;
  872. printf ("REG #%02x (%s) = 0x%02xn", ix, regName [ix],
  873. *pSbic->pRegFile);
  874. }
  875.     return (OK);
  876.     }