public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* C/H/S from user space
@ 2006-02-17 17:01 linux-os (Dick Johnson)
  2006-02-17 18:37 ` Jeff V. Merkey
  0 siblings, 1 reply; 14+ messages in thread
From: linux-os (Dick Johnson) @ 2006-02-17 17:01 UTC (permalink / raw)
  To: Linux kernel

[-- Attachment #1: Type: text/plain, Size: 1720 bytes --]



For those who think that C/H/S translation is useful,
attached is a simple program that gets whatever the BIOS
used from user-space. If you have large media (most do),
you will descover that C/H/S is useless because it is
always set to "MAX" like this:

 	Disk parameter table(s) at vector 0x41
Disk0
     Cylinders = 1024
       Sectors = 63
         Heads = 255
Write precomp = 0
  Landing zone = 65296
 	Reserved bit 0 set
 	Reserved bit 1 set
 	Reserved bit 2 set
 	More than 8 heads
 	Reserved bit 4 set
 	Defect map present
 	Disable retries
 	Disable retries
Disk1
     Cylinders = 306
       Sectors = 1
         Heads = 4
Write precomp = 0
  Landing zone = 12544
 	Disk parameter table(s) at vector 0x46
Disk0
     Cylinders = 306
       Sectors = 1
         Heads = 4
Write precomp = 0
  Landing zone = 12544
Disk1
     Cylinders = 306
       Sectors = 1
         Heads = 4
Write precomp = 0
  Landing zone = 12544


Cheers,
Dick Johnson
Penguin : Linux version 2.6.15.4 on an i686 machine (5589.55 BogoMips).
Warning : 98.36% of all statistics are fiction.
_
\x1a\x04


****************************************************************
The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

[-- Attachment #2: CHS.tar.gz --]
[-- Type: APPLICATION/x-gzip, Size: 4141 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  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)
  0 siblings, 2 replies; 14+ messages in thread
From: Jeff V. Merkey @ 2006-02-17 18:37 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: Linux kernel


Dick,

The model Netware uses for large drives for calculating C/H/S addressed 
this problem years ago and
provides more useful output, since C/H/S is converted into a hieristic 
which acts almost like an MD5 hash
and for a given dimension, does provide unique output for even very 
large drives.

Code Attached.

Jeff



ULONG SetPartitionTableGeometry(BYTE *hd, BYTE *sec, BYTE *cyl,
                ULONG LBA, ULONG TracksPerCylinder,
                ULONG SectorsPerTrack)
{
    ULONG offset, cylinders, head, sector;

    if (!cyl || !hd || !sec)
       return -1;

    cylinders = (LBA / (TracksPerCylinder * SectorsPerTrack));
    offset = LBA % (TracksPerCylinder * SectorsPerTrack);
    head = (WORD)(offset / SectorsPerTrack);
    sector = (WORD)(offset % SectorsPerTrack) + 1;

    if (cylinders < 1023)
    {
       *sec = (BYTE)sector;
       *hd = (BYTE)head;
       *cyl = (BYTE)(cylinders & 0xff);
       *sec |= (BYTE)((cylinders >> 2) & 0xC0);
    }
    else
    {
    *sec = (BYTE)(SectorsPerTrack | 0xC0);
    *hd = (BYTE)(TracksPerCylinder - 1);
    *cyl = (BYTE)0xFE;
    }

    return 0;
}

ULONG SetPartitionTableValues(struct PartitionTableEntry *Part,
                  ULONG Type,
                  ULONG StartingLBA,
                  ULONG EndingLBA,
                  ULONG Flag,
                  ULONG TracksPerCylinder,
                  ULONG SectorsPerTrack)
{

    Part->SysFlag = (BYTE) Type;
    Part->fBootable = (BYTE) Flag;
    Part->StartLBA = StartingLBA;
    Part->nSectorsTotal = (EndingLBA - StartingLBA) + 1;

    SetPartitionTableGeometry(&Part->HeadStart, &Part->SecStart, 
&Part->CylStart,
                  StartingLBA, TracksPerCylinder, SectorsPerTrack);

    SetPartitionTableGeometry(&Part->HeadEnd, &Part->SecEnd, &Part->CylEnd,
                  EndingLBA, TracksPerCylinder, SectorsPerTrack);

    return 0;

}




linux-os (Dick Johnson) wrote:

>For those who think that C/H/S translation is useful,
>attached is a simple program that gets whatever the BIOS
>used from user-space. If you have large media (most do),
>you will descover that C/H/S is useless because it is
>always set to "MAX" like this:
>
> 	Disk parameter table(s) at vector 0x41
>Disk0
>     Cylinders = 1024
>       Sectors = 63
>         Heads = 255
>Write precomp = 0
>  Landing zone = 65296
> 	Reserved bit 0 set
> 	Reserved bit 1 set
> 	Reserved bit 2 set
> 	More than 8 heads
> 	Reserved bit 4 set
> 	Defect map present
> 	Disable retries
> 	Disable retries
>Disk1
>     Cylinders = 306
>       Sectors = 1
>         Heads = 4
>Write precomp = 0
>  Landing zone = 12544
> 	Disk parameter table(s) at vector 0x46
>Disk0
>     Cylinders = 306
>       Sectors = 1
>         Heads = 4
>Write precomp = 0
>  Landing zone = 12544
>Disk1
>     Cylinders = 306
>       Sectors = 1
>         Heads = 4
>Write precomp = 0
>  Landing zone = 12544
>
>
>Cheers,
>Dick Johnson
>Penguin : Linux version 2.6.15.4 on an i686 machine (5589.55 BogoMips).
>Warning : 98.36% of all statistics are fiction.
>_
>\x1a\x04
>
>
>****************************************************************
>The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.
>
>Thank you.
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-17 18:37 ` Jeff V. Merkey
@ 2006-02-17 19:59   ` Phillip Susi
  2006-02-17 20:04   ` linux-os (Dick Johnson)
  1 sibling, 0 replies; 14+ messages in thread
From: Phillip Susi @ 2006-02-17 19:59 UTC (permalink / raw)
  To: Jeff V. Merkey; +Cc: linux-os (Dick Johnson), Linux kernel

Other than generate CHS addresses that are invalid due to having S > 62, 
what is this code supposed to do?


Jeff V. Merkey wrote:
> 
> Dick,
> 
> The model Netware uses for large drives for calculating C/H/S addressed 
> this problem years ago and
> provides more useful output, since C/H/S is converted into a hieristic 
> which acts almost like an MD5 hash
> and for a given dimension, does provide unique output for even very 
> large drives.
> 
> Code Attached.
> 
> Jeff
> 
> 
> 
> ULONG SetPartitionTableGeometry(BYTE *hd, BYTE *sec, BYTE *cyl,
>                ULONG LBA, ULONG TracksPerCylinder,
>                ULONG SectorsPerTrack)
> {
>    ULONG offset, cylinders, head, sector;
> 
>    if (!cyl || !hd || !sec)
>       return -1;
> 
>    cylinders = (LBA / (TracksPerCylinder * SectorsPerTrack));
>    offset = LBA % (TracksPerCylinder * SectorsPerTrack);
>    head = (WORD)(offset / SectorsPerTrack);
>    sector = (WORD)(offset % SectorsPerTrack) + 1;
> 
>    if (cylinders < 1023)
>    {
>       *sec = (BYTE)sector;
>       *hd = (BYTE)head;
>       *cyl = (BYTE)(cylinders & 0xff);
>       *sec |= (BYTE)((cylinders >> 2) & 0xC0);
>    }
>    else
>    {
>    *sec = (BYTE)(SectorsPerTrack | 0xC0);
>    *hd = (BYTE)(TracksPerCylinder - 1);
>    *cyl = (BYTE)0xFE;
>    }
> 
>    return 0;
> }
> 
> ULONG SetPartitionTableValues(struct PartitionTableEntry *Part,
>                  ULONG Type,
>                  ULONG StartingLBA,
>                  ULONG EndingLBA,
>                  ULONG Flag,
>                  ULONG TracksPerCylinder,
>                  ULONG SectorsPerTrack)
> {
> 
>    Part->SysFlag = (BYTE) Type;
>    Part->fBootable = (BYTE) Flag;
>    Part->StartLBA = StartingLBA;
>    Part->nSectorsTotal = (EndingLBA - StartingLBA) + 1;
> 
>    SetPartitionTableGeometry(&Part->HeadStart, &Part->SecStart, 
> &Part->CylStart,
>                  StartingLBA, TracksPerCylinder, SectorsPerTrack);
> 
>    SetPartitionTableGeometry(&Part->HeadEnd, &Part->SecEnd, &Part->CylEnd,
>                  EndingLBA, TracksPerCylinder, SectorsPerTrack);
> 
>    return 0;
> 
> }
> 
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  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 21:04     ` Phillip Susi
  1 sibling, 2 replies; 14+ messages in thread
From: linux-os (Dick Johnson) @ 2006-02-17 20:04 UTC (permalink / raw)
  To: Jeff V. Merkey; +Cc: Linux kernel


On Fri, 17 Feb 2006, Jeff V. Merkey wrote:

>
> Dick,
>
> The model Netware uses for large drives for calculating C/H/S addressed
> this problem years ago and
> provides more useful output, since C/H/S is converted into a hieristic
> which acts almost like an MD5 hash
> and for a given dimension, does provide unique output for even very
> large drives.
>
> Code Attached.
>
> Jeff
>
>
>
> ULONG SetPartitionTableGeometry(BYTE *hd, BYTE *sec, BYTE *cyl,
>                ULONG LBA, ULONG TracksPerCylinder,
>                ULONG SectorsPerTrack)
> {
>    ULONG offset, cylinders, head, sector;
>
>    if (!cyl || !hd || !sec)
>       return -1;
>
>    cylinders = (LBA / (TracksPerCylinder * SectorsPerTrack));
>    offset = LBA % (TracksPerCylinder * SectorsPerTrack);
>    head = (WORD)(offset / SectorsPerTrack);
>    sector = (WORD)(offset % SectorsPerTrack) + 1;
>
>    if (cylinders < 1023)
>    {
>       *sec = (BYTE)sector;
>       *hd = (BYTE)head;
>       *cyl = (BYTE)(cylinders & 0xff);
>       *sec |= (BYTE)((cylinders >> 2) & 0xC0);
>    }
>    else
>    {
>    *sec = (BYTE)(SectorsPerTrack | 0xC0);
>    *hd = (BYTE)(TracksPerCylinder - 1);
>    *cyl = (BYTE)0xFE;
>    }
>
>    return 0;
> }
>
> ULONG SetPartitionTableValues(struct PartitionTableEntry *Part,
>                  ULONG Type,
>                  ULONG StartingLBA,
>                  ULONG EndingLBA,
>                  ULONG Flag,
>                  ULONG TracksPerCylinder,
>                  ULONG SectorsPerTrack)
> {
>
>    Part->SysFlag = (BYTE) Type;
>    Part->fBootable = (BYTE) Flag;
>    Part->StartLBA = StartingLBA;
>    Part->nSectorsTotal = (EndingLBA - StartingLBA) + 1;
>
>    SetPartitionTableGeometry(&Part->HeadStart, &Part->SecStart,
> &Part->CylStart,
>                  StartingLBA, TracksPerCylinder, SectorsPerTrack);
>
>    SetPartitionTableGeometry(&Part->HeadEnd, &Part->SecEnd, &Part->CylEnd,
>                  EndingLBA, TracksPerCylinder, SectorsPerTrack);
>
>    return 0;
>
> }
>
>
>
[SNIPPED...]

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.

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.

Cheers,
Dick Johnson
Penguin : Linux version 2.6.15.4 on an i686 machine (5589.53 BogoMips).
Warning : 98.36% of all statistics are fiction.
_
\x1a\x04

****************************************************************
The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  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
  1 sibling, 1 reply; 14+ messages in thread
From: Nick Warne @ 2006-02-17 20:24 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: Jeff V. Merkey, Linux kernel

 > 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.


If I am off the mark here, forgive me.

Since I moved exclusively to GNU/Linux 2 years ago, I notice when I
update kernel I get this:

nick@linuxamd:nick$ sudo /sbin/lilo -v
LILO version 22.5.9, Copyright (C) 1992-1998 Werner Almesberger
Development beyond version 21 Copyright (C) 1999-2004 John Coffman
Released 08-Apr-2004 and compiled at 00:18:50 on May 21 2004.

Warning: LBA32 addressing assumed
Reading boot sector from /dev/hda2
Warning: Kernel & BIOS return differing head/sector geometries for device 0x80
    Kernel: 65535 cylinders, 16 heads, 63 sectors
      BIOS: 1024 cylinders, 255 heads, 63 sectors
Warning: Kernel & BIOS return differing head/sector geometries for device 0x81
    Kernel: 29777 cylinders, 16 heads, 63 sectors
      BIOS: 1024 cylinders, 255 heads, 63 sectors

Now, from day one I never used the -v option with lilo, but as I get
more experienced (!) I do now and see the above... I have never
investigated due to worrying if I start messing with it I will trash
my disks - as I see all anyway on this disks (and no errors), all
works great/fast etc.

Is this what is going on here (re this thread?).

Nick

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
@ 2006-02-17 20:30 Seewer Philippe
  0 siblings, 0 replies; 14+ messages in thread
From: Seewer Philippe @ 2006-02-17 20:30 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: linux-kernel


<snip>

wow this is really great... but just for your information
on my ibm notebook the output is this:

        Disk parameter table(s) at vector 0x41
Disk0
    Cylinders = 1024
      Sectors = 63
        Heads = 240
Write precomp = 255
 Landing zone = 65296
        Reserved bit 0 set
        Reserved bit 1 set
        Reserved bit 2 set
        More than 8 heads
        Reserved bit 4 set
        Defect map present
        Disable retries
        Disable retries
Disk1
    Cylinders = 1024
      Sectors = 4
        Heads = 16
Write precomp = 0
 Landing zone = 0
        Disk parameter table(s) at vector 0x46
Disk0
    Cylinders = 34281
      Sectors = 240
        Heads = 230
Write precomp = 7950
 Landing zone = 61
        Reserved bit 2 set
        More than 8 heads
        Disable retries
Disk1
    Cylinders = 47631
      Sectors = 102
        Heads = 46
Write precomp = 3698
 Landing zone = 7952
        More than 8 heads
        Defect map present
        Disable retries


Just Note the "MAX" of 240 heads (very typical for IBM notebooks).

But anyway this tool is very useful for me. many, many thanks.



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-17 20:24     ` Nick Warne
@ 2006-02-17 20:39       ` linux-os (Dick Johnson)
  0 siblings, 0 replies; 14+ messages in thread
From: linux-os (Dick Johnson) @ 2006-02-17 20:39 UTC (permalink / raw)
  To: Nick Warne; +Cc: Jeff V. Merkey, Linux kernel


On Fri, 17 Feb 2006, Nick Warne wrote:

> > 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.
>
>
> If I am off the mark here, forgive me.
>
> Since I moved exclusively to GNU/Linux 2 years ago, I notice when I
> update kernel I get this:
>
> nick@linuxamd:nick$ sudo /sbin/lilo -v
> LILO version 22.5.9, Copyright (C) 1992-1998 Werner Almesberger
> Development beyond version 21 Copyright (C) 1999-2004 John Coffman
> Released 08-Apr-2004 and compiled at 00:18:50 on May 21 2004.
>
> Warning: LBA32 addressing assumed
> Reading boot sector from /dev/hda2
> Warning: Kernel & BIOS return differing head/sector geometries for device 0x80
>    Kernel: 65535 cylinders, 16 heads, 63 sectors
>      BIOS: 1024 cylinders, 255 heads, 63 sectors
> Warning: Kernel & BIOS return differing head/sector geometries for device 0x81
>    Kernel: 29777 cylinders, 16 heads, 63 sectors
>      BIOS: 1024 cylinders, 255 heads, 63 sectors
>
> Now, from day one I never used the -v option with lilo, but as I get
> more experienced (!) I do now and see the above... I have never
> investigated due to worrying if I start messing with it I will trash
> my disks - as I see all anyway on this disks (and no errors), all
> works great/fast etc.
>
> Is this what is going on here (re this thread?).
>
> Nick
>

Nothing to worry about. If you make lots of new kernels to
try them out, you might wish to use GRUB instead of LILO.

However, once the boot-process gets out of 16-bit mode, it
isn't going to use the 16-bit disk services so it doesn't
care about any of that stuff. C/H/S is just a "key" to get
you through the fact that the 16-bit BIOS puts some minimal
stuff in registers to access the disk.

Cheers,
Dick Johnson
Penguin : Linux version 2.6.15.4 on an i686 machine (5589.53 BogoMips).
Warning : 98.36% of all statistics are fiction.
_
\x1a\x04

****************************************************************
The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-17 20:04   ` linux-os (Dick Johnson)
  2006-02-17 20:24     ` Nick Warne
@ 2006-02-17 21:04     ` Phillip Susi
  2006-02-17 21:22       ` linux-os (Dick Johnson)
  2006-02-17 22:22       ` Jeff V. Merkey
  1 sibling, 2 replies; 14+ messages in thread
