/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/vdev/vaspi/vaevent.c, vaspi, r207 94/08/15";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = VAEVENT.C
 *
 * DESCRIPTIVE NAME = VASPI.SYS - OS/2 Virtual ASPI Device Driver
 *
 *
 *
 * VERSION = V1.0
 *
 * DATE
 *
 * DESCRIPTION : Entry point in VDD for PDD to call
 *
 *      VASPI is organized as follows:
 *         VAINIT.C    - Init routine
 *         VAUSER.C    - UserHooks for VDM Creation, VDMTermination
 *         VADATA.C    - Data
 *         VAEVENT.C   - Entry point in VDD for PDD to call
 *         VAMEM.C     - Memory and queue management routines
 *         VAROUTER.C  - ASPI Router and DOS Link routines
 *
 *         VASPI.H     - Defines, etc
 *         VASPIX.H    - External data definitions
 *         VASPIP.H    - Function profile definitions
 *         VASPIMAC.H  - Macros
 *
 *
*/#include <mvdm.h>
#include <scsi.h>
#include <aspi.h>


#include "vaspi.h"
#include "vaspix.h"
#include "vaspip.h"
#include "vaspimac.h"

#define F_VM            0x00020000      // (V)irtual 8086 (M)ode
#define F_INTERRUPT     0x00000200

#pragma BEGIN_GLOBAL_CODE

/********************** START OF SPECIFICATIONS **********
*                                                        *
* SUBROUTINE NAME:  VASPIEventProc                       *
*                                                        *
* DESCRIPTIVE NAME:  VASPI entry point for PDD           *
*                                                        *
* FUNCTION:  This subroutine is registered by the VDD    *
*            during VDD initialization via VDHOpenPDD and*
*            is called by the PDD to provide notification*
*            of various events.                          *
*                                                        *
* CONTEXT: PDD task time and PDD interrupt time          *
*                                                        *
* ENTRY POINT:  VASPIEventProc                           *
*    LINKAGE:  CALL NEAR 32                              *
*                                                        *
* INPUT:                                                 *
*          ulFunc - request function                     *
*          pSRB  - virtual pSRB                          *
*          f16p2  - unused                               *
*                                                        *
* EXIT-NORMAL: return TRUE                               *
*                                                        *
* EXIT-ERROR: return FALSE - invalid request function    *
*                                                        *
* EFFECTS:  NONE                                         *
*                                                        *
* INTERNAL REFERENCES:  NONE                             *
*                                                        *
* EXTERNAL REFERENCES:  NONE                             *
*                                                        *
****************** END OF SPECIFICATIONS ****************/
SBOOL VDDENTRY VASPIEventProc( ULONG ulFunc, F16PVOID pSRB, F16PVOID f16p2)

   {
   NPVSRB_LINK         pSRBL, *pHookData;
   PASPI_SRB_HEADER    pOS2SRB, pDosSRB;


   WORDOF(pSRB,0) = 0;
   pSRBL = (NPVSRB_LINK) VDHQueryLin(pSRB);

   /* Defer request handling until task time. */
   if (pSRBL->hkVDMContext)
      {
      /* If the VDM has been destroyed, clean up now without */
      /* waiting for a context switch (which will never occur). */
      /* Since OS2ASPI is faking out the VDM, this code should */
      /* never be executed at interrupt time. */
      if (pSRBL->Flags & LF_VDM_DESTROYED)
         {
         /* Release the context hook associated with the SRB */
         VDHFreeHook(pSRBL->hkVDMContext);

         /* Release the lock on the data buffer */
         if (pSRBL->hDataLock)
            VDHUnlockMem(pSRBL->hDataLock);

         /* Release the selector:offset passed to OS2ASPI.DMD */
         VDHDestroySel((SEL)SEGMENTOF16(pSRBL->pSRBL16));

         /* Remove the SRBL from the active list */
         RemoveActiveSRB(pSRBL);

         /* Release the SRB buffer */
         ReleaseBuf(pSRBL,
                    pSRBL->AllocBytes);

         return TRUE;
         }
      else
         {
         VDHArmContextHook(pSRBL->hkVDMContext,
                           pSRBL->hHVDM);

         pHookData = (NPVSRB_LINK *) VDHQueryHookData(pSRBL->hkVDMContext);
         *pHookData = pSRBL;

         return TRUE;
         }
      }
   /**
    ** At this point we know we are handling a simple request and
    ** do NOT have to worry about running at INTERRUPT time
    **/

   pOS2SRB  = pSRBL->pOS2SRB;
   pDosSRB  = pSRBL->pDosSRB;

   if (pOS2SRB->CommandCode == ASPI_CMD_ADAPTER_INQUIRY)
      memcpy(pDosSRB,
             pOS2SRB,
             sizeof(ASPI_SRB_INQUIRY));
   else
      if (pOS2SRB->CommandCode == ASPI_CMD_GET_DEVICE_TYPE)
         memcpy(pDosSRB,
                pOS2SRB,
                sizeof(ASPI_SRB_DEVICE_TYPE));

   /* Release the selector:offset passed to OS2ASPI.DMD */
   VDHDestroySel((SEL)SEGMENTOF16(pSRBL->pSRBL16));

   /* Remove the SRBL from the active list */
   RemoveActiveSRB(pSRBL);

   /* Release the SRB buffer */
   ReleaseBuf(pSRBL,
              pSRBL->AllocBytes);

   return TRUE;
   }

#pragma END_GLOBAL_CODE

#pragma BEGIN_SWAP_CODE

/********************** START OF SPECIFICATIONS **********
*                                                        *
* SUBROUTINE NAME:  ASPIContextRoutine                   *
*                                                        *
* DESCRIPTIVE NAME:  VASPI routine called at TASK time   *
*                                                        *
* FUNCTION:  This subroutine is called after the VDD     *
*            has been notified that an SRB completed     *
*            and the context of the VDM is task.         *
*                                                        *
* CONTEXT: VDD task time                                 *
*                                                        *
* ENTRY POINT:  VASPIEventProc                           *
*    LINKAGE:  CALL NEAR 32                              *
*                                                        *
* INPUT:                                                 *
*         pHookData - pointer to the hook data area      *
*         pcrf - pointer to the VDM register frame       *
*                                                        *
* EXIT-NORMAL: return TRUE                               *
*                                                        *
* EXIT-ERROR: return FALSE - invalid request function    *
*                                                        *
* EFFECTS:  NONE                                         *
*                                                        *
* INTERNAL REFERENCES:  NONE                             *
*                                                        *
* EXTERNAL REFERENCES:  NONE                             *
*                                                        *
****************** END OF SPECIFICATIONS ****************/
BOOL HOOKENTRY ASPIContextRoutine(PVOID pHookData, PCRF pcrf)

   {
   HHOOK          hSTIHook;
   NPVSRB_LINK    pSRBL;
   PVOID          pSTIHData;


   pSRBL = *(NPVSRB_LINK *) pHookData;

   /* Release the VDM Context hook */
   VDHFreeHook(pSRBL->hkVDMContext);

   pSRBL->hkVDMContext = 0;

   hSTIHook = VDHAllocHook((ULONG)  VDH_STI_HOOK,
                           (PFNARM) ASPIPostRoutine,
                           (ULONG)  2*sizeof(PVOID));

   pSTIHData = (PVOID) VDHQueryHookData(hSTIHook);
   ((PULONG) pSTIHData)[0] = (ULONG) hSTIHook;
   ((PULONG) pSTIHData)[1] = (ULONG) pSRBL;

   VDHArmSTIHook((HHOOK) hSTIHook,
                 (HVDM) sessionHandle);

   return TRUE;
   }


/********************** START OF SPECIFICATIONS **********
*                                                        *
* SUBROUTINE NAME:  ASPIPostRoutine                      *
*                                                        *
* DESCRIPTIVE NAME:  VASPI routine called at TASK time   *
*                                                        *
* FUNCTION:  This subroutine is called after the VDD     *
*            has been notified that an SRB completed     *
*            and the context of the VDM is task.         *
*                                                        *
* CONTEXT: VDD task time                                 *
*                                                        *
* ENTRY POINT:  VASPIEventProc                           *
*    LINKAGE:  CALL NEAR 32                              *
*                                                        *
* INPUT:                                                 *
*         pHookData - pointer to the hook data area      *
*         pcrf - pointer to the VDM register frame       *
*                                                        *
* EXIT-NORMAL: return TRUE                               *
*                                                        *
* EXIT-ERROR: return FALSE - invalid request function    *
*                                                        *
* EFFECTS:  NONE                                         *
*                                                        *
* INTERNAL REFERENCES:  NONE                             *
*                                                        *
* EXTERNAL REFERENCES:  NONE                             *
*                                                        *
****************** END OF SPECIFICATIONS ****************/
BOOL HOOKENTRY ASPIPostRoutine(PVOID pHookData, PCRF pcrf)

   {
   NPVSRB_LINK    pSRBL;

   PCRF     pHookcrf;
   PUCHAR   pHookSRBInfo;

   HHOOK    hhookASPIPostReturn;
   PULONG   pHookRData;

   UCHAR    SRBFlags;
   UCHAR    SRBAdapter;
   UCHAR    SRBTarget;
   UCHAR    SRBLun;
   PVOID    pSRBPostRoutine;

   PASPI_SRB_EXECUTE_IO   pOS2SRB;
   PDASPI_SRB_EXECUTE_IO  pDosSRB;

   PBYTE    pOS2Sense, pDosSense;

   ULONG    V86SRBPtr;

   FPFN     pSRBPost32 = 0;

   USHORT   LinkFlag;

   PWAITQ_HEAD pDeviceWaitQ;

   pSRBL  = ((NPVSRB_LINK *) pHookData)[1];

   (PASPI_SRB_HEADER) pOS2SRB = pSRBL->pOS2SRB;
   (PASPI_SRB_HEADER) pDosSRB = pSRBL->pDosSRB;

   LinkFlag = pSRBL->Flags;

   /* Release the VDM Context hook */
   VDHFreeHook(((PHHOOK) pHookData)[0]);

   /* Record the state of the ASPI request flags so that they can */
   /* be accessed AFTER the SRB has been released */
   SRBFlags = pOS2SRB->SRBHdr.ASPIReqFlags;

   /* Save the adapter and target information for post return recovery */
   SRBAdapter = pDosSRB->SRBHdr.AdapterIndex;
   SRBTarget = pDosSRB->DeviceTargetID;
   SRBLun = pDosSRB->DeviceTargetLUN;

   /* Update all the status fields in the DOS SRB */
   pDosSRB->HostStatus        = pOS2SRB->HostStatus;
   pDosSRB->TargetStatus      = pOS2SRB->TargetStatus;
   pDosSRB->SRBHdr.ASPIStatus = pOS2SRB->SRBHdr.ASPIStatus;


   /* Update the sense data in the DOS SRB */
   if (pOS2SRB->SRBHdr.ASPIStatus != ASPI_STATUS_NO_ERROR)
      {
      pDosSense = pDosSRB->SCSICDBStart + pDosSRB->SCSICDBLen;
      pOS2Sense = pOS2SRB->SCSICDBStart + pOS2SRB->SCSICDBLen;
      memcpy(pDosSense,
             pOS2Sense,
             pOS2SRB->SenseDataLen);
      }

   pSRBPostRoutine = (PVOID) pDosSRB->RM_PostAddress;
   V86SRBPtr       = pSRBL->V86SRBPtr;

   /* Release the lock on the data buffer */
   if (pSRBL->hDataLock)
      {
      VDHUnlockMem(pSRBL->hDataLock);
      pSRBL->hDataLock = 0;
      }

   /* Release the selector:offset passed to OS2ASPI.DMD */
   VDHDestroySel((SEL)SEGMENTOF16(pSRBL->pSRBL16));

   /* Remove the SRBL from the active list */
   RemoveActiveSRB(pSRBL);

   /* Release the SRB buffer */
   ReleaseBuf(pSRBL,
              pSRBL->AllocBytes);

   /* Post the command if necessary */
   if (SRBFlags & ASPI_REQFLAG_POST_ENABLE)
      {
      /* Allocate a hook and save it in the hook data area */
      hhookASPIPostReturn = VDHAllocHook((ULONG)  VDH_RETURN_HOOK,
                                         (PFNARM) ASPIPostReturn,
                                         (ULONG)  3*sizeof(ULONG)+
                                          sizeof(CRF));

      pHookRData = (PULONG) VDHQueryHookData(hhookASPIPostReturn);

      /* Pass the pointer to the post hook */
      pHookRData[0] = (ULONG) hhookASPIPostReturn;

      /* Save the adapter, target and LUN for post recovery */
      pHookSRBInfo = (PUCHAR) &pHookRData[2];
      *pHookSRBInfo = SRBAdapter;
      *(pHookSRBInfo + 1) = SRBTarget;
      *(pHookSRBInfo + 2) = SRBLun;

      /* Save client regs that ASPI Post Routine may corrupt. */
      pHookcrf = (PCRF) &pHookRData[3];
      *pHookcrf = *pcrf;

      /* If the VDM should be in V86 mode but it is in  */
      /* protected mode, switch back to V86 mode. */
      if (!(LinkFlag & LF_VPM_CLIENT) &&
           (flVdmStatus & VDM_STATUS_VPM_EXEC))
         {
         VDHSwitchToV86();
         LinkFlag |= LF_VPM_MODESWITCH;
         }
      else
         /* If the VDM should be in protected mode but it is in */
         /* V86 mode, switch back to protected mode. */
         if ((LinkFlag & LF_VPM_CLIENT) &&
             !(flVdmStatus & VDM_STATUS_VPM_EXEC))
            {
            VDHSwitchToVPM();
            LinkFlag |= LF_VPM_MODESWITCH;
            }

      pHookRData[1] = LinkFlag;

      /* Remember that we are now entering the application's post */
      /* routine. All SRB's received for this target/LUN must be  */
      /* deferred until the application exits the post routine.   */
      pDeviceWaitQ = GetDeviceWaitQueuePtr(SRBAdapter,
                                           SRBTarget,
                                           SRBLun);

      pDeviceWaitQ->PostRoutineActive = TRUE;

      /* Set up to call the return routine when posting completes */
      VDHArmReturnHook(hhookASPIPostReturn,
                       VDHARH_CSEIP_HOOK);

      /* Place the SRB pointer on the user's stack */
      VDHPushStack(sizeof(PASPI_SRB_EXECUTE_IO),
                   SSToDS(&V86SRBPtr));

      /* Place the post routine address on the user's stack */
      OFFSETOF32(pSRBPost32)  = OFFSETOF16(pSRBPostRoutine);
      SEGMENTOF32(pSRBPost32) = SEGMENTOF16(pSRBPostRoutine);
      VDHPushFarCall(pSRBPost32);

      pcrf->crf_eflag &= ~F_INTERRUPT;

      VDHSetFlags(pcrf->crf_eflag);
      }

   return TRUE;
   }

