scsiMgrLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:53k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* scsiMgrLib.c - SCSI manager library (SCSI-2) */
  2. /* Copyright 1989-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03d,10jul97,dds  added library support for adaptec chips.
  8. 01c,29oct96,dgp  doc: editing for newly published SCSI libraries
  9. 01b,21oct96,dds  removed NOMANUAL from functions called by 
  10.                  the driver interface.
  11. 01a,12sep96,dds  added the scsiMgr routines from scsi2Lib.c
  12. */
  13. /*
  14. DESCRIPTION
  15. This SCSI-2 library implements the SCSI manager.  The purpose of the SCSI
  16. manager is to manage SCSI threads between requesting VxWorks tasks and the
  17. SCSI controller.  The SCSI manager handles SCSI events and SCSI threads
  18. but allocation and de-allocation of SCSI threads is not the manager's
  19. responsiblity.  SCSI thread management includes despatching threads and
  20. scheduling multiple threads (which are performed by the SCSI manager, plus
  21. allocation and de-allocation of threads (which are performed by routines in
  22. scsi2Lib).
  23. The SCSI manager is spawned as a VxWorks task upon initialization
  24. of the SCSI interface within VxWorks. The entry point of the SCSI manager task
  25. is scsiMgr(). The SCSI manager task is usually spawned 
  26. during initialization of the SCSI controller driver. The driver's 
  27. xxxCtrlCreateScsi2() routine is typically responsible for such SCSI interface
  28. initializations.
  29. Once the SCSI manager has been initialized, it is ready to handle SCSI
  30. requests from VxWorks tasks. The SCSI manager has the following resposibilities:
  31. .iP
  32. It processes requests from client tasks. 
  33. .iP
  34. It activates a SCSI transaction thread by appending it to the target
  35. device's wait queue and allocating a specified time period
  36. to execute a transaction.
  37. .iP
  38. It handles timeout events which cause threads to be aborted.
  39. .iP
  40. It receives event notifications from the SCSI driver interrupt service
  41. routine (ISR) and processes the event.
  42. .iP
  43. It responds to events generated by the controller hardware, such as
  44. disconnection and information transfer requests.
  45. .iP
  46. It replies to clients when their requests have completed or
  47. aborted.
  48. .LP
  49. One SCSI manager task must be spawned per SCSI controller. Thus, if a 
  50. particular hardware platform contains more than one SCSI controller then
  51. that number of SCSI manager tasks must be spawned by the controller-driver
  52. intialization routine.
  53. INCLUDE FILES
  54. scsiLib.h, scsi2Lib.h
  55. SEE ALSO: scsiLib, scsi2Lib, scsiCommonLib, scsiDirectLib, scsiSeqLib, 
  56. scsiCtrlLib,
  57. .I  "American National Standard for Information Systems - Small Computer"
  58. .I  "System Interface (SCSI-2), ANSI X3T9,"
  59. .pG "I/O System, Local File Systems"
  60. */
  61. #define  INCLUDE_SCSI2
  62. #include "vxWorks.h"
  63. #include "ioLib.h"
  64. #include "intLib.h"
  65. #include "ctype.h"
  66. #include "cacheLib.h"
  67. #include "stdlib.h"
  68. #include "errnoLib.h"
  69. #include "taskLib.h"
  70. #include "lstLib.h"
  71. #include "logLib.h"
  72. #include "msgQLib.h"
  73. #include "string.h"
  74. #include "stdio.h"
  75. #include "sysLib.h"
  76. #include "scsiLib.h"
  77. #include "wdLib.h"
  78. /* globals variables */
  79. int scsiMgrActionSemOptions = SEM_Q_FIFO;   /* only one task waits on it */
  80. int scsiThreadReplyQOptions = MSG_Q_FIFO;   /* only one task waits on it */
  81. int scsiMgrEventQSize       = SCSI_DEF_EVENT_Q_SIZE;
  82. int scsiMgrTimeoutQSize     = SCSI_DEF_TIMEOUT_Q_SIZE;
  83. int scsiMgrRequestQSize     = SCSI_DEF_REQUEST_Q_SIZE;
  84. int scsiMgrReplyQSize       = SCSI_DEF_REPLY_Q_SIZE;
  85. /* global functions */
  86. STATUS      scsiMgrRequestExecute  (SCSI_CTRL    * pScsiCtrl,
  87.     SCSI_REQUEST * pRequest,
  88.     SCSI_REPLY   * pReply);
  89. VOID        scsiMgrPhysDevTagInit  (SCSI_PHYS_DEV * pScsiPhysDev);
  90. /*  SCSI system manager functions */
  91. LOCAL BOOL        scsiMgrMsgGet (RING_ID queueId, void * buffer, int length);
  92. LOCAL void        scsiMgrEventProc   (SCSI_CTRL  * pScsiCtrl, 
  93. SCSI_EVENT * pEvent);
  94. LOCAL void        scsiMgrTimeoutProc (SCSI_CTRL * pScsiCtrl, 
  95. SCSI_TIMEOUT * pTimeout);
  96. LOCAL void        scsiMgrRequestProc (SCSI_CTRL * pScsiCtrl, 
  97. SCSI_REQUEST * pRequest);
  98. LOCAL void        scsiMgrReplyProc   (SCSI_CTRL *  pScsiCtrl, 
  99. SCSI_REPLY * pReply);
  100. LOCAL void        scsiMgrActivateRequest (SCSI_REQUEST * pRequest);
  101. LOCAL void        scsiMgrRequestComplete (SCSI_THREAD  * pThread);
  102. LOCAL void        scsiMgrCompleteReply   (SCSI_REPLY   * pReply);
  103. LOCAL void        scsiMgrTimeoutNotify   (SCSI_THREAD  * pThread);
  104. LOCAL SCSI_THREAD * scsiMgrRunnableThreadGet (SCSI_CTRL * pScsiCtrl);
  105. LOCAL void         scsiMgrThreadDespatch (SCSI_THREAD * pThread);
  106. LOCAL void         scsiMgrThreadComplete (SCSI_THREAD * pThread);
  107. LOCAL void         scsiMgrThreadDefer    (SCSI_THREAD * pThread);
  108. LOCAL STATUS       scsiMgrThreadActivate (SCSI_THREAD * pThread);
  109. LOCAL void         scsiMgrPhysDevReset (SCSI_PHYS_DEV * pScsiPhysDev);
  110. LOCAL void         scsiMgrPhysDevEvent (SCSI_PHYS_DEV      * pScsiPhysDev,
  111.       SCSI_TAG            tagNum,
  112.       SCSI_DEV_EVENT_TYPE type);
  113. LOCAL SCSI_THREAD *scsiMgrPhysDevRunnableThreadGet 
  114.        (SCSI_PHYS_DEV * pScsiPhysDev);
  115. LOCAL void         scsiMgrPhysDevWaitQAdd      (SCSI_PHYS_DEV * pScsiPhysDev,
  116. SCSI_THREAD   * pThread);
  117. LOCAL STATUS       scsiMgrPhysDevWaitQRemove   (SCSI_PHYS_DEV * pScsiPhysDev,
  118. SCSI_THREAD   * pThread);
  119. LOCAL void         scsiMgrPhysDevActiveQAdd    (SCSI_PHYS_DEV * pScsiPhysDev,
  120. SCSI_THREAD   * pThread);
  121. LOCAL STATUS       scsiMgrPhysDevActiveQRemove (SCSI_PHYS_DEV * pScsiPhysDev,
  122. SCSI_THREAD   * pThread);
  123. LOCAL STATUS       scsiMgrPhysDevTagAllocate   (SCSI_PHYS_DEV * pScsiPhysDev,
  124. SCSI_TAG_TYPE   tagType,
  125. SCSI_TAG      * pTagNum);
  126. LOCAL void         scsiMgrPhysDevTagFree       (SCSI_PHYS_DEV * pScsiPhysDev,
  127. SCSI_TAG       tagNum);
  128. LOCAL STATUS       scsiMgrPhysDevTagTypeValidate (SCSI_PHYS_DEV * pScsiPhysDev,
  129.   SCSI_TAG_TYPE  tagType,
  130.   BOOL          * pTagged);
  131. /*******************************************************************************
  132. *
  133. * scsiMgr - SCSI system manager
  134. *
  135. * Manage a SCSI (bus interface) controller.  This entails:
  136. *
  137. *   - carrying out requests on behalf of client tasks to perform SCSI
  138. *    operations on threads, such as executing a transaction
  139. *
  140. *   - responding to events generated by the controller hardware, such as
  141. *    disconnection, information transfer request, etc.
  142. *
  143. *   - handling timeout events which cause threads to be aborted
  144. *
  145. *   - replying to clients when their requests have been completed or
  146. *    aborted.
  147. *
  148. * NOTE
  149. * This function should not be called by application programs.  It is normally
  150. * spawned automatically by the controller driver to form a SCSI manager task
  151. * for each SCSI interface.
  152. *
  153. * INTERNAL
  154. *
  155. * The details of controller event handling are hardware-specific.  The event
  156. * message and event handling routines are made "virtual", i.e. implemented
  157. * by the controller driver.
  158. *
  159. * The order in which the various events and requests are processed is
  160. * important and must not be changed.  Reasons for this vary from obvious to
  161. * pretty subtle - see comments for other "scsiMgr...()" functions for further
  162. * information.
  163. *
  164. * RETURNS: this function does not normally return
  165. *
  166. * NOMANUAL
  167. */
  168. void scsiMgr
  169.     (
  170.     SCSI_CTRL * pScsiCtrl /* SCSI controller to be used */
  171.     )
  172.     {
  173.     SCSI_REQUEST  request;
  174.     SCSI_REPLY    reply;
  175.     SCSI_TIMEOUT  timeout;
  176.     SCSI_EVENT  * pEvent;
  177.     SCSI_THREAD * pThread;
  178.     
  179.     /* initialise */
  180.     pEvent = malloc (pScsiCtrl->eventSize);
  181.     if (pEvent == NULL)
  182. return;
  183.     /*
  184.      * Service loop
  185.      */
  186.     while (TRUE)
  187. {
  188. /*
  189.  *  Wait for an event, timeout or client request to be posted
  190.  */
  191. semTake (pScsiCtrl->actionSem, WAIT_FOREVER);
  192. /*
  193.  *  Service all controller events ...
  194.  */
  195. while (scsiMgrMsgGet (pScsiCtrl->eventQ, pEvent, pScsiCtrl->eventSize))
  196.     {
  197.     scsiMgrEventProc (pScsiCtrl, pEvent);
  198.     }
  199. /*
  200.  *  Service any timeouts ...
  201.  */
  202. while (scsiMgrMsgGet (pScsiCtrl->timeoutQ, &timeout, sizeof (timeout)))
  203.     {
  204.     scsiMgrTimeoutProc (pScsiCtrl, &timeout);
  205.     }
  206. /*
  207.  *  Service any client requests ...
  208.  */
  209. while (scsiMgrMsgGet (pScsiCtrl->requestQ, &request, sizeof (request)))
  210.     {
  211.     scsiMgrRequestProc (pScsiCtrl, &request);
  212.     }
  213. /*
  214.  *  Forward any replies to clients ...
  215.  */
  216. while (scsiMgrMsgGet (pScsiCtrl->replyQ, &reply, sizeof (reply)))
  217.     {
  218.     scsiMgrReplyProc (pScsiCtrl, &reply);
  219.     }
  220. /*
  221.  *  ... finally, despatch the highest priority request if possible
  222.  */
  223. if ((pThread = scsiMgrRunnableThreadGet (pScsiCtrl)) != 0)
  224.     {
  225.          scsiMgrThreadDespatch (pThread);
  226.     }
  227. }
  228.     }
  229. /*******************************************************************************
  230. *
  231. * scsiMgrMsgGet - get the next message, if any, from a SCSI manager msg queue
  232. *
  233. * Extract the next message, if any is available, from the specified queue and
  234. * copy it into the specified buffer.  If no message is available, do not wait.
  235. *
  236. * NOTE:
  237. * SCSI manager message queues are implemented using ring buffers because there
  238. * is a separate mechanism for synchronisation.  This code is careful to
  239. * always read complete messages from the ring buffer.  A single reader (i.e.,
  240. * the SCSI manager task) is assumed.
  241. */
  242. LOCAL BOOL scsiMgrMsgGet
  243.     (
  244.     RING_ID queue, /* SCSI manager msg queue to read */
  245.     void *  buffer, /* buffer to copy msg into        */
  246.     int     length /* (exact) length of msg expected */
  247.     )
  248.     {
  249.     if (rngNBytes (queue) < length)
  250. return (FALSE);
  251.     if (rngBufGet (queue, buffer, length) != length)
  252. {
  253. logMsg ("scsiMgrMsgGet: rngBufGet failedn", 0, 0, 0, 0, 0, 0);
  254. return (FALSE);
  255. }
  256.     
  257.     return (TRUE);
  258.     }
  259. /*******************************************************************************
  260. *
  261. * scsiMgrEventProc - process a SCSI controller event
  262. *
  263. * Call the appropriate controller-specific function to process the event.
  264. *
  265. * NOTE:
  266. * This function exists primarily as a place-holder for debugging and possible
  267. * future enhancements such as event logging.
  268. */
  269. LOCAL void scsiMgrEventProc
  270.     (
  271.     SCSI_CTRL *  pScsiCtrl,
  272.     SCSI_EVENT * pEvent
  273.     )
  274.     {
  275.     (*pScsiCtrl->scsiEventProc) (pScsiCtrl, pEvent);
  276.     }
  277. /*******************************************************************************
  278. *
  279. * scsiMgrTimeoutProc - process a request timeout event
  280. *
  281. * First try to remove the thread from the device's wait queue.  If it was
  282. * on the queue, simply complete the request (with a timeout error) because
  283. * it has not yet had a tag allocated, etc.
  284. *
  285. * If the thread wasn't on the device's wait queue, see whether its tag number
  286. * corresponds to a current thread.  If not, the thread must have completed,
  287. * so the timeout request can be ignored.
  288. *
  289. * If the tag number corresponds to an in-progress thread, call the controller
  290. * thread abort routine.  If this returns TRUE, the thread is currently active
  291. * on the controller, which will manage the abort process.  Otherwise (the
  292. * thread is not currently active on the controller) abort it here.
  293. *
  294. * Possible race conditions and how they are avoided:
  295. *
  296. *   1) thread completes "just before" the watchdog expires.  The following
  297. *    cases may occur:
  298. *
  299. *    a)  thread completion event and timeout event are processed in the
  300. *        same SCSI manager activation cycle.  In this case, the thread's
  301. *        tag number must be free (timeouts are processed before any new
  302. *        threads are started) and the timeout will be ignored.
  303. *
  304. *    b)  thread completion event is processed but no timeout event occurs
  305. *        in the same activation cycle.  In this case, a new thread using
  306. *        the same tag number may have been started by the time the next
  307. *        activation cycle occurs.  However, since the first thread's
  308. *        watchdog is cancelled during completion processing in the first
  309. *        cycle, if a timeout event has not occurred by the end of that
  310. *        cycle, it can never occur and the newly activated thread is safe.
  311. *
  312. *   2) thread completion occurs "just after" the watchdog expires.  In this
  313. *    case, the completion event will not be processed until the next
  314. *    activation cycle at the earliest.  There are two cases:
  315. *
  316. *    a)  the thread is currently active on the controller when the timeout
  317. *        is processed: in this case, the controller driver's abort routine
  318. *        must ensure that the thread is (possibly) aborted and (definitely)
  319. *        completed, in that order.  It doesn't necessarily do this in a
  320. *        single activation cycle.
  321. *
  322. *    b)  the thread is not currently active on the controller when the
  323. *        timeout occurs: in this case, the request is completed with a
  324. *        timeout error and the tag is marked aborted in the first cycle.
  325. *        When an attempt is later made to re-establish this thread, the
  326. *        identification will fail due to the aborted state of the tag.
  327. *        The controller driver must detect this and force the connected
  328. *        device to disconnect, after which it must free up the tag for
  329. *        re-use by another thread.
  330. *
  331. * NOTE:
  332. * This routine is complex because completion of the thread (i.e. replying to
  333. * the client) must be decoupled from what is happening on the SCSI bus, if
  334. * the timeout is to be useful.  This implies that even after the thread has
  335. * been completed, the corresponding nexus may continue to exist on the
  336. * target device.  This is sorted out by the physical device event processing
  337. * (see "scsiMgrPhysDevEvent ()").
  338. *
  339. * RETURNS: N/A
  340. */
  341. LOCAL void scsiMgrTimeoutProc
  342.     (
  343.     SCSI_CTRL *    pScsiCtrl,
  344.     SCSI_TIMEOUT * pTimeout
  345.     )
  346.     {
  347.     SCSI_THREAD   * pThread      = pTimeout->thread;
  348.     SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;
  349.     SCSI_TAG        tagNum       = pThread->tagNumber;
  350.     BOOL doAbort;
  351.     SCSI_DEBUG_MSG ("scsiMgrTimeoutProc: thread 0x%08x (state = %d) timed outn"
  352.      , (int) pThread, pThread->state, 0, 0, 0, 0);
  353.     /*
  354.      * Ensure thread is not in device's wait queue
  355.      */
  356.     if (scsiMgrPhysDevWaitQRemove (pScsiPhysDev, pThread) == OK)
  357. {
  358. doAbort = TRUE;
  359. }
  360.     /*
  361.      * Thread is either current or completed: look up tag to decide
  362.      */
  363.     else if (scsiMgrPhysDevActiveThreadFind (pScsiPhysDev, tagNum) != pThread)
  364. {
  365. doAbort = FALSE;
  366. }
  367.     /*
  368.      * Thread is current: call controller to abort if connected.
  369.      */
  370.     else if ((*pScsiCtrl->scsiThreadAbort) (pScsiCtrl, pThread))
  371. {
  372. doAbort = FALSE;
  373. }
  374.     /*
  375.      * Thread is current, but not connected.  Remove thread from active
  376.      * list and complete the request.  Tag completion will be handled
  377.      * by controller driver when reconnection occurs.
  378.      */
  379.     else
  380. {
  381. if (scsiMgrPhysDevActiveQRemove (pScsiPhysDev, pThread) != OK)
  382.     {
  383.     logMsg ("scsiMgrTimeoutProc: thread not on active queue !n",
  384.     0, 0, 0, 0, 0, 0);
  385.     return;
  386.     }
  387. doAbort = TRUE;
  388. }
  389.     /*
  390.      * If "doAbort" is true, the thread must be completed now and it has
  391.      * been removed from the device's wait or active queue.  If "doAbort"
  392.      *  is false, either the thread has already been completed or the
  393.      *  controller driver will complete it in due course.
  394.      */
  395.     if (doAbort)
  396. {
  397.      pThread->status = ERROR;
  398.      pThread->errNum = S_scsiLib_ABORTED;
  399.      scsiMgrThreadComplete (pThread);
  400. }
  401.     }
  402. /*******************************************************************************
  403. *
  404. * scsiMgrRequestProc - process a client request
  405. *
  406. * Parse the request type and act accordingly.
  407. *
  408. * NOTE
  409. * Currently only one request type (activate a transaction) is accepted,
  410. * however this routine is intended to allow other request types in future
  411. * (e.g., to support SCSI target mode).
  412. *
  413. * RETURNS: N/A
  414. */
  415. LOCAL void scsiMgrRequestProc
  416.     (
  417.     SCSI_CTRL *    pScsiCtrl,
  418.     SCSI_REQUEST * pRequest
  419.     )
  420.     {
  421.     SCSI_REQUEST_TYPE type = pRequest->type;
  422.     SCSI_DEBUG_MSG ("scsiMgrRequestProc: client request: %dn",
  423.     type, 0, 0, 0, 0, 0);
  424.     
  425.     switch (type)
  426. {
  427.      case SCSI_REQUEST_ACTIVATE:
  428.     scsiMgrActivateRequest (pRequest);
  429.     break;
  430.      default:
  431.     logMsg ("scsiMgrRequestProc: invalid action (%d) requestedn",
  432.     type, 0, 0, 0, 0, 0);
  433.     break;
  434. }
  435.     }
  436. /*******************************************************************************
  437. *
  438. * scsiMgrReplyProc - reply to a client
  439. *
  440. * Parse the reply type and act accordingly.
  441. *
  442. * NOTE
  443. * Currently only one reply type (transaction complete) is accepted, however
  444. * this routine is intended to allow other reply types in future (e.g., to
  445. * support SCSI target mode).
  446. *
  447. * RETURNS: N/A
  448. */
  449. LOCAL void scsiMgrReplyProc
  450.     (
  451.     SCSI_CTRL  * pScsiCtrl,
  452.     SCSI_REPLY * pReply
  453.     )
  454.     {
  455.     SCSI_REPLY_TYPE type = pReply->type;
  456.     SCSI_DEBUG_MSG ("scsiMgrReplyProc: client reply: %dn",
  457.     type, 0, 0, 0, 0, 0);
  458.     
  459.     switch (type)
  460. {
  461.      case SCSI_REPLY_COMPLETE:
  462.     scsiMgrCompleteReply (pReply);
  463.     break;
  464.      default:
  465.     logMsg ("scsiMgrReplyProc: invalid action (%d) requestedn",
  466.     type, 0, 0, 0, 0, 0);
  467.     break;
  468. }
  469.     }
  470. /*******************************************************************************
  471. *
  472. * scsiMgrActivateRequest - process an "Activate" request from a client
  473. *
  474. * Start a watchdog timer for the transaction, then add the thread to the
  475. * target device's wait queue.  It will be despatched at the next opportunity.
  476. *
  477. * RETURNS: N/A
  478. */
  479. LOCAL void scsiMgrActivateRequest
  480.     (
  481.     SCSI_REQUEST * pRequest
  482.     )
  483.     {
  484.     SCSI_THREAD * pThread = pRequest->thread;
  485.     
  486.     SCSI_DEBUG_MSG ("scsiMgrActivateRequest: thread 0x%08xn",
  487.     (int) pThread, 0, 0, 0, 0, 0);
  488.     wdStart (pThread->wdog, pThread->timeout,
  489.           (FUNCPTR) scsiMgrTimeoutNotify,
  490.           (int)     pThread);
  491.     scsiMgrPhysDevWaitQAdd (pThread->pScsiPhysDev, pThread);
  492.     pThread->state = SCSI_THREAD_WAITING;
  493.     }
  494. /*******************************************************************************
  495. *
  496. * scsiMgrRequestComplete - terminate processing of an "Activate" request
  497. *
  498. * Cancel the watchdog timer associated with the thread, and post a message
  499. * requesting the client be sent a reply.
  500. *
  501. * NOTE:
  502. * It might seem peculiar not to just reply directly to the client here.
  503. * The current approach allows the SCSI manager to better prioritise its
  504. * activities, and avoids a subtle race condition which could otherwise occur.
  505. *
  506. * (The exact scenario is as follows: suppose a client task of higher priority
  507. * than the SCSI manager issues a SCSI command and then deletes the physical
  508. * device.  If this routine unblocked the client rather than deferring this
  509. * to the top-level loop of the SCSI manager, the client would pre-empt the
  510. * SCSI manager and could then delete a device for which the SCSI manager may
  511. * still have some outstanding housekeeping to carry out.  This would most
  512. * likely cause the SCSI manager task to fail.  Although this sounds like a
  513. * contrived and unlikely scenario, it would actually happen during SCSI
  514. * auto-configuration by the root task or the shell.)
  515. */
  516. LOCAL void scsiMgrRequestComplete
  517.     (
  518.     SCSI_THREAD * pThread
  519.     )
  520.     {
  521.     SCSI_REPLY  reply;
  522.     SCSI_CTRL * pScsiCtrl = pThread->pScsiCtrl;
  523.     
  524.     wdCancel (pThread->wdog);
  525.     reply.type    = SCSI_REPLY_COMPLETE;
  526.     reply.thread  = pThread;
  527.     reply.status  = pThread->status;
  528.     reply.errNum  = pThread->errNum;
  529.     if (rngBufPut (pScsiCtrl->replyQ,
  530.    (char *) &reply, sizeof (reply)) != sizeof (reply))
  531. {
  532. logMsg ("scsiMgrRequestComplete: rngBufPut failedn",
  533. 0, 0, 0, 0, 0, 0);
  534. }
  535.     }
  536. /******************************************************************************
  537. *
  538. * scsiMgrCompleteReply - process a "Complete" reply to be sent to a client
  539. *
  540. * Build an appropriate reply message and send it on the thread's message
  541. * queue.  This unblocks the client task.  Th thread contains status and
  542. * errno values associated with the reply.
  543. *
  544. * RETURNS: N/A
  545. */
  546. LOCAL void scsiMgrCompleteReply
  547.     (
  548.     SCSI_REPLY  * pReply
  549.     )
  550.     {
  551.     SCSI_THREAD * pThread = pReply->thread;
  552.     SCSI_DEBUG_MSG ("scsiMgrCompleteReply: thread 0x%08x "
  553.     "(status: %d, errno: %d)n",
  554.     (int) pThread, pThread->status, pThread->errNum, 0, 0, 0);
  555.     
  556.     if (msgQSend (pThread->replyQ, (char *) pReply,
  557.                    sizeof (SCSI_REPLY),
  558.                    NO_WAIT,
  559.                    MSG_PRI_NORMAL) != OK)
  560.      {
  561. SCSI_ERROR_MSG ("scsiMgrCompleteReply: can't post reply message "
  562. "(errno = %d)n", errno, 0, 0, 0, 0, 0);
  563. }
  564.     }
  565. /******************************************************************************
  566. *
  567. * scsiMgrRequestExecute - execute a SCSI request
  568. *
  569. * (This routine is called by a client task to have the SCSI manager execute a
  570. * request.)
  571. *
  572. * Post the request message on the SCSI manager's request queue, notifying it
  573. * that there is something there by giving its semaphore.  Wait for the SCSI
  574. * manager's reply using the message queue associated with the thread.
  575. *
  576. * NOTE:
  577. * Since the SCSI manager's request queue is implemented using a ring buffer,
  578. * access by multiple clients is serialised within this routine.  This is
  579. * achieved using the controller's mutex semaphore, which is also used to
  580. * serialise access to the free thread list.  This will not cause deadlock.
  581. *
  582. * The return value of this function tells the caller whether the basic
  583. * request/reply mechanism worked or not, not whether or not the request
  584. * itself succeeded.  In fact, this function should never return ERROR unless
  585. * the software has failed or data structures have been corrupted.
  586. *
  587. * This function should not be called directly by application programs.
  588. *
  589. * RETURNS: OK, or ERROR if the request could not be executed.
  590. *
  591. * NOMANUAL
  592. */
  593. STATUS scsiMgrRequestExecute
  594.     (
  595.     SCSI_CTRL *    pScsiCtrl,
  596.     SCSI_REQUEST * pRequest,
  597.     SCSI_REPLY *   pReply
  598.     )
  599.     {
  600.     int requestSize = sizeof (SCSI_REQUEST);
  601.     int replySize   = sizeof (SCSI_REPLY);
  602.     
  603.     /*
  604.      * Send request to SCSI manager task
  605.      */
  606.     semTake (pScsiCtrl->mutexSem, WAIT_FOREVER);
  607.     if (rngFreeBytes (pScsiCtrl->requestQ) < requestSize)
  608. {
  609. semGive (pScsiCtrl->mutexSem);
  610. logMsg ("scsiMgrRequestExecute: request queue is fulln",
  611. 0, 0, 0, 0, 0, 0);
  612. return (ERROR);
  613. }
  614.     
  615.     if (rngBufPut (pScsiCtrl->requestQ,
  616.    (char *) pRequest, requestSize) != requestSize)
  617. {
  618. semGive (pScsiCtrl->mutexSem);
  619. logMsg ("scsiMgrRequestExecute: rngBufPut failedn",
  620. 0, 0, 0, 0, 0, 0);
  621. return (ERROR);
  622. }
  623.     semGive (pScsiCtrl->mutexSem);
  624.     /*
  625.      * Notify SCSI manager that request has been posted
  626.      */
  627.     semGive (pScsiCtrl->actionSem);
  628.     
  629.     /*
  630.      *  Wait for request to be executed by SCSI manager
  631.      */
  632.     if (msgQReceive (pRequest->thread->replyQ,
  633.      (char *) pReply, replySize, WAIT_FOREVER) != replySize)
  634. {
  635. SCSI_DEBUG_MSG ("scsiMgrRequestExecute: msgQReceive failed "
  636. "(errno = %d)n",
  637. errno, 0, 0, 0, 0, 0);
  638. return (ERROR);
  639. }
  640.     return (OK);
  641.     }
  642. /*******************************************************************************
  643. *
  644. * scsiMgrTimeoutNotify - notify the SCSI manager of a transaction timeout
  645. *
  646. * Post a timeout message on the appropriate SCSI manager queue, then notify
  647. * the SCSI manager that there is something to do.
  648. *
  649. * NOTE:
  650. * No access serialisation is required because timeout messages are only
  651. * posted by the timeout watchdog ISR.
  652. *
  653. * RETURNS: N/A
  654. */
  655. LOCAL void scsiMgrTimeoutNotify
  656.     (
  657.     SCSI_THREAD * pThread
  658.     )
  659.     {
  660.     SCSI_CTRL * pScsiCtrl = pThread->pScsiCtrl;
  661.     
  662.     SCSI_TIMEOUT timeout;
  663.     timeout.thread = pThread;
  664.     if (rngBufPut (pScsiCtrl->timeoutQ,
  665.    (char *) &timeout, sizeof (timeout)) != sizeof (timeout))
  666. {
  667. logMsg ("scsiMgrTimeoutNotify: can't post timeout messagen",
  668. 0, 0, 0, 0, 0, 0);
  669. }
  670.     semGive (pScsiCtrl->actionSem);
  671.     }
  672. /*******************************************************************************
  673. *
  674. * scsiMgrEventNotify - notify the SCSI manager of a SCSI (controller) event
  675. *
  676. * This routine posts an event message on the appropriate SCSI manager queue,
  677. * then notifies the SCSI manager that there is a message to be accepted.
  678. *
  679. * NOTE:
  680. * This routine should not be called by application programs.
  681. *
  682. * No access serialization is required, because event messages are only
  683. * posted by the SCSI controller ISR. See the reference entry for 
  684. * scsiBusResetNotify().
  685. *
  686. * RETURNS: OK, or ERROR if the SCSI manager's event queue is full.
  687. *
  688. * SEE ALSO: scsiBusResetNotify()
  689. */
  690. STATUS scsiMgrEventNotify
  691.     (
  692.     SCSI_CTRL *  pScsiCtrl,  /* pointer to SCSI controller structure */
  693.     SCSI_EVENT * pEvent, /* pointer to the SCSI event */
  694.     int          eventSize /* size of the event information */
  695.     )
  696.     {
  697.     if (rngBufPut (pScsiCtrl->eventQ, (char *) pEvent, eventSize) != eventSize)
  698. {
  699. logMsg ("scsiMgrEventNotify: can't post event messagen",
  700. 0, 0, 0, 0, 0, 0);
  701. return (ERROR);
  702. }
  703.     semGive (pScsiCtrl->actionSem);
  704.     return (OK);
  705.     }
  706. /*******************************************************************************
  707. *
  708. * scsiMgrBusReset - handle a controller-bus reset event 
  709. *
  710. * This routine resets in turn:  each attached physical device, each target,
  711. * and the controller-finite-state machine.  In practice, this routine 
  712. * implements the SCSI hard reset option.
  713. *
  714. * NOTE:
  715. * This routine does not physically reset the SCSI bus; see scsiBusReset().
  716. * This routine should not be called by application programs.
  717. *
  718. * RETURNS: N/A
  719. */
  720. void scsiMgrBusReset
  721.     (
  722.     SCSI_CTRL * pScsiCtrl /* SCSI ctrlr on which bus reset */
  723.     )
  724.     {
  725.     UINT i;
  726.     /*
  727.      * Reset all physical devices
  728.      */
  729.     for (i = 0; i < SCSI_MAX_PHYS_DEVS; ++i)
  730. {
  731.      SCSI_PHYS_DEV * pScsiPhysDev = pScsiCtrl->physDevArr[i];
  732. if (pScsiPhysDev != 0)
  733.     scsiMgrPhysDevReset (pScsiPhysDev);
  734. }
  735.     /*
  736.      * Reset all SCSI targets
  737.      */
  738.     for (i = 0; i < SCSI_MAX_TARGETS; ++i)
  739. scsiTargetReset (pScsiCtrl, i);
  740.     /*
  741.      * Reset controller state
  742.      */
  743.     scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_DISCONNECTED);
  744.     }
  745. /*******************************************************************************
  746. *
  747. * scsiMgrRunnableThreadGet - find the next thread to run, if any
  748. *
  749. * If the controller is active, no thread can be started.  Otherwise, find the
  750. * highest priority waiting thread by querying each physical device.  If a
  751. * runnable thread is found, do not remove it from any wait queue.
  752. *
  753. * NOTE: a simple round-robin scheme is used to avoid unfairly favouring
  754. * threads from any particular physical device, when they all have equal
  755. * priority.
  756. *
  757. * RETURNS: thread ptr, or 0 if no runnable thread exists
  758. */
  759. LOCAL SCSI_THREAD * scsiMgrRunnableThreadGet
  760.     (
  761.     SCSI_CTRL * pScsiCtrl
  762.     )
  763.     {
  764.     SCSI_PRIORITY   bestPriority;
  765.     SCSI_THREAD *   pBestThread;
  766.     int             bestDevIndex;
  767.     int             devIndex;
  768.     int             i;
  769.     /*
  770.      * Can't do anything if the controller is active !
  771.      */
  772.     if (pScsiCtrl->scsiSpecialHandler == NULL)
  773. if (pScsiCtrl->active)
  774.     return (0);
  775.     /*
  776.      * Find best available thread on all existing physical devices
  777.      */
  778.     bestPriority = SCSI_THREAD_MIN_PRIORITY;
  779.     pBestThread  = 0;
  780.     bestDevIndex = 0;
  781.     devIndex = pScsiCtrl->nextDev;
  782.     for (i = 0; i < SCSI_MAX_PHYS_DEVS; ++i)
  783. {
  784.      SCSI_PHYS_DEV * pScsiPhysDev = pScsiCtrl->physDevArr [devIndex];
  785. /*
  786.  *  If this phys dev exists, and has a runnable thread with
  787.  *  higher priority than the best so far, remember it.
  788.  */
  789. if (pScsiPhysDev != 0)
  790.     {
  791.     SCSI_THREAD * pThread;
  792.     
  793.     pThread = scsiMgrPhysDevRunnableThreadGet (pScsiPhysDev);
  794.     if ((pThread != 0) &&
  795. SCSI_IS_HIGHER_PRIORITY (pThread->priority, bestPriority))
  796.      {
  797.      bestDevIndex = devIndex;
  798.      bestPriority = pThread->priority;
  799.      pBestThread  = pThread;
  800. }
  801.     }
  802. if (++devIndex >= SCSI_MAX_PHYS_DEVS)
  803.     devIndex = 0;
  804. }
  805.     if (pBestThread != 0) 
  806. {
  807. pScsiCtrl->nextDev = bestDevIndex + 1;
  808. if (pScsiCtrl->nextDev >= SCSI_MAX_PHYS_DEVS)
  809.     pScsiCtrl->nextDev  = 0;
  810. }
  811.     
  812.     return (pBestThread);
  813.     }
  814. /*******************************************************************************
  815. *
  816. * scsiMgrThreadDespatch - despatch a new thread
  817. *
  818. * Remove the thread from its device's wait queue, activate it and install it
  819. * on the device's active queue.  If activation fails, complete the thread
  820. * with a suitable error code.
  821. *
  822. * RETURNS: N/A
  823. */
  824. LOCAL void scsiMgrThreadDespatch
  825.     (
  826.     SCSI_THREAD * pThread
  827.     )
  828.     {
  829.     SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;
  830.     scsiMgrPhysDevWaitQRemove (pScsiPhysDev, pThread);
  831.     
  832.     if (scsiMgrThreadActivate (pThread) != OK)
  833. {
  834. pThread->status = ERROR;
  835. pThread->errNum = errno;
  836. scsiMgrThreadComplete (pThread);
  837. return;
  838. }
  839.     scsiMgrPhysDevActiveQAdd  (pScsiPhysDev, pThread);
  840.     }
  841. /******************************************************************************
  842. *
  843. * scsiMgrThreadComplete - complete an initiator thread
  844. *
  845. * Check for contingent allegiance condition by parsing the SCSI status set
  846. * by the target device; set or clear the physical device's contingent
  847. * allegiance flag accordingly.  (This affects the access serialisation rules
  848. * used to schedule threads on the device: for more details see
  849. * "scsiMgrPhysDevRunnableThreadGet()".)
  850. *
  851. * Finish processing the client's request (i.e., eventually, reply).
  852. *
  853. * NOTE:
  854. * The thread must be a valid initiator thread (from a client request) and
  855. * must not be on either a device wait queue or a device active queue.
  856. *
  857. * RETURNS: N/A
  858. */
  859. LOCAL void scsiMgrThreadComplete
  860.     (
  861.     SCSI_THREAD * pThread        /* ptr to thread info */
  862.     )
  863.     {
  864.     SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;
  865.     SCSI_DEBUG_MSG ("scsiMgrThreadComplete: thread 0x%08xn",
  866.     (int) pThread, 0, 0, 0, 0, 0);
  867.     /*
  868.      * Check for contingent allegiance condition on physical device
  869.      */
  870.     if (pThread->status == OK)
  871. {
  872. UINT scsiStatus = *pThread->statusAddress;
  873. switch (scsiStatus & SCSI_STATUS_MASK)
  874.     {
  875.     case SCSI_STATUS_CHECK_CONDITION:
  876.     case SCSI_STATUS_CMD_TERMINATED:
  877.      SCSI_DEBUG_MSG ("scsiMgrThreadComplete: device 0x%08x: "
  878. "contingent allegiance detectedn",
  879.      (int) pScsiPhysDev, 0, 0, 0, 0, 0);
  880.      pScsiPhysDev->pendingCA = TRUE;
  881. break;
  882.     default:
  883. if (pScsiPhysDev->pendingCA)
  884.     {
  885.     SCSI_DEBUG_MSG ("scsiMgrThreadComplete: device 0x%08x: "
  886.     "contingent allegiance clearedn",
  887.      (int) pScsiPhysDev, 0, 0, 0, 0, 0);
  888.     pScsiPhysDev->pendingCA = FALSE;
  889.     }
  890. break;
  891.     }
  892. }
  893.     /*
  894.      * Finish processing the client's request
  895.      */
  896.     scsiMgrRequestComplete (pThread);
  897.     }
  898. /******************************************************************************
  899. *
  900. * scsiMgrThreadDefer - defer execution of an initiator thread
  901. *
  902. * (This routine is called if a thread "loses arbitration" to reselection
  903. * during an attempt to select a target device.)
  904. *
  905. * Remove the thread from its physical device's active queue and re-insert it
  906. * onto the wait queue to be re-despatched at the next opportunity.
  907. *
  908. * NOTE:
  909. * The check that the thread actually was on the active queue avoids any
  910. * possibility of races with the transaction timeout mechanism.
  911. *
  912. * RETURNS: N/A
  913. */
  914. LOCAL void scsiMgrThreadDefer
  915.     (
  916.     SCSI_THREAD * pThread        /* ptr to thread info */
  917.     )
  918.     {
  919.     SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;
  920.     SCSI_DEBUG_MSG ("scsiMgrThreadDefer: thread 0x%08xn",
  921.     (int) pThread, 0, 0, 0, 0, 0);
  922.     if (scsiMgrPhysDevActiveQRemove (pScsiPhysDev, pThread) == OK)
  923. {
  924. scsiMgrPhysDevWaitQAdd (pScsiPhysDev, pThread);
  925. pThread->state = SCSI_THREAD_WAITING;
  926. }
  927.     }
  928. /*******************************************************************************
  929. *
  930. * scsiMgrThreadActivate - start running the specified thread
  931. *
  932. * Allocate a tag number (if required) for the target physical device, build
  933. * a corresponding identification message, and call the controller-specific
  934. * thread activation routine.  Notify the controller and the thread of the
  935. * activation event.
  936. *
  937. * RETURNS: OK, or ERROR if activation failed.
  938. */
  939. LOCAL STATUS scsiMgrThreadActivate
  940.     (
  941.     SCSI_THREAD * pThread
  942.     )
  943.     {
  944.     SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;
  945.     SCSI_CTRL     * pScsiCtrl    = pThread->pScsiCtrl;
  946.     /*
  947.      * Allocate a tag number according to required type
  948.      */
  949.     if (pThread->tagType == SCSI_TAG_DEFAULT)
  950. pThread->tagType = pScsiPhysDev->tagType;
  951.     if (scsiMgrPhysDevTagAllocate (pScsiPhysDev, pThread->tagType,
  952.         &pThread->tagNumber) != OK)
  953. {
  954. SCSI_DEBUG_MSG ("scsiMgrThreadActivate: thread 0x%08x: "
  955. "can't allocate tagn",
  956.      (int) pThread, 0, 0, 0, 0, 0);
  957. return (ERROR);
  958. }
  959.     /*
  960.      * Build identification message using this tag
  961.      */
  962.     pThread->identMsgLength = scsiIdentMsgBuild (pThread->identMsg,
  963.  pScsiPhysDev,
  964.  pThread->tagType,
  965.  pThread->tagNumber);
  966.     /*
  967.      * Initialise active and saved data pointers
  968.      */
  969.     pThread->activeDataLength  = pThread->dataLength;
  970.     pThread->activeDataAddress = pThread->dataAddress;
  971.     pThread->savedDataLength   = pThread->dataLength;
  972.     pThread->savedDataAddress  = pThread->dataAddress;
  973.     /*
  974.      * Activate the thread using the controller driver
  975.      */
  976.     if ((*pScsiCtrl->scsiThreadActivate) (pScsiCtrl, pThread) != OK)
  977. {
  978. SCSI_DEBUG_MSG ("scsiMgrThreadActivate: thread 0x%08x: "
  979. "controller activation failedn",
  980. (int) pThread, 0, 0, 0, 0, 0);
  981. return (ERROR);
  982. }
  983.     scsiMgrCtrlEvent   (pScsiCtrl, SCSI_EVENT_CONNECTED);
  984.     scsiMgrThreadEvent (pThread,   SCSI_THREAD_EVENT_ACTIVATED);
  985.     return (OK);
  986.     }
  987. /*******************************************************************************
  988. *
  989. * scsiMgrCtrlEvent - send an event to the SCSI controller state machine
  990. *
  991. * This routine is called by the thread driver whenever selection,
  992. * reselection, or disconnection occurs or when a thread is activated.
  993. * It manages a simple finite-state machine for the SCSI controller.
  994. *
  995. * NOTE:
  996. * This function should not be called by application programs.
  997. *
  998. * RETURNS: N/A
  999. */
  1000. void scsiMgrCtrlEvent
  1001.     (
  1002.     SCSI_CTRL *     pScsiCtrl,
  1003.     SCSI_EVENT_TYPE eventType
  1004.     )
  1005.     {
  1006.     switch (eventType)
  1007. {
  1008. case SCSI_EVENT_CONNECTED:
  1009.     pScsiCtrl->active = TRUE;
  1010.          break;
  1011. case SCSI_EVENT_DISCONNECTED:
  1012.          pScsiCtrl->active = FALSE;
  1013.     break;
  1014. default:
  1015.     logMsg ("scsiMgrCtrlEvent: invalid event type (%d)n",
  1016.     eventType, 0, 0, 0, 0, 0);
  1017.     break;
  1018. }
  1019.     }
  1020. /*******************************************************************************
  1021. *
  1022. * scsiMgrThreadEvent - send an event to the thread state machine
  1023. *
  1024. * This routine forwards an event to the thread's physical device.  If the 
  1025. * event is completion or deferral, it frees up the tag which was allocated 
  1026. * when the thread was activated and either completes or defers the thread.
  1027. *
  1028. * NOTE:
  1029. * This function should not be called by application programs.
  1030. *
  1031. * The thread passed into this function does not have to be an active client
  1032. * thread (it may be an identification thread).
  1033. *
  1034. * If the thread has no corresponding physical device, this routine does
  1035. * nothing.  (This occassionally occurs if an unexpected disconnection
  1036. * or bus reset happens when an identification thread has not yet identified
  1037. * which physical device it corresponds to.
  1038. *
  1039. * RETURNS: N/A
  1040. */
  1041. void scsiMgrThreadEvent
  1042.     (
  1043.     SCSI_THREAD * pThread,
  1044.     SCSI_THREAD_EVENT_TYPE eventType
  1045.     )
  1046.     {
  1047.     SCSI_PHYS_DEV * pScsiPhysDev = pThread->pScsiPhysDev;
  1048.     SCSI_TAG        tagNum       = pThread->tagNumber;
  1049.     /*
  1050.      * Check for threads with no associated physical device.  In this case,
  1051.      * there is nothing to be done.
  1052.      */
  1053.     if (pScsiPhysDev == 0)
  1054. return;
  1055.     switch (eventType)
  1056. {
  1057. case SCSI_THREAD_EVENT_ACTIVATED:
  1058.     scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_ACTIVATED);
  1059.     break;
  1060.     
  1061. case SCSI_THREAD_EVENT_DISCONNECTED:
  1062.     scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_DISCONNECTED);
  1063.     break;
  1064.     
  1065. case SCSI_THREAD_EVENT_RECONNECTED:
  1066.     scsiMgrPhysDevEvent (pScsiPhysDev, tagNum, SCSI_DEV_RECONNECTED);
  1067.     break;
  1068.     
  1069. case SCSI_THREAD_EVENT_COMPLETED:
  1070.     scsiMgrPhysDevEvent   (pScsiPhysDev, tagNum, SCSI_DEV_COMPLETED);
  1071.     scsiMgrPhysDevTagFree (pScsiPhysDev, tagNum);
  1072.     if (scsiMgrPhysDevActiveQRemove (pScsiPhysDev, pThread) == OK)
  1073.      scsiMgrThreadComplete (pThread);
  1074.     break;
  1075.     
  1076. case SCSI_THREAD_EVENT_DEFERRED:
  1077.     scsiMgrPhysDevEvent   (pScsiPhysDev, tagNum, SCSI_DEV_COMPLETED);
  1078.     scsiMgrPhysDevTagFree (pScsiPhysDev, tagNum);
  1079.     scsiMgrThreadDefer (pThread);
  1080.     break;
  1081. default:
  1082.     logMsg ("scsiMgrThreadEvent: invalid event type (%d)n",
  1083.     eventType, 0, 0, 0, 0, 0);
  1084.     break;
  1085. }
  1086.     }
  1087. /*******************************************************************************
  1088. *
  1089. * scsiMgrPhysDevReset - reset a physical device
  1090. *
  1091. * Clean up all threads currently in progress on the device, failing them
  1092. * with an error code corresponding to SCSI bus reset.
  1093. *
  1094. * Clean up any state variables associated with the device.
  1095. *
  1096. * Any threads waiting for the device to become available are not affected,
  1097. * and will continue to be executed normally.
  1098. *
  1099. * NOTE: all threads are assumed to be physically disconnected (not to be
  1100. * reconnected) by the target device before this routine is called.
  1101. *
  1102. * RETURNS: N/A
  1103. */
  1104. LOCAL void scsiMgrPhysDevReset
  1105.     (
  1106.     SCSI_PHYS_DEV *pScsiPhysDev
  1107.     )
  1108.     {
  1109.     SCSI_THREAD * pThread;
  1110.     /*
  1111.      * Clean up all active threads: none are connected after a reset
  1112.      */
  1113.     while ((pThread = (SCSI_THREAD *) lstGet (&pScsiPhysDev->activeThreads))
  1114. != 0)
  1115. {
  1116. pThread->status = ERROR;
  1117. pThread->errNum = S_scsiLib_BUS_RESET;
  1118.      scsiMgrThreadComplete (pThread);
  1119. }
  1120.     /*
  1121.      * Re-initialise tag system
  1122.      */
  1123.     scsiMgrPhysDevTagInit (pScsiPhysDev);
  1124.     
  1125.     /*
  1126.      * Reset miscellaneous state variables
  1127.      */
  1128.     pScsiPhysDev->connected = FALSE;
  1129.     pScsiPhysDev->pendingCA = FALSE;
  1130.     pScsiPhysDev->nexus  = SCSI_NEXUS_NONE;
  1131.     pScsiPhysDev->curTag = SCSI_TAG_NONE;
  1132.     
  1133.     pScsiPhysDev->nTaggedNexus = 0;
  1134.     }
  1135. /*******************************************************************************
  1136. *
  1137. * scsiMgrPhysDevEvent - notify the physical device of an event
  1138. *
  1139. * Maintain the physical device's state variables according to the type of
  1140. * event and the tag involved.  These state variables affect the scheduling
  1141. * of new threads on the device (see "scsiMgrPhysDevRunnableThreadGet ()").
  1142. *
  1143. * RETURNS: N/A
  1144. */
  1145. LOCAL void scsiMgrPhysDevEvent
  1146.     (
  1147.     SCSI_PHYS_DEV *     pScsiPhysDev,
  1148.     SCSI_TAG            tagNum,
  1149.     SCSI_DEV_EVENT_TYPE eventType
  1150.     )
  1151.     {
  1152.     /*
  1153.      * Validate tag number
  1154.      */
  1155.     if ((tagNum != SCSI_TAG_NONE) && (tagNum >= pScsiPhysDev->nTags))
  1156. {
  1157. logMsg ("scsiMgrPhysDevEvent: device 0x%08x: invalid tag (%d)n",
  1158. (int) pScsiPhysDev, tagNum, 0, 0, 0, 0);
  1159. return;
  1160. }
  1161.     /*
  1162.      * Handle the event for this tag (and the device as a whole)
  1163.      */
  1164.     switch (eventType)
  1165. {
  1166. case SCSI_DEV_ACTIVATED:
  1167.     pScsiPhysDev->curTag    = tagNum;
  1168.     pScsiPhysDev->connected = TRUE;
  1169.     if (tagNum == SCSI_TAG_NONE)
  1170. {
  1171. if (pScsiPhysDev->pendingCA)
  1172.     pScsiPhysDev->savedNexus = pScsiPhysDev->nexus;
  1173. pScsiPhysDev->nexus = SCSI_NEXUS_ITL;
  1174.           }
  1175.     else
  1176. {
  1177. pScsiPhysDev->nexus = SCSI_NEXUS_ITLQ;
  1178. ++pScsiPhysDev->nTaggedNexus;
  1179. }
  1180.     break;
  1181. case SCSI_DEV_DISCONNECTED:
  1182.     pScsiPhysDev->curTag    = SCSI_TAG_NONE;
  1183.     pScsiPhysDev->connected = FALSE;
  1184.     break;
  1185. case SCSI_DEV_RECONNECTED:
  1186.     pScsiPhysDev->curTag    = tagNum;
  1187.     pScsiPhysDev->connected = TRUE;
  1188.     break;
  1189.     
  1190. case SCSI_DEV_COMPLETED:
  1191.     pScsiPhysDev->curTag    = NONE;
  1192.     pScsiPhysDev->connected = FALSE;
  1193.     if (tagNum == SCSI_TAG_NONE)
  1194. {
  1195. pScsiPhysDev->nexus = (pScsiPhysDev->pendingCA)
  1196.               ? pScsiPhysDev->savedNexus
  1197.               : SCSI_NEXUS_NONE;
  1198. }
  1199.     
  1200.     else if (--pScsiPhysDev->nTaggedNexus == 0)
  1201. pScsiPhysDev->nexus = SCSI_NEXUS_NONE;
  1202.     break;
  1203. default:
  1204.     logMsg ("scsiMgrPhysDevEvent: device 0x%08x: "
  1205.     "invalid event type (%d)n",
  1206.     (int) pScsiPhysDev, eventType, 0, 0, 0, 0);
  1207.     break;
  1208. }
  1209.     }
  1210. /*******************************************************************************
  1211. *
  1212. * scsiMgrPhysDevWaitQAdd - add a thread to a physical device's wait queue
  1213. *
  1214. * Insert a thread into the priority-ordered queue of pending requests for
  1215. * a physical device.  Requests of the same priority are queued in FIFO
  1216. * order.  Threads which are recovering from contingent allegiance condition
  1217. * (i.e. have tag type SENSE_RECOVERY) are considered to have higher priority
  1218. * than all other threads waiting for the device.
  1219. *
  1220. * The wait queue is examined to determine the next thread that may be
  1221. * despatched on the device - see "scsiMgrPhysDevRunnableThreadGet()".
  1222. *
  1223. * NOTE:
  1224. * Treating the SENSE_RECOVERY tag type as an extra-high priority is a
  1225. * debatable design.  It may be better to just queue it in correct priority
  1226. * order and have "scsiMgrPhysDevRunnableThreadGet()" scan the wait queue for
  1227. * the first thread with this tag type, when the device has a contingent
  1228. * allegiance condition.
  1229. *
  1230. * RETURNS: N/A
  1231. */
  1232. LOCAL void scsiMgrPhysDevWaitQAdd
  1233.     (
  1234.     SCSI_PHYS_DEV * pScsiPhysDev,
  1235.     SCSI_THREAD   * pThread
  1236.     )
  1237.     {
  1238.     NODE * pPrev = 0;
  1239.     if (pThread->tagType != SCSI_TAG_SENSE_RECOVERY)
  1240. {
  1241. SCSI_THREAD * pCur;
  1242. for (pCur  = (SCSI_THREAD *) lstFirst (&pScsiPhysDev->waitingThreads);
  1243.      pCur != 0;
  1244.      pCur  = (SCSI_THREAD *) lstNext ((NODE *) pCur))
  1245.     {
  1246.     if ((pCur->tagType != SCSI_TAG_SENSE_RECOVERY) &&
  1247. SCSI_IS_HIGHER_PRIORITY (pThread->priority, pCur->priority))
  1248. break;
  1249.  
  1250.     pPrev = (NODE *) pCur;
  1251.     }
  1252. }
  1253.     lstInsert (&pScsiPhysDev->waitingThreads, pPrev, (NODE *) pThread);
  1254.     }
  1255. /*******************************************************************************
  1256. *
  1257. * scsiMgrPhysDevWaitQRemove - remove a thread from a phys dev's wait queue
  1258. *
  1259. * NOTE:
  1260. * It would be nice if "lstDelete()" told you whether or not the target node
  1261. * was on the list - then three would be no need to have the "lstFind" first.
  1262. *
  1263. * RETURNS: OK, or ERROR if the thread was not on the queue.
  1264. */
  1265. LOCAL STATUS scsiMgrPhysDevWaitQRemove
  1266.     (
  1267.     SCSI_PHYS_DEV * pScsiPhysDev,
  1268.     SCSI_THREAD   * pThread
  1269.     )
  1270.     {
  1271.     if (lstFind (&pScsiPhysDev->waitingThreads, (NODE *) pThread) == ERROR)
  1272. return (ERROR);
  1273.     
  1274.     lstDelete (&pScsiPhysDev->waitingThreads, (NODE *) pThread);
  1275.     return (OK);
  1276.     }
  1277. /*******************************************************************************
  1278. *
  1279. * scsiMgrPhysDevRunnableThreadGet - find a runnable thread on this phys dev
  1280. *
  1281. * If the physical device is connected, no new thread can be started.
  1282. * Otherwise, the thread at the front of the wait queue is the only thread to
  1283. * consider (it is the highest priority thread waiting for access to this
  1284. * device).  If there is such a thread, consider its tag type and the current
  1285. * nexus type on the physical device to determine whether or not the thread
  1286. * can be started.
  1287. *
  1288. * Essentially, if the device currently has an ITL nexus it cannot have any
  1289. * new threads started.  If it has an ITLQ nexus, another tagged thread can be
  1290. * started provided there is a tag available, or a sense recovery (untagged)
  1291. * thread can be started.
  1292. *
  1293. * RETURNS: the highest priority thread which can be started on this device,
  1294. * or 0 if no threads are available or the device can't start a new thread.
  1295. */
  1296. LOCAL SCSI_THREAD * scsiMgrPhysDevRunnableThreadGet
  1297.     (
  1298.     SCSI_PHYS_DEV * pScsiPhysDev
  1299.     )
  1300.     {
  1301.     BOOL          canStart;
  1302.     SCSI_THREAD * pThread;
  1303.     
  1304.     if (pScsiPhysDev->connected)
  1305. return (NULL);
  1306.     pThread = (SCSI_THREAD *) lstFirst (&pScsiPhysDev->waitingThreads);
  1307.     if (pThread == 0)
  1308. return (NULL);
  1309.     
  1310.     switch (pScsiPhysDev->nexus)
  1311. {
  1312. case SCSI_NEXUS_NONE:
  1313.     canStart = TRUE;
  1314.     break;
  1315. case SCSI_NEXUS_ITL:
  1316.     canStart = FALSE;
  1317.     break;
  1318. case SCSI_NEXUS_ITLQ:
  1319.     canStart = (pScsiPhysDev->nFreeTags != 0) ||
  1320.        (pThread->tagType == SCSI_TAG_SENSE_RECOVERY);
  1321.     break;
  1322. default:
  1323.     logMsg ("scsiMgrPhysDevRunnableThreadGet: device 0x%08x: "
  1324.     "invalid nexus (%d)n",
  1325.     (int) pScsiPhysDev, pScsiPhysDev->nexus, 0, 0, 0, 0);
  1326.     canStart = FALSE;
  1327.     break;
  1328. }
  1329.     return (canStart ? pThread : 0);
  1330.     }
  1331. /*******************************************************************************
  1332. *
  1333. * scsiMgrPhysDevActiveQAdd - add a thread to a phys dev's active queue
  1334. *
  1335. * Simply insert the thread onto the list.  The list is unordered.
  1336. *
  1337. * RETURNS: N/A
  1338. */
  1339. LOCAL void scsiMgrPhysDevActiveQAdd
  1340.     (
  1341.     SCSI_PHYS_DEV * pScsiPhysDev,
  1342.     SCSI_THREAD   * pThread
  1343.     )
  1344.     {
  1345.     lstInsert (&pScsiPhysDev->activeThreads, 0, (NODE *) pThread);
  1346.     }
  1347. /*******************************************************************************
  1348. *
  1349. * scsiMgrPhysDevActiveQRemove - remove a thread from a phys dev's active queue
  1350. *
  1351. * NOTE:
  1352. * It would be nice if "lstDelete()" told you whether or not the target node
  1353. * was on the list - then three would be no need to have the "lstFind" first.
  1354. *
  1355. * RETURNS: OK, or ERROR if the thread was not on the queue.
  1356. */
  1357. LOCAL STATUS scsiMgrPhysDevActiveQRemove
  1358.     (
  1359.     SCSI_PHYS_DEV * pScsiPhysDev,
  1360.     SCSI_THREAD   * pThread
  1361.     )
  1362.     {
  1363.     if (lstFind (&pScsiPhysDev->activeThreads, (NODE *) pThread) == ERROR)
  1364. return (ERROR);
  1365.     
  1366.     lstDelete (&pScsiPhysDev->activeThreads, (NODE *) pThread);
  1367.     return (OK);
  1368.     }
  1369. /*******************************************************************************
  1370. *
  1371. * scsiMgrPhysDevActiveThreadFind - find thread corresponding to tag on phys dev
  1372. *
  1373. * Search the physical device's active thread list to find one corresponding to
  1374. * the given tag number.
  1375. *
  1376. * NOTE:
  1377. * This function should not be called by application programs.
  1378. *
  1379. * RETURNS: thread ptr, or 0 if no active thread corresponding to this tag
  1380. *
  1381. * NOMANUAL
  1382. */
  1383. SCSI_THREAD * scsiMgrPhysDevActiveThreadFind
  1384.     (
  1385.     SCSI_PHYS_DEV * pScsiPhysDev, /* physical device to search    */
  1386.     SCSI_TAG        tagNum /* tag number, or SCSI_TAG_NONE */
  1387.     )
  1388.     {
  1389.     SCSI_THREAD * pThread;
  1390.     for (pThread  = (SCSI_THREAD *) lstFirst (&pScsiPhysDev->activeThreads);
  1391.  pThread != 0;
  1392.  pThread  = (SCSI_THREAD *) lstNext ((NODE *) pThread))
  1393. {
  1394. if (pThread->tagNumber == tagNum)
  1395.     return (pThread);
  1396. }
  1397.     return (0);
  1398.     }
  1399. /*******************************************************************************
  1400. *
  1401. * scsiMgrPhysDevTagInit - initialise tag table for a physical device
  1402. *
  1403. * Set all tags not in use; reset the free tag count and next free tag number.
  1404. *
  1405. * RETURNS: N/A
  1406. *
  1407. * NOMANUAL
  1408. */
  1409. VOID scsiMgrPhysDevTagInit
  1410.     (
  1411.     SCSI_PHYS_DEV * pScsiPhysDev
  1412.     )
  1413.     {
  1414.     UINT     nTags = pScsiPhysDev->nTags;
  1415.     SCSI_TAG tagNum;
  1416.     /*
  1417.      * Initialise "dummy" tag used for untagged threads
  1418.      */
  1419.     pScsiPhysDev->untagged.inUse = FALSE;
  1420.     /*
  1421.      * Set all real tags to "available"
  1422.      */
  1423.     for (tagNum = 0; tagNum < nTags; ++tagNum)
  1424. {
  1425. SCSI_TAG_INFO * pTag = pScsiPhysDev->pTagInfo + tagNum;
  1426. pTag->inUse = FALSE;
  1427. }
  1428.     pScsiPhysDev->nFreeTags = nTags;
  1429.     pScsiPhysDev->nextTag   = (nTags == 0) ? SCSI_TAG_NONE : 0;
  1430.     }
  1431. /*******************************************************************************
  1432. *
  1433. * scsiMgrPhysDevTagAllocate - allocate a tag number on the physical device
  1434. *
  1435. * Validate the requested tag type; if it is tagged, allocate a tag number
  1436. * on the physical device.
  1437. *
  1438. * The actual tag number allocated has no significance other than that it
  1439. * identifies an active thread on the physical device.  In particular, it has
  1440. * no bearing on the order in which the target executes the command.  Thus the
  1441. * choice of tag number is somewhat arbitrary; however, this routine attempts
  1442. * to use tags in rotation rather than continually re-using the same tag
  1443. * numbers.  (This is primarily because it makes debugging somewhat easier.)
  1444. *
  1445. * NOTE:
  1446. * An incorrect tag type can result from a bad choice by the client, however
  1447. * unavailability of free tags can only result from software failure (the SCSI
  1448. * manager should not be activating a thread on a device which has no tags
  1449. * free !)
  1450. *
  1451. * The search for a free tag could get quite slow when the device supports a
  1452. * large number of tags and they are nearly all in use.  In practice this is
  1453. * not likely to cause problems even with the simple scheme used currently.
  1454. * A more sophisticated approach would be to store free tag numbers on a
  1455. * list or queue, however this would use substantial amounts of memory (up to
  1456. * 256 free tags per physical device).
  1457. *
  1458. * RETURNS: OK, or ERROR if no tags available
  1459. */
  1460. LOCAL STATUS scsiMgrPhysDevTagAllocate
  1461.     (
  1462.     SCSI_PHYS_DEV * pScsiPhysDev,
  1463.     SCSI_TAG_TYPE   tagType,
  1464.     SCSI_TAG      * pTagNum
  1465.     )
  1466.     {
  1467.     BOOL     tagged;
  1468.     SCSI_TAG tagNum;
  1469.     SCSI_TAG_INFO * pTag = 0; /* initialise to avoid warning */
  1470.     if (scsiMgrPhysDevTagTypeValidate (pScsiPhysDev, tagType, &tagged) != OK)
  1471. return (ERROR);
  1472.     
  1473.     if (!tagged)
  1474. {
  1475.      tagNum = SCSI_TAG_NONE;
  1476. pTag = &pScsiPhysDev->untagged;
  1477. }
  1478.     else
  1479. {
  1480. int i;
  1481. if (pScsiPhysDev->nFreeTags == 0)
  1482.     {
  1483.     logMsg ("scsiMgrPhysDevTagAllocate: device 0x%08x: no free tagsn",
  1484.     (int) pScsiPhysDev, 0, 0, 0, 0, 0);
  1485.     errnoSet (S_scsiLib_SOFTWARE_ERROR);
  1486.     return (ERROR);
  1487.     }
  1488. --pScsiPhysDev->nFreeTags;
  1489. /*
  1490.  *  Search for a free tag; starting at one after we last used
  1491.  */
  1492.      tagNum = pScsiPhysDev->nextTag;
  1493. for (i = 0; i < pScsiPhysDev->nTags; ++i)
  1494.     {
  1495.     pTag = (pScsiPhysDev->pTagInfo + tagNum);
  1496.     if (!pTag->inUse)
  1497. break;
  1498.     if (++tagNum >= pScsiPhysDev->nTags)
  1499. tagNum = 0;
  1500.     }
  1501. if (i == pScsiPhysDev->nTags)
  1502.     {
  1503.     logMsg ("scsiMgrPhysDevTagAllocate: device 0x%08x: "
  1504.     "tag not found (%d free)n",
  1505.     (int) pScsiPhysDev, pScsiPhysDev->nTags, 0, 0, 0, 0);
  1506.     errnoSet (S_scsiLib_SOFTWARE_ERROR);
  1507.     return (ERROR);
  1508.     }
  1509. if ((pScsiPhysDev->nextTag = tagNum + 1) == pScsiPhysDev->nTags)
  1510.     pScsiPhysDev->nextTag = 0;
  1511. }
  1512.     
  1513.     pTag->inUse = TRUE;
  1514.     *pTagNum = tagNum;
  1515.     return (OK);
  1516.     }
  1517. /*******************************************************************************
  1518. *
  1519. * scsiMgrPhysDevTagFree - free a tag for the physical device.
  1520. *
  1521. * Mark the specified tag not in use.
  1522. *
  1523. * RETURNS: OK, or ERROR if no tags available
  1524. */
  1525. LOCAL void scsiMgrPhysDevTagFree
  1526.     (
  1527.     SCSI_PHYS_DEV * pScsiPhysDev,
  1528.     SCSI_TAG        tagNum
  1529.     )
  1530.     {
  1531.     SCSI_TAG_INFO * pTag;
  1532.     if (tagNum == SCSI_TAG_NONE)
  1533. {
  1534. pTag = &pScsiPhysDev->untagged;
  1535. }
  1536.     else
  1537. {
  1538. ++pScsiPhysDev->nFreeTags;
  1539.      pTag = (pScsiPhysDev->pTagInfo + tagNum);
  1540. }
  1541.     pTag->inUse = FALSE;
  1542.     }
  1543. /*******************************************************************************
  1544. *
  1545. * scsiMgrPhysDevTagTypeValidate - validate requested tag type for phys dev
  1546. *
  1547. * Check the requested tag type is valid given the current nexus type of the
  1548. * device.  Note the special cases which allow an untagged sense recovery
  1549. * command to be started when the device has tagged nexuses active, provided
  1550. * it is in a contingent allegiance condition.
  1551. *
  1552. * RETURNS: OK, or ERROR if the requested tag type is (currently) invalid
  1553. */
  1554. LOCAL STATUS scsiMgrPhysDevTagTypeValidate
  1555.     (
  1556.     SCSI_PHYS_DEV * pScsiPhysDev,
  1557.     SCSI_TAG_TYPE   tagType,
  1558.     BOOL          * pTagged
  1559.     )
  1560.     {
  1561.     BOOL valid;
  1562.     BOOL tagged;
  1563.     
  1564.     switch (tagType)
  1565. {
  1566.      case SCSI_TAG_UNTAGGED:
  1567.     valid  = (pScsiPhysDev->nexus != SCSI_NEXUS_ITLQ);
  1568.     tagged = FALSE;
  1569.     break;
  1570. case SCSI_TAG_SENSE_RECOVERY:
  1571.     valid  = (pScsiPhysDev->nexus != SCSI_NEXUS_ITLQ) ||
  1572.      pScsiPhysDev->pendingCA;
  1573.     tagged = FALSE;
  1574.     break;
  1575. case SCSI_TAG_SIMPLE:
  1576. case SCSI_TAG_ORDERED:
  1577. case SCSI_TAG_HEAD_OF_Q:
  1578.     valid  = (pScsiPhysDev->nexus   != SCSI_NEXUS_ITL) &&
  1579.      (pScsiPhysDev->tagType != SCSI_TAG_UNTAGGED);
  1580.     tagged = TRUE;
  1581.     break;
  1582.     
  1583.      default:
  1584.     valid  = FALSE;
  1585.     tagged = FALSE;
  1586.     break;
  1587. }
  1588.     if (!valid)
  1589. {
  1590. SCSI_DEBUG_MSG ("scsiPhysDevTagTypeValidate: invalid tag type (%d) "
  1591. "for device 0x%08xn",
  1592. tagType, (int) pScsiPhysDev, 0, 0, 0, 0);
  1593. errnoSet (S_scsiLib_INVALID_TAG_TYPE);
  1594. return (ERROR);
  1595. }
  1596.     *pTagged = tagged;
  1597.     return (OK);
  1598.     }
  1599. /*******************************************************************************
  1600. *
  1601. * scsiMgrShow - show status information for the SCSI manager
  1602. *
  1603. * This routine shows the current state of the SCSI manager for the specified
  1604. * controller, including the total number of threads created and the number of
  1605. * threads currently free.
  1606. *
  1607. * Optionally, this routine also shows details for all created physical devices 
  1608. * on this controller and all threads for which SCSI requests are outstanding.
  1609. * It also shows the IDs of all free threads.
  1610. *
  1611. * NOTE: The information displayed is volatile; this routine is best used when
  1612. * there is no activity on the SCSI bus.  Threads allocated by a client but
  1613. * for which there are no outstanding SCSI requests are not shown.
  1614. *
  1615. * RETURNS: N/A
  1616. */
  1617. void scsiMgrShow
  1618.     (
  1619.     SCSI_CTRL * pScsiCtrl, /* SCSI controller to use        */
  1620.     BOOL        showPhysDevs, /* TRUE => show phys dev details */
  1621.     BOOL        showThreads, /* TRUE => show thread details   */
  1622.     BOOL        showFreeThreads /* TRUE => show free thread IDs  */
  1623.     )
  1624.     {
  1625.     char * state;
  1626.     int    nFree;
  1627.     
  1628.     if (pScsiCtrl == NULL)
  1629. pScsiCtrl = pSysScsiCtrl;
  1630.     
  1631.     if (pScsiCtrl == NULL)
  1632. {
  1633. printf ("No SCSI controller specified.n");
  1634. return;
  1635. }
  1636.     state = pScsiCtrl->active ? "active" : "inactive";
  1637.     
  1638.     nFree = lstCount (&pScsiCtrl->freeThreads);
  1639.     
  1640.     printf ("Controller   State    # Threads (tot/free)n");
  1641.     printf ("----------  --------  --------------------n");
  1642.     printf ("0x%08x  %-8s        %3d  %3dn",
  1643.     (int) pScsiCtrl,
  1644.     state,
  1645.     pScsiCtrl->nThreads,
  1646.     nFree);
  1647.     if (showPhysDevs)
  1648. {
  1649. BOOL noHeader = FALSE;
  1650. int  i;
  1651. printf ("n");
  1652. for (i = 0; i < SCSI_MAX_PHYS_DEVS; ++i)
  1653.     {
  1654.     SCSI_PHYS_DEV * pScsiPhysDev = pScsiCtrl->physDevArr[i];
  1655.     if (pScsiPhysDev != 0)
  1656. {
  1657. scsiPhysDevShow (pScsiPhysDev, FALSE, noHeader);
  1658. noHeader = TRUE;
  1659. }
  1660.     }
  1661. }
  1662.     if (showThreads)
  1663. {
  1664. /*
  1665.  *  This is crude.  A better approach would be to collect all
  1666.  *  the thread IDs into a buffer, then sort by priority before
  1667.  *  calling "scsiThreadShow" for each thread.
  1668.  */
  1669. int i;
  1670. printf ("n");
  1671. for (i = 0; i < SCSI_MAX_PHYS_DEVS; ++i)
  1672.     {
  1673.     SCSI_PHYS_DEV * pScsiPhysDev = pScsiCtrl->physDevArr[i];
  1674.     if (pScsiPhysDev != 0)
  1675. {
  1676. scsiThreadListShow (&pScsiPhysDev->activeThreads);
  1677. scsiThreadListShow (&pScsiPhysDev->waitingThreads);
  1678. }
  1679.     }
  1680. }
  1681.     if (showFreeThreads && (nFree != 0))
  1682. {
  1683. printf ("nFree threads:n");
  1684. scsiThreadListIdShow (&pScsiCtrl->freeThreads);
  1685. }
  1686.     }