Messages in this thread Patch in this message | | | Date | Wed, 25 Aug 1999 21:29:01 +0200 (MET DST) | From | Andries.Brouwer@cwi ... | Subject | Re: IBM 37GB drive |
| |
p0070621@brookes.ac.uk:
: I've just found your copy of the Large Disk HOWTO, 2.2c, : dated Sunday. : : My 37Gb DPTA-353750 drive arrived yesterday, and caused me problems. : It ought to have 72680 cylinders, but is clocking over at 64k, and : only reporting 7144, with a resulting capacity of 3.4 Gb. : Fortunately, the notes under 12.1 IDE problems with 34+ GB disks : claim that a patch is available.
Try the one below. (It is not quite finished - I did some work last Sunday and plan to do more but there are too many things...) Please report on success / non-success.
It is a patch on linux-2.3.14. Similar changes work on other kernels.
(In fact 2.3.14 [patched or not] does not work for me, but I have not yet investigated the cause. If it works for you, fine. Otherwise a very similar patch should work on 2.2.11 or so. And if the only goal is to make this particular drive work a 1-line patch might suffice.)
Andries - aeb@cwi.nl
[Linus, Alan: this is not the submission of a patch - do not use this.]
-------------------------------------------------------------------- diff -u --recursive --new-file ../linux-2.3.14/linux/drivers/block/ide-disk.c ./linux/drivers/block/ide-disk.c --- ../linux-2.3.14/linux/drivers/block/ide-disk.c Tue Jul 13 15:12:02 1999 +++ ./linux/drivers/block/ide-disk.c Sun Aug 22 23:59:32 1999 @@ -94,42 +94,41 @@ * * Returns: 1 if lba_capacity looks sensible * 0 otherwise + * + * It is called only once for each drive. + * (%% It modifies id->lba_capacity, bad!) */ static int lba_capacity_is_ok (struct hd_driveid *id) { - unsigned long lba_sects = id->lba_capacity; - unsigned long chs_sects = id->cyls * id->heads * id->sectors; - unsigned long _10_percent = chs_sects / 10; + unsigned long lba_sects, chs_sects, head, tail; /* - * very large drives (8GB+) may lie about the number of cylinders - * This is a split test for drives 8 Gig and Bigger only. + * The ATA spec tells large drives to return + * C/H/S = 16383/16/63 independent of their size. + * Some drives can be jumpered to use 15 heads instead of 16. */ - if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) && - (id->heads == 16) && (id->sectors == 63)) { - id->cyls = lba_sects / (16 * 63); /* correct cyls */ - return 1; /* lba_capacity is our only option */ - } - /* - * ... and at least one TLA VBC has POS instead of brain and can't - * tell 16 from 15. - */ - if ((id->lba_capacity >= 15481935) && (id->cyls == 0x3fff) && - (id->heads == 15) && (id->sectors == 63)) { - id->cyls = lba_sects / (15 * 63); /* correct cyls */ - return 1; /* lba_capacity is our only option */ - } - /* perform a rough sanity check on lba_sects: within 10% is "okay" */ - if ((lba_sects - chs_sects) < _10_percent) { - return 1; /* lba_capacity is good */ - } + if (id->cyls == 16383 && id->sectors == 63 && + (id->heads == 15 || id->heads == 16) && + id->lba_capacity >= 16383*63*id->heads) + return 1; + + lba_sects = id->lba_capacity; + chs_sects = id->cyls * id->heads * id->sectors; + + /* perform a rough sanity check on lba_sects: within 10% is OK */ + if ((lba_sects - chs_sects) < chs_sects/10) + return 1; + /* some drives have the word order reversed */ - lba_sects = (lba_sects << 16) | (lba_sects >> 16); - if ((lba_sects - chs_sects) < _10_percent) { - id->lba_capacity = lba_sects; /* fix it */ + head = ((lba_sects >> 16) & 0xffff); + tail = (lba_sects & 0xffff); + lba_sects = (head | (tail << 16)); + if ((lba_sects - chs_sects) < chs_sects/10) { + id->lba_capacity = lba_sects; /* %% fix it */ return 1; /* lba_capacity is (now) good */ } - return 0; /* lba_capacity value is bad */ + + return 0; /* lba_capacity value may be bad */ } /* @@ -450,24 +449,27 @@ } /* - * current_capacity() returns the capacity (in sectors) of a drive - * according to its current geometry/LBA settings. + * Compute drive->capacity, the full capacity of the drive */ -static unsigned long idedisk_capacity (ide_drive_t *drive) +static void init_idedisk_capacity (ide_drive_t *drive) { struct hd_driveid *id = drive->id; unsigned long capacity = drive->cyl * drive->head * drive->sect; drive->select.b.lba = 0; + /* Determine capacity, and use LBA if the drive properly supports it */ if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { - if (id->lba_capacity >= capacity) { - drive->cyl = id->lba_capacity / (drive->head * drive->sect); - capacity = id->lba_capacity; - drive->select.b.lba = 1; - } + drive->cyl = id->lba_capacity / (drive->head * drive->sect); + capacity = id->lba_capacity; + drive->select.b.lba = 1; } - return (capacity - drive->sect0); + drive->capacity = capacity; +} + +static unsigned long idedisk_capacity (ide_drive_t *drive) +{ + return (drive->capacity - drive->sect0); } static void idedisk_special (ide_drive_t *drive) @@ -628,7 +630,7 @@ int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; - ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); @@ -679,7 +681,7 @@ static void idedisk_setup (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - unsigned long capacity, check; + unsigned long capacity; idedisk_add_settings(drive); @@ -705,66 +707,37 @@ drive->head = drive->bios_head = id->heads; drive->sect = drive->bios_sect = id->sectors; } + /* Handle logical geometry translation by the drive */ if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) { - /* - * Extract the physical drive geometry for our use. - * Note that we purposely do *not* update the bios info. - * This way, programs that use it (like fdisk) will - * still have the same logical view as the BIOS does, - * which keeps the partition table from being screwed. - * - * An exception to this is the cylinder count, - * which we reexamine later on to correct for 1024 limitations. - */ drive->cyl = id->cur_cyls; drive->head = id->cur_heads; drive->sect = id->cur_sectors; - - /* check for word-swapped "capacity" field in id information */ - capacity = drive->cyl * drive->head * drive->sect; - check = (id->cur_capacity0 << 16) | id->cur_capacity1; - if (check == capacity) { /* was it swapped? */ - /* yes, bring it into little-endian order: */ - id->cur_capacity0 = (capacity >> 0) & 0xffff; - id->cur_capacity1 = (capacity >> 16) & 0xffff; - } } + /* Use physical geometry if what we have still makes no sense */ if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) { if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) { id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors))); } - drive->cyl = id->cur_cyls = id->cyls; - drive->head = id->cur_heads = id->heads; - drive->sect = id->cur_sectors = id->sectors; + drive->cyl = id->cyls; + drive->head = id->heads; + drive->sect = id->sectors; } /* calculate drive capacity, and select LBA if possible */ - capacity = idedisk_capacity (drive); + init_idedisk_capacity (drive); /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: */ + capacity = idedisk_capacity (drive); if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) && - (!drive->forced_geom) && drive->bios_sect && drive->bios_head) { + (!drive->forced_geom) && drive->bios_sect && drive->bios_head) drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head; -#ifdef DEBUG - printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n", - drive->id->cur_cyls, - drive->id->cur_heads, - drive->id->cur_sectors, - drive->bios_cyl, - drive->bios_head, - drive->bios_sect); -#endif - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - } #if 0 /* done instead for entire identify block in arch/ide.h stuff */ /* fix byte-ordering of buffer size field */ @@ -790,19 +763,6 @@ } } printk("\n"); - - if (drive->select.b.lba) { - if (*(int *)&id->cur_capacity0 < id->lba_capacity) { -#ifdef DEBUG - printk(" CurSects=%d, LBASects=%d, ", - *(int *)&id->cur_capacity0, id->lba_capacity); -#endif - *(int *)&id->cur_capacity0 = id->lba_capacity; -#ifdef DEBUG - printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0); -#endif - } - } drive->mult_count = 0; if (id->max_multsect) { diff -u --recursive --new-file ../linux-2.3.14/linux/drivers/block/ide-floppy.c ./linux/drivers/block/ide-floppy.c --- ../linux-2.3.14/linux/drivers/block/ide-floppy.c Sun Aug 22 00:09:06 1999 +++ ./linux/drivers/block/ide-floppy.c Sun Aug 22 21:49:23 1999 @@ -1498,7 +1498,7 @@ int major = HWIF(drive)->major; int minor = drive->select.b.unit << PARTN_BITS; - ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); diff -u --recursive --new-file ../linux-2.3.14/linux/drivers/block/ide-probe.c ./linux/drivers/block/ide-probe.c --- ../linux-2.3.14/linux/drivers/block/ide-probe.c Sun Aug 22 00:09:06 1999 +++ ./linux/drivers/block/ide-probe.c Sun Aug 22 23:13:29 1999 @@ -372,6 +372,8 @@ * The only "perfect" way to handle this would be to modify the setup.[cS] code * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info * for us during initialization. I have the necessary docs -- any takers? -ml + * I did this, but it doesnt work - there is no reasonable way to find the + * correspondence between the BIOS numbering of the disks and the Linux numbering. -aeb */ static void probe_cmos_for_drives (ide_hwif_t *hwif) { diff -u --recursive --new-file ../linux-2.3.14/linux/drivers/block/ide.c ./linux/drivers/block/ide.c --- ../linux-2.3.14/linux/drivers/block/ide.c Sun Aug 22 00:09:41 1999 +++ ./linux/drivers/block/ide.c Mon Aug 23 00:51:59 1999 @@ -2318,10 +2318,11 @@ case HDIO_GETGEO: { struct hd_geometry *loc = (struct hd_geometry *) arg; + unsigned short bios_cyl = drive->bios_cyl; /* truncate */ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; - if (put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; + if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start)) return -EFAULT; return 0; @@ -2340,7 +2341,8 @@ return -EINVAL; if (drive->id == NULL) return -ENOMSG; - if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) + if (copy_to_user((char *)arg, (char *)drive->id, + (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; return 0; @@ -3048,37 +3050,24 @@ if (!drive) return 0; - if (drive->forced_geom) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 0; + if (xparm == -1) { + drive->remap_0_to_1 = 1; + if (drive->bios_head > 16) { + printk("[remap 0->1]"); + return 0; + } } - if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; + if (drive->forced_geom) + return 0; + + if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) return 0; /* we already have a translation */ - } printk("%s ", msg); - if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; + if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) return 0; /* small disk: no translation needed */ - } if (drive->id) { drive->cyl = drive->id->cyls; @@ -3117,12 +3106,6 @@ drive->part[0].nr_sects = current_capacity(drive); printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect); - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; return 1; } diff -u --recursive --new-file ../linux-2.3.14/linux/drivers/scsi/ide-scsi.c ./linux/drivers/scsi/ide-scsi.c --- ../linux-2.3.14/linux/drivers/scsi/ide-scsi.c Tue Jul 13 15:12:09 1999 +++ ./linux/drivers/scsi/ide-scsi.c Sun Aug 22 21:49:36 1999 @@ -487,7 +487,7 @@ /* * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function */ - ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL); diff -u --recursive --new-file ../linux-2.3.14/linux/include/linux/ide.h ./linux/include/linux/ide.h --- ../linux-2.3.14/linux/include/linux/ide.h Sun Aug 22 00:09:35 1999 +++ ./linux/include/linux/ide.h Mon Aug 23 15:01:45 1999 @@ -282,8 +282,9 @@ byte sect; /* "real" sectors per track */ byte bios_head; /* BIOS/fdisk/LILO number of heads */ byte bios_sect; /* BIOS/fdisk/LILO sectors per track */ - unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */ - unsigned short cyl; /* "real" number of cyls */ + unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ + unsigned int cyl; /* "real" number of cyls */ + unsigned long capacity; /* total number of sectors */ unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ void *hwif; /* actually (ide_hwif_t *) */ wait_queue_head_t wqueue; /* used to wait for drive in open() */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |