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

VxWorks

开发平台:

C/C++

  1. /* templateScsi2.c - Template for a SCSI-2 driver */
  2. /* Copyright 1989-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. TODO - Remove the template modification history and begin a new history
  8. starting with version 01a and growing the history upward with
  9. each revision.
  10. 01d,24sep97,dat  changed arguments to TEMPLATE_REG_READ.
  11. 01c,20aug97,dat  code review comments from Dinesh
  12. 01b,11aug97,dat  fixed compilation bugs.
  13. 01a,01aug97,dat  written (from ncr810Lib.c, ver 01p)
  14. */
  15. /*
  16. DESCRIPTION
  17. TODO - Describe the entire chip completely.  If this device is a part of
  18. a larger ASIC, describe the complete device in a single paragraph.
  19. TODO - Describe the device completely.  Describe all operating modes and
  20. capabilties, whether used or not.
  21. TODO - Describe the modes and limitations of this driver.  Describe how
  22. this driver interacts with the chip and any limitations imposed by the
  23. software.  If this driver interacts with other drivers, describe that
  24. interaction.
  25. TODO - Update the remainder of this documentation to reflect your new
  26. driver code.
  27. For each controller device we create a manager task to manage the threads
  28. on each bus.
  29. This driver supports multiple initiators, disconnect/reconnect, tagged
  30. command queueing and synchronous data transfer protocol.  In general, the
  31. SCSI system and this driver will automatically choose the best combination
  32. of these features to suit the target devices used.  However, the default
  33. choices may be over-ridden by using the function "scsiTargetOptionsSet()"
  34. (see scsiLib).
  35. USER-CALLABLE ROUTINES
  36. Most of the routines in this driver are accessible only through the I/O
  37. system.  Three routines, however, must be called directly:
  38. templateCtrlCreate() to create a controller structure, and templateCtrlInit()
  39. to initialize it.
  40. There are debug variables to trace events in the driver.
  41. <scsiDebug> scsiLib debug variable, trace event in scsiLib, scsiScsiPhase(),
  42. and scsiTransact().
  43. <scsiIntsDebug> prints interrupt information.
  44. The macro SCSI_DEBUG_MSG(format,...) can be used to insert debugging
  45. messages anywhere in the code.  The debug messages will appear only when
  46. the global variable scsiDebug is set to a non-zero value.
  47. INTERFACE
  48. The BSP must connect the interrupt service routine for the controller device
  49. to the appropriate interrupt system.  The routine to be called is
  50. templateIntr(), and the argument is the pointer to the controller device pSiop.
  51. i.e.
  52. .CS
  53.     pSiop = templateCtrlCreate (...);
  54.     intConnect (XXXX, templateIntr, pSiop);
  55.     templateCtrlInit (pSiop, ...);
  56. .CE
  57. HARDWARE ACCESS
  58. All hardware access is to be done through macros.  The default definition
  59. of the TEMPLATE_REG_READ() and TEMPLATE_REG_WRITE() macros assumes a
  60. memory mapped i/o model.  The macros can be redefined as necessary to 
  61. accomodate other models, and situations where timing and write pipe
  62. considerations need to be addressed.
  63. The macro TEMPLATE_REG_READ(pDev, reg,result) is used to read a
  64. byte from a specified register.  The three arguments are the device structure
  65. pointer, the register id (element of the dev structure), 
  66. and the variable (not a pointer) to receive the register contents.
  67. (If the third argument were a pointer, then it would affect compiler
  68. optimization and could lead to inefficient code generation).
  69. The macro TEMPLATE_REG_WRITE(pDev, reg,data) is used to write data to the
  70. specified register address.  These macros presume memory mapped i/o by
  71. default.  Both macros can be redefined to tailor the driver to some other
  72. i/o model.
  73. INCLUDE FILES
  74. scsiLib.h
  75. */
  76. #define INCLUDE_SCSI2 /* This is a SCSI2 driver */
  77. #include "vxWorks.h"
  78. #include "memLib.h"
  79. #include "ctype.h"
  80. #include "stdlib.h"
  81. #include "string.h"
  82. #include "stdio.h"
  83. #include "logLib.h"
  84. #include "semLib.h"
  85. #include "intLib.h"
  86. #include "errnoLib.h"
  87. #include "cacheLib.h"
  88. #include "taskLib.h"
  89. #include "scsiLib.h"
  90. /* defines */
  91. /* state enumeration, different hardware states for the controller */
  92. typedef enum templateState /* TEMPLATE_STATE */
  93.     {
  94.     TEMPLATE_STATE_IDLE = 0, /* not running any script            */
  95.     TEMPLATE_STATE_PASSIVE, /* waiting for reselect or host cmd  */
  96.     TEMPLATE_STATE_ACTIVE /* running a client script           */
  97.     } TEMPLATE_STATE;
  98. /* Hardware specific events, supplements the SCSI_EVENT types */
  99. typedef enum templateEvent /* TEMPLATE_EVENT_TYPE, hardware events */
  100.     {
  101.     TEMPLATE_SINGLE_STEP=30, /* don't conflict with SCSI_EVENTS */
  102.     TEMPLATE_ABORT,
  103.     TEMPLATE_UNEXPECTED_DISCON,
  104.     TEMPLATE_SCSI_TIMEOUT,
  105.     TEMPLATE_HANDSHAKE_TIMEOUT,
  106.     TEMPLATE_PHASE_MISMATCH,
  107.     TEMPLATE_SCRIPT_ABORTED,
  108.     TEMPLATE_SCSI_COMPLETE,
  109.     TEMPLATE_FATAL_ERROR,
  110.     TEMPLATE_MESSAGE_OUT_SENT,
  111.     TEMPLATE_MESSAGE_IN_RECVD,
  112.     TEMPLATE_NO_MSG_OUT,
  113.     TEMPLATE_EXT_MESSAGE_SIZE,
  114.     TEMPLATE_ILLEGAL_PHASE,
  115.     } TEMPLATE_EVENT_TYPE;
  116. /* identifiers for the different hardware scripts the device can execute */
  117. typedef enum templateScriptEntry /* TEMPLATE_SCRIPT_ENTRY */
  118.     {
  119.     TEMPLATE_SCRIPT_WAIT           = 0, /* wait for re-select or host cmd */
  120.     TEMPLATE_SCRIPT_INIT_START     = 1, /* start an initiator thread      */
  121.     TEMPLATE_SCRIPT_INIT_CONTINUE  = 2, /* continue an initiator thread   */
  122.     TEMPLATE_SCRIPT_TGT_DISCONNECT = 3 /* disconnect a target thread     */
  123.     } TEMPLATE_SCRIPT_ENTRY;
  124. /* The expanded EVENT structure, with add'l device specific info */
  125. typedef struct {  /* TEMPLATE_EVENT, extended EVENT type */
  126.     SCSI_EVENT scsiEvent;
  127.     int remCount;
  128.     } TEMPLATE_EVENT;
  129. /* The expanded THREAD structure, with add'l device specific info */
  130. typedef struct templateThread /* TEMPLATE_THREAD, extended thread type */
  131.     {
  132.     SCSI_THREAD scsiThread; /* generic SCSI thread structure */
  133.     /* TODO - add device specific thread info */
  134.     UINT8 nHostFlags; /* DUMMY information */
  135.     UINT8 nMsgOutState; /* DUMMY information */
  136.     UINT8 nMsgInState; /* DUMMY information */
  137.     UINT8 nBusIdBits; /* DUMMY information */
  138.     UINT8 nBusPhase; /* DUMMY information */
  139.     } TEMPLATE_THREAD;
  140. /* The expanded SCSI_CTRL structure with add'l device specific info */
  141. typedef struct { /* TEMPLATE_SCSI_CTRL */
  142.     SCSI_CTRL scsiCtrl;         /* generic SCSI controller info */
  143.     /* TODO - add device specific information */
  144.     SEM_ID    singleStepSem; /* use to debug script in single step mode */
  145.     
  146.     /* Hardware implementation dependencies */
  147.     TEMPLATE_THREAD* pIdentThread;
  148.     TEMPLATE_THREAD* pNewThread;/* DUMMY */
  149.     TEMPLATE_THREAD* pHwThread; /* DUMMY */
  150.     TEMPLATE_STATE   state; /* DUMMY */
  151.     UCHAR*           pCmd; /* DUMMY Device command/status register */
  152.     int   devType; /* DUMMY type of device (see define's below) */
  153.     BOOL  resetReportDsbl; /* DUMMY disable SCSI bus reset reporting */
  154.     BOOL  parityTestMode; /* DUMMY enable parity test mode */
  155.     BOOL  parityCheckEnbl; /* DUMMY to enable parity checking */
  156.     UINT  clkPeriod;      /* DUMMY period of ctrl clock (nsec x 100) */
  157.     UINT8 clkDiv; /* DUMMY async and sync clock divider */
  158.     BOOL  cmdPending; /* DUMMY task wants to start new command */
  159.     BOOL  singleStep; /* DUMMY single step mode */
  160.     } TEMPLATE_SCSI_CTRL;
  161. typedef TEMPLATE_SCSI_CTRL SIOP; /* shorthand */
  162. /* Hardware Abstraction macros hide all actual access to the chip */
  163. #define TEMPLATE_REG_READ(pSiop, reg, result) 
  164. ((result) = *(pSiop->reg)
  165. #define TEMPLATE_REG_WRITE(pSiop, reg, data) 
  166. (*pSiop->reg = data)
  167. /* Other miscellaneous defines */
  168. #define TEMPLATE_MAX_XFER_WIDTH 1 /* 16 bit wide transfer */
  169. #define TEMPLATE_MAX_XFER_LENGTH 0xffffff /* 16MB max transfer */
  170. /* Configurable options, scsi manager task */
  171. int   templateSingleStepSemOptions = SEM_Q_PRIORITY;
  172. char* templateScsiTaskName         = SCSI_DEF_TASK_NAME;
  173. int   templateScsiTaskOptions      = SCSI_DEF_TASK_OPTIONS;
  174. int   templateScsiTaskPriority     = SCSI_DEF_TASK_PRIORITY;
  175. int   templateScsiTaskStackSize    = SCSI_DEF_TASK_STACK_SIZE;
  176. /* forward declarations */
  177. LOCAL STATUS templateThreadActivate (SIOP* pSiop, TEMPLATE_THREAD* pThread);
  178. LOCAL void templateEvent (SIOP* pSiop, TEMPLATE_EVENT* pEvent);
  179. LOCAL STATUS templateThreadInit (SIOP* pSiop, TEMPLATE_THREAD* pThread);
  180. LOCAL STATUS templateThreadActivate (SIOP* pSiop, TEMPLATE_THREAD* pThread);
  181. LOCAL BOOL templateThreadAbort (SIOP* pSiop, TEMPLATE_THREAD* pThread);
  182. LOCAL STATUS templateScsiBusControl (SIOP* pSiop, int operation);
  183. LOCAL STATUS templateXferParamsQuery (SCSI_CTRL* pScsiCtrl, UINT8* pOffset,
  184. UINT8* pPeriod);
  185. LOCAL STATUS templateXferParamsSet (SCSI_CTRL* pScsiCtrl, UINT8 offset,
  186. UINT8 period);
  187. LOCAL STATUS templateWideXferParamsQuery (SCSI_CTRL* pScsiCtrl,
  188. UINT8* xferWidth);
  189. LOCAL STATUS templateWideXferParamsSet (SCSI_CTRL* pScsiCtrl, UINT8 xferWidth);
  190. LOCAL void templateScriptStart (SIOP* pSiop, TEMPLATE_THREAD* pThread,
  191. TEMPLATE_SCRIPT_ENTRY entryId);
  192. LOCAL int templateEventTypeGet (SIOP* pSiop);
  193. LOCAL STATUS templateThreadParamsSet (TEMPLATE_THREAD*, UINT8, UINT8);
  194. LOCAL STATUS templateActivate (SIOP* pSiop, TEMPLATE_THREAD* pThread);
  195. LOCAL void templateThreadStateSet (TEMPLATE_THREAD* pThread,
  196. SCSI_THREAD_STATE state);
  197. LOCAL void templateAbort (SIOP* pSiop);
  198. LOCAL void templateThreadEvent (TEMPLATE_THREAD* pThread, 
  199. TEMPLATE_EVENT* pEvent);
  200. LOCAL void templateInitEvent (TEMPLATE_THREAD* pThread,
  201. TEMPLATE_EVENT*  pEvent);
  202. LOCAL void templateThreadUpdate (TEMPLATE_THREAD* pThread);
  203. LOCAL void templateInitIdentEvent(TEMPLATE_THREAD* pThread,
  204. TEMPLATE_EVENT* pEvent);
  205. LOCAL void templateIdentInContinue (TEMPLATE_THREAD *pThread);
  206. LOCAL STATUS templateResume (SIOP* pSiop, TEMPLATE_THREAD* pThread,
  207.     TEMPLATE_SCRIPT_ENTRY entryId);
  208. LOCAL void templateThreadFail (TEMPLATE_THREAD* pThread, int errNum);
  209. LOCAL void templateThreadComplete (TEMPLATE_THREAD* pThread);
  210. LOCAL void templateThreadDefer (TEMPLATE_THREAD* pThread);
  211. LOCAL STATUS templatePhaseMismatch (TEMPLATE_THREAD* pThread, int phase,
  212. UINT remCount);
  213. LOCAL void templateThreadReconnect (TEMPLATE_THREAD* pThread);
  214. /*******************************************************************************
  215. *
  216. * templateCtrlCreate - create a structure for a TEMPLATE device
  217. *
  218. * This routine creates a SCSI Controller data structure and must be called 
  219. * before using an SCSI Controller chip.  It should be called once and only 
  220. * once for a specified SCSI Controller controller. Since it allocates memory
  221. * for a structure needed by all routines in templateLib, it must be called
  222. * before any other routines in the library. After calling this routine,
  223. * templateCtrlInit() should be called at least once before any SCSI
  224. * transactions are initiated using the SCSI Controller.
  225. *
  226. * RETURNS: A pointer to TEMPLATE_SCSI_CTRL structure, or NULL if memory 
  227. * is unavailable or there are invalid parameters.
  228. */
  229. TEMPLATE_SCSI_CTRL *templateCtrlCreate 
  230.     (
  231.     /* TODO - This argument list is device specific information */
  232.     UINT8* baseAdrs, /* DUMMY, base address of the SCSI Controller */
  233.     UINT   clkPeriod, /* DUMMY, clock controller period (nsec*100) */
  234.     UINT16 devType /* DUMMY, SCSI device type */
  235.     )
  236.     {
  237.     FAST SIOP *pSiop;     /* ptr to SCSI Controller info */
  238.     SCSI_CTRL *pScsiCtrl;
  239.     
  240.     /* TODO - cacheDmaMalloc the controller struct and any shared data areas */
  241.     pScsiCtrl = &(pSiop->scsiCtrl);
  242.     /* fill in generic SCSI info for this controller */
  243.     pScsiCtrl->eventSize     = sizeof (TEMPLATE_EVENT);
  244.     pScsiCtrl->threadSize     = sizeof (TEMPLATE_THREAD);
  245.     pScsiCtrl->maxBytesPerXfer     = TEMPLATE_MAX_XFER_LENGTH;
  246.     pScsiCtrl->wideXfer     = FALSE;
  247.     pScsiCtrl->scsiTransact     = (FUNCPTR)    scsiTransact;
  248.     pScsiCtrl->scsiEventProc       = (VOIDFUNCPTR) templateEvent;
  249.     pScsiCtrl->scsiThreadInit      = (FUNCPTR)     templateThreadInit;
  250.     pScsiCtrl->scsiThreadActivate  = (FUNCPTR)     templateThreadActivate;
  251.     pScsiCtrl->scsiThreadAbort     = (FUNCPTR)     templateThreadAbort;
  252.     pScsiCtrl->scsiBusControl      = (FUNCPTR)     templateScsiBusControl;
  253.     pScsiCtrl->scsiXferParamsQuery = (FUNCPTR)     templateXferParamsQuery;
  254.     pScsiCtrl->scsiXferParamsSet   = (FUNCPTR)     templateXferParamsSet;
  255.     pScsiCtrl->scsiWideXferParamsQuery = (FUNCPTR) templateWideXferParamsQuery;
  256.     pScsiCtrl->scsiWideXferParamsSet   = (FUNCPTR) templateWideXferParamsSet;
  257.     /* TODO - fill in device specific data for this controller */
  258.     scsiCtrlInit (pScsiCtrl);
  259.     /* Create synchronisation semaphore for single-step support  */
  260.     pSiop->singleStepSem = semBCreate (templateSingleStepSemOptions, SEM_EMPTY);
  261.     /* TODO - Initialize fields in any client shared data area */
  262.     /* spawn SCSI manager - use generic code from "scsiLib.c" */
  263.     pScsiCtrl->scsiMgrId = taskSpawn (templateScsiTaskName,
  264.                    templateScsiTaskPriority,
  265.                    templateScsiTaskOptions,
  266.                    templateScsiTaskStackSize,
  267.                    (FUNCPTR) scsiMgr,
  268.                    (int) pSiop, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  269.     
  270.     return (pSiop);
  271.     }
  272. /*******************************************************************************
  273. *
  274. * templateCtrlInit - initialize a SCSI Controller Structure.
  275. *
  276. * This routine initializes an  SCSI Controller structure, after the structure
  277. * is created with templateCtrlCreate().  This structure must be initialized
  278. * before the SCSI Controller can be used.  It may be called more than once
  279. * if needed; however,it should only be called while there is no activity on
  280. * the SCSI interface.
  281. *
  282. * RETURNS: OK, or ERROR if parameters are out of range.
  283. */
  284. STATUS templateCtrlInit
  285.     (
  286.     SIOP* pSiop, /* ptr to SCSI Controller struct */
  287.     int scsiCtrlBusId /* SCSI bus ID of this SCSI Controller */
  288.     )
  289.     {
  290.     SCSI_CTRL* pScsiCtrl = &pSiop->scsiCtrl;
  291.     pScsiCtrl->scsiCtrlBusId = scsiCtrlBusId;
  292.     /* TODO - Initialise and reset the SCSI Controller */
  293.     templateScriptStart (pSiop, (TEMPLATE_THREAD *)pScsiCtrl->pIdentThread,
  294. TEMPLATE_SCRIPT_WAIT);
  295.     pSiop->state = TEMPLATE_STATE_PASSIVE;
  296.     return (OK);
  297.     }
  298. /*******************************************************************************
  299. *
  300. * templateIntr - interrupt service routine for the SCSI Controller
  301. *
  302. * The first thing to determine is if the device is generating an interrupt.
  303. * If not, then this routine must exit as quickly as possible.
  304. *
  305. * Find the event type corresponding to this interrupt, and carry out any
  306. * actions which must be done before the SCSI Controller is re-started.  
  307. * Determine  whether or not the SCSI Controller is connected to the bus 
  308. * (depending on the event type - see note below).  If not, start a client 
  309. * script if possible or else just make the SCSI Controller wait for something 
  310. * else to happen.
  311. *
  312. * Notify the SCSI manager of a controller event.
  313. *
  314. * RETURNS: N/A
  315. */
  316. void templateIntr
  317.     (
  318.     SIOP *pSiop
  319.     )
  320.     {
  321.     TEMPLATE_EVENT event;
  322.     SCSI_EVENT* pScsiEvent = (SCSI_EVENT *) &event.scsiEvent;
  323.     BOOL  connected = TRUE;
  324.     BOOL  notify    = TRUE;
  325.     TEMPLATE_STATE   oldState  = (int) pSiop->state;
  326.     /* TODO - If device is not interrupting, then return immediately */
  327.     /* TODO - Save (partial) Controller register context in current thread */
  328.     pScsiEvent->type = templateEventTypeGet (pSiop);
  329.     /* Synchronise with single-step routine, if enabled. */
  330.     if (pSiop->singleStep)
  331.      semGive (pSiop->singleStepSem);
  332.     if (pScsiEvent->type == TEMPLATE_SINGLE_STEP)
  333. return;
  334.     
  335.     switch (pScsiEvent->type)
  336. {
  337. /*
  338.  * TODO - 
  339.  * For events where the bus is not connected to a target,
  340.  * set connected=FALSE.
  341.  *
  342.  * For events not requiring scsi manager, set notify = FALSE.
  343.  */
  344. /* Generic event types */
  345. case SCSI_EVENT_SELECTED:
  346. case SCSI_EVENT_RESELECTED:
  347. case SCSI_EVENT_DISCONNECTED:
  348. case SCSI_EVENT_BUS_RESET:
  349. /* device specific events */
  350. case TEMPLATE_ABORT:
  351. case TEMPLATE_UNEXPECTED_DISCON:
  352. case TEMPLATE_SCSI_TIMEOUT:
  353. case TEMPLATE_HANDSHAKE_TIMEOUT:
  354. case TEMPLATE_PHASE_MISMATCH:
  355. case TEMPLATE_SCRIPT_ABORTED:
  356. case TEMPLATE_SCSI_COMPLETE:
  357. case TEMPLATE_SINGLE_STEP:
  358. case TEMPLATE_FATAL_ERROR:
  359. default:
  360.     connected = TRUE;
  361.     notify = TRUE;
  362. }
  363.     /*
  364.      *  Controller is now idle: if possible, make it run a script.
  365.      *
  366.      * If a SCSI thread is suspended and must be processed at task-level,
  367.      * leave the device idle.  It will be re-started by the SCSI manager
  368.      * calling "templateResume()".
  369.      *
  370.      * Otherwise, if there's a new SCSI thread to start (i.e., the SCSI
  371.      * manager has called "threadActivate()"), start the appropriate script.
  372.      *
  373.      * Otherwise, start a script which puts the device into passive mode
  374.      * waiting for re-selection, selection or a host command.
  375.      *
  376.      * In all cases, clear any request to start a new thread.  The only
  377.      * tricky case is when there was a request pending and the device is
  378.      * left IDLE.  This should only ever occur when the current event is
  379.      * selection or reselection, in which case the SCSI manager will retry
  380.      * the activation request.  (Also see "templateActivate ()".)
  381.      */
  382.     if (connected)
  383. {
  384.      pSiop->state = TEMPLATE_STATE_IDLE;
  385. }
  386.     else if (pSiop->cmdPending)
  387. {
  388. templateScriptStart (pSiop, pSiop->pNewThread,
  389.    TEMPLATE_SCRIPT_INIT_START);
  390. pSiop->state = TEMPLATE_STATE_ACTIVE;
  391. }
  392.     else
  393. {
  394. templateScriptStart (pSiop, pSiop->pIdentThread,
  395.    TEMPLATE_SCRIPT_WAIT);
  396. pSiop->state = TEMPLATE_STATE_PASSIVE;
  397. }
  398.     pSiop->cmdPending = FALSE;
  399.     SCSI_INT_DEBUG_MSG ("templateIntr: state %d -> %dn",
  400. oldState, pSiop->state, 0, 0, 0, 0);
  401.     /* Send the event to the SCSI manager to be processed. */
  402.     if (notify)
  403.      scsiMgrEventNotify ((SCSI_CTRL *) pSiop, pScsiEvent, sizeof (event));
  404.     }
  405. /*******************************************************************************
  406. *
  407. * templateEvent - SCSI Controller event processing routine
  408. *
  409. * Parse the event type and act accordingly.  Controller-level events are
  410. * handled within this function, and the event is then passed to the current
  411. * thread (if any) for thread-level processing.
  412. *
  413. * RETURNS: N/A
  414. */
  415. LOCAL void templateEvent
  416.     (
  417.     SIOP *         pSiop,
  418.     TEMPLATE_EVENT * pEvent
  419.     )
  420.     {
  421.     SCSI_CTRL  *    pScsiCtrl  = (SCSI_CTRL *)  pSiop;
  422.     SCSI_EVENT *    pScsiEvent = &pEvent->scsiEvent;
  423.     TEMPLATE_THREAD * pThread    = (TEMPLATE_THREAD *) pScsiCtrl->pThread;
  424.  
  425.     SCSI_DEBUG_MSG ("templateEvent: received event %d (thread = 0x%08x)n",
  426.     pScsiEvent->type, (int) pThread, 0, 0, 0, 0);
  427.     /* Do controller-level event processing */
  428.     switch (pScsiEvent->type)
  429. {
  430. case SCSI_EVENT_SELECTED:
  431. case SCSI_EVENT_RESELECTED:
  432.     /*
  433.      * Forward event to current thread, if any (it should defer)
  434.      * then install a reserved thread for identification purposes.
  435.      */
  436.          if (pThread != 0)
  437.      templateThreadEvent (pThread, pEvent);
  438.          pScsiCtrl->peerBusId = pScsiEvent->busId;
  439.          pScsiCtrl->pThread = pScsiCtrl->pIdentThread;
  440.     
  441.     pScsiCtrl->pThread->role = (pScsiEvent->type == SCSI_EVENT_SELECTED)
  442.                ? SCSI_ROLE_IDENT_TARG
  443.      : SCSI_ROLE_IDENT_INIT;
  444.     pThread = (TEMPLATE_THREAD *) pScsiCtrl->pThread;
  445.     scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_CONNECTED);
  446.     break;
  447. case SCSI_EVENT_DISCONNECTED:
  448. case TEMPLATE_SCSI_COMPLETE:
  449. case TEMPLATE_UNEXPECTED_DISCON:
  450. case TEMPLATE_SCSI_TIMEOUT:
  451.          pScsiCtrl->peerBusId = NONE;
  452.          pScsiCtrl->pThread   = 0;
  453.     scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_DISCONNECTED);
  454.     
  455.     break;
  456. case SCSI_EVENT_BUS_RESET:
  457.          pScsiCtrl->peerBusId = NONE;
  458.          pScsiCtrl->pThread   = 0;
  459.          scsiMgrBusReset (pScsiCtrl);
  460.     break;
  461. default:
  462.     /*
  463.      * Any other event type is assumed to be thread-specific.
  464.      * The thread event handler will report an error if it's
  465.      * not a valid type.
  466.      */
  467.     if (pThread == 0)
  468. {
  469.      logMsg ("templateEvent: invalid event type (%d)n",
  470.      pScsiEvent->type, 0, 0, 0, 0, 0);
  471. }
  472.     break;
  473. }
  474.     /* If there's a thread on the controller, forward the event to it */
  475.     if (pThread != 0)
  476. templateThreadEvent (pThread, pEvent);
  477.     }
  478.     
  479. /*******************************************************************************
  480. *
  481. * templateThreadInit - initialize a client thread structure
  482. *
  483. * Initialize the fixed data for a thread (i.e., independent of the command).
  484. * Called once when a thread structure is first created.
  485. *
  486. * RETURNS: OK, or ERROR if an error occurs
  487. */
  488. LOCAL STATUS templateThreadInit
  489.     (
  490.     SIOP *          pSiop,
  491.     TEMPLATE_THREAD * pThread
  492.     )
  493.     {
  494.     scsiThreadInit (&pThread->scsiThread);
  495.     /* TODO - device specific thread initialization */
  496.     return (OK);
  497.     }
  498. /*******************************************************************************
  499. *
  500. * templateThreadActivate - activate a SCSI connection for an initiator thread
  501. *
  502. * Set whatever thread/controller state variables need to be set.  Ensure that
  503. * all buffers used by the thread are coherent with the contents of the
  504. * system caches (if any).
  505. *
  506. * Set transfer parameters for the thread based on what its target device
  507. * last negotiated.
  508. *
  509. * Update the thread context (including shared memory area) and note that
  510. * there is a new client script to be activated (see "templateActivate()").
  511. *
  512. * Set the thread's state to ESTABLISHED.
  513. * Do not wait for the script to be activated.  Completion of the script will
  514. * be signalled by an event which is handled by "templateEvent()".
  515. *
  516. * RETURNS: OK or ERROR
  517. */
  518. LOCAL STATUS templateThreadActivate
  519.     (
  520.     SIOP *          pSiop, /* ptr to controller info */
  521.     TEMPLATE_THREAD * pThread /* ptr to thread info     */
  522.     )
  523.     {
  524.     SCSI_CTRL *   pScsiCtrl   = (SCSI_CTRL *)   pSiop;
  525.     SCSI_THREAD * pScsiThread = &pThread->scsiThread;
  526.     SCSI_TARGET * pScsiTarget = pScsiThread->pScsiTarget;
  527.     
  528.     SCSI_DEBUG_MSG ("templateThreadActivate: thread 0x%08x: activatingn",
  529.     (int) pThread, 0, 0, 0, 0, 0);
  530.     scsiCacheSynchronize (pScsiThread, SCSI_CACHE_PRE_COMMAND);
  531.     /* Reset controller state variables: set sync xfer parameters */
  532.     pScsiCtrl->msgOutState = SCSI_MSG_OUT_NONE;
  533.     pScsiCtrl->msgInState  = SCSI_MSG_IN_NONE;
  534.     
  535.     /*
  536.      * A wide transfer is initiated before a synchronous transfer. However,
  537.      * when a wide transfer has been done the next activation causes the
  538.      * synchronous transfer to be activated. Another possible but more
  539.      * complicated way to implement this would be to have both wide and
  540.      * synchronous negotiations in the same activation or thread i.e.
  541.      * the same SCSI transaction.
  542.      */
  543.     scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, WIDE_XFER_NEW_THREAD);
  544.     scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_NEW_THREAD);
  545.     if (templateThreadParamsSet (pThread, pScsiTarget->xferOffset,
  546.               pScsiTarget->xferPeriod) != OK)
  547. {
  548. SCSI_ERROR_MSG ("templateThreadActivate: failed to set thread " 
  549. "params.n", 0, 0, 0, 0, 0, 0);
  550. return (ERROR);
  551. }
  552.     /* Update thread context; activate the thread */
  553.     templateThreadUpdate (pThread);
  554.     
  555.     if (templateActivate (pSiop, pThread) != OK)
  556. {
  557. SCSI_ERROR_MSG ("templateThreadActivate: failed to activate thread.n",
  558.         0, 0, 0, 0, 0, 0);
  559. return (ERROR);
  560. }
  561.     pScsiCtrl->pThread = pScsiThread;
  562.     templateThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED);
  563.     
  564.     return (OK);
  565.     }
  566. /*******************************************************************************
  567. *
  568. * templateThreadAbort - abort a thread
  569. *
  570. * If the thread is not currently connected, do nothing and return FALSE to
  571. * indicate that the SCSI manager should abort the thread.
  572. *
  573. * RETURNS: TRUE if the thread is being aborted by this driver (i.e. it is
  574. * currently active on the controller, else FALSE.
  575. */
  576. LOCAL BOOL templateThreadAbort
  577.     (
  578.     SIOP *          pSiop, /* ptr to controller info */
  579.     TEMPLATE_THREAD * pThread /* ptr to thread info     */
  580.     )
  581.     {
  582.     BOOL          tagged;
  583.     SCSI_CTRL *   pScsiCtrl   = (SCSI_CTRL *)   pSiop;
  584.     SCSI_THREAD * pScsiThread = &pThread->scsiThread;
  585.     SCSI_DEBUG_MSG ("templateThreadAbort: thread 0x%08x (state = %d) "
  586.     "abortingn", (int)pThread, pScsiThread->state, 0, 0, 0, 0);
  587.     if (pScsiThread != pScsiCtrl->pThread)
  588. return (FALSE);
  589.     
  590.     switch (pScsiThread->state)
  591. {
  592. case SCSI_THREAD_INACTIVE:
  593. case SCSI_THREAD_WAITING:
  594. case SCSI_THREAD_DISCONNECTED:
  595.     return (FALSE);
  596.     break;
  597. default:
  598.     /*
  599.      * Build an ABORT (or ABORT TAG) message.  When this has been
  600.      * sent, the target should disconnect.  Mark the thread aborted
  601.      * and continue until disconnection.
  602.      */
  603.     tagged = (pScsiThread->tagNumber != NONE);
  604.     pScsiCtrl->msgOutBuf[0] = tagged ? SCSI_MSG_ABORT_TAG
  605.                     : SCSI_MSG_ABORT;
  606.     pScsiCtrl->msgOutLength = 1;
  607.     pScsiCtrl->msgOutState  = SCSI_MSG_OUT_PENDING;
  608.     templateAbort (pSiop);
  609.          templateThreadStateSet (pThread, SCSI_THREAD_ABORTING);
  610.     break;
  611. }
  612.     return (TRUE);
  613.     }
  614. /*******************************************************************************
  615. *
  616. * templateScsiBusControl - miscellaneous low-level SCSI bus control operations
  617. *
  618. * Currently supports only the SCSI_BUS_RESET operation; other operations are
  619. * not used explicitly by the driver because they are carried out automatically
  620. * by the script program.
  621. *
  622. * NOTE: after the SCSI bus has been reset, we expect the device
  623. * to create a TEMPLATE_BUS_RESET event to be sent to the SCSI manager.
  624. * See "templateIntr()".
  625. *
  626. * RETURNS: OK, or ERROR if an invalid operation is requested.
  627. *
  628. * NOMANUAL
  629. */
  630. LOCAL STATUS templateScsiBusControl
  631.     (
  632.     SIOP * pSiop,        /* ptr to controller info                   */
  633.     int    operation     /* bitmask for operation(s) to be performed */
  634.     )
  635.     {
  636.     if (operation & SCSI_BUS_RESET)
  637. {
  638. /* TODO - assert & deassert the RST line */
  639. return OK;
  640. }
  641.     return ERROR; /* unknown operation */
  642.     }
  643. /*******************************************************************************
  644. *
  645. * templateXferParamsQuery - get synchronous transfer parameters
  646. *
  647. * Updates the synchronous transfer parameters suggested in the call to match
  648. * the TEMPLATE SCSI Controller's capabilities.  Transfer period is in SCSI units
  649. * (multiples * of 4 ns).
  650. *
  651. * RETURNS: OK
  652. */
  653. LOCAL STATUS templateXferParamsQuery
  654.     (
  655.     SCSI_CTRL *pScsiCtrl, /* ptr to controller info       */
  656.     UINT8     *pOffset, /* max REQ/ACK offset  [in/out] */
  657.     UINT8     *pPeriod /* min transfer period [in/out] */
  658.     )
  659.     {
  660.     /* TODO - alter the offset and period variables to acceptable values */
  661.     return (OK);
  662.     }
  663.     
  664. /*******************************************************************************
  665. *
  666. * templateXferParamsSet - set transfer parameters
  667. *
  668. * Validate the requested parameters, convert to the TEMPLATE SCSI Controller's 
  669. * native format and save in the current thread for later use (the chip's
  670. * registers are not actually set until the next script activation for this 
  671. * thread).
  672. *
  673. * Transfer period is specified in SCSI units (multiples of 4 ns).  An offset
  674. * of zero specifies asynchronous transfer.
  675. *
  676. * RETURNS: OK if transfer parameters are OK, else ERROR.
  677. */
  678. LOCAL STATUS templateXferParamsSet
  679.     (
  680.     SCSI_CTRL *pScsiCtrl, /* ptr to controller info */
  681.     UINT8      offset, /* max REQ/ACK offset     */
  682.     UINT8      period /* min transfer period    */
  683.     )
  684.     {
  685.     return (templateThreadParamsSet ((TEMPLATE_THREAD*)pScsiCtrl->pThread,
  686.     offset, period));
  687.     }
  688. /*******************************************************************************
  689. *
  690. * templateWideXferParamsQuery - get wide data transfer parameters
  691. *
  692. * Updates the wide data transfer parameters suggested in the call to match
  693. * the TEMPLATE SCSI Controller's capabilities.  Transfer width is in the units 
  694. * of the WIDE DATA TRANSFER message's transfer width exponent field. This is
  695. * an 8 bit field where 0 represents a narrow transfer of 8 bits, 1 represents
  696. * a wide transfer of 16 bits and 2 represents a wide transfer of 32 bits.
  697. *
  698. * RETURNS: OK
  699. */
  700. LOCAL STATUS templateWideXferParamsQuery
  701.     (
  702.     SCSI_CTRL *pScsiCtrl, /* ptr to controller info       */
  703.     UINT8     *xferWidth /* suggested transfer width     */
  704.     )
  705.     {
  706.     if (*xferWidth > TEMPLATE_MAX_XFER_WIDTH)
  707. *xferWidth = TEMPLATE_MAX_XFER_WIDTH;
  708.     
  709.     templateWideXferParamsSet (pScsiCtrl, *xferWidth);
  710.     return (OK);
  711.     }
  712. /*******************************************************************************
  713. *
  714. * templateWideXferParamsSet - set wide transfer parameters
  715. *
  716. * Assume valid parameters and set the TEMPLATE's thread parameters to the
  717. * appropriate values. The actual registers are not written yet, but will
  718. * be written from the thread values when it is activated.
  719. *
  720. * Transfer width is specified in SCSI transfer width exponent units. 
  721. *
  722. * RETURNS: OK 
  723. */
  724. LOCAL STATUS templateWideXferParamsSet
  725.     (
  726.     SCSI_CTRL *pScsiCtrl, /* ptr to controller info */
  727.     UINT8      xferWidth  /* wide data transfer width */
  728.     )
  729.     {
  730.     /* TODO - update thread to enable/disable wide data xfers */
  731.     return OK;
  732.     }
  733. /*******************************************************************************
  734. *
  735. * templateThreadParamsSet - set various parameters for a thread
  736. *
  737. * Parameters include transfer offset and period, as well as the ID of the
  738. * target device.  All of these end up as encoded values stored either in
  739. * the thread's register context or its associated shared memory area.
  740. *
  741. * Transfer period is specified in SCSI units (multiples of 4 ns).  An offset
  742. * of zero specifies asynchronous transfer.
  743. *
  744. * RETURNS: OK if parameters are OK, else ERROR.
  745. *
  746. * NOMANUAL
  747. */
  748. LOCAL STATUS templateThreadParamsSet
  749.     (
  750.     TEMPLATE_THREAD * pThread,      /* thread to be affected  */
  751.     UINT8           offset, /* max REQ/ACK offset     */
  752.     UINT8           period /* min transfer period    */
  753.     )
  754.     {
  755.     /* TODO - setup synch/asynch control bits */
  756.     /* TODO - setup wide control bits */
  757.     /* TODO - update device control registers if needed */
  758.     return (OK);
  759.     }
  760. /******************************************************************************
  761. *
  762. * templateEventTypeGet - parse status registers at interrupt time
  763. *
  764. * This routine examines the device state to determine what type of event
  765. * is pending.  If none is pending then a fatal error code is returned.
  766. *
  767. * RETURNS: Returns an interrupt (event) type code or TEMPLATE_FATAL_ERROR.
  768. */
  769. LOCAL int templateEventTypeGet
  770.     (
  771.     SIOP * pSiop
  772.     )
  773.     {
  774.     int key;
  775.     /*
  776.      * We should be locked in interrupt context while the status
  777.      * registers are being read so that there is no contention between
  778.      * a synchronous thread and a bus initiated thread (reselect)
  779.      */
  780.     key = intLock (); 
  781.     /* TODO - Read and save device status registers */
  782.     intUnlock (key);
  783.     SCSI_INT_DEBUG_MSG ("templateEventTypeGet: n", 0, 0, 0, 0, 0, 0);
  784.     if (0) /* TODO - check for fatal error */
  785. return TEMPLATE_ABORT;
  786.     /* TODO - try the rest (NB order of tests can be important !) */
  787.     if  (0) /* TODO - check for SCSI Bus reset */
  788.         {
  789. SCSI_INT_DEBUG_MSG ("templateEventTypeGet: SCSI bus reset.n",
  790.     0, 0, 0, 0, 0, 0);
  791. /* TODO - clear FIFOs, etc. */
  792. return (SCSI_EVENT_BUS_RESET);
  793.         }
  794.      
  795.     if  (0) /* TODO - check for unexpected disconnect */
  796.         {
  797. SCSI_INT_DEBUG_MSG ("templateEventTypeGet: unexpected disconnection.n",
  798.     0, 0, 0, 0, 0, 0);
  799. /* TODO - clear FIFOs, etc. */
  800. return (TEMPLATE_UNEXPECTED_DISCON);
  801.         }
  802.     if (0) /* TODO - check for scsi bus timeout */
  803. {
  804.      SCSI_INT_DEBUG_MSG ("templateEventTypeGet: SCSI bus timeout.n",
  805.     0, 0, 0, 0, 0, 0);
  806. /* TODO - clear FIFOs, etc. */
  807. return (TEMPLATE_SCSI_TIMEOUT);
  808. }
  809.     if (0) /* TODO - check for SCSI handshake timeout */
  810. {
  811.      SCSI_INT_DEBUG_MSG ("templateEventTypeGet: SCSI handshake timeout.n",
  812.     0, 0, 0, 0, 0, 0);
  813. /* TODO - clear FIFOs, etc. */
  814. return (TEMPLATE_HANDSHAKE_TIMEOUT);
  815. }
  816.     if (0) /* TODO - check for phase mismatch condition */
  817.         {
  818. SCSI_INT_DEBUG_MSG ("templateEventTypeGet: phase mismatch.n",
  819. 0, 0, 0, 0, 0, 0);
  820. return (TEMPLATE_PHASE_MISMATCH);
  821.         }
  822.     
  823.     if (0) /* TODO - check for a script abort */
  824.         {
  825. SCSI_INT_DEBUG_MSG ("templateEventTypeGet: script aborted.n",
  826.          0, 0, 0, 0, 0, 0);
  827. return (TEMPLATE_SCRIPT_ABORTED);
  828.         }
  829.     if (0) /* TODO - check for normal script completion */
  830. {
  831. SCSI_INT_DEBUG_MSG ("templateEventTypeGet: script completed.n",
  832.     0, 0, 0, 0, 0, 0);
  833. return (TEMPLATE_SCSI_COMPLETE);
  834.         }
  835.     if (0) /* TODO - check for a single step event */
  836. {
  837. SCSI_INT_DEBUG_MSG ("templateEventTypeGet: single-step.n",
  838.     0, 0, 0, 0, 0, 0);
  839. return (TEMPLATE_SINGLE_STEP);
  840. }
  841.     /* No reason for the interrupt ! */
  842.     
  843.     return (TEMPLATE_FATAL_ERROR);
  844.     }
  845. /*******************************************************************************
  846. *
  847. * templateThreadEvent - SCSI Controller thread event processing routine
  848. *
  849. * Forward the event to the proper handler for the thread's current role.
  850. *
  851. * If the thread is still active, update the thread context (including
  852. * shared memory area) and resume the thread.
  853. *
  854. * RETURNS: N/A
  855. */
  856. LOCAL void templateThreadEvent
  857.     (
  858.     TEMPLATE_THREAD * pThread,
  859.     TEMPLATE_EVENT *  pEvent
  860.     )
  861.     {
  862.     SCSI_EVENT *  pScsiEvent  = &pEvent->scsiEvent;
  863.     SCSI_THREAD * pScsiThread = &pThread->scsiThread;
  864.     SIOP *        pSiop       = (SIOP *)        pScsiThread->pScsiCtrl;
  865.     TEMPLATE_SCRIPT_ENTRY entryPt;
  866.     
  867.     SCSI_DEBUG_MSG ("templateThreadEvent: thread 0x%08x: received event %dn",
  868.     (int) pThread, pScsiEvent->type, 0, 0, 0, 0);
  869.     switch (pScsiThread->role)
  870. {
  871. case SCSI_ROLE_INITIATOR:
  872.     templateInitEvent (pThread, pEvent);
  873.     entryPt = TEMPLATE_SCRIPT_INIT_CONTINUE;
  874.     break;
  875.     
  876. case SCSI_ROLE_IDENT_INIT:
  877.     templateInitIdentEvent (pThread, pEvent);
  878.     entryPt = TEMPLATE_SCRIPT_INIT_CONTINUE;
  879.     break;
  880. case SCSI_ROLE_TARGET:
  881. default:
  882.     logMsg ("templateThreadEvent: thread 0x%08x: invalid role (%d)n",
  883.     (int) pThread, pScsiThread->role, 0, 0, 0, 0);
  884.     entryPt = TEMPLATE_SCRIPT_TGT_DISCONNECT;
  885.     break;
  886. }
  887.     /* Resume thread if it is still connected */
  888.     switch (pScsiThread->state)
  889. {
  890. case SCSI_THREAD_INACTIVE:
  891. case SCSI_THREAD_WAITING:
  892. case SCSI_THREAD_DISCONNECTED:
  893.     break;
  894. default:
  895.          templateThreadUpdate (pThread);
  896.     if (templateResume (pSiop, pThread, entryPt) != OK)
  897.      {
  898.      SCSI_ERROR_MSG("templateThreadEvent: failed to resume threadn",
  899.      0, 0, 0, 0, 0, 0);
  900. templateThreadFail (pThread, S_scsiLib_DISCONNECTED);
  901.      }
  902.     break;
  903. }
  904.     }
  905. /*******************************************************************************
  906. *
  907. * templateInitEvent - device initiator thread event processing routine
  908. *
  909. * Parse the event type and handle it accordingly.  This may result in state
  910. * changes for the thread, state variables being updated, etc.
  911. *
  912. * RETURNS: N/A
  913. */
  914. LOCAL void templateInitEvent
  915.     (
  916.     TEMPLATE_THREAD * pThread,
  917.     TEMPLATE_EVENT *  pEvent
  918.     )
  919.     {
  920.     SCSI_EVENT *  pScsiEvent  = &pEvent->scsiEvent;
  921.     SCSI_THREAD * pScsiThread = &pThread->scsiThread;
  922.     SCSI_CTRL *   pScsiCtrl   = pScsiThread->pScsiCtrl;
  923.     /* Update controller msg in/out state after script completes */
  924.     pScsiCtrl->msgOutState = pThread->nMsgOutState;
  925.     pScsiCtrl->msgInState  = pThread->nMsgInState;
  926.     
  927.     /* Parse script exit status; handle as necessary */
  928.     switch (pScsiEvent->type)
  929. {
  930. case SCSI_EVENT_DISCONNECTED:
  931.          SCSI_DEBUG_MSG ("DISCONNECT message inn", 0, 0, 0, 0, 0, 0);
  932.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_DISCONNECTED);
  933.     templateThreadStateSet (pThread, SCSI_THREAD_DISCONNECTED);
  934.     break;
  935. case TEMPLATE_SCSI_COMPLETE:
  936.     SCSI_DEBUG_MSG ("COMMAND COMPLETE message inn", 0, 0, 0, 0, 0, 0);
  937.     templateThreadComplete (pThread);
  938.     break;
  939. case SCSI_EVENT_SELECTED:
  940. case SCSI_EVENT_RESELECTED:
  941.          SCSI_DEBUG_MSG ("templateInitEvent: thread 0x%08x: (re)selection.n",
  942.          (int) pThread, 0, 0, 0, 0, 0);
  943.     templateThreadDefer (pThread);
  944.     break;
  945.      case TEMPLATE_MESSAGE_OUT_SENT:
  946.     (void) scsiMsgOutComplete (pScsiCtrl, pScsiThread);
  947.     break;
  948.     
  949. case TEMPLATE_MESSAGE_IN_RECVD:
  950.     (void) scsiMsgInComplete (pScsiCtrl, pScsiThread);
  951.     break;
  952.     
  953. case TEMPLATE_NO_MSG_OUT:
  954.     /*
  955.      * The target has requested a message out when there is none
  956.      * pending.  Set up a NO-OP message to be sent when thread is
  957.      *  resumed.
  958.      *
  959.      * The script could handle this on its own, but arguably the
  960.      * host should be involved as it may represent an error.
  961.      */
  962.     pScsiCtrl->msgOutBuf[0] = SCSI_MSG_NO_OP;
  963.     pScsiCtrl->msgOutLength = 1;
  964.     pScsiCtrl->msgOutState  = SCSI_MSG_OUT_NONE;    /* sic */
  965.     break;
  966.     
  967. case TEMPLATE_EXT_MESSAGE_SIZE:
  968.     /*
  969.      *  The SIOP has just read the length byte for an extended
  970.      *  message in.  The shared memory area is updated with the
  971.      * appropriate length just before the thread is resumed (see
  972.      * "templateThreadUpdate()".
  973.      */
  974.     break;
  975.     
  976. case TEMPLATE_PHASE_MISMATCH:
  977.     if (templatePhaseMismatch (pThread, pThread->nBusPhase,
  978.      pEvent->remCount) != OK)
  979. {
  980. templateThreadFail (pThread, errno);
  981. }
  982.     break;
  983. case TEMPLATE_SCSI_TIMEOUT:
  984.     SCSI_ERROR_MSG ("templateInitEvent: thread 0x%08x: " 
  985.     "select timeout.n", (int) pThread, 0, 0, 0, 0, 0);
  986.     templateThreadFail (pThread, S_scsiLib_SELECT_TIMEOUT);
  987.     break;
  988. case TEMPLATE_SCRIPT_ABORTED:
  989.     SCSI_DEBUG_MSG ("templateInitEvent: thread 0x%08x: abortedn",
  990.     (int) pThread, 0, 0, 0, 0, 0);
  991.     break;
  992.     
  993. case SCSI_EVENT_BUS_RESET:
  994.          SCSI_DEBUG_MSG ("templateInitEvent: thread 0x%08x: bus resetn",
  995.          (int) pThread, 0, 0, 0, 0, 0);
  996.     /* Do not try to resume this thread.  SCSI mgr will tidy up. */
  997.     templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  998.     break;
  999. case TEMPLATE_UNEXPECTED_DISCON:
  1000.     /* not really unexpected after an abort message ... */
  1001.          SCSI_ERROR_MSG ("templateInitEvent: thread 0x%08x: "
  1002.          "unexpected disconnectionn",
  1003.          (int) pThread, 0, 0, 0, 0, 0);
  1004.     templateThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1005.     break;
  1006.     
  1007. case TEMPLATE_ILLEGAL_PHASE:
  1008.     SCSI_ERROR_MSG ("templateInitEvent: thread 0x%08x: "
  1009.     "illegal phase requested.n",
  1010.     (int) pThread, 0, 0, 0, 0, 0);
  1011.     templateThreadFail (pThread, S_scsiLib_INVALID_PHASE);
  1012.     break;
  1013. default:
  1014.     logMsg ("templateInitEvent: invalid event type (%d)n",
  1015.     pScsiEvent->type, 0, 0, 0, 0, 0);
  1016.     break;
  1017. }
  1018.     }
  1019. /******************************************************************************
  1020. *
  1021. * templateActivate - activate a script corresponding to a new thread
  1022. *
  1023. * Request activation of (the script for) a new thread, if possible; do not
  1024. * wait for the script to complete (or even start) executing.  Activation
  1025. * is requested by signalling the controller, which causes an interrupt.
  1026. * The script is started by the ISR in response to this event.
  1027. *
  1028. * NOTE: Interrupt locking is required to ensure that the correct action
  1029. * is taken once the controller state has been checked.
  1030. *
  1031. * RETURNS: OK, or ERROR if the controller is in an invalid state (this
  1032. * indicates a major software failure).
  1033. */
  1034. LOCAL STATUS templateActivate
  1035.     (
  1036.     SIOP *          pSiop,
  1037.     TEMPLATE_THREAD * pThread
  1038.     )
  1039.     {
  1040.     STATUS status = OK;
  1041.     int key;
  1042.     key = intLock ();
  1043.     /* TODO - Activate Controller for the current thread */
  1044.     intUnlock (key);
  1045.     return (status);
  1046.     }
  1047. /*******************************************************************************
  1048. *
  1049. * templateAbort - abort the active script corresponding to the current thread
  1050. *
  1051. * Check that there is currently an active script running.  If so, set the
  1052. * SCSI Controller Abort flag which will halt the script and cause an interrupt.
  1053. *
  1054. * RETURNS: N/A
  1055. */
  1056. LOCAL void templateAbort
  1057.     (
  1058.     SIOP* pSiop /* ptr to controller info */
  1059.     )
  1060.     {
  1061.     int    key;
  1062.     key = intLock ();
  1063.     /* TODO - Abort the active script corresponding to the current thread */
  1064.     intUnlock (key);
  1065.     }
  1066. /*******************************************************************************
  1067. *
  1068. * templateScriptStart - start the SCSI Controller executing a script
  1069. *
  1070. * Restore the SCSI Controller register context, including the shared memory
  1071. * area, from the thread context.  Put the address of the script entry point
  1072. * into the DSP register.  If not in single-step mode, start the script.
  1073. *
  1074. * RETURNS: N/A
  1075. */
  1076. LOCAL void templateScriptStart
  1077.     (
  1078.     SIOP*            pSiop,  /* pointer to  SCSI Controller info */
  1079.     TEMPLATE_THREAD* pThread,  /* ncr thread info */
  1080.     TEMPLATE_SCRIPT_ENTRY entryId  /* routine address entry point */
  1081.     )
  1082.     {
  1083.     IMPORT ULONG templateWait[]; /* DUMMY entries to scripts */
  1084.     IMPORT ULONG templateInitStart[];
  1085.     IMPORT ULONG templateInitContinue[];
  1086.     IMPORT ULONG templateTgtDisconnect[];
  1087.     int key;
  1088.     static ULONG * templateScriptEntry [] =
  1089. {
  1090.         templateWait, /* wait for re-select or host cmd   */
  1091.      templateInitStart, /* start an initiator thread        */
  1092.      templateInitContinue, /* continue an initiator thread     */
  1093. templateTgtDisconnect,      /* disconnect a target thread       */
  1094. };    
  1095.     key = intLock ();
  1096.     /* TODO - Restore the SCSI Controller  register context for this thread. */
  1097.     /*
  1098.      * TODO - Set the shared data address, load the script start address,
  1099.      * then start the SCSI Controller unless it's in single-step mode.
  1100.      */
  1101.     /* DUMMY CMD */
  1102.     TEMPLATE_REG_WRITE (pSiop, pCmd, (int)templateScriptEntry[entryId]);
  1103.     intUnlock (key);
  1104.     }
  1105. /*******************************************************************************
  1106. *
  1107. * templateThreadUpdate - update the thread structure for a current SCSI command
  1108. *
  1109. * Update the dynamic data (e.g. data pointers, transfer parameters) in
  1110. * the thread to reflect the latest state of the corresponding physical device.
  1111. *
  1112. * RETURNS: N/A
  1113. *
  1114. * NOMANUAL
  1115. */
  1116. LOCAL void templateThreadUpdate
  1117.     (
  1118.     TEMPLATE_THREAD * pThread /* thread info */
  1119.     )
  1120.     {
  1121.     SCSI_THREAD   * pScsiThread = &pThread->scsiThread;
  1122.     SCSI_CTRL     * pScsiCtrl   = pScsiThread->pScsiCtrl;
  1123.     UINT            msgOutSize;
  1124.     UINT            msgInSize;
  1125.     /*
  1126.      *  If there is an identification message, ensure ATN is asserted
  1127.      * during (re)selection.
  1128.      */
  1129.     /* TODO - update device specific info in the thread structure */
  1130.     /* Update dynamic message in/out sizes */
  1131.     if (pScsiCtrl->msgOutState == SCSI_MSG_OUT_NONE)
  1132. msgOutSize = 0;
  1133.     else
  1134. msgOutSize = pScsiCtrl->msgOutLength;
  1135.     if (pScsiCtrl->msgInState != SCSI_MSG_IN_EXT_MSG_DATA)
  1136. msgInSize = 0;
  1137.     
  1138.     else if ((msgInSize = pScsiCtrl->msgInBuf[SCSI_EXT_MSG_LENGTH_BYTE]) == 0)
  1139. msgInSize = SCSI_EXT_MSG_MAX_LENGTH;
  1140.     /* TODO - Update commands in shared memory area */
  1141.     }
  1142. /*******************************************************************************
  1143. *
  1144. * templateThreadComplete - successfully complete execution of a client thread
  1145. *
  1146. * Set the thread status and errno appropriately, depending on whether or
  1147. * not the thread has been aborted.  Set the thread inactive, and notify
  1148. * the SCSI manager of the completion.
  1149. *
  1150. * RETURNS: N/A
  1151. */
  1152. LOCAL void templateThreadComplete
  1153.     (
  1154.     TEMPLATE_THREAD * pThread
  1155.     )
  1156.     {
  1157.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1158.     
  1159.     SCSI_DEBUG_MSG ("templateThreadComplete: thread 0x%08x completedn",
  1160.     (int) pThread, 0, 0, 0, 0, 0);
  1161.     if (pScsiThread->state == SCSI_THREAD_ABORTING)
  1162. {
  1163. pScsiThread->status = ERROR;
  1164. pScsiThread->errNum = S_scsiLib_ABORTED;
  1165. }
  1166.     else
  1167. {
  1168.      pScsiThread->status = OK;
  1169.      pScsiThread->errNum = 0;
  1170.      }
  1171.     
  1172.     templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1173.     scsiCacheSynchronize (pScsiThread, SCSI_CACHE_POST_COMMAND);
  1174.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED);
  1175.     }
  1176. /*******************************************************************************
  1177. *
  1178. * templateThreadDefer - defer execution of a thread
  1179. *
  1180. * Set the thread's state to INACTIVE and notify the SCSI manager of the
  1181. * deferral event.
  1182. *
  1183. * This routine is invoked when a re-selection event occurs.
  1184. *
  1185. * RETURNS: N/A
  1186. */
  1187. LOCAL void templateThreadDefer
  1188.     (
  1189.     TEMPLATE_THREAD * pThread
  1190.     )
  1191.     {
  1192.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1193.     
  1194.     SCSI_DEBUG_MSG ("templateThreadDefer: thread 0x%08x deferredn",
  1195.     (int) pThread, 0, 0, 0, 0, 0);
  1196.     templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1197.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_DEFERRED);
  1198.     }
  1199.     
  1200. /*******************************************************************************
  1201. *
  1202. * templateThreadFail - complete execution of a thread, with error status
  1203. *
  1204. * Set the thread's status and errno according to the type of error.  Set
  1205. * the thread's state to INACTIVE, and notify the SCSI manager of the
  1206. * completion event.
  1207. *
  1208. * RETURNS: N/A
  1209. */
  1210. LOCAL void templateThreadFail
  1211.     (
  1212.     TEMPLATE_THREAD * pThread,
  1213.     int             errNum
  1214.     )
  1215.     {
  1216.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1217.     
  1218.     SCSI_DEBUG_MSG ("templateThreadFail: thread 0x%08x failed (errno = %d)n",
  1219.     (int) pThread, errNum, 0, 0, 0, 0);
  1220.     pScsiThread->status = ERROR;
  1221.     if (pScsiThread->state == SCSI_THREAD_ABORTING)
  1222. pScsiThread->errNum = S_scsiLib_ABORTED;
  1223.     else
  1224.      pScsiThread->errNum = errNum;
  1225.     
  1226.     templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1227.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED);
  1228.     }
  1229.     
  1230. /******************************************************************************
  1231. *
  1232. * templateThreadStateSet - set the state of a thread
  1233. *
  1234. * This is really just a place-holder for debugging and possible future
  1235. * enhancements such as state-change logging.
  1236. *
  1237. * RETURNS: N/A
  1238. */
  1239. LOCAL void templateThreadStateSet
  1240.     (
  1241.     TEMPLATE_THREAD *   pThread, /* ptr to thread info */
  1242.     SCSI_THREAD_STATE state
  1243.     )
  1244.     {
  1245.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1246.     
  1247.     SCSI_DEBUG_MSG ("templateThreadStateSet: thread 0x%08x: %d -> %dn",
  1248.     (int) pThread, pScsiThread->state, state, 0, 0, 0);
  1249.     pScsiThread->state = state;
  1250.     }
  1251. /*******************************************************************************
  1252. *
  1253. * templatePhaseMismatch - recover from a SCSI bus phase mismatch
  1254. *
  1255. * This routine does whatever is required to keep the pointers, counts, etc.
  1256. * used by task-level software in step when a SCSI phase mismatch occurs.
  1257. *
  1258. * The interrupt-level mismatch processing has stored the phase of the
  1259. * information transfer before the mismatch, and the number of bytes
  1260. * remaining to be transferred.  See "templateRemainderGet()".
  1261. *
  1262. * Note that the only phase mismatches supported at this level are:
  1263. *
  1264. * 1) during data in/out phases - presumably because the target has
  1265. * transferred as much data as it intends to before sending a message
  1266. * in (typically DISCONNECT or COMMAND COMPLETE).  Recovery consists
  1267. * of updating the active data pointer/count according to the number
  1268. * of data bytes actually transferred before the mismatch.
  1269. *
  1270. * 2) during a message out phase - presumably because the target does not
  1271. * understand our outgoing message and is sending a MESSAGE REJECT
  1272. * message, or similar.  No recovery is needed here - it's all done
  1273. * when the MESSAGE REJECT message has been received (see routine
  1274. * "scsiMsgOutReject()").
  1275. *
  1276. * 3) during a message in phase - presumably because we have asserted ATN
  1277. * to abort or reject an incoming message.  No recovery is needed here -
  1278. * it's done by the thread management code, which should have enough
  1279. * state information to know what to do.
  1280. *
  1281. * RETURNS: OK, or ERROR for an unsupported or invalid phase
  1282. *
  1283. * NOMANUAL
  1284. */
  1285. LOCAL STATUS templatePhaseMismatch
  1286.     (
  1287.     TEMPLATE_THREAD  * pThread, /* ptr to thread info           */
  1288.     int              phase, /* bus phase before mismatch    */
  1289.     UINT             remCount /* # bytes not yet transferred  */
  1290.     )
  1291.     {
  1292.     SCSI_THREAD *pScsiThread = (SCSI_THREAD *) pThread;
  1293.     UINT xferCount;
  1294.     /* TODO - compute nbr of bytes actually transferred. */
  1295.     xferCount = 1024 - remCount; /* DUMMY CODE */
  1296.     switch (phase)
  1297. {
  1298. case SCSI_DATA_IN_PHASE:
  1299. case SCSI_DATA_OUT_PHASE:
  1300.     pScsiThread->activeDataAddress += xferCount;
  1301.     pScsiThread->activeDataLength  -= xferCount;
  1302.     
  1303.     SCSI_DEBUG_MSG ("templatePhaseMismatch: data transfer aborted "
  1304.     "(%d bytes transferred).n",
  1305.     xferCount, 0, 0, 0, 0, 0);
  1306.     break;
  1307.     
  1308. case SCSI_MSG_OUT_PHASE:
  1309.     SCSI_DEBUG_MSG("templatePhaseMismatch: message out aborted "
  1310.    "(%d of %d bytes sent).n",
  1311.    pScsiThread->pScsiCtrl->msgOutLength,
  1312.    pScsiThread->pScsiCtrl->msgOutLength - remCount,
  1313.    0, 0, 0, 0);
  1314.     break;
  1315.     
  1316. case SCSI_MSG_IN_PHASE:
  1317.     SCSI_DEBUG_MSG("templatePhaseMismatch: message in aborted "
  1318.    "(%d bytes received).n",
  1319.    pScsiThread->pScsiCtrl->msgInLength,
  1320.    0, 0, 0, 0, 0);
  1321.     break;
  1322. case SCSI_COMMAND_PHASE:
  1323. case SCSI_STATUS_PHASE:
  1324.     SCSI_ERROR_MSG ("templatePhaseMismatch: unsupported phase (%d).n",
  1325.     phase, 0, 0, 0, 0, 0);
  1326.     return (ERROR);
  1327.     
  1328. default:
  1329.     logMsg ("templatePhaseMismatch: invalid phase (%d).n",
  1330.     phase, 0, 0, 0, 0, 0);
  1331.     return (ERROR);
  1332.         }
  1333.     return (OK);
  1334.     }
  1335. /*******************************************************************************
  1336. *
  1337. * templateInitIdentEvent - identification thread event processing 
  1338. *
  1339. * Parse the event type and handle it accordingly.  This may result in state
  1340. * changes for the thread, state variables being updated, etc.
  1341. *
  1342. * RETURNS: N/A
  1343. */
  1344. LOCAL void templateInitIdentEvent
  1345.     (
  1346.     TEMPLATE_THREAD * pThread,
  1347.     TEMPLATE_EVENT *  pEvent
  1348.     )
  1349.     {
  1350.     SCSI_EVENT *  pScsiEvent  = (SCSI_EVENT *)  pEvent;
  1351.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1352.     SCSI_CTRL *   pScsiCtrl   = pScsiThread->pScsiCtrl;
  1353.     /* Update controller msg in/out state after script completes */
  1354.     pScsiCtrl->msgOutState = pThread->nMsgOutState;
  1355.     pScsiCtrl->msgInState  = pThread->nMsgInState;
  1356.     
  1357.     /* Parse script exit status; handle as necessary */
  1358.     switch (pScsiEvent->type)
  1359. {
  1360. case SCSI_EVENT_RESELECTED:
  1361.          pScsiThread->nBytesIdent = pScsiEvent->nBytesIdent;
  1362.     bcopy ((char *) pScsiCtrl->identBuf,
  1363.    (char *) pScsiThread->identMsg,
  1364.    pScsiThread->nBytesIdent);
  1365.     templateThreadStateSet (pThread, SCSI_THREAD_IDENT_IN);
  1366.          templateIdentInContinue (pThread);
  1367.     break;
  1368. case TEMPLATE_MESSAGE_OUT_SENT:
  1369.     /*
  1370.      * This will be after we have sent an "ABORT (TAG)" msg.
  1371.      * The target will disconnect any time; it may have already
  1372.      * done so, in which case we won't be able to resume the
  1373.      * thread, but no matter.
  1374.      */
  1375.     break;
  1376. case TEMPLATE_MESSAGE_IN_RECVD:
  1377.     /*
  1378.      *  Continue parsing the identification message.  It
  1379.      *  should by now be complete.
  1380.      *
  1381.      * First byte of ident msg is already in ident buffer.
  1382.      * Remaining bytes are in the normal message input buffer.
  1383.      * This should always be a two-byte message (viz. QUEUE TAG);
  1384.      * it would be nicer if there were a way to avoid hard-coding
  1385.      * this.
  1386.      */
  1387.     bcopy ((char *) pScsiCtrl->msgInBuf,
  1388.    (char *) pScsiThread->identMsg + pScsiThread->nBytesIdent,
  1389.    2);
  1390.     
  1391.          pScsiThread->nBytesIdent += 2;
  1392.          templateIdentInContinue (pThread);
  1393.     break;
  1394. case TEMPLATE_SCRIPT_ABORTED:
  1395.     SCSI_DEBUG_MSG ("templateInitIdentEvent: thread 0x%08x: abortedn",
  1396.     (int) pThread, 0, 0, 0, 0, 0);
  1397.     break;
  1398.         case SCSI_EVENT_DISCONNECTED:
  1399.     SCSI_DEBUG_MSG ("templateInitIdentEvent: thread 0x%08x:"
  1400.     "disconnectedn",
  1401.     (int) pThread, 0, 0, 0, 0, 0);
  1402.     templateThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1403.     break;
  1404.     
  1405. case SCSI_EVENT_BUS_RESET:
  1406.          SCSI_DEBUG_MSG ("templateInitIdentEvent: thread 0x%08x: bus resetn",
  1407.          (int) pThread, 0, 0, 0, 0, 0);
  1408.     /* Do not try to resume this thread.  SCSI mgr will tidy up.  */
  1409.     templateThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  1410.     break;
  1411. case TEMPLATE_UNEXPECTED_DISCON:
  1412.     /* not really unexpected after an abort message ... */
  1413.          SCSI_ERROR_MSG ("templateInitIdentEvent: thread 0x%08x: "
  1414.          "unexpected disconnectionn",
  1415.          (int) pThread, 0, 0, 0, 0, 0);
  1416.     templateThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1417.     break;
  1418.     
  1419. case TEMPLATE_ILLEGAL_PHASE:
  1420.     SCSI_ERROR_MSG ("templateInitIdentEvent: thread 0x%08x: "
  1421.     "illegal phase requested.n",
  1422.     (int) pThread, 0, 0, 0, 0, 0);
  1423.     
  1424.     templateThreadFail (pThread, S_scsiLib_INVALID_PHASE);
  1425.     break;
  1426. default:
  1427.     logMsg ("templateInitIdentEvent: invalid event type (%d)n",
  1428.     pScsiEvent->type, 0, 0, 0, 0, 0);
  1429.     break;
  1430. }
  1431.     }
  1432.     
  1433. /*******************************************************************************
  1434. *
  1435. * templateResume - resume a script corresponding to a suspended thread
  1436. *
  1437. * NOTE: the script can only be resumed if the controller is currently idle.
  1438. * To avoid races, interrupts must be locked while this is checked and the
  1439. * script re-started.
  1440. *
  1441. * Reasons why the controller might not be idle include SCSI bus reset and
  1442. * unexpected disconnection, both of which might occur in practice.  Hence
  1443. * this is not considered to be a major software error.
  1444. *
  1445. * RETURNS: OK, or ERROR if the controller is in an invalid state (this
  1446. * should not be treated as a major software failure).
  1447. */
  1448. LOCAL STATUS templateResume
  1449.     (
  1450.     SIOP *           pSiop, /* ptr to controller info          */
  1451.     TEMPLATE_THREAD* pThread, /* ptr to thread info              */
  1452.     TEMPLATE_SCRIPT_ENTRY entryId /* entry point of script to resume */
  1453.     )
  1454.     {
  1455.     STATUS status;
  1456.     int    key;
  1457.     /* Check validity of connection and start script if OK */
  1458.     key = intLock ();
  1459.     switch (pSiop->state)
  1460. {
  1461. case TEMPLATE_STATE_IDLE:
  1462.     SCSI_INT_DEBUG_MSG ("templateResume: thread: 0x%08x:"
  1463. " state %d -> %dn",
  1464.      (int) pThread,
  1465.      TEMPLATE_STATE_IDLE, TEMPLATE_STATE_ACTIVE,
  1466.      0, 0, 0);
  1467.     templateScriptStart (pSiop, pThread, entryId);
  1468.     pSiop->state = TEMPLATE_STATE_ACTIVE;
  1469.     status = OK;
  1470.     break;
  1471. case TEMPLATE_STATE_PASSIVE:
  1472. case TEMPLATE_STATE_ACTIVE:
  1473. default:
  1474.     status = ERROR;
  1475.     break;
  1476. }
  1477.     intUnlock (key);
  1478.     return (status);
  1479.     }
  1480. /*******************************************************************************
  1481. *
  1482. * templateIdentInContinue - continue incoming identification
  1483. *
  1484. * Parse the message built up so far.  If it is not yet complete, do nothing.
  1485. * If the message is complete, attempt to reconnect the thread it identifies,
  1486. * and deactivate this thread (the identification thread is no longer active).
  1487. * Otherwise (identification has failed), abort the identification sequence.
  1488. *
  1489. * RETURNS: N/A
  1490. */
  1491. LOCAL void templateIdentInContinue
  1492.     (
  1493.     TEMPLATE_THREAD * pThread
  1494.     )
  1495.     {
  1496.     SCSI_THREAD *     pNewThread;
  1497.     SCSI_THREAD *     pScsiThread = (SCSI_THREAD *) pThread;
  1498.     SCSI_CTRL *       pScsiCtrl   = pScsiThread->pScsiCtrl;
  1499.     SCSI_IDENT_STATUS status;
  1500.     SCSI_THREAD_STATE state;
  1501.     status = scsiIdentMsgParse (pScsiCtrl, pScsiThread->identMsg,
  1502.                    pScsiThread->nBytesIdent,
  1503.                   &pScsiThread->pScsiPhysDev,
  1504.        &pScsiThread->tagNumber);
  1505.     switch (status)
  1506. {
  1507. case SCSI_IDENT_INCOMPLETE:
  1508.     state = SCSI_THREAD_IDENT_IN;
  1509.     break;
  1510. case SCSI_IDENT_COMPLETE:
  1511.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_RECONNECTED);
  1512.     if ((pNewThread = scsiMgrPhysDevActiveThreadFind (
  1513.           pScsiThread->pScsiPhysDev,
  1514.           pScsiThread->tagNumber)) == 0)
  1515. {
  1516. state = SCSI_THREAD_IDENT_ABORTING;
  1517. }
  1518.     else
  1519. {
  1520.      templateThreadReconnect ((TEMPLATE_THREAD *) pNewThread);
  1521.      state = SCSI_THREAD_INACTIVE;
  1522. }
  1523.     break;
  1524. case SCSI_IDENT_FAILED:
  1525.     state = SCSI_THREAD_IDENT_ABORTING;
  1526.     break;
  1527. default:
  1528.     logMsg ("templateIdentInContinue: invalid ident status (%d)n",
  1529.               status, 0, 0, 0, 0, 0);
  1530.     state = SCSI_THREAD_INACTIVE;
  1531.     break;
  1532. }
  1533.     if (state == SCSI_THREAD_IDENT_ABORTING)
  1534. templateThreadAbort ((SIOP *) pScsiCtrl, pThread);
  1535.     templateThreadStateSet (pThread, state);
  1536.     }
  1537. /*******************************************************************************
  1538. *
  1539. * templateThreadReconnect - reconnect a thread
  1540. *
  1541. * Restore the SCSI pointers for the thread (this really should be in a more
  1542. * generic section of code - perhaps part of the SCSI manager's thread event
  1543. * procesing ?).  Update the newly-connected thread's context (including
  1544. * shared memory area) and resume it.  Set the thread's state to ESTABLISHED.
  1545. *
  1546. * RETURNS: N/A
  1547. *
  1548. * NOMANUAL
  1549. */
  1550. LOCAL void templateThreadReconnect
  1551.     (
  1552.     TEMPLATE_THREAD * pThread
  1553.     )
  1554.     {
  1555.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1556.     SCSI_CTRL   * pScsiCtrl   = pScsiThread->pScsiCtrl;
  1557.     SIOP        * pSiop       = (SIOP *) pScsiCtrl;
  1558.     
  1559.     SCSI_DEBUG_MSG ("templateThreadReconnect: reconnecting thread 0x%08xn",
  1560.     (int) pThread, 0, 0, 0, 0, 0);
  1561.     pScsiCtrl->pThread = pScsiThread;
  1562.     /* Implied RESTORE POINTERS action: see "scsiMsgInComplete ()" */
  1563.     pScsiThread->activeDataAddress = pScsiThread->savedDataAddress;
  1564.     pScsiThread->activeDataLength  = pScsiThread->savedDataLength;
  1565.     templateThreadUpdate (pThread);
  1566.     if (templateResume (pSiop, pThread, TEMPLATE_SCRIPT_INIT_CONTINUE) != OK)
  1567. {
  1568. SCSI_ERROR_MSG ("templateThreadReconnect: failed to resume thread.n",
  1569. 0, 0, 0, 0, 0, 0);
  1570. templateThreadFail (pThread, S_scsiLib_DISCONNECTED);
  1571. return;
  1572. }
  1573.     templateThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED);
  1574.     }