/*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/s506init.c, idskflt, c.basedd, fixbld 00/02/29 */
/**************************************************************************
 *
 * SOURCE FILE NAME = S506INIT.C
 *
 * DESCRIPTIVE NAME = IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Adapter Driver initialization routines.
 *
 * Purpose:
 *
 *
 *
 *
 *
*//*
 * Edit History for defect # 148406:
 *
 * Edit    Date    Comments
 * ----- --------  -------------------------------------------------------------
 * [001] 05-12-95  Integrated changes Shishir Shah made to original 2.1 version
 *                 of IBM1S506 driver to implement block mode and slave DMA. In
 *                 this file the changes were in several areas: /jlh
 *
 *      1) In ParseCmdLineOption()
 *          - Test for System Type EISA and/OR PCI
 *              - If EISA and PCI, scatter/gather will be ON at Default Base
 *                  Port 400h
 *              - If EISA/ISA or EISA/PCI then DMA Type will be set to type B.
 *              - If PCI/ISA then DMA Type will be set to type F.
 *              - User Input required for DMA Channel number to turn on DMA
 *      2) In ConfigureController()
 *          - Initialize DMA channel ports for specified adapter.
 *          - Set DMA scatter/gather flag for specified adapter.
 *      3) In DetermineUnitGeometry()
 *          - If WDC drive or supported OEM system then
 *              - Turn on LBA mode if supported by drive
 *              - Turn on DMA mode if supported by drive
 *      4) In PrintInfo()
 *          - Added DMA scatter/gather text to message.
 *      5) Add CheckSystemDMAType()
 *          - This function determines the support system DMA type (B/F) and
 *            returns this information to the caller.
 *
 * [002] 06-01-95  Add Bus Master DMA capabilities to merged driver. /jlh
 *      1) Add enhanced informational messages for DMA enabled and type.
 *      2) In CheckSystemDMAType()
 *          - Add checks for Triton PCI Bus Master IDE DMA controller
 *          - Add npACB parameter so it can store the Bus Master registers
 *
 * [003] 08-31-95  Integrated latest IBM driver changes. IBM changes flagged with
 *                 unique IBM change codes as in table above. /jlh
 *
 * [004] 09-15-95  Modify support for Bus Master DMA switches. /jlh
 *      1) Get rid of switch for force enable of Bus Master DMA.
 *      2) Move handling of Bus Master DMA switches from the
 *         ConfigureATAPIDevice and DetermineUnitGeometry functions
 *         to the main code in DriveInit.
 *
 * [005] 09-25-95  Fix problem with /!BM switch after /UNIT:x switch not working.
 *                 also affects other switches that use Mask variable which was
 *                 USHORT instead of ULONG. /jlh
 * [006] 10-05-96  Fix problem with PCIInfo being corrupted so that
 *                 timing setup is not performed. /jlh
 *
 * [007] 11-20-95  Add code to correct ATAPI timing configuration and
 *                 display timings picked for ATAPI devices. /jlh
 *
 * [008] 11-29-96  Add IODelay() after each outp in set mode sequences. /mol
 *
 * [009] 11-29-95  Add PIIX3 slave IDE timing support:                  /mol
 *       1) In DriveInit()   - added PIIX3 presence check.
 *                           - added PIIX3 SIDETIM programmnig.
 *       2) CalculateAdapterTiming() takes 2 more params: PIIX3Present and uChannel.

 *          If PIIX3Present is TRUE it updates piix3_SIDETim with timings for
 *          the slave drives.  If PIIX3 isn't present it initializes npACB->PIIX_IDEtim
 *          only, with the best timing for both master and slave.  uChannel (TURE =
 *          Primary, FALSE = Secondary ) is used to determine the shift offset for
 *          SIDETIM bit fields.
 *       3) In CheckSystemDMAType() added PIIX3 presence check.
 *
 * [010] 11-29-95  Add support for 2 PIIX mobile configuration:         /mol
 *       1) In DriveInit() add check for 2-nd PIIX chip and bus master register init.
 *
 * [011] 11-29-95  In CheckSystemDMAType() add search for Orion chipset id and, if found,
 *                 disable bus master IDE xfers if its revision id. is less than 04. /mol
 *
 * [012] 11-30-95 Fixed Scater/Gather allocation, the case when the larger
 *                 chunk of the buffer is after a 4K boundary. /mol
 *
 * [013] 12-21-95 Shuffle around some declarations to ease integration
 *                of IOCTL function to change timings. /jlh
 *       1) Moved declaration for piix3_SIDETim in ACB structure. [later deleted]
 *       2) Moved declaration for PIIX3Present to global permanent
 *          storage.
 *
 * [014] 01-19-96 Set D0DMA and D1DMA bits in BMISTA as appropriate for
 *                devices detect on the channels. This information is
 *                used by the Bus Master ATAPI CD-ROM driver to identify
 *                devices to run DMA on. /jlh
 *
 * [015] 01-19-96 Process ATBM_BM_DMA switches for ATAPI CD-ROM. /jlh
 *
 * Edit History for defect # 152648:
 *
 * Edit    Date    Comments
 * ----- --------  -------------------------------------------------------------
 *
 * [016] 02-01-96 Change CalculateAdapterTiming() to always use 33/30MHz settings.
 *                This eliminates the sensitivity to the ISA Clock Speed switch
 *                setting, with a small performance penalty in 25MHz systems./mol
 *
 * [017] 02-16-96 To calculate and program slave timings, we must use the
 *                global piix3_SIDETim. /mol
 *
 * [018] 02-17-96 Workaround for CD-ROM devices that remain in an unstable state after
 *                an ATA command.
 *       1) In DoATAPIPresenseCheck(), add ATAPI reset in the case when DoIdentify
 *          returns with error, before checking ATAPI signature. Some CD-ROM devices
 *          don't show the ATAPI signature after an ATA (Identify) command.
 *       2) In DeviceInit(), before set features, change test for RDY with test for
 *          non-BSY. CD-ROM devices may not set DRDY bit prior to programming the IDE
 *          register file.
 *       3) In DeviceInit(), add ATAPIReset() after setting features.
 *
 * [019] 02-17-96 In ParseCmdLine(), make BM option insensitive to the order the
 *                units are specified on the command line. /mol
 *
 * [020] 02-19-96 In DeviceInit(), call ConfigureATAPIDevice() for the case of a single
 *                slave ATAPI device./mol
 *
 * [021] 03-06-96  Add support for Micro House EzDrive. This includes special support for
 *                 solution for drives > 2.1 GB (more than 4095 cylinders). Some Phoenix,
 *                 AMI, and Award BIOS have problems when drives reporting more than 4095
 *                 cylinders are installed. Problems range from truncation of capacity at
 *                 2.1 GB to system lockups. The solution is for drives to lie about their
 *                 number of cylinders through word 1 of identify data. A special INT13
 *                 hooker such as EzDrive or Disk Manager must then be used to access the
 *                 full drive capacity. We must therefore take the drive geometry
 *                 information from the EzDrive internal tables rather than trying to
 *                 figure out what the drive and software are thinking. The added code
 *                 will check for EzDrive present. If it is it will indicate so in the
 *                 saved adapter/device information tables. It will then use the geometry
 *                 supplied in the EzDrive Enhanced Drive Parameter Tables as the logical
 *                 and physical geometries. It will also check for EzDrive floppy boot
 *                 protection. Any device that has this enabled has its partition table on
 *                 0, 0, 2 rather than 0, 0, 1 (C,H,S) as a safety precaution. /jlh
 *
 * [022] 02-22-96 Workaround for CR-581 CD-ROM.  This devices needs few seconds after an
 *                ATAPI reset to show the ATAPI signature./mol
 *
 * [023] 04-11-96  Fix problem with ordering of switches for /BM commands. This ordering
 *                 problem was caused by the fact that a new /U:x did not clear the PCF
 *                 flag for the prior /U:x switch. Also deleted code to enable bus master
 *                 DMA on a per adapter basis. It didn't work and it also didn't really
 *                 make sense to allow this. The code for disabling bus master DMA on a
 *                 per adapter basis was modified to set the no bus master DMA flags for
 *                 each unit on the adapter. /jlh
*/

 #define INCL_NOPMAPI
 #define INCL_DOSINFOSEG                                            /*@V153620*/
 #define INCL_NO_SCB
 #define INCL_INITRP_ONLY
 #define INCL_DOSERRORS
 #include "os2.h"
 #include "dos.h"
 #include "bseerr.h"
 #include "dskinit.h"
 #include <scb.h>
 #include <abios.h>

 #include "devhdr.h"
 #include "iorb.h"
 #include "reqpkt.h"
 #include "dhcalls.h"
 #include "addcalls.h"
 #include "devclass.h"

 #include "s506cons.h"
 #include "s506type.h"
 #include "s506regs.h"
 #include "s506ext.h"
 #include "s506pro.h"
 #include "s506misc.h"
 #include "s506ps2.h"

/* [002.2] comment out following define if compile is for non-restricted version */
/*         otherwise this driver only enables DMA and some other features if a */
/*         Western Digital drive is present in the system. */        /*@V151345*/

/*------------------------------------*/
/*                                    */
/*                                    */
/*------------------------------------*/
VOID FAR NotifyIORBDone( PIORB pIORB )
{
  USHORT        AwakeCount;

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

/*------------------------------------------------------*/          /*@V147576*/
/*  CheckController()                                   */          /*@VVVVVVV*/
/*                                                      */
/*  Determine if there are any devices on the IDE port  */
/*  identified by npAT.  Initially assume the bios has  */
/*  correctly configured the IDE interface and test for */
/*  the presense of any devices.  If no devices are     */
/*  found then attempt to flip the status of the IDE    */
/*  port and test again.                                */
/*                                                      */
/*------------------------------------------------------*/
USHORT NEAR CheckController( NPATBL npAT )
{
   USHORT        rc;
   SHORT         PortState = INDETERMINANT;

   /*
   ** Check for possible devices on this IDE port.
   */
   rc = CheckCylinderLRegs( npAT );

   if( npAT->PCIInfo.Present && npAT->PCIInfo.Ident.PCIFunc_PortState )
   {
      /*
      ** A PCI chip was detected and a PortState function is defined
      ** for it.  Get the current state of the IDE port.
      */
      PortState = npAT->PCIInfo.Ident.PCIFunc_PortState( npAT );

      switch( PortState )
      {
      case ON:
         if( rc && npAT->PCIInfo.Ident.PCIFunc_TurnPort )
         {
            PortState = npAT->PCIInfo.Ident.PCIFunc_TurnPort( npAT, OFF );

            if( PortState == OFF )
            {
               /* Check again. */
               rc = CheckCylinderLRegs( npAT );
               /*
               ** If devices were detected, leave the port switched
               ** OFF, otherwise turn it back ON.
               */
               if( rc )
               {
                  npAT->PCIInfo.Ident.PCIFunc_TurnPort( npAT, ON );
                  npAT->PCIInfo.Present = FALSE;
               }
            }
         }
         break;

      case OFF:
         if( rc && npAT->PCIInfo.Ident.PCIFunc_TurnPort )
         {
            PortState = npAT->PCIInfo.Ident.PCIFunc_TurnPort( npAT, ON );

            if( PortState == ON )
            {
               /* Check again. */
               rc = CheckCylinderLRegs( npAT );
               /*
               ** If devices were detected, leave the port switched
               ** ON, otherwise turn it back OFF.
               */
               if( rc )
               {
                  npAT->PCIInfo.Ident.PCIFunc_TurnPort( npAT, OFF );
               }
            }
         }
         else
         {
            npAT->PCIInfo.Present = FALSE;
         }
         break;

      case INDETERMINANT:
         if( rc )
         {
            npAT->PCIInfo.Present = FALSE;
         }
         break;
      }
   }
   else if( rc && !npAT->PCIInfo.Present )
   {
      /*
      ** This port setup is valid only for older IBM ValuePoint machines
      ** that need special initialization on the IDE port HW, non-PCI.
      */
      // Here we know an ATA device has not been detected and       /*@V182291*/
      // it will not be controlled by PCI hardware so it could be   /*@V182291*/
      // a PS2IDE device.  So turn on the PS2IDE port and try       /*@V182291*/
      // again to detect the device.                                /*@V182291*/
      SetupPS2IDEPort( npAT->BasePort, ON );                        /*@V182291*/
                                                                    /*@V182291*/
      // Look for the device again.                                 /*@V182291*/
      rc = CheckCylinderLRegs( npAT );                              /*@V182291*/
      if( rc ) {                                                    /*@V182291*/
         // Detection failed so leave the port OFF.                 /*@V182291*/
         SetupPS2IDEPort( npAT->BasePort, OFF );                    /*@V182291*/
      }                                                             /*@V182291*/
      else {                                                        /*@V182291*/
         // Detection succeeded, after turning the port on, so      /*@V182291*/
         // this is a PS2IDE which needs to have it's disk light    /*@V182291*/
         // controlled by this driver.                              /*@V182291*/
         npAT->Flags |= ATBF_PS2IDEPORT;                            /*@V182291*/
      }                                                             /*@V182291*/
   }

   return( rc );                                                    /*@AAAAAAA*/
}                                                                   /*@V147576*/


/*---------------------------------------------*/                   /*@V147576*/
/*  CheckCylinderLRegs()                       */                   /*@VVVVVVV*/
/*                                             */
/*  Check for the presense of any devices on   */
/*  on the input IDE port.                     */
/*---------------------------------------------*/
USHORT NEAR CheckCylinderLRegs( NPATBL npAT )
{
   USHORT    rc;

   rc = CheckCylinderLReg( npAT, 0 );                               /*@V93625*/

   if( rc )                                                         /*@V108783*/
   {                                                                /*@V108783*/
      DISABLE                                                       /*@V108783*/
      rc = CheckCylinderLReg( npAT, 1 );                            /*@V108783*/
      ENABLE                                                        /*@V108783*/
   }                                                                /*@V108783*/

   return( rc );                                                    /*@AAAAAAA*/
}                                                                   /*@V147576*/


/*------------------------------------*/
/*                                    */
/*                                    */
/*                                    */
/*------------------------------------*/
USHORT NEAR CheckCylinderLReg( NPATBL npAT, USHORT UnitId )        /*@V93625*/
{
  USHORT        i;
  USHORT        j;
  USHORT        i_Inv;                                            /*@V106915*/
  USHORT        Port;
  USHORT        SectorReg;                                        /*@V106915*/

  USHORT        devhdPort;                               // Start defect: 218501
  USHORT        devhdData;

  /*---------------------------*/
  /* Insure UnitId is selected */
  /*---------------------------*/
  devhdPort = npAT->BasePort + 6;

  /*--------------------*/                                         /*@V87325*/
  /* Save Register Data */                                         /*@V87325*/
  /*--------------------*/                                         /*@V87325*/
  inp( devhdPort, devhdData );
  IODelay();                                                       /*@V87325*/

  i = (UnitId) ?  0xB0 : 0xA0; /* Select Unit */                   /*@V93625*/
  outp( devhdPort, i );
  IODelay();                                               // End defect: 218501

  /*----------------------------------------------*/
  /* Read/Write data patterns to the Cylinder reg */
  /*----------------------------------------------*/
  Port      = npAT->BasePort + 4;                                  /*@V87325*/
  SectorReg = npAT->BasePort + 2;                                  /*@V106915*/

  i = -1;

  do
  {
    i++;
    outp( Port, i);
    IODelay();
    /*----------------------------------------------------------------------*/
    /* output the bitwise or of the data to another register.  This ensures */
    /* the data that we read back in the in is from the register and not    */
    /* transient data on the bus.                                           */
    /*----------------------------------------------------------------------*/
    i_Inv = ~i;                                                   /*@V147576*/
    outp( SectorReg, i_Inv );                                     /*@V106915*/
    IODelay();                                                    /*@V106915*/
    inp( Port, j );
    IODelay();
  }
  while ( i < 0x81 && i == j );

  /*-----------------------*/                                      /*@V87325*/
  /* Restore Register Data */                                      /*@V87325*/
  /*-----------------------*/                                      /*@V87325*/
  outp( devhdPort, devhdData );                                    
  IODelay();                                                       /*@V87325*/

  return ( !(i == j) );                                            /*@AAAAAAA*/
}                                                                  /*@V151345*/


/*------------------------------------*/
/*                                    */
/* ResetController()                  */
/*                                    */
/*------------------------------------*/
VOID NEAR ResetController( NPACB npACB )
{
  NPIORB_EXECUTEIO      npTI = &InitIORB;

  npACB->ReqFlags=npACB->UnitCB[0].ReqFlags = ACBR_RESETCONTROLLER;

  setmem( (PBYTE) npTI, 0, sizeof(IORB_EXECUTEIO) );

  npTI->iorbh.Length          = sizeof(IORB_EXECUTEIO);
  npTI->iorbh.UnitHandle      = (USHORT) &npACB->UnitCB[0];
  npTI->iorbh.CommandCode     = IOCC_EXECUTE_IO;
  npTI->iorbh.CommandModifier = IOCM_NO_OPERATION;
  npTI->iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
  npTI->iorbh.NotifyAddress   = NotifyIORBDone;

  ADDEntryPoint( (PIORB) npTI );

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

  npACB->UnitCB[0].ReqFlags = 0;

  return;
}

/*------------------------------------*/
/*                                    */
/* DriveInit()                        */
/*                                    */
/*------------------------------------*/
VOID NEAR DriveInit(PRPINITIN pRPH )
{
  PRPINITIN             pRPI = (PRPINITIN)  pRPH;
  PRPINITOUT            pRPO = (PRPINITOUT) pRPH;
  NPATBL                npAT = AdapterTable;
  PMACHINE_CONFIG_INFO  pMCHI;
  USHORT                i;
  BOOL                  rc;
  USHORT                DriveId;
  BOOL                  ApmRegistered = FALSE;                      /*@V155162*/
  PSEL                  p;                                          /*@V153620*/
  PGINFOSEG             pGlobal=0;                                  /*@V153620*/
  USHORT                SystemType = 0;

  Device_Help = pRPH->DevHlpEP;

  if( rc = DevHelp_GetDOSVar( DHGETDOSV_SYSINFOSEG,                 /*@V153620*/
                              0, (PPVOID)&p ) )                     /*@V153620*/
  {                                                                 /*@V153620*/
     _asm int 3                                                     /*@V153620*/
  }                                                                 /*@V153620*/
  SELECTOROF(pGlobal) = *p;                                         /*@V153620*/
  pMCHI           =  (PMACHINE_CONFIG_INFO) pRPH->InitArgs;           /*@V154573*/
  OFFSETOF(pMCHI) = ((PDDD_PARM_LIST) pMCHI)->machine_config_table;   /*@VVVVVVV*/

  SystemType = 0;               /* DMA type unknown */           /*@V154573*/ /*@V179942*/

  if( pMCHI->BusInfo & BUSINFO_MCA )
  {
     DriverBusType = BUS_MCA;
  }
  else if( pMCHI->BusInfo & BUSINFO_EISA )
  {
     DriverBusType = BUS_EISA;
     SystemType    = SDMA_TYPE_B;            /* DMA type B */    /*@V154573*/ /*@V179942*/
  }
  else if( pMCHI->BusInfo & BUSINFO_PCI )
  {
     DriverBusType = BUS_PCI;
     SystemType    = SDMA_TYPE_F;            /* DMA type F */     /*@V154573*/ /*@V179942*/
  }
  else
  {
     DriverBusType = BUS_UNKNOWN;
  }                                                                 /*@V154573*/

  /*-----------------------------------------*/                     /*@V98451*/
  /* Put name from Config.sys in DrvrName of */                     /*@V98451*/
  /* the DriverStruct structure.             */                     /*@V98451*/
  /*-----------------------------------------*/                     /*@V98451*/
                                                                    /*@V98451*/
  RMGetDriverName (pRPI, DriverStruct.DrvrName, DrvrNameSize);      /*@V98451*/
                                                                    /*@V98451*/
  /*---------------------------------------------------*/           /*@V98451*/
  /* Allocate Driver Handle                            */           /*@V98451*/
  /*                                                   */           /*@V98451*/
  /* Most of this data is 'canned' and is discard      */           /*@V98451*/
  /* after initialization completes.                   */           /*@V98451*/
  /*---------------------------------------------------*/           /*@V98451*/
  if(RMCreateDriver(&DriverStruct,                                  /*@V98451*/
                    &hDriver))                                      /*@V98451*/
  {                                                                 /*@V98451*/
     _asm int 3                                                     /*@V98451*/
  }                                                                 /*@V98451*/

  pDDD_Parm_List = (PDDD_PARM_LIST) pRPI->InitArgs;

  InitActive = 1;

  /*-----------------------------------------------*/
  /* Transfer information from Machine Info packet */
  /*-----------------------------------------------*/
  pMCHI = MAKEP( SELECTOROF(pDDD_Parm_List),
                 (USHORT)   pDDD_Parm_List->machine_config_table );

  MachineID = (pMCHI->Model << 8) | pMCHI->SubModel;

  /*------------------------------------------*/
  /* If this is a uChannel machine, deinstall */
  /* this driver.                             */
  /*------------------------------------------*/
  if ( pMCHI->BusInfo & BUSINFO_MCA )
  {
    #ifdef MCA                                                          /*@V117508*/
     /*---------------------------------------*/                     /*@V119250*/
     /* We do not want to do the CMD640 check */                     /*@V119250*/
     /* on a micro-channel system             */                     /*@V119250*/
     /*---------------------------------------*/                     /*@V119250*/
     if (!Get_IDE_LID ( npAT, pMCHI ))                               /*@V117508*/
        goto S506_Deinstall;                                         /*@V117508*/
    #else                                                               /*@V117508*/
     rc = TRUE;
     goto S506_Deinstall;
    #endif                                                              /*@V117508*/
  }

  SystemType = DeterminePCIChips( SystemType );                       /*@217469*/

  /*---------------------------------------------------------------*/ /*@V156660 - moved after PCI detection */
  /* Modify defaults in ADAPTER TABLE per command line parameters. */
  /* SystemType is the system bus type and DMA type, determined    */
  /* above when IDE interfaces were identified.                    */
  /*---------------------------------------------------------------*/
  if ( ParseCmdLine( pDDD_Parm_List, npAT, SystemType ) )           /*@V156660 - moved & modified */
  {                                                                 /*@V156660 - moved */
    TTYWrite( ParmErrMsg );                                         /*@V156660 - moved */
  }                                                                 /*@V156660 - moved */

  rc = FALSE;

  /*--------------------------------------------*/                  /*@V106915*/
  /* Check for DPT adapters which require a     */                  /*@V106915*/
  /* status read in order to clear an interrupt */                  /*@V106915*/
  /*--------------------------------------------*/                  /*@V106915*/
  ChkIfDPT_Present();                                               /*@217469*/

  ADD_InitTimer( TimerPool, sizeof(TimerPool));

  /*                                                                  @V155162
  ** Register this driver with PCMCIA socket services if there        @V155162
  ** were any PCMICA adapters specified on the command line.          @V155162
  */                                                                /*@V155162*/
  for( i = 0; i < MAX_ADAPTERS; i++, npAT++ )                       /*@V155162*/
  {                                                                 /*@V155162*/
     if( npAT->Flags & ATBF_PCMCIA )                                /*@V155162*/
     {                                                              /*@V155162*/
        if( !ApmRegistered )                                        /*@V155162*/
        {                                                           /*@V155162*/
           PCMCIASetup();                                           /*@V155162*/
           ApmRegistered = TRUE;                                    /*@V155162*/
        }                                                           /*@V155162*/
        /*                                                            @V155162
        ** Adapter detection on the PCI bus will be performed         @V155162
        ** unless we disable it.  Since the current adapter is        @V155162
        ** on the PCMCIA bus, it can't be on the PCI bus so           @V155162
        ** disable searchs on the PCI bus for this IDE adapter.       @V155162
        */                                                          /*@V155162*/
        npAT->PCIInfo.Present = FALSE;                              /*@V155162*/
     }                                                              /*@V155162*/
  }                                                                 /*@V155162*/

  /*----------------------------------------*/
  /* Setup each Adapter. Scan each adapter  */
  /* for drives (units).                    */
  /*----------------------------------------*/
  DriveId = ScanForOtherADDs() + 0x80;

  /*                                                                  @V153620
  ** if Merlin or later get the PnP detected devices                  @V153620
  */                                                                /*@V153620*/
  if( (pGlobal->uchMajorVersion > 20) ||                            /*@V166306*/
      ( (pGlobal->uchMajorVersion == 20) &&                         /*@V166306*/
        (pGlobal->uchMinorVersion > 30) ) )                         /*@V166306*/
  {                                                                 /*@V153620*/
     FindDetected( FALSE );                                         /*@V153620*/
     FindDetected( TRUE );                                          /*@V153620*/
  } /* endif */                                                     /*@V153620*/

  // Create a mini-VDM to get int 13 (BIOS) data.                   /*@V192176*/
  if( !VDMInt13Create() )                                           /*@V192176*/
  {                                                                 /*@V192176*/
     VDMInt13Created = TRUE;                                        /*@V192176*/
  }                                                                 /*@V192176*/

  CkAdapters4Units( DriveId );                                      /*@217469*/

  // Destroy the mini-VDM.                                          /*@V192176*/
  if( VDMInt13Created )                                             /*@V192176*/
  {                                                                 /*@V192176*/
     VDMInt13Destroy();                                             /*@V192176*/
  }                                                                 /*@V192176*/
  
  /*--------------------------------------------------*/
  /* Do a final read verify on each unit to clear any */
  /* pending Recalibrate or Set Parameter requests    */
  /*--------------------------------------------------*/
  FinalReadVerify();                                               /*@217469*/

  /**************************************************************************/
  /* Begin [002.2] Process only for first two IDE adapters as that is all   */
  /*               Triton PIIX chip has. Other channels cannot run Bus      */
  /*               Master DMA nor be configured through PIIX chip           */
  /**************************************************************************/

  SetupPCIChips();                                                  /*@217469*/

  if ( Verbose )
  {
     PrintInfo( AdapterTable );
  }

  if ( !cUnits )
  {
    ADD_DeInstallTimer();

    rc = TRUE;
    goto S506_Deinstall;
  }

  pRPO->CodeEnd     = (USHORT) &DriveInit;
  pRPO->DataEnd     = (USHORT) npACBPool;
  pRPO->rph.Status  = STDON;

  if ( DevHelp_RegisterDeviceClass( (NPSZ)     AdapterName,
                                    (PFN)      &ADDEntryPoint,
                                    (USHORT)   0,
                                    (USHORT)   1,
                                    (PUSHORT)  &ADDHandle      )  )
  {
    _asm { int 3 }
  }

  AssignResources();                                                /*@V98451*/

  /*                                                                  @V156660
  ** Put any PCI Configuration Registers back to bios' state.         @V156660
  */                                                                /*@V156660*/
  for (i=0; i < cAdapters; i++ )                                    /*@V156660*/
  {                                                                 /*@V156660*/
    if( ACBPtrs[i].npACB->PCIInfo.Present )                         /*@V156660*/
       ConfigurePCI( ACBPtrs[i].npACB, PCIC_START_COMPLETE );       /*@V156660*/
  }                                                                 /*@V156660*/

  S506_Deinstall:

  if( rc )
  {
    pRPO->CodeEnd     = 0;
    pRPO->DataEnd     = 0;
    pRPO->rph.Status  = STDON + ERROR_I24_QUIET_INIT_FAIL;

    RMDestroyDriver(hDriver);                                       /*@V98451*/
  }

  InitActive = 0;
}

/*----------------------------------------------------------------*/
/*                                                                */
/*  ConfigureController()                                         */
/*                                                                */
/*  Activate the this controller's ACB:                           */
/*    - Move any initialization data required to persist from     */
/*      the Adapter Table (npAT) to the Adapter Control Block     */
/*      (npACB).                                                  */
/*    - Hook the IRQ.                                             */
/*                                                                */
/*----------------------------------------------------------------*/

USHORT NEAR ConfigureController( NPATBL npAT )
{
  NPACB          npACB;
  NPUTBL         npUT;                                              // 206371
  USHORT         rc = 0;
  USHORT         i;

  if (AllocAdapterResources(npAT))                                  /*@V98451*/
  {                                                                 /*@V98451*/
     /* AllocAdapterResources will assign the status to     */      /*@V98451*/
     /* npAT->Status for a failure on a resource allocation */      /*@V98451*/
                                                                    /*@V98451*/
     goto ConfigureControllerExit;                                  /*@V98451*/
  }                                                                 /*@V98451*/

  npACB = npAT->npACB = npACBPool;

  npACBPool++;

  ACBPtrs[cAdapters].npACB    = npACB;
  ACBPtrs[cAdapters].IRQLevel = npAT->IRQLevel;                    /*@V87325*/

  setmem((PBYTE) npACB, 0, sizeof(ACB) );

  for (i = FI_PDAT; i < FI_RFDR; i++ )
  {
    npACB->IOPorts[i] = npAT->BasePort + i;
  }
  npACB->IOPorts[FI_PERR]  = npACB->IOPorts[FI_PWRP];
  npACB->IOPorts[FI_PSTAT] = npACB->IOPorts[FI_PCMD];

  /*                                                                  @V153620
  ** if set exactly by PnP Snooper, srd                               @V153620
  */                                                                /*@V153620*/
  if( npAT->Flags & ATBF_CONTROLSPECIFIC )                          /*@V153620*/
  {                                                                 /*@V153620*/
     npACB->IOPorts[FI_RFDR] = npAT->StatusPort;                    /*@V153620*/
  } /* endif */                                                     /*@V153620*/
  else                                                              /*@V153620*/
  {                                                                 /*@V153620*/
     /*--------------------------------------------------------*/   /*@V64402*/
     /* Quantum Hardcards can use a Base Port of 0320. This    */   /*@V64402*/
     /* causes the Device Control Register (03x6) to be mapped */   /*@V64402*/
     /* at the same address as the Drive/Head register (01x6). */   /*@V64402*/
     /* Quantum uses address 032E as an alternate address.     */   /*@V64402*/
     /* for the Device Control Register.                       */   /*@V64402*/
     /*--------------------------------------------------------*/   /*@V64402*/
                                                                    /*@V64402*/
     npACB->IOPorts[FI_RFDR] =                                      /*@V64402*/
                  npACB->IOPorts[FI_PDRHD] |                        /*@V64402*/
                  ((npAT->BasePort & 0x0200) ? 0x0308 : 0x0300);    /*@V64402*/
  } /* endelse */                                                 /*@V153620*/

/* Begin [001.2] */

  npACB->DMAChannel      = npAT->DMA_Channel;
  npACB->DMACountPort    = npAT->DMA_Count_port;
  npACB->DMAAddrPort     = npAT->DMA_Addr_port;
  npACB->DMAAddrpagePort = npAT->DMA_Addr_page_port;
  npACB->DMAModePort     = npAT->DMA_Mode_port;
  npACB->DMAChainMode    = npAT->DMA_Chain_mode;
  npACB->DMAExtModePort  = npAT->DMA_Ext_Mode_port;
  npACB->DMAMaskPort     = npAT->DMA_Mask_port;
  npACB->DMAClrBytePtr   = npAT->DMA_Clr_Byte_ptr;
  npACB->DMASGDCmdPort   = npAT->DMA_SGD_Cmd_port;
  npACB->DMASGDPtrPort   = npAT->DMA_SGD_Ptr_port;

/* End [001.2] */

  npACB->IORegs[FI_RFDR]  = 0x08;

  npACB->IntLevel   = npAT->IRQLevel;
  npACB->Channel    = npAT->Channel;                            /*@217469*/

  npACB->TimeOut              = INIT_TIMEOUT_SHORT;
  npACB->IRQTimeOut           = INIT_TIMEOUT_SHORT;
  npACB->DelayedRetryInterval = DELAYED_RETRY_INTERVAL;
  npACB->DelayedResetInterval = DELAYED_RESET_INTERVAL;
  npACB->IRQEntry             = ACBPtrs[cAdapters].IRQHandler;

  for (i=0; i < MAX_UNITS; i++ )
  {
    npACB->UnitCB[i].UnitId = i;
    npACB->UnitCB[i].npACB  = npACB;
  }

  npACB->IOSGPtrs.iPortAddress = npACB->IOPorts[FI_PDAT];

  /*                                                                  @V129765
  ** Move any PCI Configuration data to the ACB.                      @V129765
  */                                                                /*@V129765*/
  if ( npAT->PCIInfo.Present )                                      /*@V129765*/
     npACB->PCIInfo = npAT->PCIInfo;                                /*@V129765*/
  else                                                              /*@V129765*/
     setmem( (PBYTE)&npACB->PCIInfo, 0, sizeof(PCI_INFO) );         /*@V129765*/

  /*----------------------------------------------------------*/   /*@V108783*/
  /* If an ATAPI device is set as slave and is the only       */   /*@V108783*/
  /* unit attached, a reset will a very long to time out.     */   /*@V108783*/
  /* CheckController will erase the first byte of the         */   /*@V108783*/
  /* signature, therefore it's existance must be checked here */   /*@V108783*/
  /*----------------------------------------------------------*/   /*@V108783*/
  for( i = 0; i < MAX_UNITS; i++ )
  {
     if( !CheckForATAPISignature( npAT, i ) )                      /*@V108783*//*@V192176*/
     {                                                             /*@V108783*//*@V192176*/
        // If unit identified itself as an ATAPI device the easy   // 206371
        // way then mark it and count it.                          // 206371
        npAT->Flags            |= ATBF_ATAPIPRESENT;               /*@V108783*//*@V192176*/

        npUT                    = &npAT->Unit[i];                  // 206371
        npUT->Status            = UTS_OK;                          // 206371
        npUT->Flags            |= UTBF_ATAPIDEVICE;                // 206371

        npACB->UnitCB[i].Flags |= UCBF_ATAPIDEVICE;                // 206371

        CountTheUnit( npAT );                                      /*@217469*/
     }                                                             /*@V108783*//*@V192176*/
  }

  if ( CheckController( npAT ) )                                   /*@V152648*/
  {
    if ( !(npAT->Flags & ATBF_ATAPIPRESENT) )                       /*@V149971*/
    {
      npAT->Status = ATS_NOT_PRESENT;
      goto ConfigureControllerExit;
    }
  }

  if ( npAT->Flags & ATBF_PS2IDEPORT )
  {
    npACB->Flags |= ACBF_PS2IDEPORT;
  }

  if ( npAT->Flags & ATBF_DISABLERESET )
  {
    npACB->Flags |= ACBF_DISABLERESET;
  }

  if ( npAT->Flags & ATBF_IRQCLEAR )                                /*@V106915*/
  {                                                                 /*@V106915*/
     npACB->Flags |= ACBF_IRQCLEAR;                                 /*@V106915*/
  }                                                                 /*@V106915*/


/* Begin [001.2] */

  if ( npAT->Flags & ATBF_DMASG )
  {

    npACB->Flags |= ACBF_DMASGMODE;

    DevHelp_VirtToPhys(  (PVOID) &npACB->DMASGList, (PULONG) &npACB->physSGListAddr );

  }

/* End [001.2] */

  if ( !IODelayCount )                                               /*@V90963*/
  {
    CalibrateTimers( npACB );
  }

  /*---------------------------------------------*/                 /*@V147576*/
  /* Setup the Hardware Resource structure       */                 /*@V147576*/
  /*                                             */                 /*@V147576*/
  /* All adapters are initially assumed to be    */                 /*@V147576*/
  /* independent and as such are assigned        */                 /*@V147576*/
  /* independent HWResource structures.  This is */                 /*@V147576*/
  /* because during initialization all device    */                 /*@V147576*/
  /* access is single threaded.                  */                 /*@V147576*/
  /*---------------------------------------------*/                 /*@V147576*/
                                                                    /*@V147576*/
  npACB->HWResourceIndex = cAdapters;                               /*@V147576*/
  HWResource[cAdapters].npOwnerACB  = npACB;                        /*@V147576*/
  HWResource[cAdapters].npFirstACBX = npACB;                        /*@V147576*/
  npACB->npNextACBX = NULL;                                         /*@V147576*/
                                                                    /*@V147576*/
  /*---------------------------------------------*/                 /*@V147576*/
  /* Initialize the ACB's state machine to       */                 /*@V147576*/
  /* process requests.                           */                 /*@V147576*/
  /*---------------------------------------------*/                 /*@V147576*/
  npACB->State = ACBS_START;                                        /*@V147576*/

  cAdapters++;                                                       /*@V90963*/

  /*---------------------------------------------*/                /*@V87325*/
  /* Activate the ACB                            */                /*@V87325*/
  /*                                             */                /*@V87325*/
  /* This Hooks the requested IRQ level if not   */                /*@V87325*/
  /* already hooked                              */                /*@V87325*/
  /*---------------------------------------------*/                /*@V87325*/
                                                                   /*@V87325*/
  if ( ActivateACB( npACB ) )                                      /*@V87325*/
  {                                                                /*@V87325*/
     npAT->Status = ATS_SET_IRQ_FAILED;                            /*@V87325*/
     goto ConfigureControllerExit;                                 /*@V87325*/
  }                                                                /*@V87325*/

  /*                                                                  @V129765
  ** Perform any required OEM specific PCI initializations.           @V129765
  */                                                                /*@V129765*/
  if( npACB->PCIInfo.Present )                                      /*@V129765*/
     npAT->Status = ConfigurePCI( npACB, PCIC_START );              /*@V147576*/

  // Start: 206371
  //
  // The above check for an ATAPI device signature does not see all ATAPI
  // devices in all configurations.  So now that the controller is
  // identified and this driver's state machine initialized, try again to
  // detect an ATAPI device via the ATAPI Identify opeation.
  for( i = 0; i < MAX_UNITS; i++ )
  {
     npUT = &npAT->Unit[i];
     if( !(npUT->Flags & UTBF_ATAPIDEVICE) &&
         !(npUT->Flags & UTBF_FORCE) &&
         !(npACB->Flags & ACBF_DISABLERESET) )
     {
        if( DoATAPIPresenseCheck( npAT, i ) )
        {
           ResetController( npACB );
        }
     }
  }
  //
  // End: 206371

ConfigureControllerExit:
  if (( npAT->Status ) && !( npAT->Flags & ATBF_ATAPIPRESENT ))     /*@V108555*/
     DeallocAdapterResources( npAT );

  return ( npAT->Status );
}


/*------------------------------------*/
/*                                    */
/*                                    */
/*                                    */
/*------------------------------------*/
VOID NEAR CalibrateTimers( NPACB npACB )
{
  WaitDRQCount    = CALIBRATE_LOOP_COUNT;
  CheckReadyCount = CALIBRATE_LOOP_COUNT;
  IODelayCount    = CALIBRATE_LOOP_COUNT;

  WaitDRQCount    = CalibrateWorker( npACB, &WaitDRQ )    * MAX_WAIT_DRQ;
  CheckReadyCount = CalibrateWorker( npACB, &CheckReady ) * MAX_WAIT_READY;
  IODelayCount    = CalibrateWorker( npACB, &IODelay    ) / 1000l;


  if ( !WaitDRQCount    ) WaitDRQCount    = 100;
  if ( !CheckReadyCount ) CheckReadyCount = 100;
  if ( !IODelayCount    ) IODelayCount    = 1;

  if ( ADD_StartTimerMS((PULONG) &ElapsedTimerHandle,
                        (ULONG)  ELAPSED_TIMER_INTERVAL,
                        (PFN)    ElapsedTimer,
                        (ULONG)  0,
                        (ULONG)  0              ) )
  {
     _asm { int 3 }
  }
}

/*------------------------------------*/
/*                                    */
/*                                    */
/*                                    */
/*------------------------------------*/
ULONG NEAR CalibrateWorker( NPACB npACB, NPCV npWorker )
{
  ULONG         CallCount      = 0;

  Calibrate      = 1;
  CallWorker     = 1;
  CallWorkerSync = 1;

  if ( ADD_StartTimerMS((PULONG) &CalibrateTimerHandle,
                        (ULONG)  CALIBRATE_TIMER_INTERVAL,
                        (PFN)    CalibrateTimer,
                        (ULONG)  0,
                        (ULONG)  0              ) )
  {
     _asm { int 3 }
  }


  while ( CallWorkerSync )
    ;

  while ( CallWorker )
  {
    (*npWorker)( npACB );

    CallCount++;
  }

  ADD_CancelTimer( CalibrateTimerHandle );

  Calibrate = 0;

  CallCount *= CALIBRATE_LOOP_COUNT;

  return ( CallCount / CALIBRATE_TIMER_INTERVAL );
}


/*------------------------------------*/
/*                                    */
/*                                    */
/*                                    */
/*------------------------------------*/
VOID FAR CalibrateTimer( ULONG hCalibrateTimer, ULONG Unused1, ULONG Unused2 )
{
  if ( CallWorkerSync )
  {
    CallWorkerSync = 0;
  }
  else
  {
    CallWorker = 0;
  }
}

/*------------------------------------*/
/*                                    */
/* ConfigureATAUnit()                 */
/*                                    */
/*------------------------------------*/
USHORT ConfigureATAUnit( NPATBL npAT, USHORT UnitId )
{
  NPACB         npACB;
  NPUTBL        npUT;                                               /*@V149971*/
  USHORT        rc;
  NPUCB         npUCB;                                              /*@V185215*/
  USHORT        i;                                                  

  npACB = npAT->npACB;
  npUT  = &npAT->Unit[UnitId];                                      /*@V149971*/
  npUCB = &npACB->UnitCB[UnitId];                                   /*@V149971*//*@V185215*/
                                                                /*@V151345*/
  /*----------------------------------------*/
  /* Select unit and check status for READY */
  /*----------------------------------------*/

  /*------------------------------------------*/
  /* COMPAQ machines throw an interrupt when  */
  /* a non-installed unit is selected.        */
  /*------------------------------------------*/

  DISABLE
  // Select the unit and check the cylinder regs to assure HW is   /*@V195918*/
  // present.  Just checking ready results in doing a              /*@V195918*/                                        /*@V195083*/
  // DetermineUnitGeometry() on non-existent drives which is very  /*@V195918*/
  // time consuming during boot.                                   /*@V195918*/

                                                         // Start defect: 221965
  // Some older ATA drives can be a little slow at getting ready
  // after sending down an ATAPI Identify, like was just done to
  // it above in ConfigureController().
  for( i = 0; i < 16; i++ )
  {
     rc = CheckCylinderLReg( npAT, UnitId );                       /*@V195918*/
     if( !rc )
     {
        break;
     }
  }                                                        // End defect: 221965

  if( !rc ) rc = CheckReady( npACB );

  SelectUnit( npACB, 0 );                                          /*@V87325*/
  ENABLE
                                                                   /*@V151345*/
  if (npUT->Flags & UTBF_FORCE)
  {                                                                 /*@V149971*/
    npUCB->Flags |= UCBF_FORCE;                                     /*@V149971*/
    if ( rc )                                                       /*@V149971*/
    {                                                               /*@V149971*/
      /*------------------------------------------*/                /*@V149971*/
      /* Force Unit to be recognized as present.  */                /*@V149971*/
      /* The DetermineUnitGeometry() can still    */                /*@V149971*/
      /* fail if insufficient information exists. */                /*@V149971*/
      /*------------------------------------------*/                /*@V149971*/
      npUCB->Flags |= UCBF_NOTPRESENT;                              /*@V149971*/
      rc = 0;                                                       /*@V149971*/
    }                                                               /*@V149971*/
  }                                                                 /*@V149971*/

  // The UCB Flag, UCBF_DISABLERETRY is used to save the            /*@V185215*/
  // initialization-time determined state of ATBF_DISABLERETRY.     /*@V185215*/
  // This permits the state machine to turn-on ACBF_DISABLERETRIES  /*@V185215*/
  // from within the state machine for the duration of an operation /*@V185215*/
  // but then put ACBF_DISABLERESET back to the initiazized state   /*@V185215*/
  // at the start of the next operation.                            /*@V185215*/
  if( npAT->Flags & ATBF_DISABLERESET )                             /*@V185215*/
  {                                                                 /*@V185215*/
     npUCB->Flags |= UCBF_DISABLERESET;                             /*@V185215*/
  }                                                                 /*@V185215*/

  
  
  if( !(npUT->Flags & UTBF_ATAPIDEVICE) )                           
  {
     if( rc )
     {
        rc = npAT->Unit[UnitId].Status = UTS_NOT_READY;
     }
     else if( !(npUCB->Flags & UCBF_NOTPRESENT) &&                  /*@V195085*/
              !(rc=DetermineUnitGeometry( npAT, UnitId )) )
     {
        CountTheUnit( npAT );                                       /*@217469*/
     }
  }                                                                 

  if( npUT->Flags & UTBF_NODASDSUPPORT )                            /*@V192176, moved here */
  {                                                                 /*@V192176, moved here */
     npUCB->Flags |= UCBF_NODASDSUPPORT;                            /*@V192176, moved here */
  }                                                                 /*@V192176, moved here */

#ifdef BBR
// Transfer command line specified     block sequences from the
// unit table to the unit control block.
{
   USHORT i;

   for( i = 0; i < npUT->nBBRSequences; i++ )
   {
      npUCB->BBRSequence[i] = npUT->BBRSequence[i];
   }
   npUCB->BBRFlags      = npUT->BBRFlags;
   npUCB->nBBRSequences = npUT->nBBRSequences;
}
#endif

  return ( rc );
}
                                                                   /*@V87325*/
                                                                   /*@VVVVVV*/
/*------------------------------------*/
/*                                    */
/* CheckForATAPISignature             */
/*                                    */
/*------------------------------------*/
USHORT CheckForATAPISignature( NPATBL npAT, USHORT UnitId )
{
   USHORT Port;
   USHORT Data;
   USHORT rc = 1;
   NPACB  npACB;

   npACB = npAT->npACB;

   SelectUnit ( npACB, UnitId );

   Port = npAT->BasePort + FI_PCYLL;
   inp( Port, Data );
   IODelay();

   if( Data == ATAPISIGL )
   {
      /* Erase Signature in case the drive is shadowing  */        /*@V117508*/
      /* registers for a non-existing slave device       */        /*@V117508*/
      outp ( Port, 0 );                                            /*@V117508*/
      IODelay();                                                   /*@V117508*/

      Port = npAT->BasePort + FI_PCYLH;
      inp( Port, Data );
      IODelay();

      /* Erase Signature in case the drive is shadowing  */        /*@V117508*/
      /* registers for a non-existing slave device       */        /*@V117508*/
      outp ( Port, 0 );                                            /*@V117508*/
      IODelay();                                                   /*@V117508*/

      if( Data == ATAPISIGH )
      {
         
         // previous command could have caused the task registers to
         // continue to show the signature from the master device.
         // Teac drives need this extra test.

         Port = npAT->BasePort + FI_RFDR;
         inp( Port, Data );
         IODelay();
         if( !(Data & FX_ERROR) )
         {
            rc = 0;
         }                                                      
      }
   }

   return( rc );
}

/*------------------------------------*/
/*                                    */
/* DoATAPIPresenseCheck               */
/*                                    */
/*------------------------------------*/
USHORT DoATAPIPresenseCheck( NPATBL npAT, USHORT UnitId )
{
  NPACB                 npACB;
  NPUCB                 npUCB;
  NPUTBL                npUT;
  USHORT                rc = 1;                 /* default is fail */
  USHORT                DevicePresent = 0;      /* default is not present */
  USHORT                i, j;                                       /*[022]*/
  NPIDENTIFYDATA        npID;
  UCHAR                 TryReset = 0;
  USHORT                ACBFlags;                                   /*@V117508*/

  npACB = npAT->npACB;
  npUCB = &npACB->UnitCB[UnitId];
  npUT  = &npAT->Unit[UnitId];

  npACB->TimeOut    = INIT_TIMEOUT_SHORT;
  npACB->IRQTimeOut = INIT_TIMEOUT_SHORT;

  /* Some ATAPI Devices / IDE Card combinations cause infinite interrupts when
     the ATAPI device is the master and no slave is present and the slave is
     selected via the drive select register.  A single interrupt will be
     processed if interrupts are disabled while the registers of the device are
     checked.  A non-existing device will report 0xFF in all registers. */

  DISABLE
  SelectUnit ( npACB, UnitId );

  DevicePresent=!CheckCylinderLReg( npAT, UnitId );                /*@V93625*/

  if ((!DevicePresent) && !(npUT->Flags & UTBF_ATAPIDEVICE))
  {
     SelectUnit( npACB, 0 );
     ENABLE
     goto DoATAPIPresenseCheckExit;
  }

  ENABLE

  npID = (NPIDENTIFYDATA) ScratchBuf;

  do
  {
    /* Identify needs to know to identify ATAPI */
    npUCB->Flags |= UCBF_ATAPIDEVICE;

    /* Clear any pending requests  created from the first Identify in
       ConfigureATAUnit                                                 */
    npUCB->ReqFlags = 0;

    if ( TryReset )
    {
       DISABLE
       SelectUnit( npACB, UnitId );

       if (( !( npAT->Flags & ATBF_DISABLERESET) || ATAPISlaveChk ) /*@V117508*/
              && !( npAT->Flags & ATBF_NOT_DPT ))                   /*@V117508*/
                                                                    /*@V109483*/
       {                                                             /*@V93625*/
         ResetController( npACB );                                   /*@V93625*/
         if (GetStatusReg( npACB ) & FX_ERROR) /*Probable DPT */     /*@V93625*/
         {                                                           /*@V93625*/
            SelectUnit( npACB, 0 );                                  /*@V93625*/
            ENABLE                                                   /*@V93625*/
            goto DoATAPIPresenseCheckExit;                           /*@V93625*/
         }                                                           /*@V93625*/
         /* We know it's not DPT.  Save this info so that the  */   /*@V117508*/
         /* slave device does not do the reset.                */   /*@V117508*/
         npAT->Flags |= ATBF_NOT_DPT;                               /*@V117508*//*@V155162*/
       }                                                             /*@V93625*/

       if ( ATAPIReset( npACB ) )
       {
          SelectUnit( npACB, 0 );
       }
       ENABLE
       TryReset = FALSE;
    }
    else
    {
       if (!UnitId) /* Only attempt a reset on the Master */        /*@V117508*/
       {                                                            /*@V117508*/
         TryReset = TRUE;
       }
    }

    if ( UnitId ) /* Disable resets on identify of Slave Devices */ /*@V117508*/
                  /* This is to protect us from getting the      */ /*@V117508*/
                  /* signature from a master device that is      */ /*@V117508*/
                  /* shadowing the slave registers               */ /*@V117508*/
    {                                                               /*@V117508*/
       /* Save the ACBFlags */                                      /*@V117508*/
       ACBFlags = npACB->Flags;                                     /*@V117508*/
       npACB->Flags = ACBF_DISABLERESET;                            /*@V117508*/
       rc = DoIdentify( npAT, UnitId, npID );                       /*@V117508*/
       npACB->Flags = ACBFlags;                                     /*@V117508*/
    }                                                               /*@V117508*/
    else                                                            /*@V117508*/
    {
       rc = DoIdentify( npAT, UnitId, npID );                       /*@V117508*/
    }

    if ( (npUT->Flags & UTBF_ATAPIDEVICE) || rc )
    {
       /* A DoIdentify Failure will select unit 0 */                /*@V108783*/
       SelectUnit( npACB, UnitId );                                 /*@V108783*/

       for( j = 0; j < MAX_ATAPI_RECOVERY_TRYS; j++ )               /*[022]*/
       {                                                            /*[022]*/
         /* ATAPI Units can take several ms to show the signature *//*@V108783*/
         for ( i=0;i < ATAPI_RECOVERY; i++ )                        /*@V108783*/
         {                                                          /*@V108783*/
           IODelay();                                               /*@V108783*/
         }                                                          /*@V108783*/

         if ( !(rc=CheckForATAPISignature( npAT, UnitId ) ) )       /*[022]*/
         {
           break;                                                   /*[022]*/
         }
       }                                                            /*[022]*/

       /*                                                             @V153159
       ** Some ATAPI devices do not properly present their ATAPI      @V153159
       ** signature.  If the above failed then try sending an ATAPI   @V153159
       ** Identify command to the device.  If this works, then go     @V153159
       ** ahead and assume the drive is an ATAPI CD-ROM even though   @V153159
       ** the drive failed to present its signature.                  @V153159
       */                                                           /*@V153159*/
       if( rc )                                                     /*@V153159*/
       {                                                            /*@V153159*/
          npAT->Unit[UnitId].Status = UTS_OK;                       /*@V153159*/
          npAT->Unit[UnitId].Flags |= UTBF_ATAPIDEVICE;             /*@V153159*/
                                                                    /*@V153159*/
          if( rc = IdentifyDevice( npAT, UnitId, npID, ATAPI_DEVICE ))
          {                                                         /*@V153159*/
             if( !(npUCB->Flags & UCBF_FORCE) )                     /*@V155162*/
             {                                                      /*@V155162*/
                npAT->Unit[UnitId].Flags &= ~UTBF_ATAPIDEVICE;      /*@V153159*/
                npAT->Unit[UnitId].Status = UTS_NOT_PRESENT;        /*@V153159*/
                npUCB->Flags &= ~UCBF_ATAPIDEVICE;                  /*@V153159*/
             }                                                      /*@V153159*/
          }                                                         /*@V155162*/
       }                                                            /*@V153159*/

       if ( !rc ||                                                  /*[022]*/
             (npUT->Flags & UTBF_ATAPIDEVICE) )
       {
          npAT->Unit[UnitId].Status = UTS_OK;
          npAT->Unit[UnitId].Flags |= UTBF_ATAPIDEVICE;             /*@V108783*/
          CountTheUnit( npAT );                                     /*@217469*/

          /* force good return code if case UTBF_ATAPIDEVICE flag set */
          rc = 0;

          /* Force the SONY CDROM ready. */                    /*@V157002*/
          ReadDrive( npACB, UnitId, 0, 1, NULL );              /*@V157002*/


          /* Some ATAPI units show FF in all registers until initialized. */
          /* We need to select unit 0 in case the HD is there so that it  */
          /* does not see the bsy caused by ff                            */
          SelectUnit( npACB, 0 );
       }
    }
    else
    {
       rc = 1;
    }

  } while ( rc && TryReset );

  DoATAPIPresenseCheckExit:

  if ( rc )
  {
    npUCB->Flags &= ~UCBF_ATAPIDEVICE;
    npAT->Unit[UnitId].Status = UTS_NOT_PRESENT;
  }

  return ( rc );
}

/*------------------------------------*/
/*                                    */
/* ATAPIReset()                       */
/*                                    */
/*------------------------------------*/
USHORT ATAPIReset( NPACB npACB )
{
   USHORT rc = 0;
   USHORT Data;
   USHORT Port;
   USHORT i;

   Data = FX_ATAPI_RESET;
   Port = npACB->IOPorts[FI_PCMD];
   outp( Port, Data );

   for ( i=0; i<8; i++ )
   {
      rc = CheckReady( npACB );
      if ( !rc )
      {
         break;
      }
   }

   return( rc );
}

/*------------------------------------*/                           /*@V153159*/
/*                                    */                           /*@VVVVVVV*/
/* ConfigureATAPIDevice()             */
/*                                    */
/* for ATAPI devices                  */
/*                                    */
/*------------------------------------*/
BOOL ConfigureATAPIDevice( NPATBL npAT, USHORT UnitId )             /*@V162970, made BOOL*/
{
   NPUTBL          npUT = &npAT->Unit[UnitId];                      
   NPACB           npACB;
   NPUCB           npUCB;
   NPIDENTIFYDATA  npID;

   npACB =   npAT->npACB;
   npUCB = &npACB->UnitCB[UnitId];

   
   
   if( npUT->Flags & UTBF_ATAPIDEVICE )                             
   {                                                                
      npUCB->Flags |= UCBF_ATAPIDEVICE;                             
   }                                                                

   /*************************************/
   /* Required for ConfigureATAPIDevice */
   /*************************************/
   npUCB->Flags &= ~UCBF_NOTPRESENT;                                /*@V149971*/

   npID = (NPIDENTIFYDATA) ScratchBuf;                              /*@V182322*/

   if( IdentifyDevice( npAT, UnitId, npID, ATAPI_DEVICE ))
   {
      /*--------------------------------*/
      /* Error executing ATAPI identify */
      /*--------------------------------*/
      if( npUCB->Flags & UCBF_FORCE )                               /*@V149971*/
      {
         /***********************************************************/
         /* The device has failed to initialize; and is being faked */
         /* then assume the device is not currently present.        */
         /***********************************************************/
         npUCB->Flags |= UCBF_NOTPRESENT;                           /*@V149971*/

         return( 0 );
      }
      else if( !(npACB->Flags & ACBF_DISABLERESET) )
      {                                                            /*@V152648*/
         ResetController( npACB );
      }                                                            /*@V152648*/

      /***************************************************/        /*@V162970*/
      /* We have an error, so we need to issue the ATAPI */        /*VVVVVVVV*/
      /* Reset cmd in order to restore the ATAPI device  */
      /* to accept the ATA cmd.                          */
      /***************************************************/

      SelectUnit( npACB, UnitId );
                                                                   /*AAAAAAAA*/
      ATAPIReset( npACB );                                         /*@V162970*/

      return( 1 );                                  /* Error */
   }

   /*-----------------------------*/
   /* Setup UCB DMA and PIO parms */
   /*-----------------------------*/

   UCBSetupDMAPIO( npID, npAT, npUCB, 0 );                         /*@V179942*/

   return( 0 );                                     /* SUCCESS */
}

/* End [002.2] */                                                  /*@AAAAAA*/
                                                                   /*@V87325*/

/*------------------------------------*/
/*                                    */
/* ReadDrive()                        */
/*                                    */
/*------------------------------------*/
USHORT ReadDrive( NPACB  npACB, USHORT UnitId, ULONG RBA,           /*@V108555*/
                  USHORT Retry, PBYTE pBuf )                        /*@V108555*/
{
  NPIORB_EXECUTEIO      npTI = &InitIORB;

  setmem( (PBYTE) npTI, 0, sizeof(IORB_EXECUTEIO) );

  if ( !pBuf )                                                      /*@V108555*/
  {                                                                 /*@VVVVVVV*/
    npTI->iorbh.CommandModifier = IOCM_READ_VERIFY;
    npTI->cSGList               = 0;
    npTI->pSGList               = 0;
  }
  else
  {
    npTI->iorbh.CommandModifier = IOCM_READ;

    if ( DevHelp_VirtToPhys( (PVOID)  pBuf,
                             (PULONG) &ScratchSGList.ppXferBuf ) )
    {
      _asm { int 3 }
    }
    npTI->cSGList               = 1;
    npTI->pSGList               = &ScratchSGList;                   /*@VAAAAAA*/
  }                                                                 /*@V108555*/

/*                                                                    @V154572
   Deleted the following 2 lines, these flags should only be cleared  @V154572
   for PASSTHRU commands.                                             @V154572
  npACB->ReqFlags = 0;                                                @V154572
  npACB->UnitCB[UnitId].ReqFlags=0;                                   @V154572
*/                                                                  /*@V154572*/

  npTI->iorbh.Length          = sizeof(IORB_EXECUTEIO);
  npTI->iorbh.UnitHandle      = (USHORT) &npACB->UnitCB[UnitId];
  npTI->iorbh.CommandCode     = IOCC_EXECUTE_IO;
  npTI->iorbh.RequestControl  = IORB_ASYNC_POST | ((Retry) ? 0 : IORB_DISABLE_RETRY);
  npTI->iorbh.NotifyAddress   = NotifyIORBDone;
  npTI->RBA                   = RBA;
  npTI->BlockCount            = 1;
  npTI->BlocksXferred         = 0;
  npTI->BlockSize             = 512;

  ADDEntryPoint( (PIORB) npTI );

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

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


/*------------------------------------*/
/*                                    */
/* DoIdentify()                       */
/*                                    */
/*------------------------------------*/
USHORT DoIdentify( NPATBL npAT, USHORT UnitId, NPIDENTIFYDATA npID )
{
   NPACB    npACB;
   NPUCB    npUCB;
   USHORT   errorcode = 0;

   npACB =  npAT->npACB;
   npUCB = &npACB->UnitCB[UnitId];

   if( ((npACB->UnitCB[0].Flags & UCBF_IDENTIFYFAIL) &&
       !(npACB->UnitCB[0].Flags & UCBF_ATAPIDEVICE))                /*@V87325*/
      || (npUCB->Flags & UCBF_NOTPRESENT) )                        /*@V149971*/
   {
      npUCB->Flags |= UCBF_IDENTIFYFAIL;
      errorcode     = IOERR_DEVICE_REQ_NOT_SUPPORTED;

      goto DoIdentify_Exit;
   }

   npUCB->Flags |= UCBF_ALLOCATED;

   /*---------------------*/
   /* Identify ATA Device */
   /*---------------------*/

   errorcode = IdentifyDevice( npAT, UnitId, npID, ATA_DEVICE );

   npUCB->Flags &= ~UCBF_ALLOCATED;

   if( errorcode )
   {
      npUCB->Flags |= UCBF_IDENTIFYFAIL;

      if( !(npACB->Flags & ACBF_DISABLERESET) )
      {
         ResetController( npACB );
      }
   }

DoIdentify_Exit:

   return( errorcode );
}


/*------------------------------------*/
/*                                    */
/*                                    */
/*                                    */
/*------------------------------------*/
USHORT NEAR ScanForOtherADDs()
{
  NPIORB_CONFIGURATION  pIORB;
  DEVICETABLE           *pDeviceTable;
  NPADAPTERINFO         pAdapterInfo;

  struct DevClassTableStruc far *pDriverTable;

  USHORT                rc, i, j, k, n;

  USHORT                UnitFlags;
  USHORT                UnitType;
  USHORT                DriveCount = 0;

  VOID                  (FAR * DriverEP) ();

  if ( rc = DevHelp_GetDOSVar((USHORT) DHGETDOSV_DEVICECLASSTABLE, 1,
                              (PPVOID) &pDriverTable) )
  {
    _asm { int 3 }
  }

  pDeviceTable = (DEVICETABLE *) ScratchBuf;

  for (i = 0; i < pDriverTable->DCCount; i++)
  {
    pIORB = (NPIORB_CONFIGURATION) &InitIORB;
    pIORB->iorbh.Length = sizeof(IORB_CONFIGURATION);
    pIORB->iorbh.CommandCode = IOCC_CONFIGURATION;
    pIORB->iorbh.CommandModifier = IOCM_GET_DEVICE_TABLE;
    pIORB->iorbh.Status = 0;
    pIORB->iorbh.RequestControl = IORB_ASYNC_POST;
    pIORB->iorbh.NotifyAddress = &InitPost;
    pIORB->pDeviceTable = (PVOID) ScratchBuf;
    pIORB->DeviceTableLen = sizeof(ScratchBuf);

    OFFSETOF(DriverEP) =  pDriverTable->DCTableEntries[i].DCOffset;
    SELECTOROF(DriverEP) = pDriverTable->DCTableEntries[i].DCSelector;

    setmem( ScratchBuf, 0, sizeof(ScratchBuf) );

    (*DriverEP) ((PVOID)(pIORB));

    while ( !(pIORB->iorbh.Status & IORB_DONE) )  /* Wait till done */
    ;

    if (pIORB->iorbh.Status & IORB_ERROR )
      continue;

    for (j = 0; j < pDeviceTable->TotalAdapters; j++)
    {
      pAdapterInfo =  pDeviceTable->pAdapter[j];

      for (k = 0; k < pAdapterInfo->AdapterUnits; k++)
      {
        UnitFlags = pAdapterInfo->UnitInfo[k].UnitFlags;
        UnitType  = pAdapterInfo->UnitInfo[k].UnitType;
        if ( !(UnitFlags & (UF_NODASD_SUPT | UF_DEFECTIVE)) )
        {
          if ( (UnitType == UIB_TYPE_DISK) && !(UnitFlags & UF_REMOVABLE) )
          {
            DriveCount++;
          }
        }
      }
    }
  }

  return (DriveCount);
}

/*------------------------------------*/
/*                                    */
/* InitPost()                         */
/*                                    */
/*------------------------------------*/
VOID FAR InitPost(PIORB pIORB)
{
}

/*------------------------------------*/
/*                                    */
/* CheckACBViable()                   */
/*                                    */
/*------------------------------------*/
VOID NEAR CheckACBViable( NPATBL npAT )                              /*@V90963*/
{                                                                    /*@VVVVVV*/
  NPACB         npACB;

  if ( npACB = npAT->npACB )
  {
    if ( !npAT->cUnits )
    {
      DeactivateACB( npACB );
      DeallocAdapterResources( npAT );                              /*@V108555*/
      npACBPool--;
      cAdapters--;

      npAT->npACB  = ACBPtrs[cAdapters].npACB = 0;
      npAT->cUnits = 0;
    }
  }                                                                       /*@VAAAAA*/
}                                                                         /*@V90963*/

/*------------------------------------*/                                  /*@V151345*/
/*                                    */                                  /*@VVVVVVV*/
/*                                    */
/*                                    */
/*------------------------------------*/

/* Begin [001.1] Add codes for additional parameters to Flags bit array */
/*               Must redefine Flags to be 32-bit instead of 16-bit since */
/*               it is full already. */

#define PCF_ADAPTER0    0x00008000
#define PCF_ADAPTER1    0x00004000
#define PCF_ADAPTER2    0x00002000                                 /*@V87325*/
#define PCF_ADAPTER3    0x00001000                                 /*@V87325*/

#define PCF_IGNORE      0x00000800
#define PCF_RESET       0x00000400
#define PCF_PORT        0x00000200
#define PCF_IRQ         0x00000100
#define PCF_DM          0x00000080

#define PCF_UNIT0       0x00000040
#define PCF_UNIT1       0x00000020
#define PCF_GEO         0x00000010
#define PCF_TIMEOUT     0x00000008
#define PCF_LBAMODE     0x00000004
#define PCF_SMS         0x00000002
#define PCF_ATAPI       0x00000001                                       /*@V93531*/

#define PCF_DMATYPE     0x00080000
#define PCF_DMACHANNEL  0x00040000
#define PCF_DMASGP      0x00020000
#define PCF_BMDMA       0x00010000

#define PCF_FORCE       0x00100000                                  /*@V149971*/
#define PCF_PCMCIA      0x00200000                                  /*@V155162*/
#define PCF_PS2LED      0x00400000                                  /*@V182291*/
#define PCF_CYLA        0x00800000                                  /*@V192088*/

#define PCF_CLEAR_ADAPTER (PCF_IGNORE | PCF_IRQ  | PCF_PORT | PCF_DM |    \
                           PCF_RESET | PCF_UNIT0  | PCF_UNIT1  | PCF_DMATYPE | \
                           PCF_DMACHANNEL | PCF_DMASGP | PCF_BMDMA | PCF_PCMCIA | \
                           PCF_PS2LED )

#define PCF_CLEAR_UNIT (PCF_GEO | PCF_TIMEOUT | PCF_DM | PCF_LBAMODE |    \
                        PCF_SMS | PCF_ATAPI | PCF_FORCE | PCF_BMDMA | PCF_UNIT0  | PCF_UNIT1 )  /* [002.2] @V151345 [023] */

/* End [001.1] */

/*------------------------------------*/
/*                                    */
/* ParseCmdLine()                     */
/*                                    */
/*------------------------------------*/
USHORT ParseCmdLine( PDDD_PARM_LIST pADDParms, NPATBL npAT, USHORT SystemDMAType ) /*@V156660*/
{
  PSZ           pCmdLine;
  CC            cc;

  NPUTBL        npUT;
  NPGEOMETRY    npGEO;
  NPSZ          pOutBuf;
  NPATBL        npATABLE = npAT;

  ULONG         Flags = 0;      /* [001.1] Change to 32-bit unsigned */
  ULONG         Mask;           /* [005] change t 32-bit unsigned */

  USHORT        i,j;
  USHORT        rc = 0;
  USHORT        Length;

  USHORT        AdptId;
  USHORT        UnitId;

  USHORT        SecPerTrk;
  ULONG         TotalCyl;                                           /*@V192176*/
  USHORT        NumHeads;
  USHORT        WrtPreCmp;

/* Begin [001.1] Add code to handle init and vars for DMA options. */

  USHORT        DMASG_BasePort;

  USHORT        SystemDMASG=0;
  USHORT        SystemDMABM=0;                                       /* [002.2] */

  /* Check For System DMA Type               */
  /* Check if system is EISA OR PCI Type     */
  /* [002.2] Also check for Triton and other Bus Master IDE DMA controllers */

  /* [002.2] delete repetitious comments */

  /* Begin [002.2] Add support for Bus Master DMA */

  if( SystemDMAType & SDMA_BusMaster )
  {
    SystemDMABM = 1;

    if ( SystemDMAType & SDMA_SG )
    {
      SystemDMASG = 1;                      /* indicate system supports s/g */
    }

    for (i=0; i< MAX_ADAPTERS ;i++ )              /*@217469*/
    {
      #ifdef DMA_DEFAULT_OFF                                                               /*@V162458*/
            npAT[i].Flags &= ~ATBF_BM_DMA;        /* default DMA disabled for Bus Master *//*@V162458*/
      #else                                                                                /*@V162458*/
            npAT[i].Flags |= ATBF_BM_DMA;         /* force DMA enabled for Bus Master */
      #endif                                                                               /*@V162458*/

      if( npAT[i].PCIInfo.Present == FALSE ) {
         npAT[i].Flags &= ~ATBF_BM_DMA;           /* Turn off Bus Master DMA */            /*@V190477*/
      }

      if ( SystemDMASG )                    /* if scatter/gather enabled */
      {
        #ifdef DMA_DEFAULT_OFF                                                               /*@V162458*/
              npAT[i].Flags &= ~ATBF_DMASG;       /* also force scatter/gather off */      /*@V162458*/
        #else                                                                                /*@V162458*/
              npAT[i].Flags |= ATBF_DMASG;        /* also force scatter/gather on */
        #endif                                                                               /*@V162458*/
      }
    }
  }
  else if ( SystemDMAType & 0x10 )
  {
    SystemDMASG = 1;
  }

  if ( !CheckSMSEnable() )                                          /*@V108555*/
  {                                                                 /*@V108555*/
    for (i=0;i<MAX_ADAPTERS ;i++ )                                   /*@V87325*/
    {                                                                /*@V87325*/
       for (j=0;j<MAX_UNITS ;j++ )                                   /*@V87325*/
       {                                                             /*@V87325*/
         npAT[i].Unit[j].Flags |= UTBF_SMSENABLED;                   /*@V87325*//*@V155162*/
       }                                                             /*@V87325*/
    }                                                                /*@V87325*/
  }                                                                 /*@V108555*/

  pOutBuf = poutbuf;

  pCmdLine = MAKEP( SELECTOROF(pADDParms),
                    (USHORT)   pADDParms->cmd_line_args );

  cc = Command_Parser( (PSZ)          pCmdLine,
                       (POPTIONTABLE) &opttable,
                       (PBYTE)        pOutBuf,
                       (USHORT)       outbuf_len );

  if ( cc.ret_code == NO_ERR )
  {
    while ( !rc && pOutBuf[1] != (UCHAR) TOK_ID_END )
    {

      Length = pOutBuf[0];

      switch ( pOutBuf[1] )
      {

        /*-------------------------------------------*/
        /* Quite/Verbose Mode - /!V /V               */
        /* (bit 0)                                   */
        /*-------------------------------------------*/

        case TOK_ID_V:

          Verbose |= 1;                                             /*@V192545*/
          break;

        case TOK_ID_NOT_V:

          #ifdef PRE_RELEASE
                Verbose |= 1;     /* can't turn Verbose off for pre-release */
          #else
                Verbose &= ~1;                                      /*@V192545*/
          #endif
          break;

        /*-------------------------------------------*/             /*@V192545*/
        /* Pause Verbose Mode - /W                   */             /*VVVVVVVV*/
        /* (bit 1)              /!W                  */
        /*-------------------------------------------*/

        case TOK_ID_VPAUSE:

          Verbose |= 3;
          break;

        case TOK_ID_NOT_VPAUSE:

          Verbose &= ~2;                                            /*AAAAAAAA*/
          break;                                                    /*@V192545*/

        /*-------------------------------------------*/
        /* Adapter Id - /A:0, /A:1, /A:2 or /A:3     */            /*@V87325*/
        /*                                           */
        /* Check for  correct adapter index. Address */
        /* ADAPTERTABLE structure.                   */
        /*-------------------------------------------*/

        case TOK_ID_ADAPTER:

          AdptId = pOutBuf[2];

          switch (AdptId)                                          /*@V87325*/
          {                                                        /*@V87325*/
             case  0 : Mask = PCF_ADAPTER0; break;                 /*@V87325*/
             case  1 : Mask = PCF_ADAPTER1; break;                 /*@V87325*/
             case  2 : Mask = PCF_ADAPTER2; break;                 /*@V87325*/
             case  3 : Mask = PCF_ADAPTER3;                        /*@V87325*/
          }                                                        /*@V87325*/

          if ( (AdptId > (MAX_ADAPTERS-1)) || (Flags & Mask))
          {
            rc = 1;
            break;
          }
          Flags |= Mask;
          Flags &= ~PCF_CLEAR_ADAPTER;
          DMASG_BasePort = 0;       /* [001.1] Init DMA scatter/gather base port */
          npAT = npATABLE + AdptId;                                 /*@V149971*/
          npAT->SysDMAType = SystemDMAType; /* [001.1] Init DMA type */
          npAT->DMA_Channel=0;      /* [001.1] Init DMA channel */

          break;

        /*-------------------------------------------*/
        /* Base Port - /P:hhhh                       */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_PORT:

          if ( (Flags & PCF_PORT) )
          {
            rc = 1;
            break;
          }
          npAT->BasePort = *(NPUSHORT)(pOutBuf+2);
          Flags |= PCF_PORT;

          npAT->Flags &= ~ATBF_DISABLED;                           /*@V87325*/

          break;


        /*-------------------------------------------*/
        /* IRQ Level - /IRQ:nn                       */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_IRQ:

          if ( (Flags & PCF_IRQ) )
          {
            rc = 1;
            break;
          }
          npAT->IRQLevel = pOutBuf[2];
          Flags |= PCF_IRQ;                                          /*@V64402*/

          break;

        /*-------------------------------------------*/
        /* Ignore Adapter - /I                       */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_IGNORE:

          if ( (Flags & PCF_IGNORE) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_IGNORE;

          npAT->Flags |= ATBF_DISABLED;

          break;


        /*-------------------------------------------*/
        /* Allow/Prevent Adapter Resets - /R, /!R    */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_RESET:

          if ( Flags & PCF_RESET )
          {
            rc = 1;
            break;
          }
          Flags |= PCF_RESET;
          break;

        case TOK_ID_NORESET:

          if ( Flags & PCF_RESET )
          {
            rc = 1;
            break;
          }
          Flags |= PCF_RESET;

          npAT->Flags |= ATBF_DISABLERESET;
          break;


        /*-------------------------------------------*/
        /* DASD Manager Support - /!DM, /DM          */
        /*                                           */
        /* If this is specified before /U (Unit Id)  */
        /* then this switch applies to all units.    */
        /* Otherwise, this switch applies to the     */
        /* current unit.                             */
        /*-------------------------------------------*/

        case TOK_ID_NOT_DM:

          if ( (Flags & PCF_DM) )
          {
            rc = 1;
            break;
          }
          Flags |= PCF_DM;                                           /*@V64402*/

          if ( Flags & (PCF_UNIT0 | PCF_UNIT1) )
          {
            npUT->Flags |= UTBF_NODASDSUPPORT;
          }
          else
          {
            npAT->Flags |= ATBF_NODASDSUPPORT;                      /*@V149971*/
            for (i = 0; i < MAX_UNITS; i++ )
            {
              npAT->Unit[i].Flags |= UTBF_NODASDSUPPORT;
            }
          }
          break;

        case TOK_ID_DM:

          if ( (Flags & PCF_DM) )
          {
            rc = 1;
            break;
          }
          Flags |= PCF_DM;                                           /*@V64402*/

          if ( Flags & (PCF_UNIT0 | PCF_UNIT1) )
          {
            npUT->Flags &= ~UTBF_NODASDSUPPORT;
          }

          break;

        /*-------------------------------------------*/
        /* Unit Number - /U:0, /U:1                  */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_UNIT:

          UnitId = pOutBuf[2];
          Mask = (!UnitId) ? PCF_UNIT0 : PCF_UNIT1;
          if ( (UnitId > (MAX_UNITS-1)) || (Flags & Mask))
          {
            rc = 1;
            break;
          }
          Flags &= ~(PCF_CLEAR_UNIT);
          Flags |= Mask;
          npUT   = &npAT->Unit[UnitId];

          break;

        /*-------------------------------------------*/
        /* Unit Geometry -  /G:(C,H,S,W) or /G:nn    */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_GEO:

          if ( (Flags & PCF_GEO) )
          {
            rc = 1;
            break;
          }
          Flags |= PCF_GEO;                                          /*@V64402*/

          /*-------------------------------------------------*/
          /* User specified a Physical Geometry for the      */
          /* disk.                                           */
          /*                                                 */
          /* Check if DriveType or (Cyl,Head,Sec,WrtPCmp)    */
          /* was provided.                                   */
          /*-------------------------------------------------*/

          if ( (pOutBuf[2] >> 4) == GEOTYPE_DRIVETYPE )
          {
            if ( DriveTypeToGeometry( (USHORT)     pOutBuf[3],
                                      (NPGEOMETRY) &npUT->CMDPhysGeom,
                                      (NPUSHORT)   &npUT->CMDWrtPreCmp ) )
            {
              rc = 1;
              break;
            }
          }
          else if ( (pOutBuf[2] >> 4) == GEOTYPE_DRIVESPEC )
          {
            TotalCyl  = *(NPUSHORT) (pOutBuf+3);
            NumHeads  = *(NPUSHORT) (pOutBuf+5);
            SecPerTrk = *(NPUSHORT) (pOutBuf+7);
            WrtPreCmp = *(NPUSHORT) (pOutBuf+9);

            /*------------------------------------------*/
            /* Check if user provided physical geometry */
            /* is within reasonable limits.             */
            /*------------------------------------------*/

            if ( !NumHeads || !SecPerTrk || !TotalCyl ||
                 SecPerTrk > BR_MAX_SECTORSPERTRACK   ||
                 NumHeads > BR_MAX_PHYS_HEADS           )
            {
              rc = 1;
              break;
            }

            if ( WrtPreCmp > TotalCyl )
            {
              WrtPreCmp = -1;
            }

            npUT->CMDPhysGeom.TotalCylinders  = TotalCyl;
            npUT->CMDPhysGeom.NumHeads        = NumHeads;
            npUT->CMDPhysGeom.SectorsPerTrack = SecPerTrk;
            npUT->CMDWrtPreCmp                = WrtPreCmp;
            npUT->CMDPhysGeom.TotalSectors    = TotalCyl * NumHeads * SecPerTrk; /*@V192176*/
          }
          else
          {
            rc = 1;
            break;
          }

          /*-------------------------------------------------*/
          /* User specified a Logical (INT 13) for the disk. */
          /*                                                 */
          /* This is unusual since most BIOS ROMs map the    */
          /* drive Physical = Logical with translation being */
          /* done being by the controller itself.            */
          /*                                                 */
          /* Check if DriveType or (Cyl,Head,Sec,WrtPCmp)    */
          /* was provided.                                   */
          /*-------------------------------------------------*/

          if ( (pOutBuf[2] & 0x0f) == GEOTYPE_DRIVETYPE )
          {
            if ( DriveTypeToGeometry( (USHORT)     pOutBuf[3],
                                      (NPGEOMETRY) &npUT->CMDLogGeom,
                                      (NPUSHORT)   0               ) )
            {
              rc = 1;
              break;
            }
          }
          else if ( (pOutBuf[2] & 0x0f) == GEOTYPE_DRIVESPEC )
          {
            /*------------------------------------------*/
            /* Check if user provided logical geometry  */
            /* is within reasonable limits.             */
            /*------------------------------------------*/
            TotalCyl  = *(NPUSHORT) (pOutBuf+11);
            NumHeads  = *(NPUSHORT) (pOutBuf+13);
            SecPerTrk = *(NPUSHORT) (pOutBuf+15);

            if ( !NumHeads  || !SecPerTrk || !TotalCyl  ||
                 SecPerTrk > BR_MAX_SECTORSPERTRACK     ||
                 NumHeads  > BR_MAX_HEADS                 )
            {
              rc = 1;
              break;
            }

            npUT->CMDLogGeom.TotalCylinders  = TotalCyl;
            npUT->CMDLogGeom.NumHeads        = NumHeads;
            npUT->CMDLogGeom.SectorsPerTrack = SecPerTrk;
          }
          /*---------------------------------------*/
          /* If no logical geometry was provided,  */
          /* Then map the disk Logical = Physical  */
          /*---------------------------------------*/
          else
          {
            npUT->CMDLogGeom = npUT->CMDPhysGeom;
          }

          npUT->Flags |= UTBF_CMDGEOMETRYVALID;

          break;


        /*-------------------------------------------*/
        /* Unit TimeOut -  /T:nn (sec)               */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_TIMEOUT:

          if ( (Flags & PCF_TIMEOUT) )
          {
            rc = 1;
            break;
          }

          npUT->TimeOut = *(NPUSHORT) pOutBuf+2;

          Flags |= PCF_TIMEOUT;

          break;


        /*-------------------------------------------*/
        /* Enable LBA Mode - LBA                     */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_LBAMODE:

          if ( (Flags & PCF_LBAMODE) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_LBAMODE;

          npUT->Flags |= UTBF_LBAMODEENABLED;

          break;

        /*-------------------------------------------*/
        /* Enable Set Multiple Support               */
        /*                                           */
        /*-------------------------------------------*/

        case TOK_ID_SMS:

          if ( (Flags & PCF_SMS) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_SMS;

          npUT->Flags |= UTBF_SMSENABLED;

          break;


        case TOK_ID_NOT_SMS:

          if ( (Flags & PCF_SMS) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_SMS;

          npUT->Flags &= ~UTBF_SMSENABLED;                           /*@V77133*/

          break;

        /*-------------------------------------------*/              /*@V93531*/
        /* Unit is an ATAPI device                   */              /*@V93531*/
        /*                                           */              /*@V93531*/
        /*-------------------------------------------*/              /*@V93531*/
                                                                     /*@V93531*/
        case TOK_ID_ATAPI:                                           /*@V93531*/
                                                                     /*@V93531*/
          if ( (Flags & PCF_ATAPI) )                                 /*@V93531*/
          {                                                          /*@V93531*/
            rc = 1;                                                  /*@V93531*/
            break;                                                   /*@V93531*/
          }                                                          /*@V93531*/
                                                                     /*@V93531*/
          Flags |= PCF_ATAPI;                                        /*@V93531*/
                                                                     /*@V93531*/
          npAT->Flags |= ATBF_ATAPIPRESENT;                          /*@V93531*/
          npUT->Flags |= UTBF_ATAPIDEVICE;                           /*@V93531*/
                                                                     /*@V93531*/
          break;                                                     /*@V93531*/
                                                                     /*@V93531*/
                                                                     /*@V93531*/
        case TOK_ID_NOT_ATAPI:                                       /*@V93531*/
                                                                     /*@V93531*/
          if ( (Flags & PCF_ATAPI) )                                 /*@V93531*/
          {                                                          /*@V93531*/
            rc = 1;                                                  /*@V93531*/
            break;                                                   /*@V93531*/
          }                                                          /*@V93531*/
                                                                     /*@V93531*/
          Flags |= PCF_ATAPI;                                        /*@V93531*/
                                                                     /*@V93531*/
          npUT->Flags &= ~UTBF_ATAPIDEVICE;                          /*@V93531*/
                                                                     /*@V93531*/
          break;                                                     /*@V93531*/

        case TOK_ID_FORCE:                                          /*@V149971*/
                                                                    /*@V149971*/
          if ( (Flags & PCF_FORCE) )                                /*@V149971*/
          {                                                         /*@V149971*/
            rc = 1;                                                 /*@V149971*/
            break;                                                  /*@V149971*/
          }                                                         /*@V149971*/
                                                                    /*@V149971*/
          Flags |= PCF_FORCE;                                       /*@V149971*/
                                                                    /*@V149971*/
          npAT->Flags |= ATBF_FORCE;                                /*@V149971*/
          npUT->Flags |= UTBF_FORCE;                                /*@V149971*/
                                                                    /*@V149971*/
          break;                                                    /*@V149971*/

        case TOK_ID_PCMCIA:                                         /*@V155162*/
                                                                    /*@V155162*/
          if ( (Flags & PCF_PCMCIA) )                               /*@V155162*/
          {                                                         /*@V155162*/
            rc = 1;                                                 /*@V155162*/
            break;                                                  /*@V155162*/
          }                                                         /*@V155162*/
                                                                    /*@V155162*/
          Flags |= PCF_PCMCIA;                                      /*@V155162*/
          Flags |= PCF_FORCE;                                       /*@V155162*/
          /*                                                          @V155162
          ** If the adapter is PCMCIA then its presense is            @V155162
          ** also being FORCEd.  We don't know what units, if any,    @V155162
          ** will be found.  Also, PCMCIA units can come and go,      @V155162
          ** therefore FORCEd units can not be assumed for PCMCIA.    @V155162
          */                                                        /*@V155162*/
          npAT->Flags |= ATBF_FORCE;                                /*@V155162*/
          npAT->Flags |= ATBF_PCMCIA;                               /*@V155162*/
          /* turn off the disabled flag for this adapter */         /*@V153620*/
          npAT->Flags &= ATBF_DISABLED;                             /*@V153620*/
                                                                    /*@V155162*/
          break;                                                    /*@V155162*/

/* Begin [001.1] Check for DMA options in command line */

        /*-------------------------------------------*/
        /*  System DMA Type /DT:                                                          */
        /*-------------------------------------------*/

        case TOK_ID_DMATYPE:

          if ( (Flags & PCF_DMATYPE) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_DMATYPE;

          if ( (*(NPUSHORT)(pOutBuf+2) == SDMA_TYPE_B)
                || (*(NPUSHORT)(pOutBuf+2) == SDMA_TYPE_F))
          {
/* [002.2] Added next line and modified 2nd line to or in new type bits from cmd line */
            npAT->SysDMAType &= SDMA_MASK;
            npAT->SysDMAType |= *(NPUSHORT)(pOutBuf+2);
            if (npAT->DMA_Channel != 0)
            {
              npAT->Flags|= ATBF_DMAMODEENABLED;
            }
            else
            {
              npAT->Flags &= ~ATBF_DMAMODEENABLED;                  /*@V155162*/
            }
          }
          break;


        /*-------------------------------------------*/
        /*  System DMA Scatter/Gather ON or OFF          */
        /*-------------------------------------------*/

        case TOK_ID_DMASGP:         /* [002.2] Modified token definition */

          if ( (Flags & PCF_DMASGP) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_DMASGP;
          npAT->Flags |= ATBF_DMASG;
          DMASG_BasePort = *(NPUSHORT)(pOutBuf+2);
          switch (npAT->DMA_Channel)
          {

                case 3:
              npAT->DMA_SGD_Cmd_port = DMASG_BasePort | 0x013;
              npAT->DMA_SGD_Ptr_port =  DMASG_BasePort | 0x02C;
              break;

            case 5:
              npAT->DMA_SGD_Cmd_port = DMASG_BasePort | 0x015;
              npAT->DMA_SGD_Ptr_port =  DMASG_BasePort | 0x034;
              break;

            case 6:
              npAT->DMA_SGD_Cmd_port = DMASG_BasePort | 0x016;
              npAT->DMA_SGD_Ptr_port =  DMASG_BasePort | 0x038;
              break;

            case 7:
              npAT->DMA_SGD_Cmd_port = DMASG_BasePort | 0x017;
              npAT->DMA_SGD_Ptr_port =  DMASG_BasePort | 0x03C;
              break;

            default:
              npAT->Flags |= ATBF_DMASG;
              npAT->DMA_SGD_Cmd_port = 0;
              npAT->DMA_SGD_Ptr_port =  0;
              break;
                  }
          break;

        /*-------------------------------------------*/
        /*  DMA Scatter/Gather Disabled              */
        /*-------------------------------------------*/

        case TOK_ID_NOT_DMASG:

          npAT->Flags &= ~ATBF_DMASG;                               /*@V155162*/
          SystemDMASG = 0;
          break;

        /*-------------------------------------------*/
        /*  DMA Channel Number /DC:                  */
        /*-------------------------------------------*/

        case TOK_ID_DMACHNL:
          if ( (Flags & PCF_DMACHANNEL) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_DMACHANNEL;

          switch  (*(NPUSHORT)(pOutBuf+2))
          {
            case 3:
              npAT->DMA_Channel = *(NPUSHORT)(pOutBuf+2);
              npAT->DMA_Count_port = 0x0007;
              npAT->DMA_Addr_port = 0x0006;
              npAT->DMA_Addr_page_port = 0x0082;
              npAT->DMA_Mode_port = 0x000B;
              npAT->DMA_Chain_mode      = 0x040A;
              npAT->DMA_Ext_Mode_port   = 0x040B;
              npAT->DMA_Mask_port = 0x000A;
              npAT->DMA_Clr_Byte_ptr = 0x000C;
              npAT->DMA_SGD_Cmd_port = 0x0413;
              npAT->DMA_SGD_Ptr_port = 0x042C;
              break;

            case 5:
              npAT->DMA_Channel = *(NPUSHORT)(pOutBuf+2);
              npAT->DMA_Count_port      = 0x00C6;
              npAT->DMA_Addr_port       = 0x00C4;
              npAT->DMA_Addr_page_port = 0x008B;
              npAT->DMA_Mode_port = 0x00D6;
              npAT->DMA_Chain_mode      = 0x04D4;
              npAT->DMA_Ext_Mode_port   = 0x04D6;
              npAT->DMA_Mask_port = 0x00D4;
              npAT->DMA_Clr_Byte_ptr = 0x00D8;
              npAT->DMA_SGD_Cmd_port = 0x0415;
              npAT->DMA_SGD_Ptr_port = 0x0434;
              break;

            case 6:
              npAT->DMA_Channel = *(NPUSHORT)(pOutBuf+2);
              npAT->DMA_Count_port      = 0x00CA;
              npAT->DMA_Addr_port       = 0x00C8;
              npAT->DMA_Addr_page_port = 0x0089;
              npAT->DMA_Mode_port = 0x00D6;
              npAT->DMA_Chain_mode      = 0x04D4;
              npAT->DMA_Ext_Mode_port   = 0x04D6;
              npAT->DMA_Mask_port = 0x00D4;
              npAT->DMA_Clr_Byte_ptr = 0x00D8;
              npAT->DMA_SGD_Cmd_port = 0x416;
              npAT->DMA_SGD_Ptr_port = 0x438;
              break;

            case 7:
              npAT->DMA_Channel = *(NPUSHORT)(pOutBuf+2);
              npAT->DMA_Count_port      = 0x00CE;
              npAT->DMA_Addr_port       = 0x00CC;
              npAT->DMA_Addr_page_port = 0x008A;
              npAT->DMA_Mode_port = 0x00D6;
              npAT->DMA_Chain_mode      = 0x04D4;
              npAT->DMA_Ext_Mode_port   = 0x04D6;
              npAT->DMA_Mask_port = 0x00D4;
              npAT->DMA_Clr_Byte_ptr = 0x00D8;
              npAT->DMA_SGD_Cmd_port = 0x0417;
              npAT->DMA_SGD_Ptr_port = 0x043C;
              break;

            default:
              npAT->DMA_Channel = 0;
              npAT->DMA_Count_port = 0;
              npAT->DMA_Addr_port=0;
              npAT->DMA_Addr_page_port = 0;
              npAT->DMA_Mode_port = 0;
              npAT->DMA_Chain_mode = 0;
              npAT->DMA_Ext_Mode_port= 0;
              npAT->DMA_Mask_port       = 0;
              npAT->DMA_Clr_Byte_ptr = 0;
              npAT->DMA_SGD_Cmd_port = 0;
              npAT->DMA_SGD_Ptr_port = 0;
              break;
          }

          if (npAT->SysDMAType != 0)
          {
            npAT->Flags |= ATBF_DMAMODEENABLED;
            if (SystemDMASG == 1)
            {
              npAT->Flags |= ATBF_DMASG;
            }
          }
          break;

/* End [001.1] */

/* Begin [002.2] Added switches for Bus Master DMA and enable scatter/gather */

        /*-------------------------------------------*/
        /*  DMA Scatter/Gather Enabled               */
        /*-------------------------------------------*/

        case TOK_ID_DMASG:

          npAT->Flags |= ATBF_DMASG;
          SystemDMASG = 1;
          break;

        /*-------------------------------------------*/
        /*  Bus Master DMA Enable/Disable            */
        /*                                           */
        /* If this switch occurs after the /UNIT:x   */
        /* switch then the disable action applies    */
        /* only towards that specific unit.          */
        /*                                           */
        /* If it appears after the /A:x switch then  */
        /* it applies to all units of the adapter.   */
        /* Any other use of these switches is not    */
        /* valid.                                    */
        /*-------------------------------------------*/

        case TOK_ID_BM_DMA:
          if ( (Flags & PCF_BMDMA) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_BMDMA;

          if ( Flags & PCF_UNIT0 )
          {
            npAT->BM_Overides |= ATBM_BM_UNIT0;
          }
          else if ( Flags & PCF_UNIT1 )
          {
            npAT->BM_Overides |= ATBM_BM_UNIT1;
          }
          else                                                                      /*@V162458*/
          {                                                                         /*@V162458*/
            npAT->BM_Overides |= ( ATBM_BM_UNIT0 | ATBM_BM_UNIT1 );                 /*@V162458*/
          }                                                                         /*@V162458*/
          #ifdef DMA_DEFAULT_OFF                                                              /*@V162458*/
                npAT->Flags |= ATBF_BM_DMA;         /* force DMA enabled for Bus Master *//*@V162458*/
                npAT->Flags |= ATBF_DMASG;          /* also force scatter/gather on */    /*@V162458*/
          #endif                                                                              /*@V162458*/

          break;

        case TOK_ID_NOT_BM_DMA:
          if ( (Flags & PCF_BMDMA) )
          {
            rc = 1;
            break;
          }

          Flags |= PCF_BMDMA;

          if ( Flags & PCF_UNIT0 )
          {
            npAT->BM_Overides |= ATBM_NOBM_UNIT0;
          }
          else if ( Flags & PCF_UNIT1 )
          {
            npAT->BM_Overides |= ATBM_NOBM_UNIT1;
          }
          else
          {
            npAT->BM_Overides |= ( ATBM_NOBM_UNIT0 | ATBM_NOBM_UNIT1 );       /* [023] */
            npAT->Flags &= ~(ATBF_BM_DMA | ATBF_DMASG);             /*@V190477*/
          }
          break;

/* End [002.2] */

      /*-------------------------------------------*/               /*@V182291*/
      /* Enable Forced Drive Light Control for     */               /*@V182291*/
      /* PS2 IDE - /LED                            */               /*@V182291*/
      /*-------------------------------------------*/               /*@V182291*/
                                                                    /*@V182291*/
      case TOK_ID_PS2LED:                                           /*@V182291*/
                                                                    /*@V182291*/
        if ( (Flags & PCF_PS2LED) )                                 /*@V182291*/
        {                                                           /*@V182291*/
          rc = 1;                                                   /*@V182291*/
          break;                                                    /*@V182291*/
        }                                                           /*@V182291*/
                                                                    /*@V182291*/
        Flags |= PCF_PS2LED;                                        /*@V182291*/
                                                                    /*@V182291*/
        npAT->Flags |= ATBF_PS2IDEPORT;                             /*@V182291*/
                                                                    /*@V182291*/
        break;                                                      /*@V182291*/

      /*-------------------------------------------*/               /*@V192088*/
      /* Last Cylinder Adjust                      */               /*@VVVVVVV*/
      /*                       /!CYLA     /CYLA    */
      /*-------------------------------------------*/

      case TOK_ID_NOT_CYLA:

        if( Flags & PCF_CYLA )
        {
          rc = 1;
          break;
        }

        LastCylinderAdjust = 1;

        Flags |= PCF_CYLA;

        break;

      case TOK_ID_CYLA:

        if( Flags & PCF_CYLA )
        {
          rc = 1;
          break;
        }

        LastCylinderAdjust = 0;

        Flags |= PCF_CYLA;
                                                                     /*AAAAAAAA*/
        break;                                                       /*@V192088*/
                                                            /* Start of roman16 */
      case TOK_ID_SHUTDOWN:                                 //@roman16
         Shutdown=0;                                        //@roman16
         break;                                             //@roman16
                                                            /* End of roman16 */
      case  TOK_ID_FORCEDUDMA:                              
         MaxUDMA = pOutBuf[2];                              /*Force UDMA limit*/
         break;
#ifdef BBR
      case TOK_ID_BBRINT3:

        // User wants an int 3 when a BB is detected on this unit.
        npUT->BBRFlags |= BBRF_INT3;

      case TOK_ID_BBR:

        // Can receive an array of     block specifiers consisting of a
        // starting RBA and a length.  First determine how many sequences
        // were specified.
        i = (Length - TOK_MIN_LENGTH)/6;
        if( i > MAX_BBR_SEQUENCES )
        {
           i = MAX_BBR_SEQUENCES;
        }
        for( j = 0; j < i; j++ )
        {
           npUT->BBRSequence[j].startBlock = *(ULONG NEAR *)
              (pOutBuf + TOK_MIN_LENGTH + (j * sizeof(BBR_SEQUENCE)));
           npUT->BBRSequence[j].blockCount = *(USHORT NEAR *)
              (pOutBuf + TOK_MIN_LENGTH + (j * sizeof(BBR_SEQUENCE)) + sizeof(ULONG));
        }

        npUT->nBBRSequences = i;

        break;
#endif

        /*-------------------------------------------*/
        /* Unknown Switch                            */
        /*                                           */
        /*-------------------------------------------*/

        default:

          rc = 1;
          break;
      }

      if ( !rc ) pOutBuf += Length;

    }
  }
  else if ( cc.ret_code != NO_OPTIONS_FND_ERR )
  {
    rc = 1;
  }

  return( rc );
}


/*------------------------------------*/
/*                                    */
/* PrintInfo()                        */
/*                                    */
/*------------------------------------*/
VOID PrintInfo( NPATBL npAT )
{
  NPACB    npACB;
  NPUCB    npUCB;
  NPUTBL   npUT;

  USHORT   i;
  USHORT   j;

  UCHAR    Buf[122];
  PUCHAR   s = Buf;
  UCHAR    Buf1[30];                /* [021] Buffer for DM or EzDrive message */
  PUCHAR   s1 = Buf1;               /* [021] */
  UCHAR    Buf2[30];                /* [002.1] Buffer for enhanced DMA message */
  PUCHAR   s2 = Buf2;               /* [002.1] Buffer for enhanced DMA message */
  UCHAR    Buf3[30];                /* [003] Buffer for enhanced DMA message */
  PUCHAR   s3 = Buf3;               /* [003] Buffer for enhanced DMA message */
  UCHAR    Buf4[30];                                                /*@V192176*/
  PUCHAR   s4 = Buf4;                                               /*@V192176*/
  USHORT   percentUsed[3];                                          /*@V192176*/
  ULONG    TSectorsUsed;                                            
  ULONG    TSectorsAvail;                                           

  TTYWrite( VersionMsg );

  for ( j = 0; j < MAX_ADAPTERS; j++, npAT++ )
  {
    if ( !(npAT->Flags & ATBF_DISABLED) )
    {
      npACB = npAT->npACB;

      sprntf( (PUCHAR) s,
              (PUCHAR) VControllerInfo,                             /*@V106915*/
              (USHORT) j,
              (USHORT) npAT->BasePort,
              (USHORT) npAT->IRQLevel,
              (PSZ)    (((npAT->PCIInfo.Present) && (npAT->Status == 1))
                         ? AdptMsgs[NO_DEVICES_FOUND] : AdptMsgs[npAT->Status]),
              (PSZ)    ( ((npAT->Flags & ATBF_BM_DMA) && !(npAT->Status)) ?
                                                         MsgBMOn : MsgNull ),
              (PSZ)    ( (((npAT->Flags & ATBF_BM_DMA) || (npAT->Flags & ATBF_DMAMODEENABLED))
                                    && !(npAT->Status)) ? MsgDMAtxt : MsgNull ),
              (PSZ)    (((((npAT->Flags & ATBF_DMAMODEENABLED)||(npAT->Flags & ATBF_BM_DMA)) &&
                        (npAT->Flags & ATBF_DMASG)) && !(npAT->Status))  ? MsgSGOn : MsgNull)); /* [001.4] */

      TTYWrite( s );

      if( npAT->PCIInfo.Present )                                   /*@V129765*//*@V159935*/
      {                                                             /*@V129765*/
         sprntf( (PUCHAR) s,                                        /*@V129765*/
                 (PUCHAR) VPCIInfo,                                 /*@V129765*/
                 (UCHAR)  PCIMajorVer,                              /*@V129765*/
                 (UCHAR)  PCIMinorVer,                              /*@V129765*/
                 (PSZ)    npAT->npPCIDeviceMsg,                     /*@V129765*/
                 (UCHAR)  npAT->PCIInfo.Ident.Revision,             /*@V129765*//*@V159935*/
                 (USHORT) npAT->PCIInfo.Ident.Vendor,               /*@V129765*//*@V159935*/
                 (USHORT) npAT->PCIInfo.Ident.Device );             /*@V129765*//*@V159935*/
         TTYWrite( s );                                             /*@V129765*/
      }                                                             /*@V129765*/

      if( npACB = npAT->npACB )
      {
        // Pause the output between adapters so verbose info does   /*@V192545*/
        // not roll off the screen.                                 /*@V192545*/
        if( j && (Verbose & 0x02) )                                 /*@V192545*/
        {                                                           /*@V192545*/
           sprntf( s, (PSZ)VPauseVerbose0 );                        /*@V192545*/
           TTYWrite( s );                                           /*@V192545*/
        }                                                           /*@V192545*/

        for ( i=0; i < npACB->cUnits; i++ )
        {
          npUT =  &npAT->Unit[i];
          npUCB = &npACB->UnitCB[i];

          if ( npUCB->Flags & UCBF_ATAPIDEVICE )                   /*@V87325*/
          {                                                        /*@V87325*/
            /*****************************/
            /* Process Strings s2 and s3 */
            /*****************************/

            ProcessVerboseTimings( npUCB, npAT, s2, s3 );

            sprntf( (PUCHAR) s,                                    /*@V87325*/
                     (PUCHAR) VUnitInfo1,                         /*@V106915*/
                     (USHORT) i,                                   /*@V87325*/
                     (PSZ)    ATAPIMsg,                            /*@V87325*/ /* [007] */
                     (PSZ)    s2,                                   /*@V179942*/
                     (PSZ)    s3 );                                /* [007] */
                                                                   /*@V87325*/
            TTYWrite( s );                                         /*@V87325*/
          }                                                        /*@V87325*/
          else if ( npUT->Status == UTS_NO_MASTER )               /*@V108783*/
          {                                                       /*@V108783*/
            sprntf( (PUCHAR) s,                                   /*@V108783*/
                     (PUCHAR) VUnitInfo1,                         /*@V108783*/
                     (USHORT) i,                                  /*@V108783*/
                     (PSZ)    UnitMsgs[npUT->Status],             /*@V108783*/ /* [007] */
                     (PSZ)    "",                                 /*@V179942*/
                     (PSZ)    "" );                               /* [007] */
                                                                  /*@V108783*/
            TTYWrite( s );                                        /*@V108783*/
          }                                                       /*@V108783*/
          else                                                    /*@V108783*/
          {
            /*****************************/
            /* Process Strings s2 and s3 */
            /*****************************/

            ProcessVerboseTimings( npUCB, npAT, s2, s3 );

            *s1 = 0;

            if ( npUCB->Flags & UCBF_ONTRACK )                /* Disk Manager */
            {
              sprntf( (PUCHAR) s1,
                      (PUCHAR) VString,
                      (PSZ)    MsgONTrackOn );
            }
            else if ( npUCB->Flags & UCBF_EZDRIVEFBP )             /* EZDrive */
            {
              sprntf( (PUCHAR) s1,
                      (PUCHAR) VString,
                      (PSZ)    MsgEzDriveFBP );
            }

            if( npUT->Flags & UTBF_CMDGEOMETRYVALID )               /*@V179486*/
            {                                                       /*@V179486*/
               sprntf( s4, (PSZ)VCMDInfo );                         /*@V179486*/
            }                                                       /*@V179486*/
            else if( npUT->Flags & UTBF_BPBGEOMETRYVALID )          /*@V179486*/
            {                                                       /*@V179486*/
               sprntf( s4, (PSZ)VBPBInfo );                         /*@V179486*/
            }                                                       /*@V179486*/
            else if( npUT->Flags & UTBF_I13GEOMETRYVALID )          /*@V192176*/
            {                                                       /*@V192176*/
               sprntf( s4, (PSZ)VI13Info );                         /*@V192176*/
            }                                                       /*@V192176*/
            else if( npUT->Flags & UTBF_IDEGEOMETRYVALID )          /*@V192176*/
            {                                                       /*@V192176*/
               sprntf( s4, (PSZ)VIDEInfo );                         /*@V192176*/
            }                                                       /*@V192176*/

            sprntf( (PUCHAR) s,
                    (PUCHAR) VUnitInfo2,                            /*@V106915*/
                    (USHORT) i,
                    (PSZ)    UnitMsgs[npUT->Status],

                    (PSZ)   ((npUCB->Flags & UCBF_SMSENABLED) ?        /*@V75103*/
                                                 MsgSMSOn  : MsgNull), /*@V75103*/

                    (PSZ)   ((npUCB->Flags & UCBF_LBAMODE) ?
                                                 MsgLBAOn : MsgNull),

                    (PSZ)   ((npUCB->Flags & UCBF_ONTRACK) ?        /*@V108555*/
                                         MsgONTrackOn : MsgNull), /*@V108555*/ /* [001.4] */
                                                                        /*@V151345*/
                    (PSZ)   ((npUCB->Flags & UCBF_FORCE) ?          /*@V149971*//*@V155162*/
                             MsgUnitForce: MsgNull),                /*@V149971*/
                    (PUCHAR)s1,                                         /* [021] */
                    (PUCHAR)s2,                                         /* [002.1] [003] */
                    (PUCHAR)s3,                                         /* [003] */
                    (PUCHAR)s4 );                                   /*@V192176*/
            TTYWrite( s );

            sprntf( (PUCHAR) s,                                        /*@V75103*/
                    (PUCHAR) VModelInfo,                              /*@V106915*/
                                                                       /*@V75103*/
                    (PSZ)    ((npUT->ModelNum[0]) ?                    /*@V75103*/
                                      npUT->ModelNum : VModelUnknown), /*@V75103*/
                                                                       /*@V75103*/
                    (PSZ)    npUT->FirmwareRN  );                      /*@V75103*/
            TTYWrite( s );                                             /*@V75103*/

            if( (npUT->EBIOSCapabilities & BIOS_EXTENSIONS_FIXED_DISK) || /*@V192176*/
                (npUT->EBIOSCapabilities & BIOS_EXTENSIONS_LOCK_EJECT) || /*@V192176*/
                (npUT->EBIOSCapabilities & BIOS_EXTENSIONS_ENHANCED) )    /*@V192176*/
            {                                                       /*@V192176*/
               sprntf( (PUCHAR) s,                                  /*@V192176*/
                       (PUCHAR) EBIOSIdString,                      /*@V192176*/
                       (USHORT) npUT->EBIOSVersion );               /*@V192176*/
               TTYWrite( s );                                       /*@V192176*/
            }                                                       /*@V192176*/
                                                                    /*@V192176*/
            sprntf( (PUCHAR) s,                                     /*@V192176*/
                    (PUCHAR) VGeomInfo0 );                          /*@V192176*/
            TTYWrite( s );                                          /*@V192176*/

            sprntf( (PUCHAR) s,
                    (PUCHAR) VGeomInfo1,                            /*@V106915*/
                     (ULONG) npUCB->LogGeom.TotalCylinders,
                     (ULONG) npUCB->PhysGeom.TotalCylinders,
                     (ULONG) npUT->I13LogGeom.TotalCylinders,
                     (ULONG) npUT->IDELogGeom.TotalCylinders,
                     (ULONG) npUT->IDEPhysGeom.TotalCylinders,
                     (ULONG) npUT->IDEPhysGeom.TotalSectors );      /*@V192176*/
            TTYWrite( s );

            sprntf( (PUCHAR) s,
                    (PUCHAR) VGeomInfo2,                            /*@V106915*/
                    (USHORT) npUCB->LogGeom.NumHeads,
                    (USHORT) npUCB->PhysGeom.NumHeads,
                    (USHORT) npUT->I13LogGeom.NumHeads,
                    (USHORT) npUT->BPBLogGeom.NumHeads,
                    (USHORT) npUT->IDELogGeom.NumHeads,
                    (USHORT) npUT->IDEPhysGeom.NumHeads,
                    (ULONG)  npUCB->LogGeom.TotalSectors );         /*@V192176*/
            TTYWrite( s );

            // Compute % of drive available to the OS.                  /*@V192176*/
            TSectorsUsed  = npUCB->LogGeom.TotalSectors;                
            TSectorsAvail = npUT->IDEPhysGeom.TotalSectors;

            if( TSectorsUsed > 40000000)
            {
               TSectorsUsed  = (TSectorsUsed/10);
               TSectorsAvail = (TSectorsAvail/10);
            }

            percentUsed[0] =      TSectorsUsed * 100l /
                                  TSectorsAvail;
            percentUsed[1] =   (((TSectorsUsed   * 100l) %
                                  TSectorsAvail) * 100l) /
                                  TSectorsAvail;
            percentUsed[2] = (((((TSectorsUsed   * 100l) %
                                  TSectorsAvail) * 100l) %
                                  TSectorsAvail) * 100l) /
                                  TSectorsAvail;                        /*@A235927*/
            if( percentUsed[2] > 50 )                                   /*@V192176*/
            {                                                           /*@V192176*/
               percentUsed[1]++;                                        /*@V192176*/
               if( percentUsed[1] == 100 )                              /*@V192176*/
               {                                                        /*@V192176*/
                  percentUsed[0] = 100;                                 /*@V192176*/
                  percentUsed[1] = 0;                                   /*@V192176*/
               }                                                        /*@V192176*/
            }                                                           /*@V192176*/

            sprntf( (PUCHAR) s,
                    (PUCHAR) VGeomInfo3,                            /*@V106915*/
                    (USHORT) npUCB->LogGeom.SectorsPerTrack,
                    (USHORT) npUCB->PhysGeom.SectorsPerTrack,
                    (USHORT) npUT->I13LogGeom.SectorsPerTrack,
                    (USHORT) npUT->BPBLogGeom.SectorsPerTrack,
                    (USHORT) npUT->IDELogGeom.SectorsPerTrack,
                    (USHORT) npUT->IDEPhysGeom.SectorsPerTrack,
                    (USHORT) percentUsed[0],                        /*@V192176*/
                    (USHORT) percentUsed[1] );                      /*@V192176*/
            TTYWrite( s );
          }
        }
      }
      else                                                          /*@V159935*/
      {                                                             /*@V159935*/
            sprntf( (PUCHAR) s,                                     /*@V159935*/
                    (PUCHAR) MsgACBNotVia );                        /*@V159935*/
            TTYWrite( s );                                          /*@V159935*/
      }                                                             /*@V159935*/
    }                                                               /*@V159935*/
  }

  // Pause the output at the end of verbose messages so info does   /*@V192545*/
  // not roll off the screen.                                       /*@V192545*/
  if( Verbose & 0x02 )                                              /*@V192545*/
  {                                                                 /*@V192545*/
     sprntf( s, (PSZ)VPauseVerbose1 );                              /*@V192545*/
     TTYWrite( s );                                                 /*@V192545*/
  }                                                                 /*@V192545*/
}

/*-------------------------------*/
/*                               */
/* TTYWrite()                    */
/*                               */
/*-------------------------------*/
VOID TTYWrite( PSZ Buf )
{
  InitMsg.MsgStrings[0] = Buf;

  DevHelp_Save_Message( (NPBYTE) &InitMsg );
}


/*-------------------------------*/
/*                               */
/* ProcessVerboseTimings()       */
/*                               */
/*-------------------------------*/
VOID ProcessVerboseTimings( NPUCB npUCB, NPATBL npAT, PUCHAR s2, PUCHAR s3 )
{
   *s2 = 0;                                      /* start with empty strings */
   *s3 = 0;

   /*********************************/
   /* s2 string Processing          */
   /*********************************/

   if( npUCB->Flags & UCBF_BM_DMA )
   {
     sprntf( (PUCHAR) s2,
             (PUCHAR) VString,
             (PSZ)    MsgTypeMDMAOn );
   }
   else if ( npUCB->Flags & UCBF_DMAMODE )
   {
     if ((npAT->SysDMAType & SDMA_MASK) == SDMA_TYPE_B)
     {
       sprntf( (PUCHAR) s2,
               (PUCHAR) VString,
               (PSZ)    MsgTypeBDMAOn );
     }
     else if ((npAT->SysDMAType & SDMA_MASK) == SDMA_TYPE_F)
     {
       sprntf( (PUCHAR) s2,
               (PUCHAR) VString,
               (PSZ)    MsgTypeFDMAOn );
     }
   }

   /*********************************/
   /* s3 string Processing          */
   /*********************************/

   if( (npUCB->Flags & UCBF_BM_DMA)||(npUCB->Flags & UCBF_DMAMODE) )
   {
      if( npUCB->CurDMAMode > 2 )             /* show UltraDMA and PIO modes */
      {
         sprntf( (PUCHAR) s3,
                 (PUCHAR) VULTRADMAString,
                 (USHORT) GetUltraDMAMode( npUCB->CurDMAMode ),    
                 (USHORT) npUCB->CurPIOMode  );
      } else {
         sprntf( (PUCHAR) s3,                      /* show DMA and PIO modes */
                 (PUCHAR) VDMAString,
                 (USHORT) npUCB->CurDMAMode,
                 (USHORT) npUCB->CurPIOMode );
      }
   } else {                                            /* show only PIO mode */
      sprntf( (PUCHAR) s3,
              (PUCHAR) VPIOString,
              (USHORT) npUCB->CurPIOMode );
   }
}

/*------------------------------------*/                           /*@V108555*/
/*                                    */                           /*@VVVVVVV*/
/* CheckSMSEnable()                   */
/*                                    */
/*------------------------------------*/
USHORT CheckSMSEnable()
{
  PBYTE         pBIOS = 0;
  ULONG         ppBIOS;
  USHORT        rc = 0;
  USHORT        ModeFlag;

  /*------------------------------------------------*/
  /* Scan BIOS Region for Promise Controller BIOS   */
  /*                                                */
  /* Promise controllers dont like multiple mode    */
  /* even though the disk reports it supports this  */
  /* feature. This is fixed in later versions of    */
  /* the controller which suppress the reporting    */
  /* of Multiple Mode support in the ATA Identify   */
  /* data.                                          */
  /*------------------------------------------------*/

  for ( ppBIOS = BIOS_MEM_LOW; ppBIOS < BIOS_MEM_HIGH; ppBIOS+=BIOS_SIZE )
  {
    if ( DevHelp_PhysToVirt((ULONG)   ppBIOS,
                            (USHORT)  BIOS_SIZE,
                            (PVOID)   &pBIOS,
                            (PUSHORT) &ModeFlag          ) )
    {
      break;
    }

    if ( !strncmp( pBIOS+PROMISE_ID_STRING_OFFSET,
                  PromiseIdString,
                  PromiseIdLength )                   )
    {
      rc = 1;
      break;
    }
  }

  return ( rc );                                                    /*@VAAAAAA*/
}                                                                   /*@V108555*/

/*-------------------------------*/                                  /*@V98451*/
/* AllocAdapterResources()       */
/*                               */
/*-------------------------------*/
USHORT NEAR AllocAdapterResources ( NPATBL npAT )
{
   USHORT         rc = 0;
   RESOURCESTRUCT Resource;
   PAHRESOURCE    pResourceList;

   pResourceList = (PAHRESOURCE)&npAT->ResourceBuf;

   pResourceList->NumResource  = 3;
   pResourceList->hResource[0] = 0L;
   pResourceList->hResource[1] = 0L;
   pResourceList->hResource[2] = 0L;

   /*-----------------------*/
   /* AllocIRQResource      */
   /*-----------------------*/

   Resource.ResourceType              = RS_TYPE_IRQ;
   Resource.IRQResource.IRQLevel      = npAT->IRQLevel;
   Resource.IRQResource.Reserved      = 0;
   Resource.IRQResource.pfnIntHandler = 0l;

   if( NativePCIIDE( npAT ))
   {
      Resource.IRQResource.PCIIrqPin  = RS_PCI_INT_A;    /* We assume INTA */
      Resource.IRQResource.IRQFlags   = RS_IRQ_SHARED;
   } else {
      Resource.IRQResource.PCIIrqPin  = RS_PCI_INT_NONE;

      if( GetIRQSharedBit( npAT->IRQLevel ))                      /*@217469*/
      {
         Resource.IRQResource.IRQFlags   = RS_IRQ_SHARED;
      } else {
         Resource.IRQResource.IRQFlags   = RS_IRQ_MULTIPLEXED;
      }
   }

   if ( (rc = RMAllocResource( hDriver,
                               &pResourceList->hResource[0],
                               &Resource ))  )
   {
     npAT->Status = ATS_ALLOC_IRQ_FAILED;
     goto AllocAdapterResourcesExit;
   }

   /*----------------------*/
   /* AllocIOResource      */
   /*----------------------*/

   Resource.IOResource.BaseIOPort     = npAT->BasePort;
   Resource.ResourceType              = RS_TYPE_IO;
   Resource.IOResource.IOAddressLines = 16;
   Resource.IOResource.NumIOPorts     = FI_RFDR;
   Resource.IOResource.IOFlags        = RS_IO_MULTIPLEXED;

   if ( (rc = RMAllocResource( hDriver,
                               &pResourceList->hResource[1],
                               &Resource ))  )
   {
     npAT->Status = ATS_ALLOC_IO_FAILED;
     RMDeallocResource( hDriver, pResourceList->hResource[0]);
     pResourceList->hResource[0] = 0;
     goto AllocAdapterResourcesExit;
   }

   /*----------------------*/
   /* AllocIOResource      */
   /*----------------------*/

   Resource.ResourceType              = RS_TYPE_IO;
   Resource.IOResource.IOAddressLines = 16;
   Resource.IOResource.NumIOPorts     = 1;
   Resource.IOResource.IOFlags        = RS_IO_MULTIPLEXED;

   if( NativePCIIDE( npAT ))
   {
      Resource.IOResource.BaseIOPort  = npAT->StatusPort;
   } else {
      Resource.IOResource.BaseIOPort  = npAT->BasePort+FI_PDRHD |
                                           ((npAT->BasePort & 0x0200)?
                                                   0x0308 : 0x0300);
   }

   if ( (rc = RMAllocResource( hDriver,
                               &pResourceList->hResource[2],
                               &Resource ))  )
   {
     npAT->Status = ATS_ALLOC_IO_FAILED;
     RMDeallocResource( hDriver, pResourceList->hResource[0]);
     RMDeallocResource( hDriver, pResourceList->hResource[1]);
     pResourceList->hResource[0] = 0;
     pResourceList->hResource[1] = 0;
     goto AllocAdapterResourcesExit;
   }

   AllocAdapterResourcesExit:

   return( rc );
}

/*-------------------------------*/
/*                               */
/* DeallocAdapterResources()     */
/*                               */
/*-------------------------------*/
VOID NEAR DeallocAdapterResources ( NPATBL npAT )                 /*@V98451*/
{
   RESOURCESTRUCT Resource;
   PAHRESOURCE    pResourceList;

   pResourceList = (PAHRESOURCE)&npAT->ResourceBuf;

   if(pResourceList->hResource[0])
      RMDeallocResource( hDriver, pResourceList->hResource[0]);  /*V98451*/
   if(pResourceList->hResource[1])
      RMDeallocResource( hDriver, pResourceList->hResource[1]);  /*V98451*/
   if(pResourceList->hResource[2])
      RMDeallocResource( hDriver, pResourceList->hResource[2]);  /*V98451*/

   return;
}

/*-------------------------------*/
/*                               */
/* AssignResources()             */
/*                               */
/*-------------------------------*/
VOID NEAR AssignResources()
{
   UCHAR   i, j, k;
   NPATBL  npAT;
   NPUTBL  npUT;
   NPACB   npACB;
   ADJUNCT Adjunct;
   UCHAR   Buf[42];

   Adjunct.pNextAdj = 0;
   Adjunct.AdjLength = sizeof(ADJUNCT);
   Adjunct.AdjType   = ADJ_ADD_UNIT;
   Adjunct.Add_Unit.ADDHandle = ADDHandle;

   for( i=0, npAT = AdapterTable; i < cAdapters; npAT++ )
   {
      if ( !npAT->cUnits )                                          /*@V108555*/
      {
         continue;
      }

      npACB = npAT->npACB;

      /*---------------------------------------------------*/
      /* increment controller number in adapter string:    */
      /* Original String is "IDE_0 ST506/IDE Controller"   */
      /*---------------------------------------------------*/

      AdapterStruct.AdaptDescriptName[4] = '0' + i;                 /*@V153620*/
      i++;

      /*
      ** There is adapter object information available to
      ** identify individual PCI adapters.  Only a global is
      ** is available to disern other bus types.  Default host
      ** host bus type is AS_HOSTBUS_ISA.
      */
      if( npAT->PCIInfo.Present )
         AdapterStruct.HostBusType = AS_HOSTBUS_PCI;
      else if( DriverBusType == BUS_EISA )
         AdapterStruct.HostBusType = AS_HOSTBUS_EISA;
      else if( DriverBusType == BUS_MCA )
         AdapterStruct.HostBusType = AS_HOSTBUS_uCHNL;
      else
         AdapterStruct.HostBusType = AS_HOSTBUS_ISA;

      if (RMCreateAdapter( hDriver,
                           &npAT->hAdapter,
                           &AdapterStruct,
                           (HDEVICE)NULL,
                           (PAHRESOURCE)&npAT->ResourceBuf))
      {
         _asm int 3    /* Need to Halt */
      }

      for (j=0; j < npACB->cUnits; j++ )
      {
         Adjunct.Add_Unit.UnitHandle = (USHORT) &npACB->UnitCB[j];
         DevStruct.pAdjunctList = &Adjunct;

         npUT  = &npAT->Unit[j];

         if (!( npACB->UnitCB[j].Flags & UCBF_ATAPIDEVICE ) )
         {
            /*-----------------------------------------*/
            /* Copy Device Description to local buffer */
            /*-----------------------------------------*/

            for (k=0; (k < 42) && DevDescriptNameTxt[k] ; k++ )
            {
               Buf[k] = DevDescriptNameTxt[k];
            }

            /* ensure null termination */
            Buf[15] = 0;

            /*---------------------------------------------------*/
            /* increment device number in buffer string:         */
            /* Original String is "HD_0 Hard Drive"              */
            /*---------------------------------------------------*/

            Buf[3]+=j;

            /*--------------------------------------------------*/
            /* if a model number is exists, copy the portion of */
            /* string that will fit in the local buffer         */
            /*--------------------------------------------------*/

            if (npUT->ModelNum[0])
            {
               /* put a space between key and drive info */

               Buf[4] = ' ';

               for (k=5; (k < 42) && npUT->ModelNum[k-5]; k++)
               {
                  Buf[k] = npUT->ModelNum[k-5];
               }

               /* ensure we are null terminated */

               Buf[41] = 0;
            }

            DevStruct.DevDescriptName = (PSZ) &Buf;

            // SRD report to RM correctly                           /*@V151345*/
            if(npACB->UnitCB[j].Flags & UCBF_REMOVABLE)             /*@VVVVVVV*/
              {
              DevStruct.DevFlags=DS_REMOVEABLE_MEDIA;
              } /* endif */
            else
              {
              DevStruct.DevFlags=DS_FIXED_LOGICALNAME;              /*@AAAAAAA*/
              } /* endelse */                                       /*@V151345*/

            if ( RMCreateDevice( hDriver,
                                 &npACB->UnitCB[j].hDevice,
                                 &DevStruct,
                                 npAT->hAdapter,
                                 NULL))
            {
               _asm int 3
            }
         }
      }
   }
}                                                                    /*@VAAAAA*/
                                                                     /*@V98451*/

/*-------------------------------*/
/*                               */
/* LocateATEntry()               */
/*                               */
/*-------------------------------*/
NPATBL NEAR LocateATEntry( USHORT BasePort )                        /*@V153620*/
{                                                                   /*@VVVVVVV*/
NPATBL npAT=AdapterTable;
USHORT i;
       for(i=0; i<MAX_ADAPTERS;i++, npAT++ )
         {
         // if the ports match
         if(BasePort==npAT->BasePort)
           {
           // we've found the entry
           break;
           } /* endif */
         else
           {
           // if port didn't match, is this entry disabled
           // and not defined??
           if((npAT->Flags & ATBF_DISABLED) && (npAT->BasePort==0))
             {
             // found the place to put this one
             break;
             } /* endif */
           } /* endelse */
         } /* endfor */
         // searched table, no free slots, oops
         if(i==MAX_ADAPTERS)
           {
           npAT=NULL;
           } /* endif */
        return npAT;
}

/*-------------------------------*/
/*                               */
/* UpdateATTable()               */
/*                               */
/*-------------------------------*/
VOID NEAR UpdateATTable( PRESOURCELIST pResourceList )
{
NPATBL npAT;
USHORT i,j;

        // loop thru the resource structures
        for(j=0; j<pResourceList->Count; j++)
          {
          // if this is an IO Structure with an 8 port usage
          // (status port is one port usage)
          if(pResourceList->Resource[j].ResourceType==RS_TYPE_IO &&
             pResourceList->Resource[j].IOResource.NumIOPorts==8
            )
            {
            // find AT entry that matches, or a new one
            if(npAT=LocateATEntry(pResourceList->Resource[j].IOResource.BaseIOPort))
              {
              // turn off disabled flag
              npAT->Flags &=~ATBF_DISABLED;
              // start at the top of the resource list again
              for(i=0; i<pResourceList->Count; i++)
                {
                switch(pResourceList->Resource[i].ResourceType)
                  {
                  case RS_TYPE_IO:
                    // set base port address
                    if(pResourceList->Resource[i].IOResource.NumIOPorts==8)
                      {
                      npAT->BasePort=pResourceList->Resource[i].IOResource.BaseIOPort;
                      } /* endif */
                    else
                      {
                      // set Device Control port address
                      npAT->StatusPort=pResourceList->Resource[i].IOResource.BaseIOPort;
                      // set flag to indicate this is exactly what we have
                      // don't calculate it later
                      npAT->Flags |= ATBF_CONTROLSPECIFIC;
                      } /* endelse */
                    break;
                  case RS_TYPE_IRQ:
                    // set IRQ level
                    npAT->IRQLevel=pResourceList->Resource[i].IRQResource.IRQLevel;
                    break;
                  case RS_TYPE_DMA:
                    // Set DMA channel
                    npAT->DMA_Channel=pResourceList->Resource[i].DMAResource.DMAChannel;
                    break;
                  default:
                    // shouldn't be any other resources
                   break;
                  } /* endswitch */
                } /* endfor */
              } /* endif */
            // done handling this entry
            break;
            } /* endif */
          } /* endfor */

}

/*-------------------------------*/
/*                               */
/* FindDetected()                */
/*                               */
/*-------------------------------*/
VOID NEAR FindDetected( BOOL CompatableID )
{
ULONG pnpid=0,Compatid=0;
CHAR work[sizeof(HANDLELIST)+(sizeof(RMHANDLE)*MAX_ADAPTERS)];
PHANDLELIST pHandleList=(PHANDLELIST)&work;
USHORT i,j;
PRM_GETNODE_DATA pNode=(PRM_GETNODE_DATA)&PnPwork;

   // convert ID to binary
   if(!RMConvertID(CompatableID?&Compatid:&pnpid,IDEPnPID,RM_CONVERT_TO_ID))
     {
     // clear handle counts
     pHandleList->cHandles= 0;                      // force count to 0
     pHandleList->cMaxHandles= 1+MAX_ADAPTERS;      // tell how much room is in the buffer
     // search for devices with this ID
     RMDevIDToHandleList(RM_IDTYPE_EISA,            // specific format of device ID fields
                           pnpid,
                           NULL,
                           Compatid,
                           NULL,
                           NULL,
                           CompatableID?SEARCH_ID_COMPATIBLEID:SEARCH_ID_DEVICEID,
                                                      // device ID fields
                           HANDLE_CURRENT_DETECTED,   // search the CURRENT detected tree
                           pHandleList );             // place for output
     // if there were some devices found
     if(pHandleList->cHandles)
       {
       // loop thru the list
       for(i=0; i<pHandleList->cHandles; i++ )
         {
         // get size of data for node space
         pNode->RMNodeSize=sizeof(PnPwork);
         // Get the node data now
         if(!RMGetNodeInfo(pHandleList->Handles[i],pNode, sizeof(PnPwork)))
           {
           // update the Adapter Table with this node
           if(pNode->RMNode.pResourceList)
             {
             UpdateATTable(pNode->RMNode.pResourceList);
             } /* endif */
           } /* endif */
         } /* endfor */
       } /* endif */
     } /* endif */                                                  /*@AAAAAAA*/
}                                                                   /*@V153620*/

/*-------------------------------*/                                /*@V179942*/
/*                               */                                /*VVVVVVVV*/
/* UCBSetupDMAPIO()              */
/*                               */
/* For ATA or ATAPI devices      */
/*                               */
/*-------------------------------*/
VOID UCBSetupDMAPIO( NPIDENTIFYDATA npID, NPATBL npAT, NPUCB npUCB,
                                                       USHORT WDIDValid )
{
   /********************************************/
   /* Note: WDIDValid should only apply to ATA */
   /*       drives and not ATAPI devices       */
   /********************************************/
  if( (npID->IDECapabilities & FX_DMASUPPORTED) &&
        ((npAT->Flags & ATBF_DMAMODEENABLED) || (npAT->Flags & ATBF_BM_DMA)) )
   {
      /*****************************************/
      /* Set DMA or Bus Master DMA enable bits */
      /* depending on adapter setting          */
      /*****************************************/

      if( npAT->Flags  & ATBF_DMAMODEENABLED )
         npUCB->Flags |= UCBF_DMAMODE;

      if( npAT->Flags  & ATBF_BM_DMA )
         npUCB->Flags |= UCBF_BM_DMA;

      /***********************************/
      /* Check for Device Ultra DMA Mode */
      /***********************************/

      if( npID->AdditionalWordsValid & FX_WORD88_VALID )
      {
         GetDeviceULTRAMode( npUCB, npID );
      }

      /****************************************/
      /* Check for Device Multi-Word DMA Mode */
      /****************************************/

      /***********************************************************/
      /* We will assume that if a drive supports words 64-70 it  */
      /* also supports word 63 (multi-word DMA modes supported). */
      /***********************************************************/

      if( npID->AdditionalWordsValid & FX_WORDS64_70VALID )
      {
         GetDeviceDMAMode( npUCB, npID, npAT);
      }
      else if( (npID->DMACycleTime >= 0x200) && WDIDValid )
      {
        /************************************************************/
        /* If older WDC drive then use word 52 to decide DMA timing */
        /* Note this is for ATA drives only                         */
        /************************************************************/

        npUCB->DMAType = 0x003C;     /* Type F DMA, 16 bit I/O Count by Bytes */
        npUCB->CurDMAMode = 1;       /* ATA-2 Mode 1 DMA */
      }
      else if( WDIDValid )
      {
        npUCB->Flags &= ~( UCBF_BM_DMA | UCBF_DMAMODE );
        npUCB->DMAType = 0x002C;   /* Type B DMA, 16 bit IO Count by Bytes */
        npUCB->CurDMAMode = 0;        /* ATA-2 Mode 0 DMA */
      }
   }

   /*********************************/
   /*     Get Device PIO Mode       */
   /*********************************/

   if( npID->AdditionalWordsValid & FX_WORDS64_70VALID )
   {
      GetDevicePIOMode( npUCB, npID );
   }

   /***********************************/
   /* Check for     WDC Mode 3 drives */
   /***********************************/

   if( WDIDValid &&
      (npUCB->CurPIOMode != 4) && (npID->Reserved4[129-69] != 0x5555) )
   {
     npUCB->Flags     &= ~( UCBF_BM_DMA | UCBF_DMAMODE );
     npUCB->DMAType    = 0;
     npUCB->CurDMAMode = 0;
   }
}

/*-------------------------------*/
/*                               */
/* GetDeviceULTRAMode()          */
/*                               */
/* For ATA or ATAPI devices      */
/*                               */
/*-------------------------------*/
VOID GetDeviceULTRAMode( NPUCB npUCB, NPIDENTIFYDATA npID )
{
   USHORT  TmpUDMA;

   /*****************************************/
   /* Find highest supported ULTRA DMA mode */
   /*****************************************/          

   if( npID->UltraDMAModes & ULTRADMAMODE_5)            /* Mode 5 */  
   {
      npUCB->UltraDMAMode = ULTRADMAMODE_5;
   }
   else if( npID->UltraDMAModes & ULTRADMAMODE_4)       /* Mode 4 */
   {
      npUCB->UltraDMAMode = ULTRADMAMODE_4;
   }
   else if( npID->UltraDMAModes & ULTRADMAMODE_3)       /* Mode 3 */
   {
      npUCB->UltraDMAMode = ULTRADMAMODE_3;
   }
   else if( npID->UltraDMAModes & ULTRADMAMODE_2)       /* Mode 2 */
   {
      npUCB->UltraDMAMode = ULTRADMAMODE_2;
   }
   else if( npID->UltraDMAModes & ULTRADMAMODE_1)       /* Mode 1 */
   {
      npUCB->UltraDMAMode = ULTRADMAMODE_1;
   }
   else if( npID->UltraDMAModes & ULTRADMAMODE_0)       /* Mode 0 */
   {
      npUCB->UltraDMAMode = ULTRADMAMODE_0;
   }
   else {
      npUCB->UltraDMAMode = 0;                    /* No Ultra DMA Modes */
   }                                                   

   if (MaxUDMA)                                    
   {
      switch (MaxUDMA)
      {
      case 1: TmpUDMA = ULTRADMAMODE_1;
         break;
      case 2: TmpUDMA = ULTRADMAMODE_2;
         break;
      case 3: TmpUDMA = ULTRADMAMODE_3;
         break;
      case 4: TmpUDMA = ULTRADMAMODE_4;
         break;
      case 5: TmpUDMA = ULTRADMAMODE_5;
         break;
      default: break;
      }

      if (npUCB->UltraDMAMode > TmpUDMA)
      {
         npUCB->UltraDMAMode = TmpUDMA;
      }                                           
   }

   /***********************************************************/
   /* npUCB->UltraDMAMode will contain highest Ultra DMA Mode */
   /***********************************************************/
}

/*-------------------------------*/
/*                               */
/* GetDeviceDMAMode()            */
/*                               */
/* For ATA or ATAPI devices      */
/*                               */
/*-------------------------------*/
VOID GetDeviceDMAMode( NPUCB npUCB, NPIDENTIFYDATA npID, NPATBL npAT)
{
   USHORT dmaMWMode;

   npUCB->DMAMWordFlags = npID->DMAMWordFlags;

   /************************************************/
   /* Find highest MW DMA mode unit can operate in */
   /************************************************/

   dmaMWMode = (npID->DMAMWordFlags & 0x00FF) >> 1;

   for( npUCB->CurDMAMode=-1; dmaMWMode; dmaMWMode >>= 1, ++npUCB->CurDMAMode )
     ;


   if(npUCB->CurDMAMode == -1)                /* reset DMA mode if invalid */
   {
     npUCB->Flags &= ~UCBF_DMAMODE;
   } else {
     ++npUCB->CurDMAMode;
   }

   if ( (npUCB->CurDMAMode == 1) &&
        ((npAT->SysDMAType & SDMA_MASK) == SDMA_TYPE_F) )
   {
     npUCB->DMAType = 0x003C;     /* Type F DMA, 16 bit I/O Count by Bytes */
   }
   if ( (npUCB->CurDMAMode == 0) &&
        ((npAT->SysDMAType & SDMA_MASK) == SDMA_TYPE_B) )
   {
     npUCB->DMAType = 0x002C;     /* Type B DMA, 16 bit I/O Count by Bytes */
   }
}

/*-------------------------------*/
/*                               */
/* GetDevicePIOMode()            */
/*                               */
/* For ATA or ATAPI devices      */
/*                               */
/*-------------------------------*/
VOID GetDevicePIOMode( NPUCB npUCB, NPIDENTIFYDATA npID )
{
   USHORT advPIOMode;

   // PIO mode is only in the lower 2 bits, so ignore higher bits.  /*@V185215*/
   advPIOMode = npID->AdvancedPIOModes & 3;                         /*@V185215*/

   npUCB->AdvancedPIOModes = advPIOMode;                       /* save value */

   /*************************************************/
   /* Find highest PIO mode the unit can operate in */
   /*************************************************/

   for( npUCB->CurPIOMode=2; advPIOMode; advPIOMode >>= 1, ++npUCB->CurPIOMode )
     ;
}

/*-----------------------------------*/
/* IdentifyDevice()                  */
/*                                   */
/* For ATA or ATAPI devices          */
/*                                   */
/* returns:                          */
/*         errorcode for ATA device  */
/*         1         for ATAPI       */
/*         0         for no error    */
/*-----------------------------------*/
USHORT IdentifyDevice( NPATBL npAT, USHORT UnitId, NPIDENTIFYDATA npID,
                                                           USHORT ATAPIDevice )
{
   NPACB                 npACB;
   NPUCB                 npUCB;
   IORB_ADAPTER_PASSTHRU TI;
   PassThruATA           icp;

   npACB =   npAT->npACB;
   npUCB = &npACB->UnitCB[UnitId];

   setmem( (PBYTE) &TI,  0, sizeof(TI)  );
   setmem( (PBYTE) &icp, 0, sizeof(icp) );

   icp.TaskFileIn.Command    = FX_IDENTIFY;          /* Default ATA Identify */
   if( ATAPIDevice ) {                               /*       ATAPI Identify */
      icp.TaskFileIn.Command = FX_ATAPI_IDENTIFY;
   }

   icp.RegisterTransferMap = ( PTA_RTMWR_COMMAND |
                               PTA_RTMRD_ERROR   |
                               PTA_RTMRD_STATUS   );

   if ( DevHelp_VirtToPhys( (PVOID)  npID,
                            (PULONG) &ScratchSGList.ppXferBuf ) )   /*@V108555*/
   {
     _asm { int 3 }
   }

   ScratchSGList.XferBufLen = 512;

   /*************************************************/
   /* Clear any pending requests created from the   */
   /* DoIdentify attempted in DoATAPIPresenseCheck. */
   /*************************************************/

   npUCB->ReqFlags = 0;

   if( !ATAPIDevice )
   {
      npUCB->UnitId = UnitId;        /* Assign UnitID *//* Found in DoIdentify */
   }

   TI.iorbh.Length          = sizeof(IORB_ADAPTER_PASSTHRU);
   TI.iorbh.UnitHandle      = (USHORT) npUCB;
   TI.iorbh.CommandCode     = IOCC_ADAPTER_PASSTHRU;
   TI.iorbh.CommandModifier = IOCM_EXECUTE_ATA;
   TI.iorbh.RequestControl  = IORB_ASYNC_POST | IORB_DISABLE_RETRY;
   TI.iorbh.NotifyAddress   = NotifyIORBDone;
   TI.cSGList               = 1;
   TI.pSGList               = &ScratchSGList;                       /*@V108555*/

   TI.ControllerCmdLen      = sizeof(icp);
   TI.pControllerCmd        = (PBYTE) &icp;
   TI.Flags                 = PT_DIRECTION_IN;

   ADDEntryPoint( (PIORB) &TI );

   DISABLE
   while( !(TI.iorbh.Status & IORB_DONE) )
   {
     DevHelp_ProcBlock( (ULONG)(PIORB) &TI, -1, WAIT_IS_NOT_INTERRUPTABLE );
     DISABLE
   }
   ENABLE

   if( TI.iorbh.Status & IORB_ERROR )              /* ERROR */
   {
      if( ATAPIDevice ) {
         return( 1 );                              /* ATAPI */
      }else {
         return( TI.iorbh.ErrorCode );             /* ATA Device */ /*@V151345*/
      }
   }

   return( 0 );                                    /* SUCCESS */   /*AAAAAAAA*/
}                                                                  /*@V179942*/

/*-----------------------------------*/                            
/*                                   */
/* GetUltraDMAMode()                 */
/*                                   */
/*-----------------------------------*/
USHORT GetUltraDMAMode( USHORT CurDMAMode )
{
   USHORT UltraDMAMode = 0;
   USHORT j;                                                /* 543210xx */
   CurDMAMode >>= 2;                                        /* Shift it back */

   for( j=0; j <= MAXULTRADMAMODE; j++)                     
   {
      if( CurDMAMode == 1 )
      {
         UltraDMAMode = j;
         break;
      }
      CurDMAMode >>= 1;
   }

   return( UltraDMAMode );
}

/*---------------------------------------------------------------*/
/*  ChkIfDPT_Present()                                           */
/*                                                               */
/*  This routine checks to see if the DPT controller is present  */
/*  and sets all the adapter table flags.                        */
/*---------------------------------------------------------------*/ 
VOID ChkIfDPT_present()
{
   USHORT i;
   NPATBL npAT = AdapterTable;

   if( DPT_Present() )
   {
      for( i=0; i < MAX_ADAPTERS; i++, npAT++ )
      {
         npAT->Flags |= ATBF_IRQCLEAR;
      }
   }
}

/*---------------------------------------------------------------*/
/*  ChkAdapters4Units()                                          */
/*                                                               */
/*  This routine checks the adapters that have been found and    */
/*  determines what devices are attached.                        */
/*---------------------------------------------------------------*/ 
VOID CkAdapters4Units( USHORT DriveId )
{
  UCHAR   i,j;
  NPATBL  npAT = AdapterTable;
  NPACB   npACB;
  ULONG   TimeOut;

  for( i=0; i < MAX_ADAPTERS; i++, npAT++ )
  {
    if ( !(npAT->Flags & ATBF_DISABLED) )
    {
      if ( !ConfigureController( npAT ) )
      {
        for( j = 0; j < MAX_UNITS; j++ )
        {
          npAT->Unit[j].DriveId = DriveId;

          if( !ConfigureATAUnit( npAT, j ) &&                       /*@V108783*/
              !(npAT->Unit[j].Flags & UTBF_ATAPIDEVICE) )           /*@V192176*/
          {                                                         /*@V179486*/
             /*-----------------------------------------------*/
             /* Increment the BIOS DriveID only if an HDD was */    /*@V179486*/
             /* found, CD-ROMs don't count!                   */    /*@V179486*/
             /*-----------------------------------------------*/
             DriveId++;                                             /*@V179486*/
          }                                                         /*@V179486*/
          else if( !(npAT->Unit[j].Flags & UTBF_ATAPIDEVICE) )      // 206371
          {                                                         // 206371
            // Only done if we still don't know if this unit is     // 206371
            // ATAPI or not.  If already identified as ATAPI skip.  // 206371
            // DriveID has no use in case of a non-existent drive   /*@V179486*/
            // or a CD-ROM drive.                                   /*@V179486*/
            npAT->Unit[j].DriveId = 0;                              /*@V179486*/
            if ( DoATAPIPresenseCheck( npAT, j ) )
            {
              if( !j && !(npAT->Unit[1].Flags & UTBF_ATAPIDEVICE) )   //207688
              /*----------------------------------------------*/
              /* No Master Unit was found, see if there is a  */
              /* slave ATAPI unit.                            */
              /*----------------------------------------------*/
              {
                j++;
                npAT->npACB->UnitCB[0].Flags &= ~UCBF_IDENTIFYFAIL;

                /*-----------------------------------------*/
                /* If no master unit, no diag info will    */
                /* be available to a reset.                */
                /*-----------------------------------------*/
                npAT->Flags                  |= ATBF_DISABLERESET;
                npAT->npACB->Flags           |= ACBF_DISABLERESET;
                npAT->npACB->UnitCB[0].Flags |= UCBF_DISABLERESET;  /*@V185215*/
                npAT->npACB->UnitCB[1].Flags |= UCBF_DISABLERESET;  /*@V185215*/

                ATAPISlaveChk = 1;                                  /*@V109483*/

                if( !DoATAPIPresenseCheck( npAT, j ) )
                {
                   LoopConfigureATAPI( npAT, j, 0 );                /*@217469*/

                   // Have found a slave device with no master.  To keep
                   // the Unit and UnitCB structures in sync with nUnits
                   // must count the master unit but mark it as not present.

                   NoMasterStatusCountUnit( npAT );                 /*@217469*/
                }
                ATAPISlaveChk = 0;                                  /*@V109483*/
              } else if( !j )                                  // Start: 207688
              {
                 // There is no master device, but we previously detected
                 // and counted a slave ATAPI device, so now must count the
                 // master and mark it as not present.

                 NoMasterStatusCountUnit( npAT );                 /*@217469*/

                 // This unit will be configured next time through
                 // the for loop, just below at: "Configure it now."
              }                                                   // End: 207668
            } else {                                               /* [002.2] */

               LoopConfigureATAPI( npAT, j, 0 );                  /*@217469*/
            }
          } else {                                              // Start: 207688
             // Unit was previously detected to be an ATAPI device
             // but has not been configured yet.  Configure it now.

             LoopConfigureATAPI( npAT, j, 1 );                      /*@217469*/
          }                                                     // End: 207688
        }

        
        
        for( j = 0; j < MAX_UNITS; j++ )                            
        {                                                           
           if( npAT->Unit[j].Flags & UTBF_FORCE &&                  
               npAT->Unit[j].Status == UTS_NOT_PRESENT )            
           {                                                        
              CountTheUnit( npAT );
           }                                                        
        }                                                           

        npACB = npAT->npACB;

        for (j=0; j < npACB->cUnits; j++)
        {
          npACB->DelayedRetryInterval = DELAYED_RETRY_INTERVAL;
          npACB->IRQTimeOut           = IRQ_TIMEOUT_INTERVAL;

          if ( (TimeOut=npAT->Unit[j].TimeOut) < MIN_USER_TIMEOUT )
          {
            TimeOut = DEFAULT_USER_TIMEOUT;
          }
          npACB->TimeOut = 1000L * TimeOut;
        }

        CheckACBViable( npAT );                                      /*@V90963*/
      }
    } else {
      npAT->Status = ATS_SKIPPED;
    }
  }
}

/*---------------------------------------------------------------*/
/*  FinalReadVerify()                                            */
/*                                                               */
/*  This routine does a final read verify to verify that the     */
/*  devices are there.                                           */
/*---------------------------------------------------------------*/ 
VOID FinalReadVerify( VOID )
{
   USHORT i,j,k,l;
   NPACB  npACB;

   InitIOComplete = 1;

   for( i=0; i < cAdapters; i++ )
   {
     npACB = ACBPtrs[i].npACB;

     for( j=0; j < npACB->cUnits; j++ )
     {
       if( !(npACB->UnitCB[j].Flags & UCBF_NODASDSUPPORT) &&        /*@V108783*/
           !(npACB->UnitCB[j].Flags & UCBF_NOTPRESENT) )            /*@V149971*/
       {                                                            /*@V151345*/
         if( npACB->UnitCB[j].Flags & UCBF_ATAPIDEVICE )            /*@V87325*/
         {
           /*------------------------------------------------------*/
           /* Do the ATAPI Reset only when the ATAPI device is on  */
           /* the Slave and there is no DASD device on the Master. */
           /*------------------------------------------------------*/
           if ( (j == 1) && (npACB->UnitCB[0].Flags & UCBF_NODASDSUPPORT) )
           {
             SelectUnit( npACB, j );                                /*@V152648*/

             ATAPIReset( npACB );

             /*--------------------------------------------------------*/
             /* ATAPI Units can take several ms to show the signature. */                                                     /*@V152648*/
             /*--------------------------------------------------------*/
             for( k = 0; k < MAX_ATAPI_RECOVERY_TRYS; k++ )         /*@V152648*/
             {                                                      /*@V152648*/
               for( l = 0; l < ATAPI_RECOVERY; l++ )                /*@V152648*/
               {                                                    /*@V152648*/
                 IODelay();                                         /*@V152648*/
               }                                                    /*@V152648*/
               /*-----------------------------------------------*/
               /* Check that the drive is ready and not busy or */
               /* else is showing its signature.  In either of  */   /*@V152648*/
               /* these states the CD-ROM drive is reset.       */   /*@V152648*/
               /*-----------------------------------------------*/
               if( !( CheckReady( npACB ) && (npACB->TimerFlags & ACBT_BUSY)))/*@V152648*/
               {                                                    /*@V152648*/
                 break;                                             /*@V152648*/
               }                                                    /*@V152648*/
               if( !CheckForATAPISignature( &AdapterTable[i], j ) ) /*@V152648*/
               {                                                    /*@V152648*/
                 break;                                             /*@V152648*/
               }                                                    /*@V152648*/
             }                                                      /*@V152648*/
           }
         } else {                                                   /*@V152648*/

           ReadDrive( npACB, j, 0, 1, NULL );                       /*@V108555*/
         }
       }
     }
   }
}

/*---------------------------------------------------------------*/
/*  LoopConfigureAtapi()                                         */
/*                                                               */
/*  This routine will loop to configure an ATAPI device.         */
/*  It will also check if the CkForce flag is passed in.         */
/*---------------------------------------------------------------*/ 
VOID LoopConfigureATAPI( NPATBL npAT, UCHAR j, UCHAR CkForce )
{
   USHORT loopCnt;

   for( loopCnt=0; loopCnt < MAX_ATAPI_CONFIGURE_TRYS; loopCnt++ )
   {
      if( !ConfigureATAPIDevice( npAT, j ) )
      {
         if( CkForce )
         {
            if( npAT->Unit[j].Flags & UTBF_FORCE )
            {                                                         
               CountTheUnit( npAT );     // Found a forced ATAPI unit, count it.
            }                                                         
         }
         break;
      }
   }
}

/*---------------------------------------------------------------*/
/*  CountTheUnit()                                               */
/*                                                               */
/*  This routine increments the cUnits in the npACB, npAT and    */
/*  cUnits itself.                                               */
/*---------------------------------------------------------------*/ 
VOID CountTheUnit( NPATBL npAT )
{
   npAT->npACB->cUnits++;
          npAT->cUnits++;
                cUnits++;
}

/*---------------------------------------------------------------*/
/*  NoMasterStatusCountUnit()                                    */
/*                                                               */
/*  This routine set the master status as UTS_NO_MASTER and      */
/*  counts the slave unit by calling CountTheUnit().             */
/*---------------------------------------------------------------*/ 
VOID NoMasterStatusCountUnit( NPATBL npAT )
{
   npAT->Unit[0].Status          = UTS_NO_MASTER;
   npAT->npACB->UnitCB[0].Flags |= UCBF_NODASDSUPPORT;

   CountTheUnit( npAT );
}

/*---------------------------------------------------------------*/
/*  NativePCIIDE()                                               */
/*                                                               */
/*  This routine determines whether the PCI Chip is operating in */
/*  LEGACY or PCI NATIVE mode based upon the baseport address.   */
/*---------------------------------------------------------------*/ 
BOOL NativePCIIDE( NPATBL npAT )
{
   if( (npAT->BasePort == FX_PRIMARY) || (npAT->BasePort == FX_SECONDARY) )
   {
      return( LEGACY );
   }
   return( NATIVE );
}