From: Phillip Susi @ 2006-02-17 21:04 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: Jeff V. Merkey, Linux kernel

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.



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  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-17 22:24         ` Jeff V. Merkey
  2006-02-17 22:22       ` Jeff V. Merkey
  1 sibling, 2 replies; 14+ messages in thread
From: linux-os (Dick Johnson) @ 2006-02-17 21:22 UTC (permalink / raw)
  To: Phillip Susi; +Cc: Jeff V. Merkey, Linux kernel


On Fri, 17 Feb 2006, 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.
   ^^^____

Who is YOU??? I would certainly be requesting the right sectors
if I (or anybody else who knows what they are doing), wrote
the boot code. The boot loader knows about OFFSETS into the
device where it's going to get its data, which eventually
becomes a whole operating system. It doesn't give a *uck about
anything else. There is a table of OFFSETS, obtained from
the file-system, of the correct pieces of files (since there
will not be a file-system until the machine is booted). This
table of offsets needs to be read somewhere in the first 63
sectors (32256 bytes). These offsets contain the junk to
be loaded into memory.

The boot-code, the code that executes in the 16-bit environment,
converts those offsets (after getting data from the DPB) into
the respective junk to put into the registers as I explained
over and over and over again.

You refuse to learn. Please go away.

[SNIPPED...]

Cheers,
Dick Johnson
Penguin : Linux version 2.6.15.4 on an i686 machine (5589.53 BogoMips).
Warning : 98.36% of all statistics are fiction.
_
\x1a\x04

****************************************************************
The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  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-17 22:24         ` Jeff V. Merkey
  1 sibling, 1 reply; 14+ messages in thread
From: Phillip Susi @ 2006-02-17 22:20 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: Jeff V. Merkey, Linux kernel

linux-os (Dick Johnson) wrote:
> Who is YOU??? I would certainly be requesting the right sectors
> if I (or anybody else who knows what they are doing), wrote
> the boot code. The boot loader knows about OFFSETS into the
> device where it's going to get its data, which eventually
> becomes a whole operating system. It doesn't give a *uck about
> anything else. There is a table of OFFSETS, obtained from
> the file-system, of the correct pieces of files (since there
> will not be a file-system until the machine is booted). This
> table of offsets needs to be read somewhere in the first 63
> sectors (32256 bytes). These offsets contain the junk to
> be loaded into memory.
> 

We weren't talking about a boot loader you would write, or lilo even, we 
were talking about windows's boot loader, which, to the best of my 
knowledge, directly passes the CHS address of the starting sector of the 
partition stored in the MBR to int 13.  That CHS address is calculated 
by fdisk based on the geometry it believes the disk has and is written 
to the MBR when you partition the disk.  The last time I checked a dos 
MBR, the boot code there didn't recompute the CHS address at runtime 
based on the LBA and current geometry according to the bios, so it has 
to be written correctly in the first place by fdisk, which requires that 
fdisk know the bios geometry.

> The boot-code, the code that executes in the 16-bit environment,
> converts those offsets (after getting data from the DPB) into
> the respective junk to put into the registers as I explained
> over and over and over again.

Maybe I'm just dense, but that's not what I heard you explaining.  Is it 
your position then, that the MS DOS/WIN MBR does actually recompute the 
CHS address at boot time based on the geometry the bios currently 
reports, and the LBA in the partition table, rather than use the CHS 
address stored in the partition table and precomputed by fdisk?

If that is the case, then fdisk can use whatever geometry it chooses and 
everything will be fine, so why does the kernel have to carry around 
some geometry instead of just letting fdisk make one up when it is run?

> 
> You refuse to learn. Please go away.
> 

That is uncalled for.  I don't understand why you have shown a bad 
attitude this whole time.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-17 21:04     ` Phillip Susi
  2006-02-17 21:22       ` linux-os (Dick Johnson)
@ 2006-02-17 22:22       ` Jeff V. Merkey
  1 sibling, 0 replies; 14+ messages in thread