/*********************************************************
*                                                        *
*   Procedure Name : ASPIPostReturn                      *
*                                                        *
*   Description : This procedure cleans up any remaining *
*   data structures after the post routine within the    *
*   ASPI application has completed.                      *
*                                                        *
*   Input :                                              *
*                                                        *
*         pHookData - pointer to the hook data area      *
*         pcrf - pointer to the VDM register frame       *
*                                                        *
*   Output :                                             *
*                                                        *
*********************************************************/
BOOL HOOKENTRY ASPIPostReturn(PVOID pHookData, PCRF pcrf)

   {
   UCHAR       SRBScratchArea[4];
   PCRF        pHookcrf;
   PUCHAR      pHookSRBInfo;
   USHORT      LinkFlag;

   NPVSRB_LINK pSRBL;
   UCHAR       SRBAdapter;
   UCHAR       SRBTarget;
   UCHAR       SRBLun;
   PWAITQ_HEAD pDeviceWaitQ;

   /* Extract all status information from the hook data area */
   LinkFlag = (USHORT) ((PULONG) pHookData)[1];

   /**
    ** DOS ASPI uses C-calling conventions requiring the
    ** caller to clean-up.
    **
    ** In this case, we were the caller of the Client's
    ** Post Routine.
    **/
   if (!(LinkFlag & LF_VPM_CLIENT))
      VDHPopStack((ULONG) sizeof(PASPI_SRB_EXECUTE_IO),
                  (PVOID) SSToDS(SRBScratchArea));

   /* Restore the correct mode to the VDM */
   if (LinkFlag & LF_VPM_MODESWITCH)
      if (flVdmStatus & VDM_STATUS_VPM_EXEC)
         VDHSwitchToV86();
      else
         VDHSwitchToVPM();

   pHookSRBInfo = (PUCHAR) (((PULONG)pHookData)+2);
   SRBAdapter = *pHookSRBInfo;
   SRBTarget = *(pHookSRBInfo + 1);
   SRBLun = *(pHookSRBInfo + 2);

   pHookcrf = (PCRF)(((PULONG)pHookData)+3);
   *pcrf = *pHookcrf;
   VDHSetFlags(pcrf->crf_eflag);

   VDHFreeHook(*(PHHOOK) pHookData);

   /* Now that the post has been completed, it is safe to complete */
   /* the SRB that MAY have been issued from it. */

   pDeviceWaitQ = GetDeviceWaitQueuePtr(SRBAdapter,
                                        SRBTarget,
                                        SRBLun);

   /* Clear the flag blocking SRBs from OS2ASPI. */
   pDeviceWaitQ->PostRoutineActive = FALSE;

   pSRBL = GetDeviceWaitQueueSRB(pDeviceWaitQ);

   /* Make sure there is a command waiting and the VDM is alive. */
   if ((pSRBL) &&
       (VDMActive == TRUE))
      {
      QueueActiveSRB(pSRBL);

      /* Let PDD do all of the real work. */
      PDDProc(PDDCMD_SRB_REQUEST,
              (PVOID) VPFROMVADDR(SEGMENTOF16(pSRBL->pSRBL16),
                                  pSRBL->linkOffset),
              (PVOID) NULL);
      }
   }

#pragma END_SWAP_CODE

