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

/**************************************************************************
 *
 * SOURCE FILE NAME = DMBPB.C
 *
 * DESCRIPTIVE NAME = OS2DASD.DMD - OS/2 DASD Device Manager
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Partition/BPB Management Routines
 *
 *
 *
*/
#include "dmh.h"

/*--------------------------------------------------------------------------
;
;** Process_Partition - Process the partition table of the fixed disk
;
;   Process_Partition processes the partition table obtained from the
;   fixed disk and determines where the DOS boot sector is found on the
;   disk.
;
;   USHORT Process_Partition (NPVOLCB pVolCB, PULONG VolBootRBA,
;                                             PULONG NumSectors)
;
;   ENTRY:    pVolCB           - input pointer to VolCB
;             VolBootRBA       - returned RBA of Volume Boot Sector
;             NumSectors       - returned number of sectors in partition
;
;   RETURN:   USHORT           - Result Code (NO_ERROR if valid partition)
;
;   EFFECTS:
;
;   NOTES:    Global variable ScratchBuffer contains boot sector
;             on input.
;
;----------------------------------------------------------------------------*/

USHORT Process_Partition (pVolCB, VolBootRBA, NumSectors)

NPVOLCB pVolCB;
PULONG  VolBootRBA;
PULONG  NumSectors;
{
   BOOL   found;
   USHORT i;
   MBR    *pMBR = (MBR *) ScratchBuffer;
   ULONG  temp;
   fBigFat = 0;

   pVolCB->Flags &= ~vf_NoDOSPartition;         /* Partition ok so far */

   if (pMBR->Signature != 0xAA55)               /* Check for signature word */
      pVolCB->Flags |= vf_NoDOSPartition;       /* Partition invalid */
   else
   {
      found = FALSE;
      for (i = 0; i < 4 && found == FALSE ; i++)
      {
         found = TRUE;
         switch (pMBR->PartitionTable[i].SysIndicator)
         {
            case PARTITION_16M:         /* Partition up to 16M */
                   break;
            case PARTITION_16Mto32M:    /* Partition > 16M and <= 32 M */
                   break;
            case PARTITION_32M:         /* Partition > 32M  */
                   break;
            case PARTITION_FAT16X:      //d_267583
                   break;
            case PARTITION_IFS:         /* IFS Partition */
                   break;
            case PARTITION_FTACTIVE:    /* Active Fault Tolerant partition */
                   pVolCB->Flags |= vf_FTPartition;
                   break;
            case PARTITION_FTINACTIVE:  /* Inactive Fault Tolerant partition */
                   pVolCB->Flags |= vf_FTPartition;
                   break;
            default:
               found = FALSE;
         }
      }

      /* If invalid partition type or valid found and < 32K in size */
      /* then indicate not a valid partition.                       */

      i--;
      if (!found || pMBR->PartitionTable[i].NumSectors < 64)
         pVolCB->Flags |= vf_NoDOSPartition;    /* Partition invalid */
      else
      {
         if ((DDFlags & DDF_INIT_TIME) &&                            /*@V64818*/
                                 (pVolCB->Flags & vf_FTPartition))   /*@V64818*/
            NumFTPartitions ++;

         pVolCB->PartitionType = pMBR->PartitionTable[i].SysIndicator;

         /* Make sure end of partition within 4G sectors of start of disk */
         if (f_add32(pMBR->PartitionTable[i].RelativeSectors,
             pMBR->PartitionTable[i].NumSectors) == 0)
                 fBigFat |= vf_TooBig;

         pVolCB->MediaBPB.HiddenSectors=pMBR->PartitionTable[i].RelativeSectors;

         if (pMBR->PartitionTable[i].NumSectors <= (ULONG) 0xffff)
            pVolCB->MediaBPB.TotalSectors=(USHORT)pMBR->PartitionTable[i].NumSectors;
         else
         {
            pVolCB->MediaBPB.TotalSectors = 0;
            pVolCB->MediaBPB.BigTotalSectors=pMBR->PartitionTable[i].NumSectors;
         }

         /* Return RBA of Volume Boot Sector and NumSectors in Partition */

         *VolBootRBA = pVolCB->MediaBPB.HiddenSectors;

         *NumSectors = pMBR->PartitionTable[i].NumSectors;
      }
   }
   if (pVolCB->Flags & vf_NoDOSPartition)
      return(ERROR);
   else
      return(NO_ERROR);
}


/*--------------------------------------------------------------------------
;                                                                    @V187707
;** Process_FloppyAsPartitioned - Check for and process floppy formatted media
;
;   Process_FloppyAsPartitioned updates the given VolCB to make floppy
;   formatted media appear as a fixed disk.  It performs the same processing
;   as ProcessPartition(), except for floppy formatted media.
;
;   USHORT Process_FloppyAsPartitioned (NPVOLCB pVolCB, PULONG VolBootRBA,
;                                                       PULONG NumSectors)
;
;   ENTRY:    pVolCB           - input pointer to VolCB
;             VolBootRBA       - returned RBA of Volume Boot Sector
;             NumSectors       - returned number of sectors in partition
;
;   ASSUMPTIONS on ENTRY:
;   - ScratchBuffer contains the DOS Boot Record.
;   - The DOS Boot Record has already been validated by calling Is_BPB_Boot()
;
;   RETURN:   USHORT           - Result Code (NO_ERROR if valid partition)
;
;   EFFECTS:
;
;   NOTES:    Global variable ScratchBuffer contains media's first sector
;             on input.
;
;----------------------------------------------------------------------------*/

USHORT Process_FloppyAsPartitioned
             (NPVOLCB pVolCB, PULONG VolBootRBA, PULONG NumSectors)  /*@V187707*/

{
   PDOSBOOTREC pBootRec = (PDOSBOOTREC) ScratchBuffer;

   pVolCB->PartitionType = PARTITION_IFS;
   pVolCB->MediaBPB.HiddenSectors = 0;
   pVolCB->MediaBPB.TotalSectors = pBootRec->bpb.TotalSectors;
   pVolCB->MediaBPB.BigTotalSectors = pBootRec->bpb.BigTotalSectors;
   *VolBootRBA = 0;
   *NumSectors = pVolCB->MediaBPB.TotalSectors ? pVolCB->MediaBPB.TotalSectors
                                               : pVolCB->MediaBPB.BigTotalSectors;
   pVolCB->Flags &= ~vf_NoDOSPartition;

   return NO_ERROR;
}