From: Jeff V. Merkey @ 2006-02-17 22:22 UTC (permalink / raw)
  To: Phillip Susi; +Cc: linux-os (Dick Johnson), Linux kernel


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.
>
>
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-17 21:22       ` linux-os (Dick Johnson)
  2006-02-17 22:20         ` Phillip Susi
@ 2006-02-17 22:24         ` Jeff V. Merkey
  1 sibling, 0 replies; 14+ messages in thread
From: Jeff V. Merkey @ 2006-02-17 22:24 UTC (permalink / raw)
  To: linux-os (Dick Johnson); +Cc: Phillip Susi, Linux kernel



And a very useful translation table for coversion to 63 head models.

Jeff

// 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


linux-os (Dick Johnson) wrote:

>On Fri, 17 Feb 2006, 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.
>>    
>>
>   ^^^____
>
>Who is YOU??? I would certainly be requesting the right sectors
>if I (or anybody else who knows what they are doing), wrote
>the boot code. The boot loader knows about OFFSETS into the
>device where it's going to get its data, which eventually
>becomes a whole operating system. It doesn't give a *uck about
>anything else. There is a table of OFFSETS, obtained from
>the file-system, of the correct pieces of files (since there
>will not be a file-system until the machine is booted). This
>table of offsets needs to be read somewhere in the first 63
>sectors (32256 bytes). These offsets contain the junk to
>be loaded into memory.
>
>The boot-code, the code that executes in the 16-bit environment,
>converts those offsets (after getting data from the DPB) into
>the respective junk to put into the registers as I explained
>over and over and over again.
>
>You refuse to learn. Please go away.
>
>[SNIPPED...]
>
>Cheers,
>Dick Johnson
>Penguin : Linux version 2.6.15.4 on an i686 machine (5589.53 BogoMips).
>Warning : 98.36% of all statistics are fiction.
>_
>\x1a\x04
>
>****************************************************************
>The information transmitted in this message is confidential and may be privileged.  Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited.  If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@analogic.com - and destroy all copies of this information, including any attachments, without reading or disclosing them.
>
>Thank you.
>-
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at  http://www.tux.org/lkml/
>
>  
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-17 22:20         ` Phillip Susi
@ 2006-02-18  3:42           ` Marcin Dalecki
  2006-02-18 16:20             ` Phillip Susi
  0 siblings, 1 reply; 14+ messages in thread
