/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1992 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 source code is provided to you solely for       */
/*    the purpose of assisting you in your development of OS/2 device        */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Developer Connection Device Driver       */
/*    Source Kit for OS/2. This Copyright statement may not be removed.      */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/dev/dasd/os2dasd/dmiorb.c, dsdm, basedd, initial 93/07/14";*/
#define SCCSID  "src/dev/dasd/os2dasd/dmiorb.c, dsdm, basedd, initial 93/07/14"

/**************************************************************************
 *
 * SOURCE FILE NAME = DMIORB.C
 *
 * DESCRIPTIVE NAME = OS2DASD.DMD - OS/2 DASD Device Manager
 *                    IORB managment routines for OS/2 DASD Manager
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION    Handles allocation, initialization, and freeing of
 *                I/O request blocks (IORBs) used to communicate with
 *                Adapter Device Drivers (ADDs).
 *
 *
 *
*/
#include "dmh.h"
#include "dmfault.h"


/*------------------------------------------------------------------------
;
;** InitCBPool - Initialize the control block pool
;
;   Initializes the control block pool which is used for IORB,
;   CWA and FTDB allocation.
;
;   USHORT InitCBPool ()
;
;   ENTRY:
;
;   RETURN:
;
;   EFFECTS:
;
------------------------------------------------------------------------*/
VOID InitCBPool ()
{
   NPUNITCB pUnitCB;
   NPBYTE   pCB;
   NPIORBH  pIORB;
   USHORT   NumCBs, CBSize, i;
   USHORT   NumIORBs = 0;

   /*--------------------------------*/
   /* Calculate the size of the Pool */
   /*--------------------------------*/

   /* The size of a control block is the max size of an IORB, CWA and FTDB */

   CBSize = MAX_IORB_SIZE;
   if (CBSize < sizeof(CWA))
      CBSize = sizeof(CWA);


   /* Calculate the number of IORBs to allocate by summing the */
   /* Queuing Counts in each UnitCB.                           */

   for (pUnitCB = UnitCB_Head, i = 0; i < NumUnitCBs; i++, pUnitCB++)
   {
     if ( (pUnitCB->UnitInfo.QueuingCount > MAX_QUEUING_COUNT) ||
          (pUnitCB->UnitInfo.QueuingCount == 0) )
        NumIORBs += MAX_QUEUING_COUNT;
     else
        NumIORBs += pUnitCB->UnitInfo.QueuingCount;
   }

   NumCBs = NumIORBs + NUM_DEFAULT_CWAS;   /* add in room for CWAs */

   FreePoolSpace = (USHORT) &InitData - (USHORT) pNextFreeCB;

   /*  Make sure Pool Size isnt greater than available space left in */
   /*  the data segment.                                             */

   if ( ((ULONG)NumCBs * CBSize) < (ULONG)FreePoolSpace)
      PoolSize = NumCBs * CBSize;
   else
   {
      NumCBs = FreePoolSpace / CBSize;
      PoolSize = NumCBs * CBSize;
   }

   /*-----------------------------------*/
   /* Initialize the Control Block Pool */
   /*-----------------------------------*/

   CB_FreeList = pNextFreeCB;

   pCB = CB_FreeList;

   for (i = 0; i < NumCBs; i++)
   {

      ((NPIORBH) pCB)->pNxtIORB = (PIORBH) (pCB + CBSize);
      pCB += CBSize;
   }

   ((NPIORBH) (pCB - CBSize))->pNxtIORB = 0;    /* Zero terminate list */

   pNextFreeCB = pCB;


   /*------------------------------------------*/
   /* Allocate one dedicated IORB to each Unit */
   /*------------------------------------------*/

   pCB = CB_FreeList;

   for (pUnitCB = UnitCB_Head, i = 0; i < NumUnitCBs; i++, pUnitCB++)
   {
      pUnitCB->pDedicatedIORB = (NPIORBH) pCB;
      ((NPIORBH) pCB)->pNxtIORB = 0;
      pCB += CBSize;
   }

   CB_FreeList = pCB;            /* Free List now starts past dedicated IORBs */


}



typedef struct _ReqToIORB_CmdEntry
{
   UCHAR  PktCommand;
   UCHAR  PktFunction;
   USHORT IORBCommandCode;
   USHORT IORBCommandModifier;
} ReqToIORB_CmdEntry;

/*------------------------------------------------------------------------
;
;** SetupIORB - Setup an IORB
;
;   Sets ups an IORB from the input Request Packet or Request List Entry
;
;   VOID SetupIORB  (NPUNITCB pUnitCB, PBYTE pReq, pIORB)
;
;   ENTRY:    pUnitCB          - Pointer to UnitCB
;             pReq             - Pointer to Request Packet or Request List Entry
;             pIORB            - Pointer to IORB
;
;   RETURN:
;
;   EFFECTS:
;
------------------------------------------------------------------------*/
typedef NPIORB_EXECUTEIO NPXIO;
typedef NPIORB_FORMAT    NPFIO;

VOID   SetupIORB (pUnitCB, pReqIn, pIORB)

NPUNITCB pUnitCB;
PBYTE    pReqIn;
NPIORBH  pIORB;

{

static ReqToIORB_CmdEntry ReqToIORB_CmdTable[] = {

{PB_REQ_LIST, PB_READ_X,     IOCC_EXECUTE_IO, IOCM_READ},
{PB_REQ_LIST, PB_WRITE_X,    IOCC_EXECUTE_IO, IOCM_WRITE},

{CMDINPUT,         0,        IOCC_EXECUTE_IO, IOCM_READ},                                               /*@RAWIO*/
{CMDOUTPUT,        0,        IOCC_EXECUTE_IO, IOCM_WRITE},                                              /*@RAWIO*/

{PB_REQ_LIST, PB_WRITEV_X,   IOCC_EXECUTE_IO, IOCM_WRITE_VERIFY},
{PB_REQ_LIST, PB_PREFETCH_X, IOCC_EXECUTE_IO, IOCM_READ_PREFETCH},

/*@RAWIO {CMDINPUT,         0,        IOCC_EXECUTE_IO, IOCM_READ}, */
/*@RAWIO {CMDOUTPUT,        0,        IOCC_EXECUTE_IO, IOCM_WRITE}, */
{CMDOUTPUTV,       0,        IOCC_EXECUTE_IO, IOCM_WRITE_VERIFY},
{CMDInputBypass,   0,        IOCC_EXECUTE_IO, IOCM_READ},
{CMDOutputBypass,  0,        IOCC_EXECUTE_IO, IOCM_WRITE},
{CMDOutputBypassV, 0,        IOCC_EXECUTE_IO, IOCM_WRITE_VERIFY},

{CMDInternal, DISKOP_READ_VERIFY,        IOCC_EXECUTE_IO, IOCM_READ_VERIFY},
{CMDInternal, DISKOP_FORMAT,             IOCC_FORMAT,     IOCM_FORMAT_TRACK},
{CMDInternal, DISKOP_FORMAT_VERIFY,      IOCC_FORMAT,     IOCM_FORMAT_TRACK},
{CMDInternal, DISKOP_GET_CHANGELINE_STATE, IOCC_UNIT_STATUS, IOCM_GET_CHANGELINE_STATE},
{CMDInternal, DISKOP_GET_MEDIA_SENSE,    IOCC_UNIT_STATUS, IOCM_GET_MEDIA_SENSE},
{CMDInternal, DISKOP_SUSPEND_DEFERRED,   IOCC_DEVICE_CONTROL, IOCM_SUSPEND},
{CMDInternal, DISKOP_RESUME,             IOCC_DEVICE_CONTROL, IOCM_RESUME},
{CMDInternal, DISKOP_GET_MEDIA_GEOMETRY, IOCC_GEOMETRY, IOCM_GET_MEDIA_GEOMETRY},
{CMDInternal, DISKOP_SET_MEDIA_GEOMETRY, IOCC_GEOMETRY, IOCM_SET_MEDIA_GEOMETRY},
{CMDInternal, DISKOP_SET_LOGICAL_GEOMETRY, IOCC_GEOMETRY, IOCM_SET_LOGICAL_GEOMETRY},
{CMDInternal, DISKOP_LOCKMEDIA,          IOCC_DEVICE_CONTROL, IOCM_LOCK_MEDIA},      /*@V51531*/
{CMDInternal, DISKOP_UNLOCKMEDIA,        IOCC_DEVICE_CONTROL, IOCM_UNLOCK_MEDIA},    /*@V51531*/
{CMDInternal, DISKOP_EJECTMEDIA,         IOCC_ADAPTER_PASSTHRU,IOCM_EXECUTE_CDB},     /*@V51531*/
{CMDInternal, DISKOP_EJECTMEDIA1,        IOCC_ADAPTER_PASSTHRU,IOCM_EXECUTE_CDB},     /*@V51531*/
{CMDInternal, DISKOP_STARTUNIT,          IOCC_ADAPTER_PASSTHRU,IOCM_EXECUTE_CDB},     /*@V51531*/
{CMDInternal, DISKOP_PASSTHRU,           IOCC_ADAPTER_PASSTHRU,IOCM_EXECUTE_CDB},     /*@V51531*/
{CMDInternal, DISKOP_PASSTHRU_IN,        IOCC_ADAPTER_PASSTHRU,IOCM_EXECUTE_CDB},     /*@V51531*/
{CMDInternal, DISKOP_PASSTHRU_OUT,       IOCC_ADAPTER_PASSTHRU,IOCM_EXECUTE_CDB},     /*@V51531*/
{CMDInternal, DISKOP_GET_UNIT_STATUS,    IOCC_UNIT_STATUS,    IOCM_GET_UNIT_STATUS}, /*@V51531*/
{CMDInternal, DISKOP_GET_LOCK_STATUS,    IOCC_UNIT_STATUS,    IOCM_GET_LOCK_STATUS}, /*@V51531*/
{CMDInternal, DISKOP_UPDATE_REC_BPB,     IOCC_GEOMETRY, IOCM_GET_MEDIA_GEOMETRY},    /*@V63867*/
{-1}, };                                /* End of Table */


   UCHAR PktCommand, PktFunction;
   USHORT i;
   NPGEOMETRY pGeometry;
   NPFORMAT_CMD_TRACK pFCT;
   NPVOLCB pVolCB;
   NPIORB_DMWORK pDMWork;

   _segment ReqSeg;
   PB_Read_Write _based(ReqSeg)    *pRLE;
   Req_List_Header _based(ReqSeg) *pRLH;
   RP_RWV _based(ReqSeg) *pRP;

   ReqSeg = SELECTOROF(pReqIn);
   (USHORT) pRLE = OFFSETOF(pReqIn);
   (USHORT) pRP = OFFSETOF(pReqIn);

   pDMWork = (NPIORB_DMWORK) &(pIORB->DMWorkSpace);

   /* Setup the IORB header */

   pIORB->UnitHandle = pUnitCB->UnitInfo.UnitHandle;
   pIORB->RequestControl = IORB_ASYNC_POST;
   pIORB->NotifyAddress = NotifyDoneIORB;
   pIORB->Status = 0;
   pIORB->ErrorCode = 0;                                             /*@V58430*/
   pDMWork->pUnitCB = pUnitCB;
   pDMWork->pRequest = (PBYTE) pReqIn;

   /* Determine the IORB CommandCode/CommandModifier and goto the     */
   /* associate command handler to initialize the rest of the IORB.   */

   PktCommand = pRP->rph.Cmd;
   PktFunction = 0;
   if (PktCommand == PB_REQ_LIST)
      PktFunction = pRLE->RqHdr.Command_Code;
   else if (PktCommand == CMDInternal)
      PktFunction = ((PRP_INTERNAL) pRP)->Function;

   for (i = 0; ReqToIORB_CmdTable[i].PktCommand != -1; i++)
   {
      if ( (PktCommand == ReqToIORB_CmdTable[i].PktCommand) &&
           (PktFunction == ReqToIORB_CmdTable[i].PktFunction) )
      {
         pIORB->CommandCode = ReqToIORB_CmdTable[i].IORBCommandCode;
         pIORB->CommandModifier = ReqToIORB_CmdTable[i].IORBCommandModifier;

/*@RAWIO         if ( (DDFlags & DDF_DMAReadBack) &&
  @RAWIO            (pIORB->CommandCode == IOCC_EXECUTE_IO) &&
  @RAWIO            (pIORB->CommandModifier == IOCM_WRITE) &&
  @RAWIO            (pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE) ) */
         if ( (pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE) &&                           /*@RAWIO*/
              (DDFlags & DDF_DMAReadBack) &&                                                                            /*@RAWIO*/
              (pIORB->CommandCode == IOCC_EXECUTE_IO) &&                                                /*@RAWIO*/
              (pIORB->CommandModifier == IOCM_WRITE) )                                          /*@RAWIO*/

                 pIORB->CommandModifier = IOCM_WRITE_VERIFY;

         break;
      }
   }

   switch (pIORB->CommandCode)
   {
      case IOCC_EXECUTE_IO:

         if (PktCommand == PB_REQ_LIST)
            goto ExecuteIO_RLE;
         else
            goto ExecuteIO_RP;

      case IOCC_FORMAT:
         goto Format_RP;

      case IOCC_UNIT_STATUS:
         goto UnitStatus_RP;

      case IOCC_DEVICE_CONTROL:
         goto DeviceControl_RP;

      case IOCC_GEOMETRY:
         goto Geometry_RP;

      case IOCC_ADAPTER_PASSTHRU:
         goto Passthru_RP;

   }


   /*----------------------------------------------*/
   /* Setup EXECUTE_IO IORB for Request List Entry */
   /*----------------------------------------------*/

ExecuteIO_RLE:
   (USHORT) pRLH = (USHORT) pRLE - pRLE->RqHdr.Head_Offset;

   if ( (DDFlags & DDF_FT_ENABLED) &&
        ( ((PRHFT)pRLE)->ftdb.FT_Flags & FTF_FT_REQUEST) )
      Get_VolCB_Addr(((PRHFT)pRLE)->Block_Dev_Unit, (NPVOLCB FAR *) &pVolCB);
   else
      Get_VolCB_Addr(pRLH->Block_Dev_Unit, (NPVOLCB FAR *) &pVolCB);

   pIORB->Length = sizeof(IORB_EXECUTEIO);
   ((NPXIO)pIORB)->RBA = pRLE->Start_Block +
               pVolCB->PartitionOffset + pVolCB->MediaBPB.HiddenSectors;
   ((NPXIO)pIORB)->BlockCount = pRLE->Block_Count;
   ((NPXIO)pIORB)->BlockSize = 512;
   if ( &(pVolCB->MediaBPB) != 0 ) {                                            
      if  (pVolCB->MediaBPB.BytesPerSector == 1024) {                           
             ((NPXIO)pIORB)->BlockSize = 1024;                                  
      }                                                                         
   }                                                                            

   /* Set up pointers to the scatter/gather list for all commands */
   /* except a read prefetch.                                    */

   if (pIORB->CommandModifier != IOCM_READ_PREFETCH)
   {
      ((NPXIO)pIORB)->cSGList = pRLE->SG_Desc_Count;
      SELECTOROF(((NPXIO)pIORB)->pSGList) = ReqSeg;
      OFFSETOF(((NPXIO)pIORB)->pSGList) = (USHORT)pRLE + sizeof(PB_Read_Write);
      ((NPXIO)pIORB)->ppSGList = pRLH->y_PhysAddr +
                          OFFSETOF(((NPXIO)pIORB)->pSGList) - (USHORT)pRLH;

      ((NPXIO)pIORB)->Flags = 0;

      /* Disable caching if requested */

      if (  ( !(pRLE->RW_Flags & RW_Cache_Req) ) ||                  /*@V46569*/
            (pUnitCB->Flags & UCF_REMOVABLE_NON_FLOPPY) )            /*@V46569*/
      {
         ((NPXIO)pIORB)->Flags |=  (XIO_DISABLE_HW_WRITE_CACHE |
                                    XIO_DISABLE_HW_READ_CACHE);
      }
  }
  return;

   /*-------------------------------------------*/
   /* Setup EXECUTE_IO IORB for Request Packets */
   /*-------------------------------------------*/

ExecuteIO_RP:
   pIORB->Length = sizeof(IORB_EXECUTEIO);
   ((NPXIO)pIORB)->RBA = pRP->rba;
   if (pRP->rph.Flags & RPF_CHS_ADDRESSING)
      pIORB->RequestControl |= IORB_CHS_ADDRESSING;

   ((NPXIO)pIORB)->BlockCount = pRP->NumSectors;
   ((NPXIO)pIORB)->BlockSize = 512;
   ((NPXIO)pIORB)->Flags = 0;

   if ( (pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE) &&
        (pRP->rph.Flags & RPF_Internal) &&
        (((PRP_INTERNAL)pRP)->SectorSize != 512) &&
        (((PRP_INTERNAL)pRP)->SectorSize != 0) )

        ((NPXIO)pIORB)->BlockSize = ((PRP_INTERNAL)pRP)->SectorSize;
   else if ((PktCommand == 0x04) || (PktCommand == 0x08) ||                     
        (PktCommand == 0x09) || (PktCommand == 0x10) ||                         
        (PktCommand == 0x18) || (PktCommand == 0x19) ||                         
        (PktCommand == 0x1A)) {                                                 
            if (pRP->sfn != 0) {                                                
                if ((pRP->sfn == 512) || (pRP->sfn == 1024)) {                  
                    ((NPXIO)pIORB)->BlockSize = pRP->sfn;                       
                }                                                               
            }                                                                   
        }                                                                       

   /* Set up pointers to the scatter/gather list for all commands */
   /* except a read verify.  The scatter/gather list for Request  */
   /* Packets is created within a reserved field in the           */
   /* IORB_EXECUTEIO control block.                               */

   if (pIORB->CommandModifier != IOCM_READ_VERIFY)
   {
      ((NPXIO)pIORB)->cSGList = 1;
      ((NPXIO)pIORB)->pSGList = (PVOID) pIORB;
      OFFSETOF( ((NPXIO)pIORB)->pSGList) = (USHORT) (&(pDMWork->SGList));
      ((NPXIO)pIORB)->ppSGList =
             (ULONG) (ppDataSeg + (ULONG)((USHORT)&(pDMWork->SGList)));

      /* Set up single entry scatter/gather list within IORB */
      (ULONG) (pDMWork->SGList.ppXferBuf) = pRP->XferAddr;
      (ULONG) (pDMWork->SGList.XferBufLen) =
           ((ULONG)((NPXIO)pIORB)->BlockCount)                       /*@V69289*/
                               * ((NPXIO)pIORB)->BlockSize;          /*@V69289*/
   }

   /* Disable caching if removable SCSI media */

   if (pUnitCB->Flags & UCF_REMOVABLE_NON_FLOPPY)                    /*@V46569*/
   {                                                                 /*@V46569*/
      ((NPXIO)pIORB)->Flags |=  (XIO_DISABLE_HW_WRITE_CACHE |        /*@V46569*/
                                 XIO_DISABLE_HW_READ_CACHE);         /*@V46569*/
   }                                                                 /*@V46569*/
   return;

   /*-------------------------------------------*/
   /* Setup FORMAT IORB for Request Packets     */
   /*-------------------------------------------*/
Format_RP:
   pFCT = (NPFORMAT_CMD_TRACK) &( ((NPFIO)pIORB)->Reserved_1[0]);

   pIORB->Length = sizeof(IORB_FORMAT);

   if (pRP->rph.Flags & RPF_CHS_ADDRESSING)
      pIORB->RequestControl |= IORB_CHS_ADDRESSING;

   ((NPFIO)pIORB)->cSGList = 1;
   ((NPFIO)pIORB)->pSGList = (PVOID) pIORB;
   OFFSETOF( ((NPFIO)pIORB)->pSGList) = (USHORT) (&(pDMWork->SGList));
   ((NPFIO)pIORB)->ppSGList =
            (ULONG) (ppDataSeg + (ULONG)((USHORT)&(pDMWork->SGList)));

   /* Set up single entry scatter/gather list within IORB */
   (ULONG) (pDMWork->SGList.ppXferBuf) = ((PRP_INTERNAL)pRP)->XferAddr;
   (ULONG) (pDMWork->SGList.XferBufLen) =
           ((PRP_INTERNAL)pRP)->NumSectors * sizeof(FTT);

   ((NPFIO)pIORB)->FormatCmdLen = sizeof(FORMAT_CMD_TRACK);
   ((NPFIO)pIORB)->pFormatCmd = (PVOID) pFCT;

   pFCT->RBA = ((PRP_INTERNAL)pRP)->rba;
   pFCT->cTrackEntries = ((PRP_INTERNAL)pRP)->NumSectors;

   /* If FormatVerify then turn on the verify flag.  */

   pFCT->Flags = 0;
   if (PktFunction == DISKOP_FORMAT_VERIFY)
      pFCT->Flags |= FF_VERIFY;

   return;

   /*------------------------------------------------*/
   /* Setup UNIT STATUS IORB for Request Packets     */
   /*------------------------------------------------*/
UnitStatus_RP:
   pIORB->Length = sizeof(IORB_UNIT_STATUS);

   return;

   /*---------------------------------------------------*/
   /* Setup DEVICE CONTROL IORB                         */
   /*---------------------------------------------------*/
DeviceControl_RP:
   pIORB->Length = sizeof(IORB_DEVICE_CONTROL);

   if (PktFunction == DISKOP_SUSPEND_DEFERRED)
      ((NPIORB_DEVICE_CONTROL)pIORB)->Flags |= DC_SUSPEND_DEFERRED;

   return;

   /*---------------------------------------------------*/
   /* Setup GEOMETRY IORB                               */
   /*---------------------------------------------------*/
Geometry_RP:
   pVolCB = (NPVOLCB) ((PRP_INTERNAL)pRP)->NumSectors;
   (USHORT) pGeometry = OFFSETOF(pIORB) + sizeof(IORB_GEOMETRY);

   pIORB->Length = sizeof(IORB_GEOMETRY);
   ((NPIORB_GEOMETRY)pIORB)->pGeometry = (PVOID) pGeometry;
   ((NPIORB_GEOMETRY)pIORB)->GeometryLen = sizeof(GEOMETRY);

   if ( (pIORB->CommandModifier == IOCM_SET_MEDIA_GEOMETRY) ||
        (pIORB->CommandModifier == IOCM_SET_LOGICAL_GEOMETRY) )
   {
      if (pVolCB->MediaBPB.TotalSectors != 0)
         pGeometry->TotalSectors = pVolCB->MediaBPB.TotalSectors;
      else
         pGeometry->TotalSectors = pVolCB->MediaBPB.BigTotalSectors;

      pGeometry->BytesPerSector = pVolCB->MediaBPB.BytesPerSector;
      pGeometry->NumHeads = pVolCB->MediaBPB.NumHeads;
      pGeometry->TotalCylinders = pVolCB->NumLogCylinders;
      pGeometry->SectorsPerTrack = pVolCB->MediaBPB.SectorsPerTrack;
   }

   return;
Passthru_RP:
   {
   NPIORB_ADAPTER_PASSTHRU npIORBCdb;
   npIORBCdb=(NPIORB_ADAPTER_PASSTHRU)pIORB;
   npIORBCdb->iorbh.Length = sizeof(IORB_ADAPTER_PASSTHRU);
   switch(PktFunction)
     {
     case DISKOP_EJECTMEDIA:
       npIORBCdb->pControllerCmd=EjectCDB;
       npIORBCdb->ControllerCmdLen=sizeof(EjectCDB);
       break;
     case DISKOP_EJECTMEDIA1:
       npIORBCdb->pControllerCmd=EjectCDB1;
       npIORBCdb->ControllerCmdLen=sizeof(EjectCDB1);
       break;
     case DISKOP_STARTUNIT:
       npIORBCdb->pControllerCmd=StartCDB;
       npIORBCdb->ControllerCmdLen=sizeof(StartCDB);
       break;
     case DISKOP_PASSTHRU_IN:
     case DISKOP_PASSTHRU_OUT:
       {
       PCTRLSTRING pCtrl;
       PBYTE p;
       USHORT junk;
       //
       npIORBCdb->iorbh.CommandCode = (IOCC_ADAPTER_PASSTHRU|0x80);
       // get a virtual pointer to the request Parm Packet
       // the parm packet, altho locked, is technically in user space (calling
       // application), and we passed its physical address cause this routine
       // can be called in interrupt context on the Completion(Notify) callback
       // from the ADD that some PREVIOUS IORB has completed. Thus we might not be IN
       // the process context of the application having submitted the
       // request in the first place.
       //
       if(!DevHelp_PhysToVirt((ULONG)((PRP_GENIOCTL)pRP)->ParmPacket,
                              ((PRP_GENIOCTL)pRP)->ParmLen,
                              &pCtrl,&junk))
         {
         // move the CBD data to just after the iorb data structure
         // this depends on the IORB being smaller than < MAX_IORB_SIZE
         // which, for this passthru it is..
         //
         // the reason for this is that we have only a temp virtual pointer here
         // (pointers built using DevHelp_PhysToVirt are only valid til we block or change context)
         // and we don't know what process context we are in, or whether the
         // downstream add/filter is going to queue this work or execute it now.
         //
         // If this IORB gets queued, it may be that when the ADD gets around to
         // processing it, the process context will have changed, and boom,
         // the ADD will trap (not a good thing).. We KNOW that the IORB buffer
         // area is taken from a global (GDT based) data area, and is addressable
         // in ALL contexts, so this will avoid the problem..
         //

         // get address of buffer after iorb
         p=(PBYTE)(npIORBCdb+1);

         // set the pointer IN the IORB
         npIORBCdb->pControllerCmd=p;

         // copy the CDB data
         for(junk=0;junk<pCtrl->scsi_command_length;junk++)
            p[junk]=pCtrl->scsi_command[junk];

         // set the length of the supplied command string
         npIORBCdb->ControllerCmdLen=(USHORT)pCtrl->scsi_command_length;

         npIORBCdb->iorbh.Length+= npIORBCdb->ControllerCmdLen;

         // if this device is attached to an ATA bus, and
         // the command size matches an ATA patthru structure
         // then change the Iorb header command modifier
         if(pUnitCB->InterfaceType==INTERFACE_ATAPI &&
            pCtrl->scsi_command_length ==sizeof(PassThruATA))
           {
           npIORBCdb->iorbh.CommandModifier=IOCM_EXECUTE_ATA;
           } /* endif */

         npIORBCdb->cSGList = 1;
         npIORBCdb->pSGList = (PVOID) npIORBCdb;
         OFFSETOF( npIORBCdb->pSGList) = (USHORT) (&(pDMWork->SGList));
         npIORBCdb->ppSGLIST =
                  (ULONG) (ppDataSeg + (ULONG)((USHORT)&(pDMWork->SGList)));

         /* Set up single entry scatter/gather list within IORB */
         (ULONG) (pDMWork->SGList.ppXferBuf) = (ULONG)((PRP_GENIOCTL)pRP)->DataPacket;
         (ULONG) (pDMWork->SGList.XferBufLen) = ((PRP_GENIOCTL)pRP)->DataLen;

         // if this request is for inbound data
         // then set the flag in the IORB
         if(PktFunction==DISKOP_PASSTHRU_IN)
           {
           npIORBCdb->Flags=PT_DIRECTION_IN;
           } /* endif */

         // set the IORB command timeout value;
         npIORBCdb->iorbh.Timeout=pCtrl->DeviceTimeout_Sec;
         } /* endif */
       else
         {
         } /* endelse */
       }
       break;
     default:
      break;
     } /* endswitch */
   return;
   }



}


/*------------------------------------------------------------------------
;
;** AllocIORB - Allocate an IORB
;
;   Allocates an IORB.
;
;   USHORT AllocIORB  (NPUNITCB pUnitCB, NPIORB *pIORB)
;
;   ENTRY:    pUnitCB           - UnitCB requesting allocation
;             pIORB             - returned pointer to IORB
;
;   RETURN:   USHORT            = 0, IORB allocated
;                               ! 0 , IORB not allocated
;
;   NOTES:
;
------------------------------------------------------------------------*/
USHORT  AllocIORB(pUnitCB, pIORB)

NPUNITCB pUnitCB;
NPIORBH  FAR *pIORB;

{
   USHORT rc = 0;

   PUSHFLAGS;
   DISABLE;     /* Make sure interrupts are disabled */

   /* Try allocating the dedicated IORB for the requesting unit */

   if ( !(pUnitCB->Flags & UCF_IORB_ALLOCATED) )
   {
      pUnitCB->Flags |= UCF_IORB_ALLOCATED;

      if (pUnitCB->pDedicatedIORB == 0) {
         _asm int 3;                //HCT Debug should never have a null IORB
         rc = 2;
      }

      *pIORB = pUnitCB->pDedicatedIORB;
   }
   else
   {
     /* Dedicated IORB already allocated, so get an IORB from the pool. */

     if (CB_FreeList != 0)
     {
       *pIORB = (NPIORBH) CB_FreeList;           /* Get IORB from free list */
       CB_FreeList = (NPBYTE) (*pIORB)->pNxtIORB; /* Update free list head  */
     }
     else
       rc = 1;
   }

   /* Zero fill IORB */

   if (rc == 0)
      f_ZeroCB((PBYTE)*pIORB, MAX_IORB_SIZE);

   POPFLAGS;
   return(rc);
}

/*------------------------------------------------------------------------
;
;** AllocIORB_Wait - Allocate an IORB, wait until one is available
;
;   Allocates an IORB from the Control Block pool and block if one
;   is not available.
;
;   VOID AllocIORB_Wait  (NPUNITCB pUnitCB, NPIORB *pIORB)
;
;   ENTRY:    pUnitCB           - UnitCB requesting allocation
;             pIORB             - returned pointer to IORB
;
;   RETURN:   VOID
;
;   EFFECTS:
;
------------------------------------------------------------------------*/
VOID  AllocIORB_Wait (pUnitCB, pIORB)

NPUNITCB pUnitCB;
NPIORBH  FAR *pIORB;

{
   USHORT Allocated = FALSE;

   PUSHFLAGS;
   DISABLE;

   do
   {
      if (CB_FreeList != 0)             /* Allocate from free list */
      {
         *pIORB = (NPIORBH) CB_FreeList;
         CB_FreeList = (NPBYTE) (*pIORB)->pNxtIORB; /* Update free list head  */
         Allocated = TRUE;
      }
      else                              /* else wait till control block free */
      {
         PoolSem++;                     /* Indicate at least 1 thread blocked */
         DevHelp_ProcBlock((ULONG) ppDataSeg, (ULONG)-1, 0);
         DISABLE;
         PoolSem--;                     /* Indicate at least 1 thread blocked */
      }
   } while (Allocated == FALSE);

   ENABLE;
   /* Zero fill the IORB */

   f_ZeroCB((PBYTE)*pIORB, MAX_IORB_SIZE);

   POPFLAGS;
}
/*------------------------------------------------------------------------
;
;** FreeIORB - Free an IORB
;
;   Free an IORB.
;
;   VOID FreeIORB  (NPUNITCB pUnitCB, NPIORB pIORB)
;
;   ENTRY:    pUnitCB           - UnitCB requesting deallocation
;             pIORB             - IORB to deallocate
;
;   RETURN:
;
;   EFFECTS:
;
------------------------------------------------------------------------*/

VOID  FreeIORB (pUnitCB, pIORB)

NPUNITCB pUnitCB;
NPIORBH  pIORB;

{
   USHORT AwakeCount;

   PUSHFLAGS;
   DISABLE;

   /* If the IORB being freed is the unit's dedicated IORB, then simply */
   /* clear the UCF_IORB_ALLOCATED flag in the UnitCB, otherwise return */
   /* the IORB to the free pool.                                        */

   if (pIORB == pUnitCB->pDedicatedIORB)
      pUnitCB->Flags &= ~UCF_IORB_ALLOCATED;
   else
   {
      pIORB->pNxtIORB = (NPIORBH) CB_FreeList;
      CB_FreeList = (NPBYTE) pIORB;
   }

   /* If anyone waiting on the pool, then wake them up */

   if (PoolSem)
   {
      DevHelp_ProcRun((ULONG)ppDataSeg, &AwakeCount);
   }

   POPFLAGS;
}



