/*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.      */
/*                                                                           */
/*****************************************************************************/
/* SCCSID = src/dev/dasd/cdrom/ibm1s506/s506rte.c, idskflt, c.basedd 99/10/21 */
/**************************************************************************
 *
 * SOURCE FILE NAME = S506RTE.C
 *
 * DESCRIPTIVE NAME = IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Strategy 1 Entry Point
 *
 * Purpose:
 *
 *
 *
 *
 *
*//*
 * Edit History for defect # 148406:
 *
 * Edit    Date    Comments
 * ----- --------  -------------------------------------------------------------
 * [001] 09-21-95  Added code to support SMART and Statistics IOCTLs. /jlh
 *
 * [002] 11-05-95  Added code to return current counter values. Also
 *                 add code to return unit information structure. /jlh
 *
 * [003] 11-16-95  Add code to serialize IOCTL requests. /jlh
 *
 * [004] 11-30-95  Use ScratchBuf as buffer for Identify Device, Read SMART Attributes
 *                 and Read SMART Thresholds commands.  This buffer is always in a contiguous
 *                 address space, whreas the caller's buffer may not be. /mol
 *
 * [005] 12-12-95  Added definition for FX_SMARTCMD rather than using constant. /jlh
 *
 * [006] 12-21-95  Added functions to allow for changing interface
 *                 interface timings on the fly through IOCTLs. /jlh
 *
 * [007] 01-19-96  Don't clear counters after read per request. /jlh
 *
 * [008] 03-01-96  Move PIIX_SIDETIM back to using global variable exclusively. /jlh
 *
 * [009] 04-12-96  Add code to check for valid buffers being passed. /jlh
 */

 #define INCL_NOBASEAPI
 #define INCL_NOPMAPI
 #define INCL_NO_SCB
// #define INCL_INITRP_ONLY             /* [001] need other packets */
 #include "os2.h"
 #include "dos.h"
 #include "devcmd.h"
 #include "dskinit.h"

 #include "iorb.h"
 #include "strat2.h"                    /* [001] need more definitions */
 #include "reqpkt.h"
 #include "dhcalls.h"
 #include "addcalls.h"

 #include "s506cons.h"
 #include "s506type.h"
 #include "s506ext.h"
 #include "s506pro.h"
 #include "s506regs.h"                  /* [001] need more definitions */


void NEAR DoIOCTLs( PRP_GENIOCTL );  /* [001] forward declaration */


/*------------------------------------------------------------------------*/
/* OS/2 Strategy Request Router                                           */
/* ----------------------------                                           */
/* This routine receives the OS/2 Initialization Request Packet. Any      */
/* other request types are rejected.                                      */
/*------------------------------------------------------------------------*/

VOID NEAR S506Str1()
{
  PRPH pRPH;                   /* Pointer to RPH (Request Packet Header)      */
  UCHAR         Cmd;           /* Request packet command code  */   /*@V153620*/
  UCHAR         SubCmd;        /* Request packet qualifier code */  /*@V153620*/
  USHORT        AwakeCount;       /* [003] */
  USHORT        BlockRet;         /* [003] */

  _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_STARTUP
    int 3
#endif
  }
  pRPH->Status = STATUS_DONE;
  Cmd = pRPH->Cmd;
  // Need the real RP definition, but the Unit field is in the      /*@V153820*/
  // right place, so for now...                                     /*@V153820*/
  SubCmd = ((PRPINITIN)pRPH)->Unit;                                 /*@V153820*/

  if ( Cmd == CMDInitBase )
  {
#if defined( ARIUM_MONITOR_P54 ) || defined( ARIUM_MONITOR_PRO )
    /*
    ** Write a bit to the appropriate Machine Specific Register to enable
    ** branch trace messaging.  (Future: could eliminate the additional
    ** #ifdef'ing if a mechanism were incorporated to identify the processor.
    */
    _asm
    {
       _emit 0x66                 // Use 32-bit operands
       _emit 0x50                 // push eax

       _emit 0x66
       _emit 0x51                 // push ecx

       _emit 0x66
       _emit 0x52                 // push edx
#endif

#if defined( ARIUM_MONITOR_P54 )
       /*
       ** Turn on bit 1 in TR12 (Model Specific Register (MSR)) 0x0E.
       */
       _emit 0x66
       _emit 0xB9                 // mov  ecx, 0x0E
       _emit 0x0E
       _emit 0x00
       _emit 0x00
       _emit 0x00

       _emit 0x66
       _emit 0x33                 // xor  edx, edx
       _emit 0xD2

       _emit 0x66
       _emit 0xB8                 // mov  eax, 0x00000002
       _emit 0x02
       _emit 0x00
       _emit 0x00
       _emit 0x00

#elif defined( ARIUM_MONITOR_PRO )
       /*
       ** Turn on bit 6 in Model Specific Register (MSR) 0x1D9.
       */
       _emit 0x66
       _emit 0xB9                 // mov  ecx, 0x01D9
       _emit 0xD9
       _emit 0x01
       _emit 0x00
       _emit 0x00

       _emit 0x66
       _emit 0x0f                 // rdmsr - Read MSR[ECX]->EDX:EAX
       _emit 0x32

       _emit 0x66
       _emit 0x35                 // xor eax, 0x00000040
       _emit 0x40
       _emit 0x00
       _emit 0x00
       _emit 0x00
#endif

#if defined( ARIUM_MONITOR_P54 ) || defined( ARIUM_MONITOR_PRO )
       _emit 0x66
       _emit 0x0F                 // wrmsr - Write EDX:EAX->MSR[ECX]
       _emit 0x30

       _emit 0x66
       _emit 0x5A                 // pop  edx

       _emit 0x66
       _emit 0x59                 // pop  ecx

       _emit 0x66
       _emit 0x58                 // pop  eax
    }
#endif

    DriveInit( (PRPINITIN) pRPH );
  }
  else if( Cmd == CMDSaveRestore )                                  /*@V153820*/
  {                                                                 /*@V153820*/
     NPACB         npACB;                                           /*@V153820*/
     USHORT        i;                                               /*@V153820*/
                                                                    /*@V153820*/
     if( !SubCmd )  /* Restore bios configuration */                /*@V153820*/
     {                                                              /*@V153820*/
        /*                                                            @V153820
        ** Reject any further I/O requests until restore.             @V153820
        */                                                          /*@V153820*/
        OS2Suspend = TRUE;                                          /*@V153820*/
                                                                    /*@V153820*/
        /*                                                            @V153820
        ** The bios is about to start using the HW so restore the     @V153820
        ** PCI configuration registers to a bios compatible state.    @V153820
        */                                                          /*@V153820*/
        for( i = 0; i < MAX_ADAPTERS; i++ )                         /*@V153820*/
        {                                                           /*@V153820*/
           npACB = ACBPtrs[i].npACB;                                /*@V153820*/
#ifdef DEBUG                                                        /*@V153820*/
           /* Make sure the state machine is currently inactive */  /*@V153820*/
           if( npACB->Flags & ACBF_SM_ACTIVE )                      /*@V153820*/
           {                                                        /*@V153820*/
              _asm int 3                                            /*@V153820*/
           }                                                        /*@V153820*/
#endif                                                              /*@V153820*/
           if( npACB->PCIInfo.Present )                             /*@V153820*/
           {                                                        /*@V153820*/
              ConfigurePCI( npACB, PCIC_SUSPEND );                  /*@V153820*//*@V156660*/
           }                                                        /*@V153820*/
        }                                                           /*@V153820*/
     }                                                              /*@V153820*/
     else if( SubCmd )    /* Restore driver configuration */        /*@V153820*/
     {                                                              /*@V153820*/
        /*                                                            @V153820
        ** The bios has been using the HW so restore the PCI          @V153820
        ** configuration registers to the driver state.               @V153820
        */                                                          /*@V153820*/
        for( i = 0; i < MAX_ADAPTERS; i++ )                         /*@V153820*/
        {                                                           /*@V153820*/
           npACB = ACBPtrs[i].npACB;                                /*@V153820*/
           if( npACB->PCIInfo.Present )                             /*@V153820*/
           {                                                        /*@V153820*/
              ConfigurePCI( npACB, PCIC_RESUME );                   /*@V153820*//*@V156660*/
           }                                                        /*@V153820*/
        }                                                           /*@V153820*/
                                                                    /*@V153820*/
        /*                                                            @V153820
        ** Allow I/O requests to be queued again.                     @V153820
        */                                                          /*@V153820*/
        OS2Suspend = FALSE;                                         /*@V153820*/
     }                                                              /*@V153820*/
#ifdef DEBUG                                                        /*@V153820*/
     else                                                           /*@V153820*/
     {                                                              /*@V153820*/
        _asm int 3                                                  /*@V153820*/
     }                                                              /*@V153820*/
#endif                                                              /*@V153820*/
  }                                                                 /*@V153820*/

  /* Begin [001] Add code to call our IOCTL handler */

  else if ( Cmd == CMDGenIOCTL )
  {
    /* Begin [003] Handle serialization of IOCTL requests */

    DISABLE
    if ( ReqCount >= 1 )
    {
      PUCHAR    DataPacketSave;

      ++ReqCount;
      DataPacketSave = ((PRP_GENIOCTL)pRPH)->DataPacket;  /* save data packet addr */

      /* setup up queue and wait for wakeup */

      ((PRP_GENIOCTL)pRPH)->DataPacket = (PUCHAR)(struct _ILockEntry FAR*)Queue;
      Queue = (ULONG) pRPH;
      pRPH->Status |= STBUI;
      while( pRPH->Status & STBUI )
      {
        BlockRet = DevHelp_ProcBlock( (ULONG) pRPH,
                                      5000, WAIT_IS_INTERRUPTABLE );
        DISABLE
      }

      /* woke up, clean up and run command now */

      ((PRP_GENIOCTL)pRPH)->DataPacket = DataPacketSave;  /* restore data packet addr */

      if ( BlockRet == WAIT_TIMED_OUT )
      {
        StatusError( pRPH, STATUS_DONE | STERR );
        goto ExitStrat;
      }
    }
    else
    {
      ++ReqCount;                     /* now processing a command */
      Queue = 0L;                     /* force queue empty */
    }

    ENABLE
    DoIOCTLs( (PRP_GENIOCTL) pRPH );  /* process IOCTL subfunctions */

    DISABLE
    --ReqCount;                       /* decrement request count */
    if ( ReqCount )
    {
      /* pick request packet for process to wake up and remove from chain */

      pRPH = (PRPH)Queue;
      Queue = (ULONG)(((PRP_GENIOCTL)pRPH)->DataPacket);
      pRPH->Status &= ~STBUI;
      DevHelp_ProcRun( (ULONG) pRPH,
                       &AwakeCount ); /* run blocked process */
    }

  }

  /* End [001][003] */

  else if ( Cmd == CMDInitComplete )                                /*@V155162*/
  {                                                                 /*@V155162*/
      // set status completed ok                                    /*@V155162*/
      pRPH->Status = STATUS_DONE;                                   /*@V155162*/
      // attach to APM                                              /*@V155162*/
      if ( APMAttach() == 0 )                                       /*@V149971*//* moved for @V155162*/
      {                                                             /*@V149971*//* moved for @V155162*/
        // if attached, register for suspend and resume             /*@V155162*/
        APMRegister( APMEventHandler,                               /*@V149971*//* moved for @V155162*/
                     APM_NOTIFYSETPWR | APM_NOTIFYNORMRESUME |      /*@V149971*//* moved for @V155162*/
                     APM_NOTIFYCRITRESUME,                          /*@V149971*//* moved for @V155162*/
                     (USHORT) 0 );                                  /*@V149971*//* moved for @V155162*/
      }                                                             /*@V149971*//* moved for @V155162*/
  }
  else  if(Cmd==CMDShutdown)                                //@roman16 Is it a Shutdown request?
        {                                                 //@roman16
               if(((PRP_SHUTDOWN)pRPH)->Function)         //@roman16 Check is it a shutdown end?
               ProcessStandby();                          //@roman16  If yes then prepare and send a STANDBY command to HDDs



        }                                                 //@roman16
  

  else
  {
    StatusError( pRPH, STATUS_DONE | STATUS_ERR_UNKCMD );
  }

ExitStrat:                                                          /* [003] *//* moved for @V155162*/

  ENABLE                                                            /* moved for @V155162*/

  _asm
  {
    leave
    retf
  }

 }

/*---------------------------------------------------------------------------*
 * Strategy 1 Error Processing                                               *
 * ---------------------------                                               *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/
VOID NEAR StatusError(PRPH pRPH, USHORT ErrorCode )
{
  pRPH->Status = ErrorCode;
  return;
}

/* Begin [001] Process all generic IOCTL calls */

/*---------------------------------------------------------------------------*
 * Perform IORB Notification                                                 *
 * -------------------------                                                 *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

static VOID FAR NotifyIORBDone( PIORB pIORB )
{
  USHORT        AwakeCount;

  if ( pIORB->Status & IORB_DONE )
  {
    DevHelp_ProcRun( (ULONG) pIORB, &AwakeCount );
  }
}

/*---------------------------------------------------------------------------*
 * Process SMART Commands                                                    *
 * ----------------------                                                    *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

static int NEAR DoSMART( USHORT PhysicalUnit, BYTE bySubFunction,
                         BYTE byParameter, PVOID pBuffer )
{
  NPACB                   npACB;
  USHORT                  UnitId;
  /*                                                                  @V155162
  ** Moved PTIORB and icp structures to the ACB.                      @V155162
  */                                                                /*@V155162*/

  // Verify the input physical unit translates to an active
  // and valid ACB.
  if( PhysicalUnit/2 >= cAdapters )
  {
     return IOERR_UNIT_NOT_READY;
  }

  npACB = ACBPtrs[PhysicalUnit/2].npACB;
  UnitId = PhysicalUnit % 2;

  if ( (UnitId >= npACB->cUnits) ||
       (npACB->UnitCB[UnitId].Flags & UCBF_NODASDSUPPORT) )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_UNIT_NOT_READY;
    return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
  }

  setmem( (PBYTE) &npACB->PTIORB, 0, sizeof(npACB->PTIORB) );
  setmem( (PBYTE) &npACB->icp, 0, sizeof(npACB->icp) );

  npACB->icp.TaskFileIn.CylinderLow = 0x4F;        /* magic key for SMART */
  npACB->icp.TaskFileIn.CylinderHigh = 0xC2;
  npACB->icp.TaskFileIn.SectorCount = byParameter;
  npACB->icp.TaskFileIn.Features = bySubFunction;
  npACB->icp.TaskFileIn.Command = FX_SMARTCMD;     /* [005] SMART command code */

  npACB->icp.RegisterTransferMap = PTA_RTMWR_FEATURES | PTA_RTMWR_SECTORCOUNT |
                            PTA_RTMWR_CYLINDERLOW | PTA_RTMWR_CYLINDERHIGH |
                            PTA_RTMWR_COMMAND |
                            PTA_RTMRD_ERROR | PTA_RTMRD_STATUS;

  if( pBuffer)                              /* if involving data transfer */
  {
    /* [004] Use local ScratchBuf for xfer */
    if ( DevHelp_VirtToPhys( ScratchBuf,
                             (PULONG) &ScratchSGList.ppXferBuf ) )
    {
      _asm int 3;
    }
    npACB->PTIORB.cSGList               = 1;
    npACB->PTIORB.pSGList               = &ScratchSGList;
    ScratchSGList.XferBufLen = 512;
  }

  npACB->PTIORB.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
  npACB->PTIORB.iorbh.UnitHandle      = (USHORT) &npACB->UnitCB[UnitId];
  npACB->PTIORB.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
  npACB->PTIORB.iorbh.CommandModifier = IOCM_EXECUTE_ATA;
  npACB->PTIORB.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
  npACB->PTIORB.iorbh.NotifyAddress   = NotifyIORBDone;

  npACB->PTIORB.ControllerCmdLen      = sizeof(npACB->icp);
  npACB->PTIORB.pControllerCmd        = (PBYTE) &npACB->icp;
  npACB->PTIORB.Flags                 = PT_DIRECTION_IN;

  ADDEntryPoint( (PIORB) &npACB->PTIORB );

  DISABLE
  while( !(npACB->PTIORB.iorbh.Status & IORB_DONE) )
  {

    DevHelp_ProcBlock( (ULONG)(PIORB) &npACB->PTIORB, -1, WAIT_IS_INTERRUPTABLE );
    DISABLE
  }
  ENABLE

  /* Begin [004] */
  if( pBuffer )
  {
    /* Move data from the local ScratchBuf to caller's buffer */
    for( UnitId = 0; UnitId < 512; UnitId++ )
         ((PBYTE)pBuffer)[UnitId] = ScratchBuf[UnitId];
  }
  /* End [004] */

  if ( npACB->icp.TaskFileOut.Status & FX_ERROR )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_DEVICE_REQ_NOT_SUPPORTED;
  }

  return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
}


/*---------------------------------------------------------------------------*
 * Get SMART Status                                                          *
 * ----------------                                                          *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

static int GetSmartStatus( USHORT PhysicalUnit, PDWORD pData )
{
  NPACB                   npACB;
  USHORT                  UnitId;

  // Verify the input physical unit translates to an active
  // and valid ACB.
  if( PhysicalUnit/2 >= cAdapters )
  {
     return IOERR_UNIT_NOT_READY;
  }

  npACB = ACBPtrs[PhysicalUnit/2].npACB;
  UnitId = PhysicalUnit % 2;

  if ( (UnitId >= npACB->cUnits) ||
       (npACB->UnitCB[UnitId].Flags & UCBF_NODASDSUPPORT) )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_UNIT_NOT_READY;
    return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
  }

  setmem( (PBYTE) &npACB->PTIORB, 0, sizeof(npACB->PTIORB) );
  setmem( (PBYTE) &npACB->icp, 0, sizeof(npACB->icp) );

  npACB->icp.TaskFileIn.CylinderLow = 0x4F;        /* magic key for SMART */
  npACB->icp.TaskFileIn.CylinderHigh = 0xC2;
  npACB->icp.TaskFileIn.Features = 0xDA;
  npACB->icp.TaskFileIn.Command = FX_SMARTCMD;     /* [005] SMART command code */

  npACB->icp.RegisterTransferMap = PTA_RTMWR_FEATURES | PTA_RTMWR_SECTORCOUNT |
                            PTA_RTMWR_CYLINDERLOW | PTA_RTMWR_CYLINDERHIGH |
                            PTA_RTMWR_COMMAND |
                            PTA_RTMRD_CYLINDERLOW | PTA_RTMRD_CYLINDERHIGH |
                            PTA_RTMRD_ERROR | PTA_RTMRD_STATUS;

  npACB->PTIORB.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
  npACB->PTIORB.iorbh.UnitHandle      = (USHORT) &npACB->UnitCB[UnitId];
  npACB->PTIORB.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
  npACB->PTIORB.iorbh.CommandModifier = IOCM_EXECUTE_ATA;
  npACB->PTIORB.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
  npACB->PTIORB.iorbh.NotifyAddress   = NotifyIORBDone;

  npACB->PTIORB.ControllerCmdLen      = sizeof(npACB->icp);
  npACB->PTIORB.pControllerCmd        = (PBYTE) &npACB->icp;
  npACB->PTIORB.Flags                 = PT_DIRECTION_IN;

  ADDEntryPoint( (PIORB) &npACB->PTIORB );

  DISABLE
  while( !(npACB->PTIORB.iorbh.Status & IORB_DONE) )
  {

    DevHelp_ProcBlock( (ULONG)(PIORB) &npACB->PTIORB, -1, WAIT_IS_INTERRUPTABLE );
    DISABLE
  }
  ENABLE

  if ( (npACB->icp.TaskFileOut.Status & FX_ERROR) &&
       (npACB->icp.TaskFileOut.Error & FX_ABORT) )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_DEVICE_REQ_NOT_SUPPORTED;
    *pData = -1;
  }
  else if ( (npACB->icp.TaskFileOut.CylinderLow == 0x4F) &&
            (npACB->icp.TaskFileOut.CylinderHigh == 0xC2) )
  {
    *pData = 0;
  }
  else if ( (npACB->icp.TaskFileOut.CylinderLow == 0xF4) &&
            (npACB->icp.TaskFileOut.CylinderHigh == 0x2C) )
  {
    *pData = 1;
  }

  return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
}

/*---------------------------------------------------------------------------*
 * Get Inquiry Data                                                          *
 * ----------------                                                          *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

int GetInquiryData( NPUCB npUCB, PBYTE pBuffer , USHORT Buffersize)
{
  NPACB  npACB = npUCB->npACB;                                      /*@V155162*/
  USHORT temp;

  setmem( (PBYTE) &npACB->PTIORB, 0, sizeof(npACB->PTIORB) );
  setmem( (PBYTE) &npACB->icp, 0, sizeof(npACB->icp) );

  npACB->icp.TaskFileIn.Command =
    (npUCB->Flags & UCBF_ATAPIDEVICE) ?                              /*@V151345*/
      FX_ATAPI_IDENTIFY : FX_IDENTIFY;

  npACB->icp.RegisterTransferMap = PTA_RTMWR_COMMAND |
                            PTA_RTMRD_ERROR | PTA_RTMRD_STATUS;

  /* [004] Use local ScratchBuf for xfer */
  if ( DevHelp_VirtToPhys( ScratchBuf,
                           (PULONG) &ScratchSGList.ppXferBuf ) )
  {
    _asm int 3;
  }
  npACB->PTIORB.cSGList               = 1;
  npACB->PTIORB.pSGList               = &ScratchSGList;
  ScratchSGList.XferBufLen = 512;

  npACB->PTIORB.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
  npACB->PTIORB.iorbh.UnitHandle      = (USHORT) npUCB;                         /*@V151345*/
  npACB->PTIORB.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;                  /*@V151345*/
  npACB->PTIORB.iorbh.CommandModifier = IOCM_EXECUTE_ATA;                       /*@V151345*/
  npACB->PTIORB.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;   /*@V151345*/
  npACB->PTIORB.iorbh.NotifyAddress   = NotifyIORBDone;                         /*@V151345*/

  npACB->PTIORB.ControllerCmdLen      = sizeof(npACB->icp);                            /*@V151345*/
  npACB->PTIORB.pControllerCmd        = (PBYTE) &npACB->icp;                           /*@V151345*/
  npACB->PTIORB.Flags                 = PT_DIRECTION_IN;                        /*@V151345*/

  npUCB->ReqFlags = 0;                                                   /*@V151345*/

  ADDEntryPoint( (PIORB) &npACB->PTIORB );

  DISABLE
  while( !(npACB->PTIORB.iorbh.Status & IORB_DONE) )
  {

    DevHelp_ProcBlock( (ULONG)(PIORB) &npACB->PTIORB, -1, WAIT_IS_INTERRUPTABLE );
    DISABLE
  }
  ENABLE

  /* [004] Move data from the local ScratchBuf to caller's buffer */
  for( temp = 0; temp < Buffersize; temp++ )                             /*@V151345*/
      *pBuffer++ = ScratchBuf[temp];                                     /*@V151345*/

  if ( npACB->icp.TaskFileOut.Status & FX_ERROR )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_DEVICE_REQ_NOT_SUPPORTED;
  }

  return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
}


/*---------------------------------------------------------------------------*
 * Issue Set Features                                                        *
 * ------------------                                                        *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

int IssueSetFeatures( NPACB npACB, USHORT UnitId,                     /*@V151345*/
                             BYTE SubCommand, BYTE Arg )
{
  setmem( (PBYTE) &npACB->PTIORB, 0, sizeof(npACB->PTIORB) );
  setmem( (PBYTE) &npACB->icp, 0, sizeof(npACB->icp) );

  npACB->icp.TaskFileIn.Command = FX_SETFEAT;
  npACB->icp.TaskFileIn.Features = SubCommand;
  npACB->icp.TaskFileIn.SectorCount = Arg;

  npACB->icp.RegisterTransferMap = PTA_RTMWR_COMMAND | PTA_RTMWR_FEATURES |
                            PTA_RTMWR_SECTORCOUNT |
                            PTA_RTMRD_CYLINDERHIGH | PTA_RTMRD_CYLINDERLOW |
                            PTA_RTMRD_ERROR | PTA_RTMRD_STATUS;
                                                                      /*@V151345*/
                                                                      /*@VVVVVVV*/
  npACB->PTIORB.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
  npACB->PTIORB.iorbh.UnitHandle      = (USHORT) &npACB->UnitCB[UnitId];
  npACB->PTIORB.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
  npACB->PTIORB.iorbh.CommandModifier = IOCM_EXECUTE_ATA;
  npACB->PTIORB.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
  npACB->PTIORB.iorbh.NotifyAddress   = NotifyIORBDone;

  npACB->PTIORB.ControllerCmdLen      = sizeof(npACB->icp);
  npACB->PTIORB.pControllerCmd        = (PBYTE) &npACB->icp;
  npACB->PTIORB.Flags                 = PT_DIRECTION_IN;

  ADDEntryPoint( (PIORB) &npACB->PTIORB );

  DISABLE
  while( !(npACB->PTIORB.iorbh.Status & IORB_DONE) )
  {

    DevHelp_ProcBlock( (ULONG)(PIORB) &npACB->PTIORB, -1, WAIT_IS_INTERRUPTABLE );
    DISABLE
  }
  ENABLE

  if ( npACB->icp.TaskFileOut.Status & FX_ERROR )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_DEVICE_REQ_NOT_SUPPORTED;
  }

  return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
}
/*---------------------------------------------------------------------------*
 * Issue GetMediaStatus                                                      *
 * ------------------                                                        *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

int IssueGetMediaStatus( NPACB npACB, USHORT UnitId)
{
  setmem( (PBYTE) &npACB->PTIORB, 0, sizeof(npACB->PTIORB) );
  setmem( (PBYTE) &npACB->icp, 0, sizeof(npACB->icp) );

  npACB->icp.TaskFileIn.Command = FX_GET_MEDIA_STATUS;

  npACB->icp.RegisterTransferMap = PTA_RTMWR_COMMAND |
                            PTA_RTMRD_ERROR | PTA_RTMRD_STATUS;

  npACB->PTIORB.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
  npACB->PTIORB.iorbh.UnitHandle      = (USHORT) &npACB->UnitCB[UnitId];
  npACB->PTIORB.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
  npACB->PTIORB.iorbh.CommandModifier = IOCM_EXECUTE_ATA;
  npACB->PTIORB.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
  npACB->PTIORB.iorbh.NotifyAddress   = NotifyIORBDone;

  npACB->PTIORB.ControllerCmdLen      = sizeof(npACB->icp);
  npACB->PTIORB.pControllerCmd        = (PBYTE) &npACB->icp;
  npACB->PTIORB.Flags                 = PT_DIRECTION_IN;

  ADDEntryPoint( (PIORB) &npACB->PTIORB );

  DISABLE
  while( !(npACB->PTIORB.iorbh.Status & IORB_DONE) )
  {

    DevHelp_ProcBlock( (ULONG)(PIORB) &npACB->PTIORB, -1, WAIT_IS_INTERRUPTABLE );
    DISABLE
  }
  ENABLE

  if ( npACB->icp.TaskFileOut.Status & FX_ERROR )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    if(npACB->icp.TaskFileOut.Error & FX_ABORT)
      {
      npACB->PTIORB.iorbh.ErrorCode = IOERR_CMD_ABORTED;
      } /* endif */
    else
      {
      // signal the status has changed
      npACB->PTIORB.iorbh.ErrorCode = IOERR_DEVICE_NONSPECIFIC;
      }
  }

  return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
}
/*---------------------------------------------------------------------------*
 * ProcessLockUnlockEject                                                    *
 * ------------------                                                        *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

int ProcessLockUnlockEject(NPACB npACB, PIORB pIORB, USHORT Function) /*@V155162*/
{
  setmem( (PBYTE) &npACB->PTIORB, 0, sizeof(npACB->PTIORB) );
  setmem( (PBYTE) &npACB->icp, 0, sizeof(npACB->icp) );

  switch(Function)
    {
    case IOCM_EJECT_MEDIA:
      npACB->icp.TaskFileIn.Command = FX_EJECT_MEDIA;
      break;
    case IOCM_LOCK_MEDIA:
      npACB->icp.TaskFileIn.Command = FX_LOCK_DOOR;
      break;
    case IOCM_UNLOCK_MEDIA:
      npACB->icp.TaskFileIn.Command = FX_UNLOCK_DOOR;
      break;
    default:
     break;
    } /* endswitch */

  npACB->icp.RegisterTransferMap = PTA_RTMWR_COMMAND |
                            PTA_RTMRD_ERROR | PTA_RTMRD_STATUS;

  npACB->PTIORB.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
  npACB->PTIORB.iorbh.UnitHandle      = pIORB->UnitHandle;
  npACB->PTIORB.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
  npACB->PTIORB.iorbh.CommandModifier = IOCM_EXECUTE_ATA;
  npACB->PTIORB.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
  npACB->PTIORB.iorbh.NotifyAddress   = NotifyIORBDone;

  npACB->PTIORB.ControllerCmdLen      = sizeof(npACB->icp);
  npACB->PTIORB.pControllerCmd        = (PBYTE) &npACB->icp;
  npACB->PTIORB.Flags                 = PT_DIRECTION_IN;

  ADDEntryPoint( (PIORB) &npACB->PTIORB );

  DISABLE
  while( !(npACB->PTIORB.iorbh.Status & IORB_DONE) )
  {
    DevHelp_ProcBlock( (ULONG)(PIORB) &npACB->PTIORB, -1, WAIT_IS_INTERRUPTABLE );
    DISABLE
  }
  ENABLE

  if ( npACB->icp.TaskFileOut.Status & FX_ERROR )
  {
    pIORB->Status |= IORB_ERROR;                                    /*@V153620*/
    if(npACB->icp.TaskFileOut.Error & FX_ABORT)
      {
      pIORB->ErrorCode = IOERR_CMD_ABORTED;                         /*@V153620*/
      } /* endif */
    else
      {
      // signal the status has changed
      if(npACB->icp.TaskFileOut.Error & 8)
        {
        pIORB->ErrorCode = IOERR_MEDIA_CHANGED;                     /*@V153620*/
        } /* endif */
      else
        {
        pIORB->ErrorCode = IOERR_DEVICE_NONSPECIFIC;                /*@V153620*/
        } /* endelse */
      }
  }
                                                                   /*@AAAAAAA*/
                                                                   /*@V151345*/
}

#ifdef ENABLE_SET_TIMINGS                                           /*@V179942*/

/*---------------------------------------------------------------------------*
 * Set Timing Modes                                                          *
 * ----------------                                                          *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

static int SetTimingModes( PConfigureUnitParameters pCUP )
{
  NPACB                   npACB;
  USHORT                  UnitId;

  // Verify the input physical unit translates to an active
  // and valid ACB.
  if( pCUP->byPhysicalUnit/2 >= cAdapters )
  {
     return IOERR_UNIT_NOT_READY;
  }

  npACB = ACBPtrs[pCUP->byPhysicalUnit/2].npACB;
  UnitId = pCUP->byPhysicalUnit % 2;

  if ( (UnitId >= npACB->cUnits) ||
       (npACB->UnitCB[UnitId].Flags & UCBF_NODASDSUPPORT) )
  {
    npACB->PTIORB.iorbh.Status |= IORB_ERROR;
    npACB->PTIORB.iorbh.ErrorCode = IOERR_UNIT_NOT_READY;
    return( (npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );
  }

  /* handle setting of Bus Master DMA enable switches */

  if ( pCUP->BusMasterDMA.CommandBits & CUPCB_BUSMASTERENABLE )
  {
    if ( pCUP->BusMasterDMA.OnOff )         /* if nonzero, turn on DMA */
    {
      npACB->UnitCB[UnitId].Flags |= UCBF_BM_DMA;
    }
    else                                    /* otherwise, turn it off */
    {
      npACB->UnitCB[UnitId].Flags &= ~UCBF_BM_DMA;
    }
  }

  /* handle PIO mode selection */

  if ( pCUP->BusMasterDMA.CommandBits & CUPCB_SETPIOMODE )
  {
    npACB->UnitCB[UnitId].CurPIOMode = pCUP->BusMasterDMA.PIO_Mode;
  }

  /* handle DMA mode selection */
  if ( pCUP->BusMasterDMA.CommandBits & CUPCB_SETDMAMODE )
  {
    npACB->UnitCB[UnitId].CurDMAMode = pCUP->BusMasterDMA.DMA_Mode;
  }

  /* Calculate adapter timing based on new setting for unit. */

  CalculateAdapterTiming( npACB, piix_Level,                        /*@V179942*/
                          npACB->IOPorts[FI_PDAT] == FX_PRIMARY );

  /* Issue required set features commands */

  if ( npACB->UnitCB[UnitId].CurPIOMode )
  {
    IssueSetFeatures( npACB, UnitId, FX_SETXFERMODE,
                      (BYTE)(FX_PIOMODEX |
                      npACB->UnitCB[UnitId].CurPIOMode) );
  }
  else
  {
    IssueSetFeatures( npACB, UnitId, FX_SETXFERMODE, FX_PIOMODE0 );
  }

  if ( npACB->UnitCB[UnitId].Flags & UCBF_BM_DMA )
  {
    IssueSetFeatures( npACB, UnitId, FX_SETXFERMODE,
                      (BYTE)(FX_MWDMAMODEX |
                      npACB->UnitCB[UnitId].CurDMAMode) );
  }
}

#endif

/* End [006] */

/*---------------------------------------------------------------------------*
 * Process Generic IOCTL Calls                                               *
 * ---------------------------                                               *
 *                                                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

static void NEAR DoIOCTLs( PRP_GENIOCTL pRP_IOCTL )
{
  PDSKSP_CommandParameters    pcp;
  USHORT                      status = STATUS_DONE;
  USHORT                      rc = IOERR_DEVICE_REQ_NOT_SUPPORTED;

  pcp = (PDSKSP_CommandParameters) pRP_IOCTL->ParmPacket;

  /* Begin [005] */

  if ( DevHelp_VerifyAccess(SELECTOROF(pcp), sizeof(PDSKSP_CommandParameters),
                            OFFSETOF(pcp), VERIFY_READONLY) )
  {
    StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
    return;
  }

  /* End [005] */

  if ( pRP_IOCTL->Category == DSKSP_CAT_SMART )
  {
    switch ( pRP_IOCTL->Function )
    {
    case DSKSP_SMART_ONOFF:

        /* Begin [005] */

        if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                  sizeof(BYTE),
                                  OFFSETOF(pRP_IOCTL->DataPacket),
                                  VERIFY_READONLY) )
        {
          StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
          return;
        }

        /* End [005] */

        rc = DoSMART( (USHORT) pcp->byPhysicalUnit,
                       (BYTE) ((*(PBYTE)(pRP_IOCTL->DataPacket)) ? 0xD8 : 0xD9),
                       0,0L );
        break;

    case DSKSP_SMART_AUTOSAVE_ONOFF:

        /* Begin [005] */

        if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                  sizeof(BYTE),
                                  OFFSETOF(pRP_IOCTL->DataPacket),
                                  VERIFY_READONLY) )
        {
          StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
          return;
        }

        /* End [005] */

        rc = DoSMART( pcp->byPhysicalUnit,
                       0xD2,
                       (BYTE) ((*(PBYTE)(pRP_IOCTL->DataPacket)) ? 0xF1 : 0),
                       NULL );
        break;

    case DSKSP_SMART_SAVE:
        rc = DoSMART( pcp->byPhysicalUnit, 0xD3, 0, NULL );
        break;

    case DSKSP_SMART_GETSTATUS:

        /* Begin [005] */

        if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                  sizeof(DWORD),
                                  OFFSETOF(pRP_IOCTL->DataPacket),
                                  VERIFY_READWRITE) )
        {
          StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
          return;
        }

        /* End [005] */

        rc = GetSmartStatus( pcp->byPhysicalUnit,
                              (PDWORD) pRP_IOCTL->DataPacket );
        break;

    case DSKSP_SMART_GET_ATTRIBUTES:

        /* Begin [005] */

        if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                  512*sizeof(BYTE),
                                  OFFSETOF(pRP_IOCTL->DataPacket),
                                  VERIFY_READWRITE) )
        {
          StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
          return;
        }

        /* End [005] */

        rc = DoSMART( pcp->byPhysicalUnit, 0xD0, 0,
                       pRP_IOCTL->DataPacket );
        break;

    case DSKSP_SMART_GET_THRESHOLDS:

        /* Begin [005] */

        if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                  512*sizeof(BYTE),
                                  OFFSETOF(pRP_IOCTL->DataPacket),
                                  VERIFY_READWRITE) )
        {
          StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
          return;
        }

        /* End [005] */

        rc = DoSMART( pcp->byPhysicalUnit, 0xD1, 0,
                       pRP_IOCTL->DataPacket );
        break;
    }
  }
  else if ( pRP_IOCTL->Category == DSKSP_CAT_GENERIC )
  {
    switch ( pRP_IOCTL->Function )
    {

    /* Begin [002] Add code to return counters */

#ifdef ENABLE_COUNTERS
      case DSKSP_GEN_GET_COUNTERS:
        {
          NPACB                   npACB;
          USHORT                  UnitId;

          /* Begin [005] */

          if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                    sizeof(DeviceCountersData),
                                    OFFSETOF(pRP_IOCTL->DataPacket),
                                    VERIFY_READWRITE) )
          {
            StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
            return;
          }

          /* End [005] */

          // Verify the input physical unit translates to an active
          // and valid ACB.
          if( pcp->byPhysicalUnit/2 >= cAdapters )
          {
             rc = IOERR_UNIT_NOT_READY;
             break;
          }

          npACB = ACBPtrs[pcp->byPhysicalUnit/2].npACB;
          UnitId = pcp->byPhysicalUnit % 2;

          // Verify the input physical unit translates to an active
          // and valid UnitId.
          if( (UnitId >= npACB->cUnits) ||
              (npACB->UnitCB[UnitId].Flags & UCBF_NODASDSUPPORT) )
          {
             rc = IOERR_UNIT_NOT_READY;
             break;
          }

          memcpy(pRP_IOCTL->DataPacket,
                 (PBYTE) &npACB->UnitCB[UnitId].DeviceCounters,
                 sizeof(DeviceCountersData));

          /*  Begin [007] No longer clear counters after read */

//          setmem((PBYTE) &npACB->UnitCB[UnitId].DeviceCounters +
//                    sizeof(npACB->UnitCB[UnitId].DeviceCounters.wRevisionNumber),
//                 0,
//                 sizeof(DeviceCountersData) -
//                    sizeof(npACB->UnitCB[UnitId].DeviceCounters.wRevisionNumber) );

          /* End [007] */

        }
        rc = 0;
        break;
#endif

      case DSKSP_GET_UNIT_INFORMATION:
        {
          NPACB                   npACB;
          USHORT                  UnitId;
          PUnitInformationData    ui = (PUnitInformationData)pRP_IOCTL->DataPacket;

          /* Begin [005] */

          if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                    sizeof(UnitInformationData),
                                    OFFSETOF(pRP_IOCTL->DataPacket),
                                    VERIFY_READWRITE) )
          {
            StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
            return;
          }

          /* End [005] */

          // Verify the input physical unit translates to an active
          // and valid ACB.
          if( pcp->byPhysicalUnit/2 >= cAdapters )
          {
             rc = IOERR_UNIT_NOT_READY;
             break;
          }

          npACB = ACBPtrs[pcp->byPhysicalUnit/2].npACB;
          UnitId = pcp->byPhysicalUnit % 2;

          // Verify the input physical unit translates to an active
          // and valid UnitId.
          if( (UnitId >= npACB->cUnits) ||
              (npACB->UnitCB[UnitId].Flags & UCBF_NODASDSUPPORT) )
          {
             rc = IOERR_UNIT_NOT_READY;
             break;
          }

          ui->wRevisionNumber = 0;
          ui->wTaskFileBase = npACB->IOPorts[FI_PDAT];
          ui->wAlternateStatusAddress = npACB->IOPorts[FI_RFDR];
          ui->wIRQ = npACB->IntLevel;
          ui->wFlags |= UIF_VALID;
          ui->wFlags |= ((pcp->byPhysicalUnit/2) < 2) ? UIF_TIMINGS_VALID : 0;
          ui->wFlags |= (npACB->UnitCB[UnitId].Flags & UCBF_BM_DMA) ?
              UIF_RUNNING_BMDMA : 0;
          ui->wFlags |= (npACB->UnitCB[UnitId].Flags & UCBF_DMAMODE) ?
              UIF_RUNNING_DMA : 0;
          ui->wFlags |= (UnitId) ? UIF_SLAVE : 0;
          ui->wFlags |= (npACB->UnitCB[UnitId].Flags & UCBF_ATAPIDEVICE) ?
              UIF_ATAPI : 0;
          ui->byPIO_Mode = npACB->UnitCB[UnitId].CurPIOMode;
          ui->byDMA_Mode = npACB->UnitCB[UnitId].CurDMAMode;
        }
        rc = 0;
        break;

    /* End [002] */

      case DSKSP_GET_INQUIRY_DATA:
        {                                                           /*@V151345*/
          NPACB                   npACB;                            /*@VVVVVVV*/
          NPUCB                   npUCB;
          USHORT                  UnitId;

          /* Begin [005] */

          if ( DevHelp_VerifyAccess(SELECTOROF(pRP_IOCTL->DataPacket),
                                    sizeof(IDENTIFYDATA),
                                    OFFSETOF(pRP_IOCTL->DataPacket),
                                    VERIFY_READWRITE) )
          {
            StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
            return;
          }

          /* End [005] */

          // Verify the input physical unit translates to an active
          // and valid ACB.
          if( pcp->byPhysicalUnit/2 >= cAdapters )
          {
             rc = IOERR_UNIT_NOT_READY;
             break;
          }

          npACB = ACBPtrs[pcp->byPhysicalUnit/2].npACB;
          UnitId = pcp->byPhysicalUnit % 2;

          if ( (UnitId >= npACB->cUnits) ||
               (npACB->UnitCB[UnitId].Flags & UCBF_NODASDSUPPORT) )
          {
          rc= IOERR_UNIT_NOT_READY;
          }
          else
            {
            npUCB = &npACB->UnitCB[UnitId];
            npACB->UnitId = npUCB->UnitId;
            npACB->npUCB  = npUCB;
            rc = GetInquiryData( npUCB, pRP_IOCTL->DataPacket, 512 );
            }                                                      /*@AAAAAAA*/
        }                                                          /*@V151345*/
        break;
    }
  }
  else if ( pRP_IOCTL->Category == DSKSP_CAT_TEST_CALLS )
  {
    switch ( pRP_IOCTL->Function )
    {
      case DSKSP_TEST_CONFIGURE_UNIT:

        /* Begin [005] */

        if ( DevHelp_VerifyAccess(SELECTOROF(pcp),
                                  sizeof(ConfigureUnitParameters),
                                  OFFSETOF(pcp),
                                  VERIFY_READONLY) )
        {
          StatusError( (PRPH) pRP_IOCTL, STATUS_DONE |  STERR | STATUS_ERR_INVPAR );
          return;
        }

        /* End [005] */

        /* Begin [006] */

#ifdef ENABLE_SET_TIMINGS

        rc = SetTimingModes( (PConfigureUnitParameters) pcp );

#endif
      /* End [006] */

        break;
    }
  }
  else
  {
  }

  if ( rc )
  {
    if ( rc == IOERR_UNIT_NOT_READY )
    {
      status |= STERR | 0x0002;   /* unit not ready error */
    }
    else
    {
      status |= STATUS_ERR_UNKCMD;
    }
  }

  StatusError( (PRPH) pRP_IOCTL, status );
}

/* End [001] */


/*roman16*/
/**********************************************************************
*   Function:          ProcessStandby()
*  
*   Description:       Checks all units attached to every adapter.
*                      In case it is a HDD function calls the IssueStandby() 
*                      to send a STANDBY command to specified unit.
*
***********************************************************************/
   int ProcessStandby()                                                  //@roman16
   {                                                                     //@roman16
      int i,j,rc=1;                                                      //@roman16
      NPACB npACB;                                                       //@roman16
      
      if(!Shutdown)                                                      //@roman16
         return rc;                                                      //@roman16

      for(i=0;i<cAdapters;i++)                                           //@roman16
        {   npACB=ACBPtrs[i].npACB;                                      //@roman16
      for(j=0;j<npACB->cUnits;j++)                                       //@roman16
      {   if( !(npACB->UnitCB[j].Flags & UCBF_NODASDSUPPORT)             //@roman16
              && !(npACB->UnitCB[j].Flags & UCBF_NOTPRESENT)             //@roman16
              && !(npACB->UnitCB[j].Flags & UCBF_REMOVABLE)              //@roman16
              && !(npACB->UnitCB[j].Flags & UCBF_ATAPIDEVICE))           //@roman16
               {  rc=IssueStandby(npACB,j);                              //@roman16
               }//endif                                                  //@roman16 


      }//endfor j                                                        //@roman16
  }//endfor i                                                            //@roman16
             return rc;                                                  //@roman16
   }                                                                     //@roman16


/***********************************************************************
*   Function:           IssueStandby(npACB,UnitID)
*
*   Description:        Prepares a Device Control IORB with the IDE command
*                       STANDBY and issues it to a specified Unit.
*         
*   Variables:         npACB - current adapter's control block
*                      UnitID - specifies a unit attachet to the adapter.
*  
*   Notes:             Dual opcodes for STANDBY command has been realised.
*                      In case of failing with the fist opcode function will try 
*                      to process STANDBY with the second one.
*                      (Second opcode needed for older HDDs)
*
************************************************************************/



int IssueStandby(NPACB npACB,USHORT UnitID)                              //@roman16
{                                                                        //@roman16
   /* Preparing the Device Control IORB */
   if(!SecondOpcode)                                                     //@roman16 If memory is already alloced don't allocate it
   {   setmem((PBYTE) &npACB->PTIORB,0,sizeof(npACB->PTIORB));           //@roman16
       setmem((PBYTE) &npACB->icp,0,sizeof(npACB->icp));                 //@roman16
       npACB->icp.TaskFileIn.Command=FX_STANDBY; //The first opcode      //@roman16
   }                                                                     //@roman16
   else                                                                  //@roman16
      npACB->icp.TaskFileIn.Command=FX_STANDBY2; //The second opcode     //@roman16
//   npACB->icp.TaskFileIn.SectorCount=Shutdown;   // Need a non zero value to process STANDBY //@roman16 //removed with @JR13839
   npACB->icp.TaskFileIn.SectorCount=0;                    //@JR13839 - Need 0 to prevent from setting up the h/w timer
   npACB->icp.RegisterTransferMap=PTA_RTMWR_COMMAND|                     //@roman16
                                  PTA_RTMWR_SECTORCOUNT|                 //@roman16
                                  PTA_RTMRD_CYLINDERHIGH|                //@roman16
                                  PTA_RTMRD_CYLINDERLOW|                 //@roman16
                                  PTA_RTMRD_ERROR|                       //@roman16
                                  PTA_RTMRD_STATUS;                      //@roman16

   npACB->PTIORB.iorbh.Length=sizeof(IORB_ADAPTER_PASSTHRU);             //@roman16
   npACB->PTIORB.iorbh.UnitHandle=(USHORT) &npACB->UnitCB[UnitID];       //@roman16
   npACB->PTIORB.iorbh.CommandCode=IOCC_ADAPTER_PASSTHRU;                //@roman16
   npACB->PTIORB.iorbh.CommandModifier=IOCM_EXECUTE_ATA;                 //@roman16
   npACB->PTIORB.iorbh.RequestControl=IORB_ASYNC_POST | IORB_DISABLE_RETRY; //@roman16
   npACB->PTIORB.iorbh.NotifyAddress=NotifyIORBDone;
   npACB->PTIORB.pControllerCmd=(PBYTE) &npACB->icp;                     //@roman16
   npACB->PTIORB.Flags=PT_DIRECTION_IN;                                  //@roman16

   /* Send this IORB to Adapter's Entry point to process it */
   ADDEntryPoint((PIORB) &npACB->PTIORB);                                //@roman16

   /*Wait for completion*/
   DISABLE                                                               //@roman16

   while(!(npACB->PTIORB.iorbh.Status & IORB_DONE))                                  //@roman16
   {    DevHelp_ProcBlock((ULONG)(PIORB) &npACB->PTIORB,-1,WAIT_IS_INTERRUPTABLE);   //@roman16
        DISABLE                                                          //@roman16
   }                                                                     //@roman16

   ENABLE                                                                //@roman16

   if(npACB->icp.TaskFileOut.Status & FX_ERROR) //Is there some errors?  //@roman16
   {   if(!SecondOpcode)   //If error occur with First opcode try it with the socond one //@roman16
        {SecondOpcode=1;                                                 //@roman16
         IssueStandby(npACB,UnitID);}                                    //@roman16
       
       npACB->PTIORB.iorbh.Status|=IORB_ERROR;                           //@roman16
       npACB->PTIORB.iorbh.ErrorCode=IOERR_DEVICE_REQ_NOT_SUPPORTED;     //@roman16
   }                                                                     //@roman16
   SecondOpcode=0;                                                       //@roman16
   return((npACB->PTIORB.iorbh.Status & IORB_ERROR) ? npACB->PTIORB.iorbh.ErrorCode : 0 );  //@roman16
                                                                         //@roman16
}

/*roman16*/