From: Marcin Dalecki @ 2006-02-18  3:42 UTC (permalink / raw)
  To: Phillip Susi; +Cc: linux-os (Dick Johnson), Jeff V. Merkey, Linux kernel


On 2006-02-17, at 23:20, Phillip Susi wrote:
> If that is the case, then fdisk can use whatever geometry it  
> chooses and everything will be fine, so why does the kernel have to  
> carry around some geometry instead of just letting fdisk make one  
> up when it is run?

It has been already tried years ago to eliminate this ridicle. The  
answer to your
question is put bluntly: It's like that, because some kernel "prima  
ballerinas",
whose names "relate to alternating current", will get at you with  
mock up somke
and mirror woodo examples where it's supposed to be sooo required.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: C/H/S from user space
  2006-02-18  3:42           ` Marcin Dalecki
@ 2006-02-18 16:20             ` Phillip Susi
  0 siblings, 0 replies; 14+ messages in thread
From: Phillip Susi @ 2006-02-18 16:20 UTC (permalink / raw)
  To: Marcin Dalecki; +Cc: linux-os (Dick Johnson), Jeff V. Merkey, Linux kernel

Marcin Dalecki wrote:
> It has been already tried years ago to eliminate this ridicle. The 
> answer to your
> question is put bluntly: It's like that, because some kernel "prima 
> ballerinas",
> whose names "relate to alternating current", will get at you with mock 
> up somke
> and mirror woodo examples where it's supposed to be sooo required.

I myself have been trying to show why it is required.  Unless I am wrong 
about the msdos MBR code passing the CHS partition start values directly 
to int 13 rather than computing them based on the LBA in the MBR and the 
currently reported geometry from the bios, then fdisk does require the 
correct bios geometry to maintain compatibility with msdos/windows.


My original point was that if it is required ( and since it is still in 
the kernel, that seems to be the case ) then at least make sure it is 
_correct_.  Whether it is needed but wrong, or if it is simply not 
needed, then it is silly to keep geometry in the kernel.


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2006-02-18 16:21 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
  -- strict thread matches above, loose matches on Subject: below --
2006-02-17 20:30 Seewer Philippe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox