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

VxWorks

开发平台:

C/C++

  1.     LOCAL int scsiCmdLength [8] =
  2.         {
  3.         SCSI_GROUP_0_CMD_LENGTH,
  4.         SCSI_GROUP_1_CMD_LENGTH,
  5.         NONE,
  6.         NONE,
  7.         NONE,
  8.         SCSI_GROUP_5_CMD_LENGTH,
  9.         NONE,
  10.         NONE
  11.         };
  12.     if ((*pCmdLength = cmdLength = scsiCmdLength [groupCode]) == NONE)
  13. return (ERROR);
  14.     if ((groupCode == 0) && (logBlockAdrs > 0x1fffff || xferLength > 0xff))
  15. return (ERROR);
  16.     else if (xferLength > 0xffff)
  17. return (ERROR);
  18.     scsiCmd[0] = opCode;
  19.     scsiCmd[1] = (UINT8) ((LUN & 0x7) << 5);
  20.     switch (groupCode)
  21. {
  22. case 0:
  23.     scsiCmd[1] |= (UINT8) ((logBlockAdrs >> 16) & 0x1f);
  24.     scsiCmd[2]  = (UINT8) ((logBlockAdrs >>  8) & 0xff);
  25.     scsiCmd[3]  = (UINT8) ((logBlockAdrs      ) & 0xff);
  26.     scsiCmd[4]  = (UINT8) xferLength;
  27.     scsiCmd[5]  = controlByte;
  28.     break;
  29. case 1:
  30. case 5:
  31.     scsiCmd[1] |= (UINT8) (relAdrs ? 1 : 0);
  32.     scsiCmd[2]  = (UINT8) ((logBlockAdrs >> 24) & 0xff);
  33.     scsiCmd[3]  = (UINT8) ((logBlockAdrs >> 16) & 0xff);
  34.     scsiCmd[4]  = (UINT8) ((logBlockAdrs >>  8) & 0xff);
  35.     scsiCmd[5]  = (UINT8) ((logBlockAdrs      ) & 0xff);
  36.     scsiCmd[6]  = (UINT8) 0;
  37.     if (groupCode == 5)
  38. {
  39.         scsiCmd[7]  = (UINT8) 0;
  40.         scsiCmd[8]  = (UINT8) 0;
  41. }
  42.     scsiCmd [cmdLength - 3] = (UINT8) ((xferLength >> 8) & 0xff);
  43.     scsiCmd [cmdLength - 2] = (UINT8) ((xferLength     ) & 0xff);
  44.     scsiCmd [cmdLength - 1] = controlByte;
  45.     break;
  46. }
  47.     return (OK);
  48.     }
  49. /*
  50.  *   
  51.  *     Controller-independent SCSI support routines 
  52.  *  
  53.  */
  54. /*******************************************************************************
  55. *
  56. * scsiCacheSynchronize - synchronize the caches for data coherency
  57. *
  58. * This routine performs whatever cache action is necessary to ensure cache
  59. * coherency with respect to the various buffers involved in a SCSI command.
  60. *
  61. * The process is as follows:
  62. *
  63. * .iP 1. 4
  64. * The buffers for command, identification, and write data,
  65. * which are simply written to SCSI, are flushed before the command.
  66. * .iP 2.
  67. * The status buffer, which is written and then read, is cleared
  68. * (flushed and invalidated) before the command.
  69. * .iP 3.
  70. * The data buffer for a read command, which is only read, is
  71. * cleared before the command.
  72. * .LP
  73. *
  74. * The data buffer for a read command is cleared before the command rather
  75. * than invalidated after it because it may share dirty cache lines with data
  76. * outside the read buffer.  DMA drivers for older versions of the SCSI
  77. * library have flushed the first and last bytes of the
  78. * data buffer before the command.  However, this approach is not sufficient
  79. * with the enhanced SCSI library because the amount of data transferred into
  80. * the buffer may not fill it, which would cause dirty cache lines which
  81. * contain correct data for the un-filled part of the buffer to be lost
  82. * when the buffer is invalidated after the command.
  83. *
  84. * To optimize the performance of the driver in supporting different caching
  85. * policies, the routine uses the CACHE_USER_FLUSH macro when flushing the
  86. * cache.  In the absence of a CACHE_USER_CLEAR macro, the following steps are 
  87. * taken:
  88. * .iP 1. 5
  89. * If there is a non-NULL flush routine in the `cacheUserFuncs' structure, 
  90. * the cache is cleared.
  91. * .iP 2.
  92. * If there is a non-NULL invalidate routine, the cache is invalidated. 
  93. * .iP 3.
  94. * Otherwise nothing is done; the cache is assumed to be coherent
  95. * without any software intervention.
  96. * .LP
  97. *
  98. * Finally, since flushing (clearing) cache line entries for a large data
  99. * buffer can be time-consuming, if the data buffer is larger
  100. * than a preset (run-time configurable) size, the entire cache is flushed.
  101. *
  102. * RETURNS: N/A
  103. */
  104. void scsiCacheSynchronize
  105.     (
  106.     SCSI_THREAD *     pThread, /* ptr to thread info    */
  107.     SCSI_CACHE_ACTION action /* cache action required */
  108.     )
  109.     {
  110.     int     direction = pThread->dataDirection;
  111.     UINT8 * dataAddr  = pThread->dataAddress;
  112.     UINT    dataSize  = pThread->dataLength;
  113.     FUNCPTR clearRtn = (cacheUserFuncs.flushRtn != NULL)
  114.             ? cacheClear
  115.                  : cacheUserFuncs.invalidateRtn;
  116.     /* 
  117.      * If hardware snooping is enabled then don't do anything. By default
  118.      * cacheSnooping is disabled, unless enabled by the BSP
  119.      */
  120.     if (pThread->pScsiCtrl->cacheSnooping == TRUE)
  121. return;
  122.     /*
  123.      * Invalidating the entire cache is incorrect. However, flushing the
  124.      * entire cache is correct. It is safest to invalidate and flush
  125.      * by cache lines, although there is a performance penalty to be 
  126.      * paid.
  127.      */
  128. #if FALSE
  129.     if (dataSize >= scsiCacheFlushThreshold)
  130. {
  131. dataSize = ENTIRE_CACHE;
  132. dataAddr = 0;
  133. }
  134. #endif
  135.     switch (action)
  136. {
  137.      case SCSI_CACHE_PRE_COMMAND:
  138. #if (CPU == SPARC)
  139.             /*
  140.              *  The "cacheClear ()" function, called by CACHE_USER_FLUSH,
  141.              *  occasionally crashes on microSPARC when asked to clear a
  142.              *  small area of cache (try "repeat (0, cacheClear, 1, 0, 100)").
  143.              *  It appears to work reliably when clearing the entire cache.
  144.              *
  145.              *  To avoid this, if there is a non-null flush routine or a non-
  146.              *  null invalidation routine, just clear the whole cache.
  147.              *  This is a superset of everything normally done.
  148.              *
  149.              *  If both flush and invalidation routines are null, there is
  150.              *  nothing to do.
  151.              */
  152.             if ((cacheUserFuncs.flushRtn      != 0) ||
  153.                 (cacheUserFuncs.invalidateRtn != 0))
  154.                 {
  155.                 cacheClear (DATA_CACHE, 0, ENTIRE_CACHE);
  156.                 }
  157.             break;
  158. #endif
  159.          /*
  160.      * Flush command and identify buffers; clear status buffer.
  161.      */
  162.     CACHE_USER_FLUSH (pThread->identMsg,   pThread->identMsgLength);
  163.          CACHE_USER_FLUSH (pThread->cmdAddress, pThread->cmdLength);
  164.     if (clearRtn != 0)
  165.      (* clearRtn) (DATA_CACHE, pThread->statusAddress,
  166.                   pThread->statusLength);
  167.     /*
  168.      * Flush (write) or clear (read) data buffer.
  169.      */
  170.     if (direction == O_WRONLY)
  171. CACHE_USER_FLUSH (dataAddr, dataSize);
  172.     else if (clearRtn != 0)
  173. {
  174. #if (CPU == MC68040)
  175.      /*
  176.       *  "cacheInvalidate (DATA_CACHE, 0, ENTIRE_CACHE)" crashes
  177.       *  on the 68040 (for some reason).  Use "cacheClear" instead
  178.  *  in this case.
  179.       */
  180. if (dataSize == ENTIRE_CACHE)
  181.     clearRtn = cacheClear;
  182. #endif
  183. (* clearRtn) (DATA_CACHE, dataAddr, dataSize);
  184.      }
  185.     break;
  186.     
  187.      case SCSI_CACHE_POST_COMMAND:
  188.     /*
  189.      * No action is required.  For a read, we cleared the cache
  190.      * before the command and therefore don't need to invalidate
  191.      * it here.
  192.      */
  193.     break;
  194.     
  195.      default:
  196.     logMsg ("scsiCacheSynchronize: invalid action (%d).n",
  197.     action, 0, 0, 0, 0, 0);
  198.     break;
  199. }
  200.     }
  201. /*******************************************************************************
  202. *
  203. * scsiIdentMsgBuild - build an identification message
  204. *
  205. * This routine builds an identification message in the caller's buffer,
  206. * based on the specified physical device, tag type, and tag number.
  207. *
  208. * If the target device does not support messages, there is no identification
  209. * message to build.
  210. *
  211. * Otherwise, the identification message consists of an IDENTIFY byte plus an
  212. * optional QUEUE TAG message (two bytes), depending on the type of tag used.
  213. *
  214. * NOTE:
  215. * This function is not intended for use by application programs.
  216. *
  217. * RETURNS: The length of the resulting identification message in bytes or -1 
  218. * for ERROR.
  219. */
  220. int scsiIdentMsgBuild
  221.     (
  222.     UINT8 *         msg,
  223.     SCSI_PHYS_DEV * pScsiPhysDev,
  224.     SCSI_TAG_TYPE   tagType,
  225.     UINT            tagNumber
  226.     )
  227.     {
  228.     SCSI_TARGET * pScsiTarget = pScsiPhysDev->pScsiTarget;
  229.     
  230.     int msgLen = 0;
  231.     if (!pScsiTarget->messages)
  232. return (0);
  233.     msg[0] = SCSI_MSG_IDENTIFY | (UINT8) pScsiPhysDev->scsiDevLUN;
  234.     if (pScsiTarget->disconnect)
  235.      msg[0] |= SCSI_MSG_IDENT_DISCONNECT;
  236.     switch (tagType)
  237.      {
  238.      case SCSI_TAG_UNTAGGED:
  239.      case SCSI_TAG_SENSE_RECOVERY:
  240.          msgLen = 1;
  241.          break;
  242. case SCSI_TAG_SIMPLE:
  243.     msg[1] = SCSI_MSG_SIMPLE_Q_TAG;
  244.          msg[2] = tagNumber;
  245.          msgLen = 3;
  246.          break;
  247.      case SCSI_TAG_ORDERED:
  248.          msg[1] = SCSI_MSG_ORDERED_Q_TAG;
  249.          msg[2] = tagNumber;
  250.          msgLen = 3;
  251.          break;
  252.      case SCSI_TAG_HEAD_OF_Q:
  253.          msg[1] = SCSI_MSG_HEAD_OF_Q_TAG;
  254.          msg[2] = tagNumber;
  255.          msgLen = 3;
  256.          break;
  257. default:
  258.     logMsg ("scsiIdentMsgBuild: invalid tag type (%d)n",
  259.     tagType, 0, 0, 0, 0, 0);
  260.     return (-1);
  261.         }
  262.     return (msgLen);
  263. }
  264. /*******************************************************************************
  265. *
  266. * scsiIdentMsgParse - parse an identification message
  267. *
  268. * This routine scans a (possibly incomplete) identification message,
  269. * validating it in the process.  If there is an IDENTIFY message, it
  270. * identifies the corresponding physical device.
  271. *
  272. * If the physical device is currently processing an untagged (ITL) nexus,
  273. * identification is complete. Otherwise, the identification is complete only
  274. * if there is a complete QUEUE TAG message.
  275. *
  276. * If there is no physical device corresponding to the IDENTIFY message, or
  277. * if the device is processing tagged (ITLQ) nexuses and the tag does not
  278. * correspond to an active thread (it may have been aborted by a timeout, for
  279. * example), then the identification sequence fails.
  280. *
  281. * The caller's buffers for physical device and tag number (the results
  282. * of the identification process) are always updated.  This is required by
  283. * the thread event handler (see scsiMgrThreadEvent().)
  284. *
  285. * NOTE: This function is not intended for use by application programs.
  286. *
  287. * RETURNS: The identification status (incomplete, complete, or rejected).
  288. */
  289. SCSI_IDENT_STATUS scsiIdentMsgParse
  290.     (
  291.     SCSI_CTRL      * pScsiCtrl,
  292.     UINT8          * msg,
  293.     int              msgLength,
  294.     SCSI_PHYS_DEV ** ppScsiPhysDev,
  295.     SCSI_TAG       * pTagNum
  296.     )
  297.     {
  298.     SCSI_PHYS_DEV   * pScsiPhysDev = 0; /* initialize to avoid warning */
  299.     SCSI_IDENT_STATUS status;
  300.     BOOL              tagged = (msgLength >= 1 + 2); /* id (1) + tag (2) */
  301.     /*
  302.      * If no IDENTIFY message has been received, always incomplete.
  303.      */
  304.     if (msgLength < 1)
  305. {
  306. status = SCSI_IDENT_INCOMPLETE;
  307. }
  308.     /*
  309.      * First byte should be an IDENTIFY message: check it
  310.      */
  311.     else if ((msg[0] & ~SCSI_MSG_IDENT_LUN_MASK) != SCSI_MSG_IDENTIFY)
  312. {
  313. SCSI_ERROR_MSG ("scsiIdentMsgParse: invalid IDENTIFY message (0x%x)n",
  314. msg[0], 0, 0, 0, 0, 0);
  315. status = SCSI_IDENT_FAILED;
  316. }
  317.     
  318.     /*
  319.      * Second byte, if present, should be a SIMPLE QUEUE TAG message: check it
  320.      */
  321.     else if (tagged && (msg[1] != SCSI_MSG_SIMPLE_Q_TAG))
  322. {
  323. SCSI_ERROR_MSG ("scsiIdentMsgParse: not a queue tag message (0x%x)n",
  324. msg[1], 0, 0, 0, 0, 0);
  325. status = SCSI_IDENT_FAILED;
  326. }
  327.     /*
  328.      * IDENTIFY message has been received: get the physical device.
  329.      */
  330.     else if ((pScsiPhysDev = scsiPhysDevIdGet (pScsiCtrl,
  331.        pScsiCtrl->peerBusId,
  332.       msg[0] & SCSI_MSG_IDENT_LUN_MASK)) == 0)
  333. {
  334. status = SCSI_IDENT_FAILED; /* invalid IDENTIFY message */
  335. }
  336.     /*
  337.      * Physical device has been found: if using tagged commands, ident.
  338.      * is complete iff a tag message has been received.
  339.      */
  340.     else if (pScsiPhysDev->nexus == SCSI_NEXUS_ITLQ)
  341. {
  342. status = tagged ? SCSI_IDENT_COMPLETE : SCSI_IDENT_INCOMPLETE;
  343. }
  344.     /*
  345.      * Device is not using tagged commands: there can only be a single
  346.      * thread, so identification is complete.  Error if a tag message
  347.      * has been received.
  348.      */
  349.     else if (!tagged)
  350. {
  351. status = SCSI_IDENT_COMPLETE;
  352. }
  353.     else
  354. {
  355. SCSI_ERROR_MSG ("scsiIdentMsgParse: unexpected tag "
  356.         "(phys dev = 0x%08x)n",
  357. (int) pScsiPhysDev, 0, 0, 0, 0, 0);
  358. tagged = FALSE;
  359. status = SCSI_IDENT_FAILED;
  360. }
  361.     *ppScsiPhysDev = pScsiPhysDev;
  362.     *pTagNum       = tagged ? msg[2] : NONE;
  363.     return (status);
  364.     }
  365. /******************************************************************************
  366. *
  367. * scsiMsgOutComplete - perform post-processing after a SCSI message is sent
  368. *
  369. * This routine parses the complete message and takes any necessary action.
  370. *
  371. * NOTE:
  372. * This function is intended for use only by SCSI controller drivers.
  373. *
  374. * RETURNS: OK, or ERROR if the message is not supported.
  375. */
  376. STATUS scsiMsgOutComplete
  377.     (
  378.     SCSI_CTRL   *pScsiCtrl, /* ptr to SCSI controller info */
  379.     SCSI_THREAD *pThread          /* ptr to thread info          */
  380.     )
  381.     {
  382.     int msgType; /* SCSI message type code */
  383.     msgType = pScsiCtrl->msgOutBuf[0];
  384.     switch (msgType)
  385. {
  386. case SCSI_MSG_ABORT:
  387.     SCSI_DEBUG_MSG ("ABORT message outn", 0, 0, 0, 0, 0, 0);
  388.     break;
  389. case SCSI_MSG_ABORT_TAG:
  390.     SCSI_DEBUG_MSG ("ABORT TAG message outn", 0, 0, 0, 0, 0, 0);
  391.     break;
  392.     
  393.         case SCSI_MSG_MESSAGE_REJECT:
  394.             SCSI_DEBUG_MSG ("MESSAGE REJECT message outn", 0, 0, 0, 0, 0, 0);
  395.             break;
  396.         case SCSI_MSG_NO_OP:
  397.             SCSI_DEBUG_MSG ("NO OP message outn", 0, 0, 0, 0, 0, 0);
  398.             break;
  399.         case SCSI_MSG_EXTENDED_MESSAGE:
  400.     msgType = pScsiCtrl->msgOutBuf[SCSI_EXT_MSG_TYPE_BYTE];
  401.     switch (msgType)
  402. {
  403.              case SCSI_EXT_MSG_SYNC_XFER_REQ:
  404.                     SCSI_DEBUG_MSG ("SYNCHRONOUS TRANSFER REQUEST message outn"
  405.               "    offset = %d, period = %dn",
  406.     pScsiCtrl->msgOutBuf[SCSI_SYNC_XFER_MSG_OFFSET],
  407.     pScsiCtrl->msgOutBuf[SCSI_SYNC_XFER_MSG_PERIOD],
  408.     0, 0, 0, 0);
  409.             scsiSyncXferNegotiate (pScsiCtrl,
  410.    pThread->pScsiTarget,
  411.    SYNC_XFER_MSG_OUT);
  412.             break;
  413.                 case SCSI_EXT_MSG_WIDE_XFER_REQ:
  414.                     SCSI_DEBUG_MSG ("WIDE DATA TRANSFER REQUEST message outn"
  415.               "    xferWidth = %d where 0 => 8 bits 1 => 16...n",
  416.     pScsiCtrl->msgOutBuf[SCSI_WIDE_XFER_MSG_WIDTH],
  417.     0, 0, 0, 0, 0);
  418.             scsiWideXferNegotiate (pScsiCtrl,
  419.    pThread->pScsiTarget,
  420.    WIDE_XFER_MSG_OUT);
  421.             break;
  422.                 default:
  423.     SCSI_MSG ("Unsupported extended message (0x%02x) out !n", 
  424.       msgType, 0, 0, 0, 0, 0);
  425.     return (ERROR);
  426.                 }
  427.             break;
  428.      default:
  429.     if (msgType & SCSI_MSG_IDENTIFY)
  430. {
  431. SCSI_DEBUG_MSG ("IDENTIFY message (0x%02x) outn", msgType,
  432. 0, 0, 0, 0, 0);
  433. }
  434.     else
  435. {
  436. SCSI_MSG ("Unsupported message (0x%02x) out !n", msgType,
  437.   0, 0, 0, 0, 0);
  438. return (ERROR);
  439. }
  440.     break;
  441. }
  442.     return (OK);
  443.     }
  444. /******************************************************************************
  445. *
  446. * scsiMsgOutReject - perform post-processing when an outgoing message is rejected
  447. *
  448. * NOTE:
  449. * This function is intended for use only by SCSI controller drivers.
  450. *
  451. * RETURNS: OK, or ERROR if the message is not supported.
  452. */
  453. void scsiMsgOutReject
  454.     (
  455.     SCSI_CTRL   *pScsiCtrl, /* ptr to SCSI controller info */
  456.     SCSI_THREAD *pThread          /* ptr to thread info          */
  457.     )
  458.     {
  459.     int msgType; /* SCSI message type code */
  460.     pScsiCtrl->msgOutState = SCSI_MSG_OUT_NONE;
  461.     /*
  462.      * Handle rejection of the message according to type
  463.      */
  464.     if ((msgType = pScsiCtrl->msgOutBuf[0]) == SCSI_MSG_EXTENDED_MESSAGE)
  465.         msgType  = pScsiCtrl->msgOutBuf[SCSI_EXT_MSG_TYPE_BYTE];
  466.     switch (msgType)
  467. {
  468.      case SCSI_EXT_MSG_SYNC_XFER_REQ:
  469.             SCSI_DEBUG_MSG ("SYNCHRONOUS TRANSFER REQUEST rejectedn",
  470.     0, 0, 0, 0, 0, 0);
  471.     scsiSyncXferNegotiate (pScsiCtrl,
  472.    pThread->pScsiTarget,
  473.    SYNC_XFER_MSG_REJECTED);
  474.     break;
  475.      case SCSI_EXT_MSG_WIDE_XFER_REQ:
  476.             SCSI_DEBUG_MSG ("WIDE DATA TRANSFER REQUEST rejectedn",
  477.     0, 0, 0, 0, 0, 0);
  478.     scsiWideXferNegotiate (pScsiCtrl,
  479.    pThread->pScsiTarget,
  480.    WIDE_XFER_MSG_REJECTED);
  481.     break;
  482.      default:
  483.     break;
  484. }
  485.     }
  486. /******************************************************************************
  487. *
  488. * scsiMsgInComplete - handle a complete SCSI message received from the target
  489. *
  490. * This routine parses the complete message and takes any necessary action,
  491. * which may include setting up an outgoing message in reply.  If the message
  492. * is not understood, the routine rejects it and returns an ERROR status.
  493. *
  494. * NOTE:
  495. * This function is intended for use only by SCSI controller drivers.
  496. *
  497. * RETURNS: OK, or ERROR if the message is not supported.
  498. */
  499. STATUS scsiMsgInComplete
  500.     (
  501.     SCSI_CTRL   *pScsiCtrl, /* ptr to SCSI controller info */
  502.     SCSI_THREAD *pThread          /* ptr to thread info          */
  503.     )
  504.     {
  505.     int  msgType; /* SCSI message type code        */
  506.     BOOL msgReject = FALSE; /* will we send MSG REJECT msg ? */
  507.     msgType = pScsiCtrl->msgInBuf[0];
  508.     switch (msgType)
  509. {
  510.      case SCSI_MSG_COMMAND_COMPLETE:
  511.     SCSI_DEBUG_MSG ("COMMAND COMPLETE message inn", 0, 0, 0, 0, 0, 0);
  512.     pThread->state = SCSI_THREAD_WAIT_COMPLETE;
  513.     break;
  514.     
  515.         case SCSI_MSG_DISCONNECT:
  516.     SCSI_DEBUG_MSG ("DISCONNECT message inn", 0, 0, 0, 0, 0, 0);
  517.     pThread->state = SCSI_THREAD_WAIT_DISCONNECT;
  518.     break;
  519.     
  520.     
  521. case SCSI_MSG_SAVE_DATA_POINTER:
  522.     SCSI_DEBUG_MSG ("SAVE DATA POINTER message inn", 0, 0, 0, 0, 0, 0);
  523.     pThread->savedDataAddress = pThread->activeDataAddress;
  524.     pThread->savedDataLength  = pThread->activeDataLength;
  525.     break;
  526.     
  527. case SCSI_MSG_RESTORE_POINTERS:
  528.     SCSI_DEBUG_MSG ("RESTORE POINTERS message inn", 0, 0, 0, 0, 0, 0);
  529.     pThread->activeDataAddress = pThread->savedDataAddress;
  530.     pThread->activeDataLength  = pThread->savedDataLength;
  531.     break;
  532.     
  533. case SCSI_MSG_MESSAGE_REJECT:
  534.     SCSI_DEBUG_MSG ("MESSAGE REJECT message inn", 0, 0, 0, 0, 0, 0);
  535.     scsiMsgOutReject (pScsiCtrl, pThread);
  536.     break;
  537.     
  538. case SCSI_MSG_NO_OP:
  539.     SCSI_DEBUG_MSG ("NO OP message inn", 0, 0, 0, 0, 0, 0);
  540.     break;
  541.     
  542.         case SCSI_MSG_EXTENDED_MESSAGE:
  543.             msgType = pScsiCtrl->msgInBuf[SCSI_EXT_MSG_TYPE_BYTE];
  544.     switch (msgType)
  545. {
  546.         case SCSI_EXT_MSG_SYNC_XFER_REQ:
  547.             SCSI_DEBUG_MSG ("SYNCHRONOUS TRANSFER REQUEST message inn"
  548.             "    offset = %d, period = %dn",
  549.         pScsiCtrl->msgInBuf[SCSI_SYNC_XFER_MSG_OFFSET],
  550.         pScsiCtrl->msgInBuf[SCSI_SYNC_XFER_MSG_PERIOD],
  551.         0, 0, 0, 0);
  552.     
  553.             scsiSyncXferNegotiate (pScsiCtrl,
  554.    pThread->pScsiTarget,
  555.    SYNC_XFER_MSG_IN);
  556.             break;
  557.                 case SCSI_EXT_MSG_WIDE_XFER_REQ:
  558.                     SCSI_DEBUG_MSG ("WIDE DATA TRANSFER REQUEST message inn"
  559.               "    xferWidth = %d where 0 => 8 bits 1 => 16...n",
  560.     pScsiCtrl->msgInBuf[SCSI_WIDE_XFER_MSG_WIDTH],
  561.     0, 0, 0, 0, 0);
  562.             scsiWideXferNegotiate (pScsiCtrl,
  563.    pThread->pScsiTarget,
  564.    WIDE_XFER_MSG_IN);
  565.             break;
  566.                 default:
  567.             SCSI_ERROR_MSG ("unsupported extended message in" 
  568.     "(type = 0x%02x)n",
  569.          msgType, 0, 0, 0, 0, 0);
  570.             msgReject = TRUE;
  571.             break;
  572. }
  573.     
  574.     break;
  575. default:
  576.     SCSI_ERROR_MSG ("unsupported message in (type = 0x%02x)n",
  577.     msgType, 0, 0, 0, 0, 0);
  578.     
  579.     msgReject = TRUE;
  580.     break;
  581. }
  582.     
  583.     /*
  584.      * If the message is to be rejected, set up a MESSAGE REJECT message out.
  585.      */
  586.     if (msgReject)
  587. {
  588. pScsiCtrl->msgOutState  = SCSI_MSG_OUT_PENDING;
  589. pScsiCtrl->msgOutBuf[0] = SCSI_MSG_MESSAGE_REJECT;
  590. pScsiCtrl->msgOutLength = 1;
  591. }
  592.     
  593.     return (msgReject ? ERROR : OK);
  594.     }
  595. /*******************************************************************************
  596. *
  597. * scsiSyncXferNegotiate - initiate or continue negotiating transfer parameters
  598. *
  599. * This routine manages negotiation by means of a finite-state machine which
  600. * is driven by "significant events" such as incoming and outgoing messages.
  601. * Each SCSI target has its own independent state machine.
  602. *
  603. * NOTE:
  604. * If the controller does not support synchronous transfer or if the
  605. * target's maximum REQ/ACK offset is zero, attempts to initiate a round of
  606. * negotiation are ignored.
  607. *
  608. * This function is intended for use only by SCSI controller drivers.
  609. *
  610. * RETURNS: N/A
  611. */
  612. void scsiSyncXferNegotiate
  613.     (
  614.     SCSI_CTRL           *pScsiCtrl, /* ptr to SCSI controller info  */
  615.     SCSI_TARGET         *pScsiTarget, /* ptr to SCSI target info      */
  616.     SCSI_SYNC_XFER_EVENT eventType /* tells what has just happened */
  617.     )
  618.     {
  619.     SCSI_SYNC_XFER_STATE state = pScsiTarget->syncXferState;
  620.     UINT8 offset;
  621.     UINT8 period;
  622.     BOOL  setValues = FALSE;
  623.     BOOL  sendMsg   = FALSE;
  624.     switch (eventType)
  625. {
  626. case SYNC_XFER_RESET:
  627.     state = SYNC_XFER_NOT_NEGOTIATED;
  628.     break;
  629.      case SYNC_XFER_NEW_THREAD:
  630.     offset = pScsiTarget->maxOffset;
  631.     period = pScsiTarget->minPeriod;
  632.     if (pScsiCtrl->syncXfer &&
  633.                 ((offset !=  pScsiTarget->xferOffset) ||
  634.  (period !=  pScsiTarget->xferPeriod)) &&
  635. (state  != SYNC_XFER_NEGOTIATION_COMPLETE))
  636. {
  637. /* initiate a round of negotiation */
  638. sendMsg = TRUE;
  639. state   = SYNC_XFER_REQUEST_PENDING;
  640. }
  641.     else
  642. state = SYNC_XFER_NEGOTIATION_COMPLETE;
  643.          break;
  644.      case SYNC_XFER_MSG_IN:
  645.     offset = pScsiCtrl->msgInBuf[SCSI_SYNC_XFER_MSG_OFFSET];
  646.     period = pScsiCtrl->msgInBuf[SCSI_SYNC_XFER_MSG_PERIOD];
  647.     if (state == SYNC_XFER_REQUEST_SENT)
  648. {
  649. /* target is replying to our initial request */
  650. setValues = TRUE;
  651. state     = SYNC_XFER_NEGOTIATION_COMPLETE;
  652. }
  653.     else
  654. {
  655. /* target is making unsolicited request */
  656. sendMsg = TRUE;
  657.           state   = SYNC_XFER_REPLY_PENDING;
  658. }
  659.          break;
  660.      case SYNC_XFER_MSG_OUT:
  661.     offset = pScsiCtrl->msgOutBuf[SCSI_SYNC_XFER_MSG_OFFSET];
  662.     period = pScsiCtrl->msgOutBuf[SCSI_SYNC_XFER_MSG_PERIOD];
  663.     if (state == SYNC_XFER_REQUEST_PENDING)
  664. {
  665. /* we have sent initial request (need target's reply) */
  666. state = SYNC_XFER_REQUEST_SENT;
  667. }
  668.     else if (state == SYNC_XFER_REPLY_PENDING)
  669. {
  670. /* we have replied to target's unsolicited request */
  671. setValues = TRUE;
  672. state     = SYNC_XFER_NEGOTIATION_COMPLETE;
  673. }
  674.     else
  675. SCSI_ERROR_MSG ("scsiSyncXferNegotiate: unexpected msg outn",
  676. 0, 0, 0, 0, 0, 0);
  677.          break;
  678.      case SYNC_XFER_MSG_REJECTED:
  679.     offset = SCSI_SYNC_XFER_ASYNC_OFFSET;
  680.     period = SCSI_SYNC_XFER_ASYNC_PERIOD;
  681.     
  682.     if (state == SYNC_XFER_REQUEST_SENT)
  683. {
  684. /* target has rejected our initial request */
  685. setValues = TRUE;
  686. state     = SYNC_XFER_NEGOTIATION_COMPLETE;
  687. }
  688.          break;
  689.      default:
  690.     SCSI_MSG ("scsiSyncXferNegotiate: invalid event type (%d)n",
  691.       eventType, 0, 0, 0, 0, 0);
  692.     break;
  693. }
  694.     if (sendMsg)
  695.      {
  696. UINT8 *msg = pScsiCtrl->msgOutBuf;
  697. if (pScsiCtrl->scsiSpecialHandler != NULL)
  698.     {
  699.     if ((pScsiTarget->syncSupport) && (pScsiTarget->syncXferState !=
  700.       SYNC_XFER_NEGOTIATION_COMPLETE))
  701. {
  702. (*pScsiCtrl->scsiXferParamsQuery) (pScsiCtrl, &offset, 
  703.    &period);
  704. if ((*pScsiCtrl->scsiXferParamsSet) (pScsiCtrl, offset, period)
  705.     != OK)
  706.     SCSI_ERROR_MSG ("syncXferNego: can't set xfer params.n",
  707.     0, 0, 0, 0, 0, 0);
  708. state = SYNC_XFER_NEGOTIATION_COMPLETE;
  709. }
  710.     }
  711. else
  712.     {
  713.     (*pScsiCtrl->scsiXferParamsQuery) (pScsiCtrl, &offset, &period);
  714.     
  715.     msg[0]                         = SCSI_MSG_EXTENDED_MESSAGE;
  716.     msg[SCSI_EXT_MSG_LENGTH_BYTE]  = SCSI_SYNC_XFER_REQ_MSG_LENGTH;
  717.     msg[SCSI_EXT_MSG_TYPE_BYTE]    = SCSI_EXT_MSG_SYNC_XFER_REQ;
  718.     msg[SCSI_SYNC_XFER_MSG_PERIOD] = period;
  719.     msg[SCSI_SYNC_XFER_MSG_OFFSET] = offset;
  720.     
  721.     pScsiCtrl->msgOutState  = SCSI_MSG_OUT_PENDING;
  722.     pScsiCtrl->msgOutLength = SCSI_EXT_MSG_HDR_LENGTH +
  723.       SCSI_SYNC_XFER_REQ_MSG_LENGTH;
  724.     }
  725. }
  726.     if (setValues)
  727.      {
  728. pScsiTarget->xferOffset = offset;
  729. pScsiTarget->xferPeriod = period;
  730. if ((*pScsiCtrl->scsiXferParamsSet) (pScsiCtrl, offset, period) != OK)
  731.     {
  732.     SCSI_ERROR_MSG ("scsiSyncXferNegotiate: can't set xfer params.n",
  733.     0, 0, 0, 0, 0, 0);
  734.     }
  735.      }
  736.     pScsiTarget->syncXferState = state;
  737.     }
  738. /*******************************************************************************
  739. *
  740. * scsiWideXferNegotiate - initiate or continue negotiating wide parameters
  741. *
  742. * This routine manages negotiation means of a finite-state machine which is
  743. * driven by "significant events" such as incoming and outgoing messages.
  744. * Each SCSI target has its own independent state machine.
  745. *
  746. * NOTE:
  747. * If the controller does not support wide transfers or the
  748. * target's transfer width is zero, attempts to initiate a round of
  749. * negotiation are ignored; this is because zero is the default narrow transfer.
  750. *
  751. * This function is intended for use only by SCSI controller drivers.
  752. *
  753. * RETURNS: N/A
  754. */
  755. void scsiWideXferNegotiate
  756.     (
  757.     SCSI_CTRL           *pScsiCtrl, /* ptr to SCSI controller info  */
  758.     SCSI_TARGET         *pScsiTarget, /* ptr to SCSI target info      */
  759.     SCSI_WIDE_XFER_EVENT eventType /* tells what has just happened */
  760.     )
  761.     {
  762.     SCSI_WIDE_XFER_STATE state = pScsiTarget->wideXferState;
  763.     UINT8 xferWidth;
  764.     BOOL  setValues = FALSE;
  765.     BOOL  sendMsg   = FALSE;
  766.     switch (eventType)
  767. {
  768. case WIDE_XFER_RESET:
  769.     state = WIDE_XFER_NOT_NEGOTIATED;
  770.     break;
  771.      case WIDE_XFER_NEW_THREAD:
  772.     xferWidth = pScsiTarget->xferWidth;
  773.     if (pScsiCtrl->wideXfer                     &&
  774. (xferWidth != SCSI_WIDE_XFER_SIZE_NARROW) &&
  775. (state  != WIDE_XFER_NEGOTIATION_COMPLETE))
  776. {
  777. /* initiate a round of negotiation */
  778. sendMsg = TRUE;
  779. state   = WIDE_XFER_REQUEST_PENDING;
  780. /* 
  781.  * Set the synchronous state to "complete". This state 
  782.  * should be reset when the wide negotiation is over. This
  783.  * is because a wide negotiation must occur before a 
  784.  * sync xfer negotiation.
  785.  */
  786. if (pScsiCtrl->scsiSpecialHandler == NULL)
  787.     pScsiTarget->syncXferState = SYNC_XFER_NEGOTIATION_COMPLETE;
  788. }
  789.     else
  790. {
  791. if ((pScsiCtrl->scsiSpecialHandler != NULL) &&
  792.     (state != WIDE_XFER_NEGOTIATION_COMPLETE))
  793.     sendMsg = TRUE;
  794. else 
  795.     state = WIDE_XFER_NEGOTIATION_COMPLETE;
  796. }
  797.          break;
  798.      case WIDE_XFER_MSG_IN:
  799.     xferWidth = pScsiCtrl->msgInBuf[SCSI_WIDE_XFER_MSG_WIDTH];
  800.     if (state == WIDE_XFER_REQUEST_SENT)
  801. {
  802. /* target is replying to our initial request */
  803. setValues = TRUE;
  804. state     = WIDE_XFER_NEGOTIATION_COMPLETE;
  805.                 /* 
  806.  * After a wide negotiation is complete, a synchronous
  807.  * negotiation must be activated when the next new
  808.  * thread begins.
  809.  */
  810. pScsiTarget->syncXferState = SYNC_XFER_NOT_NEGOTIATED;
  811. }
  812.     else
  813. {
  814. /* target is making unsolicited request */
  815. sendMsg = TRUE;
  816.           state   = WIDE_XFER_REPLY_PENDING;
  817. }
  818.          break;
  819.      case WIDE_XFER_MSG_OUT:
  820.     xferWidth = pScsiCtrl->msgOutBuf[SCSI_WIDE_XFER_MSG_WIDTH];
  821.     if (state == WIDE_XFER_REQUEST_PENDING)
  822. {
  823. /* we have sent initial request (need target's reply) */
  824. state = WIDE_XFER_REQUEST_SENT;
  825. }
  826.     else if (state == WIDE_XFER_REPLY_PENDING)
  827. {
  828. /* we have replied to target's unsolicited request */
  829. setValues = TRUE;
  830. state     = WIDE_XFER_NEGOTIATION_COMPLETE;
  831. /* Allow a synchronous negotiation to occur */
  832. pScsiTarget->syncXferState = SYNC_XFER_NOT_NEGOTIATED;
  833. }
  834.     else
  835. SCSI_ERROR_MSG ("scsiWideXferNegotiate: unexpected msg outn",
  836. 0, 0, 0, 0, 0, 0);
  837.          break;
  838.      case WIDE_XFER_MSG_REJECTED:
  839.     xferWidth = SCSI_WIDE_XFER_SIZE_NARROW;
  840.     
  841.     if (state == WIDE_XFER_REQUEST_SENT)
  842. {
  843. /* target has rejected our initial request */
  844. setValues = TRUE;
  845. state     = WIDE_XFER_NEGOTIATION_COMPLETE;
  846. /* Allow a synchronous negotiation to occur */
  847. pScsiTarget->syncXferState = SYNC_XFER_NOT_NEGOTIATED;
  848. }
  849.          break;
  850.      default:
  851.     SCSI_MSG ("scsiWideXferNegotiate: invalid event type (%d)n",
  852.       eventType, 0, 0, 0, 0, 0);
  853.     break;
  854. }
  855.     if (sendMsg)
  856.      {
  857. UINT8 *msg = pScsiCtrl->msgOutBuf;
  858. /*
  859.          * Make sure that we are sending the correct params according to the
  860.  * controller driver.
  861.  */
  862. if (pScsiCtrl->scsiSpecialHandler != NULL)
  863.     {
  864.     if ((pScsiTarget->wideSupport) && (pScsiTarget->wideXferState != 
  865.        WIDE_XFER_NEGOTIATION_COMPLETE))
  866. {
  867. if ((*pScsiCtrl->scsiWideXferParamsSet) (pScsiCtrl, xferWidth) 
  868.     != OK)
  869.     SCSI_ERROR_MSG ("syncXferNego: can't set xfer params.n",
  870.     0, 0, 0, 0, 0, 0);
  871. state = WIDE_XFER_NEGOTIATION_COMPLETE;
  872. pScsiTarget->syncXferState = SYNC_XFER_NOT_NEGOTIATED;
  873. }
  874.     }
  875. else
  876.     {
  877.     (*pScsiCtrl->scsiWideXferParamsQuery) (pScsiCtrl, &xferWidth);
  878.     msg[0]                         = SCSI_MSG_EXTENDED_MESSAGE;
  879.     msg[SCSI_EXT_MSG_LENGTH_BYTE]  = SCSI_WIDE_XFER_REQ_MSG_LENGTH;
  880.     msg[SCSI_EXT_MSG_TYPE_BYTE]    = SCSI_EXT_MSG_WIDE_XFER_REQ;
  881.     msg[SCSI_WIDE_XFER_MSG_WIDTH]  = xferWidth;
  882.     
  883.     pScsiCtrl->msgOutState  = SCSI_MSG_OUT_PENDING;
  884.     pScsiCtrl->msgOutLength = SCSI_EXT_MSG_HDR_LENGTH +
  885.       SCSI_WIDE_XFER_REQ_MSG_LENGTH;
  886.     }
  887. }
  888.     if (setValues)
  889.      {
  890. pScsiTarget->xferWidth = xferWidth;
  891. if ((*pScsiCtrl->scsiWideXferParamsSet) (pScsiCtrl, xferWidth) != OK)
  892.     {
  893.     SCSI_ERROR_MSG ("scsiWideXferNegotiate: can't set xfer params.n",
  894.     0, 0, 0, 0, 0, 0);
  895.     }
  896.      }
  897.     pScsiTarget->wideXferState = state;
  898.     }
  899. /*******************************************************************************
  900. *
  901. * scsiTimeoutCvt - convert timeout in microseconds to system clock ticks
  902. *
  903. * Clip the specified timeout to be within the allowed range, then convert
  904. * to system clock ticks.
  905. *
  906. * NOTE: this is non-trivial simply because it must avoid problems with
  907. * overflow or underflow during the conversion.  A quick-and-dirty approach
  908. * would use floating point maths, but that needlessly drags in another
  909. * (possibly large) library.
  910. *
  911. * RETURNS: timeout in system clock ticks
  912. */
  913. LOCAL UINT scsiTimeoutCvt
  914.     (
  915.     UINT uSecs /* timeout in microseconds */
  916.     )
  917.     {
  918.     UINT ticksPerSec = sysClkRateGet ();
  919.     UINT secs;
  920.     UINT Mticks;
  921.     
  922.     /*
  923.      * Clip timeout (if necessary) to be within current allowed range
  924.      */
  925.     if (uSecs > scsiMaxTimeout)
  926. uSecs = scsiMaxTimeout;
  927.     if (uSecs < scsiMinTimeout)
  928. uSecs = scsiMinTimeout;
  929.     /*
  930.      * Convert timeout from usec to system clock ticks
  931.      */
  932.     if (uSecs < 0xffffffff / ticksPerSec)
  933. {
  934. Mticks = uSecs * ticksPerSec;
  935. return (Mticks / 1000000);
  936. }
  937.     else
  938. {
  939. secs = uSecs / 1000000;
  940.      return (secs * ticksPerSec);
  941. }
  942.     }
  943. /*******************************************************************************
  944. *
  945. * scsiPriorityCvt - convert priority for a SCSI transaction
  946. *
  947. * Converts a priority as specified by the application to one used by the
  948. * SCSI manager task.  If the application specifies a default priority, the
  949. * current task priority is used.  Otherwise, the specified value is used.
  950. *
  951. * NOTE:
  952. * This routine should trap out-of-range priorities and return an error.
  953. *
  954. * RETURNS: SCSI transaction priority
  955. */
  956. LOCAL SCSI_PRIORITY scsiPriorityCvt
  957.     (
  958.     UINT priority
  959.     )
  960.     {
  961.     if (priority == SCSI_THREAD_TASK_PRIORITY)
  962. {
  963. int taskPriority;
  964.      taskPriorityGet (0, &taskPriority);
  965. priority = taskPriority;
  966. }
  967.     return (priority);
  968.     }
  969. /*******************************************************************************
  970. *
  971. * scsiThreadCreate - create and initialise a new SCSI thread context
  972. *
  973. * Use the thread allocator to allocate a thread structure.  Initialise the
  974. * thread context from the transaction it will execute.
  975. *
  976. * RETURNS: thread ptr, or 0 if an error occurs
  977. */
  978. LOCAL SCSI_THREAD * scsiThreadCreate
  979.     (
  980.     SCSI_PHYS_DEV    * pScsiPhysDev,    /* physical device used by thread  */
  981.     SCSI_TRANSACTION * pScsiXaction /* transaction thread will execute */
  982.     )
  983.     {
  984.     SCSI_THREAD * pThread;
  985.     SCSI_CTRL *   pScsiCtrl = pScsiPhysDev->pScsiCtrl;
  986.     
  987.     /*
  988.      * Allocate a thread structure
  989.      */
  990.     if ((pThread = scsiThreadAllocate (pScsiCtrl)) == 0)
  991. {
  992. SCSI_DEBUG_MSG ("scsiThreadCreate: can't allocate thread.n",
  993. 0, 0, 0, 0, 0, 0);
  994. return (0);
  995. }
  996.     /*
  997.      * Initialise thread structure for this transaction
  998.      */
  999.     pThread->pScsiCtrl     =  pScsiCtrl;
  1000.     pThread->pScsiPhysDev  =  pScsiPhysDev;
  1001.     pThread->pScsiTarget   =  pScsiPhysDev->pScsiTarget;
  1002.     
  1003.     pThread->role          =  SCSI_ROLE_INITIATOR;
  1004.     pThread->state         =  SCSI_THREAD_INACTIVE;
  1005.     if (pScsiXaction->cmdTimeout == WAIT_FOREVER)
  1006. pThread->timeout = WAIT_FOREVER;
  1007.     else
  1008. pThread->timeout   =  scsiTimeoutCvt  (pScsiXaction->cmdTimeout);
  1009.     pThread->priority    =  scsiPriorityCvt (pScsiXaction->priority);
  1010.     pThread->dataDirection =  pScsiXaction->dataDirection;
  1011.     pThread->tagType       =  pScsiXaction->tagType;
  1012.     pThread->cmdAddress    =  pScsiXaction->cmdAddress;
  1013.     pThread->cmdLength     =  pScsiXaction->cmdLength;
  1014.     pThread->dataAddress   =  pScsiXaction->dataAddress;
  1015.     pThread->dataLength    =  pScsiXaction->dataLength;
  1016.     pThread->statusAddress = &pScsiXaction->statusByte;
  1017.     pThread->statusLength  =  1;
  1018.     return (pThread);
  1019.     }
  1020.     
  1021. /*******************************************************************************
  1022. *
  1023. * scsiThreadDelete - delete a SCSI thread context
  1024. *
  1025. * Deallocate the thread structure.
  1026. *
  1027. * NOTE:
  1028. * This function is provided mainly for symmetry with "scsiThreadCreate()",
  1029. * and to provide a place-holder for future extensions.
  1030. *
  1031. * RETURNS: N/A
  1032. */
  1033. LOCAL void scsiThreadDelete
  1034.     (
  1035.     SCSI_THREAD * pThread         /* thread to be destroyed */
  1036.     )
  1037.     {
  1038.     /*
  1039.      * Deallocate the thread structure
  1040.      */
  1041.     scsiThreadDeallocate (pThread->pScsiCtrl, pThread);
  1042.     }
  1043.     
  1044. /*******************************************************************************
  1045. *
  1046. * scsiThreadAllocate - allocate and initialise a SCSI thread structure
  1047. *
  1048. * To avoid dynamic creation and deletion of threads (and the objects they
  1049. * contain) for every SCSI transaction, a pool of available thread structures
  1050. * is automatically built up and maintained for each SCSI controller.
  1051. *
  1052. * Thus, the allocator first checks the pool (list) of free threads and takes
  1053. * a thread from this pool if possible.  Otherwise (there are no free threads)
  1054. * it allocates storage for and initialises a number of thread structures,
  1055. * reserves one to be returned to the caller, and adds the rest to the free
  1056. * list.
  1057. *
  1058. * Two globals control the allocation policy:
  1059. *
  1060. *   scsiAllocNumThreads - how many threads to allocate in one go, and
  1061. *
  1062. *   scsiMaxNumThreads - the maximum number of threads to allow per ctrlr
  1063. *
  1064. * NOTE:
  1065. * If a new thread cannot be allocated, this routine returns an error rather
  1066. * than waiting for a thread to become free.
  1067. *
  1068. * Access to the free thread list must be serialised because this routine is
  1069. * called in the context of the SCSI client task(s).
  1070. *
  1071. * RETURNS: thread ptr, or 0 if none can be allocated
  1072. */
  1073. LOCAL SCSI_THREAD * scsiThreadAllocate
  1074.     (
  1075.     SCSI_CTRL * pScsiCtrl
  1076.     )
  1077.     {
  1078.     SCSI_THREAD * pThread;
  1079.     semTake (pScsiCtrl->mutexSem, WAIT_FOREVER);
  1080.     
  1081.     if ((pThread = (SCSI_THREAD *) lstGet (&pScsiCtrl->freeThreads)) == 0)
  1082. {
  1083. /*
  1084.  *  No free threads: create more if possible.
  1085.       */
  1086.      if (pScsiCtrl->nThreads >= scsiMaxNumThreads)
  1087.     {
  1088.     SCSI_DEBUG_MSG ("scsiThreadAllocate: max threads (%d) reachedn",
  1089.     scsiMaxNumThreads, 0, 0, 0, 0, 0);
  1090.     errnoSet (S_scsiLib_NO_MORE_THREADS);
  1091.     }
  1092. else
  1093.     {
  1094.     char * pArray;
  1095.     int    i;
  1096.     int    nThreads = min (scsiAllocNumThreads,
  1097.    scsiMaxNumThreads - pScsiCtrl->nThreads);
  1098.     if ((pArray = scsiThreadArrayCreate (pScsiCtrl, nThreads)) == 0)
  1099. {
  1100. SCSI_DEBUG_MSG ("scsiThreadAllocate: can't create arrayn",
  1101. 0, 0, 0, 0, 0, 0);
  1102.                 semGive (pScsiCtrl->mutexSem);
  1103. return (NULL);
  1104. }
  1105.     pScsiCtrl->nThreads += nThreads;
  1106.     /*
  1107.      *  Grab the first one; put the rest onto the free queue
  1108.      */
  1109.     pThread = (SCSI_THREAD *) pArray;
  1110.     for (i = 1; i < nThreads; ++i)
  1111.           lstAdd (&pScsiCtrl->freeThreads,
  1112. (NODE *) (pArray + i * pScsiCtrl->threadSize));
  1113.     }
  1114. }
  1115.     semGive (pScsiCtrl->mutexSem);
  1116.     
  1117.     return (pThread);
  1118.     }
  1119. /*******************************************************************************
  1120. *
  1121. * scsiThreadDeallocate - deallocate a thread structure
  1122. *
  1123. * Deallocation consists of returning the thread structure to the free thread
  1124. * list: once allocated, threads are never "really freed".
  1125. *
  1126. * NOTE:
  1127. * Access to the free thread list must be serialised because this routine is
  1128. * called in the context of the SCSI client task(s).
  1129. *
  1130. * RETURNS: N/A
  1131. */
  1132. LOCAL void scsiThreadDeallocate
  1133.     (
  1134.     SCSI_CTRL *   pScsiCtrl,
  1135.     SCSI_THREAD * pThread
  1136.     )
  1137.     {
  1138.     semTake (pScsiCtrl->mutexSem, WAIT_FOREVER);
  1139.     
  1140.     lstAdd (&pScsiCtrl->freeThreads, (NODE *) pThread);
  1141.     semGive (pScsiCtrl->mutexSem);
  1142.     }
  1143. /*******************************************************************************
  1144. *
  1145. * scsiThreadArrayCreate - allocate and initialise storage for N threads
  1146. *
  1147. * Allocate storage for an array of `nThreads' thread structures, each of the
  1148. * controller-specific size.  Step through the array calling the controller-
  1149. * specific initialisation routine for each thread structure.
  1150. *
  1151. * RETURNS: ptr to array of thread structures, or 0 if an error occurs
  1152. */
  1153. LOCAL char * scsiThreadArrayCreate
  1154.     (
  1155.     SCSI_CTRL * pScsiCtrl,
  1156.     int         nThreads
  1157.     )
  1158.     {
  1159.     char * pArray;
  1160.     int    i;
  1161.     /*
  1162.      * Allocate memory for an array of thread structures
  1163.      */
  1164.     if ((pArray = malloc (nThreads * pScsiCtrl->threadSize)) == 0)
  1165. {
  1166. SCSI_DEBUG_MSG ("scsiThreadArrayCreate: can't allocate threads.n",
  1167. 0, 0, 0, 0, 0, 0);
  1168. return (0);
  1169. }
  1170.     /*
  1171.      * Initialise (controller-specific) each thread structure in array
  1172.      */
  1173.     for (i = 0; i < nThreads; ++i)
  1174. {
  1175. SCSI_THREAD * pThread = (SCSI_THREAD *) (pArray +
  1176.  i * pScsiCtrl->threadSize);
  1177.      if ((*pScsiCtrl->scsiThreadInit) (pScsiCtrl, pThread) != OK)
  1178.     {
  1179.     SCSI_DEBUG_MSG ("scsiThreadArrayCreate: can't initialise threadn",
  1180.     0, 0, 0, 0, 0, 0);
  1181.     free (pArray);
  1182.     return (0);
  1183.     }
  1184. }
  1185.     return (pArray);
  1186.     }
  1187. /*******************************************************************************
  1188. *
  1189. * scsiThreadInit - perform generic SCSI thread initialization
  1190. *
  1191. * This routine initializes the controller-independent parts of a thread 
  1192. * structure, which are specific to the SCSI manager.
  1193. *
  1194. * NOTE:
  1195. * This function should not be called by application programs.  It is intended
  1196. * to be used by SCSI controller drivers.
  1197. *
  1198. * RETURNS: OK, or ERROR if the thread cannot be initialized.
  1199. */
  1200. STATUS scsiThreadInit
  1201.     (
  1202.     SCSI_THREAD * pThread
  1203.     )
  1204.     {
  1205.     if ((pThread->replyQ = msgQCreate (1, sizeof (SCSI_REPLY),
  1206.           scsiThreadReplyQOptions)) == 0)
  1207. {
  1208. SCSI_DEBUG_MSG ("scsiThreadInit: can't create thread's reply queue.n",
  1209. 0, 0, 0, 0, 0, 0);
  1210. return (ERROR);
  1211. }
  1212.     if ((pThread->wdog = wdCreate ()) == 0)
  1213. {
  1214. SCSI_DEBUG_MSG ("scsiThreadInit: can't create thread's watchdog.n",
  1215. 0, 0, 0, 0, 0, 0);
  1216. return (ERROR);
  1217. }
  1218.     
  1219.     return (OK);
  1220.     }
  1221. /*******************************************************************************
  1222. *
  1223. * scsiThreadExecute - execute the specified thread
  1224. *
  1225. * Build an activation request and execute it via the SCSI manager.  Parse the
  1226. * return status in the SCSI manager's reply message.
  1227. *
  1228. * RETURNS: OK, or ERROR if the thread could not be executed, or failed
  1229. */
  1230. LOCAL STATUS scsiThreadExecute
  1231.     (
  1232.     SCSI_THREAD * pThread         /* thread to be executed  */
  1233.     )
  1234.     {
  1235.     SCSI_CTRL *  pScsiCtrl;        /* ptr to controller info */
  1236.     SCSI_REQUEST request;      /* thread activation request msg */
  1237.     SCSI_REPLY   reply;       /* thread completion reply   msg */
  1238.     pScsiCtrl = pThread->pScsiCtrl;
  1239.     /*
  1240.      * Build thread activation request
  1241.      */
  1242.     request.type   = SCSI_REQUEST_ACTIVATE;
  1243.     request.thread = pThread;
  1244.     /*
  1245.      *  Execute thread activation request
  1246.      */
  1247.    if (scsiMgrRequestExecute (pScsiCtrl, &request, &reply) != OK)
  1248. {
  1249. SCSI_DEBUG_MSG ("scsiThreadExecute: error executing request.n",
  1250. 0, 0, 0, 0, 0, 0);
  1251. return (ERROR);
  1252. }
  1253.     /*
  1254.      *  Check reply type, set errno if necessary
  1255.      */
  1256.     switch (reply.type)
  1257. {
  1258. case SCSI_REPLY_COMPLETE:
  1259.     break;
  1260. default:
  1261.     logMsg ("scsiThreadExecute: invalid reply type (%d)n",
  1262.     reply.type, 0, 0, 0, 0, 0);
  1263.     return (ERROR);
  1264. }
  1265.     if (reply.status != OK)
  1266. errnoSet (reply.errNum);
  1267.     return (reply.status);
  1268.     }
  1269. /*******************************************************************************
  1270. *
  1271. * scsiCommand - execute a single SCSI command
  1272. *
  1273. * This routine executes a single SCSI command.  It retries while the device
  1274. * is unable to execute the command (busy or queue full status), and returns
  1275. * when the target has completed (or failed) the command, at which time the
  1276. * status byte is available in the transaction structure.
  1277. *
  1278. * RETURNS: OK, or ERROR if not successful for any reason.
  1279. */
  1280. LOCAL STATUS scsiCommand
  1281.     (
  1282.     SCSI_PHYS_DEV *    pScsiPhysDev, /* ptr to physical device info */
  1283.     SCSI_TRANSACTION * pScsiXaction /* ptr to transaction info */
  1284.     )
  1285.     {
  1286.     SCSI_THREAD * pThread;   
  1287.     SCSI_CTRL *   pScsiCtrl; /* ptr to SCSI controller info */
  1288.     STATUS        status; /* return status */
  1289.     BOOL          retry; /* TRUE if command must be retried */
  1290.     pScsiCtrl = pScsiPhysDev->pScsiCtrl;
  1291.     /*
  1292.      * Validate target device's bus ID
  1293.      */
  1294.     if (pScsiPhysDev->pScsiTarget->scsiDevBusId == pScsiCtrl->scsiCtrlBusId)
  1295.      {
  1296. errnoSet (S_scsiLib_ILLEGAL_BUS_ID);
  1297.         return (ERROR);
  1298. }
  1299.     if ((pThread = scsiThreadCreate (pScsiPhysDev, pScsiXaction)) == 0)
  1300. {
  1301. SCSI_DEBUG_MSG ("scsiCommand: can't create thread.n",
  1302. 0, 0, 0, 0, 0, 0);
  1303. return (ERROR);
  1304. }
  1305.     do
  1306.         {
  1307. retry = FALSE;
  1308. if ((status = scsiThreadExecute (pThread)) != OK)
  1309.     {
  1310.     SCSI_DEBUG_MSG ("scsiCommand: thread execution failedn",
  1311.     0, 0, 0, 0, 0, 0);
  1312.     }
  1313. else
  1314.     {
  1315.     switch (pScsiXaction->statusByte)
  1316.      {
  1317.      case SCSI_STATUS_BUSY:
  1318.          SCSI_DEBUG_MSG ("scsiCommand: device busy - retryingn",
  1319.      0, 0, 0, 0, 0, 0);
  1320.     retry = TRUE;
  1321.     break;
  1322.      case SCSI_STATUS_QUEUE_FULL:
  1323.          SCSI_DEBUG_MSG ("scsiCommand: queue full - retryingn",
  1324.          0, 0, 0, 0, 0, 0);
  1325.     retry = TRUE;
  1326.     break;
  1327.      default:
  1328.     break;
  1329. }
  1330.     }
  1331.         }
  1332.     while (retry);
  1333.     (void) scsiThreadDelete (pThread);
  1334.     return (status);
  1335.     }
  1336. /*******************************************************************************
  1337. *
  1338. * scsi2Transact - execute a SCSI transaction
  1339. *
  1340. * This routine calls scsiCommand() to execute the command specified.
  1341. * If there are physical path management errors, then this routine returns
  1342. * ERROR.  If not, then the status returned from the command is checked.  If
  1343. * it is "Check Condition", then a "Request Sense" CCS command is executed
  1344. * and the sense key is examined.  An indication of the success of the
  1345. * command is returned (OK or ERROR).
  1346. *
  1347. * RETURNS: OK, or ERROR if a path management error occurs
  1348. * or the status or sense information indicates an error.
  1349. */
  1350. LOCAL STATUS scsi2Transact
  1351.     (
  1352.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to the target device    */
  1353.     SCSI_TRANSACTION *pScsiXaction      /* ptr to the transaction info */
  1354.     )
  1355.     {
  1356.     STATUS status;     /* routine return status                */
  1357.     int senseKey;     /* extended sense key from target       */
  1358.     int addSenseCode;     /* additional sense code from target    */
  1359.     int addSenseCodeQual;           /* additional sense code qualifier      */
  1360.     SCSI_DEBUG_MSG ("scsi2Transact:n",0, 0, 0, 0, 0, 0);
  1361.     if ((status = scsiCommand (pScsiPhysDev, pScsiXaction)) == ERROR)
  1362. {
  1363. SCSI_DEBUG_MSG ("scsiTransact: scsiCommand ERROR.n",
  1364. 0, 0, 0, 0, 0, 0);
  1365. goto cleanExit;
  1366. }
  1367.     /* check device status and take appropriate action */
  1368.     switch (pScsiXaction->statusByte & SCSI_STATUS_MASK)
  1369. {
  1370. case SCSI_STATUS_GOOD:
  1371.     status = OK;
  1372.     pScsiPhysDev->lastSenseKey = SCSI_SENSE_KEY_NO_SENSE;
  1373.     pScsiPhysDev->lastAddSenseCode = (UINT8) 0;
  1374.     goto cleanExit;
  1375. case SCSI_STATUS_CHECK_CONDITION:
  1376.     {
  1377.     SCSI_COMMAND reqSenseCmd; /* REQUEST SENSE command */
  1378.     SCSI_TRANSACTION reqSenseXaction; /* REQUEST SENSE xaction */
  1379. /* REQUEST SENSE buffer  */
  1380.             UINT8 reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE + 1];
  1381.     /* build a REQUEST SENSE command and transact it */
  1382.     (void) scsiCmdBuild (reqSenseCmd, &reqSenseXaction.cmdLength,
  1383.     SCSI_OPCODE_REQUEST_SENSE,
  1384.  pScsiPhysDev->scsiDevLUN, FALSE, 0,
  1385.  pScsiPhysDev->reqSenseDataLength, (UINT8) 0);
  1386.     reqSenseXaction.cmdAddress = (UINT8 *) reqSenseCmd;
  1387.     /* if there is no user request sense buffer, supply it */
  1388.     if ( pScsiPhysDev->pReqSenseData == (UINT8 *)NULL )
  1389. {
  1390.                 reqSenseXaction.dataAddress = reqSenseData;
  1391. if (!pScsiPhysDev->extendedSense)
  1392.     reqSenseXaction.dataLength = NON_EXT_SENSE_DATA_LENGTH;
  1393.                 else
  1394.     reqSenseXaction.dataLength = REQ_SENSE_ADD_LENGTH_BYTE + 1;
  1395.                 } 
  1396.             else
  1397. {
  1398.         reqSenseXaction.dataAddress = pScsiPhysDev->pReqSenseData;
  1399.         reqSenseXaction.dataLength  = 
  1400.                            pScsiPhysDev->reqSenseDataLength;
  1401.                 }
  1402.     reqSenseXaction.dataDirection = O_RDONLY;
  1403.     reqSenseXaction.addLengthByte = REQ_SENSE_ADD_LENGTH_BYTE;
  1404.     reqSenseXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1405.     reqSenseXaction.tagType       = SCSI_TAG_SENSE_RECOVERY;
  1406.          reqSenseXaction.priority      = SCSI_THREAD_MAX_PRIORITY;
  1407.     SCSI_DEBUG_MSG ("scsiTransact: issuing a REQUEST SENSE command.n",
  1408.     0, 0, 0, 0, 0, 0);
  1409.     if ((status = scsiCommand (pScsiPhysDev, &reqSenseXaction))
  1410. == ERROR)
  1411. {
  1412. SCSI_DEBUG_MSG ("scsiTransact: scsiCommand ERROR.n",
  1413. 0, 0, 0, 0, 0, 0);
  1414. goto cleanExit;
  1415. }
  1416.     /* REQUEST SENSE command status != GOOD indicates fatal error */
  1417.     if (reqSenseXaction.statusByte != SCSI_STATUS_GOOD)
  1418. {
  1419. SCSI_DEBUG_MSG ("scsiTransact: non-zero REQ SENSE status.n",
  1420. 0, 0, 0, 0, 0, 0);
  1421. errnoSet (S_scsiLib_REQ_SENSE_ERROR);
  1422. status = ERROR;
  1423. goto cleanExit;
  1424. }
  1425.     /* if device uses Nonextended Sense Data Format, return now */
  1426.     if (!pScsiPhysDev->extendedSense)
  1427. {
  1428. status = ERROR;
  1429. goto cleanExit;
  1430. }
  1431.     /* check sense key and take appropriate action */
  1432.     pScsiPhysDev->lastSenseKey =
  1433. (pScsiPhysDev->pReqSenseData)[2] & SCSI_SENSE_KEY_MASK;
  1434.     pScsiPhysDev->lastAddSenseCode = (pScsiPhysDev->pReqSenseData)[12];
  1435.     addSenseCode = (int) pScsiPhysDev->lastAddSenseCode;
  1436.             /* store additional sense code qualifier */
  1437.     addSenseCodeQual = (pScsiPhysDev->pReqSenseData)[13];
  1438.     switch (senseKey = (int) pScsiPhysDev->lastSenseKey)
  1439.         {
  1440.         case SCSI_SENSE_KEY_NO_SENSE:
  1441.             {
  1442.             SCSI_DEBUG_MSG ("scsiTransact: No Sensen",
  1443.     0, 0, 0, 0, 0, 0);
  1444.             status = OK;
  1445.             goto cleanExit;
  1446.             }
  1447.         case SCSI_SENSE_KEY_RECOVERED_ERROR:
  1448.             {
  1449.     SCSI_DEBUG_MSG ("scsiTransact: Recovered Error Sense,",
  1450.     0, 0, 0, 0, 0, 0);
  1451.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1452.     addSenseCode, 0, 0, 0, 0, 0);
  1453.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1454.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1455.             status = OK;
  1456.             goto cleanExit;
  1457.             }
  1458.         case SCSI_SENSE_KEY_NOT_READY:
  1459.             {
  1460.     SCSI_DEBUG_MSG ("scsiTransact: Not Ready Sense,",
  1461.     0, 0, 0, 0, 0, 0);
  1462.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1463.     addSenseCode, 0, 0, 0, 0, 0);
  1464.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1465.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1466.             errnoSet (S_scsiLib_DEV_NOT_READY);
  1467.             status = ERROR;
  1468.             goto cleanExit;
  1469.             }
  1470.                 case SCSI_SENSE_KEY_MEDIUM_ERROR:
  1471.                     {
  1472.                     SCSI_DEBUG_MSG ("scsiTransact: Not Ready Sense,",
  1473.                                     0, 0, 0, 0, 0, 0);
  1474.                     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1475.                                     addSenseCode, 0, 0, 0, 0, 0);
  1476.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1477.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1478.                     errnoSet (S_scsiLib_MEDIUM_ERROR);
  1479.                     status = ERROR;
  1480.                     goto cleanExit;
  1481.                     }
  1482.                 case SCSI_SENSE_KEY_HARDWARE_ERROR:
  1483.                     {
  1484.                     SCSI_DEBUG_MSG ("scsiTransact: Hardware Error Sense,",
  1485.                                     0, 0, 0, 0, 0, 0);
  1486.                     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1487.                                     addSenseCode, 0, 0, 0, 0, 0);
  1488.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1489.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1490.                     errnoSet (S_scsiLib_HARDWARE_ERROR);
  1491.                     status = ERROR;
  1492.                     goto cleanExit;
  1493.                     }
  1494.                 case SCSI_SENSE_KEY_ILLEGAL_REQUEST:
  1495.                     {
  1496.                     SCSI_DEBUG_MSG ("scsiTransact: Illegal Request Sense,",
  1497.                                     0, 0, 0, 0, 0, 0);
  1498.                     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1499.                                     addSenseCode, 0, 0, 0, 0, 0);
  1500.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1501.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1502.                     errnoSet (S_scsiLib_ILLEGAL_REQUEST);
  1503.                     status = ERROR;
  1504.                     goto cleanExit;
  1505.                     }
  1506.                 /* 
  1507.  * A UNIT ATTENTION occurs because of the following main
  1508.  * conditions:
  1509.  * 1. Device reset (SCSI command or hard reset)
  1510.  * 2. Removable medium has been changed
  1511.  * 3. Another initiator changed mode params or cleared
  1512.  *         tagged commnads
  1513.  * 4. Others
  1514.  * A medium change has to be reported the BLK_DEV or SEQ_DEV
  1515.  * structure.
  1516.  */
  1517.         case SCSI_SENSE_KEY_UNIT_ATTENTION:
  1518.             {
  1519.     SCSI_DEBUG_MSG ("scsiTransact: Unit Attention Sense,",
  1520.     0, 0, 0, 0, 0, 0);
  1521.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1522.     addSenseCode, 0, 0, 0, 0, 0);
  1523.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1524.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1525.                     /* check for medium change and WP bit */
  1526.                     chkMedChangeAndWP (addSenseCode, pScsiPhysDev);
  1527.     errnoSet (S_scsiLib_UNIT_ATTENTION);
  1528.             status = ERROR;
  1529.                    /* retry the command sequence */
  1530.                    
  1531.                    if (addSenseCode == SCSI_ADD_SENSE_DEVICE_RESET)
  1532.                      status = scsiCommand (pScsiPhysDev, pScsiXaction);
  1533.  
  1534.             goto cleanExit;
  1535.                     }
  1536.                 /* 
  1537.  * Indicates that a command that reads or writes the medium
  1538.  * was attempted on a block that is protected from this 
  1539.  * operation. The read/write operation is not performed.
  1540.  * In simple terms, we get this sense for write protected 
  1541.  * media
  1542.  */
  1543.         case SCSI_SENSE_KEY_DATA_PROTECT:
  1544.             {
  1545.     SCSI_DEBUG_MSG ("scsiTransact: Data Protect Sense,",
  1546.     0, 0, 0, 0, 0, 0);
  1547.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1548.     addSenseCode, 0, 0, 0, 0, 0);
  1549.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1550.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1551.     if (addSenseCode == SCSI_ADD_SENSE_WRITE_PROTECTED)
  1552. errnoSet (S_scsiLib_WRITE_PROTECTED);
  1553.             status = ERROR;
  1554.             goto cleanExit;
  1555.             }
  1556.                 case SCSI_SENSE_KEY_BLANK_CHECK:
  1557.                     {
  1558.                     SCSI_DEBUG_MSG ("scsiTransact: Blank Check Sense,",
  1559.                                     0, 0, 0, 0, 0, 0);
  1560.                     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1561.                                     addSenseCode, 0, 0, 0, 0, 0);
  1562.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1563.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1564.                     errnoSet (S_scsiLib_BLANK_CHECK);
  1565.                     status = ERROR;
  1566.                     goto cleanExit;
  1567.                     }
  1568.                 case SCSI_SENSE_KEY_ABORTED_COMMAND:
  1569.                     {
  1570.                     SCSI_DEBUG_MSG ("scsiTransact:  Aborted Command Sense,",
  1571.                                     0, 0, 0, 0, 0, 0);
  1572.                     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1573.                                     addSenseCode, 0, 0, 0, 0, 0);
  1574.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1575.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1576.                     errnoSet (S_scsiLib_ABORTED_COMMAND);
  1577.                     status = ERROR;
  1578.                     goto cleanExit;
  1579.                     }
  1580.                 case SCSI_SENSE_KEY_VOLUME_OVERFLOW:
  1581.                     {
  1582.                     SCSI_DEBUG_MSG ("scsiTransact: Volume Overflow Sense,",
  1583.                                     0, 0, 0, 0, 0, 0);
  1584.                     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1585.                                     addSenseCode, 0, 0, 0, 0, 0);
  1586.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1587.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1588.                     errnoSet (S_scsiLib_VOLUME_OVERFLOW);
  1589.                     status = ERROR;
  1590.                     goto cleanExit;
  1591.                     }
  1592.         default:
  1593.     {
  1594.     SCSI_DEBUG_MSG ("scsiTransact: Sense = %x,",
  1595.     senseKey, 0, 0, 0, 0, 0);
  1596.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1597.     addSenseCode, 0, 0, 0, 0, 0);
  1598.     SCSI_DEBUG_MSG ("ASCQ = 0x%02xn",
  1599.     addSenseCodeQual, 0, 0, 0, 0, 0);
  1600.             status = ERROR;
  1601.     errnoSet (S_scsiLib_UNKNOWN_SENSE_DATA);
  1602.             goto cleanExit;
  1603.             }
  1604.         }
  1605.     }
  1606. case SCSI_STATUS_BUSY:
  1607. case SCSI_STATUS_QUEUE_FULL:
  1608.     /* NOTE: should never occur - see "scsiCommand()" */
  1609.     /* FALLTHROUGH */
  1610. default:
  1611.          SCSI_ERROR_MSG ("scsiTransact: unsupported status (0x%02x)n",
  1612.                    pScsiXaction->statusByte & SCSI_STATUS_MASK,
  1613.     0, 0, 0, 0, 0);
  1614.     status = ERROR;
  1615.     break;
  1616. }
  1617. cleanExit:
  1618.     return (status);
  1619.     }
  1620. /*******************************************************************************
  1621. *
  1622. * chkMedChangeAndWP - check if medium has changed and if it is write protected
  1623. *
  1624. * Look at the sense information from a request sense command and determine if 
  1625. * the medium has been changed. Issue a MODE SENSE command, in order to check
  1626. * if the medium is write protected. Set the appropriate values in either a
  1627. * BLK_DEV structure or a SEQ_DEV structure, depending upon the type of device.
  1628. *
  1629. * RETURN: N/A
  1630. */
  1631. LOCAL void chkMedChangeAndWP 
  1632.     (
  1633.     int             addSenseCode,  /* additional sense code */
  1634.     SCSI_PHYS_DEV * pScsiPhysDev /* ptr to a SCSI physcial device */
  1635.     )
  1636.     {
  1637.     SCSI_BLK_DEV_NODE *pBlkDevNode; /* ptr for looping through BLK_DEV list */
  1638.     SCSI_SEQ_DEV      *pScsiSeqDev; /* ptr to SCSI_SEQ_DEV                  */
  1639.     UINT8 modeSenseHeader [4];    /* mode sense data header */
  1640.     SCSI_COMMAND modeSenseCommand;/* SCSI command byte array */
  1641.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI xaction */
  1642.     int status = OK;
  1643.     /* Has there been a change in removable medium ? */
  1644.     if (addSenseCode == SCSI_ADD_SENSE_MEDIUM_CHANGED)
  1645. {
  1646.      semTake (pScsiPhysDev->mutexSem, WAIT_FOREVER);
  1647. if (pScsiPhysDev->scsiDevType == SCSI_DEV_SEQ_ACCESS)
  1648.     {
  1649.     pScsiSeqDev = pScsiPhysDev->pScsiSeqDev;
  1650.     pScsiSeqDev->seqDev.sd_readyChanged = TRUE;
  1651.     }
  1652.         else  /* it is a block device */
  1653.     {
  1654.          for (pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1655.                    lstFirst (&pScsiPhysDev->blkDevList);
  1656.                  pBlkDevNode != NULL;
  1657.                  pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1658.                  lstNext (&pBlkDevNode->blkDevNode))
  1659.         {
  1660. pBlkDevNode->scsiBlkDev.blkDev.bd_readyChanged = TRUE;
  1661.                 }
  1662.     }
  1663.      semGive (pScsiPhysDev->mutexSem);
  1664. }
  1665.     /* Was there some kind of a device reset ? */
  1666.     else if (addSenseCode == SCSI_ADD_SENSE_DEVICE_RESET) 
  1667. {
  1668. pScsiPhysDev->resetFlag = TRUE;
  1669. }
  1670.     /* issue a MODE SENSE command */
  1671.     /* The objective of issuing a MODE SENSE command is to
  1672.      * determine if the media was write protected. 
  1673.      *
  1674.      * XXX - This may not be the best way to tell if we have
  1675.      *       read-only or read-write media. Sense key 0x7 and
  1676.      *       additionaly sense key of 0x27 could do the job
  1677.      *       as well. This should be verified.
  1678.      */
  1679.     if (scsiCmdBuild (modeSenseCommand, &scsiXaction.cmdLength,
  1680.       SCSI_OPCODE_MODE_SENSE, pScsiPhysDev->scsiDevLUN, FALSE,
  1681.       0, sizeof (modeSenseHeader), (UINT8) 0)
  1682.         == ERROR)
  1683. return;
  1684.     scsiXaction.cmdAddress    = modeSenseCommand;
  1685.     scsiXaction.dataAddress   = modeSenseHeader;
  1686.     scsiXaction.dataDirection = O_RDONLY;
  1687.     scsiXaction.dataLength    = sizeof (modeSenseHeader);
  1688.     scsiXaction.addLengthByte = MODE_SENSE_ADD_LENGTH_BYTE;
  1689.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1690.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  1691.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  1692.     SCSI_DEBUG_MSG ("scsiTransact: issuing a MODE SENSE cmd.n",
  1693.                              0, 0, 0, 0, 0, 0);
  1694.     if ((status = scsiCommand (pScsiPhysDev, &scsiXaction)) == ERROR)
  1695. {
  1696. SCSI_DEBUG_MSG ("scsiCommand returned ERRORn", 0, 0, 0, 0, 0, 0);
  1697. return;
  1698. }
  1699.     /* MODE SENSE command status != GOOD indicates
  1700.      * fatal error
  1701.      */
  1702.     if (scsiXaction.statusByte != SCSI_STATUS_GOOD)
  1703. {
  1704. SCSI_DEBUG_MSG ("scsiTransact: bad MODE SELECT stat.n",
  1705.         0, 0, 0, 0, 0, 0);
  1706. return;
  1707. }
  1708.     else  /* MODE SENSE returned successfully */
  1709. {
  1710.      semTake (pScsiPhysDev->mutexSem, WAIT_FOREVER);
  1711. /*
  1712.          * if the WP bit of the device specific parameter
  1713.  * of the Mode parameter header is set then the
  1714.  * medium is write protected 
  1715.  */
  1716.         if (pScsiPhysDev->scsiDevType == SCSI_DEV_SEQ_ACCESS)
  1717.             {
  1718.             pScsiSeqDev = pScsiPhysDev->pScsiSeqDev;
  1719.     pScsiSeqDev->seqDev.sd_mode = 
  1720.                 ( modeSenseHeader [SCSI_MODE_DEV_SPECIFIC_PARAM] & 
  1721.           (UINT8) SCSI_DEV_SPECIFIC_WP_MASK
  1722.                 ) ? O_RDONLY : O_RDWR;
  1723.             }
  1724.             else    /* it is a block device */
  1725.             {
  1726.          for (pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1727.                    lstFirst (&pScsiPhysDev->blkDevList);
  1728.                  pBlkDevNode != NULL;
  1729.            pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1730.             lstNext (&pBlkDevNode->blkDevNode))
  1731. {
  1732. pBlkDevNode->scsiBlkDev.blkDev.bd_mode =
  1733.     ( modeSenseHeader [SCSI_MODE_DEV_SPECIFIC_PARAM] & 
  1734.                       (UINT8) SCSI_DEV_SPECIFIC_WP_MASK
  1735.                     ) ? O_RDONLY : O_RDWR;
  1736.                 }
  1737.             }
  1738.      semGive (pScsiPhysDev->mutexSem);
  1739. SCSI_DEBUG_MSG ("Write-protect bit = %x.n",
  1740.            ( modeSenseHeader [SCSI_MODE_DEV_SPECIFIC_PARAM] & 
  1741.                              (UINT8) SCSI_DEV_SPECIFIC_WP_MASK
  1742.                            ), 0, 0, 0, 0, 0);
  1743. }
  1744.     }
  1745. /*******************************************************************************
  1746. *
  1747. * scsi2Ioctl - perform a device-specific control function
  1748. *
  1749. * This routine performs a specified function using a specified SCSI physical
  1750. * device.
  1751. *
  1752. * RETURNS: The status of the request, or ERROR if the request is unsupported.
  1753. */
  1754. LOCAL STATUS scsi2Ioctl
  1755.     (
  1756.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device info */
  1757.     int function,               /* function code */
  1758.     int arg                     /* argument to pass called function */
  1759.     )
  1760.     {
  1761.     switch (function)
  1762.         {
  1763.         case FIOSCSICOMMAND:
  1764.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1765.     (pScsiPhysDev, (SCSI_TRANSACTION *) arg));
  1766.         case FIODISKFORMAT:
  1767.     /* issue a FORMAT UNIT command with default parameters */
  1768.     return (scsiFormatUnit (pScsiPhysDev, 0, 0, 0, 0,
  1769.     (char *) NULL, 0));
  1770.         case FIOERASE:
  1771.     /* issue a tape erase command */
  1772.     return (scsiErase (pScsiPhysDev, arg));
  1773.         case FIODENSITYSET:
  1774.         case FIODENSITYGET:
  1775.         case FIOBLKSIZESET:
  1776.         case FIOBLKSIZEGET:
  1777.      {
  1778.      int tmp;
  1779.              tmp = (scsiSeqIoctl ((SCSI_SEQ_DEV *)pScsiPhysDev, function, arg));   
  1780.      logMsg ("scsiIoctl: blkSize: %dn", tmp,0,0,0,0,0);
  1781.      return tmp;
  1782.      }
  1783.         default:
  1784.     errnoSet (S_ioLib_UNKNOWN_REQUEST);
  1785.     return (ERROR);
  1786.         }
  1787.     }
  1788. /*******************************************************************************
  1789. *
  1790. * scsiCacheSnoopEnable - inform SCSI that hardware snooping of caches is enabled
  1791. *
  1792. * This routine informs the SCSI library that hardware snooping is enabled
  1793. * and that scsi2Lib need not execute any cache coherency code.
  1794. * In order to make scsi2Lib aware that hardware
  1795. * snooping is enabled, this routine should be called after all SCSI-2
  1796. * initializations, especially after scsi2CtrlInit().
  1797. * RETURNS: N/A
  1798. */
  1799. void scsiCacheSnoopEnable 
  1800.     (
  1801.     SCSI_CTRL * pScsiCtrl  /* pointer to a SCSI_CTRL structure */
  1802.     )
  1803.     {
  1804.     pScsiCtrl->cacheSnooping = TRUE;
  1805.     }
  1806. /*******************************************************************************
  1807. *
  1808. * scsiCacheSnoopDisable - inform SCSI that hardware snooping of caches is disabled
  1809. *
  1810. * This routine informs the SCSI library that hardware snooping is disabled
  1811. * and that scsi2Lib should execute any neccessary cache coherency code.
  1812. * In order to make scsi2Lib aware that hardware
  1813. * snooping is disabled, this routine should be called after all SCSI-2
  1814. * initializations, especially after scsi2CtrlInit().
  1815. * RETURNS: N/A
  1816. */
  1817. void scsiCacheSnoopDisable 
  1818.     (
  1819.     SCSI_CTRL * pScsiCtrl  /* pointer to a SCSI_CTRL structure */
  1820.     )
  1821.     {
  1822.     pScsiCtrl->cacheSnooping = FALSE;
  1823.     }