home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / DASD / OS2ASPI / ASPISRB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-14  |  72.7 KB  |  1,685 lines

  1. /*DDK*************************************************************************/
  2. /*                                                                           */
  3. /* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
  4. /*                                                                           */
  5. /*    The following IBM OS/2 WARP source code is provided to you solely for  */
  6. /*    the purpose of assisting you in your development of OS/2 WARP device   */
  7. /*    drivers. You may use this code in accordance with the IBM License      */
  8. /*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
  9. /*    Copyright statement may not be removed.                                */
  10. /*                                                                           */
  11. /*****************************************************************************/
  12. /*static char *SCCSID = "src/dev/dasd/os2aspi/aspisrb.c, aspi, r206 93/03/20";*/
  13. /**************************************************************************
  14.  *
  15.  * SOURCE FILE NAME = ASPISRB.C
  16.  *
  17.  * DESCRIPTIVE NAME = OS2ASPI.DMD - OS/2 ASPI Device Manager
  18.  *                    ASPI SRB Processor
  19.  *
  20.  *
  21.  * VERSION = V2.0
  22.  *
  23.  * DATE
  24.  *
  25.  * DESCRIPTION  Converts ASPI SRBs to corresponding IORB(s).
  26.  *
  27.  *
  28.  *
  29. */
  30.  
  31. #define INCL_NOBASEAPI
  32. #define INCL_NOPMAPI
  33. #include <os2.h>
  34. #include <strat2.h>
  35.  
  36. #include <devcmd.h>
  37. #include <devclass.h>
  38.  
  39. #include <reqpkt.h>
  40. #include <iorb.h>
  41. #include <dhcalls.h>
  42. #include <dskinit.h>
  43. #include <scsi.h>
  44.  
  45. #include <aspi.h>
  46. #include <aspicons.h>
  47. #include <aspitype.h>
  48. #include <aspipro.h>
  49. #include <aspiextn.h>
  50.  
  51. extern      PVOID                pDataSeg;
  52. extern      ULONG                ppDataSeg;
  53. extern      USHORT               IORBWaitSem;
  54. extern      UCHAR                numberOfASPIAdapters;
  55. extern      CHAR                 OS2ASPI_Text[];
  56. extern      NPACB                npACBAnchor;
  57. extern      NPATE                npFirstATE;
  58. extern      NPSRB_LINK           npSRBLinkFreeList;
  59. extern      NPIORB_UNIT_CONTROL  npIORBUnitControl;
  60. extern      USHORT               allocationOverride;
  61. extern      USHORT               shareTargets;
  62.  
  63. /*********************************************************
  64. *                                                        *
  65. *   Procedure Name : ASPISRBEntr                         *
  66. *                                                        *
  67. *   Description : This procedure routes all ASPI         *
  68. *   requests to the appropriate function.                *
  69. *                                                        *
  70. *   Input :                                              *
  71. *         pSRBH - A pointer to SRB header                *
  72. *         virtualASPI - Flags indicating the status of   *
  73. *           the VDM that MAY be associated with the SRB. *
  74. *                                                        *
  75. *   Output :                                             *
  76. *                                                        *
  77. *********************************************************/
  78. VOID NEAR _loadds ASPISRBEntr(PASPI_SRB_HEADER pSRBH,USHORT virtualASPI)
  79.  
  80.    {
  81.    switch (pSRBH->CommandCode)
  82.       {
  83.       case ASPI_CMD_ADAPTER_INQUIRY:
  84.          DoASPIInquiry((PASPI_SRB_INQUIRY) pSRBH,virtualASPI);
  85.          break;
  86.  
  87.       case ASPI_CMD_GET_DEVICE_TYPE:
  88.          DoASPIDeviceType((PASPI_SRB_DEVICE_TYPE) pSRBH, virtualASPI);
  89.          break;
  90.  
  91.       case ASPI_CMD_EXECUTE_IO:
  92.          DoASPIExecuteIO((PASPI_SRB_EXECUTE_IO) pSRBH,virtualASPI);
  93.          break;
  94.  
  95.       case ASPI_CMD_ABORT_IO:
  96.          DoASPIAbortIO((PASPI_SRB_ABORT_IO) pSRBH,virtualASPI);
  97.          break;
  98.  
  99.       case ASPI_CMD_RESET_DEVICE:
  100.          DoASPIExecuteIO((PASPI_SRB_EXECUTE_IO) pSRBH,virtualASPI);
  101.          break;
  102.  
  103.       case ASPI_CMD_SET_ADAPTER_PARMS:
  104.          DoASPISetAdapterParms((PASPI_SRB_ADAPTER_PARMS) pSRBH,virtualASPI);
  105.          break;
  106.  
  107.       default:
  108.          pSRBH->ASPIStatus = ASPI_STATUS_INVALID_COMMAND;
  109.        }
  110.    }
  111.  
  112.  
  113. /*********************************************************
  114. *                                                        *
  115. *   Procedure Name : DoASPIInquiry                       *
  116. *                                                        *
  117. *   Description : This procedure handles host adapter    *
  118. *   inquires.                                            *
  119. *                                                        *
  120. *   Input :                                              *
  121. *         pSRBI - A pointer to the SRB for host adapter  *
  122. *            inquiries                                   *
  123. *         virtualASPI - Flags indicating the status of   *
  124. *           the VDM that MAY be associated with the SRB. *
  125. *                                                        *
  126. *   Output :  This function returns the status for the   *
  127. *   request packet that was just handled by it.          *
  128. *                                                        *
  129. *********************************************************/
  130. USHORT NEAR DoASPIInquiry(PASPI_SRB_INQUIRY pSRBI, USHORT virtualASPI)
  131.  
  132.    {
  133.    UCHAR    adapterIndex;
  134.    NPACB    pACB;
  135.    UCHAR    ASPIStatus;
  136.    USHORT   extendedByteCount;                                       /*@V53040*/
  137.    USHORT   requestPacketStatus = STDON;
  138.  
  139.    /* Verify that host adapter is valid */
  140.    adapterIndex = pSRBI->SRBHdr.AdapterIndex;
  141.  
  142.    if (adapterIndex >= numberOfASPIAdapters)
  143.       {
  144.       ASPIStatus = ASPI_STATUS_INVALID_ADAPTER;
  145.       requestPacketStatus |= STERR;
  146.       }
  147.    else
  148.       {
  149.       pACB = FindAdapter(adapterIndex);
  150.  
  151.       /* Copy all of the information of the current host adapter */
  152.       /* into the SRB                                            */
  153.       memcpy(pSRBI->ManagerName,
  154.              OS2ASPI_Text,
  155.              sizeof(pSRBI->ManagerName));
  156.       memset(pSRBI->AdapterParms,
  157.              0,
  158.              sizeof(pSRBI->AdapterParms));
  159.  
  160.       pSRBI->AdapterCount = numberOfASPIAdapters;
  161.       pSRBI->AdapterTargetID = pACB->AdapterTargetID;
  162.       memcpy(pSRBI->AdapterName,
  163.              pACB->AdapterName,
  164.              sizeof(pSRBI->ManagerName));
  165.  
  166.       /* Determine if we should return EXTENDED adapter information */
  167.       if (*((PUSHORT) &pSRBI->Reserved_1) == 0xAA55)
  168.          {                                                           /*@V53040*/
  169.          /* Determine how many extended bytes should be returned */  /*@V53040*/
  170.          extendedByteCount = *(((PUSHORT) &(pSRBI->Reserved_1)) + 1);/*@V53040*/
  171.          if (extendedByteCount > MAX_EXTENDED_ADAPTER_COUNT)
  172.             extendedByteCount = MAX_EXTENDED_ADAPTER_COUNT;
  173.                                                                      /*@V53040*/
  174.          memcpy((PBYTE) &(pSRBI->AdapterFeatures),
  175.                 (PBYTE) &(pACB->AdapterFeatures),
  176.                 extendedByteCount);
  177.                                                                      /*@V53040*/
  178.          /* Update number of bytes transferred and signature */
  179.          *(((PUSHORT) &(pSRBI->Reserved_1)) + 1) = extendedByteCount;/*@V53040*/
  180.          *((PUSHORT) &pSRBI->Reserved_1) == 0x55AA;
  181.          }                                                           /*@V53040*/
  182.  
  183.       ASPIStatus = ASPI_STATUS_NO_ERROR;
  184.       }
  185.  
  186.    pSRBI->SRBHdr.ASPIStatus = ASPIStatus;
  187.  
  188.    if ((virtualASPI & VDM_REQUEST) != 0)
  189.       CallVirtPostRoutine((PVOID) pSRBI);
  190.  
  191.    return(requestPacketStatus);
  192.    }
  193.  
  194. /*********************************************************
  195. *                                                        *
  196. *   Procedure Name : DoASPIDeviceType                    *
  197. *                                                        *
  198. *   Description : This procedure handles ASPI inquiries  *
  199. *   about a device.                                      *
  200. *                                                        *
  201. *   Input :                                              *
  202. *         pSRBDT - A pointer to the SRB for device       *
  203. *            inquiries                                   *
  204. *         virtualASPI - Flags indicating the status of   *
  205. *           the VDM that MAY be associated with the SRB. *
  206. *                                                        *
  207. *   Output :   This function returns the status for the  *
  208. *   request packet that was just handled by it.          *
  209. *                                                        *
  210. *********************************************************/
  211. USHORT NEAR DoASPIDeviceType(PASPI_SRB_DEVICE_TYPE pSRBDT, USHORT virtualASPI)
  212.  
  213.    {
  214.    UCHAR    adapterIndex;
  215.    UCHAR    ASPIStatus;
  216.    NPATE    npATE;
  217.    USHORT   requestPacketStatus = STDON;
  218.    USHORT   allocationResult;                                        /*@V64399*/
  219.    USHORT   allocationStatus;                                        /*@V64399*/
  220.    USHORT   extendedByteCount;
  221.                                                                      /*@V64399*/
  222.    /* Assume the target is accessible */                             /*@V64399*/
  223.    allocationResult = 0;                                             /*@V64399*/
  224.  
  225.    /* Verify that the host adapter is valid */
  226.    adapterIndex = pSRBDT->SRBHdr.AdapterIndex;
  227.  
  228.    if (adapterIndex >= numberOfASPIAdapters)
  229.       {
  230.       ASPIStatus = ASPI_STATUS_INVALID_ADAPTER;
  231.       requestPacketStatus |= STERR;
  232.       }
  233.    else
  234.       {
  235.       /* Verify that the target device is attached to the host adapter */
  236.       npATE = FindTarget(adapterIndex,
  237.                          pSRBDT->DeviceTargetID,
  238.                          pSRBDT->DeviceTargetLUN);
  239.  
  240.       if (npATE)
  241.          {
  242.          /* Remember if the target is ALREADY allocated */
  243.          allocationStatus = npATE->Flags & (ATEF_ASPI_ALLOCATED |
  244.                                             ATEF_IGNORE_ALLOCATION);
  245.  
  246.          /* If the target is not already allocated, allocate it */   /*@V64399*/
  247.          if (!allocationStatus)
  248.             allocationResult = SendUnitControlCommand(npATE,         /*@V64399*/
  249.                                               IOCM_ALLOCATE_UNIT);   /*@V64399*/
  250.                                                                      /*@V64399*/
  251.          /* If allocation failed, it was most like allocated AFTER */
  252.          /* the ASPI manager was initialized. If allocation checking */
  253.          /* is being ignored, update the allocation status and continue */
  254.          if ((allocationOverride) &&
  255.              (allocationResult))
  256.             {
  257.             npATE->Flags |= ATEF_IGNORE_ALLOCATION;
  258.             npATE->TargetFeatures |= ASPI_DEVICE_ALLOCATION_SHARED;
  259.             allocationResult = 0;
  260.             }
  261.  
  262.          /* If target has been allocated to us, return device type *//*@V64399*/
  263.          if (!allocationResult)                                      /*@V64399*/
  264.             {                                                        /*@V64399*/
  265.             /* The device is available, so return the type reported */
  266.             pSRBDT->DeviceType = npATE->DeviceType;
  267.  
  268.             /* If the device was not already allocated to us,     */ /*@V64399*/
  269.             /* release it so that we can return information about */ /*@V64399*/
  270.             /* all available targets. The target will be          */ /*@V64399*/
  271.             /* permanently allocated when the first command is    */ /*@V64399*/
  272.             /* passed down to it.                                 */ /*@V64399*/
  273.  
  274.             /* If allocation failed earlier and we are now sharing it */
  275.             /* with another manager there is no deallocation needed. */
  276.             if ((!allocationStatus) &&
  277.                 (!(npATE->Flags & ATEF_IGNORE_ALLOCATION)))
  278.                SendUnitControlCommand(npATE,IOCM_DEALLOCATE_UNIT);
  279.  
  280.             /* Determine if we should return EXTENDED target information */
  281.             if (*((PUSHORT) &pSRBDT->Reserved_1) == 0xAA55)
  282.                {
  283.                /* Determine how many extended bytes should be returned */
  284.                extendedByteCount = *(((PUSHORT) &(pSRBDT->Reserved_1)) + 1);
  285.                if (extendedByteCount > MAX_EXTENDED_TARGET_COUNT)
  286.                   extendedByteCount = MAX_EXTENDED_TARGET_COUNT;
  287.  
  288.                memcpy((PBYTE) &(pSRBDT->TargetFeatures),
  289.                       (PBYTE) &(npATE->TargetFeatures),
  290.                       extendedByteCount);
  291.  
  292.                /* Update number of bytes transferred and signature */
  293.                *(((PUSHORT) &(pSRBDT->Reserved_1)) + 1) = extendedByteCount;
  294.                *((PUSHORT) &pSRBDT->Reserved_1) == 0x55AA;
  295.                }
  296.  
  297.             ASPIStatus = ASPI_STATUS_NO_ERROR;
  298.             }
  299.          else
  300.             {
  301.             ASPIStatus = ASPI_STATUS_INVALID_TARGET;
  302.             requestPacketStatus |= STERR;
  303.             }
  304.          }                                                           /*@V64399*/
  305.       else
  306.          {
  307.          ASPIStatus = ASPI_STATUS_INVALID_TARGET;
  308.          requestPacketStatus |= STERR;
  309.          }
  310.       }
  311.  
  312.    pSRBDT->SRBHdr.ASPIStatus = ASPIStatus;
  313.  
  314.    if ((virtualASPI & VDM_REQUEST) != 0)
  315.       CallVirtPostRoutine((PVOID) pSRBDT);
  316.  
  317.    return(requestPacketStatus);
  318.    }
  319.  
  320.  
  321. /*********************************************************
  322. *                                                        *
  323. *   Procedure Name : DoASPIExecuteIO                     *
  324. *                                                        *
  325. *   Description : This procedure handles requests to     *
  326. *   send commands directly to a device.                  *
  327. *                                                        *
  328. *   Input :                                              *
  329. *         pSRBIO - A pointer to the SRB for I/O          *
  330. *         virtualASPI - Flags indicating the status of   *
  331. *           the VDM that MAY be associated with the SRB. *
  332. *                                                        *
  333. *   Output :                                             *
  334. *                                                        *
  335. *********************************************************/
  336. VOID NEAR DoASPIExecuteIO(PASPI_SRB_EXECUTE_IO pSRBIO, USHORT virtualASPI)
  337.  
  338.    {
  339.    UCHAR   adapterIndex;
  340.    UCHAR   ASPIStatus;
  341.    UCHAR   ASPICmd;
  342.    NPATE   npATE;
  343.    USHORT  allocationResult = 0;
  344.  
  345.    adapterIndex = pSRBIO->SRBHdr.AdapterIndex;
  346.    ASPICmd      = pSRBIO->SRBHdr.CommandCode;
  347.  
  348.    /* Verify that the host adapter is valid */
  349.    if (adapterIndex >= numberOfASPIAdapters)
  350.       ASPIStatus = ASPI_STATUS_INVALID_ADAPTER;
  351.    else
  352.       {
  353.       /* Verify that the target device is attached to the host adapter */
  354.       npATE = FindTarget(adapterIndex,
  355.                          pSRBIO->DeviceTargetID,
  356.                          pSRBIO->DeviceTargetLUN);
  357.  
  358.       if (npATE)
  359.          {
  360.          /* If the device was allocated by OS2ASPI or if access is being */
  361.          /* shared with another manager WITHOUT deallocation, send the SRB. */
  362.          /* Otherwise, allocate the target and then send the SRB */
  363.          if (!((npATE->Flags & ATEF_ASPI_ALLOCATED) ||
  364.                (npATE->Flags & ATEF_IGNORE_ALLOCATION)))
  365.              allocationResult = SendUnitControlCommand(npATE,
  366.                                                        IOCM_ALLOCATE_UNIT);
  367.  
  368.          /* If allocation failed, it was most like allocated AFTER */
  369.          /* the ASPI manager was initialized. If allocation checking */
  370.          /* is being ignored, update the allocation status and continue */
  371.          if ((allocationOverride) &&
  372.              (allocationResult))
  373.             {
  374.             npATE->Flags |= ATEF_IGNORE_ALLOCATION;
  375.             npATE->TargetFeatures |= ASPI_DEVICE_ALLOCATION_SHARED;
  376.             allocationResult = 0;
  377.             }
  378.  
  379.          if (!allocationResult)
  380.             {
  381.             /* The unit is available, so mark the SRB in progress */
  382.             /* and issue the command to the target                */
  383.             ASPIStatus = ASPI_STATUS_IN_PROGRESS;
  384.             pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_IN_PROGRESS;
  385.  
  386.             switch (ASPICmd)
  387.                {
  388.                case ASPI_CMD_EXECUTE_IO:
  389.                   SRBToIORBPassThru(npATE,                           /*@V61092*/
  390.                                     pSRBIO,
  391.                                     0,
  392.                                     virtualASPI);
  393.                   break;
  394.                case ASPI_CMD_RESET_DEVICE :
  395.                   SRBToIORBReset(npATE,                              /*@V61092*/
  396.                                  (PASPI_SRB_RESET_DEVICE) pSRBIO,
  397.                                  0,
  398.                                  virtualASPI);
  399.                   break;
  400.                default :
  401.                   ASPIStatus = ASPI_STATUS_INVALID_COMMAND;
  402.                }
  403.             }
  404.          else
  405.             {
  406.             /* The selected target is already in use */
  407.             ASPIStatus = ASPI_STATUS_ERROR;
  408.             pSRBIO->HostStatus = ASPI_HSTATUS_SELECTION_TIMEOUT;
  409.             }
  410.          }
  411.       else
  412.          ASPIStatus = ASPI_STATUS_INVALID_TARGET;
  413.       }
  414.  
  415.    /* If the request is not pending, report the error.          */
  416.    /* All successful completions are reported in NotifyIORBDone */
  417.    if (ASPIStatus != ASPI_STATUS_IN_PROGRESS)
  418.       {
  419.       pSRBIO->SRBHdr.ASPIStatus = ASPIStatus;
  420.  
  421.       /* Call the ASPI posting routine (if necessary) */
  422.       if ((virtualASPI & VDM_REQUEST) != 0)
  423.           CallVirtPostRoutine((PVOID)pSRBIO);
  424.       else
  425.          if (pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_POST_ENABLE)
  426.             CallPostRoutine(pSRBIO);
  427.       }
  428.    }
  429.  
  430. #pragma optimize("cegl",off)        /* Disable optimization switches that    */
  431.                                     /* are illegal for routines that contain */
  432.                                     /* inline assembly code                  */
  433. /*********************************************************
  434. *                                                        *
  435. *   Procedure Name : DoASPIAbortIO                       *
  436. *                                                        *
  437. *   Description : This procedure handles requests to     *
  438. *   abort commands being executed by a device.           *
  439. *                                                        *
  440. *   Input :                                              *
  441. *         pSRBIO - A pointer to the SRB for I/O          *
  442. *         virtualASPI - Flags indicating the status of   *
  443. *           the VDM that MAY be associated with the SRB. *
  444. *                                                        *
  445. *   Output :                                             *
  446. *                                                        *
  447. *********************************************************/
  448. VOID NEAR DoASPIAbortIO(PASPI_SRB_ABORT_IO pSRBIO, USHORT virtualASPI)
  449.  
  450.    {
  451.    UCHAR    adapterIndex;
  452.    NPATE    npATE;
  453.    USHORT   resultCode;
  454.    USHORT   modeFlag;
  455.    PASPI_SRB_EXECUTE_IO pAbortSRB;
  456.    PASPI_SRBWORK pASPIWork;
  457.  
  458.    /* Verify that the host adapter is valid */
  459.    adapterIndex = pSRBIO->SRBHdr.AdapterIndex;
  460.  
  461.    if (adapterIndex >= numberOfASPIAdapters)
  462.       pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_INVALID_ADAPTER;
  463.    else
  464.       {
  465.       /* Convert physical address of SRB being aborted to virtual address */
  466.       /* and release it after extracting the targetID and targetLUN       */
  467.       resultCode = DevHelp_PhysToVirt(pSRBIO->ppSRB,
  468.                                       (USHORT) sizeof(ASPI_SRB_EXECUTE_IO),
  469.                                       (PPVOID)&pAbortSRB,
  470.                                       &modeFlag);
  471.  
  472.       /* The driver must not yield while the virtual address is being used */
  473.       DISABLE
  474.       npATE = FindTarget(adapterIndex,
  475.                          pAbortSRB->DeviceTargetID,
  476.                          pAbortSRB->DeviceTargetLUN);
  477.       if (npATE)
  478.          {
  479.          /* Retrieve the virtual pointer used by the VDD */
  480.          /* in case this request is part of a VDM_DESTROY event. */
  481.          pASPIWork = (PASPI_SRBWORK) pAbortSRB->ASPIWorkSpace;
  482.          }
  483.       ENABLE
  484.  
  485.       DevHelp_UnPhysToVirt(&modeFlag);
  486.  
  487.       if (npATE)
  488.          {
  489.          /* Abort IORB pending on the device for specified SRB.       */
  490.          /* Queues will automatically be cleaned up by NotifyIORBDone */
  491.          /* as each SRB is aborted.                                   */
  492.          AbortIORB(npATE,
  493.                    pSRBIO,
  494.                    pASPIWork,
  495.                    0,
  496.                    virtualASPI);
  497.  
  498.          }
  499.       else
  500.          pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_INVALID_TARGET;
  501.       }
  502.    }
  503.  
  504. #pragma optimize("cegl",on)         /* Enable optimization switches again */
  505.  
  506. /*********************************************************
  507. *                                                        *
  508. *   Procedure Name : AbortIORB                           *
  509. *                                                        *
  510. *   Description : This procedure attempts to abort the   *
  511. *   IORB that was created for a specified SRB. Since     *
  512. *   this IORB has already been passed to the ADD we      *
  513. *   cannot assume it will succeed. The actual success    *
  514. *   or failure of this command must be verified in the   *
  515. *   status of the ABORT SRB.                             *
  516. *                                                        *
  517. *   Input :                                              *
  518. *         npATE - A pointer to the command target's ATE  *
  519. *         pSRBIO - A pointer to the SRB                  *
  520. *         pSRBToAbortWork - A pointer to the work space  *
  521. *           of the SRB being aborted.                    *
  522. *         npSRBLink - A pointer to the SRB_LINK that is  *
  523. *           allocated for the current command.           *
  524. *         virtualASPI - Flags indicating the status of   *
  525. *           the VDM that MAY be associated with the SRB. *
  526. *                                                        *
  527. *   Output :                                             *
  528. *                                                        *
  529. *********************************************************/           /*@V61092*/
  530. VOID NEAR AbortIORB(NPATE npATE,PASPI_SRB_ABORT_IO pSRBIO,
  531.                     PASPI_SRBWORK pSRBToAbortWork, NPSRB_LINK npSRBLink,
  532.                     USHORT virtualASPI)
  533.  
  534.    {
  535.    PIORB_DEVICE_CONTROL pIORB;
  536.    PIORB_DMWORK pDMWork;
  537.    ULONG physSRBIO;
  538.    ULONG SRBLockHandle;
  539.    PIORBH pIORBToAbort;
  540.  
  541.    /* Allocate an IORB for the current SRB if one is not already available */
  542.    if (!npSRBLink)                                                        /*@V61092*/
  543.       npSRBLink = AllocateIORB(npATE,
  544.                                (PASPI_SRB_HEADER) pSRBIO,
  545.                                AbortIORB,
  546.                                virtualASPI);/*@V61092*/
  547.                                                                           /*@V61092*/
  548.    if (npSRBLink)                                                         /*@V61092*/
  549.       {
  550.       /* Create an IORB that the ADD can handle */
  551.       pIORB = (PIORB_DEVICE_CONTROL) &npSRBLink->IORB;
  552.       pDMWork = (PIORB_DMWORK) &(pIORB->iorbh.DMWorkSpace);
  553.  
  554.       memset((PBYTE) pIORB,0,sizeof(IORB_DEVICE_CONTROL));
  555.       pIORB->iorbh.Length = sizeof(IORB_DEVICE_CONTROL);
  556.       pIORB->iorbh.UnitHandle = npATE->UnitHandle;
  557.       pIORB->iorbh.CommandCode = IOCC_DEVICE_CONTROL;
  558.       pIORB->iorbh.CommandModifier = IOCM_ABORT;
  559.  
  560.       pIORB->iorbh.NotifyAddress = &NotifyIORBDone;
  561.       pIORB->iorbh.StatusBlockLen = sizeof(SCSI_STATUS_BLOCK);
  562.       pIORB->iorbh.pStatusBlock = (NPBYTE) &npSRBLink->commandStatus;
  563.  
  564.       /* Clear the status block before using it */
  565.       memset((PBYTE) &npSRBLink->commandStatus,0,sizeof(SCSI_STATUS_BLOCK));
  566.  
  567.       /* Save DS and pointers to the request packet and current ATE */
  568.       pDMWork->npATE = npATE;
  569.       pDMWork->virtualASPI = virtualASPI;
  570.       npSRBLink->OrigSRBPtr  = (PVOID) pSRBIO;
  571.  
  572.  
  573.       /* Lock the SRB selector in place and record its location. */
  574.       /* This really should have been done by the caller, but it is */
  575.       /* nice to try and be sure. */
  576.       DevHelp_Lock(SELECTOROF(pSRBIO),
  577.                    1,
  578.                    1,
  579.                    &SRBLockHandle);
  580.  
  581.       DevHelp_VirtToPhys(pSRBIO,
  582.                          &physSRBIO);
  583.  
  584.       /* Copy the SRB selector to the GDT so we can use it later */
  585.       pDMWork->SRBGDTSelector = npSRBLink->SRBGDTSelector;           /*@V58231*/
  586.       DevHelp_PhysToGDTSelector(physSRBIO,
  587.                                 sizeof(ASPI_SRB_ABORT_IO),
  588.                                 pDMWork->SRBGDTSelector);
  589.  
  590.       /* Release our lock on the SRB because it cannot be done */
  591.       /* at interrupt time!! */
  592.       DevHelp_UnLock(SRBLockHandle);
  593.  
  594.       /* Place the SRB_LINK in the active queue of the ATE */
  595.       InsertSRBActiveQueue(npATE,
  596.                            npSRBLink,
  597.                            (PASPI_SRB_HEADER) MAKEP(pDMWork->SRBGDTSelector,
  598.                                                     0));
  599.  
  600.       /* If we are aborting a VDM request in response to the destruction */
  601.       /* of the VDM itself, we will fake the VDM out to avoid any chance */
  602.       /* that the VDM will have to wait a really long time for the command */
  603.       /* to be aborted. This would occur if the device has disconnected */
  604.       /* from the SCSI bus and will not see the abort request until the */
  605.       /* command has completed and it reconnects to the bus. */
  606.       if ((virtualASPI & VDM_DESTROY_EVENT) != 0)
  607.          {
  608.          /* Modify the IORB workspace of the SRB being aborted */
  609.          /* to remember that the VDM was already destroyed. */
  610.          pIORBToAbort = (PIORBH) pSRBToAbortWork->pIORB;
  611.          ((PIORB_DMWORK) (pIORBToAbort->DMWorkSpace))->virtualASPI |= VDM_DESTROY_EVENT;
  612.  
  613.          /* Simulate the post to the VDD now. */
  614.          CallVirtPostRoutine((PASPI_SRB_EXECUTE_IO) pSRBToAbortWork->pSRB);
  615.          }
  616.  
  617.       /* Send the abort IORB to the ADD */
  618.       SendIORB((PIORBH) pIORB,npATE->TargetADD_Entry);
  619.       }
  620.    }
  621.  
  622. /*********************************************************
  623. *                                                        *
  624. *   Procedure Name : DoASPISetAdapterParms               *
  625. *                                                        *
  626. *   Description : This procedure is intended to allow    *
  627. *   adapter parameters to be modified and is therefore   *
  628. *   quite vendor specific. Currently NOTHING is done.    *
  629. *                                                        *
  630. *   Input :                                              *
  631. *         pSRAP - A pointer to the current SRB           *
  632. *         virtualASPI - Flags indicating the status of   *
  633. *           the VDM that MAY be associated with the SRB. *
  634. *                                                        *
  635. *   Output :                                             *
  636. *                                                        *
  637. *********************************************************/
  638. USHORT NEAR DoASPISetAdapterParms(PASPI_SRB_ADAPTER_PARMS pSRAP, USHORT virtualASPI)
  639.  
  640.    {
  641.    pSRAP->SRBHdr.ASPIStatus = ASPI_STATUS_NO_ERROR;
  642.    return(STDON);
  643.    }
  644.  
  645. /*********************************************************
  646. *                                                        *
  647. *   Procedure Name : SRBToIORBPassThru                   *
  648. *                                                        *
  649. *   Description : This procedure creates an IORB from    *
  650. *   the ASPI SRB and issues the command to the ADD.      *
  651. *                                                        *
  652. *   Input :                                              *
  653. *         npATE - A pointer to the command target's ATE  *
  654. *         pSRBIO - A pointer to the SRB                  *
  655. *         npSRBLink - A pointer to the SRB_LINK that is  *
  656. *           allocated for the current command.           *
  657. *         virtualASPI - Flags indicating the status of   *
  658. *           the VDM that MAY be associated with the SRB. *
  659. *                                                        *
  660. *   Output :                                             *
  661. *                                                        *
  662. *********************************************************/
  663. VOID NEAR SRBToIORBPassThru(NPATE npATE,PASPI_SRB_EXECUTE_IO pSRBIO,
  664.                             NPSRB_LINK npSRBLink,USHORT virtualASPI)
  665.  
  666.    {
  667.    /* Allocate an IORB for the current SRB if one is not already available */
  668.    if (!npSRBLink)
  669.       npSRBLink = AllocateIORB(npATE,
  670.                                (PASPI_SRB_HEADER) pSRBIO,
  671.                                SRBToIORBPassThru,
  672.                                virtualASPI);
  673.  
  674.    if (npSRBLink)
  675.       {
  676.       /* Create an IORB that the ADD can handle */
  677.       BuildPassThruIORB(npATE,
  678.                         pSRBIO,
  679.                         npSRBLink,
  680.                         virtualASPI);
  681.  
  682.       /* Place the SRB_LINK in the active queue of the ATE */
  683.       InsertSRBActiveQueue(npATE,
  684.                            npSRBLink,
  685.                            (PASPI_SRB_HEADER) pSRBIO);
  686.  
  687.       /* Send the IORB to the ADD */
  688.       SendIORB((PIORBH) &npSRBLink->IORB,
  689.                npATE->TargetADD_Entry);
  690.       }
  691.    }
  692.  
  693. /*********************************************************
  694. *                                                        *
  695. *   Procedure Name : SRBToIORBReset                      *
  696. *                                                        *
  697. *   Description : This procedure creates an IORB that    *
  698. *   will reset the selected adapter target.              *
  699. *                                                        *
  700. *   Input :                                              *
  701. *         npATE - A pointer to the current ATE           *
  702. *         pSRBRD - A pointer to the current SRB          *
  703. *         npSRBLink - A pointer to the SRB_LINK that is  *
  704. *           allocated for the current command.           *
  705. *         virtualASPI - Flags indicating the status of   *
  706. *           the VDM that MAY be associated with the SRB. *
  707. *                                                        *
  708. *   Output :                                             *
  709. *                                                        *
  710. *********************************************************/
  711. VOID NEAR SRBToIORBReset(NPATE npATE,PASPI_SRB_RESET_DEVICE pSRBRD,
  712.                          NPSRB_LINK npSRBLink,USHORT virtualASPI)
  713.  
  714.    {
  715.    PIORB_DEVICE_CONTROL pIORB;
  716.    PIORB_DMWORK pDMWork;
  717.    PASPI_SRBWORK pASPIWork;
  718.    ULONG physSRBIO;
  719.    ULONG SRBLockHandle;
  720.  
  721.    /* Allocate an IORB for the current SRB if one is not already available */
  722.    if (!npSRBLink)
  723.       npSRBLink = AllocateIORB(npATE,
  724.                                (PASPI_SRB_HEADER) pSRBRD,
  725.                                SRBToIORBReset,
  726.                                virtualASPI);
  727.  
  728.    if (npSRBLink)
  729.       {
  730.       /* Create an IORB that the ADD can handle */
  731.       pIORB = (PIORB_DEVICE_CONTROL) &npSRBLink->IORB;
  732.       pDMWork = (PIORB_DMWORK) &(pIORB->iorbh.DMWorkSpace);
  733.  
  734.       memset((PBYTE) pIORB,0,sizeof(IORB_DEVICE_CONTROL));
  735.       pIORB->iorbh.Length = sizeof(IORB_DEVICE_CONTROL);
  736.       pIORB->iorbh.UnitHandle = npATE->UnitHandle;
  737.       pIORB->iorbh.CommandCode = IOCC_DEVICE_CONTROL;
  738.       pIORB->iorbh.CommandModifier = IOCM_RESET;
  739.  
  740.       pIORB->iorbh.NotifyAddress = &NotifyIORBDone;
  741.       pIORB->iorbh.StatusBlockLen = sizeof(SCSI_STATUS_BLOCK);
  742.       pIORB->iorbh.pStatusBlock = (NPBYTE) &npSRBLink->commandStatus;
  743.  
  744.       /* Clear the status block before using it */
  745.       memset((PBYTE) &npSRBLink->commandStatus,0,sizeof(SCSI_STATUS_BLOCK));
  746.  
  747.       /* Save DS and pointers to the request packet and current ATE */
  748.       pDMWork->npATE = npATE;
  749.       pDMWork->virtualASPI = virtualASPI;
  750.       npSRBLink->OrigSRBPtr  = (PVOID) pSRBRD;
  751.  
  752.       /* Save the virtual pointer to the SRB and the IORB ptr */
  753.       /* in the SRB workspace. These will be used if the request */
  754.       /* originated in a VDM and the VDM is destroyed while the */
  755.       /* request is still pending. */
  756.       pASPIWork = (PASPI_SRBWORK) pSRBRD->ASPIWorkSpace;
  757.       pASPIWork->pSRB = npSRBLink->OrigSRBPtr;
  758.       pASPIWork->pIORB = (PIORBH) pIORB;
  759.  
  760.       /* Lock the SRB selector in place and record its location. */
  761.       /* This really should have been done by the caller, but it is */
  762.       /* nice to try and be sure. */
  763.       DevHelp_Lock(SELECTOROF(pSRBRD),
  764.                    1,
  765.                    1,
  766.                    &SRBLockHandle);
  767.  
  768.       DevHelp_VirtToPhys(pSRBRD,
  769.                          &physSRBIO);
  770.  
  771.       pDMWork->SRBGDTSelector = npSRBLink->SRBGDTSelector;           /*@V58231*/
  772.       DevHelp_PhysToGDTSelector(physSRBIO,
  773.                                 sizeof(ASPI_SRB_RESET_DEVICE),
  774.                                 pDMWork->SRBGDTSelector);
  775.  
  776.       /* Release our lock on the SRB because it cannot be done */
  777.       /* at interrupt time!! */
  778.       DevHelp_UnLock(SRBLockHandle);
  779.  
  780.       /* Place the SRB_LINK in the active queue of the ATE */
  781.       InsertSRBActiveQueue(npATE,
  782.                            npSRBLink,
  783.                            (PASPI_SRB_HEADER) MAKEP(pDMWork->SRBGDTSelector,
  784.                            0));
  785.  
  786.       /* Send the IORB to the ADD */
  787.       SendIORB((PIORBH) pIORB,
  788.                npATE->TargetADD_Entry);
  789.       }
  790.    }
  791.  
  792. /*********************************************************
  793. *                                                        *
  794. *   Procedure Name : FindAdapter                         *
  795. *                                                        *
  796. *   Description : This procedure scans the list of       *
  797. *   host adapters that are accepting ASPI commands and   *
  798. *   tries to find a match.                               *
  799. *                                                        *
  800. *   Input :                                              *
  801. *         adapterIndex - The adapter being searched for  *
  802. *                                                        *
  803. *   Output :   A pointer to the ACB of the host adapter  *
  804. *   that was found or a NULL pointer if there was no     *
  805. *   match.                                               *
  806. *                                                        *
  807. *********************************************************/
  808. NPACB FindAdapter(UCHAR adapterIndex)
  809.  
  810.    {
  811.    NPACB   npACB;
  812.    USHORT adapterCount;
  813.  
  814.    /* Start at the beginning of the ACB list */
  815.    npACB = npACBAnchor;
  816.    adapterCount = 0;
  817.  
  818.    /* Search until a match is found or all the adapters have been scanned */
  819.    while ((npACB->AdapterIndex != adapterIndex) &&
  820.           (adapterCount < numberOfASPIAdapters))
  821.       {
  822.       npACB = npACB->npNextACB;
  823.       adapterCount++;
  824.       }
  825.  
  826.    if (npACB->AdapterIndex != adapterIndex)
  827.       npACB = 0;
  828.  
  829.    return(npACB);
  830.    }
  831.  
  832. /*********************************************************
  833. *                                                        *
  834. *   Procedure Name : FindTarget                          *
  835. *                                                        *
  836. *   Description : This procedure scans the list of       *
  837. *   targets attached to the current ACB and tries to     *
  838. *   find a match.                                        *
  839. *                                                        *
  840. *   Input :                                              *
  841. *         adapterIndex - The adapter being searched      *
  842. *         targetID - The SCSI ID being searched for      *
  843. *         targetLUN - The SCSI LUN being searched for    *
  844. *                                                        *
  845. *   Output :   A pointer to the ATE of the target device *
  846. *   that was found or a NULL pointer if there was no     *
  847. *   match.                                               *
  848. *                                                        *
  849. *********************************************************/
  850. NPATE FindTarget(UCHAR adapterIndex,UCHAR targetID, UCHAR targetLUN)
  851.  
  852.    {
  853.    NPACB npACB;
  854.    NPATE npATE;
  855.  
  856.    /* Find the ACB of the target's host adapter and start searching */
  857.    /* with the first target attached to it                          */
  858.    npACB = FindAdapter(adapterIndex);
  859.    npATE = npACB->npFirstATE;
  860.  
  861.    /* Search until the targetID is found or there are no more targets */
  862.    while ((targetID != npATE->DeviceTargetID) &&
  863.           (adapterIndex == npATE->npOwnerACB->AdapterIndex) &&
  864.           (npATE))
  865.       npATE = npATE->npNextATE;
  866.  
  867.  
  868.    if ((targetID == npATE->DeviceTargetID) &&
  869.        (adapterIndex == npATE->npOwnerACB->AdapterIndex) &&
  870.        (npATE))
  871.       {
  872.       /* Search until the targetLUN is found or there are no more targets */
  873.       while ((targetLUN != npATE->DeviceTargetLUN) &&
  874.              (targetID == npATE->DeviceTargetID) &&
  875.              (adapterIndex == npATE->npOwnerACB->AdapterIndex) &&
  876.              (npATE))
  877.          npATE = npATE->npNextATE;
  878.  
  879.       if ((targetLUN != npATE->DeviceTargetLUN) ||
  880.           (targetID != npATE->DeviceTargetID) ||
  881.           (adapterIndex != npATE->npOwnerACB->AdapterIndex))
  882.          npATE = 0;
  883.       }
  884.    else
  885.       /* No target was found so DON'T return a pointer */
  886.       npATE = 0;
  887.    return(npATE);
  888.    }
  889.  
  890. #pragma optimize("cegl",off)        /* Disable optimization switches that    */
  891.                                     /* are illegal for routines that contain */
  892.                                     /* inline assembly code                  */
  893.  
  894. /*********************************************************
  895. *                                                        *
  896. *   Procedure Name : AllocateIORB                        *
  897. *                                                        *
  898. *   Description : This procedure takes the next          *
  899. *   available SRB_LINK, which contains an IORB and       *
  900. *   returns a pointer to it. If no IORB is available     *
  901. *   the SRB will be inserted in a queue of waiting SRB   *
  902. *   until all SRB_LINK required by it are available.     *
  903. *                                                        *
  904. *   Input :                                              *
  905. *                                                        *
  906. *   Output :   A pointer to the next available SRB_LINK  *
  907. *              or 0 if there are an insufficient number  *
  908. *              of SRB_LINK available for the request.    *
  909. *                                                        *
  910. *********************************************************/
  911. NPSRB_LINK AllocateIORB(NPATE npATE, PASPI_SRB_HEADER pSRBH,
  912.                         VOID (NEAR *ASPIRequestRoutine)(), USHORT virtualASPI)
  913.  
  914.    {
  915.    NPSRB_LINK npSRBLink = 0;
  916.  
  917.    /* If an SRB_LINK is available return a pointer to it       */
  918.    /* otherwise place the SRB in the queue of waiting requests */
  919.  
  920.    DISABLE
  921.  
  922.    if (npSRBLinkFreeList)
  923.       {
  924.       npSRBLink = npSRBLinkFreeList;
  925.       npSRBLinkFreeList = npSRBLinkFreeList->npNextSRBLink;
  926.       npSRBLink->OrigSRBPtr = (PVOID) pSRBH;
  927.       }
  928.    else
  929.       {
  930.       SRBWaitQueue[IORBWaitSem].SRBPtr = pSRBH;                       /*@V61092*/
  931.       SRBWaitQueue[IORBWaitSem].ATEPtr = npATE;                       /*@V61092*/
  932.       SRBWaitQueue[IORBWaitSem].callbackFunction = ASPIRequestRoutine;/*@V61092*/
  933.       SRBWaitQueue[IORBWaitSem].virtualASPI = virtualASPI;
  934.       IORBWaitSem++;                                                  /*@V61092*/
  935.       }                                                               /*@V61092*/
  936.  
  937.    ENABLE
  938.  
  939.    return(npSRBLink);
  940.    }
  941.  
  942. /*********************************************************
  943. *                                                        *
  944. *   Procedure Name : FreeIORB                            *
  945. *                                                        *
  946. *   Description : This procedure releases the IORB or    *
  947. *   that was just completed and places it back in the    *
  948. *   pool of available SRB_LINKs. If SRBs are waiting,    *
  949. *   the next one will be started.                        *
  950. *                                                        *
  951. *   Input : A pointer to the SRB_LINK(s)                 *
  952. *                                                        *
  953. *   Output :                                             *
  954. *                                                        *
  955. *********************************************************/
  956. VOID FreeIORB(NPSRB_LINK npSRBLink)
  957.  
  958.    {
  959.    DISABLE                                                           /*@V61092*/
  960.                                                                      /*@V61092*/
  961.    /* If anyone is waiting for an IORB, wake them up */              /*@V61092*/
  962.    if (IORBWaitSem)                                                  /*@V61092*/
  963.       {                                                              /*@V61092*/
  964.       IORBWaitSem--;                                                 /*@V61092*/
  965.                                                                      /*@V61092*/
  966.       npSRBLink->OrigSRBPtr = (PVOID) (SRBWaitQueue[IORBWaitSem].SRBPtr);
  967.       /* Resubmit SRB with SRB_LINK already allocated */             /*@V61092*/
  968.       (VOID) (SRBWaitQueue[IORBWaitSem].callbackFunction)            /*@V61092*/
  969.                (SRBWaitQueue[IORBWaitSem].ATEPtr,                    /*@V61092*/
  970.                 SRBWaitQueue[IORBWaitSem].SRBPtr,                    /*@V61092*/
  971.                 npSRBLink,
  972.                 SRBWaitQueue[IORBWaitSem].virtualASPI);
  973.       ENABLE                                                         /*@V61092*/
  974.       }                                                              /*@V61092*/
  975.    else                                                              /*@V61092*/
  976.       {                                                              /*@V61092*/
  977.       /* Insert the completed IORB at the front of the free list */  /*@V61092*/
  978.       npSRBLink->npNextSRBLink = npSRBLinkFreeList;                  /*@V61092*/
  979.       npSRBLinkFreeList = npSRBLink;                                 /*@V61092*/
  980.       ENABLE                                                         /*@V61092*/
  981.       }                                                              /*@V61092*/
  982.    }
  983.  
  984. /* Removed optimization from this routine because of compiler */     /*@V58231*/
  985. /*     in MSC 6.00A.04.                                       */     /*@V58231*/
  986. #pragma optimize("gl",on)    /* Enable optimization switches again *//*@V58231*/
  987.  
  988. /*********************************************************
  989. *                                                        *
  990. *   Procedure Name : BuildPassThruIORB                   *
  991. *                                                        *
  992. *   Description : This procedure builds an IORB for the  *
  993. *   current SRB within a freshly allocated SRB_LINK.     *
  994. *                                                        *
  995. *   Input :                                              *
  996. *         npATE - A pointer to the current ATE           *
  997. *         pSRBIO - A pointer to the current SRB          *
  998. *         npSRBLink - A pointer to the new SRB_LINK      *
  999. *         virtualASPI - Flags indicating the status of   *
  1000. *           the VDM that MAY be associated with the SRB. *
  1001. *                                                        *
  1002. *   Output :                                             *
  1003. *                                                        *
  1004. *********************************************************/
  1005. VOID BuildPassThruIORB(NPATE npATE,PASPI_SRB_EXECUTE_IO pSRBIO,
  1006.                        NPSRB_LINK npSRBLink, USHORT virtualASPI)
  1007.  
  1008.    {
  1009.    PIORB_ADAPTER_PASSTHRU pIORB;
  1010.    PIORB_DMWORK pDMWork;
  1011.    PASPI_SRBWORK pASPIWork;
  1012.  
  1013.    pIORB = (PIORB_ADAPTER_PASSTHRU) &npSRBLink->IORB;
  1014.    pDMWork = (PIORB_DMWORK) &(pIORB->iorbh.DMWorkSpace);
  1015.  
  1016.    memset((PBYTE) pIORB,
  1017.           0,
  1018.           sizeof(IORB_ADAPTER_PASSTHRU));
  1019.    pIORB->iorbh.Length = sizeof(IORB_ADAPTER_PASSTHRU);
  1020.    pIORB->iorbh.UnitHandle = npATE->UnitHandle;
  1021.    pIORB->iorbh.CommandCode = IOCC_ADAPTER_PASSTHRU;
  1022.    pIORB->iorbh.CommandModifier = IOCM_EXECUTE_CDB;
  1023.  
  1024.    npSRBLink->OrigSRBPtr  = (PVOID) pSRBIO;
  1025.  
  1026.    /* Save the virtual pointer to the SRB and the IORB ptr */
  1027.    /* in the SRB workspace. These will be used if the request */
  1028.    /* originated in a VDM and the VDM is destroyed when the */
  1029.    /* request is still pending. */
  1030.    pASPIWork = (PASPI_SRBWORK) pSRBIO->ASPIWorkSpace;
  1031.    pASPIWork->pSRB = npSRBLink->OrigSRBPtr;
  1032.    pASPIWork->pIORB = (PIORBH) pIORB;
  1033.  
  1034.    /* Copy the SRB selector to the GDT so we can use it later */
  1035.    pDMWork->SRBGDTSelector = npSRBLink->SRBGDTSelector;              /*@V58231*/
  1036.    DevHelp_PhysToGDTSelector(pSRBIO->ppSRB,
  1037.                              sizeof(ASPI_SRB_EXECUTE_IO) +
  1038.                              pSRBIO->SenseDataLen +
  1039.                              pSRBIO->SCSICDBLen,
  1040.                              pDMWork->SRBGDTSelector);
  1041.  
  1042.    /* Convert the SRB pointer to the "safe" GDT selector */
  1043.    pSRBIO = (PASPI_SRB_EXECUTE_IO) MAKEP(pDMWork->SRBGDTSelector,0);
  1044.  
  1045.    pIORB->iorbh.NotifyAddress = &NotifyIORBDone;
  1046.    pIORB->ControllerCmdLen = pSRBIO->SCSICDBLen;
  1047.    pIORB->pControllerCmd = pSRBIO->SCSICDBStart;
  1048.    pIORB->iorbh.StatusBlockLen = sizeof(SCSI_STATUS_BLOCK);
  1049.    pIORB->iorbh.pStatusBlock = (NPBYTE) &npSRBLink->commandStatus;
  1050.  
  1051.    /* Clear the status block before using it */
  1052.    memset((PBYTE) &npSRBLink->commandStatus,0,sizeof(SCSI_STATUS_BLOCK));
  1053.  
  1054.    ((PSCSI_STATUS_BLOCK)(pIORB->iorbh.pStatusBlock))->SenseData =
  1055.       (PSCSI_REQSENSE_DATA) (pSRBIO->SCSICDBStart + pSRBIO->SCSICDBLen);
  1056.  
  1057.    ((PSCSI_STATUS_BLOCK)(pIORB->iorbh.pStatusBlock))->ReqSenseLen =
  1058.       pSRBIO->SenseDataLen;
  1059.  
  1060.    /* Set up a pointer to the scatter/gather list or data buffer */
  1061.    if (pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_SG_ENABLE)
  1062.       {
  1063.       pIORB->cSGList = pSRBIO->SGListLen;
  1064.       pIORB->ppSGLIST = pSRBIO->ppDataBuffer;
  1065.  
  1066.       /* Get a pointer to the scatter/gather list by using the GDT */
  1067.       /* allocated to the current target for scatter/gather.       */
  1068.       pDMWork->SGGDTSelector = npSRBLink->SGGDTSelector;             /*@V58231*/
  1069.       DevHelp_PhysToGDTSelector(pIORB->ppSGLIST,
  1070.                                 pIORB->cSGList * sizeof(SCATGATENTRY),
  1071.                                 pDMWork->SGGDTSelector);             /*@V58231*/
  1072.  
  1073.       pIORB->pSGList = (PSCATGATENTRY) MAKEP(pDMWork->SGGDTSelector,0);/*@V61092*/
  1074.       }
  1075.    else
  1076.       {
  1077.       /* Treat a standard data buffer as a scatter/gather list     */
  1078.       /* with only one element. If there is no data transfer, then */
  1079.       /* do NOT build a scatter/gather list.                       */
  1080.       if (pSRBIO->DataXferLen)                                       /*@V58231*/
  1081.          {                                                           /*@V58231*/
  1082.          pIORB->cSGList = 1;                                         /*@V58231*/
  1083.          pIORB->pSGList = (PVOID) pIORB;
  1084.          OFFSETOF(pIORB->pSGList) = (USHORT)((ULONG)&(pDMWork->SGList));
  1085.          pIORB->ppSGLIST = (ULONG)  (ppDataSeg +
  1086.                                     (USHORT)((ULONG) &(pDMWork->SGList)));
  1087.  
  1088.          /* Insert the single element in the scatter/gather list */
  1089.          (ULONG) (pDMWork->SGList.ppXferBuf) = pSRBIO->ppDataBuffer;
  1090.          (ULONG) (pDMWork->SGList.XferBufLen) = pSRBIO->DataXferLen;
  1091.          }                                                           /*@V58231*/
  1092.       }
  1093.  
  1094.    /* Give all commands the MAXIMUM timeout since ASPI does not   */
  1095.    /* really require this option. Commands that don't finish will */
  1096.    /* be aborted by the driver that requested them.               */
  1097.    pIORB->iorbh.Timeout = 0xFFFFFFFF;
  1098.  
  1099.    /* Record the direction of the data transfer */
  1100.    DetermineDirectionBits(npATE, pIORB, pSRBIO);
  1101.  
  1102.    /* Save pointer to the current ATE */
  1103.    pDMWork->npATE = npATE;
  1104.    pDMWork->virtualASPI = virtualASPI;
  1105.    }
  1106.  
  1107. #pragma optimize("ce",on)        /* Enable optimization switches */  /*@V58231*/
  1108.  
  1109. /*********************************************************
  1110. *                                                        *
  1111. *   Function Name : DetermineDirectionBits               *
  1112. *                                                        *
  1113. *   Description : This function determines command       *
  1114. *   direction and inserts the appropriate bits into      *
  1115. *   the IORB.                                            *
  1116. *                                                        *
  1117. *   Input :                                              *
  1118. *         pSRBIO - A pointer to the SRB being processed  *
  1119. *         pIORB - A pointer to the IORB being created    *
  1120. *                                                        *
  1121. *   Output :                                             *
  1122. *                                                        *
  1123. *********************************************************/
  1124. USHORT DetermineDirectionBits( NPATE                  npATE,
  1125.                                PIORB_ADAPTER_PASSTHRU pIORB,
  1126.                                PASPI_SRB_EXECUTE_IO   pSRBIO )
  1127.    {
  1128.    USHORT   OpCode = pSRBIO->SCSICDBStart[0];
  1129.    USHORT   rc = 1;
  1130.    NPUCHAR  npDIRM;
  1131.    NPUCHAR  npDIREX;
  1132.    USHORT   DirBits;
  1133.    USHORT   i, n;
  1134.  
  1135.    /**
  1136.     ** Was the direction of the command given in the SRB?
  1137.     **/
  1138.  
  1139.    DirBits = pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_DIRECTION_BITS;
  1140.  
  1141.    if ( (DirBits == ASPI_REQFLAG_DIR_TO_HOST)  ||
  1142.         (DirBits == ASPI_REQFLAG_DIR_NO_DATA_XFER ) )
  1143.       {
  1144.       pIORB->Flags = PT_DIRECTION_IN;
  1145.       }
  1146.    else if ( DirBits == ASPI_REQFLAG_DIR_TO_TARGET )
  1147.       {
  1148.       pIORB->Flags = 0;
  1149.       }
  1150.    else
  1151.       {
  1152.       /**
  1153.        ** Determine the transfer direction based on the CDB
  1154.        **
  1155.        ** The appropriate direction mask is determined at INIT
  1156.        ** time. If the device does not have a known SCSI device
  1157.        ** type and we do not have a specific direction mask for
  1158.        ** it, then the ASPI client driver must specify direction!
  1159.        **
  1160.        ** The table is encodeded so that a 1-bit indicates
  1161.        ** direction of transfer is Initiator-to-Target,
  1162.        ** i.e. a WRITE to the target.
  1163.        **/
  1164.       if ( npDIREX = npATE->npDirExcept )
  1165.          {
  1166.          n = npDIREX[0] * 2 + 1;
  1167.          for (i=1; i < n; i+=2 )
  1168.             {
  1169.             if ( OpCode == npDIREX[i] )
  1170.                {
  1171.                pIORB->Flags = ( npDIREX[i+1] ) ? 0 : PT_DIRECTION_IN;
  1172.                goto Exit_Dir;
  1173.                }
  1174.             }
  1175.          }
  1176.       if ( npDIRM = npATE->npDirTable )
  1177.          {
  1178.          pIORB->Flags = ( npDIRM[OpCode/8] & (0x80>>(OpCode % 8)) )
  1179.                                                     ? 0: PT_DIRECTION_IN;
  1180.          }
  1181.       else
  1182.          {
  1183.            rc = 0;
  1184.          }
  1185.  
  1186.       }
  1187.  
  1188. Exit_Dir:
  1189.    return rc;
  1190.    }
  1191.  
  1192. /*********************************************************
  1193. *                                                        *
  1194. *   Function Name : SendIORB                             *
  1195. *                                                        *
  1196. *   Description : This function sends an IORB to the     *
  1197. *   ADD and returns immediately after submitting it.     *
  1198. *                                                        *
  1199. *   Input :                                              *
  1200. *         npIORB - A pointer to the IORB being issued    *
  1201. *         pADD_IORB_Entry - A pointer to the ADD         *
  1202. *            entry point for the unit receiving the IORB *
  1203. *                                                        *
  1204. *   Output :   This function returns the error status    *
  1205. *   reported by the IORB.                                *
  1206. *                                                        *
  1207. *********************************************************/
  1208. VOID SendIORB(PIORBH pIORB, VOID (FAR *pADD_IORB_Entry)(PIORB))
  1209.  
  1210.    {
  1211.    pIORB->RequestControl = IORB_ASYNC_POST | IORB_REQ_STATUSBLOCK |
  1212.                            IORB_DISABLE_RETRY;
  1213.  
  1214.    (*pADD_IORB_Entry)(pIORB);
  1215.    }
  1216.  
  1217.  
  1218. #pragma optimize("cegl",off)        /* Disable optimization switches that    */
  1219.                                     /* are illegal for routines that contain */
  1220.                                     /* inline assembly code                  */
  1221.  
  1222. /*********************************************************
  1223. *                                                        *
  1224. *   Function Name : SendIORBandWait                      *
  1225. *                                                        *
  1226. *   Description : This function sends an IORB to the     *
  1227. *   ADD and waits for completion before returning.       *
  1228. *                                                        *
  1229. *   Input :                                              *
  1230. *         npIORB - A pointer to the IORB being issued    *
  1231. *         pADD_IORB_Entry - A pointer to the ADD         *
  1232. *            entry point                                 *
  1233. *                                                        *
  1234. *   Output :   This function returns the error status    *
  1235. *   reported by the IORB.                                *
  1236. *                                                        *
  1237. *********************************************************/
  1238. USHORT SendIORBandWait(NPIORBH npIORB, VOID (FAR *pADD_IORB_Entry)(PIORB))
  1239.  
  1240.    {
  1241.    npIORB->RequestControl = IORB_ASYNC_POST;
  1242.  
  1243.    (*pADD_IORB_Entry)(npIORB);
  1244.  
  1245.    DISABLE
  1246.    while (!(npIORB->Status & IORB_DONE))
  1247.       {
  1248.       DevHelp_ProcBlock((ULONG) OFFSETOF(npIORB),
  1249.                         (ULONG) -1,
  1250.                         WAIT_IS_NOT_INTERRUPTABLE);
  1251.       DISABLE
  1252.       }
  1253.    ENABLE
  1254.  
  1255.    return(npIORB->ErrorCode);
  1256.    }
  1257.  
  1258. /*********************************************************
  1259. *                                                        *
  1260. *   Procedure Name : NotifyIORBDone                      *
  1261. *                                                        *
  1262. *   Description : This procedure is called by the ADD    *
  1263. *   when it has completed processing the IORB.           *
  1264. *                                                        *
  1265. *   Input :                                              *
  1266. *         fpIORB - A far pointer to the IORB that has    *
  1267. *            just been completed                         *
  1268. *                                                        *
  1269. *   Output :                                             *
  1270. *                                                        *
  1271. *********************************************************/
  1272. VOID FAR _loadds NotifyIORBDone(PIORB fpIORB)                        /*@V61779*/
  1273.  
  1274.    {
  1275.    PASPI_SRB_EXECUTE_IO pSRBIO;
  1276.    NPSRB_LINK npSRBLink;
  1277.    PIORB_DMWORK pWorkSpace;
  1278.    NPATE npATE;
  1279.  
  1280.    /* Restore DS and pointer to current ATE */
  1281.    pWorkSpace = (PIORB_DMWORK) fpIORB->DMWorkSpace;
  1282.    npATE = pWorkSpace->npATE;
  1283.  
  1284.    npSRBLink = (NPSRB_LINK) OFFSETOF(fpIORB);
  1285.    ((NPBYTE) npSRBLink) -= ((NPBYTE)&npSRBLink->IORB - (NPBYTE)npSRBLink);
  1286.  
  1287.    pSRBIO = (PASPI_SRB_EXECUTE_IO) MAKEP(pWorkSpace->SRBGDTSelector,0);
  1288.  
  1289.    /* Immediately verify that this request does not belong to VDM */
  1290.    /* that no longer exists. */
  1291.    if ((pWorkSpace->virtualASPI & VDM_DESTROY_EVENT) != 0)
  1292.       {
  1293.       /* Deallocate the target if we are sharing it with another device */
  1294.       /* manager and we allocated it for our request. This will impact */
  1295.       /* performance slightly when /SHARE is used, but it is necessary to */
  1296.       /* avoid leaving a device unaccessible to another manager. */
  1297.       if ((npATE->Flags & ATEF_SHARE_ALLOCATION) &&
  1298.           ((pSRBIO->SRBHdr.CommandCode == ASPI_CMD_EXECUTE_IO) ||
  1299.            (pSRBIO->SRBHdr.CommandCode == ASPI_CMD_RESET_DEVICE)))
  1300.          SendUnitControlCommand(npATE,
  1301.                                 IOCM_DEALLOCATE_UNIT);
  1302.  
  1303.       /* The command now being handled is either a VDM request or an abort */
  1304.       /* of a VDM request. The former was posted to the VDD before sending */
  1305.       /* the latter. The latter is actually a standard OS/2 request and */
  1306.       /* does not need to be posted. However, the OS/2 request does need */
  1307.       /* to be marked complete. */
  1308.  
  1309.       /* Create error the error status for the OS/2 request */
  1310.       if ((pWorkSpace->virtualASPI & VDM_REQUEST) == 0)
  1311.          ConvertIORBError((PIORBH) fpIORB,
  1312.                            pSRBIO);
  1313.  
  1314.       /* Clean up the queues and get out!! */
  1315.       DeleteSRBActiveQueue(npATE,
  1316.                            npSRBLink);
  1317.       FreeIORB(npSRBLink);
  1318.       }
  1319.    else
  1320.       {
  1321.       /* Create error messages for ASPI from the IORB errors */
  1322.       ConvertIORBError((PIORBH) fpIORB,
  1323.                        pSRBIO);
  1324.  
  1325.       /* Update data transfer length if residual byte count was requested *//*@V53040*/
  1326.       if (pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_RESIDUAL)              /*@V53040*/
  1327.          {
  1328.          /* We must ALWAYS return the residual byte count reported because */
  1329.          /* certain host adapters only detect OVERRUNs.                    *//*@V53040*/
  1330.          pSRBIO->DataXferLen =
  1331.             ((PSCSI_STATUS_BLOCK)((PIORBH) fpIORB->pStatusBlock))->ResidualLength;
  1332.          }
  1333.  
  1334.       /* Deallocate the target if we are sharing it with another device */
  1335.       /* manager and we allocated it for our request. This will impact */
  1336.       /* performance slightly when /SHARE is used, but it is necessary to */
  1337.       /* avoid leaving a device unaccessible to another manager. */
  1338.       if ((npATE->Flags & ATEF_SHARE_ALLOCATION) &&
  1339.           ((pSRBIO->SRBHdr.CommandCode == ASPI_CMD_EXECUTE_IO) ||
  1340.            (pSRBIO->SRBHdr.CommandCode == ASPI_CMD_RESET_DEVICE)))
  1341.          SendUnitControlCommand(npATE,
  1342.                                 IOCM_DEALLOCATE_UNIT);
  1343.  
  1344.       /* Submit the next linked SRB (if necessary) */
  1345.       if (pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_LINKED_SRB)
  1346.          SRBToIORBPassThru(npATE,                                       /*@V61092*/
  1347.                            (PASPI_SRB_EXECUTE_IO) pSRBIO->ppNxtSRB,
  1348.                            0,
  1349.                            pWorkSpace->virtualASPI);
  1350.  
  1351.       /* Call the ASPI posting routine (if necessary) */
  1352.       if (pWorkSpace->virtualASPI & VDM_REQUEST)
  1353.             CallVirtPostRoutine(npSRBLink->OrigSRBPtr);
  1354.       else
  1355.          if (pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_POST_ENABLE)
  1356.             CallPostRoutine(pSRBIO);                                    /*@V61092*/
  1357.  
  1358.       /* Remove the SRB_LINK from the active queue of the ATE */
  1359.       /* and place it back in the list of free IORB           */
  1360.       DeleteSRBActiveQueue(npATE,
  1361.                            npSRBLink);
  1362.       FreeIORB(npSRBLink);
  1363.       }
  1364.    }
  1365. #pragma optimize("cegl",on)         /* Enable optimization switches again */
  1366.  
  1367. /******************************************************
  1368. *                                                     *
  1369. *   Procedure Name : ConvertIORBError                 *
  1370. *                                                     *
  1371. *   Description : This procedure converts any error   *
  1372. *   returned in the IORB to an ASPI error code and    *
  1373. *   inserts it in the SRB.                            *
  1374. *                                                     *
  1375. *   Input :                                           *
  1376. *         pIORB - A pointer to the IORB that has just *
  1377. *            been completed                           *
  1378. *         pSRBIO - A pointer to the SRB that owns the *
  1379. *            IORB that was just completed             *
  1380. *                                                     *
  1381. *   Output :                                          *
  1382. *                                                     *
  1383. ******************************************************/
  1384. VOID ConvertIORBError(PIORBH pIORBH,PASPI_SRB_EXECUTE_IO pSRBIO)
  1385.  
  1386.    {
  1387.    /* Was there an error detected by the ADD? */
  1388.    if (pIORBH->Status & IORB_ERROR)
  1389.       {
  1390.       /* What is the general error condition? */
  1391.       switch (pIORBH->ErrorCode)
  1392.          {
  1393.          case IOERR_CMD_ABORTED :
  1394.             pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_ABORTED;
  1395.             break;
  1396.  
  1397.          case IOERR_CMD_NOT_SUPPORTED :
  1398.             pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_INVALID_COMMAND;
  1399.             break;
  1400.  
  1401.          default :
  1402.             pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_ERROR;
  1403.          }
  1404.  
  1405.  
  1406.       /* Does the SRB support adapter status and target status? */
  1407.       if (pSRBIO->SRBHdr.CommandCode == ASPI_CMD_EXECUTE_IO)
  1408.          {
  1409.          /* Did the host adapter detect an error? */
  1410.          switch (pIORBH->ErrorCode)
  1411.             {
  1412.             case IOERR_ADAPTER_TIMEOUT:
  1413.             case IOERR_ADAPTER_DEVICE_TIMEOUT:
  1414.                pSRBIO->HostStatus = ASPI_HSTATUS_SELECTION_TIMEOUT;
  1415.                break;
  1416.             case IOERR_ADAPTER_OVERRUN:
  1417.             case IOERR_ADAPTER_UNDERRUN:
  1418.             case IOERR_DEVICE_OVERRUN:
  1419.             case IOERR_DEVICE_UNDERRUN:
  1420.                pSRBIO->HostStatus = ASPI_HSTATUS_DATA_OVERRUN;
  1421.                break;
  1422.             case IOERR_ADAPTER_HOSTBUSCHECK:
  1423.             case IOERR_ADAPTER_DEVICEBUSCHECK:
  1424.                pSRBIO->HostStatus = ASPI_HSTATUS_BUS_PHASE_ERROR;
  1425.                break;
  1426.             case IOERR_CMD_SGLIST_BAD:                                  /*@V53040*/
  1427.                pSRBIO->HostStatus = ASPI_HSTATUS_BAD_SGLIST;            /*@V53040*/
  1428.                break;                                                   /*@V53040*/
  1429.             default:
  1430.  
  1431.                /* If residual byte count was requested in the SRB we must */
  1432.                /* make sure that an underrun is reported when there is    */
  1433.                /* a valid residual byte count in the status block         */
  1434.                if ((pSRBIO->SRBHdr.ASPIReqFlags & ASPI_REQFLAG_RESIDUAL) &&
  1435.                    (((PSCSI_STATUS_BLOCK) (pIORBH->pStatusBlock))->Flags &
  1436.                      STATUS_RESIDUAL_VALID) &&
  1437.                    (((PSCSI_STATUS_BLOCK) (pIORBH->pStatusBlock))->ResidualLength))
  1438.                   pSRBIO->HostStatus = ASPI_HSTATUS_DATA_OVERRUN;
  1439.                else
  1440.                   pSRBIO->HostStatus = ASPI_HSTATUS_NO_ERROR;
  1441.             }
  1442.  
  1443.          /* Did the target detect an error? */
  1444.          switch (pIORBH->ErrorCode)
  1445.             {
  1446.             case IOERR_DEVICE_BUSY:
  1447.                pSRBIO->TargetStatus = ASPI_TSTATUS_BUSY;
  1448.                break;
  1449.             case IOERR_UNIT_NOT_ALLOCATED:
  1450.                pSRBIO->TargetStatus = ASPI_TSTATUS_RESERV_CONFLICT;
  1451.                break;
  1452.             default:
  1453.  
  1454.                /* If there was sense data returned then record check condition */
  1455.                if (((PSCSI_STATUS_BLOCK) (pIORBH->pStatusBlock))->Flags &
  1456.                     STATUS_SENSEDATA_VALID)
  1457.                   pSRBIO->TargetStatus = ASPI_TSTATUS_CHECK_CONDITION;
  1458.                else
  1459.                   pSRBIO->TargetStatus = ASPI_TSTATUS_NO_ERROR;
  1460.  
  1461.             }
  1462.          }
  1463.       }
  1464.    else
  1465.       {
  1466.       /* There was no error detected */
  1467.       pSRBIO->SRBHdr.ASPIStatus = ASPI_STATUS_NO_ERROR;
  1468.  
  1469.       /* Does the SRB support adapter status and target status? */
  1470.       if (pSRBIO->SRBHdr.CommandCode == ASPI_CMD_EXECUTE_IO)
  1471.          {
  1472.          pSRBIO->TargetStatus = ASPI_TSTATUS_NO_ERROR;
  1473.          pSRBIO->HostStatus = ASPI_HSTATUS_NO_ERROR;
  1474.          }
  1475.       }
  1476.    }
  1477.  
  1478. #pragma optimize("cegl",off)        /* Disable optimization switches that    */
  1479.                                     /* are illegal for routines that contain */
  1480.                                     /* inline assembly code                  */
  1481.  
  1482. /*********************************************************
  1483. *                                                        *
  1484. *   Function Name : CallPostRoutine                      *
  1485. *                                                        *
  1486. *   Description : This function calls the post routine   *
  1487. *   of the driver whose request has just completed.      *
  1488. *                                                        *
  1489. *   Input :                                              *
  1490. *         pSRBIO - A pointer to the SRB for I/O          *
  1491. *                                                        *
  1492. *   Output :                                             *
  1493. *                                                        *
  1494. *********************************************************/
  1495. VOID CallPostRoutine(PASPI_SRB_EXECUTE_IO pSRBIO)
  1496.  
  1497.    {
  1498.    /* Save the data segment since posting will trash it */
  1499.  
  1500.    _asm push ds
  1501.    _asm push es
  1502.    _asm push si
  1503.    _asm push di
  1504.    (*pSRBIO->PM_PostAddress)(pSRBIO->PM_DataSeg,
  1505.                              (PASPI_SRB_HEADER) pSRBIO->ppSRB);
  1506.    _asm pop di
  1507.    _asm pop si
  1508.    _asm pop es
  1509.    _asm pop ds
  1510.    }
  1511.  
  1512. /*********************************************************
  1513. *                                                        *
  1514. *   Function Name : SendUnitControlCommand               *
  1515. *                                                        *
  1516. *   Description : This function reserves/frees the       *
  1517. *   current target by issuing the appropriate IORB       *
  1518. *                                                        *
  1519. *   Input :                                              *
  1520. *         npATE - A pointer to the targets's ATE         *
  1521. *         unitControlCommand - The command to send       *
  1522. *                                                        *
  1523. *   Output :   This function returns 0 if the command was*
  1524. *   successfully sent and a positive integer if an       *
  1525. *   error was detected.                                  *
  1526. *                                                        *
  1527. *********************************************************/
  1528. USHORT SendUnitControlCommand(NPATE npATE,USHORT unitControlCommand)
  1529.  
  1530.    {
  1531.    USHORT resultCode;
  1532.    NPIORB_UNIT_CONTROL npIORBUnitControl = (NPIORB_UNIT_CONTROL) npATE->UnitControlIORB; /*@V64399*/
  1533.    PIORB_DMWORK pDMWork = (PIORB_DMWORK) (npIORBUnitControl->iorbh.DMWorkSpace);         /*@V64399*/
  1534.  
  1535.    memset((PBYTE) npIORBUnitControl,
  1536.           0,
  1537.           sizeof(IORB_UNIT_CONTROL));
  1538.    npIORBUnitControl->iorbh.Length          = sizeof(IORB_UNIT_CONTROL);
  1539.    npIORBUnitControl->iorbh.UnitHandle      = npATE->UnitHandle;
  1540.    npIORBUnitControl->iorbh.CommandCode     = IOCC_UNIT_CONTROL;
  1541.    npIORBUnitControl->iorbh.CommandModifier = unitControlCommand;
  1542.    npIORBUnitControl->iorbh.Status          = 0;
  1543.    npIORBUnitControl->iorbh.ErrorCode       = 0;
  1544.    npIORBUnitControl->Flags                 = 0;
  1545.    npIORBUnitControl->iorbh.NotifyAddress = &AllocationPost;         /*@V64399*/
  1546.                                                                      /*@V64399*/
  1547.    /* Save a pointer to the current ATE */                           /*@V64399*/
  1548.    pDMWork->npATE = npATE;                                           /*@V64399*/
  1549.  
  1550.    resultCode = SendIORBandWait((NPIORB) npIORBUnitControl,
  1551.                                 npATE->TargetADD_Entry);
  1552.  
  1553.    return(resultCode);
  1554.    }
  1555.  
  1556. /*********************************************************
  1557. *                                                        *
  1558. *   Procedure Name : InsertSRBActiveQueue                *
  1559. *                                                        *
  1560. *   Description : This procedure places the SRB link     *
  1561. *   at the front of the queue of active IORBs that       *
  1562. *   belong to the current ATE.                           *
  1563. *                                                        *
  1564. *   Input :                                              *
  1565. *         npATE - A pointer to the current ATE           *
  1566. *         npSRBLink - A pointer to the new SRB link      *
  1567. *         pSRB - A pointer to the current SRB            *
  1568. *                                                        *
  1569. *   Output :                                             *
  1570. *                                                        *
  1571. *********************************************************/
  1572. VOID InsertSRBActiveQueue(NPATE npATE,NPSRB_LINK npSRBLink,PASPI_SRB_HEADER pSRBH)
  1573.  
  1574.    {
  1575.    /* Place the new SRB at the front of the queue */
  1576.    DISABLE
  1577.  
  1578.    npSRBLink->pSRB = pSRBH;
  1579.    npATE->SRBActiveQueueCount++;
  1580.    npSRBLink->npNextSRBLink = npATE->npSRBActiveQueue;
  1581.    npATE->npSRBActiveQueue = npSRBLink;
  1582.    ENABLE
  1583.    }
  1584.  
  1585. /*********************************************************
  1586. *                                                        *
  1587. *   Procedure Name : DeleteSRBActiveQueue                *
  1588. *                                                        *
  1589. *   Description : This procedure deletes the SRB link    *
  1590. *   for the IORB that has just been completed from the   *
  1591. *   active queue of its ATE.                             *
  1592. *                                                        *
  1593. *   Input :                                              *
  1594. *         npATE - A pointer to the current ATE           *
  1595. *         npSRBLink - A pointer to the SRB link that     *
  1596. *            has just been completed                     *
  1597. *                                                        *
  1598. *   Output :                                             *
  1599. *                                                        *
  1600. *********************************************************/
  1601. VOID DeleteSRBActiveQueue(NPATE npATE,NPSRB_LINK npSRBLink)
  1602.  
  1603.    {
  1604.    USHORT SRBCount = 0;
  1605.    NPSRB_LINK currentSRBLink;
  1606.    NPSRB_LINK previousSRBLink;
  1607.  
  1608.    /* Start at the front of the queue */
  1609.    currentSRBLink = previousSRBLink = npATE->npSRBActiveQueue;
  1610.  
  1611.    DISABLE
  1612.    while (SRBCount < npATE->SRBActiveQueueCount)
  1613.       {
  1614.       /* Is this the correct queue element to delete? */
  1615.       if (currentSRBLink->pSRB == npSRBLink->pSRB)
  1616.          {
  1617.          /* If this is the only element on the queue, then */        /*@V61092*/
  1618.          /* clear the whole queue.                         */        /*@V61092*/
  1619.          if ((!SRBCount) &&                                          /*@V61092*/
  1620.              (!previousSRBLink->npNextSRBLink))                      /*@V61092*/
  1621.             npATE->npSRBActiveQueue = 0;                             /*@V61092*/
  1622.          else                                                        /*@V61092*/
  1623.             previousSRBLink->npNextSRBLink = currentSRBLink->npNextSRBLink;
  1624.          break;
  1625.          }
  1626.       else
  1627.          {
  1628.          /* No match yet, so try the next element in the queue */
  1629.          previousSRBLink = currentSRBLink;
  1630.          currentSRBLink = currentSRBLink->npNextSRBLink;
  1631.          SRBCount++;
  1632.          }
  1633.       }
  1634.    npATE->SRBActiveQueueCount--;
  1635.  
  1636.    ENABLE
  1637.    }
  1638.  
  1639. #pragma optimize("cegl",on)         /* Enable optimization switches again */
  1640.  
  1641. /*********************************************************
  1642. *                                                        *
  1643. *   Procedure Name : AllocationPost                      *
  1644. *                                                        *
  1645. *   Description : This procedure is called by the ADD    *
  1646. *   whenever an allocation or deallocation request has   *
  1647. *   completed.                                           *
  1648. *                                                        *
  1649. *   Input :                                              *
  1650. *         pIORB - A far pointer to the IORB that has     *
  1651. *            just been completed                         *
  1652. *                                                        *
  1653. *   Output :                                             *
  1654. *                                                        *
  1655. *********************************************************/
  1656. VOID FAR _loadds AllocationPost(PIORB pIORB)                         /*@V64399*/
  1657.                                                                      /*@V64399*/
  1658.    {                                                                 /*@V64399*/
  1659.    NPATE npATE;                                                      /*@V64399*/
  1660.    PIORB_DMWORK pDMWork;                                             /*@V64399*/
  1661.                                                                      /*@V64399*/
  1662.    /* If the command completed successfully update our structures. *//*@V64399*/
  1663.    if (((PIORB_UNIT_CONTROL) pIORB)->iorbh.Status == IORB_DONE)      /*@V64399*/
  1664.       {                                                              /*@V64399*/
  1665.       /* Get a pointer to the appropriate ATE */                     /*@V64399*/
  1666.       pDMWork = (PIORB_DMWORK) &(((PIORB_UNIT_CONTROL) pIORB)->iorbh.DMWorkSpace);/*@V64399*/
  1667.       npATE = pDMWork->npATE;                                        /*@V64399*/
  1668.                                                                      /*@V64399*/
  1669.       /* If we are doing an allocate or deallocate we must set the *//*@V64399*/
  1670.       /* appropriate bits in the ATE, when the request finishes.   *//*@V64399*/
  1671.       if (pIORB->CommandCode == IOCC_UNIT_CONTROL)                   /*@V64399*/
  1672.          switch (pIORB->CommandModifier)                             /*@V64399*/
  1673.             {                                                        /*@V64399*/
  1674.             case IOCM_ALLOCATE_UNIT:                                 /*@V64399*/
  1675.                npATE->Flags |= ATEF_ASPI_ALLOCATED;
  1676.                break;                                                /*@V64399*/
  1677.                                                                      /*@V64399*/
  1678.             case IOCM_DEALLOCATE_UNIT:                               /*@V64399*/
  1679.                npATE->Flags &= ~ATEF_ASPI_ALLOCATED;
  1680.                break;                                                /*@V64399*/
  1681.             }                                                        /*@V64399*/
  1682.       }                                                              /*@V64399*/
  1683.    }                                                                 /*@V64399*/
  1684.  
  1685.