2000-11-18 20:01:58

by Taisuke Yamada

[permalink] [raw]
Subject: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


Hi.

Earlier this month, I had sent in a patch to 2.2.18pre17 (with
IDE-patch from http://www.linux-ide.org/ applied) to add support
for IDE disk larger than 32GB, even if the disk required "clipping"
to reduce apparent disk size due to BIOS limitation.

BIOS known to have this limitation is Award 4.51 (and before) and
it seems many mainboards with not-so-great vendor support still use it.

Now I'm moving to 2.4-based system, and so ported the patch to
2.4-test10. It also applies cleanly to 2.4-test11.

With this patch, you will be able to use disk capacity above
32GB (or 2GB/8GB depending on how clipping take effect), and
still be able to boot off from the disk because you can leave
the "clipping" turned on.

>From my experience, this patch works with both software and
hardware clipping (or jumpering). This is probably because
hardware jumper works as a flag to the disk to enable software
clipping on hardware reset. But I'm not sure if this applies to
all disks.

By the way, is it safe for me to use IDE_*_OFFSET macro as a index
for IDE task command buffer? I couldn't use IDE_COMMAND_OFFSET (== 7),
and had to specify 0 because that's what ide_cmd function requires.

Anyway, here's the patch. Hope it works well on other systems...

--- cut here --- cut here --- cut here --- cut here --- cut here ---
--- linux/drivers/ide/ide-disk.c.orig Sun Nov 19 03:17:57 2000
+++ linux/drivers/ide/ide-disk.c Sun Nov 19 03:22:43 2000
@@ -514,23 +514,147 @@
}

/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+ int flag = (drive->id->command_set_1 & 0x0a) ? 1 : 0;
+ printk("%s: host protected area => %d\n", drive->name, flag);
+ return flag;
+}
+
+/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+ byte args[7];
+ unsigned long addr = 0;
+
+ printk("%s: checking for max native LBA...\n", drive->name);
+
+ /* Create IDE/ATA command request structure
+ *
+ * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
+ * here...For real ATA command structure, offset for IDE
+ * command is 7, but in IDE driver, it needs to be at 0th
+ * index (same goes for IDE status offset below). Hmm...
+ */
+ args[0] = 0xf8; /* READ_NATIVE_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = 0x00;
+ args[IDE_LCYL_OFFSET] = 0x00;
+ args[IDE_HCYL_OFFSET] = 0x00;
+ args[IDE_SELECT_OFFSET] = 0x40;
+
+ /* submit command request - if OK, read current max LBA value */
+ if (ide_wait_cmd_task(drive, args) == 0) {
+ if ((args[0] & 0x01) == 0) {
+ addr = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args[IDE_HCYL_OFFSET] ) << 16)
+ | ((args[IDE_LCYL_OFFSET] ) << 8)
+ | ((args[IDE_SECTOR_OFFSET] ));
+ }
+ }
+
+ printk("%s: max native LBA is %lu\n", drive->name, addr);
+
+ return addr;
+}
+
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive,
+ unsigned long addr_req)
+{
+ byte args[7];
+ unsigned long addr_set = 0;
+
+ printk("%s: (un)clipping max LBA...\n", drive->name);
+
+ /* Create IDE/ATA command request structure
+ *
+ * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
+ * here...For real ATA command structure, offset for IDE
+ * command is 7, but in IDE driver, it needs to be at 0th
+ * index (same goes for IDE status offset below). Hmm...
+ */
+ args[0] = 0xf9; /* SET_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = ((addr_req ) & 0xff);
+ args[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
+ args[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
+ args[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
+
+ /* submit command request - if OK, read new max LBA value */
+ if (ide_wait_cmd_task(drive, args) == 0) {
+ if ((args[0] & 0x01) == 0) {
+ addr_set = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args[IDE_HCYL_OFFSET] ) << 16)
+ | ((args[IDE_LCYL_OFFSET] ) << 8)
+ | ((args[IDE_SECTOR_OFFSET] ));
+ }
+ }
+
+ printk("%s: max LBA (un)clipped to %lu\n", drive->name, addr_set);
+
+ return addr_set;
+}
+
+/*
* Compute drive->capacity, the full capacity of the drive
* Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ * 1. CHS value set by user (whatever user sets will be trusted)
+ * 2. LBA value from target drive (require new ATA feature)
+ * 3. LBA value from system BIOS (new one is OK, old one may break)
+ * 4. CHS value from system BIOS (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * rest of the values are ignored).
*/
static void init_idedisk_capacity (ide_drive_t *drive)
{
+ unsigned long hd_max;
+ unsigned long hd_cap = drive->cyl * drive->head * drive->sect;
+ int is_lba = 0;
+
struct hd_driveid *id = drive->id;
- unsigned long capacity = drive->cyl * drive->head * drive->sect;

- drive->select.b.lba = 0;
+ /* Unless geometry is given by user, use autodetected value */
+ if (! drive->forced_geom) {
+ /* If BIOS LBA geometry is available, use it */
+ if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+ hd_cap = id->lba_capacity;
+ is_lba = 1;
+ }

- /* Determine capacity, and use LBA if the drive properly supports it */
- if ((id->capability & 2) && lba_capacity_is_ok(id)) {
- capacity = id->lba_capacity;
- drive->cyl = capacity / (drive->head * drive->sect);
- drive->select.b.lba = 1;
+ /* If new ATA feature is supported, try using it */
+ if (idedisk_supports_host_protected_area(drive)) {
+ hd_max = idedisk_read_native_max_address(drive);
+ hd_max = idedisk_set_max_address(drive, hd_max);
+
+ if (hd_max > 0) {
+ hd_cap = hd_max;
+ is_lba = 1;
+ }
+ }
}
- drive->capacity = capacity;
+
+ printk("%s: lba = %d, cap = %lu\n", drive->name, is_lba, hd_cap);
+
+ /* update parameters with fetched results */
+ drive->select.b.lba = is_lba;
+ drive->capacity = hd_cap;
+ drive->cyl = hd_cap / (drive->head * drive->sect);
}

static unsigned long idedisk_capacity (ide_drive_t *drive)
--- cut here --- cut here --- cut here --- cut here --- cut here ---

--
Taisuke Yamada <[email protected]>
PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46


2000-11-18 20:36:14

by Andre Hedrick

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

Taisuke,

After some changes in the code to conform to the near final taskfile
solution, it is called CONFIG_IDEDISK_STROKE.

It is in the latest patch for 2.2.17 published on kernel.org but I forgot
to remove a blocking stub in ide-disk.c

Please try it and comment offline for now.

Cheers,

On Sun, 19 Nov 2000, Taisuke Yamada wrote:

>
> Hi.
>
> Earlier this month, I had sent in a patch to 2.2.18pre17 (with
> IDE-patch from http://www.linux-ide.org/ applied) to add support
> for IDE disk larger than 32GB, even if the disk required "clipping"
> to reduce apparent disk size due to BIOS limitation.
>
> BIOS known to have this limitation is Award 4.51 (and before) and
> it seems many mainboards with not-so-great vendor support still use it.
>
> Now I'm moving to 2.4-based system, and so ported the patch to
> 2.4-test10. It also applies cleanly to 2.4-test11.
>
> With this patch, you will be able to use disk capacity above
> 32GB (or 2GB/8GB depending on how clipping take effect), and
> still be able to boot off from the disk because you can leave
> the "clipping" turned on.
>
> >From my experience, this patch works with both software and
> hardware clipping (or jumpering). This is probably because
> hardware jumper works as a flag to the disk to enable software
> clipping on hardware reset. But I'm not sure if this applies to
> all disks.
>
> By the way, is it safe for me to use IDE_*_OFFSET macro as a index
> for IDE task command buffer? I couldn't use IDE_COMMAND_OFFSET (== 7),
> and had to specify 0 because that's what ide_cmd function requires.
>
> Anyway, here's the patch. Hope it works well on other systems...
>
> --- cut here --- cut here --- cut here --- cut here --- cut here ---
> --- linux/drivers/ide/ide-disk.c.orig Sun Nov 19 03:17:57 2000
> +++ linux/drivers/ide/ide-disk.c Sun Nov 19 03:22:43 2000
> @@ -514,23 +514,147 @@
> }
>
> /*
> + * Tests if the drive supports Host Protected Area feature.
> + * Returns true if supported, false otherwise.
> + */
> +static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
> +{
> + int flag = (drive->id->command_set_1 & 0x0a) ? 1 : 0;
> + printk("%s: host protected area => %d\n", drive->name, flag);
> + return flag;
> +}
> +
> +/*
> + * Queries for true maximum capacity of the drive.
> + * Returns maximum LBA address (> 0) of the drive, 0 if failed.
> + */
> +static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
> +{
> + byte args[7];
> + unsigned long addr = 0;
> +
> + printk("%s: checking for max native LBA...\n", drive->name);
> +
> + /* Create IDE/ATA command request structure
> + *
> + * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
> + * here...For real ATA command structure, offset for IDE
> + * command is 7, but in IDE driver, it needs to be at 0th
> + * index (same goes for IDE status offset below). Hmm...
> + */
> + args[0] = 0xf8; /* READ_NATIVE_MAX - see ATA spec */
> + args[IDE_FEATURE_OFFSET] = 0x00;
> + args[IDE_NSECTOR_OFFSET] = 0x00;
> + args[IDE_SECTOR_OFFSET] = 0x00;
> + args[IDE_LCYL_OFFSET] = 0x00;
> + args[IDE_HCYL_OFFSET] = 0x00;
> + args[IDE_SELECT_OFFSET] = 0x40;
> +
> + /* submit command request - if OK, read current max LBA value */
> + if (ide_wait_cmd_task(drive, args) == 0) {
> + if ((args[0] & 0x01) == 0) {
> + addr = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
> + | ((args[IDE_HCYL_OFFSET] ) << 16)
> + | ((args[IDE_LCYL_OFFSET] ) << 8)
> + | ((args[IDE_SECTOR_OFFSET] ));
> + }
> + }
> +
> + printk("%s: max native LBA is %lu\n", drive->name, addr);
> +
> + return addr;
> +}
> +
> +/*
> + * Sets maximum virtual LBA address of the drive.
> + * Returns new maximum virtual LBA address (> 0) or 0 on failure.
> + */
> +static unsigned long idedisk_set_max_address(ide_drive_t *drive,
> + unsigned long addr_req)
> +{
> + byte args[7];
> + unsigned long addr_set = 0;
> +
> + printk("%s: (un)clipping max LBA...\n", drive->name);
> +
> + /* Create IDE/ATA command request structure
> + *
> + * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
> + * here...For real ATA command structure, offset for IDE
> + * command is 7, but in IDE driver, it needs to be at 0th
> + * index (same goes for IDE status offset below). Hmm...
> + */
> + args[0] = 0xf9; /* SET_MAX - see ATA spec */
> + args[IDE_FEATURE_OFFSET] = 0x00;
> + args[IDE_NSECTOR_OFFSET] = 0x00;
> + args[IDE_SECTOR_OFFSET] = ((addr_req ) & 0xff);
> + args[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
> + args[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
> + args[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
> +
> + /* submit command request - if OK, read new max LBA value */
> + if (ide_wait_cmd_task(drive, args) == 0) {
> + if ((args[0] & 0x01) == 0) {
> + addr_set = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
> + | ((args[IDE_HCYL_OFFSET] ) << 16)
> + | ((args[IDE_LCYL_OFFSET] ) << 8)
> + | ((args[IDE_SECTOR_OFFSET] ));
> + }
> + }
> +
> + printk("%s: max LBA (un)clipped to %lu\n", drive->name, addr_set);
> +
> + return addr_set;
> +}
> +
> +/*
> * Compute drive->capacity, the full capacity of the drive
> * Called with drive->id != NULL.
> + *
> + * To compute capacity, this uses either of
> + *
> + * 1. CHS value set by user (whatever user sets will be trusted)
> + * 2. LBA value from target drive (require new ATA feature)
> + * 3. LBA value from system BIOS (new one is OK, old one may break)
> + * 4. CHS value from system BIOS (traditional style)
> + *
> + * in above order (i.e., if value of higher priority is available,
> + * rest of the values are ignored).
> */
> static void init_idedisk_capacity (ide_drive_t *drive)
> {
> + unsigned long hd_max;
> + unsigned long hd_cap = drive->cyl * drive->head * drive->sect;
> + int is_lba = 0;
> +
> struct hd_driveid *id = drive->id;
> - unsigned long capacity = drive->cyl * drive->head * drive->sect;
>
> - drive->select.b.lba = 0;
> + /* Unless geometry is given by user, use autodetected value */
> + if (! drive->forced_geom) {
> + /* If BIOS LBA geometry is available, use it */
> + if ((id->capability & 2) && lba_capacity_is_ok(id)) {
> + hd_cap = id->lba_capacity;
> + is_lba = 1;
> + }
>
> - /* Determine capacity, and use LBA if the drive properly supports it */
> - if ((id->capability & 2) && lba_capacity_is_ok(id)) {
> - capacity = id->lba_capacity;
> - drive->cyl = capacity / (drive->head * drive->sect);
> - drive->select.b.lba = 1;
> + /* If new ATA feature is supported, try using it */
> + if (idedisk_supports_host_protected_area(drive)) {
> + hd_max = idedisk_read_native_max_address(drive);
> + hd_max = idedisk_set_max_address(drive, hd_max);
> +
> + if (hd_max > 0) {
> + hd_cap = hd_max;
> + is_lba = 1;
> + }
> + }
> }
> - drive->capacity = capacity;
> +
> + printk("%s: lba = %d, cap = %lu\n", drive->name, is_lba, hd_cap);
> +
> + /* update parameters with fetched results */
> + drive->select.b.lba = is_lba;
> + drive->capacity = hd_cap;
> + drive->cyl = hd_cap / (drive->head * drive->sect);
> }
>
> static unsigned long idedisk_capacity (ide_drive_t *drive)
> --- cut here --- cut here --- cut here --- cut here --- cut here ---
>
> --
> Taisuke Yamada <[email protected]>
> PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> Please read the FAQ at http://www.tux.org/lkml/
>

Andre Hedrick
CTO Timpanogas Research Group
EVP Linux Development, TRG
Linux ATA Development

2000-11-19 17:15:36

by Dan Aloni

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

On Sun, 19 Nov 2000, Taisuke Yamada wrote:

> Earlier this month, I had sent in a patch to 2.2.18pre17 (with
> IDE-patch from http://www.linux-ide.org/ applied) to add support
> for IDE disk larger than 32GB, even if the disk required "clipping"
> to reduce apparent disk size due to BIOS limitation.
>
> [...] patch

This patch is not good. It compiles, but when I boot the kernel, it
decides to ignore the hdc=5606,255,63 parameter that I pass to the kernel,
and limits the number of sectors to fill 8.4GB.

(from dmesg:)

hdc: lba = 0, cap = 16514064
hdc: 16514064 sectors (8455 MB) w/1916KiB Cache, CHS=5606/255/63, UDMA(33)

Notes:
* Notice the contradiction between 16414064 sectors and 5606/255/63
geometry, something is definitly wrong there.
* I *didn't* change the jumper settings to 'clipping' mode, only the
kernel was modified in this test.
* When I try to read (using dd) from somewhere above the 40GB offset in
the drive, no success. I guess if I tried to read pass 8.4GB it
wouldn't have yield success either.
* In this test, the code in the patch doesn't printk() anything except
that 'hdc: lba = 0, cap = 16514064' line.
* Normally, without the patch I get:

hdc: 90069840 sectors (46116 MB) w/1916KiB Cache, CHS=5606/255/63,
UDMA(33)

And then there's no problem reading any offset on the drive.

* I really need this sort of patch, tired of booting the computer from a
floppy...
* The patch didn't want to apply for some reason, so I had to apply the
patch manually (to test11-pre7).

Here is the version of patch that does apply: (please release an
updated patch)

--- linux/drivers/ide/ide-disk.c Sun Nov 19 17:15:56 2000
+++ linux/drivers/ide/ide-disk.c Sun Nov 19 17:27:31 2000
@@ -513,24 +513,149 @@
current_capacity(drive));
}

+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+ int flag = (drive->id->command_set_1 & 0x0a) ? 1 : 0;
+ printk("%s: host protected area => %d\n", drive->name, flag);
+ return flag;
+}
+
+/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+ byte args[7];
+ unsigned long addr = 0;
+
+ printk("%s: checking for max native LBA...\n", drive->name);
+
+ /* Create IDE/ATA command request structure
+ *
+ * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
+ * here...For real ATA command structure, offset for IDE
+ * command is 7, but in IDE driver, it needs to be at 0th
+ * index (same goes for IDE status offset below). Hmm...
+ */
+ args[0] = 0xf8; /* READ_NATIVE_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = 0x00;
+ args[IDE_LCYL_OFFSET] = 0x00;
+ args[IDE_HCYL_OFFSET] = 0x00;
+ args[IDE_SELECT_OFFSET] = 0x40;
+
+ /* submit command request - if OK, read current max LBA value */
+ if (ide_wait_cmd_task(drive, args) == 0) {
+ if ((args[0] & 0x01) == 0) {
+ addr = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args[IDE_HCYL_OFFSET] ) << 16)
+ | ((args[IDE_LCYL_OFFSET] ) << 8)
+ | ((args[IDE_SECTOR_OFFSET] ));
+ }
+ }
+
+ printk("%s: max native LBA is %lu\n", drive->name, addr);
+
+ return addr;
+}
+
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive,
+ unsigned long addr_req)
+{
+ byte args[7];
+ unsigned long addr_set = 0;
+
+ printk("%s: (un)clipping max LBA...\n", drive->name);
+
+ /* Create IDE/ATA command request structure
+ *
+ * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
+ * here...For real ATA command structure, offset for IDE
+ * command is 7, but in IDE driver, it needs to be at 0th
+ * index (same goes for IDE status offset below). Hmm...
+ */
+ args[0] = 0xf9; /* SET_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = ((addr_req ) & 0xff);
+ args[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
+ args[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
+ args[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
+
+ /* submit command request - if OK, read new max LBA value */
+ if (ide_wait_cmd_task(drive, args) == 0) {
+ if ((args[0] & 0x01) == 0) {
+ addr_set = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args[IDE_HCYL_OFFSET] ) << 16)
+ | ((args[IDE_LCYL_OFFSET] ) << 8)
+ | ((args[IDE_SECTOR_OFFSET] ));
+ }
+ }
+
+ printk("%s: max LBA (un)clipped to %lu\n", drive->name, addr_set);
+
+ return addr_set;
+}
+
/*
* Compute drive->capacity, the full capacity of the drive
* Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ * 1. CHS value set by user (whatever user sets will be trusted)
+ * 2. LBA value from target drive (require new ATA feature)
+ * 3. LBA value from system BIOS (new one is OK, old one may break)
+ * 4. CHS value from system BIOS (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * rest of the values are ignored).
*/
static void init_idedisk_capacity (ide_drive_t *drive)
{
+ unsigned long hd_max;
+ unsigned long hd_cap = drive->cyl * drive->head * drive->sect;
+ int is_lba = 0;
+
struct hd_driveid *id = drive->id;
- unsigned long capacity = drive->cyl * drive->head * drive->sect;

- drive->select.b.lba = 0;
+ /* Unless geometry is given by user, use autodetected value */
+ if (! drive->forced_geom) {
+ /* If BIOS LBA geometry is available, use it */
+ if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+ hd_cap = id->lba_capacity;
+ is_lba = 1;
+ }

- /* Determine capacity, and use LBA if the drive properly supports it */
- if ((id->capability & 2) && lba_capacity_is_ok(id)) {
- capacity = id->lba_capacity;
- drive->cyl = capacity / (drive->head * drive->sect);
- drive->select.b.lba = 1;
+ /* If new ATA feature is supported, try using it */
+ if (idedisk_supports_host_protected_area(drive)) {
+ hd_max = idedisk_read_native_max_address(drive);
+ hd_max = idedisk_set_max_address(drive, hd_max);
+
+ if (hd_max > 0) {
+ hd_cap = hd_max;
+ is_lba = 1;
+ }
+ }
}
- drive->capacity = capacity;
+
+ printk("%s: lba = %d, cap = %lu\n", drive->name, is_lba, hd_cap);
+
+ /* update parameters with fetched results */
+ drive->select.b.lba = is_lba;
+ drive->capacity = hd_cap;
+ drive->cyl = hd_cap / (drive->head * drive->sect);
}

