/*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.      */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = OPSTRAT1.C
 *
 * DESCRIPTIVE NAME = Strategy 1 interface for OS/2 Optical Device Manager
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS   Provides validation and routing of Strategy 1 requests
 *             received from the OS/2 Kernel.
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#include "oph.h"

CMDFUNC functable[]=            //                                       MO.SYS functions to be verified
{                    /*--------------------------------------*/
  {DriveInit      }, /* 0x00  initialize                     */ //  _Initialize
  {MediaCheck     }, /* 0x01  check the media                */ //  _MediaCheck
  {BuildBPB       }, /* 0x02  build BPB                      */ //  _BuildBPB
  {CmdErr         }, /* 0x03  reserved                       */
  {Read           }, /* 0x04  read                           */ //  _ReadWriteVerify
  {CmdErr         }, /* 0x05  non-destructive read           */
  {CmdErr         }, /* 0x06  input status                   */
  {CmdErr         }, /* 0x07  input flush                    */
  {Write          }, /* 0x08  write                          */ //  _ReadWriteVerify
  {Write          }, /* 0x09  write with verify              */ //  _ReadWriteVerify
  {CmdErr         }, /* 0x0A  get output status              */
  {CmdErr         }, /* 0x0B  flush output                   */
  {CmdErr         }, /* 0x0C  reserved                       */
  {StatusComplete }, /* 0x0D  open                           */
  {StatusComplete }, /* 0x0E  close                          */
  {RemovableMedia }, /* 0x0F  removable media                */
  {DriveGenIOCTL  }, /* 0x10  generic IOCTL                  */ //  _GenericIoctl
  {ResetMedia     }, /* 0x11  reset uncertain media          */ //  _ResetMedia
  {GetLogDriveMap }, /* 0x12  get Logical Drive Map          */
  {SetLogDriveMap }, /* 0x13  set Logical Drive Map          */
  {CmdErr         }, /* 0x14  de-Install this device         */
  {CmdErr         }, /* 0x15  portaccess                     */
  {PartFixedDisks }, /* 0x16  get number of partitions       */
  {GetUnitMap     }, /* 0x17  get unit map                   */
  {Read           }, /* 0x18  no caching read                */ //  _ReadWriteVerify
  {Write          }, /* 0x19  no caching write               */ //  _ReadWriteVerify
  {Write          }, /* 0x1A  no caching write/verify        */ //  _ReadWriteVerify
  {DriveInit      }, /* 0x1B  initialize                     */
  {StatusComplete }, /* 0x1C  prepare for shutdown           */
  {CmdErr         }, /* 0x1D  Get Driver Capabilities        */
};                   /*--------------------------------------*/

/****************************************************************************
 *
 * FUNCTION NAME = Strat1
 *
 * DESCRIPTION   = Optical strategy 1 routine
 *
 * INPUT         = ES:BX     - pointer to Request Packet
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 ****************************************************************************/

void near Strat1(pRPH)

PRPH pRPH;
{
  NPUNITCB      pUnitCB;
  USHORT        Cmd, Status,rc;
  NPIORB_CDB    pIORB;
  ULONG volume_size,sector_size;


  pRPH->Status = 0;
  pRPH->Flags = 0;

  Cmd = pRPH->Cmd;

  /*
  ** Filter out invalid requests
  */

  if (Cmd > MAX_DISKDD_CMD)
  {
     Status = STDON + STERR + ERROR_I24_BAD_COMMAND;
     goto  ExitDiskDD;
  }

  if ( (Get_UnitCB_Addr(pRPH->Unit, (NPUNITCB FAR *) &pUnitCB) != NO_ERROR) &&
                     (Cmd != CMDInitBase) &&
                     (Cmd != CMDInit) &&
                     (Cmd != CMDPartfixeddisks) )
  {
      Status = STDON + STERR + ERROR_I24_BAD_UNIT;
      goto ExitDiskDD;
  }
#if 0
  // if NOT one of the init commands
  if(Cmd!=CMDInit && Cmd!=CMDInitBase)
    {
    // check for drives that spin down
    // if not ready, try a command to force spinup
    BuildCDB_TestUnitReady (pUnitCB, (NPIORB_CDB FAR *) &pIORB);
    if  (SubmitIORB_Wait (pUnitCB, pIORB) == STDON + STERR + ERROR_I24_NOT_READY)
      {
      FreeIORB (pUnitCB, pIORB);
      BuildCDB_StartStopUnit (pUnitCB, CDBF_START, (NPIORB_CDB FAR *) &pIORB);
      SubmitIORB_Wait (pUnitCB, pIORB);
      }
    FreeIORB (pUnitCB, pIORB);
    } /* endif */
#endif
  /*
  ** Call Worker Routine
  */
  Status = (*functable[Cmd].Strat1Near)(pRPH, pUnitCB);


  /*
  ** Finish up by setting the Status word in the Request Packet Header
  */

ExitDiskDD:  ;

  DISABLE;

  pRPH->Status = Status;                  /* Save status in Request Packet */

  ENABLE;

}


/****************************************************************************
 *
 * FUNCTION NAME = MediaCheck
 *
 * DESCRIPTION   = Check the Media    (Command = 0x01)
 *
 *       Checks to see if the media in the drive has changed.
 *
 *       USHORT MediaCheck   (PRP_MEDIACHECK pRP, NPUNITCB pUnitCB)
 *
 *       EFFECTS:  The Return Code in the Request Packet is set to one
 *                 of the following:
 *
 *                     -1 = Media has been changed
 *                      0 = Unsure if media has been changed
 *                      1 = Media unchanged
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NEAR MediaCheck(pRP, pUnitCB)

PRP_MEDIACHECK    pRP;
NPUNITCB          pUnitCB;
{
   ULONG volume_size;
   ULONG sector_size;
   USHORT rc;

   if ( pUnitCB->DeviceInfo.vendor_id_code == IBM )
     {
     rc=GetVolumeSize (pUnitCB, &volume_size,&sector_size);
     }
   else
     {
     rc=GetVolumeSize (pUnitCB, &volume_size,&sector_size);
     }

   pRP->rc = ! ((pUnitCB->Flags & UCF_UNCERTAIN_MEDIA) || (rc == STDON + STERR + ERROR_I24_NOT_READY));

   return(STDON);
}

/****************************************************************************
 *
 * FUNCTION NAME = BuildBPB
 *
 * DESCRIPTION   = Build the BPB      (Command = 0x02)
 *
 *       Builds the BPB.  This is requested when the media has changed
 *       or when the media type is uncertain.
 *
 *       USHORT BuildBPB   (PRP_BUILDBPB pRP, NPUNITCB pUnitCB)
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT NEAR BuildBPB(pRP, pUnitCB)
PRP_BUILDBPB   pRP;
NPUNITCB       pUnitCB;
{
   USHORT rc;
   ULONG  volume_size,sector_size;

   if(pUnitCB->DeviceInfo.Installed==FALSE)
     {
     if((rc= InitializeDevice (pUnitCB,SubmitIORB_Wait)) & STERR)
       {
       return rc;
       } /* endif */
     } /* endif */

   if ( pUnitCB->DeviceInfo.vendor_id_code == IBM )
     {
     DoModeSelect ( pUnitCB, PAGE_21 );     // set laser timeout value
     pUnitCB->DeviceInfo.prevent_writes = FALSE;
     } /* endif */

   if(pUnitCB->DeviceInfo.BuildBPBOffMedium)
     {
     if( (rc = GetVolumeSize (pUnitCB, &volume_size,&sector_size)) & STERR)
       return(rc);
     CopyDefaultBPB ( pUnitCB, &pUnitCB->CurrentBPB);
     } /* endif */
   pRP->bpb = (PVOID)&pUnitCB->CurrentBPB;
   pRP->MediaDescr = MEDIA_DESCRIPTOR;
   return (STDON);
}


/****************************************************************************
 *
 * FUNCTION NAME = Read
 *
 * DESCRIPTION   = Read Command  (Command 0x04, 0x18)
 *
 *         This is the basic strategy-1 I/O read routine for the driver.
 *         The request is queued and sent to the adapter driver for
 *         processing.
 *
 *         USHORT Read   (PRP_RWV pRP, NPUNITCB pUnitCB)
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Read (pRP, pUnitCB)

PRP_RWV   pRP;
NPUNITCB  pUnitCB;
{
   USHORT rc, disk_density;
   ULONG  EndSector;
   NPIORB_DMWORK pDMWork;
   BOOL   MountDrive = FALSE;                                        /*@V91985*/
   PULONG pBuff;                                                     /*@V91985*/
   PULONG i;                                                         /*@V96674*/
   USHORT ModeFlag;                                                  /*@V91985*/
   NPIORB_CDB pIORB = 0, pModeIORB = 0;

   /*
   ** Check for valid input parms
   */
   if (pRP->NumSectors == 0)
      return (STDON);

   /*
   ** Check for uncertain media
   */
   if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
   {
      pRP->NumSectors = 0;
      return(STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
   }

   /*                                                                  @V91985
   ** Determine if the File System is attempting to mount the Drive.   @V91985
   */                                                                /*@V91985*/
                                                                     /*@V91985*/
   if ( (pRP->rba == 0) &&                                           /*@V91985*/
        (pRP->NumSectors == 1) )                                     /*@V91985*/
   {                                                                 /*@V91985*/
      if ( DevHelp_PhysToVirt( (ULONG) pRP->XferAddr,                /*@V91985*/
                               (USHORT) 512,                         /*@V96674*/
                               (PVOID)  &pBuff,                      /*@V91985*/
                               (PUSHORT) &ModeFlag   ) )             /*@V91985*/
      {                                                              /*@V91985*/
         _asm {int 3}                                                /*@V91985*/
      }                                                              /*@V91985*/
      if (*pBuff == 0x544f4f42l) /* Boot Signature */                /*@V91985*/
      {                                                              /*@V91985*/
         MountDrive = TRUE;                                          /*@V91985*/
      }                                                              /*@V91985*/
   }                                                                 /*@V91985*/

   switch (pUnitCB->DeviceInfo.product_id_code)
   {

      case ERIMO1:
      default:
            rc = ReadSector (pUnitCB, pRP->rba, pRP->NumSectors,
                                                pRP->XferAddr,
                                     pUnitCB->CurrentBPB.BytesPerSector,FALSE );
   }


   if (rc & STERR)
      pRP->NumSectors = 0;

   if (rc == STDON + STERR + ERROR_I24_BAD_COMMAND)
      rc = STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND;

   #if 0
   /*                                                                  @V91985
   ** If the File System is attempting to mount the drive, and there   @V91985
   ** was an error that was not a drive ready error, give the error    @V91985
   ** (if any) from a read of the volumne descriptor.                  @V91985
   ** Clear the buffer if the read was successful.                     @V91985
   */                                                                /*@V91985*/
   if (MountDrive &&     // Atempting to mount a disc                /*@V96674*/
      (rc != STDON) &&   // An error was encountered                 /*@V96674*/
      (rc != STDON + STERR + ERROR_I24_NOT_READY) &&                 /*@V91985*/
      (rc != STDON + STERR + ERROR_I24_DISK_CHANGE) &&               /*@V91985*/
      (rc != STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA) )            /*@V91985*/
      {                                                              /*@V91985*/
         if ((rc = ReadSector(        pUnitCB,                       /*@V96674*/
                              (ULONG) PRIMARY_VOL_DESCR_RBA,         /*@V96674*/
                                      1,                             /*@V96674*/
                                      pRP->XferAddr,                 /*@V96674*/
                 pUnitCB->CurrentBPB.BytesPerSector, FALSE ))==STDON)
         {  /* zero out buffer (128 ULONGS = 512 bytes) */           /*@V96674*/
            for (i=pBuff;
                 i<pBuff+(pUnitCB->CurrentBPB.BytesPerSector/sizeof(ULONG));
                 i++ )                         /*@V96674*/
            {                                                        /*@V96674*/
               *i = 0l;                                              /*@V96674*/
            }                                                        /*@V96674*/
         }                                                           /*@V96674*/
      }                                                              /*@V91985*/
    #endif

   return(rc);
}

/****************************************************************************
 *
 * FUNCTION NAME = Write
 *
 * DESCRIPTION   = Write Command  (Command 0x08,0x09,0x19,0x1a)
 *
 *         This is the basic strategy-1 I/O read routine for the driver.
 *         The request is queued and sent to the adapter driver for
 *         processing.
 *
 *         USHORT Write  (PRP_RWV pRP, NPUNITCB pUnitCB)
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/
USHORT Write (pRP, pUnitCB)

PRP_RWV   pRP;
NPUNITCB  pUnitCB;
{
   USHORT rc, disk_density;
   ULONG  EndSector;
   NPIORB_DMWORK pDMWork;
   BOOL   MountDrive = FALSE;                                        /*@V91985*/
   PULONG pBuff;                                                     /*@V91985*/
   PULONG i;                                                         /*@V96674*/
   USHORT ModeFlag;                                                  /*@V91985*/
   NPIORB_CDB pIORB = 0, pModeIORB = 0;

   BOOL Verify = (pRP->rph.Cmd == CMDOUTPUTV || pRP->rph.Cmd == CMDOutputBypassV)?TRUE:FALSE;

   /*
   ** Check for valid input parms
   */
   if (pRP->NumSectors == 0)
      return (STDON);

   /*
   ** Check for uncertain media
   */
   if (pUnitCB->Flags & UCF_UNCERTAIN_MEDIA)
   {
      pRP->NumSectors = 0;
      return(STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA);
   }


   switch (pUnitCB->DeviceInfo.product_id_code)
     {

      case ERIMO1:
      default:
        rc = WriteSector (pUnitCB,
                          pRP->rba,
                          pRP->NumSectors,
                          pRP->XferAddr,
                          pUnitCB->CurrentBPB.BytesPerSector ,
                          Verify);
     }


   if (rc & STERR)
      pRP->NumSectors = 0;

   if (rc == STDON + STERR + ERROR_I24_BAD_COMMAND)
      rc = STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND;


   return(rc);
}



/****************************************************************************
 *
 * FUNCTION NAME = RemovableMedia
 *
 * DESCRIPTION   = Check for Removable Media    (Command = 0x0F)
 *
 *        USHORT RemovableMedia (PRPH pRPH, NPUNITCB pUnitCB)
 *
 *        EFFECTS:  The busy bit of the status word is set as follows:
 *
 *                       1 = Media is non-removable
 *                       0 = Media is removable
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT RemovableMedia(pRPH, pUnitCB)

PRPH     pRPH;
NPUNITCB pUnitCB;
{
   if (pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE)
      return (STDON);
   else
      return (STDON + STBUI);
}



/****************************************************************************
 *
 * FUNCTION NAME = ResetMedia
 *
 * DESCRIPTION   = Reset Uncertain Media  (Command = 0x11)
 *
 *                 USHORT ResetMedia (PRPH pRPH, NPUNITCB pUnitCB)
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT ResetMedia (pRPH, pUnitCB)

PRPH     pRPH;
NPUNITCB pUnitCB;
{
   USHORT rc;

   pUnitCB->Flags &= ~UCF_UNCERTAIN_MEDIA;
   return (STDON);
}


/****************************************************************************
 *
 * FUNCTION NAME = GetLogDriveMap
 *
 * DESCRIPTION   = Get Logical Drive Mapping  (Command = 0x12)
 *
 *        Returns which logical drive is currently mapped onto a particular
 *        physical drive.  A zero is returned if only one logical drive is
 *        mapped to the physical drive.
 *
 *        USHORT GetLogDriveMap (PRPH pRPH, NPUNITCB pUnitCB)
 *
 *        EFFECTS: The logical drive is returned in the unit field
 *                 of the request packet header.  The logical drive
 *                 is actually LogDriveNum + 1, which represents the
 *                 drive letter, i.e. C: = 3.  A zero is returned
 *                 if only one logical drive is mapped to the physical drive.
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT GetLogDriveMap (pRPH, pUnitCB)

PRPH     pRPH;
NPUNITCB pUnitCB;
{

   pRPH->Unit = 0;                             /* ret 0 if one drive mapped */

   return (STDON);

}


/****************************************************************************
 *
 * FUNCTION NAME = SetLogDriveMap
 *
 * DESCRIPTION   = Set Logical Drive Mapping  (Command = 0x13)
 *
 *         Maps the specified logical drive onto the physical drive.
 *
 *         USHORT SetLogDriveMap (PRPH pRPH, NPVOLCB pVolCB)
 *
 *         EFFECTS: The logical drive is returned in the unit field
 *                  of the request packet header.  The logical drive
 *                  is actually LogDriveNum + 1, which represents the
 *                  drive letter, i.e. C: = 3.  A zero is returned
 *                  if only one logical drive is mapped to the physical drive.
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT SetLogDriveMap (pRPH, pUnitCB)

PRPH     pRPH;
NPUNITCB pUnitCB;

{
   pRPH->Unit = 0;                            /* only 1 drive can be mapped */

   return (STDON);
}


/****************************************************************************
 *
 * FUNCTION NAME = PartFixedDisks
 *
 * DESCRIPTION   = Get number of fixed disks  (Command = 0x16)
 *
 *        Returns the number of fixed disks supported by the driver.
 *
 *        USHORT PartFixedDisks (PRP_PARTFIXEDDISKS pRP, NPUNITCB pUnitCB)
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT PartFixedDisks (pRP, pUnitCB)

PRP_PARTFIXEDDISKS  pRP;
NPUNITCB            pUnitCB;
{
   pRP->NumFixedDisks = 0;

   return (STDON);
}


/****************************************************************************
 *
 * FUNCTION NAME = GetUnitMap
 *
 * DESCRIPTION   = Get logical units mapped to a physical unit (Command = 0x17)
 *
 *        This command is only supported for disk media.
 *
 *        USHORT GetUnitMap (PRP_GETUNITMAP pRP, NPUNITCB pUnitCB)
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT GetUnitMap (pRP, pUnitCB)

PRP_GETUNITMAP  pRP;
NPUNITCB        pUnitCB;
{

   pRP->UnitMap = 0;                                     /* No units mapped */

   return (STDON);
}



/*
** Near Entry Point to swappable IOCTL routine.
*/

/****************************************************************************
 *
 * FUNCTION NAME = DriveGenIOCTL
 *
 * DESCRIPTION   =
 *
 * INPUT         = pRP              - Request Packet
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT DriveGenIOCTL(pRP, pUnitCB)

PRP_GENIOCTL pRP;
NPUNITCB     pUnitCB;
{
  USHORT rc;

  rc = f_DriveGenIOCTL (pRP, pUnitCB);

  rc |= STDON;

  return(rc);
}


/*
**   Packet Status return functions:
**
**   CmdErr, StatusError, StatusDevReady, StatusComplete
*/

/****************************************************************************
 *
 * FUNCTION NAME = CmdErr
 *
 * DESCRIPTION   =
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT near CmdErr (pRPH, pUnitCB)
PRPH     pRPH;
NPUNITCB pUnitCB;
{
   return (STERR + STDON + ERROR_I24_BAD_COMMAND);
}


/****************************************************************************
 *
 * FUNCTION NAME = StatusDevReady
 *
 * DESCRIPTION   =
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT StatusDevReady(pRPH, pUnitCB)
PRPH     pRPH;
NPUNITCB pUnitCB;
{
  return (STDON + STBUI);
}


/****************************************************************************
 *
 * FUNCTION NAME = StatusComplete
 *
 * DESCRIPTION   =
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT StatusComplete(pRPH, pUnitCB)
PRPH     pRPH;
NPUNITCB pUnitCB;
{
  return (STDON);
}


/****************************************************************************
 *
 * FUNCTION NAME = StatusError
 *
 * DESCRIPTION   =
 *
 * INPUT         = pRPH             - Request Packet Header
 *                 ErrorCode        - Error Code
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT StatusError( pRPH, ErrorCode )

PRPH    pRPH;
USHORT  ErrorCode;
{
  return (STDON + STERR);
}




/****************************************************************************
 *
 * FUNCTION NAME = ReadSector
 *
 * DESCRIPTION   = Issue Read Command
 *
 *        USHORT ReadSector (NPUNITCB pUnitCB, ULONG LBA,
 *                           USHORT transfer_count, ULONG ppDataBuff,
 *                           USHORT block_length)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 LBA              - LBA
 *                 transfer_count   - count of sectors to transfer
 *                 ppDataBuff       - phys addr of data buffer
 *                 block_length     - block_length
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT ReadSector (pUnitCB, LBA, transfer_count, ppDataBuff, block_length, Verify)

NPUNITCB pUnitCB;
ULONG    LBA;
USHORT   transfer_count;
ULONG    ppDataBuff;
USHORT   block_length;
BOOL Verify;

{
   USHORT rc;
   NPIORB_CDB pIORB =0;

   BuildCDB_Read_10 (pUnitCB,
                   LBA,
                   block_length,
                   transfer_count,
                   ppDataBuff,
                   (NPIORB_CDB FAR *)&pIORB,
                   Verify);

   rc = SubmitIORB_Wait(pUnitCB, pIORB);

   FreeIORB (pUnitCB, pIORB);

   return(rc);
}
/****************************************************************************
 *
 * FUNCTION NAME = WriteSector
 *
 * DESCRIPTION   = Issue Write Command
 *
 *        USHORT WriteSector (NPUNITCB pUnitCB, ULONG LBA,
 *                           USHORT transfer_count, ULONG ppDataBuff,
 *                           USHORT block_length, BOOL Verify)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 LBA              - LBA
 *                 transfer_count   - count of sectors to transfer
 *                 ppDataBuff       - phys addr of data buffer
 *                 block_length     - block_length
 *                 Verify           - write with verify if TRUE
 *
 * OUTPUT        = USHORT           - Packet Status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT WriteSector (pUnitCB, LBA, sectors, ppDataBuff, sectorsize,Verify)

NPUNITCB pUnitCB;
ULONG    LBA;
ULONG    sectors;
ULONG    ppDataBuff;
USHORT   sectorsize;
BOOL     Verify;
{
   USHORT rc;
   NPIORB_CDB pIORB =0;

   BuildCDB_Write_10 (pUnitCB,
                    LBA,
                    sectorsize,
                    (USHORT)sectors,
                    ppDataBuff,
                    (NPIORB_CDB FAR *)&pIORB,
                    Verify);

   rc = SubmitIORB_Wait(pUnitCB, pIORB);

   FreeIORB (pUnitCB, pIORB);

   return(rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = GetVolumeSize
 *
 * DESCRIPTION   = Get volume size
 *
 *       Return the volume size of the current CD
 *
 *       USHORT GetVolumeSize  (NPUNITCB pUnitCB, ULONG FAR * volume_size)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *                 volume_size      - Pointer to return volume size
 *
 * OUTPUT        = USHORT           - Packet status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT GetVolumeSize (pUnitCB, volume_size,sector_size)

NPUNITCB  pUnitCB;
PULONG volume_size,sector_size;

{
   USHORT rc;
   NPIORB_CDB pIORB;

   struct ReadCapacity_Data NEAR *pCDBData;
   union  ULONGB  ul_volume;
   union  ULONGB  ul_sector_size;


   BuildCDB_ReadCapacity(pUnitCB, (NPIORB_CDB FAR *) &pIORB);

   pCDBData = (struct ReadCapacity_Data NEAR *) pIORB->CDB_data;

   rc = SubmitIORB_Wait(pUnitCB, pIORB);

   if (rc == STDON)
   {
      ul_volume.ulbytes.byte_3  =  pCDBData->capacity_LBA.ulbytes.byte_0;
      ul_volume.ulbytes.byte_2  =  pCDBData->capacity_LBA.ulbytes.byte_1;
      ul_volume.ulbytes.byte_1  =  pCDBData->capacity_LBA.ulbytes.byte_2;
      ul_volume.ulbytes.byte_0  =  pCDBData->capacity_LBA.ulbytes.byte_3;

      ul_sector_size.ulbytes.byte_3  =  pCDBData->capacity_block_length.ulbytes.byte_0;
      ul_sector_size.ulbytes.byte_2  =  pCDBData->capacity_block_length.ulbytes.byte_1;
      ul_sector_size.ulbytes.byte_1  =  pCDBData->capacity_block_length.ulbytes.byte_2;
      ul_sector_size.ulbytes.byte_0  =  pCDBData->capacity_block_length.ulbytes.byte_3;

      *volume_size = ul_volume.dword;
      *sector_size = ul_sector_size.dword;
   }
   else if (rc == STDON + STERR + ERROR_I24_INVALID_PARAMETER)
      {
      *volume_size = BIG_TOTAL_SECTORS;
      *sector_size = SECTOR_SIZE;
      rc=STDON;
      }
   else if (rc == STDON + STERR + ERROR_I24_GEN_FAILURE)
      {
      *volume_size = BIG_TOTAL_SECTORS;
      *sector_size = SECTOR_SIZE;
      rc=STDON;
      }

   FreeIORB (pUnitCB, pIORB);

   return(rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = ClearCheckCondition
 *
 * DESCRIPTION   = Clear check condition and return error code
 *
 *                 USHORT ClearCheckCondition  (NPUNITCB pUnitCB)
 *
 * INPUT         = pUnitCB          - Pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT ClearCheckCondition (pUnitCB)

NPUNITCB pUnitCB;
{
   ULONG  volume_size,sector_size;

   return(GetVolumeSize (pUnitCB, &volume_size,&sector_size) );
}




/****************************************************************************
 *
 * FUNCTION NAME = Get_UnitCB_Addr
 *
 * DESCRIPTION   = Get UnitCB address
 *
 *       Return the address of the UnitCB for the specified unit.
 *
 *       USHORT Get_UnitCB_Addr  (UCHAR LogDriveNum, NPUNITCB FAR *pUnitCB)
 *
 * INPUT         = unit             - logical drive number
 *                 pUnitCB          - returned pointer to UnitCB
 *
 * OUTPUT        = USHORT           - Packet status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT Get_UnitCB_Addr (LogDriveNum, pUnitCB)

UCHAR LogDriveNum;
NPUNITCB FAR *pUnitCB;

{
   NPUNITCB pUnitCBx;
   USHORT   found = FALSE;

   pUnitCBx = UnitCB_Head;

   while (pUnitCBx != NULL && found == FALSE)
   {
      if ( (UCHAR) pUnitCBx->LogDriveNum == LogDriveNum )
         found = TRUE;
      else
         pUnitCBx = pUnitCBx->pNextUnitCB;
   }

   if (found == TRUE)
   {
      *pUnitCB = pUnitCBx;
      return(NO_ERROR);
   }
   else
      return(ERROR);
}

/****************************************************************************
 *
 * FUNCTION NAME = Strat1b
 *
 * DESCRIPTION   = VOID strat1b  ()
 *
 * INPUT         = ES:BX    - Request Packet
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID NEAR Strat1b()
{
  PRP_GENIOCTL  pRP;
  USHORT        Cmd, Status;
  PRPINITOUT    pRPO;

  _asm
  {
     push es
     push bx
     mov word ptr pRP[0], bx
     mov word ptr pRP[2], es
  }

  pRPO = (PRPINITOUT) pRP;                  /* Output for Init RP           */
  Status = 0;

  Cmd = pRP->rph.Cmd;

  if (Cmd == CMDInitBase || Cmd == CMDInit)
  {
     pRPO->DataEnd = DataBreakAddress;
     pRPO->CodeEnd = CodeBreakAddress;
     if (CodeBreakAddress == 0)
        Status = STDON + STERR + ERROR_I24_QUIET_INIT_FAIL;
  }
  else
     Status = STDON + STERR + ERROR_I24_BAD_COMMAND;

  DISABLE;

  pRP->rph.Status = Status | STDON ;         /*Save status in Request Packet */

  ENABLE;

  _asm
  {
     pop bx
     pop es
     LEAVE
     retf
  }
}