/*--------------------------------------------------------------------------
;
;** Process_Boot - Process the boot sector of the fixed disk
;
;   Process_Boot examines the boot sector read off the fixed disk
;   and builds a BPB for it in the BDS for the drive. If the boot
;   sector is not valid, it assumes a default BPB from a table.
;   If this is a > 32M partition and the boot sector does not have
;   a valid BPB, 'C' is returned. The caller should then set up a
;   "minimum" BPB and set the fTooBig bit.
;
;   USHORT Process_Boot (NPVOLCB pVolCB, ULONG SectorsInPartition)
;
;   ENTRY:    pVolCB             - input pointer to VolCB
;             SectorsInPartition - Number of sectors in partition
;
;   RETURN:   USHORT           - Result Code (NO_ERROR if valid partition)
;
;   EFFECTS:
;
;   NOTES:    Global variable ScratchBuffer contains boot sector
;             on input.
;
;----------------------------------------------------------------------------*/

USHORT Process_Boot(pVolCB, SectorsInPartition)

NPVOLCB  pVolCB;
ULONG    SectorsInPartition;

{
   USHORT rc, i;
   ULONG  TotalSectors, temp;
   USHORT Unknown = YES;
   PDOSBOOTREC pBootRec = (PDOSBOOTREC) ScratchBuffer;

   /*--------------------------------------------------------*/
   /* Check for a valid boot sector and use the BPB in it to */
   /* build the MediaBPB in the VolCB.  It is assumed that   */
   /* ONLY SectorsPerCluster, NumFatSectors, MaxDirEntries   */
   /* and MediaType need to be set.                          */
   /*--------------------------------------------------------*/

   if (Is_BPB_Boot(pVolCB,pBootRec) == NO_ERROR)                     /*@V64818*/
   {
      pVolCB->MediaBPB.MediaType = pBootRec->bpb.MediaType;
      if (pBootRec->bpb.TotalSectors != 0)
          TotalSectors = pBootRec->bpb.TotalSectors;
      else
          TotalSectors = pBootRec->bpb.BigTotalSectors;

      /* Make sure there are enough sectors for the boot sector, */
      /* plus the FAT sectors plus the directory sectors.        */

      if (TotalSectors > (1 + (pBootRec->bpb.NumFATSectors * 2) +
                         (pBootRec->bpb.MaxDirEntries / 16)))
      {
        pVolCB->MediaBPB.NumFATSectors = pBootRec->bpb.NumFATSectors;
        pVolCB->MediaBPB.MaxDirEntries = pBootRec->bpb.MaxDirEntries;
        pVolCB->MediaBPB.SectorsPerCluster = pBootRec->bpb.SectorsPerCluster;

        /* Calculate sectors left for data sectors */

        TotalSectors = TotalSectors - (1 + (pBootRec->bpb.NumFATSectors * 2) +
                                      (pBootRec->bpb.MaxDirEntries / 16));

        if ( (pVolCB->PartitionType != PARTITION_IFS) &&             /*@V64818*/
             !(pVolCB->Flags & vf_FTPartition)        &&             /*@V64818*/
             (pVolCB->MediaBPB.SectorsPerCluster)     &&             /*@V64818*/
             (TotalSectors / pVolCB->MediaBPB.SectorsPerCluster) > 4096-10 )
           fBigFat |= vf_Big;           /* Set FBIG if 16 bit FAT */

        Unknown = NO;
      }
   }

   if (Unknown == YES)
   {
      /* If IFS, zero out FAT related fields */

      if (pVolCB->PartitionType == PARTITION_IFS)
      {
         pVolCB->MediaBPB.SectorsPerCluster = 0;
         pVolCB->MediaBPB.ReservedSectors = 0;
         pVolCB->MediaBPB.NumFATs = 0;
         pVolCB->MediaBPB.MaxDirEntries = 512;
         if (pVolCB->MediaBPB.TotalSectors != 0)
            pVolCB->MediaBPB.BigTotalSectors = pVolCB->MediaBPB.TotalSectors;
         pVolCB->MediaBPB.TotalSectors = 0;
         pVolCB->MediaBPB.MediaType = MEDIA_FIXED_DISK;              /*@V64818*/
         pVolCB->MediaBPB.NumFATSectors = 0;
      }
      else
      {

         /* Find appropriate DiskTable entry based on SectorsInPartition */

         for (i = 0; i < DISKTABLECOUNT; i++)
           if (SectorsInPartition <= DiskTable[i].NumSectors)
              break;

         fBigFat = DiskTable[i].Flags;
         pVolCB->MediaBPB.MaxDirEntries = DiskTable[i].MaxDirEntries;
         pVolCB->MediaBPB.SectorsPerCluster= DiskTable[i].SectorsPerCluster;
         pVolCB->MediaBPB.MediaType = MEDIA_FIXED_DISK;

         /* Calculate number of FAT table sectors */

         if (fBigFat & vf_Big)
         {
            temp = (pVolCB->MediaBPB.SectorsPerCluster * 256) + 2;
            pVolCB->MediaBPB.NumFATSectors = (SectorsInPartition -
               ((pVolCB->MediaBPB.MaxDirEntries / 16) + 1) + /* Dir + Reserved*/
               temp - 1 +
               (pVolCB->MediaBPB.SectorsPerCluster * 2)) / temp;
         }
         else
         {
            TotalSectors = SectorsInPartition +
                           pVolCB->MediaBPB.SectorsPerCluster - 1;

            TotalSectors >>= DiskTable[i].Log2SectorsPerCluster;

            TotalSectors = ((TotalSectors + 1) & (0xFFFFFFFE)) + 2;

            temp = TotalSectors;

            TotalSectors >>= 1;

            pVolCB->MediaBPB.NumFATSectors = (TotalSectors + temp + 511) / 512;
         }
      }
   }

   pVolCB->Flags |= vf_BigFat;

   pVolCB->RecBPB = pVolCB->MediaBPB;   /* Copy media BPB to recommended BPB */
}


/*--------------------------------------------------------------------------
;
;** BPBFromBoot - Get BPB from the boot sector passed in
;
;   BPBFromBoot builds a BPB for the disk/media type from the boot
;   sector passed to it.
;
;   USHORT BPBFromBoot (NPVOLCB pVolCB, PDOSBOOTREC pBootSector)
;
;   ENTRY:    pVolCB           - VolCB for the drive
;             pBootSector      - DOS Boot Sector
;
;   RETURN:   USHORT           - Result Code (NO_ERROR if valid boot sector)
;
;   EFFECTS:
;
;   NOTES:  This code assumes that the media you are attempting to
;           build on is
;               a)  a DOS disk
;               b)  if it is a >2.x disk, the boot sector
;                   lies at sector 1 on track 0 (head 0).  The first
;                   3 bytes are a JMP, the next 8 bytes are a media
;                   ID ASCII string, and the 11 bytes following that
;                   are the BPB for that disk.
;               c)  if the above conditions (3 byte jump, 8 ascii ID
;                   string) are not met, then we assume the media is
;                   a DOS 1.x disk.  On a 1.x disk sector 2 on
;                   track 0 (head 0) contains the first FAT sector.
;                   The first byte of the first FAT sector contains
;                   the "FAT ID byte" which is the media ID byte for
;                   this disk.
;
;----------------------------------------------------------------------------*/
USHORT FAR f_BPBFromBoot (pVolCB, pBootSector)

NPVOLCB     pVolCB;
PDOSBOOTREC pBootSector;
{
   return(BPBFromBoot (pVolCB, pBootSector));
}

USHORT BPBFromBoot (pVolCB, pBootSector)

NPVOLCB pVolCB;
PDOSBOOTREC pBootSector;
{
   USHORT rc = NO_ERROR;

   if (!(pVolCB->Flags & vf_ReturnFakeBPB))    /* Do nothing if this is set */
   {
      if ( (rc = Is_BPB_Boot(pVolCB,pBootSector)) == NO_ERROR)       /*@V64818*/
      {
         BootBPB_To_MediaBPB (pVolCB, pBootSector);

         /*------------------------------------------------------------------
         ; In pre-DOS 3.20 versions of Format, there was a     that caused
         ; the sectors per cluster field in the BPB in the boot sector to
         ; be set to 2 even when the medium was single-sided. We "fix" this
         ; by setting the field to 1 on the diskettes that may have been
         ; affected. This will ensure that whatever has been recorded on
         ; those media will remain intact.  Also, we fix the     in the
         ; EZ-FORMAT utility which incorrectly set the hidden sectors field
         ; to 1. We'll reset it back to 0 so those diskettes can be read.
         ------------------------------------------------------------------*/

         if (pVolCB->pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE)
         {

           if ( ((pVolCB->MediaBPB.MediaType == MEDIA_160KB) ||
                 (pVolCB->MediaBPB.MediaType == MEDIA_180KB)) &&
                 (GetBootVersion(pBootSector) < 32) )

                pVolCB->MediaBPB.SectorsPerCluster = 1;


           if ( (pVolCB->MediaBPB.HiddenSectors != 0) &&
                ( *((PBYTE)pBootSector + 0xA1) == 'F') &&
                ( *((PBYTE)pBootSector + 0xA2) == 'a') &&
                ( *((PBYTE)pBootSector + 0xA3) == 'l') &&
                ( *((PBYTE)pBootSector + 0xA4) == 'k') )

                pVolCB->MediaBPB.HiddenSectors = 0;
         }
      }
   }

   return(rc);
}

/*--------------------------------------------------------------------------
;
;** BPBFromScratch - Build a BPB for the disk
;
;   BPBFromScratch builds a BPB for the drive where the boot sector
;   contains an invalid BPB in it.
;
;   For fixed disks, the partition table is read and from it the
;   location of the boot sector is obtained. The boot sector is then
;   read and the BPB built from there. An error is returned if the
;   partition table is invalid or is too small (< 32K bytes).
;
;   USHORT BPBFromScratch (NPVOLCB pVolCB, PRP pRP)
;
;   ENTRY:    pVolCB           - VolCB for the drive
;             pRP              - Request Packet
;
;   RETURN:   USHORT           - Packet Status
;
;   EFFECTS:
;
;----------------------------------------------------------------------------*/
USHORT FAR f_BPBFromScratch (pVolCB)

NPVOLCB  pVolCB;

{
   return(BPBFromScratch(pVolCB));
}


USHORT BPBFromScratch (pVolCB)

NPVOLCB  pVolCB;

{
   UCHAR   MediaType;
   USHORT  rc;
   ULONG   VolBootRBA, NumSectors;

   /* Wait for the ScratchBuffer to be free before doing a read */

   f_SWait (&ScratchBufSem);

   if (pVolCB->pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE)      /* If floppy drive */
   {
      /* Read in the first FAT sector */

      if ((rc = ReadSecInScratch_RBA (pVolCB, 1L, 0)) == NO_ERROR)
      {
         MediaType = ScratchBuffer[0];
         if (pVolCB->MediaBPB.MediaType != MediaType)
         {
            switch(MediaType)
            {
               case MEDIA_144MB:                         /* 1.44MB & 2.88MB */
                     if (pVolCB->RecBPB.SectorsPerTrack == 18)
                        pVolCB->MediaBPB = BPB_144MB;    /* 1.44 MB */
                     else
                        pVolCB->MediaBPB = BPB_288MB;    /* 2.88 MB */
                     break;

               case MEDIA_12MB:                          /* 1.2MB & 720 KB */
                     if (pVolCB->RecBPB.SectorsPerTrack == 15)
                        pVolCB->MediaBPB = BPB_12MB;     /* 1.2 MB */
                     else
                        pVolCB->MediaBPB = BPB_720KB;    /* 720 KB */
                     break;

               case MEDIA_125MB:                                                
                        pVolCB->MediaBPB = BPB_125MB;                           
                        break;                                                  
                                                                                
               case MEDIA_360KB:
                        pVolCB->MediaBPB = BPB_360KB;
                        break;

               case MEDIA_320KB:
                        pVolCB->MediaBPB = BPB_320KB;
                        break;

               case MEDIA_180KB:
                        pVolCB->MediaBPB = BPB_180KB;
                        break;


               default:
                        rc = STDON + STERR + ERROR_I24_NOT_DOS_DISK;
            }
         }
      }
   }
   else  /* Fixed disk */
   {
      /* Read RBA 0 - Master Boot Record  */

      if ((rc = ReadSecInScratch_RBA (pVolCB, 0, 1)) == NO_ERROR)
      {
         if ((rc = Process_Partition (pVolCB, &VolBootRBA, &NumSectors))
                                                            == NO_ERROR)
         {
            if ((rc = ReadSecInScratch_RBA (pVolCB, VolBootRBA, 1))
                                                            == NO_ERROR)
               Process_Boot (pVolCB, NumSectors);
         }
         else
         {
            pVolCB->MediaBPB = BPB_Minimum;      /* Setup minimum BPB */
            pVolCB->RecBPB = pVolCB->MediaBPB;   /* Copy MinBPB to recommended*/
            rc = NO_ERROR;
         }
      }
   }

   f_SSig (&ScratchBufSem);     /* Release scratch buffer */

   return (rc);
}

/*--------------------------------------------------------------------------
;
;**  BootBPB_To_MediaBPB
;
;   Copies the BPB from the passed boot sector to the media BPB in the
;   Volume Control Block. If the boot sector is older than DOS 3.2,
;   the 12 byte extended BPB is not copied because it may contain garbage.
;
;   VOID BootBPB_to_MediaBPB (NPVOLCB pVolCB, PDOSBOOTREC pBootSector
;                              USHORT Type)
;
;   ENTRY:    pVolCB           - input pointer to VolCB
;             pBootSector      - Boot Sector
;             Type             - 0 = disk, 1 = diskette
;
;   RETURN:   VOID
;
;   EFFECTS:
;
;   NOTES:
;
--------------------------------------------------------------------------*/
int validOEM(PUCHAR ptr, int size); // verifies whether OEM string is valid

VOID BootBPB_To_MediaBPB (pVolCB, pBootSector)

NPVOLCB    pVolCB;
PDOSBOOTREC pBootSector;
{
   USHORT  i;
   BOOL    done = FALSE;
   USHORT  version = 0;
   PUCHAR p;

   if(TreatAsFixed && (pVolCB->pUnitCB->Flags & UCF_REMOVABLE_AS_FIXED))
     {
     if(!validOEM((p=pBootSector->Release-3),sizeof(pBootSector->Release)+3))
       {
        p[0]  = 'I';
        p[1]  = 'B';
        p[2]  = 'M';
        p[3]  = ' ';
        p[4]  = '2';
        p[5]  = '0';
        p[6]  = '.';
        p[7]  = '0';
       } /* endif */
     } /* endif */
   version = GetBootVersion(pBootSector);


/* There's a     in DR DOS which incorrectly adds the partition offset */
/* to the hidden sectors field in the BPB.  We recognize this case     */
/* by checking for version 3.3 and subtracting out the partition offset.*/

   if ( (version == 33) &&
        ( !(pVolCB->pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE) ) &&
        (pVolCB->PartitionOffset > 0) &&
        (pBootSector->bpb.HiddenSectors ==
              (pVolCB->MediaBPB.HiddenSectors + pVolCB->PartitionOffset) ) )

           pBootSector->bpb.HiddenSectors = pVolCB->MediaBPB.HiddenSectors;


   /* Boot sector < DOS 4.0 (and known version!) */

   if ((version > 0) && (version < 40))                             /*@V108555*/
      if (version != 33)     //P62137
          pBootSector->bpb.HiddenSectors &= 0xffffff7f;

   /* Copy over BPB */

   pVolCB->MediaBPB = pBootSector->bpb;


   /* If version < DOS 3.3 (and known!) or its a diskette and using */
   /* TotalSectors then zero out the extended portion of the BPB    */

   if ( ((version > 0) && (version < 33)) ||                        /*@V108555*/
      ((pVolCB->pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE) &&
       (pBootSector->bpb.TotalSectors != 0))  )
   {
      pVolCB->MediaBPB.HiddenSectors &= 0x0000FFFF;
      pVolCB->MediaBPB.BigTotalSectors = 0;
      for (i = 0; i < sizeof(pVolCB->MediaBPB.Reserved_1); i++)
         pVolCB->MediaBPB.Reserved_1[i] = 0;
   }
}

/*--------------------------------------------------------------------------
;
;** f_BPBfromGeom - Initialize BPB using Geometry info
;
;   Initialize the BPB for a VolCB from the Geometry info returned by
;   the adapter driver.
;
;   VOID InitBPBfromGeom (NPVOLCB pVolCB, NPBPB pBPB, PGEOMETRY pGeometry)
;
;   ENTRY:    pVolCB           - input pointer to VolCB
;             pBPB             - pointer to BPB to fill in
;             pGeometry        - pointer to Geometry info
;
;   RETURN:   VOID
;
;   EFFECTS:
;
;----------------------------------------------------------------------------*/

/* Moved from DMINIT */                                              /*@V63867*/
                                                                     /*@V63867*/
VOID FAR f_BPBfromGeom (pVolCB, pBPB, pGeometry)                     /*@V63867*/

NPVOLCB   pVolCB;
NPBPB     pBPB;
PGEOMETRY pGeometry;

{
   ULONG  TotalCylinders, TotalSectors, TotalDataSectors, temp;
   ULONG  SectorsPerCyl;                                             /*@V63867*/
   USHORT i;
   NPUNITCB pUnitCB;

   pUnitCB = pVolCB->pUnitCB;
   TotalSectors = pGeometry->TotalSectors;

   /* If removable SCSI device which doesnt return geometry data when */
   /* no media is in the drive, then just put a default size in.      */

   if (TotalSectors == 0)                                            /*@V46569*/
      TotalSectors = 5760;                                           /*@V46569*/

   pUnitCB->LastRBA = TotalSectors;

   /* If the unit is removable and it's not bigger than a 2.88M drive  */
   /* then use one of the canned BPBs we have for the specified drive. */

   if ((pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE) && (TotalSectors <= 5760))
   {
      pVolCB->NumPhysCylinders = pGeometry->TotalCylinders;
      pVolCB->NumLogCylinders  = pGeometry->TotalCylinders;
      pVolCB->BootRecCyl       = 0;                                  /*@V89787*/

      switch (TotalSectors)
      {
          case 720:         /* 5.25 inch - 360 KB Drive */
            *pBPB = BPB_360KB;
            break;

          case 1440:        /* 3.5 inch - 720 KB Drive */
            *pBPB = BPB_720KB;
            break;

          case 2400:        /* 5.25 inch - 1.2M Drive */
            *pBPB = BPB_12MB;
            break;

          case 2880:        /* 3.5 inch - 1.44M Drive */
            *pBPB = BPB_144MB;
            break;

          case 5760:        /* 3.5 inch - 2.88M Drive */
            *pBPB = BPB_288MB;
            break;

          default:
            *pBPB = BPB_144MB;
            break;
      }
   }

   /* If it's a fixed disk, or a removable drive we dont have a canned */
   /* BPB for, then calculate the rest of the BPB.                     */

   else
   {
      /* If the drive doesnt return any Geometry information other *//*@V63867*/
      /* than TotalSectors, then create a virtual geometry for     *//*@V63867*/
      /* the drive, else copy the Geometry data into the BPB.      *//*@V63867*/
                                                                     /*@V63867*/
      if (pGeometry->NumHeads != 0                                   /*@V63867*/
           && pGeometry->BytesPerSector != 0                         /*@V63867*/
               && pGeometry->SectorsPerTrack != 0)                   /*@V63867*/
      {                                                              /*@V63867*/
         pBPB->BytesPerSector  = pGeometry->BytesPerSector;          /*@V63867*/
         pBPB->NumHeads        = pGeometry->NumHeads;                /*@V63867*/
         pBPB->SectorsPerTrack = pGeometry->SectorsPerTrack;         /*@V63867*/
      }                                                              /*@V63867*/
      else                                                           /*@V63867*/
      {                                                              /*@V63867*/
         pBPB->BytesPerSector  = 512;                                /*@V63867*/
         pBPB->NumHeads        = 64;                                 /*@V63867*/
         pBPB->SectorsPerTrack = 32;                                 /*@V63867*/
      }                                                              /*@V63867*/
                                                                     /*@V63867*/
      /* Make TotalSectors consistent with CHS geometry     */       /*@V63867*/
      /*                                                    */       /*@V63867*/
      /* This prevents later problems during FORMAT if the  */       /*@V63867*/
      /* last partial cylinder is accessed.                 */       /*@V63867*/
                                                                     /*@V63867*/
      TotalSectors  = pGeometry->TotalSectors;                       /*@V63867*/
      pVolCB->ActualTotalSectors = TotalSectors;                     /*@V189588*/
                                                                     /*@V63867*/
      SectorsPerCyl = (ULONG) pBPB->SectorsPerTrack *                /*@V63867*/
                      (ULONG) pBPB->NumHeads;                        /*@V63867*/
                                                                     /*@V63867*/
      TotalCylinders = TotalSectors / SectorsPerCyl;                 /*@V63867*/
                                                                     /*@V63867*/
      TotalSectors = TotalCylinders * SectorsPerCyl;                 /*@V63867*/
                                                                     /*@V63867*/
      pVolCB->NumLogCylinders  = TotalCylinders;                     /*@V63867*/
      pVolCB->NumPhysCylinders = TotalCylinders;                     /*@V63867*/
      pVolCB->BootRecCyl       = 0;                                  /*@V89787*/
                                                                     /*@V63867*/
      if (TotalSectors > 0xffff)                                     /*@V63867*/
      {                                                              /*@V63867*/
         pBPB->BigTotalSectors = TotalSectors;                       /*@V63867*/
         pBPB->TotalSectors = 0;                                     /*@V63867*/
      }                                                              /*@V63867*/
      else                                                           /*@V63867*/
      {                                                              /*@V63867*/
         pBPB->BigTotalSectors = 0;                                  /*@V63867*/
         pBPB->TotalSectors = TotalSectors;                          /*@V63867*/
      }                                                              /*@V63867*/
                                                                     /*@V63867*/

      /* If it's a removable drive, then calculate the file system fields */
      /* i.e. NumFATSectors, etc. in the BPB.                             */

      if (pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE)
      {
         /* Find appropriate DiskTable entry based on TotalSectors */

         for (i = 0; i < DISKTABLECOUNT; i++)
           if (TotalSectors <= DiskTable[i].NumSectors)
              break;

         fBigFat = DiskTable[i].Flags;
         pBPB->ReservedSectors = 1;
         pBPB->MaxDirEntries = DiskTable[i].MaxDirEntries;
         pBPB->SectorsPerCluster = DiskTable[i].SectorsPerCluster;
         pBPB->NumFATs = 2;
         pBPB->MediaType = 0xF0;

         /* Calculate number of FAT table sectors */

         if (fBigFat & vf_Big)
         {
            temp = (pBPB->SectorsPerCluster * 256) + 2;
            pBPB->NumFATSectors = (TotalSectors -
               ((pBPB->MaxDirEntries / 16) + 1) +        /* Dir + Reserved*/
               temp - 1 + (pBPB->SectorsPerCluster * 2)) / temp;
         }
         else
         {
            TotalDataSectors = TotalSectors + pBPB->SectorsPerCluster - 1;

            TotalDataSectors >>= DiskTable[i].Log2SectorsPerCluster;

            TotalDataSectors = ((TotalDataSectors + 1) & (0xFFFFFFFE)) + 2;

            temp = TotalDataSectors;

            TotalDataSectors >>= 1;

            pBPB->NumFATSectors = (TotalDataSectors + temp + 511) / 512;
         }
      }
   }
}

/*--------------------------------------------------------------------------
;
;** Is_BPB_Boot - Is this a valid boot sector ?
;
;   ScratchBuffer points to the boot sector.  In theory, the BPB is
;   correct.  We can, therefore, get all the relevant information
;   from the media (those that we cannot get from the partition
;   table) if we can recognize it.
;
;   USHORT Is_BPB_Boot (PDOSBOOTREC pBootSector)
;
;   ENTRY:    pBootSector      - DOS Boot Sector
;
;   RETURN:   USHORT           - Result Code (NO_ERROR if valid boot sector)
;
;   EFFECTS:
;
;   NOTES:
;
--------------------------------------------------------------------------*/
USHORT Is_BPB_Boot (pVolCB, pBootSector)                             /*@V64818*/
                                                                     /*@V64818*/
PDOSBOOTREC pBootSector;                                             /*@V64818*/
NPVOLCB     pVolCB;                                                  /*@V64818*/
{                                                                    /*@V64818*/
   USHORT rc = NO_ERROR;                                             /*@V64818*/
   UCHAR  MediaType;                                                 /*@V64818*/
   UCHAR  PartType;                                                  /*@V64818*/
                                                                     /*@V64818*/
   /* 1. Make sure short or near jmp is at start of boot sector */   /*@V64818*/
   /* 2.     and high nibble of MediaType in BPB is 0xF         */   /*@V64818*/
   /* 3.         and SectorsPerCluster in BPB is a power of 2   */   /*@V64818*/
                                                                     /*@V64818*/
   MediaType = pBootSector->bpb.MediaType & 0xF0;                    /*@V64818*/
   PartType  = pVolCB->PartitionType;                                /*@V64818*/
                                                                     /*@V64818*/
   if (!((pBootSector->JmpCode == 0xE9) ||                           /*@V64818*/
         (pBootSector->JmpCode == 0xEB && pBootSector->nop == 0x90)))/*@V64818*/
   {                                                                 /*@V64818*/
      rc = ERROR;                                                    /*@V64818*/
   }                                                                 /*@V64818*/
   else if ( !pBootSector->bpb.MaxDirEntries )                       /*@V64818*/
   {                                                                 /*@V64818*/
      rc = ERROR;                                                    /*@V64818*/
   }                                                                 /*@V64818*/
   /* Checks are relaxed for IFS partitions or clones */             /*@V64818*/
   /* of IFS partitions                               */             /*@V64818*/
                                                                     /*@V64818*/
   else if ( PartType == PARTITION_IFS       ||                      /*@V64818*/
             PartType == PARTITION_FTACTIVE  ||                      /*@V64818*/
             PartType == PARTITION_FTINACTIVE   )                    /*@V64818*/
   {                                                                 /*@V64818*/
     if ( MediaType && (MediaType != 0xF0) )                         /*@V64818*/
     {                                                               /*@V64818*/
        rc = ERROR;                                                  /*@V64818*/
     }                                                               /*@V64818*/
   }                                                                 /*@V64818*/
   else                                                              /*@V64818*/
   {                                                                 /*@V64818*/
     if ( MediaType != 0xF0 )                                        /*@V64818*/
     {                                                               /*@V64818*/
        rc = ERROR;                                                  /*@V64818*/
     }                                                               /*@V64818*/
     else if ( !PowerOF2(pBootSector->bpb.SectorsPerCluster) )       /*@V64818*/
     {                                                               /*@V64818*/
        rc = ERROR;                                                  /*@V64818*/
     }                                                               /*@V64818*/
   }                                                                 /*@V64818*/
                                                                     /*@V64818*/
   return(rc);                                                       /*@V64818*/
}                                                                    /*@V64818*/


int validOEM(PUCHAR ptr, int size) // verifies whether OEM string is valid
{                                  // by check for alphanum or '.'
  int i;

  for(i=0;i<size;i++)
  {
    if(ptr[i] == ' ')
     continue;
    if(ptr[i] > 127)
      return 0;
    if(ptr[i] < 46)
      return 0;
    if(ptr[i] < ':')
      continue;
    if(ptr[i] < 'A')
      return 0;
    if(ptr[i] < 'Z')
      continue;
    if(ptr[i] < 'a')
      return 0;
    if(ptr[i] < 'z')
      continue;
    return 0;
  }
  return 1;
}

/*--------------------------------------------------------------------------
;
;** GetBootVersion - Get boot version from boot record
;
;   Get the boot version of the DOS boot sector which appears as a
;   set of characters in the form 'XX.XX' after the 'DOS' or 'IBM'
;   characters.
;
;   USHORT GetBootVersion (PDOSBOOTREC pBootSector)
;
;   ENTRY:    pBootSector      - DOS Boot Sector
;
;   RETURN:   USHORT           - Boot Version
;
;   EFFECTS:
;
;   NOTES:
;
--------------------------------------------------------------------------*/
USHORT GetBootVersion (pBootSector)
PDOSBOOTREC pBootSector;
{
   USHORT i;
   USHORT version = 0;
   for (i = 0; i < sizeof(pBootSector->Release); i++)
   {
      if (pBootSector->Release[i] >= '0' && pBootSector->Release[i] <= '9')
      {
         version = version * 10;
         version = version + (pBootSector->Release[i] - '0');
         if (pBootSector->Release[i+1] == '.')
         {
            version = version * 10;
            version = version + (pBootSector->Release[i+2] - '0');
            break;
         }
      }
   }
   return(version);
}


/*--------------------------------------------------------------------------
;
;** UpdateVolCB - Update a VolCB to represent the given partition
;
;   This routine is called to update a logical VolCB to represent a partition
;   which may have changed due to a media change.  This can occur for
;   partitioned removable supported drives.
;   The logic in this routine mirrors the initialization function BuildNextVolCB().
;
;   USHORT UpdateVolCBB (NPVOLCB npVolCB, ULONG rba, BOOL isFloppy)
;
;   ENTRY:    npVolCB          - Pointer to logical VolCB
;             rba              - Partition sector offset
;             isFloppy         - TRUE if this media is formatted as floppy
;
;   RETURN:   USHORT           - Result Code (NO_ERROR if valid partition)
;
--------------------------------------------------------------------------*/

BOOL UpdateVolCB(NPVOLCB npVolCB, NPVOLCB npPhysVolCB, ULONG rba, BOOL isFloppy)
{
   USHORT rc;
   ULONG  SectorsInPartition, VolBootRBA, CylinderSize;
   ULONG  SectorsInBootRec,StartRBA;
   MBR    *pMBR = (MBR *) ScratchBuffer;
   BOOL   success;

   /* Determine if there is a valid partition (or floppy).
    *
    * Note: a side effect of the Process_xxx() routines is that the npVolCB->MediaBPB
    * HiddenSectors and total sector info is set.
    */
   if (isFloppy)
      success = Process_FloppyAsPartitioned(npVolCB,&VolBootRBA,&SectorsInBootRec)
                ==NO_ERROR;
   else
      success = Process_Partition(npVolCB,&VolBootRBA,&SectorsInBootRec)
                ==NO_ERROR;

   if (success)
     {
     // save the partition offset
     StartRBA=rba;
     // count the hidden sectors
     rba += npVolCB->MediaBPB.HiddenSectors;
     // read in the partition boot record
     rc  = ReadSecInScratch_RBA (npVolCB, rba, 1);  /* Read DOS boot sector */
     // find out if it is valid
     rc |= Is_BPB_Boot(npVolCB,(VOID _far *)&ScratchBuffer);    /*@V88662*//*@V64818*/
     if (!rc)                       /* Is boot sector valid ?      */
     {
        /* copy boot bpb to media bpb */
        BootBPB_To_MediaBPB (npVolCB, (DOSBOOTREC FAR *) &ScratchBuffer);
        npVolCB->Flags |= vf_GeomFromBPB;                            /*@V191499*/
     }
     else                                                            /*@V190002*/
     {
        /* Not a valid BPB in DOS boot record.
         * Copy geometry from the physical VolCB.
         * Note that other geometry specific fields are filled in below.
         */
        npVolCB->MediaBPB.SectorsPerTrack = npPhysVolCB->MediaBPB.SectorsPerTrack;  /*@V190700*/
        npVolCB->MediaBPB.NumHeads = npPhysVolCB->MediaBPB.NumHeads;                /*@V190700*/
        npVolCB->Flags &= ~vf_GeomFromBPB;                           /*@V191499*/
     }

     /* Setup default BPB fields for FORMAT
      */
     npVolCB->MediaBPB.MediaType =
     npVolCB->RecBPB.MediaType = MEDIA_FIXED_DISK;
     npVolCB->MediaBPB.BytesPerSector =
     npVolCB->RecBPB.BytesPerSector = 512;
     npVolCB->MediaBPB.ReservedSectors =
     npVolCB->RecBPB.ReservedSectors = 1;
     npVolCB->MediaBPB.NumFATs =
     npVolCB->RecBPB.NumFATs = 2;

     /* Set up number of logical and physical cylinders.
      * Call Process_Boot to examine the boot sector, set up FAT specific BPB
      * fields, and copy the MediaBPB to the RecBPB.
      */

     npVolCB->NumPhysCylinders = npPhysVolCB->NumPhysCylinders;

     if (npVolCB->MediaBPB.TotalSectors != 0)
        SectorsInPartition = npVolCB->MediaBPB.TotalSectors;
     else
        SectorsInPartition = npVolCB->MediaBPB.BigTotalSectors;

     CylinderSize = npVolCB->MediaBPB.SectorsPerTrack *              /*@V88662*/
                    npVolCB->MediaBPB.NumHeads;                      /*@V88662*/
                                                                     /*@V88662*/
     npVolCB->NumLogCylinders =                                      /*@V89787*/
                  (VolBootRBA + SectorsInBootRec)/CylinderSize;      /*@V89787*/                                               /*@V88662*/
                                                                     /*@V88662*/
     npVolCB->BootRecCyl =                                           /*@V89787*/
                  VolBootRBA/CylinderSize;                           /*@V89787*/                                               /*@V88662*/
                                                                     /*@V88662*/
     npVolCB->PartitionOffset=StartRBA;
     Process_Boot (npVolCB, SectorsInPartition);
     }

   return success;
}


/*--------------------------------------------------------------------------
;                                                                    @V187707
;** UpdateLogicalVolumes - Update all logical volumes associated with a
;                          given physical volume.
;
;
;   BOOL FAR f_UpdateLogicalVolumes(NPVOLCB pPhysVolCB)
;
;   ENTRY:    npVolCB          - pointer to the physical volume CB
;
;   RETURN:   TRUE   -  Updates successful
;             FALSE  -  Updates not successful
;
;   EFFECTS:
;
;   NOTES:
;
--------------------------------------------------------------------------*/

BOOL FAR f_UpdateLogicalVolumes(NPVOLCB pPhysVolCB)                  /*@V187707*/
{
   NPVOLCB pVolCB;
   ULONG   RBA, nextRBA, extended_RBA;
   MBR     *pMBR = (MBR *) ScratchBuffer;
   BOOL    morePartitions, isFloppy;
   USHORT  i;

   pVolCB = FirstLogicalVolCB(pPhysVolCB);

   if (pVolCB == 0) {
      _asm int 3;       //HCT     bug!!!
   }

   f_SWait (&ScratchBufSem);   /* Wait for scratch buffer to be free */

   /* First time through, we're looking for a primary partition, and the
    * relative block address for the MBR is 0.
    */
   RBA = 0;
   extended_RBA = 0;
   morePartitions = TRUE;

   /* Perform an initial read, which will fail due to UncertainMedia
    * report.  This resets the Uncertain media flag.
    */
   pVolCB->PartitionOffset=0;           // Set to 0 since used by ReadSecInScratch_RBA()
   pVolCB->PartitionType = PARTITION_IFS; // Needed for Is_BPB_Boot()
   ReadSecInScratch_RBA (pVolCB, RBA, 1);

   /* Scan the physical disk's partition tables and assign the partitions
    * to the logical volumes reserved for this disk.  If there are more
    * partitions than logical volumes, the additional partitions are left
    * unassigned and are not accessible.
    */
   while (pVolCB && morePartitions) {

      /* Read in the MBR at relative block address 'rba'
       */
      pVolCB->PartitionOffset=0;
      if (ReadSecInScratch_RBA (pVolCB, RBA, 1) != NO_ERROR)
         break;          // If can't read a sector, give up now

      morePartitions = FALSE;

      /* Determine if this is floppy formatted media.  This is
       * checked first time through loop (first sector) by testing
       * for a BPB sector.
       */
      if (RBA == 0)
         if (isFloppy = (Is_BPB_Boot(pVolCB, (PDOSBOOTREC)pMBR) == NO_ERROR))
            pPhysVolCB->pUnitCB->Flags |= UCF_FLOPPY_FMT_AS_FIXED;
         else
            pPhysVolCB->pUnitCB->Flags &= ~UCF_FLOPPY_FMT_AS_FIXED;

      if (!isFloppy) {
         /* Find RBA of next extended partition from the partition table.
          * This is done now since UpdateVolCB() overwrites the scratch
          * buffer which currently contains the partition table.
          */
         for (i = 0; i < 4 && !morePartitions; i++) {
//d_267583            if (pMBR->PartitionTable[i].SysIndicator == PARTITION_EBR) {
            if (pMBR->PartitionTable[i].SysIndicator == PARTITION_EBR || pMBR->PartitionTable[i].SysIndicator == PARTITION_EBRX) { //d_267583
               nextRBA = extended_RBA + pMBR->PartitionTable[i].RelativeSectors;
               morePartitions = TRUE;

               /* If this is the MBR partition table (first sector), then 'nextRBA'
                * is the RBA for the entire extended DOS partition, from which
                * all subsequent extended partition RBAs are offset from.
                */
               if (RBA == 0)
                  extended_RBA = nextRBA;
            }
         }
      }

      /* Process the partition.
       */
      if (UpdateVolCB(pVolCB, pPhysVolCB, RBA, isFloppy)) {

         /* Successfully assigned this logical volume to a partition.
          */
         pVolCB->Flags &= ~vf_NoAssignedPartition;   // Mark volume as assigned to partition
         pVolCB = NextLogicalVolCB(pVolCB);
      }
      RBA = nextRBA;
   }

   /* If there are more logical volumes than partitions,
    * mark the remaining logical volumes as unavailable.
    * Update BPBs for these volumes.
    * TBD: What, if any, updates should be made to the BPBs?
    */
   while (pVolCB) {
      pVolCB->Flags |= vf_NoAssignedPartition;
      pVolCB = NextLogicalVolCB(pVolCB);
   }

   f_SSig (&ScratchBufSem);     /* Release scratch buffer */

   SynchPhysicalGeometry(pPhysVolCB);   /* Synch up physical geometry */  /*@V189588*/

   /* Currently always return TRUE, as compromise to calling code.
    * Not clear what action caller should take if some partitions are
    * assigned successfully and some not.  In any event, unsuccessful
    * logical volumes are left in a consistent state (marked unassigned).
    */
   return TRUE;
}


/*--------------------------------------------------------------------------
;                                                                    @V189588
;** SynchPhysicalGeometry - Synchronize physical geometry with logical partition
;                           geometry if the two don't match.
;
;   This routine is called for partitioned removable media to handle the following
;   problem:
;   Different HW technologies will report different geometries for a given
;   removable media (e.g. a different geometry can be reported for the same
;   device attached to an Adaptec SCSI adapter than when attached to Symbios).
;   Thus the geometry used to create and format partitions (stored in the logical
;   partition's BPB) may not match the geometry reported by the current HW
;   (physical geometry reported by ADD) trying to use the media.
;
;   This causes problems with utilities such as FDISK and FORMAT since the
;   viewed physical geometry isn't consistent with the logical partitions
;   (e.g. partitions won't start on a cylinder boundary).  It also causes
;   internal problems with os2dasd (which has code assuming logical and physical
;   geometries match).
;
;   This routine attempts to recognize this situation and correct it by
;   changing the physical geometry to match the logical geometry.
;   Since os2dasd only uses RBAs to address IO to ADDs, the ADDs don't care
;   what geometry is used above them.
;
;   void SynchPhysicalGeometry(NPVOLCB pPhysVolCB)
;
;   ENTRY:    pPhysVolCB       - pointer to the physical volume CB
;
;   RETURN:   void
;
;   EFFECTS:
;
;   NOTES:
;
--------------------------------------------------------------------------*/
                                                                     /*@V189588*/
VOID SynchPhysicalGeometry(NPVOLCB pPhysVolCB)
{
   NPVOLCB pVolCB;
   USHORT  numHeads, sectorsPerTrack;
   ULONG   sectorsPerCyl;
   ULONG   partitionStart;
   ULONG   totalCylinders, totalSectors;
   BOOL    allSame;
   BOOL    found;                                                    /*@V191499*/

   /* Check for a valid logical partition with valid BPB geometry
    * (i.e. it was formatted), and obtain it's geometry.
    * If no such partitions exist, exit.
    *
    * Note: All logical VolCBs with assigned partitions will appear
    * ahead of 'placeholder' VolCBs using FirstLogicalVolCB(), NextLogicalVolCB().
    */
   found = FALSE;                                                    /*@V191499*/
   pVolCB = FirstLogicalVolCB(pPhysVolCB);
   if (pVolCB == 0) {
      _asm int 3;       //HCT     bug!!!
   }


   while (pVolCB && !(pVolCB->Flags & vf_NoAssignedPartition) && !found) {   /*@V191499*/
      if (pVolCB->Flags & vf_GeomFromBPB)                            /*@V191499*/
         found = TRUE;                                               /*@V191499*/
      else                                                           /*@V191499*/
         pVolCB = NextLogicalVolCB(pVolCB);                          /*@V191499*/
   }                                                                 /*@V191499*/

   if (found) {                                                      /*@V191499*/
      sectorsPerTrack = pVolCB->MediaBPB.SectorsPerTrack;
      numHeads = pVolCB->MediaBPB.NumHeads;
      sectorsPerCyl = sectorsPerTrack * numHeads;
   }
   else
      return;

   /* Check first logical partition's geometry against physical geometry.
    * If they match, exit since the geometries are already in synch.
    */
   if (sectorsPerTrack == pPhysVolCB->MediaBPB.SectorsPerTrack  &&
       numHeads == pPhysVolCB->MediaBPB.NumHeads
      )
      return;

   /* Perform a consistency check on the logical partition geometry
    * by checking that the partition starts on a track boundary.
    * Exit if consistency check fails.
    */
   partitionStart = pVolCB->PartitionOffset + pVolCB->MediaBPB.HiddenSectors;
   if (partitionStart % sectorsPerTrack != 0)
      return;

   /* Check whether all logical partitions share the same geometry.
    *
    * Only check VolCBs with an assigned partition (!vf_NoAssignedPartition)
    * and geometry from a BPB (vf_GeomFromBPB) i.e. a formatted partition.
    */
   allSame = TRUE;
   pVolCB = NextLogicalVolCB(pVolCB);
   while (pVolCB &&
          !(pVolCB->Flags & vf_NoAssignedPartition) &&               /*@V191499*/
          allSame
         ) {
      if (pVolCB->Flags & vf_GeomFromBPB)                            /*@V191499*/
         allSame = sectorsPerTrack == pVolCB->MediaBPB.SectorsPerTrack  &&
                   numHeads == pVolCB->MediaBPB.NumHeads;

      pVolCB = NextLogicalVolCB(pVolCB);
   }

   /* If all logical formatted partitions share the same geometry, synch up the
    * physical geometry to match the logical.
    * To do this, update the physical VolCB as follows:
    *   - update BPBs geometry (SectorsPerTrack and NumHeads)
    *   - update total cylinders based on new geometry
    *   - update total sectors (rounded down to cylinder boundary) based on new geometry.
    * Also:
    * o Update geometry of all unformatted partitions, since they will have previously
    *   been set to the old physical geometry.
    * o Update total physical cylinders of all logical VolCBs associated with this disk.
    */
   if (allSame) {

      /* Update physical VolCB geometry
       */
      pPhysVolCB->MediaBPB.SectorsPerTrack = pPhysVolCB->RecBPB.SectorsPerTrack =
            sectorsPerTrack;
      pPhysVolCB->MediaBPB.NumHeads = pPhysVolCB->RecBPB.NumHeads =
            numHeads;

      /* Calculate total cylinders and round total sectors down to a
       * cylinder boundary.
       */
      totalCylinders = pPhysVolCB->ActualTotalSectors / sectorsPerCyl;
      totalSectors = totalCylinders * sectorsPerCyl;

      pPhysVolCB->NumPhysCylinders = pPhysVolCB->NumLogCylinders  = totalCylinders;

      if (totalSectors > 0xffff) {
         pPhysVolCB->MediaBPB.BigTotalSectors = pPhysVolCB->RecBPB.BigTotalSectors =
               totalSectors;
         pPhysVolCB->MediaBPB.TotalSectors = pPhysVolCB->RecBPB.TotalSectors =
               0;
      }
      else {
         pPhysVolCB->MediaBPB.BigTotalSectors = pPhysVolCB->RecBPB.BigTotalSectors =
               0;
         pPhysVolCB->MediaBPB.TotalSectors = pPhysVolCB->RecBPB.TotalSectors =
               totalSectors;
      }

      /* Update total physical cylinders in the logical VolCBs
       * Update geometry of all unformatted partitions.
       */
      for (pVolCB = FirstLogicalVolCB(pPhysVolCB);
           pVolCB && !(pVolCB->Flags & vf_NoAssignedPartition);
           pVolCB = NextLogicalVolCB(pVolCB)
          ) {

         pVolCB->NumPhysCylinders = totalCylinders;

         if (!(pVolCB->Flags & vf_GeomFromBPB)) {                                   /*@V191499*/
            /* Unformatted partition.  Update it's geometry.                          @V190700
             */                                                                     /*@V190700*/
            pVolCB->MediaBPB.SectorsPerTrack = pVolCB->RecBPB.SectorsPerTrack =     /*@V190700*/
                  sectorsPerTrack;                                                  /*@V190700*/
            pVolCB->MediaBPB.NumHeads = pVolCB->RecBPB.NumHeads =                   /*@V190700*/
                  numHeads;                                                         /*@V190700*/
            totalSectors = pVolCB->MediaBPB.TotalSectors ?                          /*@V190700*/
                  pVolCB->MediaBPB.TotalSectors : pVolCB->MediaBPB.BigTotalSectors; /*@V190700*/
            pVolCB->NumLogCylinders = totalSectors / sectorsPerCyl;                 /*@V190700*/
         }                                                                          /*@V190700*/
      }
   }

}

