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

VxWorks

开发平台:

C/C++

  1. /* templateScsi1.c - template SCSI-1 driver */
  2. /* Copyright 1989-1997 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. TODO - Remove the template modification history and begin a new history
  7. starting with version 01a and growing the history upward with
  8. each revision.
  9. 01d,24sep97,dat  changed args to TEMPLATE_READ macro
  10. 01c,20aug97,dat  code review comments from Dinesh
  11. 01b,11aug97,dat  fixed compilation bugs
  12. 01a,07apr97,dat  written from ncr5390Lib1.c, ver 01j
  13. */
  14. /*
  15. DESCRIPTION
  16. TODO - Describe the entire chip completely.  If this device is a part of
  17. a larger ASIC, describe the complete device in a single paragraph.
  18. TODO - Describe the device completely.  Describe all operating modes and
  19. capabilties, whether used or not.
  20. TODO - Describe the modes and limitations of this driver.  Describe how
  21. this driver interacts with the chip and any limitations imposed by the
  22. software.  If this driver interacts with other drivers, describe that
  23. interaction.
  24. USER-CALLABLE ROUTINES
  25. The primary user routines for this driver library are templateCtrlCreate()
  26. and templateCtrlInit().
  27. TemplateCtrlCreate() is used to create a device driver structure that will
  28. represent and control the physical controller device.  
  29. TemplateCtrlInit() is used to setup the device resetting the chip and the
  30. SCSI bus.  See the synopsis for arguments.
  31. DRIVER CUSTOMIZATION
  32. TODO - Describe all macros and constants that the user can change that
  33. will effect the behaviour of this driver.
  34. This template driver presumes that the device is memory mapped, and that the
  35. <regOffset> argument to templateCtrlCreate() indicates the interval between
  36. registers, usually 1, 2 or 4 bytes.  If the base address for the device is
  37. 0x1000 and the regOffset is 4, then the CPU address of register number 3
  38. is (0x1000 + (4 * 3)) = 0x100C.
  39. The macro TEMPLATE_REG_READ(pDev, reg,result) is used to read a
  40. byte from a specified register.  The three arguments are the device structure
  41. pointer, the register id (element of the dev structure), 
  42. and the variable (not a pointer) to receive the register contents.
  43. (If the third argument were a pointer, then it would affect compiler
  44. optimization and could lead to inefficient code generation).
  45. The macro TEMPLATE_REG_WRITE(pDev, reg,data) is used to write data to the
  46. specified register address.  These macros presume memory mapped i/o by
  47. default.  Both macros can be redefined to tailor the driver to some other
  48. i/o model.
  49. The macro SCSI_DEBUG_MSG(format,...) can be used to insert debugging
  50. messages anywhere in the code.  The debug messages will appear only when
  51. the global variable scsiDebug is set to a non-zero value.
  52. INCLUDE FILES
  53. templateScsi1.h
  54. SEE ALSO: scsiLib,
  55. .pG "I/O System"
  56. */
  57. #include "vxWorks.h"
  58. #include "memLib.h"
  59. #include "errnoLib.h"
  60. #include "logLib.h"
  61. #include "scsiLib.h"
  62. #include "stdlib.h"
  63. #include "stdio.h"
  64. #include "taskLib.h"
  65. #include "sysLib.h"
  66. /* defines */
  67. #define TEMPLATE_MAX_XFER_LENGTH ((UINT) (0xffff)) /* max data xfer length */
  68. #define TEMPLATE_MAX_BUS_ID (0x7)
  69. /* Dummy command codes */
  70. #define TEMPLATE_ATN_SELECT (0x1)
  71. #define TEMPLATE_STOP_SELECT (0x2)
  72. #define TEMPLATE_SELECT (0x3)
  73. #ifndef TEMPLATE_REG_READ
  74. #   define TEMPLATE_REG_READ(pDev, reg,result) 
  75. ((result) = *pDev->reg)
  76. #endif  /*TEMPLATE_REG_READ*/
  77. #ifndef TEMPLATE_REG_WRITE
  78. #   define TEMPLATE_REG_WRITE(pDev, reg, data) 
  79. (*pDev->reg = data)
  80. #endif  /*TEMPLATE_REG_WRITE*/
  81. typedef struct { /* TEMPLATE_DEV */
  82.     SCSI_CTRL scsiCtrl;         /* generic SCSI controller info */
  83.     SEM_ID pMutexData;          /* use to protect global siop data */
  84.     SCSI_PHYS_DEV *pDevToSelect;/* device to select at intr. level or NULL */
  85.     } TEMPLATE_DEV;
  86. /* globals */
  87. IMPORT BOOL scsiDebug;
  88. IMPORT BOOL scsiIntsDebug;
  89. /* forward declarations */
  90.       STATUS templateCtrlInit (TEMPLATE_DEV *, int , UINT, int);
  91.       void templateIntr (TEMPLATE_DEV *);
  92. LOCAL void templateCommand (TEMPLATE_DEV *, int);
  93. LOCAL STATUS templateDevSelect (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);
  94. LOCAL STATUS templateMsgInAck (SCSI_CTRL *, BOOL);
  95. LOCAL STATUS templateBytesOut (SCSI_PHYS_DEV *, char *, int, int);
  96. LOCAL STATUS templateBytesIn (SCSI_PHYS_DEV *, char *, int, int);
  97. LOCAL STATUS templateBusPhaseGet (SCSI_CTRL *, int, int *);
  98. LOCAL void templateSelTimeOutCvt (SCSI_CTRL *, UINT , UINT *);
  99. LOCAL STATUS templateBusIdGet (TEMPLATE_DEV *, int *);
  100. LOCAL void templateScsiBusReset (TEMPLATE_DEV *);
  101. LOCAL void templateHwInit (TEMPLATE_DEV *);
  102. /*
  103.  * TODO - remove or replace these macros, they are just pseudo code to allow
  104.  * this template driver to compile without warnings.
  105.  */
  106. #define DEVICE_IS_DISCONNECTED 0
  107. #define NOT_EXPECTED_STATE 0
  108. #define DEVICE_IS_NOT_INTERRUPTING 0
  109. #define DMA_TERMINAL_COUNT_REACHED 0
  110. #define DEVICE_FUNC_COMPLETE 0
  111. /*******************************************************************************
  112. *
  113. * templateCtrlCreate - create a TEMPLATE_DEV device
  114. *
  115. * This routine creates a data structure that must exist before the
  116. * TEMPLATE_DEV chip can be used.  This routine must be called exactly once
  117. * for a specified TEMPLATE_DEV, and must be the first routine called, since
  118. * it calloc's a structure needed by all other routines in the library.
  119. *
  120. * TODO - The input arguments are device specific.  The argument list must
  121. * be updated.
  122. *
  123. * The device specific input parameters are as follows:
  124. * .iP <baseAdrs> 4
  125. * the address at which the CPU would access the lowest 
  126. * register of the TEMPLATE_DEV.
  127. * .iP <regOffset>
  128. * the address offset (bytes) to access consecutive registers.
  129. * (This must be a power of 2, for example, 1, 2, 4, etc.)
  130. * .iP <clkPeriod>
  131. * the period, in nanoseconds, of the signal to the TEMPLATE_DEV clock input (used only
  132. * for select command timeouts).
  133. * .iP "<templateDmaBytesIn> and <templateDmaBytesOut>"
  134. * board-specific parameters to handle DMA input and output.
  135. * If these are NULL (0), TEMPLATE_DEV program mode is used.
  136. * DMA is used only during SCSI data in/out phases.
  137. * The interface to these DMA routines must be of the form:
  138. * .CS
  139. * STATUS templateDmaBytes{In, Out}
  140. *     (
  141. *     TEMPLATE_DEV*  pScsiPhysDev,  /@ ptr to phys dev info    @/
  142. *     UINT8*         pBuffer,       /@ ptr to the data buffer  @/
  143. *     int            bufLength      /@ number of bytes to xfer @/
  144. *     )
  145. * .CE
  146. * .LP
  147. *
  148. * After creating a device, the user will usually then initialize the
  149. * device by calling templateCtrlInit().
  150. *
  151. * RETURNS: A pointer to an TEMPLATE_DEV structure,
  152. * or NULL if memory is insufficient or the parameters are invalid.
  153. */
  154. TEMPLATE_DEV * templateCtrlCreate
  155.     (
  156.     /* TODO - this argument list is device specific, change as needed */
  157.     UINT8 *baseAdrs, /* base address of TEMPLATE_DEV */
  158.     int regOffset, /* addr offset between consecutive regs. */
  159.     UINT clkPeriod, /* period of controller clock (nsec) */
  160.     FUNCPTR templateDmaBytesIn, /* SCSI DMA input function */
  161.     FUNCPTR templateDmaBytesOut /* SCSI DMA output function */
  162.     )
  163.     {
  164.     TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */
  165.     /* TODO - verify parameters, return NULL if necessary */
  166.     /* calloc the controller info structure; return NULL if unable */
  167.     pDev = (TEMPLATE_DEV *) calloc (1, sizeof (TEMPLATE_DEV));
  168.     if (pDev == (TEMPLATE_DEV *) NULL)
  169.         return ((TEMPLATE_DEV *) NULL);
  170.     /* fill in generic SCSI info for this controller */
  171.     scsiCtrlInit (&pDev->scsiCtrl);
  172.     /* fill in remainder of scsiCtrl structure */
  173.     pDev->scsiCtrl.clkPeriod = clkPeriod;
  174.     pDev->scsiCtrl.maxBytesPerXfer = TEMPLATE_MAX_XFER_LENGTH;
  175.     pDev->scsiCtrl.scsiBusReset = (VOIDFUNCPTR) templateScsiBusReset;
  176.     pDev->scsiCtrl.scsiTransact = (FUNCPTR) scsiTransact;
  177.     pDev->scsiCtrl.scsiDevSelect = (FUNCPTR) templateDevSelect;
  178.     pDev->scsiCtrl.scsiBytesIn = (FUNCPTR) templateBytesIn;
  179.     pDev->scsiCtrl.scsiBytesOut = (FUNCPTR) templateBytesOut;
  180.     pDev->scsiCtrl.scsiDmaBytesIn = (FUNCPTR) templateDmaBytesIn;
  181.     pDev->scsiCtrl.scsiDmaBytesOut = (FUNCPTR) templateDmaBytesOut;
  182.     pDev->scsiCtrl.scsiBusPhaseGet = (FUNCPTR) templateBusPhaseGet;
  183.     pDev->scsiCtrl.scsiMsgInAck = (FUNCPTR) templateMsgInAck;
  184.     pDev->scsiCtrl.scsiSelTimeOutCvt = (VOIDFUNCPTR) templateSelTimeOutCvt;
  185.     /* initialize other template_dev fields */
  186.     pDev->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  187.     /* TODO - fill in device specific data for this controller */
  188.     return (pDev);
  189.     }
  190. /*******************************************************************************
  191. *
  192. * templateCtrlInit - initialize a TEMPLATE_DEV
  193. *
  194. * This routine initializes an TEMPLATE_DEV structure created by 
  195. * templateCtrlCreate(). It must be called before the TEMPLATE_DEV is used.
  196. * This routine can be called more than once; however, it should be called
  197. * only while there is no activity on the SCSI interface, since the specified
  198. * configuration is written to the TEMPLATE_DEV.
  199. *
  200. * Before returning, this routine pulses RST (reset) on the SCSI bus, thus
  201. * resetting all attached devices.
  202. *
  203. * The input parameters are as follows:
  204. * .iP <pDev> 4
  205. * a pointer to an TEMPLATE_DEV structure created with templateCtrlCreate().
  206. * .iP <scsiCtrlBusId>
  207. * the SCSI bus ID of the TEMPLATE_DEV, in the range 0 - 7.  The ID is
  208. * somewhat arbitrary; the value 7, or highest priority, is conventional.
  209. * .iP <defaultSelTimeOut>
  210. * the timeout, in microseconds, for selecting a SCSI device attached to this
  211. * controller.  This value is used as a default if no timeout is specified in 
  212. * scsiPhysDevCreate()).  The recommended value zero (0)
  213. * specifies SCSI_DEF_SELECT_TIMEOUT (250 millisec).  The maximum timeout
  214. * possible is approximately 3 seconds.  Values exceeding this revert to the
  215. * maximum.  For more information about chip timeouts, see the device manual.
  216. * .iP <scsiPriority>
  217. * the priority to which a task is set when performing a SCSI transaction.
  218. * Valid priorities are 0 to 255.  Alternatively, the value -1 specifies 
  219. * that the priority should not be altered during SCSI transactions.
  220. *
  221. * RETURNS: OK, or ERROR if a parameter is out of range.
  222. *
  223. * SEE ALSO: scsiPhysDevCreate(),
  224. */
  225. STATUS templateCtrlInit
  226.     (
  227.     TEMPLATE_DEV* pDev, /* ptr to TEMPLATE_DEV struct */
  228.     int scsiCtrlBusId, /* SCSI bus ID of this TEMPLATE_DEV */
  229.     UINT defaultSelTimeOut, /* default dev sel timeout (microsec) */
  230.     int scsiPriority /* priority of task doing SCSI I/O */
  231.     )
  232.     {
  233.     /* verify scsiCtrlBusId and enter legal value in TEMPLATE_DEV structure */
  234.     if (scsiCtrlBusId < SCSI_MIN_BUS_ID || scsiCtrlBusId > TEMPLATE_MAX_BUS_ID)
  235. return (ERROR);
  236.     pDev->scsiCtrl.scsiCtrlBusId = (UINT8) scsiCtrlBusId;
  237.     /* verify scsiPriority and enter legal value in TEMPLATE_DEV structure */
  238.     if (scsiPriority < NONE || scsiPriority > 0xff)
  239. return (ERROR);
  240.     pDev->scsiCtrl.scsiPriority = scsiPriority;
  241.     /* TODO - if needed, issue NO-OP (required by some devices) */
  242.     /* TODO - if needed, compute and set device clocking information */
  243.     /*
  244.      * TODO - verify defaultSelTimeOut, convert it from usec to TEMPLATE_DEV
  245.      * register values, and enter value in TEMPLATE_DEV structure or registers.
  246.      */
  247.     /* disconnect is not supported with SCSI-1, for now */
  248.     pDev->scsiCtrl.disconnect = (TBOOL) FALSE;
  249.     templateHwInit (pDev);  /* initialize the TEMPLATE_DEV hardware */
  250.     return (OK);
  251.     }
  252. /*******************************************************************************
  253. *
  254. * templateDevSelect - attempt to select a SCSI physical device
  255. *
  256. * This routine is called from scsiLib to select a physical device.
  257. * The driver selects the device and sends the initial MSG_OUT and CMD
  258. * bytes.
  259. *
  260. * RETURNS: OK if device was successfully selected, otherwise ERROR.
  261. */
  262. LOCAL STATUS templateDevSelect
  263.     (
  264.     SCSI_PHYS_DEV *pScsiPhysDev,   /* ptr to SCSI physical device info */
  265.     SCSI_TRANSACTION *pScsiXaction /* ptr to SCSI transaction info     */
  266.     )
  267.     {
  268.     TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */
  269.     int templateBusId;          /* SCSI bus ID of the TEMPLATE_DEV */
  270.     UINT8 identMsg; /* for construction of the IDENTIFY message */
  271.     int ix; /* loop index */
  272.     UINT8 *pCmdByte; /* ptr to a command byte */
  273.     UINT8 templateOpcode; /* TEMPLATE_DEV opcode byte */
  274.     pDev = (TEMPLATE_DEV *) pScsiPhysDev->pScsiCtrl;
  275.     /* Return ERROR, if trying to select device's own id */
  276.     if ((templateBusIdGet (pDev, &templateBusId) == ERROR) ||
  277.         (templateBusId == pScsiPhysDev->scsiDevBusId))
  278. {
  279.         return (ERROR);
  280. }
  281.     pDev->pDevToSelect  = pScsiPhysDev;
  282.     pScsiPhysDev->devStatus = SELECT_REQUESTED;
  283.     /* TODO - issue device select command sequence */
  284.     if (pScsiPhysDev->useIdentify) /* send an identify message */
  285. {
  286. identMsg = SCSI_MSG_IDENTIFY |
  287. (pDev->scsiCtrl.disconnect ?
  288. SCSI_MSG_IDENT_DISCONNECT : 0) |
  289. (UINT8) pScsiPhysDev->scsiDevLUN;
  290. /* TODO - send identMsg in MSG_OUT phase */
  291. }
  292.     pCmdByte = pScsiXaction->cmdAddress;
  293.     for (ix = 0; ix < pScsiXaction->cmdLength; ix++)
  294. {
  295. /* TODO - send other command bytes */
  296. ;
  297. }
  298.     if (pScsiPhysDev->useIdentify)
  299. {
  300. if (pScsiPhysDev->msgLength == 0)
  301.     templateOpcode = (UINT8) TEMPLATE_ATN_SELECT;
  302. else
  303.     templateOpcode = (UINT8) TEMPLATE_STOP_SELECT;
  304. }
  305.     else
  306. templateOpcode = (UINT8) TEMPLATE_SELECT;
  307.     /* Send proper SELECT command code */
  308.     templateCommand (pDev, templateOpcode);
  309.     if (semTake (&pDev->scsiCtrl.ctrlSyncSem,
  310.  ((pScsiXaction->cmdTimeout / SCSI_TIMEOUT_1SEC) + 1) *
  311.  sysClkRateGet())
  312.  == ERROR)
  313. {
  314. /* timeout on semaphore, didn't get an interrupt */
  315. printErr ("templateDevSelect: No interrupt received.n");
  316. errorRecovery:
  317. /* TODO - flush device FIFOs, if needed */
  318. /* reset bus, delay 3 seconds to allow devices to reset */
  319. templateScsiBusReset (pDev);
  320. taskDelay (3 * sysClkRateGet ()); /* 3 seconds */
  321. return (ERROR);
  322. }
  323.     if (!(DEVICE_IS_DISCONNECTED))
  324. {
  325. if (NOT_EXPECTED_STATE)
  326.     {
  327.     printErr ("templateDevSelect: Unknown chip state.n");
  328.     /* TODO - print error statistics */
  329.     goto errorRecovery;
  330.     }
  331. else
  332.     {
  333.     /* TODO - flush FIFOs, if needed */
  334.     return (OK);
  335.     }
  336. }
  337.     else
  338. {
  339. /* simple device select timeout */
  340. /* TODO - Flush FIFOs, if needed */
  341. errnoSet (S_scsiLib_SELECT_TIMEOUT);
  342.         return (ERROR);
  343. }
  344.     }
  345. /*******************************************************************************
  346. *
  347. * templateMsgInAck - de-assert the ACK line to accept message
  348. *
  349. * This routine should be called when an incoming message has been read and
  350. * accepted.  If the incoming message did not imply an impending disconnect,
  351. * give the synchronization semaphore, so that subsequent phase can be
  352. * detected.
  353. *
  354. * RETURNS: OK.
  355. */
  356. LOCAL STATUS templateMsgInAck
  357.     (
  358.     SCSI_CTRL* pScsiCtrl, /* ptr to TEMPLATE_DEV info */
  359.     BOOL expectDisconn /* whether a disconnect is expected */
  360.     )
  361.     {
  362.     /* TODO - Send MSG_ACCEPTED to terminate MSG_IN phase, wait for new phase */
  363.     return (OK);
  364.     }
  365. /*******************************************************************************
  366. *
  367. * templateProgBytesOut - output bytes using programmed i/o
  368. *
  369. * This routine is called from templateBytesOut to output data in programmed
  370. * i/o mode.  This presumes that no DMA output routine exists, or we are
  371. * not in data out phase.
  372. *
  373. * RETURNS: OK if successful, otherwise ERROR.
  374. *
  375. * NOMANUAL
  376. */
  377. STATUS templateProgBytesOut
  378.     (
  379.     SCSI_PHYS_DEV* pScsiPhysDev,/* ptr to physical device info       */
  380.     UINT8* pBuffer, /* ptr to the data buffer            */
  381.     int bufLength, /* number of bytes to be transferred */
  382.     int scsiPhase /* phase of the transfer             */
  383.     )
  384.     {
  385.     TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */
  386.     pDev = (TEMPLATE_DEV *) pScsiPhysDev->pScsiCtrl;
  387.     if (bufLength <= 0)
  388. return OK;
  389.     /* TODO - give any setup commands */
  390.     while (bufLength > 0)
  391. {
  392. /* TODO - output byte at pBuffer, exit on error */
  393. pBuffer++;
  394. bufLength--;
  395.         }
  396.     return (OK);
  397.     }
  398. /*******************************************************************************
  399. *
  400. * templateProgBytesIn - input bytes from SCSI using programmed i/o
  401. *
  402. * Read bytes during any input mode.
  403. *
  404. * RETURNS: OK if successful, otherwise ERROR.
  405. *
  406. * NOMANUAL
  407. */
  408. STATUS templateProgBytesIn
  409.     (
  410.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to physical device info       */
  411.     UINT8 *pBuffer, /* ptr to the data buffer            */
  412.     int bufLength, /* number of bytes to be transferred */
  413.     int scsiPhase /* phase of the transfer             */
  414.     )
  415.     {
  416.     TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */
  417.     if (bufLength <= 0)
  418. return OK;
  419.     pDev = (TEMPLATE_DEV *) pScsiPhysDev->pScsiCtrl;
  420.     /* TODO - give any appropriate setup commands */
  421.     while (bufLength > 0)
  422.         {
  423.         *pBuffer++ = 0; /* TODO - transfer one byte to *pBuffer, exit on error */
  424. bufLength--;
  425.         }
  426.     /* send ack to terminate msgin phase */
  427.     if (scsiPhase == SCSI_MSG_IN_PHASE)
  428.         {
  429.         templateMsgInAck ((SCSI_CTRL *) pScsiPhysDev->pScsiCtrl, TRUE);
  430.         }
  431.     return (OK);
  432.     }
  433. /*******************************************************************************
  434. *
  435. * templateBytesOut - write bytes to SCSI data-out phase
  436. *
  437. * This routine is called from scsi1Lib to output data.
  438. * Data is written using either the programmed out routine, or the dma
  439. * out routine.  DMA is only used during the data out
  440. * phase.  Programmed output is used for all other phases.
  441. *
  442. * RETURNS: OK if specified bytes were output successfully, otherwise ERROR.
  443. */
  444. LOCAL STATUS templateBytesOut
  445.     (
  446.     SCSI_PHYS_DEV* pScsiPhysDev, /* ptr to SCSI physical dev info     */
  447.     char* pBuffer, /* ptr to byte buffer for output     */
  448.     int bufLength, /* number of bytes to be transferred */
  449.     int scsiPhase /* SCSI bus phase of the transfer    */
  450.     )
  451.     {
  452.     TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */
  453.     STATUS status; /* local status for iterative xfers */
  454.     int xferLength; /* local length for iterative xfers */
  455.     pDev = (TEMPLATE_DEV *) pScsiPhysDev->pScsiCtrl;
  456.     while (bufLength > 0)
  457. {
  458. xferLength = min (bufLength, TEMPLATE_MAX_XFER_LENGTH);
  459.         if ((scsiPhase != SCSI_DATA_OUT_PHASE) ||
  460.     (pDev->scsiCtrl.scsiDmaBytesOut == NULL))
  461.     {
  462.     status = templateProgBytesOut (pScsiPhysDev, (UINT8 *) pBuffer,
  463.       xferLength, scsiPhase);
  464.     }
  465.         else
  466.     {
  467.     status = (pDev->scsiCtrl.scsiDmaBytesOut)
  468.      (pScsiPhysDev, (UINT8 *) pBuffer, xferLength);
  469.     }
  470. /* if ERROR was returned, exit now */
  471. if (status != OK)
  472.     break;
  473. pBuffer += TEMPLATE_MAX_XFER_LENGTH;
  474. bufLength -= TEMPLATE_MAX_XFER_LENGTH;
  475. }
  476.     return (status);
  477.     }
  478. /*******************************************************************************
  479. *
  480. * templateBytesIn -  read bytes from SCSI data in phase
  481. *
  482. * Read data from SCSI.  Programmed i/o is used for all phases other than
  483. * data in.  For data in phase, DMA input will be used if available, otherwise
  484. * programmed input is used for data in phase too.
  485. *
  486. * RETURNS: OK if requested bytes were input successfully, otherwise ERROR.
  487. */
  488. LOCAL STATUS templateBytesIn
  489.     (
  490.     SCSI_PHYS_DEV* pScsiPhysDev,/* ptr to SCSI physical dev info     */
  491.     char* pBuffer,              /* ptr to byte buffer for output     */
  492.     int bufLength,              /* number of bytes to be transferred */
  493.     int scsiPhase               /* SCSI bus phase of the transfer    */
  494.     )
  495.     {
  496.     TEMPLATE_DEV* pDev; /* ptr to TEMPLATE_DEV info */
  497.     STATUS status = OK; /* local status for iterative xfers */
  498.     int xferLength; /* local length for iterative xfers */
  499.     pDev = (TEMPLATE_DEV *) pScsiPhysDev->pScsiCtrl;
  500.     while (bufLength > 0)
  501.         {
  502.         xferLength = min (bufLength, TEMPLATE_MAX_XFER_LENGTH);
  503.         if ((scsiPhase != SCSI_DATA_IN_PHASE) ||
  504.             (pDev->scsiCtrl.scsiDmaBytesIn == NULL))
  505.             {
  506.             status = templateProgBytesIn (pScsiPhysDev, (UINT8 *) pBuffer,
  507.                                      xferLength, scsiPhase);
  508.             }
  509.         else
  510.             {
  511.             status = (pDev->scsiCtrl.scsiDmaBytesIn)
  512.                      (pScsiPhysDev, (UINT8 *) pBuffer, xferLength);
  513.             }
  514.         if (status != OK)
  515.             break;
  516. pBuffer += TEMPLATE_MAX_XFER_LENGTH;
  517.         bufLength -= TEMPLATE_MAX_XFER_LENGTH;
  518. }
  519.     return (status);
  520.     }
  521. /*******************************************************************************
  522. *
  523. * templateBusPhaseGet - return the current SCSI bus phase in *pBusPhase
  524. *
  525. * This template driver tries to remember the current bus state with
  526. * each interrupt.  It is usually more efficient to return data from
  527. * memory than to do an i/o cycle.
  528. *
  529. * RETURNS: OK, always.
  530. */
  531. LOCAL STATUS templateBusPhaseGet
  532.     (
  533.     SCSI_CTRL* pScsiCtrl,  /* ptr to SCSI controller info     */
  534.     int timeOutInUsec,          /* timeout in usec (0 == infinity) */
  535.     int* pBusPhase              /* ptr to returned bus phase       */
  536.     )
  537.     {
  538.     TEMPLATE_DEV *pDev; /* ptr to TEMPLATE_DEV info */
  539.     pDev = (TEMPLATE_DEV *) pScsiCtrl;
  540.     /*
  541.      * TODO - if current bus phase was stored in memory from
  542.      * last interrupt cycle, then return that information.
  543.      * Otherwise, read bus phase from device.
  544.      */
  545.     return (OK);
  546.     }
  547. /*******************************************************************************
  548. *
  549. * templateSelTimeOutCvt - convert a select time-out in microseconds to its
  550. * equivalent TEMPLATE_DEV setting
  551. *
  552. * Also, the TEMPLATE_DEV accepts up to a 8 bit time-out, so a maximum value
  553. * of 0xff is returned in *pTimeOutSetting.
  554. */
  555. LOCAL void templateSelTimeOutCvt
  556.     (
  557.     SCSI_CTRL* pScsiCtrl,          /* ptr to SCSI controller info */
  558.     UINT timeOutInUsec,            /* time-out in microsecs       */
  559.     UINT* pTimeOutSetting          /* time-out equivalent setting */
  560.     )
  561.     {
  562.     /*
  563.      * TODO - convert microseconds to device data.
  564.      * Store at *pTimeOutSetting
  565.      */
  566.     }
  567. /*******************************************************************************
  568. *
  569. * templateBusIdGet - get the current SCSI bus ID of the TEMPLATE_DEV.
  570. *
  571. * Copies the bus ID to <pBusId>.
  572. *
  573. * RETURNS:
  574. * OK if Bus ID register holds a legal value, otherwise ERROR.
  575. */
  576. LOCAL STATUS templateBusIdGet
  577.     (
  578.     TEMPLATE_DEV* pDev,             /* ptr to TEMPLATE_DEV info        */
  579.     int* pBusId            /* ptr to returned bus ID */
  580.     )
  581.     {
  582.     /* TODO - put device id into *pBusId location */
  583.     return (OK);
  584.     }
  585. /*******************************************************************************
  586. *
  587. * templateCommand - write a command code to the TEMPLATE_DEV Command Register
  588. *
  589. * NOMANUAL
  590. */
  591. LOCAL void templateCommand
  592.     (
  593.     TEMPLATE_DEV* pDev, /* ptr to TEMPLATE_DEV info  */
  594.     int cmdCode /* new command code */
  595.     )
  596.     {
  597.     /*
  598.      * Clear the sync semaphore, just in case this command generates an
  599.      * interrupt.
  600.      */
  601.     semTake (&pDev->scsiCtrl.ctrlSyncSem, NO_WAIT);
  602.     /* TODO - issue command to device */
  603.     }
  604. /*******************************************************************************
  605. *
  606. * templateScsiBusReset - assert the RST line on the SCSI bus
  607. *
  608. * Issue a SCSI Bus Reset command to the NCR 5390.  This should put all devices
  609. * on the SCSI bus in an initial quiescent state.
  610. */
  611. LOCAL void templateScsiBusReset
  612.     (
  613.     TEMPLATE_DEV *pDev /* ptr to TEMPLATE_DEV info */
  614.     )
  615.     {
  616.     /* TODO - issue bus reset command */
  617.     semTake (&pDev->scsiCtrl.ctrlSyncSem, WAIT_FOREVER);
  618.     /* TODO - set remembered bus phase to be BUS_FREE */
  619.     /* allow time for reset signal to become inactive */
  620.     taskDelay (2);
  621.     }
  622. /*******************************************************************************
  623. *
  624. * templateIntr - interrupt service routine for the TEMPLATE_DEV
  625. *
  626. * NOMANUAL
  627. */
  628. void templateIntr
  629.     (
  630.     TEMPLATE_DEV *pDev          /* ptr to TEMPLATE_DEV info */
  631.     )
  632.     {
  633.     SCSI_PHYS_DEV *pDevToSelect;
  634.     /* TODO - read current device state, including bus phase */
  635.     /* Quick exit if no interrupt present, this is not an error. */
  636.     if (DEVICE_IS_NOT_INTERRUPTING)
  637. return;
  638.     /* TODO - save status registers as needed */
  639.     if (DMA_TERMINAL_COUNT_REACHED)
  640. {
  641. /* TODO - if necessary, clear the DMA TC condition */
  642. }
  643.     if (DEVICE_FUNC_COMPLETE)
  644.         {
  645.      /* if a selection attempt has been made, report success */
  646. if (((pDevToSelect = pDev->pDevToSelect) != (SCSI_PHYS_DEV *) NULL) &&
  647.     (pDevToSelect->devStatus == SELECT_IN_PROGRESS))
  648.     {
  649.     pDevToSelect->devStatus = SELECT_SUCCESSFUL;
  650.     pDev->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  651.     }
  652.         }
  653.     else if (DEVICE_IS_DISCONNECTED)
  654.         {
  655.      /* if a device has not been selected, then a timeout has occurred */
  656. if (((pDevToSelect = pDev->pDevToSelect) != (SCSI_PHYS_DEV *) NULL) &&
  657.     (pDevToSelect->devStatus == SELECT_IN_PROGRESS))
  658.     {
  659.     pDevToSelect->devStatus = SELECT_TIMEOUT;
  660.     pDev->pDevToSelect = (SCSI_PHYS_DEV *) NULL;
  661.     }
  662. else
  663.     {
  664.     pDev->scsiCtrl.scsiBusPhase = SCSI_BUS_FREE_PHASE;
  665.     }
  666.         }
  667.     /* send synch signal to controlling task */
  668.     semGive (&pDev->scsiCtrl.ctrlSyncSem);
  669.     /*
  670.      * TODO - If device is slow, check that the interrupt line has
  671.      * actually gone low, but don't loop forever.
  672.      */
  673.     }
  674. /*******************************************************************************
  675. *
  676. * templateHwInit - initialize the TEMPLATE_DEV chip to a known state
  677. *
  678. * This routine puts the TEMPLATE_DEV into a known quiescent state and issues a reset
  679. * to the SCSI Bus if any signals are active, thus putting target devices in
  680. * some presumably known state.  Currently the initial state is not configurable
  681. * and does not enable reselection.
  682. *
  683. * INTERNAL
  684. * Needs to handle parity enable
  685. */
  686. LOCAL void templateHwInit
  687.     (
  688.     TEMPLATE_DEV* pDev          /* ptr to an TEMPLATE_DEV info structure */
  689.     )
  690.     {
  691.     /* TODO - reset the device to its initial state */
  692.     templateScsiBusReset (pDev);  /* Reset the bus */
  693.     }
  694. #ifdef INCLUDE_SHOW_ROUTINES
  695. /*******************************************************************************
  696. *
  697. * templateShow - display the status of the TEMPLATE_DEV device
  698. *
  699. * This routine displays the state of the TEMPLATE_DEV registers in a
  700. * user-friendly manner.  It is useful primarily for debugging.
  701. *
  702. * EXAMPLE:
  703. * .CS
  704. *     -> templateShow
  705. *     pTclReg  = 0x00
  706. *     pTchReg  = 0x02
  707. *     pFifoReg = 0x00 
  708. *     pCmdReg  = 0x12
  709. *     pStatReg = 0x00
  710. *     pIntrReg = 0x00 
  711. *     pStepReg = 0xc4
  712. *     pFlgsReg = 0x00 
  713. *     pCfg1Reg = 0x07
  714. * .CE
  715. *
  716. * RETURNS: OK, or ERROR if <pScsiCtrl> and <pSysScsiCtrl> are both NULL.
  717. */
  718. LOCAL STATUS templateShow
  719.     (
  720.     SCSI_CTRL *pScsiCtrl      /* ptr to TEMPLATE_DEV info */
  721.     )
  722.     {
  723.     TEMPLATE_DEV *pDev;
  724.     if (pScsiCtrl == NULL)
  725. {
  726. if (pSysScsiCtrl == NULL)
  727.     {
  728.     printErr ("No SCSI controller specified.n");
  729.     return (ERROR);
  730.     }
  731. pScsiCtrl = pSysScsiCtrl;
  732. }
  733.     pDev = (TEMPLATE_DEV *) pScsiCtrl;
  734.     /* TODO - access and display all the device registers */
  735.     return (OK);
  736.     }
  737. #endif /* INCLUDE_SHOW_ROUTINES */