static unsigned long idedisk_capacity (ide_drive_t *drive)


--
Dan Aloni
[email protected]

2000-11-19 17:22:17

by Andre Hedrick

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


The original was good, but the changes made to do the callout fail to
return structs that need to be filled. This is my fault.

On Sun, 19 Nov 2000, Dan Aloni wrote:

> On Sun, 19 Nov 2000, Taisuke Yamada wrote:
>
> > Earlier this month, I had sent in a patch to 2.2.18pre17 (with
> > IDE-patch from http://www.linux-ide.org/ applied) to add support
> > for IDE disk larger than 32GB, even if the disk required "clipping"
> > to reduce apparent disk size due to BIOS limitation.
> >
> > [...] patch
>
> This patch is not good. It compiles, but when I boot the kernel, it
> decides to ignore the hdc=5606,255,63 parameter that I pass to the kernel,
> and limits the number of sectors to fill 8.4GB.
>
> (from dmesg:)
>
> hdc: lba = 0, cap = 16514064
> hdc: 16514064 sectors (8455 MB) w/1916KiB Cache, CHS=5606/255/63, UDMA(33)
>
> Notes:
> * Notice the contradiction between 16414064 sectors and 5606/255/63
> geometry, something is definitly wrong there.
> * I *didn't* change the jumper settings to 'clipping' mode, only the
> kernel was modified in this test.
> * When I try to read (using dd) from somewhere above the 40GB offset in
> the drive, no success. I guess if I tried to read pass 8.4GB it
> wouldn't have yield success either.
> * In this test, the code in the patch doesn't printk() anything except
> that 'hdc: lba = 0, cap = 16514064' line.
> * Normally, without the patch I get:
>
> hdc: 90069840 sectors (46116 MB) w/1916KiB Cache, CHS=5606/255/63,
> UDMA(33)
>
> And then there's no problem reading any offset on the drive.
>
> * I really need this sort of patch, tired of booting the computer from a
> floppy...
> * The patch didn't want to apply for some reason, so I had to apply the
> patch manually (to test11-pre7).
>
> Here is the version of patch that does apply: (please release an
> updated patch)
>
> --- linux/drivers/ide/ide-disk.c Sun Nov 19 17:15:56 2000
> +++ linux/drivers/ide/ide-disk.c Sun Nov 19 17:27:31 2000
> @@ -513,24 +513,149 @@
> current_capacity(drive));
> }
>
> +
> +/*
> + * Tests if the drive supports Host Protected Area feature.
> + * Returns true if supported, false otherwise.
> + */
> +static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
> +{
> + int flag = (drive->id->command_set_1 & 0x0a) ? 1 : 0;
> + printk("%s: host protected area => %d\n", drive->name, flag);
> + return flag;
> +}
> +
> +/*
> + * Queries for true maximum capacity of the drive.
> + * Returns maximum LBA address (> 0) of the drive, 0 if failed.
> + */
> +static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
> +{
> + byte args[7];
> + unsigned long addr = 0;
> +
> + printk("%s: checking for max native LBA...\n", drive->name);
> +
> + /* Create IDE/ATA command request structure
> + *
> + * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
> + * here...For real ATA command structure, offset for IDE
> + * command is 7, but in IDE driver, it needs to be at 0th
> + * index (same goes for IDE status offset below). Hmm...
> + */
> + args[0] = 0xf8; /* READ_NATIVE_MAX - see ATA spec */
> + args[IDE_FEATURE_OFFSET] = 0x00;
> + args[IDE_NSECTOR_OFFSET] = 0x00;
> + args[IDE_SECTOR_OFFSET] = 0x00;
> + args[IDE_LCYL_OFFSET] = 0x00;
> + args[IDE_HCYL_OFFSET] = 0x00;
> + args[IDE_SELECT_OFFSET] = 0x40;
> +
> + /* submit command request - if OK, read current max LBA value */
> + if (ide_wait_cmd_task(drive, args) == 0) {
> + if ((args[0] & 0x01) == 0) {
> + addr = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
> + | ((args[IDE_HCYL_OFFSET] ) << 16)
> + | ((args[IDE_LCYL_OFFSET] ) << 8)
> + | ((args[IDE_SECTOR_OFFSET] ));
> + }
> + }
> +
> + printk("%s: max native LBA is %lu\n", drive->name, addr);
> +
> + return addr;
> +}
> +
> +/*
> + * Sets maximum virtual LBA address of the drive.
> + * Returns new maximum virtual LBA address (> 0) or 0 on failure.
> + */
> +static unsigned long idedisk_set_max_address(ide_drive_t *drive,
> + unsigned long addr_req)
> +{
> + byte args[7];
> + unsigned long addr_set = 0;
> +
> + printk("%s: (un)clipping max LBA...\n", drive->name);
> +
> + /* Create IDE/ATA command request structure
> + *
> + * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
> + * here...For real ATA command structure, offset for IDE
> + * command is 7, but in IDE driver, it needs to be at 0th
> + * index (same goes for IDE status offset below). Hmm...
> + */
> + args[0] = 0xf9; /* SET_MAX - see ATA spec */
> + args[IDE_FEATURE_OFFSET] = 0x00;
> + args[IDE_NSECTOR_OFFSET] = 0x00;
> + args[IDE_SECTOR_OFFSET] = ((addr_req ) & 0xff);
> + args[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
> + args[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
> + args[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
> +
> + /* submit command request - if OK, read new max LBA value */
> + if (ide_wait_cmd_task(drive, args) == 0) {
> + if ((args[0] & 0x01) == 0) {
> + addr_set = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
> + | ((args[IDE_HCYL_OFFSET] ) << 16)
> + | ((args[IDE_LCYL_OFFSET] ) << 8)
> + | ((args[IDE_SECTOR_OFFSET] ));
> + }
> + }
> +
> + printk("%s: max LBA (un)clipped to %lu\n", drive->name, addr_set);
> +
> + return addr_set;
> +}
> +
> /*
> * Compute drive->capacity, the full capacity of the drive
> * Called with drive->id != NULL.
> + *
> + * To compute capacity, this uses either of
> + *
> + * 1. CHS value set by user (whatever user sets will be trusted)
> + * 2. LBA value from target drive (require new ATA feature)
> + * 3. LBA value from system BIOS (new one is OK, old one may break)
> + * 4. CHS value from system BIOS (traditional style)
> + *
> + * in above order (i.e., if value of higher priority is available,
> + * rest of the values are ignored).
> */
> static void init_idedisk_capacity (ide_drive_t *drive)
> {
> + unsigned long hd_max;
> + unsigned long hd_cap = drive->cyl * drive->head * drive->sect;
> + int is_lba = 0;
> +
> struct hd_driveid *id = drive->id;
> - unsigned long capacity = drive->cyl * drive->head * drive->sect;
>
> - drive->select.b.lba = 0;
> + /* Unless geometry is given by user, use autodetected value */
> + if (! drive->forced_geom) {
> + /* If BIOS LBA geometry is available, use it */
> + if ((id->capability & 2) && lba_capacity_is_ok(id)) {
> + hd_cap = id->lba_capacity;
> + is_lba = 1;
> + }
>
> - /* Determine capacity, and use LBA if the drive properly supports it */
> - if ((id->capability & 2) && lba_capacity_is_ok(id)) {
> - capacity = id->lba_capacity;
> - drive->cyl = capacity / (drive->head * drive->sect);
> - drive->select.b.lba = 1;
> + /* If new ATA feature is supported, try using it */
> + if (idedisk_supports_host_protected_area(drive)) {
> + hd_max = idedisk_read_native_max_address(drive);
> + hd_max = idedisk_set_max_address(drive, hd_max);
> +
> + if (hd_max > 0) {
> + hd_cap = hd_max;
> + is_lba = 1;
> + }
> + }
> }
> - drive->capacity = capacity;
> +
> + printk("%s: lba = %d, cap = %lu\n", drive->name, is_lba, hd_cap);
> +
> + /* update parameters with fetched results */
> + drive->select.b.lba = is_lba;
> + drive->capacity = hd_cap;
> + drive->cyl = hd_cap / (drive->head * drive->sect);
> }
>
> static unsigned long idedisk_capacity (ide_drive_t *drive)
>
>
> --
> Dan Aloni
> [email protected]
>

Andre Hedrick
CTO Timpanogas Research Group
EVP Linux Development, TRG
Linux ATA Development

2000-11-19 17:54:54

by Andries Brouwer

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

On Sun, Nov 19, 2000 at 04:30:34AM +0900, Taisuke Yamada wrote:

> Earlier this month, I had sent in a patch to 2.2.18pre17 (with
> IDE-patch from http://www.linux-ide.org/ applied) to add support
> for IDE disk larger than 32GB, even if the disk required "clipping"
> to reduce apparent disk size due to BIOS limitation.
>
> BIOS known to have this limitation is Award 4.51 (and before) and
> it seems many mainboards with not-so-great vendor support still use it.
>
> Now I'm moving to 2.4-based system, and so ported the patch to
> 2.4-test10. It also applies cleanly to 2.4-test11.
>
> With this patch, you will be able to use disk capacity above
> 32GB (or 2GB/8GB depending on how clipping take effect), and
> still be able to boot off from the disk because you can leave
> the "clipping" turned on.

Hi Taisuke,

I suppose you know that no kernel patch is required
(since setmax.c does the same from user space).
Did you try setmax?
I would like to see the results - am still in the information
gathering stage - I have two largish Maxtor disks myself, one
40 GB and one 60 GB, and their behaviour is different, so
to me it seems a bit too early to come with kernel patches.

I think I already sent you setmax.c, but in case my memory
is confused let me include it here again. This is for 2.4.

Andries

-----
/* setmax.c - aeb, 000326 */
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/hdreg.h>

#ifndef HDIO_DRIVE_CMD_AEB
#define HDIO_DRIVE_CMD_AEB 0x031e
#endif

#define INITIALIZE_DRIVE_PARAMETERS 0x91
#define READ_NATIVE_MAX_ADDRESS 0xf8
#define CHECK_POWER_MODE 0xe5
#define SET_MAX 0xf9

#define LBA 0x40
#define VV 1 /* if set in sectorct then NOT volatile */

struct idecmdin {
unsigned char cmd;
unsigned char feature;
unsigned char nsect;
unsigned char sect, lcyl, hcyl;
unsigned char select;
};

struct idecmdout {
unsigned char status;
unsigned char error;
unsigned char nsect;
unsigned char sect, lcyl, hcyl;
unsigned char select;
};

unsigned int
tolba(unsigned char *args) {
return ((args[6] & 0xf) << 24) + (args[5] << 16) + (args[4] << 8) + args[3];
}

void
fromlba(unsigned char *args, unsigned int lba) {
args[3] = (lba & 0xff);
lba >>= 8;
args[4] = (lba & 0xff);
lba >>= 8;
args[5] = (lba & 0xff);
lba >>= 8;
args[6] = (args[6] & 0xf0) | (lba & 0xf);
}

int
get_identity(int fd) {
unsigned char args[4+512] = {WIN_IDENTIFY,0,0,1,};
struct hd_driveid *id = (struct hd_driveid *)&args[4];

if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
perror("HDIO_DRIVE_CMD");
fprintf(stderr,
"WIN_IDENTIFY failed - trying WIN_PIDENTIFY\n");
args[0] = WIN_PIDENTIFY;
if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
perror("HDIO_DRIVE_CMD");
fprintf(stderr,
"WIN_PIDENTIFY also failed - giving up\n");
exit(1);
}
}

printf("lba capacity: %d sectors (%lld bytes)\n",
id->lba_capacity,
(long long) id->lba_capacity * 512);
}

/*
* result: in LBA mode precisely what is expected
* in CHS mode the correct H and S, and C mod 65536.
*/
unsigned int
get_native_max(int fd, int slave) {
unsigned char args[7];
int i, max;

for (i=0; i<7; i++)
args[i] = 0;
args[0] = READ_NATIVE_MAX_ADDRESS;
args[6] = (slave ? 0x10 : 0) | LBA;
if (ioctl(fd, HDIO_DRIVE_CMD_AEB, &args)) {
perror("HDIO_DRIVE_CMD_AEB failed READ_NATIVE_MAX_ADDRESS");
for (i=0; i<7; i++)
printf("%d = 0x%x\n", args[i], args[i]);
exit(1);
}
return tolba(args);
}

/*
* SET_MAX_ADDRESS requires immediately preceding READ_NATIVE_MAX_ADDRESS
*
* Results: this fails for delta <= 254, succeeds for delta >= 255.
* So, in order to get the last 255*512=130560 bytes back one has to reboot.
* Side effect: reset to CurCHS=16383/16/63, CurSects=16514064.
*/
void
set_max_address(int fd, int slave, int delta) {
unsigned char args[7];
int i, nativemax;

nativemax = get_native_max(fd, slave);
printf("nativemax=%d (0x%x)\n", nativemax, nativemax);

for (i=0; i<7; i++)
args[i] = 0;
args[0] = SET_MAX;
args[1] = 0;
fromlba(args, nativemax-delta);
args[6] |= LBA;

if (ioctl(fd, HDIO_DRIVE_CMD_AEB, &args)) {
perror("HDIO_DRIVE_CMD_AEB failed SET_MAX");
for (i=0; i<7; i++)
printf("%d = 0x%x\n", args[i], args[i]);
exit(1);
}
}

static char short_opts[] = "d:";
static const struct option long_opts[] = {
{ "delta", required_argument, NULL, 'd' },
{ NULL, 0, NULL, 0 }
};

static char *usage_txt =
"Call: setmax [-d D] DEVICE\n"
"\n"
"The call \"setmax --delta D DEVICE\" will do a SET_MAX command\n"
"to set the maximum accessible sector number D sectors\n"
"below end-of-disk.\n"
"\n"
"The call \"setmax DEVICE\" will do a READ_NATIVE_MAX_ADDRESS\n"
"command, and report the maximum accessible sector number.\n"
"\n"
"This is IDE-only. Probably DEVICE is /dev/hdx for some x.\n\n";

main(int argc, char **argv){
int fd, c;
int delta;

/* If you modify device, also update slave, if necessary. */
/* master: hda, hdc, hde; slave: hdb, hdd, hdf */
char *device = NULL; /* e.g. "/dev/hda" */
int slave = 0;

delta = -1;
while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) {
switch(c) {
case 'd':
delta = atoi(optarg);
break;
case '?':
default:
fprintf(stderr, "unknown option\n");
fprintf(stderr, usage_txt);
exit(1);
}
}

if (optind < argc)
device = argv[optind];
if (!device) {
fprintf(stderr, "no device specified - "
"use e.g. \"setmax /dev/hdb\"\n");
fprintf(stderr, usage_txt);
exit(1);
}
printf("Using device %s\n", device);

fd = open(device, O_RDONLY);
if (fd == -1) {
perror("open");
exit(1);
}

if (delta != -1) {
printf("setting delta=%d\n", delta);
set_max_address(fd, slave, delta);
} else {
int mad = get_native_max(fd, slave);
long long bytes = (long long) (mad+1) * 512;
int hMB = (bytes+50000000)/100000000;

printf("native max address: %d\n", mad);
printf("that is %lld bytes, %d.%d GB\n",
bytes, hMB/10, hMB%10);
}
get_identity(fd);

return 0;
}

/* READ_NATIVE_MAX_ADDRESS:
Inputs:
features, sectorct, sectornr, cyllow, cylhi: NA
device/head: 8 bits: obs LBA obs DEV na na na na
command: F8
Outputs:
error: 8 bits: na na na na na ABRT na na
sectorct: NA
sectornr, cyllo, cylhi: native max address
device/head: 8 bits: obs na obs DEV; 4bits native max address
status: BSY DRDY DF na DRQ na na ERR [010x0xx0]

SET_MAX_ADDRESS (obsolete?):
Error: ABRT=4: command not supported, max requested exceeds
device capacity, CYL > 16383, command not preceded by
READ_NATIVE_MAX_ADDRESS.
Also error if the device is in Set_Max_Locked or Set_Max_Frozen state.
*/

2000-11-19 22:45:11

by Taisuke Yamada

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using oldBIOS


> > Earlier this month, I had sent in a patch to 2.2.18pre17 (with
> > IDE-patch from http://www.linux-ide.org/ applied) to add support
> > for IDE disk larger than 32GB, even if the disk required "clipping"
> > to reduce apparent disk size due to BIOS limitation.
>
> This patch is not good. It compiles, but when I boot the kernel, it
> decides to ignore the hdc=5606,255,63 parameter that I pass to the kernel,
> and limits the number of sectors to fill 8.4GB.

Please retest with hdc=... parameter removed. If hd[a-z]=...
parameter is specified, my patch will be disabled, trusting
whatever user has specified.

Here's a example output of what you should expect if the patched
part is being executed:

hda: host protected area => 1
hda: checking for max native LBA...
hda: max native LBA is 90045647
hda: (un)clipping max LBA...
hda: max LBA (un)clipped to 90045647
hda: lba = 1, cap = 90045647
hda: 90045647 sectors (46103 MB) w/2048KiB Cache, CHS=89330/16/63, UDMA(33)
hdc: host protected area => 1
hdc: checking for max native LBA...
hdc: max native LBA is 90045647
hdc: (un)clipping max LBA...
hdc: max LBA (un)clipped to 90045647
hdc: lba = 1, cap = 90045647
hdc: 90045647 sectors (46103 MB) w/2048KiB Cache, CHS=89330/16/63, UDMA(33)

> /*
> * Compute drive->capacity, the full capacity of the drive
> * Called with drive->id != NULL.
> + *
> + * To compute capacity, this uses either of
> + *
> + * 1. CHS value set by user (whatever user sets will be trusted)
> + * 2. LBA value from target drive (require new ATA feature)
> + * 3. LBA value from system BIOS (new one is OK, old one may break)
> + * 4. CHS value from system BIOS (traditional style)
> + *
> + * in above order (i.e., if value of higher priority is available,
> + * rest of the values are ignored).
> */

--
Taisuke Yamada <[email protected]>
PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46

2000-11-19 23:01:07

by Taisuke Yamada

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


> > With this patch, you will be able to use disk capacity above
> > 32GB (or 2GB/8GB depending on how clipping take effect), and
> > still be able to boot off from the disk because you can leave
> > the "clipping" turned on.
>
> I suppose you know that no kernel patch is required (since
> setmax.c does the same from user space). Did you try setmax?

I know of its existence, but thought patch solution is better
than userland solution and made one. Unless it is included in
the kernel, it's going to cause trouble on every system with
old BIOS. After all, disk geometry detection is what the kernel
should do, not userland program.

> to me it seems a bit too early to come with kernel patches.

But yes, you have the point here. This still needs more testing
to see if it works with every 32GB+ drive. By the way, how did
your drives behave? I have tested my code with IBM and Maxtor,
and both supported this READ NATIVE MAX - SET MAX combination
without any problem.

> I think I already sent you setmax.c, but in case my memory
> is confused let me include it here again. This is for 2.4.

Actually, this is the first time to have setmax.c, but I have
already made one myself to test my code. Your past discussion
was pretty much informative :-).

--
Taisuke Yamada <[email protected]>
PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46

2000-11-19 23:15:53

by Dan Aloni

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using oldBIOS

On Mon, 20 Nov 2000, Taisuke Yamada wrote:

> > This patch is not good. It compiles, but when I boot the kernel, it
> > decides to ignore the hdc=5606,255,63 parameter that I pass to the kernel,
> > and limits the number of sectors to fill 8.4GB.
>
> Please retest with hdc=... parameter removed. If hd[a-z]=...
> parameter is specified, my patch will be disabled, trusting
> whatever user has specified.
>

Ok, I've booted without the parameter, and without the jumper on clipping
mode (I'll do it tommorow, it's 1AM now) got something similiar to what
you've written, and everything looks ok.

BTW, I have created the paratition table and all paratitions when the
drive reported 90069840 sectors. Now it reports 90069839 - one sector
less. Any damage risk to my filesystems?

dmesg:

hdc: host protected area => 1
hdc: checking for max native LBA...
hdc: max native LBA is 90069839
hdc: (un)clipping max LBA...
hdc: max LBA (un)clipped to 90069839
hdc: lba = 1, cap = 90069839
hdc: 90069839 sectors (46116 MB) w/1916KiB Cache, CHS=89354/16/63, UDMA(33)
Partition check:
hdc: [PTBL] [5606/255/63] hdc1 hdc2 hdc3 hdc4 < hdc5 >

> hda: host protected area => 1
> hda: checking for max native LBA...
> hda: max native LBA is 90045647
> hda: (un)clipping max LBA...
> hda: max LBA (un)clipped to 90045647
> hda: lba = 1, cap = 90045647
> hda: 90045647 sectors (46103 MB) w/2048KiB Cache, CHS=89330/16/63, UDMA(33)
> hdc: host protected area => 1
> hdc: checking for max native LBA...
> hdc: max native LBA is 90045647
> hdc: (un)clipping max LBA...
> hdc: max LBA (un)clipped to 90045647
> hdc: lba = 1, cap = 90045647
> hdc: 90045647 sectors (46103 MB) w/2048KiB Cache, CHS=89330/16/63, UDMA(33)

--
Dan Aloni
[email protected]

2000-11-19 23:42:55

by Taisuke Yamada

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


> > > This patch is not good...[snip]
> >
> > Please retest with hdc=...
>
> Ok, I've booted without the parameter, and without the jumper on
> clipping mode (I'll do it tommorow, it's 1AM now) got something
> similiar to what you've written, and everything looks ok.

Great, so it worked.

# Since it worked, please discard my message I sent you to wait.

> Now it reports 90069839 - one sector less. Any damage risk to
> my filesystems?

Hmm, that will be trouble if you access that last sector. I'll
take a look at it after I came back from my work (It's 8AM now
and got to go to work :-).

--
Taisuke Yamada <[email protected]>
PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46

2000-11-20 00:12:40

by Dan Aloni

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

On Mon, 20 Nov 2000, Taisuke Yamada wrote:

>
> > > > This patch is not good...[snip]
> > >
> > > Please retest with hdc=...
> >
> > Ok, I've booted without the parameter, and without the jumper on
> > clipping mode (I'll do it tommorow, it's 1AM now) got something
> > similiar to what you've written, and everything looks ok.
>
> Great, so it worked.
>
> # Since it worked, please discard my message I sent you to wait.
>
> > Now it reports 90069839 - one sector less. Any damage risk to
> > my filesystems?
>
> Hmm, that will be trouble if you access that last sector. I'll
> take a look at it after I came back from my work (It's 8AM now
> and got to go to work :-).

Well, I could patch it so it adds that one sector ;-) But that's not the
right way. The true number of sectors is 90069840, since 90069839 doesn't
divide by the number of *real* heads (6) and the number of recording zones
(15). So it needs fixing.

--
Dan Aloni
[email protected]

2000-11-20 00:31:52

by Andre Hedrick

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

On Mon, 20 Nov 2000, Dan Aloni wrote:

> Well, I could patch it so it adds that one sector ;-) But that's not the
> right way. The true number of sectors is 90069840, since 90069839 doesn't
> divide by the number of *real* heads (6) and the number of recording zones
> (15). So it needs fixing.

15 == 16 if 0 == 1 in realm of counting numbers.

Also geometry is a lie to begin with, so what is one more lie on top of
another?

Cheers,

Andre Hedrick
CTO Timpanogas Research Group
EVP Linux Development, TRG
Linux ATA Development

2000-11-20 00:48:25

by Dan Aloni

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

On Sun, 19 Nov 2000, Andre Hedrick wrote:

> On Mon, 20 Nov 2000, Dan Aloni wrote:
>
> > Well, I could patch it so it adds that one sector ;-) But that's not the
> > right way. The true number of sectors is 90069840, since 90069839 doesn't
> > divide by the number of *real* heads (6) and the number of recording zones
> > (15). So it needs fixing.
>
> 15 == 16 if 0 == 1 in realm of counting numbers.
>
> Also geometry is a lie to begin with, so what is one more lie on top of
> another?

These are real values, IBM:

http://www.storage.ibm.com/hardsoft/diskdrdl/desk/ds75gxp.htm

Let's try to read from the 90069840th sector:

# dd if=/dev/hdc of=/dev/null bs=512 count=1 skip=90069839
1+0 records in
1+0 records out

Walla. ;-)

--
Dan Aloni
[email protected]

2000-11-20 11:59:04

by Andre Hedrick

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


Andries,

Don't you mean

(drive->id->cfs_enable_1 & 0x0400) word85
and not
(drive->id->command_set_1 & 0x0400) word82

Because when bit 10 of word 85 is not set then clip or HPArea is not enabled.

Cheers,

Andre Hedrick
CTO Timpanogas Research Group
EVP Linux Development, TRG
Linux ATA Development

2000-11-20 12:30:18

by T. Yamada

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


> Both disks claim support for the Host Protected Area feature set.
> No doubt early disks had firmware flaws.

So it's yet another "borken hardware"... Is there anything like
SCSI "blacklist" for IDE driver? Then it could be handled easily
by registering the drive there and check that out before autodetection.

> - The routine idedisk_supports_host_protected_area()
> should look at bit 10 of command_set_1, but it does a "& 0x0a".

Oh, no. Thanks for catching that. It should obviously be 0x0400.

# I guess it got converted in a way like this: 10th bit -> 10 -> 0x0a. Ugh.

> - The assignment "hd_cap = hd_max;" is one off:

Now that explains one missing sector reported previously. Yes,
ATA spec says that the command returns "maximum address", not
number of sectors.

I'll make a fix and resend a patch - or since the fix is so
simple, I guess Andre can just add these fixes to IDE driver directly.

--
Taisuke Yamada <[email protected]>
PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46

