[PATCH] Re: 2.4.x kernels, big ide disks and old bios

Eric Lammerts (eric@lammerts.org)
Fri, 28 Dec 2001 01:06:25 +0100 (CET)


On Fri, 28 Dec 2001, Stephan von Krawczynski wrote:
> I must admit I have still not had a look at it, but on the other hand:
> if it makes big IDE drives work on old mobo & bios, it may be a good
> idea to include its intelligence into the kernel, or not?

I cleaned up the patch a bit (see below). It now performs the
SET_MAX command only when needed, and is far less verbose (only
prints 1 line when unclipping). It applies against 2.4.18pre1 and
2.5.2pre2.

I've tested it with a Maxtor 96147U8 (60Gb), Maxtor 98196H8 (80Gb)
and WDC WD300BB (30Gb) (the last one just for testing, and I had to
use ibmsetmax instead of setmax to make the drive remember it).
It also worked with some 2.5" IBM hdd a while back (don't remember
the exact model).

Jens, please consider this patch for inclusion into 2.4 and/or 2.5.
(or should I talk to someone else?)

Eric

--- linux/drivers/ide/ide-disk.c.orig Thu Dec 27 22:19:11 2001
+++ linux/drivers/ide/ide-disk.c Fri Dec 28 00:37:36 2001
@@ -500,6 +500,78 @@
current_capacity(drive));
}

+
+/*
+ * Queries for true maximum capacity of the drive and (if needed) sets
+ * maximum virtual LBA address accordingly. Also updates drive->*
+ * settings.
+ */
+static void idedisk_unclip(ide_drive_t *drive)
+{
+ byte args[7];
+ unsigned long addr = 0;
+
+ if(!(drive->id->command_set_1 & 0x0400)) {
+ /* drive does not support Host Protected Area feature. */
+ return;
+ }
+
+ /* create IDE/ATA command request structure */
+ 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;
+
+ if(ide_wait_cmd_task(drive, args) != 0 || (args[0] & 0x01) != 0) {
+ /* silently ignore failed command */
+ return;
+ }
+
+ /* read max LBA value */
+ addr = ((args[IDE_SELECT_OFFSET] & 0x0f) << 24) |
+ (args[IDE_HCYL_OFFSET] << 16) |
+ (args[IDE_LCYL_OFFSET] << 8) |
+ (args[IDE_SECTOR_OFFSET]);
+
+ /* sanity check */
+ if(addr == 0) return;
+
+ if(drive->capacity == (addr + 1)) {
+ /* no unclipping needed */
+ return;
+ }
+
+ printk("%s: unclipping drive from %lu sectors to %lu sectors\n",
+ drive->name, drive->capacity, addr + 1);
+
+ /* create IDE/ATA command request structure */
+ args[0] = 0xf9; /* SET_MAX - see ATA spec */
+ args[IDE_FEATURE_OFFSET] = 0x00;
+ args[IDE_NSECTOR_OFFSET] = 0x00;
+ args[IDE_SECTOR_OFFSET] = addr & 0xff;
+ args[IDE_LCYL_OFFSET] = (addr >> 8) & 0xff;
+ args[IDE_HCYL_OFFSET] = (addr >> 16) & 0xff;
+ args[IDE_SELECT_OFFSET] = ((addr >> 24) & 0x0f) | 0x40;
+
+ /* submit command request - if OK, read new max LBA value */
+ if(ide_wait_cmd_task(drive, args) == 0 && (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]);
+
+ drive->select.b.lba = 1;
+ drive->capacity = addr + 1;
+ drive->cyl = drive->capacity / (drive->head * drive->sect);
+ } else {
+ printk("%s: unclipping drive failed\n", drive->name);
+ }
+}
+
+
/*
* Compute drive->capacity, the full capacity of the drive
* Called with drive->id != NULL.
@@ -518,6 +590,8 @@
drive->select.b.lba = 1;
}
drive->capacity = capacity;
+
+ idedisk_unclip(drive);
}

static unsigned long idedisk_capacity (ide_drive_t *drive)

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