lkml.org 
[lkml]   [2006]   [Feb]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: C/H/S from user space

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

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

\
 
 \ /
  Last update: 2006-02-17 22:28    [W:0.230 / U:0.084 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site