public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Jeff V. Merkey" <jmerkey@wolfmountaingroup.com>
To: Phillip Susi <psusi@cfl.rr.com>
Cc: "linux-os (Dick Johnson)" <linux-os@analogic.com>,
	Linux kernel <linux-kernel@vger.kernel.org>
Subject: Re: C/H/S from user space
Date: Fri, 17 Feb 2006 15:22:58 -0700	[thread overview]
Message-ID: <43F64CC2.2010303@wolfmountaingroup.com> (raw)
In-Reply-To: <43F63A59.6090401@cfl.rr.com>


Here's the code to calculate that as well -- from NetWare -- with int 13 
IOCTL calls and from within Windows 98.  This code builds on the djgcc DOS
version og GNU tools.

Jeff

#if (DOS_UTIL)

#define READ_DEVICE   0x02
#define WRITE_DEVICE  0x03
#define NO_VERIFY     0x00
#define WRITE_VERIFY  0x01

// convert cylinder/head/sector addressing to LBA

ULONG CHStoLBA(ULONG disk, LONGLONG cyl, ULONG head, ULONG sector)
{
    register ULONG lba;
    ULONG heads = SystemDisk[disk]->TracksPerCylinder;
    ULONG sectors = SystemDisk[disk]->SectorsPerTrack;

    lba = cyl * (heads * sectors);
    lba += (head * sectors);
    lba += sector;
    lba -= 1;    // CHS is 1 relative so adjust LBA by subtracting 1

    return lba;

}

// convert LBA to cylinder/head/sector addressing

ULONG LBAtoCHS(ULONG disk, ULONG lba, LONGLONG *cyl, ULONG *head,
           ULONG *sector)
{
    ULONG offset;
    ULONG heads = SystemDisk[disk]->TracksPerCylinder;
    ULONG sectors = SystemDisk[disk]->SectorsPerTrack;

    if (!cyl || !head || !sector)
       return -1;

    *cyl = (lba / (heads * sectors));
    offset = lba % (heads * sectors);
    *head = (WORD)(offset / sectors);
    *sector = (WORD)(offset % sectors) + 1;  // sector addressing is
                         // 1 relative so add 1
    return 0;
}

ULONG pReadDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector,
              ULONG sectors, ULONG readAhead)
{
    register ULONG bps, ccode, bytes = 0;
    register NWDISK *NWDisk;
    LONGLONG cylinder;
    ULONG head, sector;
    static _go32_dpmi_registers r;
#if (WINDOWS_98_UTIL)
    static union REGS rl;
#endif

    NWFSSet(&r, 0, sizeof(_go32_dpmi_registers));

    NWDisk = SystemDisk[disk];
    bps = NWDisk->BytesPerSector;

    if ((sectors * bps) > IO_BLOCK_SIZE)
       return bytes;

#if (WINDOWS_98_UTIL)
    rl.x.ax = 0x440D;    // generic IOCTL
    rl.h.bh = 3;         // locks levels 0, 1, 2 or 3
    rl.h.bl = (0x80 | (disk & 0x7F)); // dos limit is 128 drives
    rl.h.ch = 0x08;      // device category
    rl.h.cl = 0x4B;      // lock physical volume
    rl.x.dx = 0;         // permissions
    int86(0x21, &rl, &rl);

#endif

    if (NWDisk->Int13Extensions)
    {
       EXT_REQUEST request;

       NWFSSet(&request, 0, sizeof(EXT_REQUEST));

       request.Size = sizeof(EXT_REQUEST);
       request.Blocks = sectors;
       request.TransferBuffer = (ULONG)(NWDisk->DataSegment << 16) & 
0xFFFF0000;
       request.LBA = StartingLBA;

       movedata(_my_ds(),
        (unsigned)&request,
        NWDisk->RequestSelector,
        0,
        sizeof(EXT_REQUEST));

       r.h.ah = 0x42;
       r.h.dl = (0x80 | (disk & 0x7F));
       r.x.ds = NWDisk->RequestSegment;
       r.x.si = 0;
       r.x.ss = r.x.sp = r.x.flags = 0;

       ccode = _go32_dpmi_simulate_int(0x13, &r);
       if (ccode)
      goto ReadExit;

       // error if carry flag is set
       if (r.x.flags & 1)
       {
      // if the drive reported an ECC occurred, return success
      if (r.h.ah == 0x11)
      {
        movedata(NWDisk->DataSelector,
             0,
             _my_ds(),
             (unsigned)Sector,
             (sectors * bps));

        bytes = (sectors * bps);
        goto ReadExit;
      }
      else
         goto ReadExit;
       }

       movedata(NWDisk->DataSelector,
        0,
        _my_ds(),
        (unsigned)Sector,
        (sectors * bps));

       bytes = (sectors * bps);
       goto ReadExit;
    }
    else
    {
       ccode = LBAtoCHS(disk, StartingLBA, &cylinder, &head, &sector);
       if (ccode)
      goto ReadExit;

       r.h.dh = (BYTE)head;
       r.h.dl = (0x80 | (disk & 0x7F));
       r.h.ch = (BYTE)(cylinder & 0xFF);
       r.h.cl = (BYTE)((cylinder & 0x0300) >> 2);
       r.h.cl |= (BYTE)(sector & 0x3F);
       r.h.ah = READ_DEVICE;
       r.h.al = (BYTE)sectors;
       r.x.es = NWDisk->DataSegment;
       r.x.bx = 0;
       r.x.ss = r.x.sp = r.x.flags = 0;

       ccode = _go32_dpmi_simulate_int(0x13, &r);
       if (ccode)
      goto ReadExit;

       // error if carry flag is set
       if (r.x.flags & 1)
       {
      // if the drive reported an ECC occurred, return success
      if (r.h.ah == 0x11)
      {
         movedata(NWDisk->DataSelector,
             0,
             _my_ds(),
             (unsigned)Sector,
             (sectors * bps));

         bytes = (sectors * bps);
         goto ReadExit;
      }
      else
         goto ReadExit;
       }

       movedata(NWDisk->DataSelector,
        0,
        _my_ds(),
        (unsigned)Sector,
        (sectors * bps));

       bytes = (sectors * bps);
    }

ReadExit:;
#if (WINDOWS_98_UTIL)
    rl.x.ax = 0x440D;    // generic IOCTL
    rl.h.bl = (0x80 | (disk & 0x7F)); // dos limit is 128 drives
    rl.h.ch = 0x08;      // device category
    rl.h.cl = 0x6B;      // unlock physical volume
    int86(0x21, &rl, &rl);
#endif

    return bytes;

}