2000-11-20 12:33:39

by Andre Hedrick

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS


Fixed now and working on it..


On Mon, 20 Nov 2000, T. Yamada wrote:

>
> > Both disks claim support for the Host Protected Area feature set.
> > No doubt early disks had firmware flaws.
>
> So it's yet another "borken hardware"... Is there anything like
> SCSI "blacklist" for IDE driver? Then it could be handled easily
> by registering the drive there and check that out before autodetection.
>
> > - The routine idedisk_supports_host_protected_area()
> > should look at bit 10 of command_set_1, but it does a "& 0x0a".
>
> Oh, no. Thanks for catching that. It should obviously be 0x0400.
>
> # I guess it got converted in a way like this: 10th bit -> 10 -> 0x0a. Ugh.
>
> > - The assignment "hd_cap = hd_max;" is one off:
>
> Now that explains one missing sector reported previously. Yes,
> ATA spec says that the command returns "maximum address", not
> number of sectors.
>
> I'll make a fix and resend a patch - or since the fix is so
> simple, I guess Andre can just add these fixes to IDE driver directly.
>
> --
> Taisuke Yamada <[email protected]>
> PGP fingerprint = 6B 57 1B ED 65 4C 7D AE 57 1B 49 A7 F7 C8 23 46
>

Andre Hedrick
CTO Timpanogas Research Group
EVP Linux Development, TRG
Linux ATA Development

2000-11-20 14:49:46

by Andries E. Brouwer

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS

From [email protected] Mon Nov 20 12:29:59 2000

Andries,

Don't you mean

(drive->id->cfs_enable_1 & 0x0400) word85
and not
(drive->id->command_set_1 & 0x0400) word82

Because when bit 10 of word 85 is not set then clip or HPArea is not enabled.

I saw no reason to complain about that part.

As far as I can see, ATA4 and ATA5 both require these two bits
to be identical. (Note that ATA4 has "supported" both in text
and table in both places, while ATA5 has "supported" in three
places and "enabled" in one. My preliminary ATA6 drafts do not differ.
And for example, there is no Set Features subcommand to enable/disable
the Host Protected Area feature. Maybe you have more recent drafts that
do allow disabling this feature?)

A small detail that might be improved is that one is only allowed to look
at this bit when words 83 and 84 have bit 15 equal to 0 and bit 14 equal to 1.
(Or, in case you prefer looking at word 85, bit 15 of word 87
must be 0 and bit 14 must be 1.)

Andries

2000-12-30 17:36:56

by Tommi Virtanen

[permalink] [raw]
Subject: Re: [PATCH] Large "clipped" IDE disk support for 2.4 when using old BIOS (fixed patch)

On Sat, Nov 18, 2000 at 09:32:26PM +0200, Taisuke Yamada wrote:
> Earlier this month, I had sent in a patch to 2.2.18pre17 (with
> IDE-patch from http://www.linux-ide.org/ applied) to add support
> for IDE disk larger than 32GB, even if the disk required "clipping"
> to reduce apparent disk size due to BIOS limitation.
[..]
> Now I'm moving to 2.4-based system, and so ported the patch to
> 2.4-test10. It also applies cleanly to 2.4-test11.

Well, the patch in the message didn't apply cleanly and
had some problems, as discussed in the rest of the thread.
As no one seems to have posted an updated patch, here
goes. This works nicely for my Maxtor 81.9GB HDD.

--- linux-2.4.0-test13-pre5/drivers/ide/ide-disk.c Fri Oct 27 09:35:48 2000
+++ linux/drivers/ide/ide-disk.c Thu Dec 28 22:49:18 2000
@@ -513,24 +513,149 @@
current_capacity(drive));
}

