/*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.      */
/*                                                                           */
/*****************************************************************************/
/*
*
*/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  RSCRTE.C                                              */
/*                                                                            */
/*   DESCRIPTIVE NAME: 	IBMRSCSI runtine routines                             */
/*                                                                            */
/*   FUNCTION: IBMRSCSI runtime environment                                   */
/*                                                                            */
/*   NOTES:                                                                   */
/*                                                                            */
/*      DEPENDENCIES: Device Helper (DevHlp)                                  */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS: RSCStrat - IBMRSCSI strategy entry point                   */
/*                 RSCNotify - IORB notification routine                      */
/*                                                                            */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          01/11/23  VJ              Initial Version                         */
/* VJ2002   02/01/07  VJ              ProcessGeometry return code fix         */
/* VJ011402 02/01/14  VJ              Replace geometry for unknown devtypes   */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "rsc.h"        
/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:   RSCStrat                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  IBMRSCSI Strategy entry point                   */
/*                                                                    */
/* FUNCTION: Process strategy requests to the IBMRSCSI filter         */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Runtime                                                   */
/*                                                                    */
/* ENTRY POINT: RSCStrat                                              */
/*     LINKAGE: NEAR                                                  */
/*                                                                    */
/* INPUT: PRPH pRPH - Pointer to RPH (Request Packet Header)          */
/*                                                                    */
/* EXIT-NORMAL: pRPH->Status set to DONE                              */
/*                                                                    */
/* EXIT-ERROR:  pRPH->Status contains error code                      */
/*                                                                    */
/* EFFECTS:  pRPH->Status - execution status                          */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:        RSCInit                                        */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#pragma optimize("eglt", off)

VOID NEAR RSCStrat()
{
   PRPH pRPH;                   /* Pointer to RPH (Request Packet Header)  */

   _asm
   {
      mov word ptr pRPH[0], bx       /*  pRPH is initialize to              */
      mov word ptr pRPH[2], es       /*  ES:BX passed from the kernel       */
   }

#ifdef DEBUG
   DBGPrint1( "RSCStrat ENTRY cmd=%xh\r\n", pRPH->Cmd);
#endif

   if ( (pRPH->Cmd == CMDInitBase) )
   {  // start the initialization
      pRPH->Status = RSCInit( (PRPINITIN) pRPH );
   }
   else
   {
      pRPH->Status = STATUS_DONE | STATUS_ERR_UNKCMD;
   }


#ifdef DEBUG
   DBGPrint1( "RSCStrat EXIT Status=%xh\r\n", pRPH->Status);
#endif


   _asm
   {
      leave
      retf
   }

} // RSCStrat END
#pragma optimize("", on)

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetDeviceTable                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  GetDeviceTable                                  */
/*                                                                    */
/* FUNCTION:   Get device table                                       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT: GetDeviceTable                                        */
/*     LINKAGE:  FAR                                                  */
/*                                                                    */
/* INPUT: PIORB_CONFIGURATION pIORB - far ptr to the devtable iorb    */
/*                                                                    */
/* EXIT-NORMAL: Device table values returned,                         */
/*              pIORB->iorbh.Status   |= IORB_DONE;                   */
/*              pIORB->iorbh.ErrorCode = 0;                           */
/*                                                                    */
/* EXIT-ERROR: pIORB->iorbh.Status   |= IORB_ERROR;                   */
/*             pIORB->iorbh.ErrorCode = IOERR_CMD_SYNTAX;             */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/* EFFECTS: pIORB->iorbh.Status                                       */
/*            pIORB->iorbh.ErrorCode                                  */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID FAR GetDeviceTable( PIORB_CONFIGURATION pIORB )
{    
   if ( pIORB->DeviceTableLen < sizeof(DEVICETABLE) )
   {
      pIORB->iorbh.Status   |= IORB_ERROR;
      pIORB->iorbh.ErrorCode = IOERR_CMD_SYNTAX;
   }
   else
   {
      pIORB->pDeviceTable->ADDLevelMajor = ADD_LEVEL_MAJOR;
      pIORB->pDeviceTable->ADDLevelMinor = ADD_LEVEL_MINOR;
      pIORB->pDeviceTable->ADDHandle     = gRSCHandle;
      pIORB->pDeviceTable->TotalAdapters = 0;
      pIORB->iorbh.Status   |= IORB_DONE;
      pIORB->iorbh.ErrorCode = 0;
   } 
} // GetDeviceTable END 

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME: NewIORBReturn                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  New IORB return                                 */
/*                                                                    */
/* FUNCTION:   Notifies caller when IORB request is completed         */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: RUNTIME                                                   */
/*                                                                    */
/* ENTRY POINT: NewIORBReturn                                         */
/*     LINKAGE: NEAR                                                  */
/*                                                                    */
/* INPUT: IORBH pIORB  - IORB block ptr                               */
/*                                                                    */
/* EXIT-NORMAL:  always                                               */
/*                                                                    */
/* EXIT-ERROR:  never                                                 */
/*                                                                    */
/* EFFECTS:   None                                                    */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID NEAR NewIORBReturn( PIORBH pIORB )
{
   // Call the upstream component notification routine, 
   //   if asyncronous callback required
   if ( pIORB->RequestControl & IORB_ASYNC_POST )
      (pIORB->NotifyAddress) ( (PIORB) pIORB );

   return;

} //  NewIORBReturn END

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  PassIORBDown                                     */
/*                                                                    */
/* DESCRIPTIVE NAME: PassIORBDown                                     */
/*                                                                    */
/* FUNCTION:  Replace unit handle Sends IORB to the downsteram        */
/*             component.                                             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: RUNTIME                                                   */
/*                                                                    */
/* ENTRY POINT: PassIORBDown                                          */
/*     LINKAGE: FAR                                                   */
/*                                                                    */
/* INPUT: PIORBH pIORB - ptr to the IORB block                        */
/*        NPUCB npUCB  - ptr to the Unit Control Block                */
/*                                                                    */
/* EXIT-NORMAL: n/a                                                   */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:   pTmpIORB->UnitHandle                                    */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:       Downstream component IORB entry point           */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID FAR PassIORBDown( PIORBH pIORB, NPUCB npUCB )
{
   PIORBH pTmpIORB = pIORB;

   do
   {
      // For each IORB in chain replace Unit handle with one saved from the
      // downstream component.
      pTmpIORB->UnitHandle = npUCB->DriverUnitHandle; 

      if (pTmpIORB->RequestControl & IORB_CHAIN) // is there any other requests in chain?
         pTmpIORB = pTmpIORB->pNxtIORB;
      else
         break;

   } 
   while ( pTmpIORB );

   (*npUCB->AdapterDriverEP) ( (PIORB)pIORB );  // Call the ADD w/ptr to IORB.

   return;

} // PassIORBDown END

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:   GetNotifyUnit                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:   GetNotifyUnit                                  */
/*                                                                    */
/* FUNCTION:  Converts unit handle to the UCB pointer                 */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT:  GetNotifyUnit                                        */
/*     LINKAGE:  NEAR                                                 */
/*                                                                    */
/* INPUT: USHORT hUnit - unit handle                                  */
/*                                                                    */
/* EXIT-NORMAL: NPUCB returned, unit found                            */
/*                                                                    */
/* EXIT-ERROR:  NULL - invalid unit handle passed                     */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
NPUCB GetNotifyUnit(USHORT hUnit)
{
   UCHAR i;

   for (i=0; i<gUT.nLastEntry; i++)
   {
      if (gUT.npUCB[i]->DriverUnitHandle==hUnit)
      {
         return (gUT.npUCB[i]);
      }
   }

#ifdef DEBUG
   DBGPrint1( "GetNotifyUnit: INVALID UNIT %xh\r\n", hUnit);
#endif

   return ( NULL );

} // GetNotifyUnit END

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:   GetUnit                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:   GetUnit                                        */
/*                                                                    */
/* FUNCTION:   Converts handle passed to the UCB pointer              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT: GetUnit                                               */
/*     LINKAGE: NEAR                                                  */
/*                                                                    */
/* INPUT: USHORT hUnit unit handle                                    */
/*                                                                    */
/* EXIT-NORMAL:  NPUCB returned, unit found                           */
/*                                                                    */
/* EXIT-ERROR:   NULL - invalid unit handle passed                    */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
NPUCB GetUnit(USHORT hUnit)
{
   if ( hUnit > gUT.nLastEntry || !hUnit )
   {
#ifdef DEBUG
      DBGPrint1("GetUnit INVALID UNIT %xh\r\n", hUnit);
#endif
      return (0);
   }
   else
   {
      return (gUT.npUCB[hUnit-1]);
   }
} // GetUnit END


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  RSCIORBEntry                                     */
/*                                                                    */
/* DESCRIPTIVE NAME: RSCIORBEntry                                     */
/*                                                                    */
/* FUNCTION:  IBMRSCSI IORB entry point.                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Runtime                                                   */
/*                                                                    */
/* ENTRY POINT: RSCIORBEntry                                          */
/*     LINKAGE: FAR                                                   */
/*                                                                    */
/* INPUT: PIORBH pIORB - ptr to the IORB block                        */
/*                                                                    */
/* EXIT-NORMAL:  pIORB->Status    = 0;                                */
/*               pIORB->ErrorCode = 0;                                */
/*                                                                    */
/* EXIT-ERROR: pIORB->Status  and pIORB->ErrorCode contain error      */
/*                                                                    */
/* EFFECTS:  pIORB->Status pIORB->ErrorCode                           */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*    ROUTINES:         GetDeviceTable                                */
/*                      NewIORBReturn                                 */
/*                      GetUnit                                       */
/*                      PassIORBDown                                  */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID _loadds FAR RSCIORBEntry(PIORBH pIORB )
{
   NPUCB   npUCB; // near pointer to unit control block

#ifdef DEBUG
   DBGPrint4( "RSCIORBEntry ENTRY cc=%xh cm=%xh unit=%xh ReqCtrl=%xh\r\n", 
              pIORB->CommandCode, 
              pIORB->CommandModifier, 
              pIORB->UnitHandle,
              pIORB->RequestControl);
#endif

   pIORB->Status    = 0;               // Ensure a "clean Iorb".
   pIORB->ErrorCode = 0;

   switch (pIORB->CommandCode)
   {
   case IOCC_CONFIGURATION:

      switch (pIORB->CommandModifier)
      {
      
      case IOCM_GET_DEVICE_TABLE:

         GetDeviceTable( (PIORB_CONFIGURATION) pIORB );
         NewIORBReturn( pIORB );

         break;

      case IOCM_COMPLETE_INIT:
         // Do nothing for that

         pIORB->Status    = IORB_DONE;
         pIORB->ErrorCode = 0;
         break;

      default:
         pIORB->Status    = IORB_DONE + IORB_ERROR;
         pIORB->ErrorCode = IOERR_CMD_NOT_SUPPORTED;
      }
      break;
   case IOCC_GEOMETRY:

      if (pIORB->CommandModifier == IOCM_GET_MEDIA_GEOMETRY || 
          pIORB->CommandModifier == IOCM_GET_DEVICE_GEOMETRY)
      {

         npUCB = GetUnit(pIORB->UnitHandle);

         if (npUCB)
         {
            npUCB->pIORB = pIORB;

            // Here we will see if we need to replace geometry or 
            // just passthru reported values
            ProcessGeometry(npUCB);

         }
         else
         {
            // Invalid unit/not filtered.
            pIORB->Status    = IORB_DONE + IORB_ERROR;
            pIORB->ErrorCode = IOERR_UNIT_NOT_ALLOCATED;

            NewIORBReturn( pIORB );
         }
      }
      break;

   default:

      npUCB = GetUnit(pIORB->UnitHandle);

      if ( !npUCB )
      {   // Invalid unit/not filtered.
         pIORB->Status    = IORB_DONE + IORB_ERROR;
         pIORB->ErrorCode = IOERR_UNIT_NOT_ALLOCATED;

         NewIORBReturn( pIORB );
      }
      else
         PassIORBDown( pIORB, npUCB );  // Call the ADD w/ptr to IORB.
   }


#ifdef DEBUG
   DBGPrint2("RSCIORBEntry EXIT Status=%xh ErrorCode=%xh\r\n", pIORB->Status, pIORB->ErrorCode);
#endif

} // RSCIORBEntry END



/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  ExecuteIORB                                      */
/*                                                                    */
/* DESCRIPTIVE NAME: Execute IORB                                     */
/*                                                                    */
/* FUNCTION:  Calls the downstream components and wait until          */
/*            IORB is done                                            */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:  Runtime                                                  */
/*                                                                    */
/* ENTRY POINT: ExecuteIORB                                           */
/*     LINKAGE: FAR                                                   */
/*                                                                    */
/* INPUT: NPUCB npUCB  - pointer to the unit control block            */
/*        PIORB pIORB  - IORB to pass down                            */
/*                                                                    */
/* EXIT-NORMAL:  always                                               */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:    pIORB->ErrorCode                                       */
/*             pIORB->Status                                          */
/*                                                                    */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:   Downstream component IORB entry             */
/*    ROUTINES:    DevHelp_ProcBlock                                  */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#pragma optimize("eglt", off)

VOID FAR ExecuteIORB(NPUCB npUCB, PIORB pIORB)
{
#ifdef DEBUG
   DBGPrint2("ExecuteIORB ENTRY cc=%xh cm=%xh\r\n", 
             pIORB->CommandCode, 
             pIORB->CommandModifier);
#endif

   do
   {
      pIORB->ErrorCode = 0;
      pIORB->Status    = 0;

      (npUCB->AdapterDriverEP) ( pIORB );

#ifdef DEBUG
      DBGPrint("ExecuteIORB BLOCK entry\r\n");
#endif

      DISABLE;
      while ( !(pIORB->Status & IORB_DONE) )
      {
         DevHelp_ProcBlock ((ULONG)(PBYTE)npUCB, -1L, 0);
         DISABLE;
      }
      ENABLE;

#ifdef DEBUG
      DBGPrint2( "ExecuteIORB BLOCK exit error=%xh Status=%xh\r\n", 
                 pIORB->ErrorCode, 
                 pIORB->Status);
#endif

   } while ( pIORB->ErrorCode==IOERR_MEDIA_CHANGED );

#ifdef DEBUG
   DBGPrint( "ExecuteIORB EXIT \r\n");
#endif


} // ExecuteIORB END
#pragma optimize("", on)




/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME: ReplaceGeo                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Replace Geometry                                */
/*                                                                    */
/* FUNCTION: Compares unit types and geometry and replaces            */
/*           geometry if needed                                       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT: ReplaceGeo                                            */
/*     LINKAGE: NEAR                                                  */
/*                                                                    */
/* INPUT: UCHAR DevType   - device type                               */
/*        PGEOMETRY pGeo  - pointer to the geometry block             */
/*                                                                    */
/* EXIT-NORMAL: Geometry is modified or not                           */
/*                                                                    */
/* EXIT-ERROR: n/a                                                    */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*    ROUTINES:         CopyBytes                                     */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

VOID ReplaceGeo(UCHAR DevType, PGEOMETRY pGeo)
{
   PGEORTBL pRGT = (PGEORTBL)&gGeoRTable[0];

   while (pRGT->DevType != DEVTYPE_END_OF_GEORTBL)
   {
      /* Compare device type and geometry with table values 
         and replace geometry from the table, if found */
      if ( (( pRGT->DevType == DevType) || (DevType==DEVTYPE_UNKNOWN ))&& //VJ011402
         pRGT->OrgGeo.TotalSectors    == pGeo->TotalSectors   &&
         pRGT->OrgGeo.BytesPerSector  == pGeo->BytesPerSector &&
         pRGT->OrgGeo.NumHeads        == pGeo->NumHeads       &&
         pRGT->OrgGeo.TotalCylinders  == pGeo->TotalCylinders &&
         pRGT->OrgGeo.SectorsPerTrack == pGeo->SectorsPerTrack )
      {

#ifdef DEBUG
         DBGPrint1("ReplaceGeo: We got something to replace. DevType=%xh\r\n", DevType);
         DBGPrint5("ReplaceGeo: Replacing TotSectors=%ld BPS=%d Heads=%xh TotalCyl=%ld SectorsPerTrack=%d\r\n",
                   pGeo->TotalSectors,    
                   pGeo->BytesPerSector,
                   pGeo->NumHeads,        
                   pGeo->TotalCylinders,
                   pGeo->SectorsPerTrack);
         DBGPrint5("ReplaceGeo: For TotSectors=%ld BPS=%xh Heads=%d TotalCyl=%ld SectorsPerTrack=%d\r\n",
                   pRGT->NewGeo.TotalSectors,      
                   pRGT->NewGeo.BytesPerSector,
                   pRGT->NewGeo.NumHeads,          
                   pRGT->NewGeo.TotalCylinders,  
                   pRGT->NewGeo.SectorsPerTrack);
#endif
         CopyBytes((PBYTE)&pRGT->NewGeo, (PBYTE)pGeo, sizeof(GEOMETRY));

         break; //VJ011402

      }

      pRGT++;

   }

   return;
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME: BuildIORB                                         */
/*                                                                    */
/* DESCRIPTIVE NAME: Build IORB                                       */
/*                                                                    */
/* FUNCTION:  This function builds IORB block with specified          */
/*            parameters                                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT: BuildIORB                                             */
/*     LINKAGE: FAR                                                   */
/*                                                                    */
/* INPUT: NPUCB  npUCB  - near pointer to the unit control block      */
/*        USHORT CommandCode                                          */
/*        USHORT CommandModifier                                      */
/*        ULONG  p1  - Command dependant parameter 1                  */
/*        ULONG  p2  - Command dependant parameter 1                  */
/*                                                                    */
/* EXIT-NORMAL: rc = NO_ERROR                                         */
/*                                                                    */
/* EXIT-ERROR:  rc - error return code sepcified                      */
/*                                                                    */
/* EFFECTS:   npUCB->IORBBuffer                                       */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:       DevHelp_VirtToPhys                              */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
USHORT FAR BuildIORB(NPUCB npUCB, USHORT CommandCode, USHORT CommandModifier, ULONG p1, ULONG p2)
{
   USHORT rc = NO_ERROR;

#ifdef DEBUG
   DBGPrint5("BuildIORB ENTRY. npUCB=%xh cc=%xh cm=%xh p1=%lxh p2=%lxh\r\n", 
             (USHORT)npUCB, 
             CommandCode, 
             CommandModifier, 
             p1, 
             p2);
#endif

   SetMem((PBYTE)npUCB->IORBBuffer, sizeof(npUCB->IORBBuffer), 0); // clean IORB buffer

   switch (CommandCode)
   {
   case IOCC_UNIT_CONTROL:
      {
         NPIORB_UNIT_CONTROL npIORB = (NPIORB_UNIT_CONTROL)npUCB->IORBBuffer;

         npIORB->iorbh.Length          = sizeof(IORB_UNIT_CONTROL);
         npIORB->iorbh.UnitHandle      = npUCB->DriverUnitHandle;                                            
         npIORB->iorbh.CommandCode     = IOCC_UNIT_CONTROL;                                                 
         npIORB->iorbh.CommandModifier = CommandModifier;                                              
         npIORB->iorbh.RequestControl  = 0;

         if ( (CommandModifier != IOCM_ALLOCATE_UNIT) && (CommandModifier != IOCM_DEALLOCATE_UNIT) )
         {
            npIORB->pUnitInfo = (PUNITINFO) &npUCB->UnitInfo;                                           
            npIORB->UnitInfoLen = sizeof(UNITINFO);                                                     
         }
      }
      break;

   case IOCC_ADAPTER_PASSTHRU:

      if (CommandModifier == IOCM_EXECUTE_CDB)
      {
         NPIORB_ADAPTER_PASSTHRU npIORB = (NPIORB_ADAPTER_PASSTHRU)npUCB->IORBBuffer;

         npIORB->iorbh.Length          = sizeof(IORB_EXECUTEIO);
         npIORB->iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
         npIORB->iorbh.CommandModifier = IOCM_EXECUTE_CDB;
         npIORB->iorbh.UnitHandle      = npUCB->DriverUnitHandle;

         if (p1!=(ULONG)(PVOID)&SCSIInquiry)
         {  // We dont need async callback at init 
            npIORB->iorbh.RequestControl  = IORB_ASYNC_POST;  
            npIORB->iorbh.NotifyAddress   = RSCNotify;
         }

#ifdef DEBUG
         DBGPrint2("BuildIORB IOCC_ADAPTER_PASSTHRU Buffer Address=%lxh addr2=%lxh\r\n", 
                   (ULONG)(PVOID)npUCB->Buffer, (ULONG)(PVOID)&npUCB->Buffer);
#endif

         if (rc = DevHelp_VirtToPhys( (PVOID)&npUCB->Buffer,
                                      (PULONG)&npUCB->scEntry.ppXferBuf ))
            return (rc);


         npUCB->scEntry.XferBufLen = sizeof(npUCB->Buffer);

         npIORB->cSGList = 1;         
         npIORB->pSGList = (PSCATGATENTRY)&npUCB->scEntry; 
         npIORB->Flags   = PT_DIRECTION_IN;
         npIORB->pControllerCmd   = (PBYTE)p1;
         npIORB->ControllerCmdLen = (USHORT)p2;

      }

      break;
   }

#ifdef DEBUG
   DBGPrint1("BuildIORB EXIT UnitHandle=%xh\r\n", ((PIORB)(npUCB->IORBBuffer))->UnitHandle);
#endif

   return (rc);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME: PassOrgGeoIORB                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Pass original Geometry IORB                     */
/*                                                                    */
/* FUNCTION:  Sends originally received IORB to the                   */
/*             downstream component                                   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT: PassOrgGeoIORB                                        */
/*     LINKAGE: NEAR                                                  */
/*                                                                    */
/* INPUT: NPUCB npUCB - ptr to the Unit Control Block                 */
/*        PIORB pOrigIORB  - pointer to the IORB received             */
/*                           from the upstream component              */
/*        PIORB pOurIORB   - ptr to the modified IORB                 */
/*                                                                    */
/* EXIT-NORMAL: always                                                */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS: Geometry block in original IORB                           */
/*            pOrigIORB->Status                                       */
/*            pOrigIORB->ErrorCode                                    */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*    ROUTINES:   CopyBytes                                           */
/*                ReplaceGeo                                          */
/*                ExecuteIORB                                         */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID NEAR PassOrgGeoIORB(NPUCB npUCB, PIORB pOrigIORB, PIORB pOurIORB)
{
   PGEOMETRY pGeometry = ((PIORB_GEOMETRY)pOrigIORB)->pGeometry;

#ifdef DEBUG
   DBGPrint4("PassOrgGeoIORB: ENTRY npUCB=%lxh pOrigIORB=%lxh pOurIORB=%lxh type=%xh\r\n", 
             (ULONG)(PVOID)npUCB, (ULONG)(PIORB)pOrigIORB, (ULONG)(PIORB)pOurIORB, npUCB->DevType);
#endif

   CopyBytes( (PBYTE)pOrigIORB,  (PBYTE)pOurIORB, sizeof(IORB_GEOMETRY));

   pOurIORB->NotifyAddress = &RSCNotify;
   pOurIORB->UnitHandle    = npUCB->DriverUnitHandle;

   ExecuteIORB(npUCB, pOurIORB);

#ifdef DEBUG
   DBGPrint2( "PassOrgGeoIORB: GEOMETRY status=%xh error=%xh\r\n",
              pOurIORB->Status,
              pOurIORB->ErrorCode );
#endif

   if (!pOurIORB->ErrorCode && !(pOurIORB->Status&IORB_ERROR))
      ReplaceGeo(npUCB->DevType, pGeometry);

#ifdef DEBUG
   DBGPrint4( "PassOrgGeoIORB: returning bps=%xh heads=%xh sectors=%xh cyl=%xh", 
              pGeometry->BytesPerSector, 
              pGeometry->NumHeads,       
              pGeometry->SectorsPerTrack,
              pGeometry->TotalCylinders);

   DBGPrint1( "TotalSectors=%ld\r\n", pGeometry->TotalSectors);
#endif

   pOrigIORB->Status    = pOurIORB->Status;
   pOrigIORB->ErrorCode = pOurIORB->ErrorCode;

#ifdef DEBUG
   DBGPrint2( "PassOrgGeoIORB EXIT. Status=%xh Error=%xh\r\n", 
              pOrigIORB->Status, 
              pOrigIORB->ErrorCode);
#endif

   return;

}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME: ProcessGeometry                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Process Geometry                                */
/*                                                                    */
/* FUNCTION: Process geometry IORB request. First tries to get        */
/*          geometry using SCSI commands, if it fails,                */
/*          then issues mandatory  GET_GEOMETRY request               */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT: ProcessGeometry                                       */
/*     LINKAGE: NEAR                                                  */
/*                                                                    */
/* INPUT: NPUCB npUCB - pointer to the unit data                      */
/*                                                                    */
/* EXIT-NORMAL: Geometry is modified                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*    ROUTINES:        BuildIORB                                      */
/*                     ExecuteIORB                                    */
/*                     PassOrgGeoIORB                                 */
/*                     NewIORBReturn                                  */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/

VOID ProcessGeometry(NPUCB npUCB)
{

   PFDP           pFDP = (PFDP)(npUCB->Buffer+sizeof(ModeHeader));
   PIORB     pOrigIORB = npUCB->pIORB;
   PIORB     pOurIORB  = (PIORB)npUCB->IORBBuffer;
   PGEOMETRY pGeometry = ((PIORB_GEOMETRY)pOrigIORB)->pGeometry;
   USHORT           rc = ERROR_BAD_UNIT;
   PGEORTBL       pRGT = (PGEORTBL)&gGeoRTable[0];


#ifdef DEBUG
   DBGPrint3( "ProcessGeometry ENTRY. npUCB=%xh pGeo=%ld GeoLen=%xh\r\n", 
              (USHORT)npUCB, 
              (ULONG)pGeometry, 
              ((PIORB_GEOMETRY)pOrigIORB)->GeometryLen) ;
#endif

   while (pRGT->DevType != DEVTYPE_END_OF_GEORTBL)
   {
      if (npUCB->DevType==pRGT->DevType)
      {
         rc = NO_ERROR;  
      }
      pRGT++;
   }


   if (!rc)
   {       // Build Mode SENSE 6 first
      rc = BuildIORB( npUCB, 
                      IOCC_ADAPTER_PASSTHRU, 
                      IOCM_EXECUTE_CDB, 
                      (ULONG)(PVOID)&SCSIModeSense6, 
                      sizeof(SCSIModeSense6));
   }

   if (!rc)
   {  // Execute MODE SENSE 6 
      ExecuteIORB(npUCB, pOurIORB);

#ifdef DEBUG
      DBGPrint2( "ProcessGeometry: MODE SENSE 6 status=%xh error=%xh\r\n",
                 pOurIORB->Status,
                 pOurIORB->ErrorCode );
#endif

      if (pOurIORB->ErrorCode || pOurIORB->Status&IORB_ERROR)
      {
         rc =  BuildIORB( npUCB, 
                          IOCC_ADAPTER_PASSTHRU, 
                          IOCM_EXECUTE_CDB, 
                          (ULONG)(PVOID)&SCSIModeSense10, 
                          sizeof(SCSIModeSense10));

         if (!rc)
         {  // Execute MODE SENSE 10 
            ExecuteIORB(npUCB, pOurIORB);
         }

#ifdef DEBUG
         DBGPrint2( "ProcessGeometry: MODE SENSE 10 status=%xh error=%xh\r\n",
                    pOurIORB->Status,
                    pOurIORB->ErrorCode );
#endif
      }
   }

   if ( rc || pOurIORB->ErrorCode || pOurIORB->Status&IORB_ERROR )
   {  // if SCSI requests failed or not supported
      // issue originally received IOCC_GEOMETRY

      PassOrgGeoIORB(npUCB, pOrigIORB, pOurIORB);
   }
   else
   {  // extract geometry data from SCSI Flexible Disk Page buffer

#ifdef DEBUG
      DBGPrint2("ProcessGeometry: Extracting FDP. npUCB->Buffer=%lxh pFDP=%lxh\r\n", 
                (ULONG)(PVOID)npUCB->Buffer, (ULONG)pFDP);
#endif
      pGeometry->BytesPerSector  = MAKEUSINTEL(pFDP->dataBytesPerSector);
      pGeometry->Reserved        = 0;
      pGeometry->NumHeads        = pFDP->noOfHeads;
      pGeometry->TotalCylinders  = MAKEUSINTEL(pFDP->noOfCylinders);
      pGeometry->SectorsPerTrack = pFDP->sectorsPerTrack;
      pGeometry->TotalSectors    = pFDP->sectorsPerTrack * 
                                   pFDP->noOfHeads * 
                                   MAKEUSINTEL(pFDP->noOfCylinders);

      pOrigIORB->Status    = IORB_DONE; // VJ2002
      pOrigIORB->ErrorCode = 0;         // VJ2002

   }

#ifdef DEBUG
   DBGPrint4( "ProcessGeometry: RETURNING BPS=%d Heads=%d Cylinders=%d Sectors=%d\r\n",
              pGeometry->BytesPerSector,
              pGeometry->NumHeads,
              pGeometry->TotalCylinders,
              pGeometry->SectorsPerTrack
            );
#endif

   NewIORBReturn(pOrigIORB);  // notifies the caller

#ifdef DEBUG
   DBGPrint( "ProcessGeometry EXIT\r\n");
#endif
   return;

} // ProcessGeometry END

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  RSCNotify                                        */
/*                                                                    */
/* DESCRIPTIVE NAME: RSCNotify                                        */
/*                                                                    */
/* FUNCTION:  IORB completion notify routine. Called by the downstream*/ 
/* component, to notify that IORB processing is completed             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT:RSCNotify                                              */
/*     LINKAGE: FAR                                                   */
/*                                                                    */
/* INPUT: PIORBH pIORB - ptr to the IORB packet                       */
/*                                                                    */
/* EXIT-NORMAL:  always                                               */
/*                                                                    */
/* EXIT-ERROR:  never                                                 */
/*                                                                    */
/* EFFECTS:                                                           */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:     DevHelp_ProcRun                                   */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID _loadds FAR RSCNotify( PIORBH pIORB )
{

   NPUCB  npUCB;
   USHORT AwakeCount;
   USHORT rc = 0;

#ifdef DEBUG
   if (pIORB)
   {
      DBGPrint5( "RSCNotify : ENTRY Unit=%xh CC=%d CM=%d Status=%xh ErrorCode=%xh\r\n", 
                 pIORB->UnitHandle,
                 pIORB->CommandCode,
                 pIORB->CommandModifier,
                 pIORB->Status,
                 pIORB->ErrorCode);
   }
   else
   {
      DBGPrint( "RSCNotify : Invalid IORB!\r\n");
   }

#endif

   if ( pIORB && (npUCB = GetNotifyUnit(pIORB->UnitHandle)) )
   { // run our waiting process 
      rc = DevHelp_ProcRun((ULONG)(PBYTE)npUCB, &AwakeCount);
   }

#ifdef DEBUG
   DBGPrint1("RCSNotify EXIT rc=%xh\r\n", rc);
#endif

   return;

} // RSCNotify END


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME: SetMem                                            */
/*                                                                    */
/* DESCRIPTIVE NAME: set memory                                       */
/*                                                                    */
/* FUNCTION: Set the block of memory to the specified value           */
/*                                                                    */
/* NOTES: Per byte basis                                              */
/*                                                                    */
/* CONTEXT: Runtime                                                   */
/*                                                                    */
/* ENTRY POINT:  SetMem                                               */
/*     LINKAGE:  FAR                                                  */
/*                                                                    */
/* INPUT: PBYTE destination  - memory address to start replacing      */
/*        USHORT n           - number of bytes to replace             */
/*        UCHAR val          - value to set                           */
/*                                                                    */
/* EXIT-NORMAL:  always                                               */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS: NONE                                                      */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID FAR SetMem( PBYTE destination, USHORT n , UCHAR val)
{
   USHORT        i;

   for ( i=0; i < n; i++ )
   {
      *destination++ = val;
   }
} // SetMem END

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CopyBytes                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Copy memory block                               */
/*                                                                    */
/* FUNCTION:   Copy the block of memory                               */
/*                                                                    */
/* NOTES:   No pointer validation                                     */
/*                                                                    */
/* CONTEXT: Runtime                                                   */
/*                                                                    */
/* ENTRY POINT:  CopyBytes                                            */
/*     LINKAGE:  FAR                                                  */
/*                                                                    */
/* INPUT: PBYTE source     - source memory address to copy from       */
/*        PBYTE destination - memory address to copy to               */               
/*        USHORT n         - number of bytes to copy                  */
/*                                                                    */
/* EXIT-NORMAL: always                                                */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:    None                                                   */
/*                                                                    */
/* INTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES: none                                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
VOID FAR CopyBytes(PBYTE source, PBYTE destination, USHORT n)
{
   USHORT i;

   for (i=0; i<n; i++)
   {
      *destination++=*source++;
   }
} // CopyBytes END

