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

VxWorks

开发平台:

C/C++

  1. /* ncr710Lib2.c - NCR 53C710 SCSI I/O Processor (SIOP) library (SCSI-2) */
  2. /* Copyright 1989-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 04p,19oct01,dat  Documentation formatting
  8. 04o,26feb99,dat  added init of wideXfer to FALSE. SPR 24089
  9. 04n,03dec98,ihw  Modified handling of ident message for new thread:
  10.  add normal message out (if any) - e.g. sync/wide xfer.
  11. 04m,26aug98,sut  renamed ncr710StepEnable into ncr710StepEnable2 ;
  12.                  in ncr710CtrlCreate added support to use
  13.                  ncr710StepEnable2 as the ncr710StepEnable
  14.                  see also ncr710CommLib.c
  15. 04l,24aug98,sut  renamed ncr710SingleStep into ncr710SingleStep2 ;
  16.                  In ncr710CtrlCreateScsi2 added support to use
  17.                  ncr710SingleStep2 as the ncr710SingleStep
  18.                  see also ncr710CommLib.c
  19. 04k,18May98,pfl  SPR 21260: added ncr710ResetATN() 
  20. 04j,09jul97,dgp  doc: correct fonts per SPR 7853
  21. 04i,29oct96,dgp  doc: editing for newly published SCSI libraries
  22. 04h,06may96,jds  and more doc tweaks...
  23. 04g,01may96,jds  yet more doc tweaks...
  24. 04f,08nov95,jds  more doc tweaks
  25. 04e,20sep95,jdi  doc cleanup.
  26. 04d,28apr95,jds  worked with ian on selection problem (hang) with WD33c93; 
  27.  integrated into WRS tree; backward compatability stuff
  28. 04c,16mar94,ihw  fixed problems highlighted by selection by WD 33C93
  29. 04b,27may94,ihw  documented prior to release
  30. 04a,02may94,ihw  major modifications to work with new SCSI architecture
  31.               supports tagged commands
  32. 03b,23feb94,ihw  improved single-step support
  33. 03a,18feb94,ihw  modified for enhanced SCSI library: multiple initiators,
  34.                     disconnect/reconnect and synchronous transfer supported
  35. 02l,10feb93,ccc  fixed cache problem and null pointers (spr 1995).
  36. 02k,26sep92,ccc  doc changes.
  37. 02j,18aug92,ccc  fixed warnings.
  38. 02i,31jul92,dnw  Changed to new cacheLib.
  39.  Added requirement that dma cache be write coherent and
  40.  removed corresponding flushes.
  41. 02h,20jul92,eve  Move debug macros from ncr710.h.
  42. 02g,20jul92,eve  Added cache support for 5.1. 
  43. 02f,18jul92,smb  Changed errno.h to errnoLib.h.
  44. 02e,13jul92,eve  Make a single exit process both for OK and ERROR in 
  45.  ncr710ScsiPhase() and create ncr710CheckStatRegs().
  46. 02d,11jul92,eve  Suppress ncr710CmdBuild() since scsiCmdBuild() is public
  47.  in scsiLib.c.Suppress ncr710Relocation() routine.
  48. 02c,02jul92,eve  start ANSI modifications.
  49. 02b,21apr92,eve  Add disconnect capability.
  50. 02a,03mar92,eve  Add the process for new bit in the ncr710HwRegister() 
  51.  and suppress access to the EA bit in the other routines. 
  52. 01n,20feb92,eve  Change the clock frequency parameter by a value
  53.                  like xxns * 100 in ncr710CtrlCreate().
  54. 01m,12jan91,eve  Add support for sync transfer capability.
  55. 01l,10dec91,eve  Correct bug in ncr710ScsiPhase() regarding the Bus fault
  56.                  Wtd timeout and illegal instruction.
  57. 01k,29nov91,eve  Change semTake timeout in ncr710StartPhase().
  58. 01j,29nov91,eve  Correct use of pDevToSelect,suppress initialisation
  59.                  devSync semaphore in ncr710HwInit().
  60. 01i,07nov91,eve  Perform a select with attention in ncr710ScsiPhase()
  61.  if useIdentify is set.
  62. 01h,01nov91,ccc  Documentation changes, changed modification numbers.
  63. 01g,01nov91,eve  Suppress pccchip2 include
  64. 01f,27oct91,eve  Suppress regOffset argument in ncr710CtlrCreate(),
  65.  the chip need to be connected to all of the address 
  66.  bus (31-0).
  67. 01e,27oct91,eve  Add ncr710SetHwRegister() routine.
  68. 01d,25oct91,eve  Allocate dynamicly ncrCtlShare data structure
  69.  keep only a pointer in SIOP info.
  70. 01c,24oct91,eve  Change clockPeriod by a frequency value
  71.  in ncr710CtrlCreate().
  72. 01b,24oct91,eve  Try to cleaning up documentation.
  73. 01a,23oct91,eve  Created. 
  74. */
  75. /*
  76. DESCRIPTION
  77. This is the I/O driver for the NCR 53C710 SCSI I/O Processor (SIOP).
  78. It is designed to work with scsi2Lib.  This driver runs in
  79. conjunction with a script program for the NCR 53C710 chip.
  80. The script uses the NCR 53C710 DMA function for data transfers.
  81. This driver supports cache functions through cacheLib.
  82. USER-CALLABLE ROUTINES
  83. Most of the routines in this driver are accessible only through the I/O
  84. system.  Three routines, however, must be called directly.  
  85. ncr710CtrlCreateScsi2() creates a controller structure and
  86. ncr710CtrlInitScsi2() initializes it.
  87. The NCR 53C710 hardware registers need to be configured according to
  88. the hardware implementation.  If the default configuration is not correct,
  89. the routine ncr710SetHwRegisterScsi2() must be used to properly configure
  90. the registers.
  91. INTERNAL
  92. This driver supports multiple initiators, disconnect/reconnect, tagged
  93. command queueing and synchronous data transfer protocol.  In general, the
  94. SCSI system and this driver will automatically choose the best combination
  95. of these features to suit the target devices used.  However, the default
  96. choices may be over-ridden by using the function "scsiTargetOptionsSet()"
  97. (see scsi2Lib).
  98. There are debug variables to trace events in the driver.
  99. <scsiDebug> scsi2Lib debug variable, trace event in scsi2Lib, ncr710ScsiPhase(),
  100. and ncr710Transact().
  101. <scsiIntsDebug> prints interrupt informations.
  102. INCLUDE FILES
  103. ncr710.h, ncr710_2.h, ncr710Script.h, ncr710Script2.h
  104. SEE ALSO: scsiLib, scsi2Lib, cacheLib,
  105. .pG "I/O System"
  106. */
  107. #define  INCLUDE_SCSI2
  108. #include "vxWorks.h"
  109. #include "memLib.h"
  110. #include "ctype.h"
  111. #include "stdlib.h"
  112. #include "string.h"
  113. #include "stdio.h"
  114. #include "logLib.h"
  115. #include "semLib.h"
  116. #include "intLib.h"
  117. #include "errnoLib.h"
  118. #include "cacheLib.h"
  119. #include "taskLib.h"
  120. #include "drv/scsi/ncr710.h"
  121. #include "drv/scsi/ncr710Script.h"
  122. /* defines */
  123. typedef NCR_710_SCSI_CTRL SIOP;
  124. #define SIOP_MAX_XFER_LENGTH   ((UINT) (0x00ffffff)) /* max data xfer length */
  125. /* External */
  126. IMPORT BOOL scsiDebug;
  127. IMPORT BOOL scsiErrors;
  128. IMPORT BOOL scsiIntsDebug;
  129. IMPORT VOIDFUNCPTR ncr710SingleStepRtn; /* Single step routine */
  130. IMPORT VOIDFUNCPTR ncr710StepEnableRtn; /* Step enable step routine */
  131. /*
  132.  *  Configurable options
  133.  */
  134. int ncr710SingleStepSemOptions = SEM_Q_PRIORITY;
  135. char *ncr710ScsiTaskName      = SCSI_DEF_TASK_NAME;
  136. int   ncr710ScsiTaskOptions   = SCSI_DEF_TASK_OPTIONS;
  137. int   ncr710ScsiTaskPriority  = SCSI_DEF_TASK_PRIORITY;
  138. int   ncr710ScsiTaskStackSize = SCSI_DEF_TASK_STACK_SIZE;
  139. /* forward declarations */
  140. LOCAL void   ncr710HwInit        (SIOP *pSiop);
  141. LOCAL int    ncr710BusIdGet      (SIOP *pSiop, UINT busIdBits);
  142. LOCAL UINT   ncr710RemainderGet  (SIOP *pSiop, UINT phase);
  143. LOCAL int    ncr710EventTypeGet  (SIOP *pSiop);
  144. LOCAL STATUS ncr710PhaseMismatch (NCR710_THREAD * pThread,
  145.   int             phase,
  146.   UINT            remCount);
  147. LOCAL STATUS ncr710ScsiBusControl (SIOP *pSiop, int operation);
  148. LOCAL void   ncr710ScsiBusReset   (SIOP *pSiop);
  149. LOCAL STATUS ncr710ThreadActivate (SIOP *pSiop, NCR710_THREAD *pThread);
  150. LOCAL BOOL   ncr710ThreadAbort    (SIOP *pSiop, NCR710_THREAD *pThread);
  151. LOCAL void   ncr710Event          (SIOP *pSiop, NCR710_EVENT  *pEvent);
  152. LOCAL void   ncr710ThreadEvent   (NCR710_THREAD *pThread, NCR710_EVENT *pEvent);
  153. LOCAL void   ncr710InitEvent     (NCR710_THREAD *pThread, NCR710_EVENT *pEvent);
  154. LOCAL void   ncr710InitIdentEvent(NCR710_THREAD *pThread, NCR710_EVENT *pEvent);
  155. LOCAL void   ncr710TargIdentEvent(NCR710_THREAD *pThread, NCR710_EVENT *pEvent);
  156. LOCAL void   ncr710IdentInContinue (NCR710_THREAD *pThread);
  157. LOCAL void   ncr710ThreadReconnect (NCR710_THREAD *pThread);
  158. LOCAL void   ncr710SharedMemInit   (SIOP *pSiop, NCR710_SHARED *pShMem);
  159. LOCAL STATUS ncr710ThreadInit      (SIOP *pSiop, NCR710_THREAD *pThread);
  160. LOCAL STATUS ncr710IdentThreadInit (NCR710_THREAD *pThread);
  161. LOCAL void   ncr710ThreadUpdate    (NCR710_THREAD *pThread);
  162. LOCAL void   ncr710ThreadComplete  (NCR710_THREAD *pThread);
  163. LOCAL void   ncr710ThreadDefer     (NCR710_THREAD *pThread);
  164. LOCAL void   ncr710ThreadFail      (NCR710_THREAD *pThread, int errNum);
  165. LOCAL void   ncr710ThreadStateSet  (NCR710_THREAD *pThread,
  166.     SCSI_THREAD_STATE state);
  167. LOCAL STATUS ncr710Activate      (SIOP               *pSiop,
  168.   NCR710_THREAD      *pThread);
  169. LOCAL STATUS ncr710Resume        (SIOP               *pSiop,
  170.   NCR710_THREAD      *pThread,
  171.   NCR710_SCRIPT_ENTRY entryId);
  172. LOCAL void   ncr710Abort         (SIOP               *pSiop);
  173. LOCAL void   ncr710ScriptStart   (SIOP               *pSiop,
  174.   NCR710_THREAD      *pThread,
  175.   NCR710_SCRIPT_ENTRY entryId);
  176. LOCAL STATUS ncr710ThreadParamsSet (NCR710_THREAD * pThread,
  177.     UINT8      offset,
  178.     UINT8      period);
  179. LOCAL STATUS ncr710XferParamsQuery (SCSI_CTRL *pScsiCtrl,
  180.     UINT8     *pOffset,
  181.     UINT8     *pPeriod);
  182. LOCAL STATUS ncr710XferParamsSet   (SCSI_CTRL *pScsiCtrl,
  183.     UINT8      offset,
  184.     UINT8      period);
  185. LOCAL BOOL   ncr710XferParamsCvt   (SIOP  *pSiop,
  186.     UINT8 *pOffset,
  187.     UINT8 *pPeriod,
  188.     UINT8 *pXferParams,
  189.     UINT8 *pClockDiv);
  190. LOCAL void   ncr710ResetATN ( FAST SCSI_CTRL *pScsiCtrl );
  191. LOCAL void ncr710SingleStep2 (SIOP* pSiop, BOOL verbose);
  192. LOCAL void ncr710StepEnable2 (SIOP* pSiop, BOOL boolValue);
  193. LOCAL void   ncr710ResetATN ( FAST SCSI_CTRL *pScsiCtrl );
  194. /*******************************************************************************
  195. *
  196. * ncr710CtrlCreateScsi2 - create a control structure for the NCR 53C710 SIOP
  197. *
  198. * This routine creates an SIOP data structure and must be called before
  199. * using an SIOP chip. It must be called exactly once for a 
  200. * specified SIOP controller.
  201. * Since it allocates memory for a structure needed by all routines in 
  202. * ncr710Lib, it must be called before any other routines in the library.
  203. * After calling this routine, ncr710CtrlInitScsi2() must be called at least
  204. * once before any SCSI transactions are initiated using the SIOP.
  205. *
  206. * A detailed description of the input parameters follows:
  207. * .iP <baseAdrs>
  208. * the address at which the CPU accesses the lowest (SCNTL0/SIEN)
  209. * register of the SIOP.
  210. * .iP <clkPeriod>
  211. * the period of the SIOP SCSI clock input, in nanoseconds, multiplied
  212. * by 100.  This is used to determine the clock period for the
  213. * SCSI core of the chip and affects the timing of both asynchronous
  214. * and synchronous transfers.
  215. * Several commonly used values are defined in ncr710.h as follows:
  216. *.CS
  217. * NCR710_1667MHZ  6000    /@ 16.67Mhz chip @/
  218. * NCR710_20MHZ    5000    /@ 20Mhz chip    @/
  219. * NCR710_25MHZ    4000    /@ 25Mhz chip    @/
  220. * NCR710_3750MHZ  2667    /@ 37.50Mhz chip @/
  221. * NCR710_40MHZ    2500    /@ 40Mhz chip    @/
  222. * NCR710_50MHZ    2000    /@ 50Mhz chip    @/
  223. * NCR710_66MHZ    1515    /@ 66Mhz chip    @/
  224. * NCR710_6666MHZ  1500    /@ 66.66Mhz chip @/
  225. *.CE
  226. *
  227. * RETURNS: A pointer to the NCR_710_SCSI_CTRL structure, or NULL if memory 
  228. * is unavailable or there are invalid parameters.
  229. */
  230. NCR_710_SCSI_CTRL *ncr710CtrlCreateScsi2 
  231.     (
  232.     UINT8 *baseAdrs, /* base address of the SIOP */
  233.     UINT   clkPeriod /* clock controller period (nsec*100) */
  234.     )
  235.     {
  236.     FAST SIOP *pSiop;     /* ptr to SIOP info */
  237.     int        nBytes;          /* total amount of cache-coherent memory */
  238.     SCSI_CTRL *pScsiCtrl;
  239.     static NCR710_HW_REGS ncr710HwRegs = DEFAULT_710_HW_REGS;
  240.     /* SingleStep routine selection */
  241.     
  242.     ncr710SingleStepRtn = ncr710SingleStep2;
  243.     ncr710StepEnableRtn = ncr710StepEnable2;
  244.     /* verify parameters */
  245.     if (baseAdrs == ((UINT8 *) NULL))
  246. return ((SIOP *) NULL);
  247.     
  248.     if ((clkPeriod > NCR710_1667MHZ) ||  
  249.         (clkPeriod < NCR710_6666MHZ))
  250.         return ((SIOP *) NULL);
  251.     
  252.     /* check that dma buffers are cache-coherent */
  253.     if (!CACHE_DMA_IS_WRITE_COHERENT () ||
  254. !CACHE_DMA_IS_READ_COHERENT ())
  255. {
  256. SCSI_MSG ("ncr710CtrlCreateScsi2: shared memory not cache coherent.n",
  257.   0, 0, 0, 0, 0, 0);
  258.         return ((SIOP *) NULL);
  259. }
  260.     /* calloc the controller info structure and two shared data areas */
  261.     nBytes = sizeof (SIOP) + 2 * sizeof (NCR710_SHARED);
  262.     if ((pSiop = (SIOP *) cacheDmaMalloc (nBytes)) == (SIOP *) NULL)
  263.         return ((SIOP *) NULL);
  264.     bzero ((char *) pSiop, nBytes);
  265.     pSiop->pIdentShMem  = (NCR710_SHARED *) (pSiop + 1);
  266.     pSiop->pClientShMem = pSiop->pIdentShMem + 1;
  267.     /* set up configuration variables */
  268.     pScsiCtrl = (SCSI_CTRL *) pSiop;
  269.     
  270.     pScsiCtrl->eventSize  = sizeof (NCR710_EVENT);
  271.     pScsiCtrl->threadSize = sizeof (NCR710_THREAD);
  272.     /* fill in virtual functions used by SCSI library */
  273.     
  274.     pScsiCtrl->maxBytesPerXfer = SIOP_MAX_XFER_LENGTH;
  275.     pScsiCtrl->scsiTransact = (FUNCPTR) scsiTransact;
  276.     pScsiCtrl->scsiEventProc       = (VOIDFUNCPTR) ncr710Event;
  277.     pScsiCtrl->scsiThreadInit      = (FUNCPTR)     ncr710ThreadInit;
  278.     pScsiCtrl->scsiThreadActivate  = (FUNCPTR)     ncr710ThreadActivate;
  279.     pScsiCtrl->scsiThreadAbort     = (FUNCPTR)     ncr710ThreadAbort;
  280.     pScsiCtrl->scsiBusControl      = (FUNCPTR)     ncr710ScsiBusControl;
  281.     pScsiCtrl->scsiXferParamsQuery = (FUNCPTR)     ncr710XferParamsQuery;
  282.     pScsiCtrl->scsiXferParamsSet   = (FUNCPTR)     ncr710XferParamsSet;
  283.     /* the following virtual functions are not used with the NCR 53C710 */
  284.    
  285.     pScsiCtrl->wideXfer        = FALSE;
  286.     pScsiCtrl->scsiWideXferParamsQuery = NULL;
  287.     pScsiCtrl->scsiWideXferParamsSet   = NULL;
  288.     pScsiCtrl->scsiDevSelect = NULL;
  289.     pScsiCtrl->scsiInfoXfer  = NULL;
  290.     /* fill in generic SCSI info for this controller */
  291.     scsiCtrlInit (&pSiop->scsiCtrl);
  292.     /* fill in SIOP specific data for this controller */
  293.     pSiop->pSien     = baseAdrs + OFF_SIEN;
  294.     pSiop->pSdid     = baseAdrs + OFF_SDID;
  295.     pSiop->pScntl1   = baseAdrs + OFF_SCNTL1;
  296.     pSiop->pScntl0   = baseAdrs + OFF_SCNTL0;
  297.     pSiop->pSocl     = baseAdrs + OFF_SOCL;
  298.     pSiop->pSodl     = baseAdrs + OFF_SODL;
  299.     pSiop->pSxfer    = baseAdrs + OFF_SXFER;
  300.     pSiop->pScid     = baseAdrs + OFF_SCID;
  301.     pSiop->pSbcl     = baseAdrs + OFF_SBCL;
  302.     pSiop->pSbdl     = baseAdrs + OFF_SBDL;
  303.     pSiop->pSidl     = baseAdrs + OFF_SIDL;
  304.     pSiop->pSfbr     = baseAdrs + OFF_SFBR;
  305.     pSiop->pSstat2   = baseAdrs + OFF_SSTAT2;
  306.     pSiop->pSstat1   = baseAdrs + OFF_SSTAT1;
  307.     pSiop->pSstat0   = baseAdrs + OFF_SSTAT0;
  308.     pSiop->pDstat    = baseAdrs + OFF_DSTAT;
  309.     pSiop->pDsa      = (UINT *) (baseAdrs + OFF_DSA);
  310.     pSiop->pCtest3   = baseAdrs + OFF_CTEST3;
  311.     pSiop->pCtest2   = baseAdrs + OFF_CTEST2;
  312.     pSiop->pCtest1   = baseAdrs + OFF_CTEST1;
  313.     pSiop->pCtest0   = baseAdrs + OFF_CTEST0;
  314.     pSiop->pCtest7   = baseAdrs + OFF_CTEST7;
  315.     pSiop->pCtest6   = baseAdrs + OFF_CTEST6;
  316.     pSiop->pCtest5   = baseAdrs + OFF_CTEST5;
  317.     pSiop->pCtest4   = baseAdrs + OFF_CTEST4;
  318.     pSiop->pTemp     = (UINT *) (baseAdrs + OFF_TEMP);
  319.     pSiop->pLcrc     = baseAdrs + OFF_LCRC;
  320.     pSiop->pCtest8   = baseAdrs + OFF_CTEST8;
  321.     pSiop->pIstat    = baseAdrs + OFF_ISTAT;
  322.     pSiop->pDfifo    = baseAdrs + OFF_DFIFO;
  323.     pSiop->pDcmd     = baseAdrs + OFF_DCMD;
  324.     pSiop->pDbc      = (UINT *) (baseAdrs + OFF_DBC);
  325.     pSiop->pDnad     = (UINT *) (baseAdrs + OFF_DNAD);
  326.     pSiop->pDsp      = (UINT *) (baseAdrs + OFF_DSP);
  327.     pSiop->pDsps     = (UINT *) (baseAdrs + OFF_DSPS);
  328.     pSiop->pScratch0 = baseAdrs + OFF_SCRATCH0;
  329.     pSiop->pScratch1 = baseAdrs + OFF_SCRATCH1;
  330.     pSiop->pScratch2 = baseAdrs + OFF_SCRATCH2;
  331.     pSiop->pScratch3 = baseAdrs + OFF_SCRATCH3;
  332.     pSiop->pDcntl    = baseAdrs + OFF_DCNTL;
  333.     pSiop->pDwt      = baseAdrs + OFF_DWT;
  334.     pSiop->pDien     = baseAdrs + OFF_DIEN;
  335.     pSiop->pDmode    = baseAdrs + OFF_DMODE;
  336.     pSiop->pAdder    = (UINT *) (baseAdrs + OFF_ADDER);
  337.     pSiop->clkPeriod = clkPeriod;
  338.     /*
  339.      * Initialise hardware-dependent registers to default values.
  340.      */
  341.     bcopy ((char *)&ncr710HwRegs, (char *)&pSiop->hwRegs,
  342.                           sizeof (NCR710_HW_REGS));
  343.     /*
  344.      * Create synchronisation semaphore for single-step support
  345.      */
  346.     if ((pSiop->singleStepSem = semBCreate(ncr710SingleStepSemOptions,
  347.    SEM_EMPTY)) == NULL)
  348. {
  349. SCSI_MSG ("ncr710CtrlCreateScsi2: semBCreate of singleStepSem failed.n"
  350.   , 0, 0, 0, 0, 0, 0);
  351. goto failed;
  352.         }
  353.     /*
  354.      * Initialise controller state variables
  355.      */
  356.     pSiop->state      = NCR710_STATE_IDLE;
  357.     pSiop->cmdPending = FALSE;
  358.     /*
  359.      * Initialize fixed fields in client shared data area
  360.      */
  361.     ncr710SharedMemInit (pSiop, pSiop->pClientShMem);
  362.     /*
  363.      * Identification thread has been created by the generic initialisation.
  364.      * Initialise it for use with the NCR 53C710.
  365.      */
  366.     ncr710IdentThreadInit ((NCR710_THREAD *) pScsiCtrl->pIdentThread);
  367.     /* spawn SCSI manager - use generic code from "scsiLib.c" */
  368.     pScsiCtrl->scsiMgrId = taskSpawn (ncr710ScsiTaskName,
  369.                    ncr710ScsiTaskPriority,
  370.                    ncr710ScsiTaskOptions,
  371.                    ncr710ScsiTaskStackSize,
  372.                    (FUNCPTR) scsiMgr,
  373.                    (int) pSiop, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  374.     if (pScsiCtrl->scsiMgrId == ERROR)
  375. {
  376. SCSI_MSG ("ncr710CtrlCreateScsi2: can't spawn SCSI manager taskn",
  377.   0, 0, 0, 0, 0, 0);
  378. goto failed;
  379. }
  380.     return (pSiop);
  381. failed:
  382.     if (pSiop->singleStepSem != NULL)
  383. (void) semDelete (pSiop->singleStepSem);
  384.     (void) cacheDmaFree ((char *) pSiop);
  385.     
  386.     return (NULL);
  387.     }
  388. /*******************************************************************************
  389. *
  390. * ncr710CtrlInitScsi2 - initialize a control structure for the NCR 53C710 SIOP
  391. *
  392. * This routine initializes an SIOP structure after the structure is created
  393. * with ncr710CtrlCreateScsi2().  This structure must be initialized before the
  394. * SIOP can be used.  It may be called more than once if needed;  however,
  395. * it must only be called while there is no activity on the SCSI interface.
  396. *
  397. * A detailed description of the input parameters follows:
  398. * .iP <pSiop>
  399. * a pointer to the NCR_710_SCSI_CTRL structure created with
  400. * ncr710CtrlCreateScsi2().
  401. * .iP <scsiCtrlBusId>
  402. * the SCSI bus ID of the SIOP.  Its value is somewhat arbitrary:  seven (7),
  403. * or highest priority, is conventional.  The value must be in the range 0 - 7.
  404. * .iP <scsiPriority>
  405. * this parameter is ignored.  All SCSI I/O is now done in the context of
  406. * the SCSI manager task; if necessary, the priority of the manager task may be
  407. * changed using taskPrioritySet() or by setting the value of the global
  408. * variable `ncr710ScsiTaskPriority' before calling ncr710CtrlCreateScsi2().
  409. * .LP
  410. *
  411. * RETURNS: OK, or ERROR if the parameters are out of range.
  412. *
  413. * SEE ALSO: ncr710CtrlCreateScsi2()
  414. */
  415. STATUS ncr710CtrlInitScsi2
  416.     (
  417.     FAST NCR_710_SCSI_CTRL *pSiop,  /* ptr to SIOP struct */
  418.     int scsiCtrlBusId,     /* SCSI bus ID of this SIOP */
  419.     int scsiPriority     /* task priority when doing SCSI I/O */
  420.     )
  421.     {
  422.     SCSI_CTRL * pScsiCtrl = (SCSI_CTRL *) pSiop;
  423.     /*
  424.      * Validate parameters
  425.      */
  426.     if (pSiop == (SIOP *)NULL)
  427. return (ERROR);
  428.     /*
  429.      * Validate and set bus ID
  430.      */
  431.     if (scsiCtrlBusId < SCSI_MIN_BUS_ID || scsiCtrlBusId > SCSI_MAX_BUS_ID)
  432. return (ERROR);
  433.     
  434.     pScsiCtrl->scsiCtrlBusId = scsiCtrlBusId;
  435.     /*
  436.      * Initialise the SIOP
  437.      */
  438.     ncr710HwInit (pSiop);
  439.     ncr710ScriptStart (pSiop,
  440.        (NCR710_THREAD *) pScsiCtrl->pIdentThread,
  441.        NCR710_SCRIPT_WAIT);
  442.     pSiop->state = NCR710_STATE_PASSIVE;
  443.     return (OK);
  444.     }
  445. /*******************************************************************************
  446. *
  447. * ncr710HwInit - initialize the SIOP chip to a known state
  448. *
  449. * This routine puts the SIOP into a known quiescent state.  Because the value
  450. * of some registers depend upon the hardware implementation of the chip you 
  451. * may have to use ncr710SetHwRegister() to adjust them.
  452. *
  453. * This routine does not touch the bits in registers that are set by 
  454. * the ncr710SetHwRegister() routine.
  455. *
  456. * See the NCR 53C710 Data Manual for fuller details of the registers
  457. * programmed by this routine.
  458. *
  459. * SEE ALSO 
  460. * ncr710SetHwRegister()
  461. *
  462. * NOMANUAL
  463. */
  464. LOCAL void ncr710HwInit
  465.     (
  466.     FAST SIOP *pSiop /* ptr to an SIOP info structure */
  467.     )
  468.     {
  469.     UINT clkPeriod;
  470.     /*
  471.      * Software reset the SIOP
  472.      */
  473.     *pSiop->pIstat = B_SOFTRST;
  474.     *pSiop->pIstat = 0;
  475.     /*
  476.      * Initialise hardware-dependent registers
  477.      */
  478.     ncr710SetHwRegisterScsi2 (pSiop, &pSiop->hwRegs);
  479.     /*
  480.      * DMA mode, control and watchdog timer registers
  481.      *
  482.      * Use manual start and NCR 53C700 compatibility mode.
  483.      * Set clock conversion factor (the clkPeriod has been checked in
  484.      * "ncr710CtrlCreate()") and save async clock period for use by
  485.      * "ncr710XferParamsCvt()".  Disable the watchdog timer.
  486.      */
  487.     *pSiop->pDwt    = 0;
  488.     *pSiop->pDmode |= B_MAN;
  489.     *pSiop->pDcntl |= B_COM;
  490.     clkPeriod = pSiop->clkPeriod;
  491.     
  492.     if (clkPeriod >= NCR710_25MHZ)             /* 16.67 - 25.00 MHz */
  493.      {
  494.         *pSiop->pDcntl |= NCR710_16MHZ_DIV;
  495. pSiop->asyncClkPeriod = clkPeriod;
  496.      }
  497.     else if (clkPeriod >= NCR710_3750MHZ)         /* 25.01 - 37.50 MHz */
  498.      {
  499.         *pSiop->pDcntl |= NCR710_25MHZ_DIV;
  500. pSiop->asyncClkPeriod = clkPeriod * 3 / 2;
  501.      }
  502.     else if (clkPeriod >= NCR710_50MHZ)      /* 37.51 - 50.00 MHz */
  503.      {
  504.         *pSiop->pDcntl |= NCR710_50MHZ_DIV;
  505. pSiop->asyncClkPeriod = clkPeriod * 2;
  506.      }
  507.     else /* (clkPeriod >= NCR710_6666MHZ) */      /* 50.01 - 66.67 MHz */
  508.      {
  509.         *pSiop->pDcntl |= NCR710_66MHZ_DIV;
  510. pSiop->asyncClkPeriod = clkPeriod * 3;
  511.      }
  512.     /*
  513.      * SCSI control registers
  514.      *
  515.      * If disconnect/reconnect is enabled, use full arbitration.
  516.      * Always generate parity; check for parity if required to do so.
  517.      * Set slow cable mode if specified.
  518.      */
  519.     *pSiop->pScntl0 = B_EPG;
  520.     *pSiop->pScntl1 = 0;
  521.     if (pSiop->scsiCtrl.disconnect) 
  522. {
  523.         *pSiop->pScntl0 |= (B_ARB1 | B_ARB0);
  524. *pSiop->pScntl1 |= B_ESR;
  525. }
  526.     if (pSiop->parityCheckEnbl)
  527. *pSiop->pScntl0 |= B_EPC;
  528.      
  529.     if (pSiop->slowCableMode)
  530. *pSiop->pScntl1 |= B_EXC;
  531.     /*
  532.      * Chip test registers
  533.      *
  534.      * Enable active negation (needed for fast SCSI)
  535.      */
  536.     *pSiop->pCtest0 = B_EAN;
  537.     /*
  538.      * Set own SCSI bus ID (checked in "ncr710CtrlInit()")
  539.      */
  540.     *pSiop->pScid = (1 << pSiop->scsiCtrl.scsiCtrlBusId);
  541.     /*
  542.      * Enable relevant SCSI and DMA interrupts (see "ncr710EventTypeGet()")
  543.      *
  544.      * Note: in target mode the phase mismatch interrupt (B_MA) is used to
  545.      * signal assertion of ATN.  Currently we cannot handle this either in
  546.      * this library or in the script.  Therefore, the script automatically
  547.      * disables this interrupt in target mode and enables it (for phase
  548.      * mismatch) in initiator mode.  Also see "ncr710EventTypeGet()".
  549.      */
  550.     *pSiop->pSien = (B_STO | B_SGE | B_UDC | B_RSTE | B_PAR); 
  551.     *pSiop->pDien = (B_BF | B_ABT | B_SIR | B_WTD | B_IID);
  552.     }
  553. /*******************************************************************************
  554. *
  555. * ncr710SetHwRegisterScsi2 - set hardware-dependent registers for the NCR 53C710
  556. *
  557. * This routine sets up the registers used in the hardware
  558. * implementation of the chip.  Typically, this routine is called by 
  559. * the sysScsiInit() routine from the BSP.  
  560. *
  561. * The input parameters are as follows:
  562. * .iP <pSiop> 4
  563. * a pointer to the NCR_710_SCSI_CTRL structure created with
  564. * ncr710CtrlCreateScsi2().
  565. * .iP <pHwRegs>
  566. * a pointer to a NCR710_HW_REGS structure that is filled with the logical
  567. * values 0 or 1 for each bit of each register described below.
  568. *
  569. * This routine includes only the bit registers that can be used to modify 
  570. * the behavior of the chip. The default configuration used during 
  571. * ncr710CtlrCreateScsi2() and ncr710CrtlInitScsi2() is 
  572. * {0,0,0,0,1,0,0,0,0,0,0,0,0,1,0}.
  573. *
  574. *.CS
  575. *    typedef struct
  576. *        {
  577. *        int ctest4Bit7;   /@ Host bus multiplex mode @/
  578. *        int ctest7Bit7;   /@ Disable/enable burst cache capability @/
  579. *        int ctest7Bit6;   /@ Snoop control bit1 @/
  580. *        int ctest7Bit5;   /@ Snoop control bit0 @/
  581. *        int ctest7Bit1;   /@ invert tt1 pin (sync bus host mode only)@/
  582. *        int ctest7Bit0;   /@ enable differential scsi bus capability@/
  583. *        int ctest8Bit0;   /@ Set snoop pins mode @/
  584. *        int dmodeBit7;    /@ Burst Length transfer bit 1 @/
  585. *        int dmodeBit6;    /@ Burst Length transfer bit 0 @/
  586. *        int dmodeBit5;    /@ Function code bit FC2 @/
  587. *        int dmodeBit4;    /@ Function code bit FC1 @/
  588. *        int dmodeBit3;    /@ Program data bit (FC0) @/
  589. *        int dmodeBit1;    /@ user  programmable transfer type @/
  590. *        int dcntlBit5;    /@ Enable Ack pin @/
  591. *        int dcntlBit1;    /@ Enable fast arbitration on host port @/
  592. *        } NCR710_HW_REGS;
  593. *
  594. *.CE
  595. * For a more detailed explanation of the register bits, refer to the
  596. * .I "NCR 53C710 SCSI I/O Processor Programming Guide."
  597. *
  598. * NOTE
  599. * Because this routine writes to the chip registers you cannot use it
  600. * if there is any SCSI bus activity.
  601. *
  602. * RETURNS: OK, or ERROR if any input parameter is NULL.
  603. *
  604. * SEE ALSO: ncr710CtrlCreateScsi2(), 
  605. * .I "NCR 53C710 SCSI I/O Processor Programming Guide"
  606. */
  607. STATUS ncr710SetHwRegisterScsi2
  608.     (
  609.     FAST SIOP    *pSiop, /* pointer to SIOP info */
  610.     NCR710_HW_REGS *pHwRegs     /* pointer to a NCR710_HW_REGS info */
  611.     )
  612.     {
  613.     /* check input parameters */
  614.     if ((pSiop == NULL) || (pHwRegs == NULL))
  615. return (ERROR);
  616.     /* fill the SIOP structure with new parameters */
  617.     bcopy ((char *)pHwRegs, (char *) &pSiop->hwRegs, sizeof(NCR710_HW_REGS));
  618.     /* Set each bit register to the new value */
  619.     
  620.     /* This bit must be set first else the chip will not anwser to a slave 
  621.      * access in some hardware implementations.
  622.      */
  623.     ((pHwRegs->dcntlBit5)  ? (*pSiop->pDcntl   =  B_EA)
  624.    : (*pSiop->pDcntl   =  0));
  625.     ((pHwRegs->ctest4Bit7) ? (*pSiop->pCtest4 |=  B_MUX)
  626.    : (*pSiop->pCtest4 &= ~B_MUX));
  627.     ((pHwRegs->ctest7Bit7) ? (*pSiop->pCtest7 |=  B_CDIS)
  628.    : (*pSiop->pCtest7 &= ~B_CDIS));
  629.     ((pHwRegs->ctest7Bit6) ? (*pSiop->pCtest7 |=  B_SC1)
  630.    : (*pSiop->pCtest7 &= ~B_SC1));
  631.     ((pHwRegs->ctest7Bit5) ? (*pSiop->pCtest7 |=  B_SC0)
  632.    : (*pSiop->pCtest7 &= ~B_SC0));
  633.     ((pHwRegs->ctest7Bit1) ? (*pSiop->pCtest7 |=  B_TT1)
  634.    : (*pSiop->pCtest7 &= ~B_TT1));
  635.     ((pHwRegs->ctest7Bit0) ? (*pSiop->pCtest7 |=  B_DIFF) 
  636.    : (*pSiop->pCtest7 &= ~B_DIFF));
  637.     ((pHwRegs->ctest8Bit0) ? (*pSiop->pCtest8 |=  B_SM)
  638.    : (*pSiop->pCtest8 &= ~B_SM));
  639.     ((pHwRegs->dmodeBit7)  ? (*pSiop->pDmode  |=  B_BL1)
  640.    : (*pSiop->pDmode  &= ~B_BL1));
  641.     ((pHwRegs->dmodeBit6)  ? (*pSiop->pDmode  |=  B_BL0)
  642.    : (*pSiop->pDmode  &= ~B_BL0));
  643.     ((pHwRegs->dmodeBit5)  ? (*pSiop->pDmode  |=  B_FC2)
  644.    : (*pSiop->pDmode  &= ~B_FC2));
  645.     ((pHwRegs->dmodeBit4)  ? (*pSiop->pDmode  |=  B_FC1)
  646.    : (*pSiop->pDmode  &= ~B_FC1));
  647.     ((pHwRegs->dmodeBit3)  ? (*pSiop->pDmode  |=  B_PD)
  648.    : (*pSiop->pDmode  &= ~B_PD));
  649.     ((pHwRegs->dmodeBit1)  ? (*pSiop->pDmode  |=  B_U0TT0)
  650.    : (*pSiop->pDmode  &= ~B_U0TT0));
  651.     ((pHwRegs->dcntlBit1)  ? (*pSiop->pDcntl  |=  B_FA)
  652.    : (*pSiop->pDcntl  &= ~B_FA));
  653.     return (OK);
  654.     }
  655. /*******************************************************************************
  656. *
  657. * ncr710ScsiBusControl - miscellaneous low-level SCSI bus control operations
  658. *
  659. * Currently supports only the SCSI_BUS_RESET operation; other operations are
  660. * not used explicitly by the driver because they are carried out automatically
  661. * by the script program.
  662. *
  663. * NOTE: after the SCSI bus has been reset, the SIOP generates an interrupt
  664. * which causes an NCR710_BUS_RESET event to be sent to the SCSI manager.
  665. * See "ncr710Intr()".
  666. *
  667. * RETURNS: OK, or ERROR if an invalid operation is requested.
  668. *
  669. * NOMANUAL
  670. */
  671. LOCAL STATUS ncr710ScsiBusControl
  672.     (
  673.     SIOP * pSiop,        /* ptr to controller info                   */
  674.     int    operation     /* bitmask for operation(s) to be performed */
  675.     )
  676.     {
  677.     if ((operation & ~SCSI_BUS_RESET) != 0)
  678. return (ERROR);
  679.     if (operation & SCSI_BUS_RESET)
  680. ncr710ScsiBusReset (pSiop);
  681.     return (OK);
  682.     }
  683. /*******************************************************************************
  684. *
  685. * ncr710ScsiBusReset - assert the RST line on the SCSI bus 
  686. *
  687. * Issue a SCSI Bus Reset command to the NCR 710. This should put all devices
  688. * on the SCSI bus in an initial quiescent state.
  689. *
  690. * The bus reset will generate an interrupt which is handled by the normal
  691. * ISR (see "ncr710Intr()").
  692. *
  693. * RETURNS: N/A
  694. *
  695. * NOMANUAL
  696. */
  697. LOCAL void ncr710ScsiBusReset
  698.     (
  699.     FAST SIOP *pSiop /* ptr to SIOP info */
  700.     )
  701.     {
  702.     *pSiop->pScntl1 |=  B_RST;
  703.     taskDelay (2); /* pause for at least 250 us */
  704.     *pSiop->pScntl1 &= ~B_RST;
  705.     }
  706. /*******************************************************************************
  707. *
  708. * ncr710IntrScsi2 - interrupt service routine for the SIOP
  709. *
  710. * Find the event type corresponding to this interrupt, and carry out any
  711. * actions which must be done before the SIOP is re-started.  Determine
  712. * whether or not the SIOP is connected to the bus (depending on the event
  713. * type - see note below).  If not, start a client script if possible or
  714. * else just make the SIOP wait for something else to happen.
  715. *
  716. * Notify the SCSI manager of a controller event.
  717. *
  718. * NOTE:
  719. * The "connected" Boolean tells whether there is a SCSI thread in progress
  720. * which must be continued before any other SCSI activity can occur.  In
  721. * principle, it might seem that reading the appropriate bit in the SIOP's
  722. * SCNTL1 register would be better than inferring the value from the interrupt
  723. * code.
  724. *
  725. * However, the SCNTL1 register may change between the time the script
  726. * completes (generates the interrupt) and the time it is read - for example,
  727. * if the SIOP is reselected immediately after generating a DISCONNECTED
  728. * interrupt.
  729. *
  730. * Because the action taken by the ISR depends critically on what will happen
  731. * in software as a result of the current interrupt, and _not_ on the current
  732. * state of the SIOP hardware, if the hardware "connected" bit were used, the
  733. * above scenario would cause the ISR to fail to re-start a script when in
  734. * fact it should do.  The result would be that the SIOP would forever remain
  735. * IDLE, and the SCSI system would become deadlocked.  (I've seen it happen !)
  736. *
  737. * One disadvantage is that the ISR has to know a little too much about the
  738. * semantics of the interrupt codes - an improvement might be to have a
  739. * distinguishing feature (e.g. bit set) in the interrupt code to indicate
  740. * whether or not to start a new script.
  741. *
  742. * RETURNS: N/A
  743. *
  744. * NOMANUAL
  745. */
  746. void ncr710IntrScsi2 
  747.     (
  748.     SIOP *pSiop
  749.     )
  750.     {
  751.     NCR710_EVENT    event;
  752.     SCSI_EVENT *    pScsiEvent = (SCSI_EVENT *) &event;
  753.     SCSI_CTRL *     pScsiCtrl  = (SCSI_CTRL *)  pSiop;
  754.     NCR710_THREAD * pThread    = (NCR710_THREAD *) pSiop->pHwThread;
  755.     BOOL connected = FALSE;
  756.     BOOL notify    = TRUE;
  757.     int  oldState  = (int) pSiop->state;
  758.     /*
  759.      * Save (partial) SIOP register context in current thread
  760.      */
  761.     pThread->scratch0 = *pSiop->pScratch0;
  762.     pThread->scratch1 = *pSiop->pScratch1;
  763.     pThread->scratch2 = *pSiop->pScratch2;
  764.     pThread->scratch3 = *pSiop->pScratch3;
  765.     pScsiEvent->type = ncr710EventTypeGet (pSiop);
  766.     
  767.     SCSI_INT_DEBUG_MSG ("ncr710Intr: DSA = 0x%08x, DSP = 0x%08x, type = %d.n",
  768. *pSiop->pDsa, *pSiop->pDsp, pScsiEvent->type, 0, 0, 0);
  769.     /*
  770.      *  Synchronise with single-step routine, if enabled.
  771.      */
  772.     if (pSiop->singleStep)
  773.      semGive (pSiop->singleStepSem);
  774.     if (pScsiEvent->type == NCR710_SINGLE_STEP)
  775. return;
  776.     
  777.     /*
  778.      * Handle interrupt according to type.
  779.      */
  780.     switch (pScsiEvent->type)
  781. {
  782. /*
  783.  *  Following cases result from completion of a script run.
  784.  */
  785. case NCR710_CMD_COMPLETE:
  786. case NCR710_DISCONNECTED:
  787.     connected = FALSE;
  788.     break;
  789.      case NCR710_MESSAGE_OUT_SENT:
  790.      case NCR710_MESSAGE_IN_RECVD:
  791. case NCR710_EXT_MESSAGE_SIZE:
  792. case NCR710_NO_MSG_OUT:
  793. case NCR710_SCRIPT_ABORTED:
  794.     connected = TRUE;
  795.     break;
  796. case NCR710_PHASE_MISMATCH:
  797.     event.remCount = ncr710RemainderGet (pSiop, pThread->nBusPhase);
  798.     
  799.     connected = TRUE;
  800.     break;
  801. /*
  802.  *  Following cases are asynchronous conditions, i.e. not resulting
  803.  *  directly from running a script.
  804.  */
  805.      case NCR710_READY:
  806.     connected = FALSE;
  807.     notify    = FALSE;
  808.     break;
  809.     
  810.      case NCR710_SELECTED:
  811.      case NCR710_RESELECTED:
  812.     pScsiEvent->busId = ncr710BusIdGet (pSiop, pThread->nBusIdBits);
  813.     pScsiEvent->nBytesIdent =
  814. (pThread->nHostFlags & FLAGS_IDENTIFY) ? 1 : 0;
  815.     connected = TRUE;
  816.     break;
  817. case NCR710_SCSI_BUS_RESET:
  818.     connected = FALSE;
  819.     break;
  820. /*
  821.  *  Following cases are error conditions (mixture of synchronous
  822.  *  and asynchronous).
  823.  */
  824. case NCR710_SCSI_TIMEOUT:
  825.     connected = FALSE;
  826.     break;
  827. case NCR710_ILLEGAL_PHASE:
  828.     connected = TRUE;
  829.     break;
  830. case NCR710_UNEXPECTED_DISCON:
  831.     connected = FALSE;
  832.     break;
  833.      case NCR710_NO_IDENTIFY:
  834.     logMsg ("ncr710Intr: no valid IDENTIFY message at (re)select.n",
  835.     0, 0, 0, 0, 0, 0);
  836.     connected = TRUE;
  837.     break;
  838.     
  839.      case NCR710_SPURIOUS_CMD:
  840.     logMsg ("ncr710Intr: spurious command interrupt.n",
  841.     0, 0, 0, 0, 0, 0);
  842.     connected = FALSE;
  843.     break;
  844. case NCR710_FATAL_ERROR:
  845.     logMsg ("ncr710Intr: unrecoverable error - re-starting SIOP.n",
  846.     0, 0, 0, 0, 0, 0);
  847.     ncr710HwInit (pSiop);
  848.     connected = FALSE;
  849.     break;
  850. default:
  851.     logMsg ("ncr710Intr: unexpected interrupt status (%d).n",
  852.     pScsiEvent->type, 0, 0, 0, 0, 0);
  853.     break;
  854. }
  855.     /*
  856.      *  Controller is now idle: if possible, make it run a script.
  857.      *
  858.      * If a SCSI thread is suspended and must be processed at task-level,
  859.      * leave the SIOP idle.  It will be re-started by the SCSI manager
  860.      * calling "ncr710Resume()".
  861.      *
  862.      * Otherwise, if there's a new SCSI thread to start (i.e., the SCSI
  863.      * manager has called "ncr710Activate()"), start the appropriate script.
  864.      *
  865.      * Otherwise, start a script which puts the SIOP into passive mode
  866.      * waiting for re-selection, selection or a host command.
  867.      *
  868.      * In all cases, clear any request to start a new thread.  The only
  869.      * tricky case is when there was a request pending and the SIOP is
  870.      * left IDLE.  This should only ever occur when the current event is
  871.      * selection or reselection, in which case the SCSI manager will retry
  872.      * the activation request.  (Also see "ncr710Activate ()".)
  873.      */
  874.     if (connected)
  875. {
  876.      pSiop->state = NCR710_STATE_IDLE;
  877. }
  878.     else if (pSiop->cmdPending)
  879. {
  880. ncr710ScriptStart (pSiop,
  881.    (NCR710_THREAD *) pSiop->pNewThread,
  882.    NCR710_SCRIPT_INIT_START);
  883. pSiop->state = NCR710_STATE_ACTIVE;
  884. }
  885.     else
  886. {
  887. ncr710ScriptStart (pSiop,
  888.    (NCR710_THREAD *) pScsiCtrl->pIdentThread,
  889.    NCR710_SCRIPT_WAIT);
  890. pSiop->state = NCR710_STATE_PASSIVE;
  891. }
  892.     pSiop->cmdPending = FALSE;
  893.     SCSI_INT_DEBUG_MSG ("ncr710Intr: state %d -> %dn",
  894. oldState, pSiop->state, 0, 0, 0, 0);
  895.     /*
  896.      * Send the event to the SCSI manager to be processed.
  897.      */
  898.     if (notify)
  899.      scsiMgrEventNotify ((SCSI_CTRL *) pSiop, pScsiEvent, sizeof (event));
  900.     }
  901. /*******************************************************************************
  902. *
  903. * ncr710BusIdGet - find bus ID of device which selected/reselected the SIOP.
  904. *
  905. * Calculate bus ID of SCSI peer which (re)selected the SIOP; "busIdBits"
  906. * contains a copy of the LCRC register, i.e. an image of the data bits
  907. * asserted on the SCSI bus during (re)selection.  Extract the peer's ID
  908. * by masking out the bit corresponding to our bus ID then shifting until
  909. * we find a bit set.
  910. * RETURNS: bus ID of connected peer device
  911. *
  912. * NOTE: This routine is called at interrupt level.
  913. *
  914. * NOMANUAL
  915. */
  916. LOCAL int ncr710BusIdGet
  917.     (
  918.     SIOP * pSiop, /* ptr to controller info       */
  919.     UINT   busIdBits /* bits corresponding to bus ID */
  920.     )
  921.     {
  922.     UINT8 devBusId;
  923.     busIdBits &= ~(*pSiop->pScid);
  924.     
  925.     for (devBusId = 0; devBusId <= SCSI_MAX_BUS_ID; ++devBusId)
  926. {
  927. if (busIdBits & (1 << devBusId))
  928.     break;
  929. }
  930.     return (devBusId);
  931.     }
  932. /*******************************************************************************
  933. *
  934. * ncr710RemainderGet - get remaining xfer count and clean up after mismatch
  935. *
  936. * Clean up the SIOP's data path and calculate the number of bytes which
  937. * were expected to be, but have not been transferred.
  938. *
  939. * The information transfer phase which halted because of the mismatch has
  940. * been saved as part of the SIOP's register context.
  941. *
  942. * RETURNS: number of bytes not transferred
  943. *
  944. * NOTE: This routine is called at interrupt level.
  945. *
  946. * NOMANUAL
  947. */
  948. LOCAL UINT ncr710RemainderGet
  949.     (
  950.     SIOP *pSiop, /* pointer to controller info     */
  951.     UINT  phase /* phase terminated by mismatch   */
  952.     )
  953.     {
  954.     UINT  remCount;
  955.     UINT8 tmpCount;
  956.     UINT8 countFifo;
  957.     /*
  958.      * Find remaining byte count (may be corrected later).  For a fuller
  959.      * explanation, see Chapter 2 of the NCR 53C710 Data Manual.
  960.      */
  961.     remCount = *pSiop->pDbc & NCR710_COUNT_MASK;
  962.     switch (phase)
  963.         {
  964.         case PHASE_DATA_IN:
  965.         case PHASE_MSG_IN:
  966. case PHASE_STATUS:
  967.     /*
  968.      * Input phases: check for pending byte to store, update
  969.      * buffer if there is one.
  970.      */
  971.             if (*pSiop->pSstat1 & B_ILF)
  972.                 {
  973.                 *((UINT8 *)pSiop->pDnad) = *pSiop->pSidl;
  974.                 remCount--;
  975.                 }
  976.          break;
  977.         case PHASE_DATA_OUT:
  978.         case PHASE_MSG_OUT:
  979. case PHASE_COMMAND:
  980.             /*
  981.      *  Output phases: check for data in fifo and output registers
  982.      * (SODR & SODL), count from DBC minus DFIFO count and 0x7f
  983.      * (see NCR 53C710 Data Manual).
  984.      */
  985.             tmpCount  = (UINT8)(remCount & 0x7f);
  986.             countFifo = *pSiop->pDfifo & 0x7f;
  987.             tmpCount  = (countFifo - tmpCount) & 0x7f;
  988.     
  989.             if (*pSiop->pSstat1 & B_OLF)
  990.                 tmpCount++;
  991.             if (*pSiop->pSstat1 & B_ORF)
  992.                 tmpCount++;
  993.     
  994.             remCount += tmpCount;
  995.     break;
  996.     
  997.         default:
  998.             logMsg ("ncr710RemainderGet: invalid phase.n", 0, 0, 0, 0, 0, 0);
  999.     break;
  1000.         }
  1001.     /*
  1002.      * Clear data FIFOs
  1003.      */
  1004.     *pSiop->pCtest8 |= B_CLF;
  1005.     return (remCount);
  1006.     }
  1007. /******************************************************************************
  1008. *
  1009. * ncr710EventTypeGet - parse SCSI and DMA status registers at interrupt time
  1010. *
  1011. * NOTE
  1012. *   Only status bits which have corresponding interrupts enabled are checked !
  1013. *
  1014. * RETURNS: an interrupt (event) type code
  1015. *
  1016. * NOMANUAL
  1017. */
  1018. LOCAL int ncr710EventTypeGet
  1019.     (
  1020.     SIOP * pSiop
  1021.     )
  1022.     {
  1023.     UINT  intrRegs;
  1024.     UINT8 scsiStatus;
  1025.     UINT8 dmaStatus;
  1026.     /*
  1027.      * Read interrupt status registers
  1028.      *
  1029.      * Note: read as a long word to avoid requirement for a delay when
  1030.      * SCSI status and DMA status registers are read individually.
  1031.      */
  1032.     scsiStatus = dmaStatus = 0;
  1033.     *pSiop->pIstat &= ~B_ABORT;
  1034.     
  1035.     while ((*pSiop->pIstat & (B_SIP | B_DIP)) != 0)
  1036.         {
  1037. #if _BYTE_ORDER==_BIG_ENDIAN
  1038.         intrRegs = *((UINT *)pSiop->pSstat2);
  1039.         scsiStatus |= (UINT8)((intrRegs >> 8) & 0x0FF);
  1040.         dmaStatus  |= (UINT8)( intrRegs       & 0x0FF);
  1041. #else
  1042.         intrRegs = *((UINT *)pSiop->pDstat);
  1043.         scsiStatus |= (UINT8)((intrRegs >> 16) & 0x0FF);
  1044.         dmaStatus  |= (UINT8)((intrRegs >> 24) & 0x0FF);
  1045. #endif
  1046.         }
  1047. SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: SCSI status = 0x%02x, "
  1048.     "DMA status = 0x%02xn",
  1049.          scsiStatus, dmaStatus, 0, 0, 0, 0);
  1050.     /*
  1051.      * Check for fatal errors (first !)
  1052.      */
  1053.     if  (scsiStatus & B_SGE)
  1054.         {
  1055. logMsg ("ncr710: SCSI bus gross error.n", 0, 0, 0, 0, 0, 0);
  1056. return (NCR710_FATAL_ERROR);
  1057.         }
  1058.     if  (scsiStatus & B_PAR)
  1059.         {
  1060. logMsg ("ncr710: parity error.n", 0, 0, 0, 0, 0, 0);
  1061. return (NCR710_FATAL_ERROR);
  1062.         }
  1063.     if (dmaStatus & B_IID)
  1064.         {
  1065. logMsg ("ncr710: illegal instruction (DSP = 0x%08x).n",
  1066. *pSiop->pDsp, 0, 0, 0, 0, 0);
  1067. return (NCR710_FATAL_ERROR);
  1068.         }
  1069.     if (dmaStatus & B_BF)
  1070.         {
  1071. logMsg ("ncr710: bus fault (DSP = 0x%08x).n",
  1072. *pSiop->pDsp, 0, 0, 0, 0, 0);
  1073. return (NCR710_FATAL_ERROR);
  1074.         }
  1075.     if (dmaStatus & B_WTD)
  1076.         {
  1077. logMsg ("ncr710: watchdog timeout (DSP = 0x%08x).n",
  1078. *pSiop->pDsp, 0, 0, 0, 0, 0);
  1079. return (NCR710_FATAL_ERROR);
  1080.         }
  1081.     /*
  1082.      * No fatal errors; try the rest (NB order of tests is important !)
  1083.      */
  1084.     if  (scsiStatus & B_RSTE)
  1085.         {
  1086. SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: SCSI bus reset.n",
  1087.     0, 0, 0, 0, 0, 0);
  1088. *pSiop->pCtest8 |= B_CLF; /* clear FIFOs */
  1089. return (NCR710_SCSI_BUS_RESET);
  1090.         }
  1091.      
  1092.     if  (scsiStatus & B_UDC)
  1093.         {
  1094. SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: unexpected disconnection.n",
  1095.     0, 0, 0, 0, 0, 0);
  1096. *pSiop->pCtest8 |= B_CLF; /* clear FIFOs */
  1097. return (NCR710_UNEXPECTED_DISCON);
  1098.         }
  1099.     if (scsiStatus & B_STO)
  1100. {
  1101.      SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: SCSI bus timeout.n",
  1102.     0, 0, 0, 0, 0, 0);
  1103. *pSiop->pCtest8 |= B_CLF; /* clear FIFOs */
  1104. return (NCR710_SCSI_TIMEOUT);
  1105. }
  1106.     if (scsiStatus & B_MA)
  1107.         {
  1108. /*
  1109.  * workaround for problem with ATN when selected
  1110.  * by ncr710 (negates and then briefly re-asserts
  1111.  * ATN during REQ/ACK cycle, causing an ATN
  1112.  * interrupt even though ATN ends up negated).
  1113.  *
  1114.  * The "phase mismatch" interrupt is used to indicate assertion of
  1115.  * ATN in target mode.  This interrupt should have been disabled
  1116.  * by the script when in target mode, because the current code does
  1117.  * not know how to handle it.
  1118.  */
  1119. if (*pSiop->pScntl0 & B_TRG)
  1120.     {
  1121.     if (*pSiop->pSien & B_MA)
  1122. {
  1123. logMsg ("ncr710EventTypeGet: enabled ATN interrupt!n",
  1124. 0, 0, 0, 0, 0, 0);
  1125. return (NCR710_FATAL_ERROR);
  1126. }
  1127.     }
  1128. else
  1129.     {
  1130.     SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: phase mismatch.n",
  1131.     0, 0, 0, 0, 0, 0);
  1132.     return (NCR710_PHASE_MISMATCH);
  1133.     }
  1134.         }
  1135.     
  1136.     if (dmaStatus & B_ABT)
  1137.         {
  1138. SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: script aborted.n",
  1139.          0, 0, 0, 0, 0, 0);
  1140. return (NCR710_SCRIPT_ABORTED);
  1141.         }
  1142.     if (dmaStatus & B_SIR)
  1143. {
  1144. SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: script completed.n",
  1145.     0, 0, 0, 0, 0, 0);
  1146. return (*pSiop->pDsps);
  1147.         }
  1148.     if (dmaStatus & B_SSI)
  1149. {
  1150. SCSI_INT_DEBUG_MSG ("ncr710EventTypeGet: single-step.n",
  1151.     0, 0, 0, 0, 0, 0);
  1152. return (NCR710_SINGLE_STEP);
  1153. }
  1154.     /*
  1155.      * No (expected) reason for the interrupt !
  1156.      */
  1157.     logMsg ("ncr710EventTypeGet: spurious interrupt !n", 0, 0, 0, 0, 0, 0);
  1158.     
  1159.     return (NCR710_FATAL_ERROR);
  1160.     }
  1161. /*******************************************************************************
  1162. * ncr710ThreadActivate - activate a SCSI connection for an initiator thread
  1163. *
  1164. * Set whatever thread/controller state variables need to be set.  Ensure that
  1165. * all buffers used by the thread are coherent with the contents of the
  1166. * system caches (if any).
  1167. *
  1168. * Set transfer parameters for the thread based on what its target device
  1169. * last negotiated.
  1170. *
  1171. * Update the thread context (including shared memory area) and note that
  1172. * there is a new client script to be activated (see "ncr710Activate()").
  1173. *
  1174. * Set the thread's state to ESTABLISHED.  This is strictly a bit premature,
  1175. * but there is no distinction as far as this driver is concerned between a
  1176. * thread which is connecting and one which has connected (i.e., the script
  1177. * just runs to completion and we have to examine its exit status to determine
  1178. * how far through the process the thread got).
  1179. *
  1180. * Do not wait for the script to be activated.  Completion of the script will
  1181. * be signalled by an event which is handled by "ncr710Event()".
  1182. *
  1183. * RETURNS: OK or ERROR
  1184. *
  1185. * NOMANUAL
  1186. */
  1187. LOCAL STATUS ncr710ThreadActivate
  1188.     (
  1189.     SIOP *          pSiop, /* ptr to controller info */
  1190.     NCR710_THREAD * pThread /* ptr to thread info     */
  1191.     )
  1192.     {
  1193.     SCSI_CTRL *   pScsiCtrl   = (SCSI_CTRL *)   pSiop;
  1194.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1195.     SCSI_TARGET * pScsiTarget = pScsiThread->pScsiTarget;
  1196.     
  1197.     SCSI_DEBUG_MSG ("ncr710ThreadActivate: thread 0x%08x: activatingn",
  1198.     (int) pThread, 0, 0, 0, 0, 0);
  1199.     scsiCacheSynchronize (pScsiThread, SCSI_CACHE_PRE_COMMAND);
  1200.     /*
  1201.      * Reset controller state variables: set sync xfer parameters
  1202.      */
  1203.     pScsiCtrl->msgOutState = SCSI_MSG_OUT_NONE;
  1204.     pScsiCtrl->msgInState  = SCSI_MSG_IN_NONE;
  1205.     
  1206.     scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_NEW_THREAD);
  1207.     if (ncr710ThreadParamsSet (pThread, pScsiTarget->xferOffset,
  1208.               pScsiTarget->xferPeriod) != OK)
  1209. {
  1210. SCSI_ERROR_MSG ("ncr710ThreadActivate: failed to set thread params.n",
  1211. 0, 0, 0, 0, 0, 0);
  1212. return (ERROR);
  1213. }
  1214.     /*
  1215.      *  Concatenate the ident message with a pending 'normal' message out,
  1216.      *  if possible.  This allows the script to send the first message out
  1217.      *  within the same MSG OUT phase as the IDENTIFY message - needed on
  1218.      *  some target systems (e.g. DG Clariion RAID) to avoid the message
  1219.      *  being rejected(!).
  1220.      */
  1221.  
  1222.     pSiop->identMsgLength = 0;
  1223.  
  1224.     bcopy (pScsiThread->identMsg,
  1225.            pSiop->identMsg,
  1226.            pScsiThread->identMsgLength);
  1227.  
  1228.     pSiop->identMsgLength += pScsiThread->identMsgLength;
  1229.  
  1230.     if (pScsiCtrl->msgOutState == SCSI_MSG_OUT_PENDING)
  1231.         {
  1232.         bcopy (pScsiCtrl->msgOutBuf,
  1233.                pSiop->identMsg + pSiop->identMsgLength,
  1234.                pScsiCtrl->msgOutLength);
  1235.  
  1236.         pSiop->identMsgLength += pScsiCtrl->msgOutLength;
  1237.         }
  1238.     /*
  1239.      * Update thread context; activate the thread
  1240.      */
  1241.     ncr710ThreadUpdate (pThread);
  1242.     
  1243.     if (ncr710Activate (pSiop, pThread) != OK)
  1244. {
  1245. SCSI_ERROR_MSG ("ncr710ThreadActivate: failed to activate thread.n",
  1246.         0, 0, 0, 0, 0, 0);
  1247. return (ERROR);
  1248. }
  1249.     pScsiCtrl->pThread = pScsiThread;
  1250.     ncr710ThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED);
  1251.     
  1252.     return (OK);
  1253.     }
  1254. /*******************************************************************************
  1255. * ncr710ThreadAbort - abort a thread
  1256. *
  1257. * If the thread is not currently connected, do nothing and return FALSE to
  1258. * indicate that the SCSI manager should abort the thread.
  1259. *
  1260. * Otherwise (the thread is active onthe controller), build an ABORT or
  1261. * ABORT TAG message which will (eventually) be sent, causing the taget to
  1262. * disconnect.  Abort the current script run so that this message can be
  1263. * sent.  Set the state of the thread accordingly, and return TRUE to
  1264. * indicate that the controller driver will handle the abort process.
  1265. *
  1266. * RETURNS: TRUE if the thread is being aborted by this driver (i.e. it is
  1267. * currently active on the controller, else FALSE.
  1268. *
  1269. * NOMANUAL
  1270. */
  1271. LOCAL BOOL ncr710ThreadAbort
  1272.     (
  1273.     SIOP *          pSiop, /* ptr to controller info */
  1274.     NCR710_THREAD * pThread /* ptr to thread info     */
  1275.     )
  1276.     {
  1277.     BOOL          tagged;
  1278.     SCSI_CTRL *   pScsiCtrl   = (SCSI_CTRL *)   pSiop;
  1279.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1280.     SCSI_DEBUG_MSG ("ncr710ThreadAbort: thread 0x%08x (state = %d) abortingn",
  1281.     (int) pThread, pScsiThread->state, 0, 0, 0, 0);
  1282.     if (pScsiThread != pScsiCtrl->pThread)
  1283. return (FALSE);
  1284.     
  1285.     switch (pScsiThread->state)
  1286. {
  1287. case SCSI_THREAD_INACTIVE:
  1288. case SCSI_THREAD_WAITING:
  1289. case SCSI_THREAD_DISCONNECTED:
  1290.     return (FALSE);
  1291.     break;
  1292. default:
  1293.     /*
  1294.      * Build an ABORT (or ABORT TAG) message.  When this has been
  1295.      * sent, the target should disconnect.  Mark the thread aborted
  1296.      * and continue until disconnection.
  1297.      */
  1298.     tagged = (pScsiThread->tagNumber != NONE);
  1299.     pScsiCtrl->msgOutBuf[0] = tagged ? SCSI_MSG_ABORT_TAG
  1300.                     : SCSI_MSG_ABORT;
  1301.     pScsiCtrl->msgOutLength = 1;
  1302.     pScsiCtrl->msgOutState  = SCSI_MSG_OUT_PENDING;
  1303.     ncr710Abort (pSiop);
  1304.     
  1305.          ncr710ThreadStateSet (pThread, SCSI_THREAD_ABORTING);
  1306.     break;
  1307. }
  1308.     return (TRUE);
  1309.     }
  1310. /*******************************************************************************
  1311. * ncr710Event - NCR 53C710 SCSI controller event processing routine
  1312. *
  1313. * Parse the event type and act accordingly.  Controller-level events are
  1314. * handled within this function, and the event is then passed to the current
  1315. * thread (if any) for thread-level processing.
  1316. *
  1317. * Note the special case when (re)selection occurs: if there is a current
  1318. * thread when the event occurs, it receives the event (and is assumed to
  1319. * defer itself) before the identification thread is made current.  The
  1320. * event is then forwarded to the identification thread.
  1321. *
  1322. * RETURNS: N/A
  1323. */
  1324. LOCAL void ncr710Event
  1325.     (
  1326.     SIOP *         pSiop,
  1327.     NCR710_EVENT * pEvent
  1328.     )
  1329.     {
  1330.     SCSI_CTRL  *    pScsiCtrl  = (SCSI_CTRL *)  pSiop;
  1331.     SCSI_EVENT *    pScsiEvent = (SCSI_EVENT *) pEvent;
  1332.     NCR710_THREAD * pThread    = (NCR710_THREAD *) pScsiCtrl->pThread;
  1333.     
  1334.     SCSI_DEBUG_MSG ("ncr710Event: received event %d (thread = 0x%08x)n",
  1335.     pScsiEvent->type, (int) pThread, 0, 0, 0, 0);
  1336.     /*
  1337.      * Do controller-level event processing
  1338.      */
  1339.     switch (pScsiEvent->type)
  1340. {
  1341. case NCR710_SELECTED:
  1342. case NCR710_RESELECTED:
  1343.     /*
  1344.      * Forward event to current thread, if any (it should defer)
  1345.      * then install a reserved thread for identification purposes.
  1346.      */
  1347.          if (pThread != 0)
  1348.      ncr710ThreadEvent (pThread, pEvent);
  1349.          pScsiCtrl->peerBusId = pScsiEvent->busId;
  1350.          pScsiCtrl->pThread = pScsiCtrl->pIdentThread;
  1351.     
  1352.     pScsiCtrl->pThread->role = (pScsiEvent->type == NCR710_SELECTED)
  1353.                ? SCSI_ROLE_IDENT_TARG
  1354.      : SCSI_ROLE_IDENT_INIT;
  1355.     pThread = (NCR710_THREAD *) pScsiCtrl->pThread;
  1356.     scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_CONNECTED);
  1357.     break;
  1358. case NCR710_DISCONNECTED:
  1359. case NCR710_CMD_COMPLETE:
  1360. case NCR710_UNEXPECTED_DISCON:
  1361. case NCR710_SCSI_TIMEOUT:
  1362.          pScsiCtrl->peerBusId = NONE;
  1363.          pScsiCtrl->pThread   = 0;
  1364.     scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_DISCONNECTED);
  1365.     
  1366.          /* assert (pThread != 0); */
  1367.     break;
  1368. case NCR710_SCSI_BUS_RESET:
  1369.          pScsiCtrl->peerBusId = NONE;
  1370.          pScsiCtrl->pThread   = 0;
  1371.          scsiMgrBusReset (pScsiCtrl);
  1372.     break;
  1373. default:
  1374.     /*
  1375.      * Any other event type is assumed to be thread-specific.
  1376.      * The thread event handler will report an error if it's
  1377.      * not a valid type.
  1378.      */
  1379.     if (pThread == 0)
  1380. {
  1381.      logMsg ("ncr710Event: invalid event type (%d)n",
  1382.      pScsiEvent->type, 0, 0, 0, 0, 0);
  1383. }
  1384.     break;
  1385. }
  1386.     /*
  1387.      * If there's a thread on the controller, forward the event to it
  1388.      */
  1389.     if (pThread != 0)
  1390. ncr710ThreadEvent (pThread, pEvent);
  1391.     }
  1392.     
  1393. /*******************************************************************************
  1394. * ncr710ThreadEvent - NCR 53C710 thread event processing routine
  1395. *
  1396. * Forward the event to the proper handler for the thread's current role.
  1397. *
  1398. * If the thread is still active, update the thread context (including
  1399. * shared memory area) and resume the thread.
  1400. *
  1401. * RETURNS: N/A
  1402. *
  1403. * NOMANUAL
  1404. */
  1405. LOCAL void ncr710ThreadEvent
  1406.     (
  1407.     NCR710_THREAD * pThread,
  1408.     NCR710_EVENT *  pEvent
  1409.     )
  1410.     {
  1411.     SCSI_EVENT *  pScsiEvent  = (SCSI_EVENT *)  pEvent;
  1412.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1413.     SIOP *        pSiop       = (SIOP *)        pScsiThread->pScsiCtrl;
  1414.     NCR710_SCRIPT_ENTRY entryPt;
  1415.     
  1416.     SCSI_DEBUG_MSG ("ncr710ThreadEvent: thread 0x%08x: received event %dn",
  1417.     (int) pThread, pScsiEvent->type, 0, 0, 0, 0);
  1418.     switch (pScsiThread->role)
  1419. {
  1420. case SCSI_ROLE_INITIATOR:
  1421.     ncr710InitEvent (pThread, pEvent);
  1422.     entryPt = NCR710_SCRIPT_INIT_CONTINUE;
  1423.     break;
  1424.     
  1425. case SCSI_ROLE_IDENT_INIT:
  1426.     ncr710InitIdentEvent (pThread, pEvent);
  1427.     entryPt = NCR710_SCRIPT_INIT_CONTINUE;
  1428.     break;
  1429. case SCSI_ROLE_IDENT_TARG:
  1430.     ncr710TargIdentEvent (pThread, pEvent);
  1431.     entryPt = NCR710_SCRIPT_TGT_DISCONNECT;
  1432.     break;
  1433.     
  1434. case SCSI_ROLE_TARGET:
  1435. default:
  1436.     logMsg ("ncr710ThreadEvent: thread 0x%08x: invalid role (%d)n",
  1437.     (int) pThread, pScsiThread->role, 0, 0, 0, 0);
  1438.     entryPt = NCR710_SCRIPT_TGT_DISCONNECT;
  1439.     break;
  1440. }
  1441.     /*
  1442.      * Resume thread iff it is still connected
  1443.      */
  1444.     switch (pScsiThread->state)
  1445. {
  1446. case SCSI_THREAD_INACTIVE:
  1447. case SCSI_THREAD_WAITING:
  1448. case SCSI_THREAD_DISCONNECTED:
  1449.     break;
  1450. default:
  1451.          ncr710ThreadUpdate (pThread);
  1452.     if (ncr710Resume (pSiop, pThread, entryPt) != OK)
  1453.      {
  1454.      SCSI_ERROR_MSG ("ncr710ThreadEvent: failed to resume threadn",
  1455.      0, 0, 0, 0, 0, 0);
  1456. ncr710ThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1457.      }
  1458.     break;
  1459. }
  1460.     }
  1461. /*******************************************************************************
  1462. * ncr710InitEvent - NCR 53C710 initiator thread event processing routine
  1463. *
  1464. * Parse the event type and handle it accordingly.  This may result in state
  1465. * changes for the thread, state variables being updated, etc.
  1466. *
  1467. * RETURNS: N/A
  1468. *
  1469. * NOMANUAL
  1470. */
  1471. LOCAL void ncr710InitEvent
  1472.     (
  1473.     NCR710_THREAD * pThread,
  1474.     NCR710_EVENT *  pEvent
  1475.     )
  1476.     {
  1477.     SCSI_EVENT *  pScsiEvent  = (SCSI_EVENT *)  pEvent;
  1478.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1479.     SCSI_CTRL *   pScsiCtrl   = pScsiThread->pScsiCtrl;
  1480.     /*
  1481.      *  Update controller msg in/out state after script completes
  1482.      */
  1483.     pScsiCtrl->msgOutState = pThread->nMsgOutState;
  1484.     pScsiCtrl->msgInState  = pThread->nMsgInState;
  1485.     
  1486.     /*
  1487.      * Parse script exit status; handle as necessary
  1488.      */
  1489.     switch (pScsiEvent->type)
  1490. {
  1491. case NCR710_DISCONNECTED:
  1492.          SCSI_DEBUG_MSG ("DISCONNECT message inn", 0, 0, 0, 0, 0, 0);
  1493.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_DISCONNECTED);
  1494.     ncr710ThreadStateSet (pThread, SCSI_THREAD_DISCONNECTED);
  1495.     break;
  1496. case NCR710_CMD_COMPLETE:
  1497.     SCSI_DEBUG_MSG ("COMMAND COMPLETE message inn", 0, 0, 0, 0, 0, 0);
  1498.     ncr710ThreadComplete (pThread);
  1499.     break;
  1500. case NCR710_SELECTED:
  1501. case NCR710_RESELECTED:
  1502.          SCSI_DEBUG_MSG ("ncr710InitEvent: thread 0x%08x: (re)selection.n",
  1503.          (int) pThread, 0, 0, 0, 0, 0);
  1504.     ncr710ThreadDefer (pThread);
  1505.     break;
  1506.      case NCR710_MESSAGE_OUT_SENT:
  1507.     (void) scsiMsgOutComplete (pScsiCtrl, pScsiThread);
  1508.     break;
  1509.     
  1510. case NCR710_MESSAGE_IN_RECVD:
  1511.     (void) scsiMsgInComplete (pScsiCtrl, pScsiThread);
  1512.     break;
  1513.     
  1514. case NCR710_NO_MSG_OUT:
  1515.     /*
  1516.      * The target has requested a message out when there is none
  1517.      * pending.  Set up a NO-OP message to be sent when thread is
  1518.      *  resumed.
  1519.      *
  1520.      * The script could handle this on its own, but arguably the
  1521.      * host should be involved as it may represent an error.
  1522.      */
  1523.     pScsiCtrl->msgOutBuf[0] = SCSI_MSG_NO_OP;
  1524.     pScsiCtrl->msgOutLength = 1;
  1525.     pScsiCtrl->msgOutState  = SCSI_MSG_OUT_NONE;    /* sic */
  1526.     break;
  1527.     
  1528. case NCR710_EXT_MESSAGE_SIZE:
  1529.     /*
  1530.      *  The SIOP has just read the length byte for an extended
  1531.      *  message in.  The shared memory area is updated with the
  1532.      * appropriate length just before the thread is resumed (see
  1533.      * "ncr710ThreadUpdate()".
  1534.      */
  1535.     /* assert (pScsiCtrl->msgInState == SCSI_MSG_IN_EXT_MSG_DATA); */
  1536.     break;
  1537.     
  1538. case NCR710_PHASE_MISMATCH:
  1539.     if (ncr710PhaseMismatch (pThread,
  1540.      pThread->nBusPhase,
  1541.      pEvent->remCount) != OK)
  1542. {
  1543. ncr710ThreadFail (pThread, errno);
  1544. }
  1545.     break;
  1546. case NCR710_SCSI_TIMEOUT:
  1547.     SCSI_ERROR_MSG ("ncr710InitEvent: thread 0x%08x: select timeout.n",
  1548.     (int) pThread, 0, 0, 0, 0, 0);
  1549.     ncr710ThreadFail (pThread, S_scsiLib_SELECT_TIMEOUT);
  1550.     break;
  1551. case NCR710_SCRIPT_ABORTED:
  1552.     SCSI_DEBUG_MSG ("ncr710InitEvent: thread 0x%08x: abortedn",
  1553.     (int) pThread, 0, 0, 0, 0, 0);
  1554.     break;
  1555.     
  1556. case NCR710_SCSI_BUS_RESET:
  1557.          SCSI_DEBUG_MSG ("ncr710InitEvent: thread 0x%08x: bus resetn",
  1558.          (int) pThread, 0, 0, 0, 0, 0);
  1559.     /*
  1560.      * Do not try to resume this thread.  SCSI mgr will tidy up.
  1561.      */
  1562.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1563.     break;
  1564. case NCR710_UNEXPECTED_DISCON:
  1565.     /* not really unexpected after an abort message ... */
  1566.          SCSI_ERROR_MSG ("ncr710InitEvent: thread 0x%08x: "
  1567.          "unexpected disconnectionn",
  1568.          (int) pThread, 0, 0, 0, 0, 0);
  1569.     ncr710ThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1570.     break;
  1571.     
  1572. case NCR710_ILLEGAL_PHASE:
  1573.     SCSI_ERROR_MSG ("ncr710InitEvent: thread 0x%08x: "
  1574.     "illegal phase requested.n",
  1575.     (int) pThread, 0, 0, 0, 0, 0);
  1576.     ncr710ThreadFail (pThread, S_scsiLib_INVALID_PHASE);
  1577.     break;
  1578. default:
  1579.     logMsg ("ncr710InitEvent: invalid event type (%d)n",
  1580.     pScsiEvent->type, 0, 0, 0, 0, 0);
  1581.     break;
  1582. }
  1583.     }
  1584.     
  1585. /*******************************************************************************
  1586. * ncr710InitIdentEvent - NCR 53C710 identification thread event processing routine
  1587. *
  1588. * Parse the event type and handle it accordingly.  This may result in state
  1589. * changes for the thread, state variables being updated, etc.
  1590. *
  1591. * RETURNS: N/A
  1592. *
  1593. * NOMANUAL
  1594. */
  1595. LOCAL void ncr710InitIdentEvent
  1596.     (
  1597.     NCR710_THREAD * pThread,
  1598.     NCR710_EVENT *  pEvent
  1599.     )
  1600.     {
  1601.     SCSI_EVENT *  pScsiEvent  = (SCSI_EVENT *)  pEvent;
  1602.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1603.     SCSI_CTRL *   pScsiCtrl   = pScsiThread->pScsiCtrl;
  1604.     /*
  1605.      *  Update controller msg in/out state after script completes
  1606.      */
  1607.     pScsiCtrl->msgOutState = pThread->nMsgOutState;
  1608.     pScsiCtrl->msgInState  = pThread->nMsgInState;
  1609.     
  1610.     /*
  1611.      * Parse script exit status; handle as necessary
  1612.      */
  1613.     switch (pScsiEvent->type)
  1614. {
  1615. case NCR710_RESELECTED:
  1616.          pScsiThread->nBytesIdent = pScsiEvent->nBytesIdent;
  1617.     bcopy ((char *) pScsiCtrl->identBuf,
  1618.    (char *) pScsiThread->identMsg,
  1619.    pScsiThread->nBytesIdent);
  1620.     ncr710ThreadStateSet (pThread, SCSI_THREAD_IDENT_IN);
  1621.          ncr710IdentInContinue (pThread);
  1622.     break;
  1623. case NCR710_MESSAGE_OUT_SENT:
  1624.     /*
  1625.      * This will be after we have sent an "ABORT (TAG)" msg.
  1626.      * The target will disconnect any time; it may have already
  1627.      * done so, in which case we won't be able to resume the
  1628.      * thread, but no matter.
  1629.      */
  1630.     break;
  1631. case NCR710_MESSAGE_IN_RECVD:
  1632.     /*
  1633.      *  Continue parsing the identification message.  It
  1634.      *  should by now be complete.
  1635.      */
  1636.     /*
  1637.      * First byte of ident msg is already in ident buffer.
  1638.      * Remaining bytes are in the normal message input buffer.
  1639.      * This should always be a two-byte message (viz. QUEUE TAG);
  1640.      * it would be nicer if there were a way to avoid hard-coding
  1641.      * this.
  1642.      */
  1643.     bcopy ((char *) pScsiCtrl->msgInBuf,
  1644.    (char *) pScsiThread->identMsg + pScsiThread->nBytesIdent,
  1645.    2);
  1646.     
  1647.          pScsiThread->nBytesIdent += 2;
  1648.          ncr710IdentInContinue (pThread);
  1649.     break;
  1650. case NCR710_SCRIPT_ABORTED:
  1651.     SCSI_DEBUG_MSG ("ncr710InitIdentEvent: thread 0x%08x: abortedn",
  1652.     (int) pThread, 0, 0, 0, 0, 0);
  1653.     break;
  1654.         case NCR710_DISCONNECTED:
  1655.     SCSI_DEBUG_MSG ("ncr710InitIdentEvent: thread 0x%08x: disconnectedn",
  1656.     (int) pThread, 0, 0, 0, 0, 0);
  1657.     ncr710ThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1658.     break;
  1659.     
  1660. case NCR710_SCSI_BUS_RESET:
  1661.          SCSI_DEBUG_MSG ("ncr710InitIdentEvent: thread 0x%08x: bus resetn",
  1662.          (int) pThread, 0, 0, 0, 0, 0);
  1663.     
  1664.     /*
  1665.      * Do not try to resume this thread.  SCSI mgr will tidy up.
  1666.      */
  1667.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1668.     break;
  1669. case NCR710_UNEXPECTED_DISCON:
  1670.     /* not really unexpected after an abort message ... */
  1671.          SCSI_ERROR_MSG ("ncr710InitIdentEvent: thread 0x%08x: "
  1672.          "unexpected disconnectionn",
  1673.          (int) pThread, 0, 0, 0, 0, 0);
  1674.     ncr710ThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1675.     break;
  1676.     
  1677. case NCR710_ILLEGAL_PHASE:
  1678.     SCSI_ERROR_MSG ("ncr710InitIdentEvent: thread 0x%08x: "
  1679.     "illegal phase requested.n",
  1680.     (int) pThread, 0, 0, 0, 0, 0);
  1681.     
  1682.     ncr710ThreadFail (pThread, S_scsiLib_INVALID_PHASE);
  1683.     break;
  1684. default:
  1685.     logMsg ("ncr710InitIdentEvent: invalid event type (%d)n",
  1686.     pScsiEvent->type, 0, 0, 0, 0, 0);
  1687.     break;
  1688. }
  1689.     }
  1690.     
  1691. /*******************************************************************************
  1692. * ncr710TargIdentEvent - NCR 53C710 identification thread event processing routine
  1693. *
  1694. * Parse the event type and handle it accordingly.  This may result in state
  1695. * changes for the thread, state variables being updated, etc.
  1696. *
  1697. * RETURNS: N/A
  1698. *
  1699. * NOMANUAL
  1700. */
  1701. LOCAL void ncr710TargIdentEvent
  1702.     (
  1703.     NCR710_THREAD * pThread,
  1704.     NCR710_EVENT *  pEvent
  1705.     )
  1706.     {
  1707.     SCSI_EVENT *  pScsiEvent  = (SCSI_EVENT *)  pEvent;
  1708.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1709.     SCSI_CTRL *   pScsiCtrl   = pScsiThread->pScsiCtrl;
  1710.     /*
  1711.      *  Update controller msg in/out state after script completes
  1712.      */
  1713.     pScsiCtrl->msgOutState = pThread->nMsgOutState;
  1714.     pScsiCtrl->msgInState  = pThread->nMsgInState;
  1715.     
  1716.     /*
  1717.      * Parse script exit status; handle as necessary
  1718.      */
  1719.     switch (pScsiEvent->type)
  1720. {
  1721. case NCR710_SELECTED:
  1722.          pScsiThread->nBytesIdent = pScsiEvent->nBytesIdent;
  1723.     bcopy ((char *) pScsiCtrl->identBuf,
  1724.    (char *) pScsiThread->identMsg,
  1725.    pScsiThread->nBytesIdent);
  1726.     ncr710ThreadStateSet (pThread, SCSI_THREAD_IDENT_IN);
  1727.     break;
  1728.     
  1729.         case NCR710_DISCONNECTED:
  1730.     SCSI_DEBUG_MSG ("ncr710TargIdentEvent: thread 0x%08x: disconnectedn",
  1731.     (int) pThread, 0, 0, 0, 0, 0);
  1732.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1733.     break;
  1734.     
  1735. case NCR710_SCSI_BUS_RESET:
  1736.          SCSI_DEBUG_MSG ("ncr710TargIdentEvent: thread 0x%08x: bus resetn",
  1737.          (int) pThread, 0, 0, 0, 0, 0);
  1738.     
  1739.     /*
  1740.      * Do not try to resume this thread.  SCSI mgr will tidy up.
  1741.      */
  1742.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1743.     break;
  1744. case NCR710_UNEXPECTED_DISCON:
  1745.          SCSI_ERROR_MSG ("ncr710TargIdentEvent: thread 0x%08x: "
  1746.          "unexpected disconnectionn",
  1747.          (int) pThread, 0, 0, 0, 0, 0);
  1748.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1749.     break;
  1750.     
  1751. default:
  1752.     logMsg ("ncr710TargIdentEvent: invalid event type (%d)n",
  1753.     pScsiEvent->type, 0, 0, 0, 0, 0);
  1754.     break;
  1755. }
  1756.     }
  1757.     
  1758. /*******************************************************************************
  1759. *
  1760. * ncr710PhaseMismatch - recover from a SCSI bus phase mismatch
  1761. *
  1762. * This routine does whatever is required to keep the pointers, counts, etc.
  1763. * used by task-level software in step when a SCSI phase mismatch occurs.
  1764. *
  1765. * The interrupt-level mismatch processing has stored the phase of the
  1766. * information transfer before the mismatch, and the number of bytes
  1767. * remaining to be transferred.  See "ncr710RemainderGet()".
  1768. *
  1769. * Note that the only phase mismatches supported at this level are:
  1770. *
  1771. * 1) during data in/out phases - presumably because the target has
  1772. *    transferred as much data as it intends to before sending a message
  1773. *    in (typically DISCONNECT or COMMAND COMPLETE).  Recovery consists
  1774. *    of updating the active data pointer/count according to the number
  1775. *    of data bytes actually transferred before the mismatch.
  1776. *
  1777. * 2) during a message out phase - presumably because the target does not
  1778. *    understand our outgoing message and is sending a MESSAGE REJECT
  1779. *    message, or similar.  No recovery is needed here - it's all done
  1780. *    when the MESSAGE REJECT message has been received (see routine
  1781. *    "scsiMsgOutReject()").
  1782. *
  1783. * 3) during a message in phase - presumably because we have asserted ATN
  1784. *    to abort or reject an incoming message.  No recovery is needed here -
  1785. *    it's done by the thread management code, which should have enough
  1786. *    state information to know what to do.
  1787. *
  1788. * RETURNS: OK, or ERROR for an unsupported or invalid phase
  1789. *
  1790. * NOMANUAL
  1791. */
  1792. LOCAL STATUS ncr710PhaseMismatch
  1793.     (
  1794.     NCR710_THREAD  * pThread, /* ptr to thread info           */
  1795.     int              phase, /* bus phase before mismatch    */
  1796.     UINT             remCount /* # bytes not yet transferred  */
  1797.     )
  1798.     {
  1799.     SCSI_THREAD *pScsiThread = (SCSI_THREAD *) pThread;
  1800.     UINT xferCount;
  1801.     
  1802.     switch (phase)
  1803. {
  1804. case SCSI_DATA_IN_PHASE:
  1805. case SCSI_DATA_OUT_PHASE:
  1806.     xferCount = pThread->pShMem->data.size - remCount;
  1807.     
  1808.     pScsiThread->activeDataAddress += xferCount;
  1809.     pScsiThread->activeDataLength  -= xferCount;
  1810.     
  1811.     SCSI_DEBUG_MSG ("ncr710PhaseMismatch: data transfer aborted "
  1812.     "(%d of %d bytes transferred).n",
  1813.     xferCount, pThread->pShMem->data.size, 0, 0, 0, 0);
  1814.     break;
  1815.     
  1816. case SCSI_MSG_OUT_PHASE:
  1817.     SCSI_DEBUG_MSG("ncr710PhaseMismatch: message out aborted "
  1818.    "(%d of %d bytes sent).n",
  1819.    pScsiThread->pScsiCtrl->msgOutLength,
  1820.    pScsiThread->pScsiCtrl->msgOutLength - remCount,
  1821.    0, 0, 0, 0);
  1822.             /* Abort the Out message */
  1823.             pScsiThread->pScsiCtrl->msgOutLength = 0;
  1824.             pScsiThread->pScsiCtrl->msgOutState = SCSI_MSG_OUT_NONE;
  1825.             ncr710ResetATN(pScsiThread->pScsiCtrl);
  1826.     break;
  1827.     
  1828. case SCSI_MSG_IN_PHASE:
  1829.     SCSI_DEBUG_MSG("ncr710PhaseMismatch: message in aborted "
  1830.    "(%d bytes received).n",
  1831.    pScsiThread->pScsiCtrl->msgInLength,
  1832.    0, 0, 0, 0, 0);
  1833.     break;
  1834. case SCSI_COMMAND_PHASE:
  1835. case SCSI_STATUS_PHASE:
  1836.     SCSI_ERROR_MSG ("ncr710PhaseMismatch: unsupported phase (%d).n",
  1837.     phase, 0, 0, 0, 0, 0);
  1838.     return (ERROR);
  1839.     
  1840. default:
  1841.     logMsg ("ncr710PhaseMismatch: invalid phase (%d).n",
  1842.     phase, 0, 0, 0, 0, 0);
  1843.     return (ERROR);
  1844.         }
  1845.     return (OK);
  1846.     }
  1847. /*******************************************************************************
  1848. *
  1849. * ncr710IdentInContinue - continue incoming identification
  1850. *
  1851. * Parse the message built up so far.  If it is not yet complete, do nothing.
  1852. * If the message is complete, attempt to reconnect the thread it identifies,
  1853. * and deactivate this thread (the identification thread is no longer active).
  1854. * Otherwise (identification has failed), abort the identification sequence.
  1855. *
  1856. * NOTE:
  1857. * This is almost entirely generic code.  It would be nice if the non-hardware
  1858. * specific parts could be provided as a standard routine by the SCSI library.
  1859. *
  1860. * RETURNS: N/A
  1861. *
  1862. * NOMANUAL
  1863. */
  1864. LOCAL void ncr710IdentInContinue
  1865.     (
  1866.     NCR710_THREAD * pThread
  1867.     )
  1868.     {
  1869.     SCSI_THREAD *     pNewThread;
  1870.     SCSI_THREAD *     pScsiThread = (SCSI_THREAD *) pThread;
  1871.     SCSI_CTRL *       pScsiCtrl   = pScsiThread->pScsiCtrl;
  1872.     SCSI_IDENT_STATUS status;
  1873.     SCSI_THREAD_STATE state;
  1874.     status = scsiIdentMsgParse (pScsiCtrl, pScsiThread->identMsg,
  1875.                    pScsiThread->nBytesIdent,
  1876.                   &pScsiThread->pScsiPhysDev,
  1877.        &pScsiThread->tagNumber);
  1878.     switch (status)
  1879. {
  1880. case SCSI_IDENT_INCOMPLETE:
  1881.     state = SCSI_THREAD_IDENT_IN;
  1882.     break;
  1883. case SCSI_IDENT_COMPLETE:
  1884.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_RECONNECTED);
  1885.     if ((pNewThread = scsiMgrPhysDevActiveThreadFind (
  1886.           pScsiThread->pScsiPhysDev,
  1887.           pScsiThread->tagNumber)) == 0)
  1888. {
  1889. state = SCSI_THREAD_IDENT_ABORTING;
  1890. }
  1891.     else
  1892. {
  1893.      ncr710ThreadReconnect ((NCR710_THREAD *) pNewThread);
  1894.      state = SCSI_THREAD_INACTIVE;
  1895. }
  1896.     break;
  1897. case SCSI_IDENT_FAILED:
  1898.     state = SCSI_THREAD_IDENT_ABORTING;
  1899.     break;
  1900. default:
  1901.     logMsg ("ncr710IdentInContinue: invalid ident status (%d)n",
  1902.               status, 0, 0, 0, 0, 0);
  1903.     state = SCSI_THREAD_INACTIVE;
  1904.     break;
  1905. }
  1906.     if (state == SCSI_THREAD_IDENT_ABORTING)
  1907. ncr710ThreadAbort ((SIOP *) pScsiCtrl, pThread);
  1908.     ncr710ThreadStateSet (pThread, state);
  1909.     }
  1910. /*******************************************************************************
  1911. *
  1912. * ncr710ThreadReconnect - reconnect a thread
  1913. *
  1914. * Restore the SCSI pointers for the thread (this really should be in a more
  1915. * generic section of code - perhaps part of the SCSI manager's thread event
  1916. * procesing ?).  Update the newly-connected thread's context (including
  1917. * shared memory area) and resume it.  Set the thread's state to ESTABLISHED.
  1918. *
  1919. * RETURNS: N/A
  1920. *
  1921. * NOMANUAL
  1922. */
  1923. LOCAL void ncr710ThreadReconnect
  1924.     (
  1925.     NCR710_THREAD * pThread
  1926.     )
  1927.     {
  1928.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1929.     SCSI_CTRL   * pScsiCtrl   = pScsiThread->pScsiCtrl;
  1930.     SIOP        * pSiop       = (SIOP *) pScsiCtrl;
  1931.     
  1932.     SCSI_DEBUG_MSG ("ncr710ThreadReconnect: reconnecting thread 0x%08xn",
  1933.     (int) pThread, 0, 0, 0, 0, 0);
  1934.     pScsiCtrl->pThread = pScsiThread;
  1935.     /* Implied RESTORE POINTERS action: see "scsiMsgInComplete ()" */
  1936.     pScsiThread->activeDataAddress = pScsiThread->savedDataAddress;
  1937.     pScsiThread->activeDataLength  = pScsiThread->savedDataLength;
  1938.     ncr710ThreadUpdate (pThread);
  1939.     if (ncr710Resume (pSiop, pThread, NCR710_SCRIPT_INIT_CONTINUE) != OK)
  1940. {
  1941. SCSI_ERROR_MSG ("ncr710ThreadReconnect: failed to resume thread.n",
  1942. 0, 0, 0, 0, 0, 0);
  1943. ncr710ThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1944. return;
  1945. }
  1946.     ncr710ThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED);
  1947.     }
  1948. /*******************************************************************************
  1949. * ncr710SharedMemInit - initialize the fields in a shared memory area
  1950. *
  1951. * Initialise pointers and counts for all message transfers.  These are
  1952. * always directed to buffers provided by the SCSI_CTRL structure.
  1953. *
  1954. * RETURNS: N/A
  1955. *
  1956. * NOMANUAL
  1957. */
  1958. LOCAL void ncr710SharedMemInit
  1959.     (
  1960.     SIOP *          pSiop,
  1961.     NCR710_SHARED * pShMem
  1962.     )
  1963.     {
  1964.     pShMem->identIn.size = 1;
  1965.     pShMem->identIn.addr = CACHE_DMA_VIRT_TO_PHYS (pSiop->scsiCtrl.identBuf);
  1966.     pShMem->msgOut.size = 0; /* set dynamically */
  1967.     pShMem->msgOut.addr = CACHE_DMA_VIRT_TO_PHYS (pSiop->scsiCtrl.msgOutBuf);
  1968.     
  1969.     pShMem->msgIn.size  = 1;
  1970.     pShMem->msgIn.addr  = CACHE_DMA_VIRT_TO_PHYS (pSiop->scsiCtrl.msgInBuf);
  1971.     pShMem->msgInSecond.size = 1;
  1972.     pShMem->msgInSecond.addr = pShMem->msgIn.addr + 1;
  1973.     pShMem->msgInRest.size   = 0;   /* set dynamically */
  1974.     pShMem->msgInRest.addr   = pShMem->msgIn.addr + 2;
  1975.     }
  1976. /*******************************************************************************
  1977. *
  1978. * ncr710ThreadInit - initialize a client thread structure
  1979. *
  1980. * Initialize the fixed data for a thread (i.e., independent of the command).
  1981. * Called once when a thread structure is first created.
  1982. *
  1983. * RETURNS: OK, or ERROR if an error occurs
  1984. *
  1985. * NOMANUAL
  1986. */
  1987. LOCAL STATUS ncr710ThreadInit
  1988.     (
  1989.     SIOP *          pSiop,
  1990.     NCR710_THREAD * pThread
  1991.     )
  1992.     {
  1993.     if (scsiThreadInit (&pThread->scsiThread) != OK)
  1994. return (ERROR);
  1995.     
  1996.     pThread->pShMem = pSiop->pClientShMem;
  1997.     return (OK);
  1998.     }
  1999.     
  2000. /*******************************************************************************
  2001. *
  2002. * ncr710IdentThreadInit - initialize an identification thread structure
  2003. *
  2004. * Set up pointers and counts for all buffers other than messages.  Also set
  2005. * transfer parameters for asynchronous mode, and update the shared memory
  2006. * area to match this thread.
  2007. *
  2008. * NOTE:
  2009. * The pointers/counts set here are normally never used by the identification
  2010. * thread; however, when an identification thread is aborted, it's possible
  2011. * that the target will attempt to transfer one or more non-message bytes
  2012. * before requesting the abort message out.  To handle this, the thread's
  2013. * pointers and counts all specify a dummy buffer.  There is no re-entrancy
  2014. * problem here because we do not care what data is transferred.  This might
  2015. * be handled more elegantly if there were a special script entry to abort
  2016. * an identification thread.
  2017. *
  2018. * RETURNS: OK, or ERROR if an error occurs
  2019. *
  2020. * NOMANUAL
  2021. */
  2022. LOCAL STATUS ncr710IdentThreadInit
  2023.     (
  2024.     NCR710_THREAD * pThread
  2025.     )
  2026.     {
  2027.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  2028.     SIOP *        pSiop       = (SIOP *) pScsiThread->pScsiCtrl;
  2029.     static UINT8  dummy;
  2030.     
  2031.     /*
  2032.      * Initialise Pointers and counts in thread
  2033.      */
  2034.     pScsiThread->cmdLength         = 1;
  2035.     pScsiThread->cmdAddress        = &dummy;
  2036.     pScsiThread->dataLength        = 1;
  2037.     pScsiThread->dataAddress       = &dummy;
  2038.     pScsiThread->activeDataLength  = 1;
  2039.     pScsiThread->activeDataAddress = &dummy;
  2040.     pScsiThread->savedDataLength   = 1;
  2041.     pScsiThread->savedDataAddress  = &dummy;
  2042.     pScsiThread->statusLength      = 1;
  2043.     pScsiThread->statusAddress     = &dummy;
  2044.     pScsiThread->identMsgLength    = 1;
  2045.     
  2046.     /*
  2047.      * Initialise SIOP register context in thread
  2048.      */
  2049.     pThread->nHostFlags   = 0;
  2050.     pThread->nMsgOutState = SCSI_MSG_OUT_NONE;
  2051.     pThread->nMsgInState  = SCSI_MSG_IN_NONE;
  2052.     pThread->sxfer = NCR710_SYNC_XFER_PARAMS_ASYNC;
  2053.     pThread->sbcl  = NCR710_CLOCK_DIVIDE_ASYNC;
  2054.     /*
  2055.      * Initialise shared memory area
  2056.      */
  2057.     pThread->pShMem = pSiop->pIdentShMem;
  2058.     
  2059.     ncr710SharedMemInit (pSiop, pThread->pShMem);
  2060.     ncr710ThreadUpdate (pThread);
  2061.     
  2062.     return (OK);
  2063.     }
  2064. /*******************************************************************************
  2065. *
  2066. * ncr710ThreadUpdate - update the thread structure for a current SCSI command
  2067. *
  2068. * Update the dynamic data (e.g. data pointers, transfer parameters) in
  2069. * the thread to reflect the latest state of the corresponding physical device.
  2070. *
  2071. * RETURNS: N/A
  2072. *
  2073. * NOMANUAL
  2074. */
  2075. LOCAL void ncr710ThreadUpdate
  2076.     (
  2077.     NCR710_THREAD * pThread /* thread info */
  2078.     )
  2079.     {
  2080.     SCSI_THREAD   * pScsiThread = (SCSI_THREAD *) pThread;
  2081.     SCSI_CTRL     * pScsiCtrl   = pScsiThread->pScsiCtrl;
  2082.     SIOP          * pSiop       = (SIOP *) pScsiCtrl;
  2083.     NCR710_SHARED * pShMem      = pThread->pShMem;
  2084.     UINT            flags       = 0;
  2085.     UINT            msgOutSize;
  2086.     UINT            msgInSize;
  2087.     /*
  2088.      *  If there is an identification message, ensure ATN is asserted
  2089.      * during (re)selection.
  2090.      */
  2091.     if (pScsiThread->identMsgLength != 0)
  2092. flags |= FLAGS_IDENTIFY;
  2093.     /*
  2094.      * Update SIOP register context
  2095.      */
  2096.     pThread->nHostFlags   = flags;
  2097.     pThread->nMsgOutState = pScsiCtrl->msgOutState;
  2098.     pThread->nMsgInState  = pScsiCtrl->msgInState;
  2099.     /*
  2100.      * Update dynamic message in/out sizes
  2101.      */
  2102.     if (pScsiCtrl->msgOutState == SCSI_MSG_OUT_NONE)
  2103. msgOutSize = 0;
  2104.     else
  2105. msgOutSize = pScsiCtrl->msgOutLength;
  2106.     if (pScsiCtrl->msgInState != SCSI_MSG_IN_EXT_MSG_DATA)
  2107. msgInSize = 0;
  2108.     
  2109.     else if ((msgInSize = pScsiCtrl->msgInBuf[SCSI_EXT_MSG_LENGTH_BYTE]) == 0)
  2110. msgInSize = SCSI_EXT_MSG_MAX_LENGTH;
  2111.     /*
  2112.      * Update shared memory area
  2113.      */
  2114.     pShMem->command.size  = pScsiThread->cmdLength;
  2115.     pShMem->command.addr  = pScsiThread->cmdAddress;
  2116.     pShMem->data.size     = pScsiThread->activeDataLength;
  2117.     pShMem->data.addr     = pScsiThread->activeDataAddress;
  2118.     pShMem->status.size   = pScsiThread->statusLength;
  2119.     pShMem->status.addr   = pScsiThread->statusAddress;
  2120.     /* These used to be pScsiThread->identMsg/identMsgLength */
  2121.     pShMem->identOut.size = pSiop->identMsgLength;
  2122.     pShMem->identOut.addr = pSiop->identMsg;
  2123.     pShMem->msgOut.size    = msgOutSize;
  2124.     pShMem->msgInRest.size = msgInSize;
  2125.     }
  2126. /*******************************************************************************
  2127. *
  2128. * ncr710ThreadComplete - successfully complete execution of a client thread
  2129. *
  2130. * Set the thread status and errno appropriately, depending on whether or
  2131. * not the thread has been aborted.  Set the thread inactive, and notify
  2132. * the SCSI manager of the completion.
  2133. *
  2134. * RETURNS: N/A
  2135. *
  2136. * NOMANUAL
  2137. */
  2138. LOCAL void ncr710ThreadComplete
  2139.     (
  2140.     NCR710_THREAD * pThread
  2141.     )
  2142.     {
  2143.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  2144.     
  2145.     SCSI_DEBUG_MSG ("ncr710ThreadComplete: thread 0x%08x completedn",
  2146.     (int) pThread, 0, 0, 0, 0, 0);
  2147.     if (pScsiThread->state == SCSI_THREAD_ABORTING)
  2148. {
  2149. pScsiThread->status = ERROR;
  2150. pScsiThread->errNum = S_scsiLib_ABORTED;
  2151. }
  2152.     else
  2153. {
  2154.      pScsiThread->status = OK;
  2155.      pScsiThread->errNum = 0;
  2156.      }
  2157.     
  2158.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  2159.     scsiCacheSynchronize (pScsiThread, SCSI_CACHE_POST_COMMAND);
  2160.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED);
  2161.     }
  2162. /*******************************************************************************
  2163. *
  2164. * ncr710ThreadDefer - defer execution of a thread
  2165. *
  2166. * Set the thread's state to INACTIVE and notify the SCSI manager of the
  2167. * deferral event.
  2168. *
  2169. * RETURNS: N/A
  2170. *
  2171. * NOMANUAL
  2172. */
  2173. LOCAL void ncr710ThreadDefer
  2174.     (
  2175.     NCR710_THREAD * pThread
  2176.     )
  2177.     {
  2178.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  2179.     
  2180.     SCSI_DEBUG_MSG ("ncr710ThreadDefer: thread 0x%08x deferredn",
  2181.     (int) pThread, 0, 0, 0, 0, 0);
  2182.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  2183.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_DEFERRED);
  2184.     }
  2185.     
  2186. /*******************************************************************************
  2187. *
  2188. * ncr710ThreadFail - complete execution of a thread, with error status
  2189. *
  2190. * Set the thread's status and errno according to the type of error.  Set
  2191. * the thread's state to INACTIVE, and notify the SCSI manager of the
  2192. * completion event.
  2193. *
  2194. * RETURNS: N/A
  2195. *
  2196. * NOMANUAL
  2197. */
  2198. LOCAL void ncr710ThreadFail
  2199.     (
  2200.     NCR710_THREAD * pThread,
  2201.     int             errNum
  2202.     )
  2203.     {
  2204.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  2205.     
  2206.     SCSI_DEBUG_MSG ("ncr710ThreadFail: thread 0x%08x failed (errno = %d)n",
  2207.     (int) pThread, errNum, 0, 0, 0, 0);
  2208.     pScsiThread->status = ERROR;
  2209.     if (pScsiThread->state == SCSI_THREAD_ABORTING)
  2210. pScsiThread->errNum = S_scsiLib_ABORTED;
  2211.     else
  2212.      pScsiThread->errNum = errNum;
  2213.     
  2214.     ncr710ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  2215.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED);
  2216.     }
  2217.     
  2218. /******************************************************************************
  2219. *
  2220. * ncr710ThreadStateSet - set the state of a thread
  2221. *
  2222. * This is really just a place-holder for debugging and possible future
  2223. * enhancements such as state-change logging.
  2224. *
  2225. * RETURNS: N/A
  2226. *
  2227. * NOMANUAL
  2228. */
  2229. LOCAL void ncr710ThreadStateSet
  2230.     (
  2231.     NCR710_THREAD *   pThread, /* ptr to thread info */
  2232.     SCSI_THREAD_STATE state
  2233.     )
  2234.     {
  2235.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  2236.     
  2237.     SCSI_DEBUG_MSG ("ncr710ThreadStateSet: thread 0x%08x: %d -> %dn",
  2238.     (int) pThread, pScsiThread->state, state, 0, 0, 0);
  2239.     pScsiThread->state = state;
  2240.     }
  2241. /******************************************************************************
  2242. *
  2243. * ncr710Activate - activate a script corresponding to a new thread
  2244. *
  2245. * Request activation of (the script for) a new thread, if possible; do not
  2246. * wait for the script to complete (or even start) executing.  Activation
  2247. * is requested by signalling the controller, which causes an interrupt.
  2248. * The script is started by the ISR in response to this event.
  2249. *
  2250. * There is a race condition inherent in SCSI between the synchronous
  2251. * activation of a thread (i.e., execution of this routine) and asynchronous
  2252. * activation of a thread as a result of selection or reselection.  The SCSI
  2253. * manager is designed to take account of this, and assumes that either the
  2254. * new thread has been successfully activated or a (re)selection has taken
  2255. * place, as determined by the next event it receives.  In the case when
  2256. * (re)selection occurs, the current activation request is deferred and
  2257. * retried later.
  2258. *
  2259. * Therefore, an activation request is lodged only if the controller is
  2260. * currently PASSIVE (waiting for (re)selection or a host command).  If the
  2261. * controller is IDLE, (re)selection is assumed to have already occurred.
  2262. * Note that this is not an error condition; there is no way for the
  2263. * caller to distinguish the two cases, because even if the thread appears
  2264. * to have been activated it may yet be "pre-empted" by (re)selection.
  2265. *
  2266. * The controller should never be ACTIVE.  If it is, the SCSI manager has
  2267. * tried to activate multiple concurrent threads on the controller, which
  2268. * indicates a major (software) disaster.
  2269. *
  2270. * NOTE: Interrupt locking is required to ensure that the correct action
  2271. * is taken once the controller state has been checked.
  2272. *
  2273. * RETURNS: OK, or ERROR if the controller is in an invalid state (this
  2274. * indicates a major software failure).
  2275. *
  2276. * NOMANUAL
  2277. */
  2278. LOCAL STATUS ncr710Activate
  2279.     (
  2280.     SIOP *          pSiop,
  2281.     NCR710_THREAD * pThread
  2282.     )
  2283.     {
  2284.     STATUS status;
  2285.     int    key;
  2286.     if (pSiop->cmdPending)
  2287. {
  2288. logMsg ("ncr710Activate: activation request already pending !n",
  2289. 0, 0, 0, 0, 0, 0);
  2290. return (ERROR);
  2291. }
  2292.     
  2293.     /*
  2294.      * Check controller state, set a new command pending and signal it
  2295.      *  if necessary.
  2296.      */
  2297.     key = intLock ();
  2298.     switch (pSiop->state)
  2299. {
  2300. case NCR710_STATE_IDLE:
  2301.     status = OK;
  2302.     break;
  2303. case NCR710_STATE_PASSIVE:
  2304.     pSiop->pNewThread = pThread;
  2305.     pSiop->cmdPending = TRUE;
  2306.     *pSiop->pIstat |= B_SIGP;
  2307.     status = OK;
  2308.     break;
  2309.     
  2310. case NCR710_STATE_ACTIVE:
  2311. default:
  2312.     status = ERROR;
  2313.     break;
  2314. }
  2315.     intUnlock (key);
  2316.     if (status != OK)
  2317. {
  2318. logMsg ("ncr710Activate: invalid controller state.n",
  2319. pSiop->state, 0, 0, 0, 0, 0);
  2320. errnoSet (S_scsiLib_SOFTWARE_ERROR);
  2321. }
  2322.     return (status);
  2323.     }
  2324. /*******************************************************************************
  2325. * ncr710Resume - resume a script corresponding to a suspended thread
  2326. *
  2327. * NOTE: the script can only be resumed if the controller is currently idle.
  2328. * To avoid races, interrupts must be locked while this is checked and the
  2329. * script re-started.
  2330. *
  2331. * Reasons why the controller might not be idle include SCSI bus reset and
  2332. * unexpected disconnection, both of which might occur in practice.  Hence
  2333. * this is not considered to be a major software error.
  2334. *
  2335. * RETURNS: OK, or ERROR if the controller is in an invalid state (this
  2336. * should not be treated as a major software failure).
  2337. *
  2338. * NOMANUAL
  2339. */
  2340. LOCAL STATUS ncr710Resume
  2341.     (
  2342.     SIOP *              pSiop, /* ptr to controller info          */
  2343.     NCR710_THREAD *     pThread, /* ptr to thread info              */
  2344.     NCR710_SCRIPT_ENTRY entryId /* entry point of script to resume */
  2345.     )
  2346.     {
  2347.     STATUS status;
  2348.     int    key;
  2349.     /*
  2350.      * Check validity of connection and start script if OK
  2351.      */
  2352.     key = intLock ();
  2353.     switch (pSiop->state)
  2354. {
  2355. case NCR710_STATE_IDLE:
  2356.     SCSI_INT_DEBUG_MSG ("ncr710Resume: thread: 0x%08x: state %d -> %dn",
  2357.      (int) pThread,
  2358.      NCR710_STATE_IDLE, NCR710_STATE_ACTIVE,
  2359.      0, 0, 0);
  2360.     ncr710ScriptStart (pSiop, pThread, entryId);
  2361.     pSiop->state = NCR710_STATE_ACTIVE;
  2362.     status = OK;
  2363.     break;
  2364. case NCR710_STATE_PASSIVE:
  2365. case NCR710_STATE_ACTIVE:
  2366. default:
  2367.     status = ERROR;
  2368.     break;
  2369. }
  2370.     intUnlock (key);
  2371.     return (status);
  2372.     }
  2373. /*******************************************************************************
  2374. * ncr710Abort - abort the active script corresponding to the current thread
  2375. *
  2376. * Check that there is currently an active script running.  If so, set the
  2377. * SIOP's Abort flag which will halt the script and cause an interrupt.
  2378. *
  2379. * RETURNS: N/A
  2380. *
  2381. * NOMANUAL
  2382. */
  2383. LOCAL void ncr710Abort
  2384.     (
  2385.     SIOP * pSiop /* ptr to controller info */
  2386.     )
  2387.     {
  2388.     STATUS status;
  2389.     int    key;
  2390.     key = intLock ();
  2391.     switch (pSiop->state)
  2392. {
  2393. case NCR710_STATE_IDLE:
  2394. case NCR710_STATE_PASSIVE:
  2395.     status = OK;
  2396.     break;
  2397. case NCR710_STATE_ACTIVE:
  2398.     *pSiop->pIstat |= B_ABORT;
  2399.     status = OK;
  2400.     break;
  2401.     
  2402. default:
  2403.     status = ERROR;
  2404.     break;
  2405. }
  2406.     intUnlock (key);
  2407.     if (status != OK)
  2408. {
  2409. logMsg ("ncr710Abort: thread = 0x%08x: invalid state (%d)n",
  2410. pSiop->state, 0, 0, 0, 0, 0);
  2411. }
  2412.     }
  2413. /*******************************************************************************
  2414. *
  2415. * ncr710ScriptStart - start the SIOP executing a script
  2416. *
  2417. * Restore the SIOP register context, including the shared memory area, from
  2418. * the thread context.  Put the address of the script entry point into the
  2419. * DSP register.  If not in single-step mode, start the script.
  2420. *
  2421. * NOTE: should always be called with SIOP interrupts locked.
  2422. *
  2423. * RETURNS: N/A
  2424. * NOMANUAL
  2425. */
  2426. LOCAL void ncr710ScriptStart
  2427.     (
  2428.     SIOP               *pSiop, /* pointer to  SIOP info */
  2429.     NCR710_THREAD      *pThread, /* ncr thread info */
  2430.     NCR710_SCRIPT_ENTRY entryId /* routine address entry point */
  2431.     )
  2432.     {
  2433.     /*
  2434.      * Script entry point addresses.  These are resolved by PROCs
  2435.      * defined in the script itself (see "ncr710init.n").
  2436.      *
  2437.      * NOTE: The number and order of members of this array _must_ match
  2438.      * the enum NCR710_SCRIPT_ENTRY.
  2439.      */
  2440.     static ULONG * ncr710ScriptEntry [] =
  2441. {
  2442.         ncr710Wait, /* wait for re-select or host cmd   */
  2443.      ncr710InitStart, /* start an initiator thread        */
  2444.      ncr710InitContinue, /* continue an initiator thread     */
  2445. ncr710TgtDisconnect,       /* disconnect a target thread       */
  2446. };    
  2447.     /*
  2448.      * Set current hardware thread pointer for ISR
  2449.      */
  2450.     pSiop->pHwThread = pThread;
  2451.     /*
  2452.      * Restore the SIOP register context for this thread.
  2453.      */
  2454.     *pSiop->pScratch0 = pThread->scratch0;
  2455.     *pSiop->pScratch1 = pThread->scratch1;
  2456.     *pSiop->pScratch2 = pThread->scratch2;
  2457.     *pSiop->pScratch3 = pThread->scratch3;
  2458.     
  2459.     *pSiop->pSxfer = pThread->sxfer | B_DHP;
  2460.     *pSiop->pSbcl  = pThread->sbcl;
  2461.     /*
  2462.      * Set the shared data address, load the script start address,
  2463.      * then start the SIOP unless it's in single-step mode.
  2464.      */
  2465.     *pSiop->pDsa = (UINT) CACHE_DMA_VIRT_TO_PHYS (pThread->pShMem);
  2466.     *pSiop->pDsp = (UINT) ncr710ScriptEntry [entryId];
  2467.     if (pSiop->singleStep)
  2468. {
  2469. logMsg ("ncr710ScriptStart: single-step required to start scriptn",
  2470. 0, 0, 0, 0, 0, 0);
  2471. }
  2472.     else
  2473. {
  2474.      *pSiop->pDcntl |= B_STD;
  2475. }
  2476.     }
  2477. /*******************************************************************************
  2478. *
  2479. * ncr710ThreadParamsSet - set various parameters for a thread
  2480. *
  2481. * Parameters include transfer offset and period, as well as the ID of the
  2482. * target device.  All of these end up as encoded values stored either in
  2483. * the thread's register context or its associated shared memory area.
  2484. *
  2485. * Transfer period is specified in SCSI units (multiples of 4 ns).  An offset
  2486. * of zero specifies asynchronous transfer.
  2487. *
  2488. * RETURNS: OK if parameters are OK, else ERROR.
  2489. *
  2490. * NOMANUAL
  2491. */
  2492. LOCAL STATUS ncr710ThreadParamsSet
  2493.     (
  2494.     NCR710_THREAD * pThread,      /* thread to be affected  */
  2495.     UINT8           offset, /* max REQ/ACK offset     */
  2496.     UINT8           period /* min transfer period    */
  2497.     )
  2498.     {
  2499.     SCSI_THREAD *   pScsiThread = (SCSI_THREAD *) pThread;
  2500.     SIOP *          pSiop       = (SIOP *) pScsiThread->pScsiCtrl;
  2501.     UINT            busId       = pScsiThread->pScsiTarget->scsiDevBusId;
  2502.     NCR710_SHARED * pShMem      = pThread->pShMem;
  2503.     if (!ncr710XferParamsCvt (pSiop, &offset, &period, &pThread->sxfer,
  2504.                                &pThread->sbcl))
  2505. { /* should never happen */
  2506. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  2507. return (ERROR);
  2508. }
  2509.     pShMem->device = (pThread->sxfer <<  NCR710_XFER_PARAMS_SHIFT) |
  2510.                                   (1 << (NCR710_TARGET_BUS_ID_SHIFT + busId));
  2511.     return (OK);
  2512.     }
  2513. /*******************************************************************************
  2514. *
  2515. * ncr710XferParamsQuery - get (synchronous) transfer parameters
  2516. *
  2517. * Updates the synchronous transfer parameters suggested in the call to match
  2518. * the NCR 53C710's capabilities.  Transfer period is in SCSI units (multiples
  2519. * of 4 ns).
  2520. *
  2521. * Note: the transfer period is made longer and the offset is made smaller if
  2522. * the NCR 53C710 cannot handle the specified values.
  2523. *
  2524. * RETURNS: OK
  2525. *
  2526. * NOMANUAL
  2527. */
  2528. LOCAL STATUS ncr710XferParamsQuery
  2529.     (
  2530.     SCSI_CTRL *pScsiCtrl, /* ptr to controller info       */
  2531.     UINT8     *pOffset, /* max REQ/ACK offset  [in/out] */
  2532.     UINT8     *pPeriod /* min transfer period [in/out] */
  2533.     )
  2534.     {
  2535.     UINT8 unused;
  2536.     (void) ncr710XferParamsCvt ((SIOP *) pScsiCtrl, pOffset, pPeriod,
  2537. &unused, &unused);
  2538.     
  2539.     return (OK);
  2540.     }
  2541.     
  2542. /*******************************************************************************
  2543. *
  2544. * ncr710XferParamsSet - set transfer parameters
  2545. *
  2546. * Validate the requested parameters, convert to the NCR 53C710's native
  2547. * format and save in the current thread for later use (the chip's registers
  2548. * are not actually set until the next script activation for this thread).
  2549. *
  2550. * Transfer period is specified in SCSI units (multiples of 4 ns).  An offset
  2551. * of zero specifies asynchronous transfer.
  2552. *
  2553. * RETURNS: OK if transfer parameters are OK, else ERROR.
  2554. *
  2555. * NOMANUAL
  2556. */
  2557. LOCAL STATUS ncr710XferParamsSet
  2558.     (
  2559.     SCSI_CTRL *pScsiCtrl, /* ptr to controller info */
  2560.     UINT8      offset, /* max REQ/ACK offset     */
  2561.     UINT8      period /* min transfer period    */
  2562.     )
  2563.     {
  2564.     NCR710_THREAD * pThread = (NCR710_THREAD *) pScsiCtrl->pThread;
  2565.     return (ncr710ThreadParamsSet (pThread, offset, period));
  2566.     }
  2567. /*******************************************************************************
  2568. * ncr710XferParamsCvt - convert transfer period from SCSI to NCR 53C710 units
  2569. *
  2570. * Given a "suggested" REQ/ACK offset and transfer period (in SCSI units of
  2571. * 4 ns), return the nearest offset and transfer period the NCR 53C710 is
  2572. * capable of using.  Also return the corresponding values of the NCR 53C710's
  2573. * Synchronous Transfer and Synchronous Bus Control registers.
  2574. *
  2575. * An offset of zero specifies asynchronous transfer, in which case the period
  2576. * is irrelevant.  Otherwise, the offset may be clipped to be within the
  2577. * maximum limit the NCR 53C710 is capable of.
  2578. *
  2579. * The transfer period is normally rounded towards longer periods if the NCR
  2580. * 53C710 is not capable of using the exact specified value.  The period may
  2581. * also be clipped to be within the NCR 53C710's maximum and minimum limits
  2582. * according to its clock period.
  2583. *
  2584. * If either the offset or period need to be clipped, the value FALSE is
  2585. * retuned as this may reflect an error condition.
  2586. *
  2587. * RETURNS: TRUE if input period is within NCR 53C710's range, else FALSE
  2588. *
  2589. * NOMANUAL
  2590. */
  2591. LOCAL BOOL ncr710XferParamsCvt
  2592.     (
  2593.     FAST SIOP  *pSiop, /* ptr to controller info            */
  2594.     FAST UINT8 *pOffset, /* REQ/ACK offset                    */
  2595.     FAST UINT8 *pPeriod, /* xfer period, SCSI units (x 4 ns)  */
  2596.     FAST UINT8 *pXferParams, /* corresponding Sync Xfer Reg value */
  2597.     FAST UINT8 *pClockDiv /* corresponding clock division bits */
  2598.     )
  2599.     {
  2600.     UINT  offset  = (UINT) *pOffset;
  2601.     UINT  period  = (UINT) *pPeriod;
  2602.     BOOL  inRange = TRUE;
  2603.     UINT8 xferParams  = 0; /* initialised to avoid warnings */
  2604.     UINT8 clockDivide = 0; /* initialised to avoid warnings */
  2605.     if (offset == SCSI_SYNC_XFER_ASYNC_OFFSET)
  2606. {
  2607. xferParams  = NCR710_SYNC_XFER_PARAMS_ASYNC;
  2608. clockDivide = NCR710_CLOCK_DIVIDE_ASYNC;
  2609. offset = SCSI_SYNC_XFER_ASYNC_OFFSET;
  2610. period = 0;
  2611.      }
  2612.     else
  2613. {
  2614. UINT div;
  2615. UINT clkCycles;
  2616.      UINT bestPeriod = (UINT) NONE; /* i.e., not a valid SCSI period */
  2617. SCSI_DEBUG_MSG ("ncr710XferParamsCvt: requested: "
  2618. "offset = %d, period = %dn",
  2619.      offset, period, 0, 0, 0, 0);
  2620. /*
  2621.  *  Clip period (if necessary) to be within legal SCSI limits
  2622.  */
  2623. if (period < SCSI_SYNC_XFER_MIN_PERIOD)
  2624.     {
  2625.     period  = SCSI_SYNC_XFER_MIN_PERIOD;
  2626.     inRange = FALSE;
  2627.     }
  2628.      /*
  2629.        *  Clip offset (if necessary) to suit NCR 53C710
  2630.        */
  2631.      if (offset > NCR710_MAX_REQ_ACK_OFFSET)
  2632.     {
  2633.     offset  = NCR710_MAX_REQ_ACK_OFFSET;
  2634.     inRange = FALSE;
  2635.     }
  2636. /*
  2637.  *  Find the best attainable period which is equal to or greater than
  2638.  *  the requested period.  Basic formula for period is:
  2639.  *
  2640.  *   period = clkPeriod * (4 + xferParams)
  2641.  *
  2642.  *  where:
  2643.  *
  2644.  *   period     = sync transfer period (ns x 100)
  2645.  *   clkPeriod   = sync clock    period (ns x 100)
  2646.  *   xferParams  = value in bits 6-4 of SCSI Xfer register (0-7)
  2647.  *
  2648.  *  The sync clock can have four possible values depending on the
  2649.  *  value of the clock divisor bits in the SCSI Bus Control register
  2650.  *  bits 1,0:
  2651.  *
  2652.  *   00  - sync clock period = async clock period (set in HwInit)
  2653.  *   01  - sync clock period = input clock period * 1.0 (2/2)
  2654.  *   10  - sync clock period = input clock period * 1.5 (3/2)
  2655.  *   11  - sync clock period = input clock period * 2.0 (4/2)
  2656.  *
  2657.  *  For each sync clock period, calculate the required number of
  2658.  *  clock cycles to achieve the requested period (or greater).
  2659.  *  If less than the minimum possible (4), round up to the minimum.
  2660.  *  If the result is not greater than the maximum number of clock
  2661.  *  cycles, then the corresponding period is attainable and is
  2662.  *  calculated.  The lowest attainable period is selected.
  2663.  */
  2664.      for (div = NCR710_MIN_CLOCK_DIV; div <= NCR710_MAX_CLOCK_DIV; ++div)
  2665.     {
  2666.     UINT clkPeriod;
  2667.     if (div == NCR710_CLOCK_DIVIDE_ASYNC)
  2668.      clkPeriod = pSiop->asyncClkPeriod;
  2669.     else
  2670.      clkPeriod = pSiop->clkPeriod * (div + 1) / 2;
  2671.     /*
  2672.      *  Round (and perhaps clip) transfer period to suit NCR 53C710
  2673.      *
  2674.      *  Note: split into two stages to avoid associativity problems,
  2675.      *   and careful to round up rather than truncate result.
  2676.      */
  2677.     clkCycles  = (period * 4 * 100) + (clkPeriod - 1);
  2678.     clkCycles /= clkPeriod;
  2679.     if (clkCycles < 4 + NCR710_MIN_XFER_PERIOD)
  2680. clkCycles = 4 + NCR710_MIN_XFER_PERIOD;
  2681.     if (clkCycles <= 4 + NCR710_MAX_XFER_PERIOD)
  2682.      {
  2683.      UINT actualPeriod = clkPeriod * clkCycles / (4 * 100);
  2684.      if ((actualPeriod >= period) &&
  2685.     (actualPeriod <  bestPeriod))
  2686.          {
  2687.                     bestPeriod  = actualPeriod;
  2688.               xferParams  = ((clkCycles - 4) << NCR710_SYNC_XFER_PERIOD_SHIFT)
  2689.                | offset;
  2690.     clockDivide = div;
  2691.     }
  2692.      }
  2693.     }
  2694. /*
  2695.  *  If "bestPeriod" has been set, a valid period has been found.
  2696.  *  Otherwise, reset to use asynchronous transfer.
  2697.  */
  2698.      if (bestPeriod != (UINT) NONE)
  2699.     period = bestPeriod;
  2700. else
  2701.             {
  2702.     xferParams  = NCR710_SYNC_XFER_PARAMS_ASYNC;
  2703.     clockDivide = NCR710_CLOCK_DIVIDE_ASYNC;
  2704.     offset = SCSI_SYNC_XFER_ASYNC_OFFSET;
  2705.     period = 0;
  2706.     inRange = FALSE;
  2707.     }
  2708. SCSI_DEBUG_MSG ("ncr710XferParamsCvt: granted:   "
  2709. "offset = %d, period = %dn",
  2710.      offset, period, 0, 0, 0, 0);
  2711.      }
  2712.     *pOffset     = offset;
  2713.     *pPeriod     = period;
  2714.     *pXferParams = xferParams;
  2715.     *pClockDiv   = clockDivide;
  2716.     return (inRange);
  2717.     }
  2718. /*******************************************************************************
  2719. *
  2720. * ncr710StepEnable2 - Enable/disable script single step 
  2721. *
  2722. * Enable/disable single step facility on ncr chip.  Also, unmask/mask single 
  2723. * step interrupt in Dien register.
  2724. * Before any SCSI execution you just have to use 
  2725. * ncr710StepEnable (pSiop, TRUE) to run in single step mode.  
  2726. * To run a script step use ncr710SingleStep(pSiop).
  2727. * To disable use ncr710StepEnable (pSiop, FALSE).
  2728. * RETURNS: N/A
  2729. *
  2730. * NOMANUAL
  2731. */
  2732. void ncr710StepEnable2
  2733.     (
  2734.     SIOP *pSiop, /* pointer to SIOP info       */
  2735.     BOOL enable           /* TRUE => enable single-step */
  2736.     )
  2737.     {
  2738.     if  (enable)
  2739. {
  2740. /* enable single-step interrupt */
  2741.         *pSiop->pDien |= B_SSI;
  2742. /* set single-step mode */
  2743. *pSiop->pDcntl |= B_SSM;
  2744. /* disable manual Start */
  2745. *pSiop->pDmode &= ~B_MAN;
  2746. }
  2747.     else 
  2748. {
  2749. /* unset single-step mode */
  2750. *pSiop->pDcntl &= ~B_SSM;
  2751. /* disable single-step interrupt */
  2752.         *pSiop->pDien &= ~B_SSI;
  2753. /* enable manual Start */
  2754. *pSiop->pDmode |= B_MAN;
  2755.         }
  2756.     pSiop->singleStep = enable;
  2757.     }
  2758. /*******************************************************************************
  2759. *
  2760. * ncr710SingleStep2 - Perform a single step 
  2761. *
  2762. * Perform a single step by writing the STD bit in the DCNTL register.
  2763. * The parameter is a pointer to the SIOP information. 
  2764. * RETURNS: N/A
  2765. * NOMANUAL
  2766. */
  2767. void ncr710SingleStep2
  2768.     (
  2769.     SIOP * pSiop,  /* pointer to SIOP info */ 
  2770.     BOOL   verbose /* show all registers   */
  2771.     )
  2772.     {
  2773.     UINT *siopPc;
  2774.     /*
  2775.      * Start the SIOP: if not in single-step mode it will then continue
  2776.      * the normal instruction sequence.  If in single-step mode, wait
  2777.      * until one instruction has been executed.
  2778.      */
  2779.     *pSiop->pDcntl |= B_STD;
  2780.     if (!pSiop->singleStep)
  2781. return;
  2782.     semTake (pSiop->singleStepSem, WAIT_FOREVER);
  2783.     /*
  2784.      * Allow any tasks using SCSI to get a look-in - they may change the
  2785.      * controller state, in which case we'd like to see that change now
  2786.      * rather than next time.
  2787.      */
  2788.     taskDelay (5);
  2789.     /*
  2790.      * Show what the SIOP is about to do
  2791.      */
  2792.     if (pSiop->state == NCR710_STATE_IDLE)
  2793. printf ("NCR710 is idle.nn");
  2794.     else
  2795. {
  2796. siopPc = (UINT *) *pSiop->pDsp;
  2797. printf ("NCR710 [%d] Next Opcode (0x%08x) => 0x%08x 0x%08xnn",
  2798. pSiop->state, (int) siopPc, siopPc[0], siopPc[1]);
  2799. }
  2800.     
  2801.     /*
  2802.      * Dump the SIOP registers, if in verbose mode
  2803.      */
  2804.     if (verbose)
  2805.      ncr710ShowScsi2 ((SCSI_CTRL *) pSiop);
  2806.     }
  2807. /*******************************************************************************
  2808. *
  2809. * ncr710ShowScsi2 - display the values of all readable NCR 53C710 SIOP registers
  2810. *
  2811. * This routine displays the state of the NCR 53C710 SIOP registers in a 
  2812. * user-friendly way.  It is primarily used for debugging. 
  2813. * The input parameter is the pointer to the SIOP information
  2814. * structure returned by the ncr710CtrlCreateScsi2() call.
  2815. *
  2816. * NOTE
  2817. * The only readable register during a script execution is the Istat register. 
  2818. * If you use this routine during the execution of a SCSI command, the result 
  2819. * could be unpredictable.
  2820. *
  2821. * EXAMPLE:
  2822. * .CS
  2823. * -> ncr710Show
  2824. * NCR710 Registers 
  2825. * ---------------- 
  2826. * 0xfff47000: Sien    = 0xa5 Sdid    = 0x00 Scntl1  = 0x00 Scntl0  = 0x04
  2827. * 0xfff47004: Socl    = 0x00 Sodl    = 0x00 Sxfer   = 0x80 Scid    = 0x80
  2828. * 0xfff47008: Sbcl    = 0x00 Sbdl    = 0x00 Sidl    = 0x00 Sfbr    = 0x00
  2829. * 0xfff4700c: Sstat2  = 0x00 Sstat1  = 0x00 Sstat0  = 0x00 Dstat   = 0x80
  2830. * 0xfff47010: Dsa     = 0x00000000
  2831. * 0xfff47014: Ctest3  = ???? Ctest2  = 0x21 Ctest1  = 0xf0 Ctest0  = 0x00
  2832. * 0xfff47018: Ctest7  = 0x32 Ctest6  = ???? Ctest5  = 0x00 Ctest4  = 0x00
  2833. * 0xfff4701c: Temp    = 0x00000000
  2834. * 0xfff47020: Lcrc    = 0x00 Ctest8  = 0x00 Istat   = 0x00 Dfifo   = 0x00
  2835. * 0xfff47024: Dcmd/Ddc= 0x50000000
  2836. * 0xfff47028: Dnad    = 0x00066144
  2837. * 0xfff4702c: Dsp     = 0x00066144
  2838. * 0xfff47030: Dsps    = 0x00066174
  2839. * 0xfff47037: Scratch3= 0x00 Scratch2= 0x00 Scratch1= 0x00 Scratch0= 0x0a
  2840. * 0xfff47038: Dcntl   = 0x21 Dwt     = 0x00 Dien    = 0x37 Dmode   = 0x01
  2841. * 0xfff4703c: Adder   = 0x000cc2b8
  2842. * value = 0 = 0x0
  2843. * .CE
  2844. *
  2845. * RETURNS: OK, or ERROR if <pScsiCtrl> and <pSysScsiCtrl> are both NULL.
  2846. *
  2847. * SEE ALSO: ncr710CtrlCreateScsi2()
  2848. */
  2849. STATUS ncr710ShowScsi2 
  2850.     (
  2851.     FAST SCSI_CTRL *pScsiCtrl  /* ptr to SCSI controller info */
  2852.     )
  2853.     {
  2854.     FAST SIOP *pSiop; /* prt to SIOP info */
  2855.     if (pScsiCtrl == NULL)
  2856. {
  2857. if (pSysScsiCtrl == NULL)
  2858.     {
  2859.     printErr ("No SCSI controller specified.n");
  2860.     return (ERROR);
  2861.     }
  2862. pScsiCtrl = pSysScsiCtrl;
  2863. }
  2864.     pSiop = (SIOP *) pScsiCtrl; 
  2865.     printf ("NCR710 Registers n");
  2866.     printf ("---------------- n");
  2867.     printf ("0x%08x: ", (int) pSiop->pSien);
  2868.     printf ("Sien    = 0x%02x ", *pSiop->pSien); 
  2869.     printf ("Sdid    = 0x%02x ", *pSiop->pSdid); 
  2870.     printf ("Scntl1  = 0x%02x ", *pSiop->pScntl1); 
  2871.     printf ("Scntl0  = 0x%02xn", *pSiop->pScntl0); 
  2872.     printf ("0x%08x: ", (int) pSiop->pSocl);
  2873.     printf ("Socl    = 0x%02x ", *pSiop->pSocl); 
  2874.     printf ("Sodl    = 0x%02x ", *pSiop->pSodl); 
  2875.     printf ("Sxfer   = 0x%02x ", *pSiop->pSxfer); 
  2876.     printf ("Scid    = 0x%02xn", *pSiop->pScid); 
  2877.     printf ("0x%08x: ", (int) pSiop->pSbcl);
  2878.     printf ("Sbcl    = 0x%02x ", *pSiop->pSbcl); 
  2879.     printf ("Sbdl    = 0x%02x ", *pSiop->pSbdl); 
  2880.     printf ("Sidl    = 0x%02x ", *pSiop->pSidl); 
  2881.     printf ("Sfbr    = 0x%02xn", *pSiop->pSfbr); 
  2882.     printf ("0x%08x: ", (int) pSiop->pSstat2);
  2883.     printf ("Sstat2  = 0x%02x ", *pSiop->pSstat2); 
  2884.     printf ("Sstat1  = 0x%02x ", *pSiop->pSstat1); 
  2885.     printf ("Sstat0  = 0x%02x ", *pSiop->pSstat0); 
  2886.     printf ("Dstat   = 0x%02xn", *pSiop->pDstat); 
  2887.     printf ("0x%08x: ", (int) pSiop->pDsa);
  2888.     printf ("Dsa     = 0x%08xn", *pSiop->pDsa); 
  2889.     /* read fifo is not a good idea */
  2890.     printf ("0x%08x: ", (int) pSiop->pCtest3);
  2891.     printf ("Ctest3  = ???? "); 
  2892.     printf ("Ctest2  = 0x%02x ", *pSiop->pCtest2); 
  2893.     printf ("Ctest1  = 0x%02x ", *pSiop->pCtest1); 
  2894.     printf ("Ctest0  = 0x%02xn", *pSiop->pCtest0); 
  2895.     printf ("0x%08x: ", (int) pSiop->pCtest7);
  2896.     printf ("Ctest7  = 0x%02x ", *pSiop->pCtest7); 
  2897.     /* read fifo is not a good idea */
  2898.     printf ("Ctest6  = ???? "); 
  2899.     printf ("Ctest5  = 0x%02x ", *pSiop->pCtest5); 
  2900.     printf ("Ctest4  = 0x%02xn", *pSiop->pCtest4); 
  2901.     printf ("0x%08x: ", (int) pSiop->pTemp);
  2902.     printf ("Temp    = 0x%08xn", *pSiop->pTemp); 
  2903.     printf ("0x%08x: ", (int) pSiop->pLcrc);
  2904.     printf ("Lcrc    = 0x%02x ", *pSiop->pLcrc); 
  2905.     printf ("Ctest8  = 0x%02x ", *pSiop->pCtest8); 
  2906.     printf ("Istat   = 0x%02x ", *pSiop->pIstat); 
  2907.     printf ("Dfifo   = 0x%02xn", *pSiop->pDfifo); 
  2908.     printf ("0x%08x: ", (int) pSiop->pDbc);
  2909.     printf ("Dcmd/Ddc= 0x%08xn", *pSiop->pDbc); 
  2910.     printf ("0x%08x: ", (int) pSiop->pDnad);
  2911.     printf ("Dnad    = 0x%08xn", *pSiop->pDnad); 
  2912.     printf ("0x%08x: ", (int) pSiop->pDsp);
  2913.     printf ("Dsp     = 0x%08xn", *pSiop->pDsp); 
  2914.     printf ("0x%08x: ", (int) pSiop->pDsps);
  2915.     printf ("Dsps    = 0x%08xn", *pSiop->pDsps); 
  2916.     printf ("0x%08x: ", (int) pSiop->pScratch0);
  2917.     printf ("Scratch3= 0x%02x ", *pSiop->pScratch3); 
  2918.     printf ("Scratch2= 0x%02x ", *pSiop->pScratch2); 
  2919.     printf ("Scratch1= 0x%02x ", *pSiop->pScratch1); 
  2920.     printf ("Scratch0= 0x%02xn", *pSiop->pScratch0); 
  2921.     printf ("0x%08x: ", (int) pSiop->pDcntl);
  2922.     printf ("Dcntl   = 0x%02x ", *pSiop->pDcntl); 
  2923.     printf ("Dwt     = 0x%02x ", *pSiop->pDwt); 
  2924.     printf ("Dien    = 0x%02x ", *pSiop->pDien); 
  2925.     printf ("Dmode   = 0x%02xn", *pSiop->pDmode); 
  2926.     printf ("0x%08x: ", (int) pSiop->pAdder);
  2927.     printf ("Adder   = 0x%08xn", *pSiop->pAdder); 
  2928.     return (OK);
  2929.     }
  2930. /*******************************************************************************
  2931. *
  2932. * ncr710ResetATN - Resets the ATN signal
  2933. *
  2934. * This routine resets the ATN line for the give controller
  2935. *
  2936. * RETURNS : N/A
  2937. */
  2938. LOCAL void ncr710ResetATN ( FAST SCSI_CTRL *pScsiCtrl )
  2939.     {
  2940.     FAST SIOP       *pSiop;         /* prt to SIOP info */
  2941.     pSiop = (SIOP *) pScsiCtrl;
  2942.         
  2943.     *pSiop->pSocl &= (UINT8)0xf7;
  2944.     }