+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+ int flag = (drive->id->command_set_1 & 0x0400) ? 1 : 0;
+ printk("%s: host protected area => %d\n", drive->name, flag);
+ return flag;
+}
+
+/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+ byte args[7];
+ unsigned long addr = 0;
+
+ printk("%s: checking for max native LBA...\n", drive->name);
+
+ /* Create IDE/ATA command request structure
+ *
+ * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
+ * here...For real ATA command structure, offset for IDE
+ * command is 7, but in IDE driver, it needs to be at 0th
+ * index (same goes for IDE status offset below). Hmm...
+ */
+ args[0] = 0xf8; /* READ_NATIVE_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = 0x00;
+ args[IDE_LCYL_OFFSET] = 0x00;
+ args[IDE_HCYL_OFFSET] = 0x00;
+ args[IDE_SELECT_OFFSET] = 0x40;
+
+ /* submit command request - if OK, read current max LBA value */
+ if (ide_wait_cmd_task(drive, args) == 0) {
+ if ((args[0] & 0x01) == 0) {
+ addr = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args[IDE_HCYL_OFFSET] ) << 16)
+ | ((args[IDE_LCYL_OFFSET] ) << 8)
+ | ((args[IDE_SECTOR_OFFSET] ));
+ }
+ }
+
+ printk("%s: max native LBA is %lu\n", drive->name, addr);
+
+ return addr;
+}
+
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive,
+ unsigned long addr_req)
+{
+ byte args[7];
+ unsigned long addr_set = 0;
+
+ printk("%s: (un)clipping max LBA...\n", drive->name);
+
+ /* Create IDE/ATA command request structure
+ *
+ * NOTE: I'm not sure if I can safely use IDE_*_OFFSET macro
+ * here...For real ATA command structure, offset for IDE
+ * command is 7, but in IDE driver, it needs to be at 0th
+ * index (same goes for IDE status offset below). Hmm...
+ */
+ args[0] = 0xf9; /* SET_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = ((addr_req ) & 0xff);
+ args[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
+ args[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
+ args[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
+
+ /* submit command request - if OK, read new max LBA value */
+ if (ide_wait_cmd_task(drive, args) == 0) {
+ if ((args[0] & 0x01) == 0) {
+ addr_set = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args[IDE_HCYL_OFFSET] ) << 16)
+ | ((args[IDE_LCYL_OFFSET] ) << 8)
+ | ((args[IDE_SECTOR_OFFSET] ));
+ }
+ }
+
+ printk("%s: max LBA (un)clipped to %lu\n", drive->name, addr_set);
+
+ return addr_set;
+}
+
/*
* Compute drive->capacity, the full capacity of the drive
* Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ * 1. CHS value set by user (whatever user sets will be trusted)
+ * 2. LBA value from target drive (require new ATA feature)
+ * 3. LBA value from system BIOS (new one is OK, old one may break)
+ * 4. CHS value from system BIOS (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * rest of the values are ignored).
*/
static void init_idedisk_capacity (ide_drive_t *drive)
{
+ unsigned long hd_max;
+ unsigned long hd_cap = drive->cyl * drive->head * drive->sect;
+ int is_lba = 0;
+
struct hd_driveid *id = drive->id;
- unsigned long capacity = drive->cyl * drive->head * drive->sect;

- drive->select.b.lba = 0;
+ /* Unless geometry is given by user, use autodetected value */
+ if (! drive->forced_geom) {
+ /* If BIOS LBA geometry is available, use it */
+ if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+ hd_cap = id->lba_capacity;
+ is_lba = 1;
+ }

- /* Determine capacity, and use LBA if the drive properly supports it */
- if ((id->capability & 2) && lba_capacity_is_ok(id)) {
- capacity = id->lba_capacity;
- drive->cyl = capacity / (drive->head * drive->sect);
- drive->select.b.lba = 1;
+ /* If new ATA feature is supported, try using it */
+ if (idedisk_supports_host_protected_area(drive)) {
+ hd_max = idedisk_read_native_max_address(drive);
+ hd_max = idedisk_set_max_address(drive, hd_max);
+
+ if (hd_max > 0) {
+ hd_cap = hd_max+1;
+ is_lba = 1;
+ }
+ }
}
- drive->capacity = capacity;
+
+ printk("%s: lba = %d, cap = %lu\n", drive->name, is_lba, hd_cap);
+
+ /* update parameters with fetched results */
+ drive->select.b.lba = is_lba;
+ drive->capacity = hd_cap;
+ drive->cyl = hd_cap / (drive->head * drive->sect);
}

static unsigned long idedisk_capacity (ide_drive_t *drive)

--
tv@{{hq.yok.utu,havoc,gaeshido}.fi,{debian,wanderer}.org,stonesoft.com}
Perl poetry: for ($tv) { s/blood/caffeine/ while /blood/ }