diff options
Diffstat (limited to 'drivers/block/ide-disk.c')
-rw-r--r-- | drivers/block/ide-disk.c | 118 |
1 files changed, 92 insertions, 26 deletions
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c index 2062f5cdf..f84ac8f14 100644 --- a/drivers/block/ide-disk.c +++ b/drivers/block/ide-disk.c @@ -1,12 +1,14 @@ /* - * linux/drivers/block/ide-disk.c Version 1.04 Jan 7, 1998 + * linux/drivers/block/ide-disk.c Version 1.08 Dec 10, 1998 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ /* - * Maintained by Mark Lord <mlord@pobox.com> - * and Gadi Oxman <gadio@netvision.net.il> + * Mostly written by Mark Lord <mlord@pobox.com> + * and Gadi Oxman <gadio@netvision.net.il> + * + * See linux/MAINTAINERS for address of current maintainer. * * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c. * @@ -19,10 +21,13 @@ * Version 1.05 add capacity support for ATA3 >= 8GB * Version 1.06 get boot-up messages to show full cyl count * Version 1.07 disable door-locking if it fails - * Version 1.07a fixed mult_count enables + * Version 1.08 fixed CHS/LBA translations for ATA4 > 8GB, + * process of adding new ATA4 compliance. + * fixed problems in allowing fdisk to see + * the entire disk. */ -#define IDEDISK_VERSION "1.07" +#define IDEDISK_VERSION "1.08" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -87,15 +92,33 @@ static int lba_capacity_is_ok (struct hd_driveid *id) unsigned long chs_sects = id->cyls * id->heads * id->sectors; unsigned long _10_percent = chs_sects / 10; - /* very large drives (8GB+) may lie about the number of cylinders */ - if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) { + /* + * very large drives (8GB+) may lie about the number of cylinders + * This is a split test for drives 8 Gig and Bigger only. + */ + 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 */ } + /* + * This is a split test for drives less than 8 Gig only. + * Drives less than 8GB sometimes declare that they have 15 heads. + * This is an accounting trick (0-15) == (1-16), just an initial + * zero point difference. + */ + if ((id->lba_capacity < 16514064) && (lba_sects > chs_sects) && + ((id->heads == 15) || (id->heads == 16)) && (id->sectors == 63)) { + if (id->heads == 15) + id->cyls = lba_sects / (15 * 63); /* correct cyls */ + if (id->heads == 16) + id->cyls = lba_sects / (16 * 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) + if ((lba_sects - chs_sects) < _10_percent) { return 1; /* lba_capacity is good */ - + } /* some drives have the word order reversed */ lba_sects = (lba_sects << 16) | (lba_sects >> 16); if ((lba_sects - chs_sects) < _10_percent) { @@ -487,13 +510,13 @@ static void idedisk_pre_reset (ide_drive_t *drive) drive->special.b.set_multmode = 1; } +#ifdef CONFIG_PROC_FS + static int smart_enable(ide_drive_t *drive) { return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL); } -#ifdef CONFIG_PROC_FS - static int get_smart_values(ide_drive_t *drive, byte *buf) { (void) smart_enable(drive); @@ -603,7 +626,7 @@ static void idedisk_add_settings(ide_drive_t *drive) 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_SHORT, 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); @@ -676,9 +699,8 @@ static void idedisk_setup (ide_drive_t *drive) 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) - { + 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. @@ -703,27 +725,49 @@ static void idedisk_setup (ide_drive_t *drive) } } /* Use physical geometry if what we have still makes no sense */ - if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) { - drive->cyl = id->cyls; - drive->head = id->heads; - drive->sect = id->sectors; + 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; } /* calculate drive capacity, and select LBA if possible */ - (void) idedisk_capacity (drive); + capacity = idedisk_capacity (drive); - /* Correct the number of cyls if the bios value is too small */ - if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) { - if (drive->cyl > drive->bios_cyl) - drive->bios_cyl = drive->cyl; + /* + * if possible, give fdisk access to more of the drive, + * by correcting bios_cyls: + */ + if ((capacity >= (drive->bios_cyl * 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 */ id->buf_size = le16_to_cpu(id->buf_size); #endif printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d", - drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2, - drive->bios_cyl, drive->bios_head, drive->bios_sect); + drive->name, id->model, + capacity/2048L, id->buf_size/2, + drive->bios_cyl, drive->bios_head, drive->bios_sect); + if (drive->using_dma) { if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7)) { @@ -735,12 +779,34 @@ static void idedisk_setup (ide_drive_t *drive) } } 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) { +#if 1 /* original, pre IDE-NFG, per request of AC */ + drive->mult_req = INITIAL_MULT_COUNT; + if (drive->mult_req > id->max_multsect) + drive->mult_req = id->max_multsect; + if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) + drive->special.b.set_multmode = 1; +#else id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; id->multsect_valid = id->multsect ? 1 : 0; drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; drive->special.b.set_multmode = drive->mult_req ? 1 : 0; +#endif } drive->no_io_32bit = id->dword_io ? 1 : 0; } |