diff -u --recursive --new-file linux-1.2.13/drivers/block/README.ide linux/drivers/block/README.ide --- linux-1.2.13/drivers/block/README.ide Wed Jan 3 17:54:07 1996 +++ linux/drivers/block/README.ide Fri Jan 5 14:07:17 1996 @@ -1,5 +1,5 @@ -README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.2.x) -================================================================================ +README.ide -- Information regarding ide.c and ide-cd.c (IDE driver version 3.16c) +================================================================================= Supported by: mlord@bnr.ca -- disks, interfaces, probing snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio @@ -26,6 +26,8 @@ NEW! - experimental support for DTC-2278D interfaces - use kernel command line option: hda=dtc2278 NEW! - run-time selectable 32bit interface support (using hdparm-2.3) +NEW! - support for DiskManager and EZ-Drive translation software (see below) +NEW! - auto-detection of RZ1000 IDE chip to disable buggy "read-ahead" mode Under construction: @@ -216,6 +218,12 @@ If the BIOS does not support this form of drive translation, then several options remain, listed below in inverse order of popularity: + - use DiskManager software from OnTrack, supplied free with + many new hard drive purchases. + - use EZ-Drive software (similar to DiskManager). Note though, + that LILO must *not* use the MBR when EZ-Drive is present. + Instead, install LILO on the first sector of your linux partition, + and mark it as "active" or "bootable" with fdisk. - boot from a floppy disk instead of the hard drive (takes 10 seconds). - use a partition below the 1024 cyl boundary to hold the linux boot files (kernel images and /boot directory), and place the rest @@ -265,14 +273,5 @@ endings" and emit messages such as "This is larger than 1024, and may cause problems with some software". Ignore them for linux partitions. The "some software" refers to DOS, the BIOS, and LILO, as described previously. - -Western Digital now ships a "DiskManager 6.03" diskette with all of their big -hard drives. Burn it! That idiotic piece of garbage isn't even universally -compatible with DOS, let alone other operating systems like Linux. Eventually -some kind person will kludge Linux to work with it, but at present the two -are completely incompatible. If you have this version of DiskManager on your -hard disk already, it can be exterminated at the expense of all data on the -drive (back it up elsewhere), by using the "DM" command from the diskette -as follows: DM /Y- mlord@bnr.ca diff -u --recursive --new-file linux-1.2.13/drivers/block/genhd.c linux/drivers/block/genhd.c --- linux-1.2.13/drivers/block/genhd.c Wed Jan 3 17:54:00 1996 +++ linux/drivers/block/genhd.c Fri Jan 5 13:07:03 1996 @@ -14,6 +14,7 @@ #include #include #include +#include struct gendisk *gendisk_head = NULL; @@ -101,14 +102,135 @@ brelse(bh); } -static void check_partition(struct gendisk *hd, unsigned int dev) +#define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ +#define EZD_PARTITION 0x55 /* EZ-DRIVE: similar to DM6 */ +#define DM6_AUX1PARTITION 0x51 /* no DDO: use xlated geom */ +#define DM6_AUX3PARTITION 0x53 /* no DDO: use xlated geom */ + +static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) { - static int first_time = 1; int i, minor = current_minor; struct buffer_head *bh; struct partition *p; - unsigned long first_sector; + unsigned char *data; int mask = (1 << hd->minor_shift) - 1; +#ifdef CONFIG_BLK_DEV_IDE + int tested_for_dm6 = 0; + +read_mbr: +#endif + if (!(bh = bread(dev,0,1024))) { + printk(" unable to read partition table\n"); + return -1; + } + data = bh->b_data; + /* In some cases we modify the geometry */ + /* of the drive (below), so ensure that */ + /* nobody else tries to re-use this data. */ + bh->b_dirt = 0; + bh->b_uptodate = 0; + bh->b_req = 0; +#ifdef CONFIG_BLK_DEV_IDE +check_table: +#endif + if (*(unsigned short *) (0x1fe + data) != 0xAA55) { + brelse(bh); + return 0; + } + p = (struct partition *) (0x1be + data); + +#ifdef CONFIG_BLK_DEV_IDE + /* + * Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation + */ + if (!tested_for_dm6++) { /* only check for DM6 *once* */ + extern int ide_xlate_1024(int, int, const char *); + /* check for various "disk managers" which do strange things */ + if (p->sys_ind == EZD_PARTITION) { + /* + * The remainder of the disk must be accessed using + * a translated geometry that reduces the number of + * apparent cylinders to less than 1024 if possible. + * + * ide_xlate_1024() will take care of the necessary + * adjustments to fool fdisk/LILO and partition check. + */ + if (ide_xlate_1024(dev, -1, " [EZD]")) { + data += 512; + goto check_table; + } + } else if (p->sys_ind == DM6_PARTITION) { + + /* + * Everything on the disk is offset by 63 sectors, + * including a "new" MBR with its own partition table, + * and the remainder of the disk must be accessed using + * a translated geometry that reduces the number of + * apparent cylinders to less than 1024 if possible. + * + * ide_xlate_1024() will take care of the necessary + * adjustments to fool fdisk/LILO and partition check. + */ + if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) { + brelse(bh); + goto read_mbr; /* start over with new MBR */ + } + } else { + /* look for DM6 signature in MBR, courtesy of OnTrack */ + unsigned int sig = *(unsigned short *)(data + 2); + if (sig <= 0x1ae + && *(unsigned short *)(data + sig) == 0x55AA + && (1 & *(unsigned char *)(data + sig + 2)) ) + { + (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]"); + } else { + /* look for DM6 AUX partition type in slot 1 */ + if (p->sys_ind == DM6_AUX1PARTITION + || p->sys_ind == DM6_AUX3PARTITION) + { + (void)ide_xlate_1024(dev, 0, " [DM6:AUX]"); + } + } + } + } +#endif /* CONFIG_BLK_DEV_IDE */ + + current_minor += 4; /* first "extra" minor (for extended partitions) */ + for (i=1 ; i<=4 ; minor++,i++,p++) { + if (!p->nr_sects) + continue; + add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects); + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { + printk(" <"); + extended_partition(hd, (hd->major << 8) | minor); + printk(" >"); + } + } + /* + * Check for old-style Disk Manager partition table + */ + if (*(unsigned short *) (data+0xfc) == 0x55AA) { + p = (struct partition *) (0x1be + data); + for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & mask) >= mask-2) + break; + if (!(p->start_sect && p->nr_sects)) + continue; + add_partition(hd, current_minor, p->start_sect, p->nr_sects); + } + } + printk("\n"); + brelse(bh); + return 1; +} + +static void check_partition(struct gendisk *hd, unsigned int dev) +{ + static int first_time = 1; + unsigned long first_sector; if (first_time) printk("Partition check:\n"); @@ -124,45 +246,12 @@ return; } - if (!(bh = bread(dev,0,1024))) { - printk(" unable to read partition table of device %04x\n",dev); + printk(" %s%c:", hd->major_name, minor_name(hd, MINOR(dev))); + if (msdos_partition(hd, dev, first_sector)) return; - } - printk(" %s%c:", hd->major_name, minor_name(hd, minor)); - current_minor += 4; /* first "extra" minor (for extended partitions) */ - if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { - p = (struct partition *) (0x1BE + bh->b_data); - for (i=1 ; i<=4 ; minor++,i++,p++) { - if (!p->nr_sects) - continue; - add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects); - if ((current_minor & 0x3f) >= 60) - continue; - if (p->sys_ind == EXTENDED_PARTITION) { - printk(" <"); - extended_partition(hd, (hd->major << 8) | minor); - printk(" >"); - } - } - /* - * check for Disk Manager partition table - */ - if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { - p = (struct partition *) (0x1BE + bh->b_data); - for (i = 4 ; i < 16 ; i++, current_minor++) { - p--; - if ((current_minor & mask) >= mask-2) - break; - if (!(p->start_sect && p->nr_sects)) - continue; - add_partition(hd, current_minor, p->start_sect, p->nr_sects); - } - } - } else - printk(" bad partition table"); - printk("\n"); - brelse(bh); + printk(" unknown partition table\n"); } + /* This function is used to re-read partition tables for removable disks. Much of the cleanup from the old partition tables should have already been diff -u --recursive --new-file linux-1.2.13/drivers/block/ide.c linux/drivers/block/ide.c --- linux-1.2.13/drivers/block/ide.c Wed Jan 3 17:54:00 1996 +++ linux/drivers/block/ide.c Fri Jan 5 14:02:41 1996 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide.c Version 3.16 May 30, 1995 + * linux/drivers/block/ide.c Version 3.16c Jan 5, 1996 * - * Copyright (C) 1994, 1995 Linus Torvalds & authors (see below) + * Copyright (C) 1994-1996 Linus Torvalds & authors (see below) */ /* @@ -120,6 +120,7 @@ * add boot flag to enable "dtc2278" probe * add probe to avoid EATA (SCSI) interfaces, * courtesy of neuffer@goofy.zdv.uni-mainz.de. + * Version 3.16c special version for Caldera, with DM6/EZDRIVE/RZ1000/CMD * * To do: * - improved CMD support: tech info is supposedly "in the mail" @@ -149,6 +150,11 @@ #include #include +#ifdef CONFIG_PCI +#include +#include +#endif /* CONFIG_PCI */ + /***************************************************************************** * IDE driver configuration options (play with these as desired): */ @@ -332,10 +338,10 @@ unsigned busy : 1; /* mutex for ide_open, revalidate_.. */ unsigned vlb_32bit : 1; /* use 32bit in/out for data */ unsigned vlb_sync : 1; /* needed for some 32bit chip sets */ - unsigned reserved0 : 1; /* unused */ + unsigned ezdrive : 1; special_t special; /* special action flags */ select_t select; /* basic drive/head select reg value */ - byte mult_count, chipset, reserved2; + byte mult_count, chipset, sect0; byte usage, mult_req, wpcom, ctl; byte head, sect, bios_head, bios_sect; unsigned short cyl, bios_cyl; @@ -408,6 +414,8 @@ #define IDE_DRIVER /* "parameter" for blk.h */ #include "blk.h" +static int disallow_unmask = 0; /* for buggy hardware */ + /* * For really screwy hardware (hey, at least it *can* be used with Linux! */ @@ -881,6 +889,8 @@ ide_handler[DEV_HWIF] = handler; } +static int multmode_was_turned_on = 0; + static void set_multmode_intr (ide_dev_t *dev) { byte stat = GET_STAT(DEV_HWIF); @@ -891,10 +901,11 @@ dev->special.b.recalibrate = 1; (void) dump_status(DEV_HWIF, "set_multmode", stat); } else { - if ((dev->mult_count = dev->mult_req)) + if ((dev->mult_count = dev->mult_req)) { + multmode_was_turned_on = 1; printk (" %s: enabled %d-sector multiple mode\n", dev->name, dev->mult_count); - else + } else if (multmode_was_turned_on) printk (" %s: multiple mode turned off\n", dev->name); } DO_REQUEST; @@ -1172,7 +1183,11 @@ end_request(0, HWIF); goto repeat; } - block += ide_hd[HWIF][minor].start_sect; + block += ide_hd[HWIF][minor].start_sect + dev->sect0; + if (block == 0 && dev->ezdrive) { + block = 1; + printk("%s: [EZD] accessing sector 1 instead of sector 0\n", dev->name); + } #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - ide_lastreq[HWIF]) < DISK_RECOVERY_TIME); #endif @@ -1578,8 +1593,10 @@ memcpy_tofs((char *)arg, (char *)dev->id, sizeof(*dev->id)); return 0; - case HDIO_SET_KEEPSETTINGS: case HDIO_SET_UNMASKINTR: + if (arg && disallow_unmask) + return -EPERM; + case HDIO_SET_KEEPSETTINGS: if (!suser()) return -EACCES; if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK)) return -EINVAL; @@ -1854,6 +1871,53 @@ while (timer > jiffies); } +/* + * This routine is called from the partition-table code in genhd.c + * to "convert" a drive to a logical geometry with fewer than 1024 cyls + * It mimics the method used by Ontrack Disk Manager. + */ +int ide_xlate_1024 (int i_rdev, int offset, const char *msg) +{ + ide_dev_t *dev; + static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; + const byte *heads = head_vals; + unsigned long tracks, capacity; + + if ((dev = get_info_ptr(i_rdev)) == NULL) + return 0; + + if (dev->id) { + dev->cyl = dev->id->cyls; + dev->head = dev->id->heads; + dev->sect = dev->id->sectors; + } + dev->bios_cyl = dev->cyl; + dev->bios_head = dev->head; + dev->bios_sect = dev->sect; + dev->special.b.set_geometry = 1; + + tracks = dev->bios_cyl * dev->bios_head * dev->bios_sect / 63; + dev->bios_sect = 63; + while (dev->bios_cyl >= 1024) { + dev->bios_head = *heads; + dev->bios_cyl = tracks / dev->bios_head; + if (0 == *++heads) + break; + } + if (offset) { + if (offset == -1) + dev->ezdrive = 1; + else { + dev->sect0 = 63; + dev->bios_cyl = (tracks - 1) / dev->bios_head; + } + } + capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect; + ide_capacity[DEV_HWIF][dev->select.b.drive] = capacity; + ide_hd[DEV_HWIF][MINOR(i_rdev)].nr_sects = capacity; + printk("%s [%d/%d/%d]", msg, dev->bios_cyl, dev->bios_head, dev->bios_sect); + return 1; +} static int try_to_identify (ide_dev_t *dev, byte cmd) /* @@ -2213,6 +2277,8 @@ dev->usage = 0; dev->vlb_32bit = 0; dev->vlb_sync = 0; + dev->sect0 = 0; + dev->ezdrive = 0; dev->id = NULL; dev->ctl = 0x08; dev->wqueue = NULL; @@ -2311,6 +2377,100 @@ }; +#ifdef CONFIG_PCI + +static void ide_pci_access_error (int rc) +{ + printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); +} + +static void buggy_interface_fallback (int rc) +{ + ide_pci_access_error (rc); + single_threaded = 1; + disallow_unmask = 1; + printk("serialized, disabled unmasking\n"); +} + +static void init_rz1000 (byte bus, byte fn) +{ + int rc; + unsigned short reg; + + printk("ide: buggy RZ1000 interface: "); + if ((rc = pcibios_read_config_word (bus, fn, PCI_COMMAND, ®))) { + ide_pci_access_error (rc); + } else if (!(reg & 1)) { + printk("not enabled\n"); + } else { + if ((rc = pcibios_read_config_word(bus, fn, 0x40, ®)) + || (rc = pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))) + buggy_interface_fallback (rc); + else + printk("disabled read-ahead\n"); + } +} + +static void init_cmd640 (byte bus, byte fn) +{ + int rc; + unsigned char reg; + + single_threaded = 1; + printk("ide: buggy CMD640 interface: "); + + /* + * The first part is undocumented magic from the DOS driver. + * According to the datasheet, there is no port 0x5b on the cmd640. + */ + (void) pcibios_write_config_byte(bus, fn, 0x5b, 0xbd); + (void) pcibios_read_config_byte (bus, fn, 0x5b, ®); + (void) pcibios_write_config_byte(bus, fn, 0x5b, 0); + /* + * The rest is from the cmd640b datasheet. + */ + if ((rc = pcibios_read_config_byte (bus, fn, 0x51, ®)) + || (rc = pcibios_write_config_byte(bus, fn, 0x51, reg | 0xc0)) /* 0xc8 to enable 2nd i/f */ + || (rc = pcibios_read_config_byte (bus, fn, 0x57, ®)) + || (rc = pcibios_write_config_byte(bus, fn, 0x57, reg | 0x0c))) + buggy_interface_fallback (rc); + else + printk("serialized, disabled read-ahead\n"); +} + +typedef void (ide_pci_init_proc_t)(byte, byte); + +/* + * ide_probe_pci() scans PCI for a specific vendor/device function, + * and invokes the supplied init routine for each instance detected. + */ +static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci_init_proc_t *init, int func_adj) +{ + unsigned long flags; + unsigned index; + byte fn, bus; + + save_flags(flags); + cli(); + for (index = 0; !pcibios_find_device (vendor, device, index, &bus, &fn); ++index) { + init (bus, fn + func_adj); + } + restore_flags(flags); +} + +/* + * ide_init_pci() finds/initializes "known" PCI IDE interfaces + * + * This routine should ideally be using pcibios_find_class() to find + * all IDE interfaces, but that function causes some systems to "go weird". + */ +static void ide_init_pci (void) +{ + ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0); + ide_probe_pci (PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, &init_cmd640, 0); +} +#endif /* CONFIG_PCI */ + #if SUPPORT_DTC2278 /* * From: andy@cercle.cts.com (Dyan Wile) @@ -2365,11 +2525,15 @@ { byte hwif; + /* single_threaded = 0; */ /* zero by default, override at boot */ +#ifdef CONFIG_PCI + ide_init_pci(); +#endif /* CONFIG_PCI */ + #if SUPPORT_DTC2278 if (probe_dtc2278) try_to_init_dtc2278(); #endif /* SUPPORT_DTC2278 */ - /* single_threaded = 0; */ /* zero by default, override at boot */ for (hwif = 0; hwif < 2; hwif++) { init_ide_data (hwif); if (SUPPORT_TWO_INTERFACES || hwif == HWIF) { diff -u --recursive --new-file linux-1.2.13/include/linux/pci.h linux/include/linux/pci.h --- linux-1.2.13/include/linux/pci.h Wed Jan 3 17:54:02 1996 +++ linux/include/linux/pci.h Fri Jan 5 12:30:21 1996 @@ -242,8 +242,8 @@ #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371 0x122e -#define PCI_VENDOR_ID_SMC 0x1042 -#define PCI_DEVICE_ID_SMC_37C665 0x1000 +#define PCI_VENDOR_ID_PCTECH 0x1042 +#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 #define PCI_VENDOR_ID_ATI 0x1002 #define PCI_DEVICE_ID_ATI_M32 0x4158 @@ -369,7 +369,7 @@ {PCI_VENDOR_ID_DEC, "DEC"}, \ {PCI_VENDOR_ID_MATROX, "Matrox"}, \ {PCI_VENDOR_ID_INTEL, "Intel"}, \ - {PCI_VENDOR_ID_SMC, "SMC"}, \ + {PCI_VENDOR_ID_PCTECH, "PCTECH"}, \ {PCI_VENDOR_ID_ATI, "ATI"}, \ {PCI_VENDOR_ID_WEITEK, "Weitek"}, \ {PCI_VENDOR_ID_CIRRUS, "Cirrus Logic"}, \ @@ -451,7 +451,7 @@ {0xff, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82430, "82430ZX Aries"}, \ {0xff, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, "82437FX Triton"}, \ {0xff, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371, "82371FB"}, \ - {0xff, PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_37C665, "FDC 37C665"}, \ + {0xff, PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, "RZ1000 (buggy)"}, \ {0xff, PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_M32, "Mach 32"}, \ {0xff, PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_M64, "Mach 64"}, \ {0xff, PCI_VENDOR_ID_WEITEK, PCI_DEVICE_ID_WEITEK_P9000, "P9000"}, \ @@ -472,7 +472,7 @@ {0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_b, "ET4000W32P rev B"}, \ {0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_c, "ET4000W32P rev C"}, \ {0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_d, "ET4000W32P rev D"}, \ - {0xff, PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, "640A"}, \ + {0xff, PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, "640 (buggy)"}, \ {0xff, PCI_VENDOR_ID_VISION, PCI_DEVICE_ID_VISION_QD8500, "QD-8500"}, \ {0xff, PCI_VENDOR_ID_VISION, PCI_DEVICE_ID_VISION_QD8580, "QD-8580"}, \ {0xff, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, "79C970"}, \