ULONG pWriteDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector,
               ULONG sectors, ULONG readAhead)
{
    register ULONG bps, ccode, bytes = 0;
    register NWDISK *NWDisk;
    LONGLONG cylinder;
    ULONG head, sector;
    static _go32_dpmi_registers r;
#if (WINDOWS_98_UTIL)
    static union REGS rl;
#endif

    NWFSSet(&r, 0, sizeof(_go32_dpmi_registers));

    NWDisk = SystemDisk[disk];
    bps = NWDisk->BytesPerSector;

    if ((sectors * bps) > IO_BLOCK_SIZE)
       return bytes;

#if (WINDOWS_98_UTIL)
    rl.x.ax = 0x440D;    // generic IOCTL
    rl.h.bh = 3;         // locks levels 0, 1, 2 or 3
    rl.h.bl = (0x80 | (disk & 0x7F)); // dos limit is 128 drives
    rl.h.ch = 0x08;      // device category
    rl.h.cl = 0x4B;      // lock physical volume
    rl.x.dx = 0;         // permissions
    int86(0x21, &rl, &rl);

#endif

    if (NWDisk->Int13Extensions)
    {
       EXT_REQUEST request;

       NWFSSet(&request, 0, sizeof(EXT_REQUEST));

       request.Size = sizeof(EXT_REQUEST);
       request.Blocks = sectors;
       request.TransferBuffer = (ULONG)(NWDisk->DataSegment << 16) & 
0xFFFF0000;
       request.LBA = StartingLBA;

       movedata(_my_ds(),
        (unsigned)&request,
        NWDisk->RequestSelector,
        0,
        sizeof(EXT_REQUEST));

       movedata(_my_ds(),
        (unsigned)Sector,
        NWDisk->DataSelector,
        0,
        (sectors * bps));

       r.h.ah = 0x43;
       r.h.al = NO_VERIFY;
       r.h.dl = (0x80 | (disk & 0x7F));
       r.x.ds = NWDisk->RequestSegment;
       r.x.si = 0;
       r.x.ss = r.x.sp = r.x.flags = 0;

       ccode = _go32_dpmi_simulate_int(0x13, &r);
       if (ccode)
      goto WriteExit;

       // error if carry flag is set
       if (r.x.flags & 1)
       {
      // if the drive reported an ECC occurred, return success
      if (r.h.ah == 0x11)
      {
         bytes = (sectors * bps);
         goto WriteExit;
      }
      else
         goto WriteExit;
       }
       bytes = (sectors * bps);
       goto WriteExit;
    }
    else
    {
       ccode = LBAtoCHS(disk, StartingLBA, &cylinder, &head, &sector);
       if (ccode)
      goto WriteExit;

       movedata(_my_ds(),
        (unsigned)Sector,
        NWDisk->DataSelector,
        0,
        (sectors * bps));

       r.h.dh = (BYTE)head;
       r.h.dl = (0x80 | (disk & 0x7F));
       r.h.ch = (BYTE)(cylinder & 0xFF);
       r.h.cl = (BYTE)((cylinder & 0x0300) >> 2);
       r.h.cl |= (BYTE)(sector & 0x3F);
       r.h.ah = WRITE_DEVICE;
       r.h.al = (BYTE)sectors;
       r.x.es = NWDisk->DataSegment;
       r.x.bx = 0;
       r.x.ds = r.x.ss = r.x.sp = r.x.flags = 0;

       ccode = _go32_dpmi_simulate_int(0x13, &r);
       if (ccode)
      goto WriteExit;

       // error if carry flag is set
       if (r.x.flags & 1)
       {
      // if the drive reported an ECC occurred, return success
      if (r.h.ah == 0x11)
      {
         bytes = (sectors * bps);
         goto WriteExit;
      }
      else
         goto WriteExit;
       }
       bytes = (sectors * bps);
       goto WriteExit;
    }

WriteExit:;
#if (WINDOWS_98_UTIL)
    rl.x.ax = 0x440D;    // generic IOCTL
    rl.h.bl = (0x80 | (disk & 0x7F)); // dos limit is 128 drives
    rl.h.ch = 0x08;      // device category
    rl.h.cl = 0x6B;      // unlock physical volume
    int86(0x21, &rl, &rl);
#endif

    return bytes;
}

ULONG pZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, ULONG sectors,
              ULONG readAhead)
{
    register ULONG bps, ccode, bytes = 0;
    register NWDISK *NWDisk;
    LONGLONG cylinder;
    ULONG head, sector;
    static _go32_dpmi_registers r;
#if (WINDOWS_98_UTIL)
    static union REGS rl;
#endif

    NWFSSet(&r, 0, sizeof(_go32_dpmi_registers));

    NWDisk = SystemDisk[disk];
    bps = NWDisk->BytesPerSector;

    if ((sectors * bps) > IO_BLOCK_SIZE)
       return bytes;

    movedata(_my_ds(),
         (unsigned)ZeroBuffer,
         NWDisk->DataSelector,
         0,
         (sectors * bps));

#if (WINDOWS_98_UTIL)
    rl.x.ax = 0x440D;    // generic IOCTL
    rl.h.bh = 3;         // locks levels 0, 1, 2 or 3
    rl.h.bl = (0x80 | (disk & 0x7F)); // dos limit is 128 drives
    rl.h.ch = 0x08;      // device category
    rl.h.cl = 0x4B;      // lock physical volume
    rl.x.dx = 0;         // permissions
    int86(0x21, &rl, &rl);

#endif

    if (NWDisk->Int13Extensions)
    {
       EXT_REQUEST request;

       NWFSSet(&request, 0, sizeof(EXT_REQUEST));

       request.Size = sizeof(EXT_REQUEST);
       request.Blocks = sectors;
       request.TransferBuffer = (ULONG)(NWDisk->DataSegment << 16) & 
0xFFFF0000;
       request.LBA = StartingLBA;

       movedata(_my_ds(),
        (unsigned)&request,
        NWDisk->RequestSelector,
        0,
        sizeof(EXT_REQUEST));

       r.h.ah = 0x43;
       r.h.al = NO_VERIFY;
       r.h.dl = (0x80 | (disk & 0x7F));
       r.x.ds = NWDisk->RequestSegment;
       r.x.si = 0;
       r.x.ss = r.x.sp = r.x.flags = 0;

       ccode = _go32_dpmi_simulate_int(0x13, &r);
       if (ccode)
      goto FillExit;

       // error if carry flag is set
       if (r.x.flags & 1)
       {
      // if the drive reported an ECC occurred, return success
      if (r.h.ah == 0x11)
      {
         bytes = (sectors * bps);
         goto FillExit;
      }
      else
         goto FillExit;
       }
       bytes = (sectors * bps);
       goto FillExit;
    }
    else
    {
       ccode = LBAtoCHS(disk, StartingLBA, &cylinder, &head, &sector);
       if (ccode)
      goto FillExit;

       r.h.dh = (BYTE)head;
       r.h.dl = (0x80 | (disk & 0x7F));
       r.h.ch = (BYTE)(cylinder & 0xFF);
       r.h.cl = (BYTE)((cylinder & 0x0300) >> 2);
       r.h.cl |= (BYTE)(sector & 0x3F);
       r.h.ah = 0x03;
       r.h.al = (BYTE)sectors;
       r.x.es = NWDisk->DataSegment;
       r.x.bx = 0;
       r.x.ds = r.x.ss = r.x.sp = r.x.flags = 0;

       ccode = _go32_dpmi_simulate_int(0x13, &r);
       if (ccode)
      goto FillExit;

       // error if carry flag is set
       if (r.x.flags & 1)
       {
      // if the drive reported an ECC occurred, return success
      if (r.h.ah == 0x11)
      {
         bytes = (sectors * bps);
         goto FillExit;
      }
      else
         goto FillExit;
       }
       bytes = (sectors * bps);
       goto FillExit;
    }

FillExit:;
#if (WINDOWS_98_UTIL)
    rl.x.ax = 0x440D;    // generic IOCTL
    rl.h.bl = (0x80 | (disk & 0x7F)); // dos limit is 128 drives
    rl.h.ch = 0x08;      // device category
    rl.h.cl = 0x6B;      // unlock physical volume
    int86(0x21, &rl, &rl);
#endif

    return bytes;

}

void ScanDiskDevices(void)
{
    register ULONG j, i, retCode;
    BYTE *Sector;
    static union REGS r;
    DRIVE_INFO dinfo;

    Sector = NWFSIOAlloc(IO_BLOCK_SIZE, DISKBUF_TAG);
    if (!Sector)
    {
       NWFSPrint("nwfs:  allocation error in AddDiskDevices\n");
       return;
    }

    for (FirstValidDisk = (ULONG)-1, j = 0; j < MAX_DOS_DISKS; j++)
    {

#if (WINDOWS_98_UTIL)
       r.x.ax = 0x440D;    // generic IOCTL
       r.h.bh = 1;         // locks levels 0, 1, 2 or 3
       r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
       r.h.ch = 0x08;      // device category
       r.h.cl = 0x4B;      // lock physical volume
       r.x.dx = 1;         // permissions
       r.h.cflag = 0x0001;

       int86(0x21, &r, &r);
#endif

       // test fixed disk status
       r.h.ah = 0x10;  // test drive status
       r.h.dl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
       int86(0x13, &r, &r);

       // if we got the drive status, and the drive is active,
       // assume the disk is valid.
       if ((!r.h.cflag) && (!r.h.ah))
       {
          // now check if this device supports removable media.  This
      // would indicate this device is a CDROM drive.  If we detect
          // that this device supports removable meida, then do not
          // add it -- it's most likely a CDROM or tape device and
      // we should not add it.

          // see if a change line is available for this device.
          r.h.ah = 0x15;  // test drive status
          r.h.dl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
          int86(0x13, &r, &r);

          // 00-no drive, 01-diskette, 02-change line, 03-fixed disk
      if (r.h.ch == 0x02)
      {

#if (WINDOWS_98_UTIL)
         r.x.ax = 0x440D;    // generic IOCTL
         r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
         r.h.ch = 0x08;      // device category
         r.h.cl = 0x6B;      // unlock physical volume
         int86(0x21, &r, &r);
#endif
         continue;
      }

      if (!SystemDisk[j])
      {
         SystemDisk[j] = (NWDISK *) NWFSAlloc(sizeof(NWDISK), NWDISK_TAG);
         if (!SystemDisk[j])
         {
        NWFSPrint("nwfs: memory allocation failure in AddDiskDevices\n");

#if (WINDOWS_98_UTIL)
        r.x.ax = 0x440D;    // generic IOCTL
        r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
        r.h.ch = 0x08;      // device category
        r.h.cl = 0x6B;      // unlock physical volume
        int86(0x21, &r, &r);
#endif
        continue;
         }
         NWFSSet(SystemDisk[j], 0, sizeof(NWDISK));
      }

      SystemDisk[j]->PhysicalDiskHandle = (void *)(0x80 | (j & 0x7F));
      SystemDisk[j]->DiskNumber = j;
      SystemDisk[j]->Int13Extensions = Int13ExtensionsPresent(j);

      SystemDisk[j]->DataSegment =
           __dpmi_allocate_dos_memory(PARAGRAPH_ALIGN(IO_BLOCK_SIZE),
                      &SystemDisk[j]->DataSelector);
      if (SystemDisk[j]->DataSegment == (WORD) -1)
      {
         SystemDisk[j]->PhysicalDiskHandle = 0;
         NWFSFree(SystemDisk[j]);
         SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
         r.x.ax = 0x440D;    // generic IOCTL
         r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
         r.h.ch = 0x08;      // device category
         r.h.cl = 0x6B;      // unlock physical volume
         int86(0x21, &r, &r);
#endif
         continue;
      }

      SystemDisk[j]->DriveInfoSegment =
           __dpmi_allocate_dos_memory(PARAGRAPH_ALIGN(IO_BLOCK_SIZE),
                      &SystemDisk[j]->DriveInfoSelector);
      if (SystemDisk[j]->DriveInfoSegment == (WORD) -1)
      {
         if (SystemDisk[j]->DataSelector)
        __dpmi_free_dos_memory(SystemDisk[j]->DataSelector);
         SystemDisk[j]->DataSelector = 0;

         SystemDisk[j]->PhysicalDiskHandle = 0;
         NWFSFree(SystemDisk[j]);
         SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
         r.x.ax = 0x440D;    // generic IOCTL
         r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
         r.h.ch = 0x08;      // device category
         r.h.cl = 0x6B;      // unlock physical volume
         int86(0x21, &r, &r);
#endif
         continue;
      }

      SystemDisk[j]->RequestSegment =
           __dpmi_allocate_dos_memory(PARAGRAPH_ALIGN(sizeof(EXT_REQUEST)),
                      &SystemDisk[j]->RequestSelector);
      if (SystemDisk[j]->RequestSegment == (WORD) -1)
      {
         if (SystemDisk[j]->DataSelector)
        __dpmi_free_dos_memory(SystemDisk[j]->DataSelector);
         SystemDisk[j]->DataSelector = 0;

         if (SystemDisk[j]->DriveInfoSelector)
        __dpmi_free_dos_memory(SystemDisk[j]->DriveInfoSelector);
         SystemDisk[j]->DriveInfoSelector = 0;

         SystemDisk[j]->PhysicalDiskHandle = 0;
         NWFSFree(SystemDisk[j]);
         SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
         r.x.ax = 0x440D;    // generic IOCTL
         r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
         r.h.ch = 0x08;      // device category
         r.h.cl = 0x6B;      // unlock physical volume
         int86(0x21, &r, &r);
#endif
         continue;
      }

      // if int 13 extensions are present, then adjust drive geometry
      // based on reported drive info.

      if (SystemDisk[j]->Int13Extensions)
      {
         register ULONG cylinders, heads, sectors;
         _go32_dpmi_registers r32;

         NWFSSet(&r32, 0, sizeof(_go32_dpmi_registers));
         NWFSSet(&dinfo, 0, sizeof(DRIVE_INFO));

         dinfo.Size = sizeof(DRIVE_INFO);

         movedata(_my_ds(), (unsigned)&dinfo,
              SystemDisk[j]->DriveInfoSelector, 0,
              sizeof(DRIVE_INFO));

         // get int 13 extension drive info
         r32.h.ah = 0x48;
         r32.h.dl = (0x80 | (j & 0x7F));
         r32.x.si = 0;
         r32.x.ds = SystemDisk[j]->DriveInfoSegment;

         _go32_dpmi_simulate_int(0x13, &r32);

         movedata(SystemDisk[j]->DriveInfoSelector, 0,
              _my_ds(), (unsigned)&dinfo,
              sizeof(DRIVE_INFO));

         // if TotalSectors is 0, then there are no drives
         // attached to this controller.

         if (!dinfo.TotalSectors)
         {
        if (SystemDisk[j]->RequestSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->RequestSelector);
        SystemDisk[j]->RequestSelector = 0;

        if (SystemDisk[j]->DataSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DataSelector);
        SystemDisk[j]->DataSelector = 0;

        if (SystemDisk[j]->DriveInfoSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DriveInfoSelector);
        SystemDisk[j]->DriveInfoSelector = 0;

        SystemDisk[j]->PhysicalDiskHandle = 0;
        NWFSFree(SystemDisk[j]);
        SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
        r.x.ax = 0x440D;    // generic IOCTL
        r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
        r.h.ch = 0x08;      // device category
        r.h.cl = 0x6B;      // unlock physical volume
        int86(0x21, &r, &r);
#endif
        continue;
         }

         r.h.ah = 0x08;   // read drive parameters
         r.h.dl = (0x80 | (j & 0x7F));

         int86(0x13, &r, &r);

         if (r.h.cflag)
         {
        if (SystemDisk[j]->RequestSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->RequestSelector);
        SystemDisk[j]->RequestSelector = 0;

        if (SystemDisk[j]->DataSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DataSelector);
        SystemDisk[j]->DataSelector = 0;

        if (SystemDisk[j]->DriveInfoSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DriveInfoSelector);
        SystemDisk[j]->DriveInfoSelector = 0;

        SystemDisk[j]->PhysicalDiskHandle = 0;
        NWFSFree(SystemDisk[j]);
        SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
        r.x.ax = 0x440D;    // generic IOCTL
        r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
        r.h.ch = 0x08;      // device category
        r.h.cl = 0x6B;      // unlock physical volume
        int86(0x21, &r, &r);
#endif
        continue;
         }

         // translate drive geometry based on the total sectors
         // reported by the Int 13 extension procedure.

         heads = r.h.dh + 1;
         sectors = ((WORD)r.h.cl & 0x003F);
         cylinders = (dinfo.TotalSectors / (heads * sectors));

         // make sure that cylinders are within the maximum value
         // allowed by the Int 13 Extended Architecture.  At present,
         // this limit is 16 mega-tera sectors (2^64).

         // assume the current IDE limits for cylinder count
         if (cylinders > (ULONG) 65536)
         {
        if (SystemDisk[j]->RequestSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->RequestSelector);
        SystemDisk[j]->RequestSelector = 0;

        if (SystemDisk[j]->DataSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DataSelector);
        SystemDisk[j]->DataSelector = 0;

        if (SystemDisk[j]->DriveInfoSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DriveInfoSelector);
        SystemDisk[j]->DriveInfoSelector = 0;

        SystemDisk[j]->PhysicalDiskHandle = 0;
        NWFSFree(SystemDisk[j]);
        SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
        r.x.ax = 0x440D;    // generic IOCTL
        r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
        r.h.ch = 0x08;      // device category
        r.h.cl = 0x6B;      // unlock physical volume
        int86(0x21, &r, &r);
#endif
        continue;
         }

         //   Use the Phoenix method of drive translation
         //   to translate drive geometry for those drives
         //   that exceed 1024 cylinders in size.
         //
         //   Phoenix Geometry Translation Table
         //   -----------------------------------
         //
         //   Phys Cylinders    Phys Heads  Trans Cyl Trans Heads  Max
         //    --------------------------------------------------------
         //   1     <C<= 1024    1 <H<= 16   C = C     H = H     528 MB
         //   1024  <C<= 2048    1 <H<= 16   C = C/2   H = H*2   1.0 GB
         //   2048  <C<= 4096    1 <H<= 16   C = C/4   H = H*4   2.1 GB
         //   4096  <C<= 8192    1 <H<= 16   C = C/8   H = H*8   4.2 GB
         //   8192  <C<= 16384   1 <H<= 16   C = C/16  H = H*16  8.4 GB
         //   16384 <C<= 32768   1 <H<= 8    C = C/32  H = H*32  8.4 GB
         //   32768 <C<= 65536   1 <H<= 4    C = C/64  H = H*64  8.4 GB
         //
         //   LBA Assisted Translation Table
         //   ------------------------------
         //
         //   (NOTE:  The method below is an alternate method for
         //   translating large drives that does not place any limits
         //   on reported drive geometry.  It has the disadvantage
         //   of always assuming 63 Sectors Per Track.)
         //
         //   Range              Sectors  Heads   Cylinders
         //   -----------------------------------------------------
         //   1 MB   <X< 528 MB    63       16    X/(63 * 16 * 512)
         //   528 MB <X< 1.0 GB    63       32    X/(63 * 32 * 512)
         //   1.0 GB <X< 2.1 GB    63       64    X/(63 * 64 * 512)
         //   2.1 GB <X< 4.2 GB    63      128    X/(63 * 128 * 512)
         //   4.2 GB <X< 8.4 GB    63      255    X/(63 * 255 * 512)
         //

         // Adjust cylinder and head dimensions until this drive
         // presents a geometry with a cylinder count that is less
         // than 1024 or Heads less than or equal to 255.

         if (cylinders >= 1024)
         {
        while ((heads * 2) <= 256)
        {
           heads *= 2;
           cylinders /= 2;
           if (cylinders < 1024)
              break;
        }
         }

             if (FirstValidDisk == (ULONG)-1)
                FirstValidDisk = j;

         SystemDisk[j]->BytesPerSector = 512;
         SystemDisk[j]->Cylinders = (LONGLONG) cylinders;
         SystemDisk[j]->TracksPerCylinder = heads;
         SystemDisk[j]->SectorsPerTrack = sectors;
         SystemDisk[j]->driveSize = (LONGLONG)
                  (SystemDisk[j]->Cylinders *
                   SystemDisk[j]->TracksPerCylinder *
                   SystemDisk[j]->SectorsPerTrack *
                   SystemDisk[j]->BytesPerSector);
#if (VERBOSE)
         NWFSPrint("disk-%d cyl-%d head-%d sector-%d (Int 13)\n",
              (int)j,
              (int)SystemDisk[j]->Cylinders,
              (int)SystemDisk[j]->TracksPerCylinder,
              (int)SystemDisk[j]->SectorsPerTrack);
#endif
      }
      else
      {
         // query the drive parameters with standard bios
         r.h.ah = 0x08;
         r.h.dl = (0x80 | (j & 0x7F));

         int86(0x13, &r, &r);

         if (r.h.cflag)
         {
        if (SystemDisk[j]->RequestSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->RequestSelector);
        SystemDisk[j]->RequestSelector = 0;

        if (SystemDisk[j]->DataSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DataSelector);
        SystemDisk[j]->DataSelector = 0;

        if (SystemDisk[j]->DriveInfoSelector)
           __dpmi_free_dos_memory(SystemDisk[j]->DriveInfoSelector);
        SystemDisk[j]->DriveInfoSelector = 0;

        SystemDisk[j]->PhysicalDiskHandle = 0;
        NWFSFree(SystemDisk[j]);
        SystemDisk[j] = 0;

#if (WINDOWS_98_UTIL)
        r.x.ax = 0x440D;    // generic IOCTL
        r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
        r.h.ch = 0x08;      // device category
        r.h.cl = 0x6B;      // unlock physical volume
        int86(0x21, &r, &r);
#endif
        continue;
         }

             if (FirstValidDisk == (ULONG)-1)
                FirstValidDisk = j;

         SystemDisk[j]->BytesPerSector = 512;
         SystemDisk[j]->Cylinders =
         (LONGLONG)(((WORD)((WORD)r.h.cl << 2) & 0x0300) |
                (WORD)r.h.ch) + 1;
         SystemDisk[j]->TracksPerCylinder = (r.h.dh + 1);
         SystemDisk[j]->SectorsPerTrack = ((WORD)r.h.cl & 0x003F);
         SystemDisk[j]->driveSize = (LONGLONG)
                  (SystemDisk[j]->Cylinders *
                   SystemDisk[j]->TracksPerCylinder *
                   SystemDisk[j]->SectorsPerTrack *
                   SystemDisk[j]->BytesPerSector);
#if (VERBOSE)
         NWFSPrint("disk-%d cyl-%d head-%d sector-%d\n",
              (int)j,
              (int)SystemDisk[j]->Cylinders,
              (int)SystemDisk[j]->TracksPerCylinder,
              (int)SystemDisk[j]->SectorsPerTrack);
#endif
      }

#if (WINDOWS_98_UTIL)
      r.x.ax = 0x440D;    // generic IOCTL
      r.h.bl = (0x80 | (j & 0x7F)); // dos limit is 128 drives
      r.h.ch = 0x08;      // device category
      r.h.cl = 0x6B;      // unlock physical volume
      int86(0x21, &r, &r);
#endif
      TotalDisks++;
      if (TotalDisks > MaximumDisks)
         MaximumDisks = TotalDisks;

      retCode = ReadDiskSectors(j, 0, Sector,
             IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector,
             IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector);
      if (!retCode)
      {
         NWFSPrint("nwfs:  disk-%d read error in ScanDiskDevices\n", 
(int)j);
         continue;
      }

      NWFSCopy(&SystemDisk[j]->partitionSignature, &Sector[0x01FE], 2);

      if (SystemDisk[j]->partitionSignature != 0xAA55)
      {
#if (VERBOSE)
         NWFSPrint("nwfs:  partition signature 0xAA55 not found 
disk(%d)\n", (int)j);
#endif
         NWFSSet(&SystemDisk[j]->PartitionTable[0].fBootable, 0, 64);
         continue;
      }
      else
      {
         NWFSCopy(&SystemDisk[j]->PartitionTable[0].fBootable,
              &Sector[0x01BE], 64);
      }

      // scan for Netware Partitions and detect 3.x and 4.x/5.x 
partition types
      for (i=0, SystemDisk[j]->NumberOfPartitions = 0; i < 4; i++)
      {
         if (SystemDisk[j]->PartitionTable[i].nSectorsTotal)
                SystemDisk[j]->NumberOfPartitions++;           

         if (SystemDisk[j]->PartitionTable[i].SysFlag == NETWARE_386_ID)
         {
        retCode = ReadDiskSectors(j,
                 SystemDisk[j]->PartitionTable[i].StartLBA,
                 Sector,
                 IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector,
                 IO_BLOCK_SIZE / SystemDisk[j]->BytesPerSector);
        if (!retCode)
        {
           NWFSPrint("nwfs:  disk-%d read error in ScanDiskDevices 
(part)\n", (int)j);
           continue;
        }

        if (!NWFSCompare(Sector, NwPartSignature, 16))
           SystemDisk[j]->PartitionVersion[i] = NW4X_PARTITION;
        else
           SystemDisk[j]->PartitionVersion[i] = NW3X_PARTITION;
         }
      }
       }
    }
    NWFSFree(Sector);
    return;
}

Phillip Susi wrote:

> linux-os (Dick Johnson) wrote:
>
>>
>> Yes, it's a very good model, in fact what I've been talking about.
>> However, several people who refused to read or understand, insisted
>> upon obtaining the exact same C/H/S that the machine claimed to
>> use when it was booted.
>>
>
> That's because if you don't use the same geometry that the bios 
> reports when calculating the CHS addresses of the sectors you intend 
> to load, you won't be requesting the right sectors from int 13.
>
>> So, since Linux doesn't destroy that information remaining in
>> the BIOS tables, I show how to make it available to a 'root' user.
>> Observation over several machines will show that the BIOS always
>> uses the same stuff for large media and, in fact, it has no choice.
>> Basically, this means that the first part of the boot-code, the
>> stuff that needs to be translated to fit into the int 0x13 registers,
>> needs to be below 1024 cylinders, 63 sectors-track, and 256 heads.
>> Trivial... even LILO was able to do that! Once the machine boots
>> past the requirement to use the BIOS services, it's a CHS=NOP.
>>
>
> Generally yes, modern large disks will get clamped at 1024 cylinders, 
> 255 heads, and 63 sectors.  You seem to be arguing that this will 
> always be the case.  If that is so, then the kernel doesn't need to 
> store these values since it is known a priori does it?  But it isn't 
> always going to be 255/63, there are some bioses ( I forget which ) 
> that cap the number of heads at 240, and disks that are smaller than 8 
> gigs also will have less than 255 heads.
>
>
>


  parent reply	other threads:[~2006-02-17 21:26 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-02-17 17:01 C/H/S from user space linux-os (Dick Johnson)
2006-02-17 18:37 ` Jeff V. Merkey
2006-02-17 19:59   ` Phillip Susi
2006-02-17 20:04   ` linux-os (Dick Johnson)
2006-02-17 20:24     ` Nick Warne
2006-02-17 20:39       ` linux-os (Dick Johnson)
2006-02-17 21:04     ` Phillip Susi
2006-02-17 21:22       ` linux-os (Dick Johnson)
2006-02-17 22:20         ` Phillip Susi
2006-02-18  3:42           ` Marcin Dalecki
2006-02-18 16:20             ` Phillip Susi
2006-02-17 22:24         ` Jeff V. Merkey
2006-02-17 22:22       ` Jeff V. Merkey [this message]
  -- strict thread matches above, loose matches on Subject: below --
2006-02-17 20:30 Seewer Philippe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=43F64CC2.2010303@wolfmountaingroup.com \
    --to=jmerkey@wolfmountaingroup.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-os@analogic.com \
    --cc=psusi@cfl.rr.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox