patch-1.3.61 linux/drivers/block/ide.c

Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ht6560b.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.60/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.25  Jan 11, 1996
+ *  linux/drivers/block/ide.c	Version 5.27  Feb  8, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -183,17 +183,30 @@
  *  Version 5.24	fix #if's for SUPPORT_CMD640
  *  Version 5.25	more touch-ups, fix cdrom resets, ...
  *			cmd640.c now configs/compiles separate from ide.c
+ *  Version 5.26	keep_settings now maintains the using_dma flag
+ *			fix [EZD] remap message to only output at boot time
+ *			fix "bad /dev/ entry" message to say hdc, not hdc0
+ *			fix ide_xlate_1024() to respect user specified CHS
+ *			use CHS from partn table if it looks translated
+ *			re-merged flags chipset,vlb_32bit,vlb_sync into io_32bit
+ *			keep track of interface chipset type, when known
+ *			add generic PIO mode "tuneproc" mechanism
+ *			fix cmd640_vlb option
+ *			fix ht6560b support (was completely broken)
+ *			umc8672.c now configures/compiles separate from ide.c
+ *			move dtc2278 support to dtc2278.c
+ *			move ht6560b support to ht6560b.c
+ *			move qd6580  support to qd6580.c
+ *			add  ali14xx support in ali14xx.c
+ * Version 5.27		add [no]autotune parameters to help cmd640
+ *			move rz1000  support to rz1000.c
  *
- *  Driver compile-time options are in ide.h
+ *  Some additional driver compile-time options are in ide.h
  *
  *  To do, in likely order of completion:
- *	- make umc8672.c compile separately from ide.c
- *	- add ALI M1443/1445 chipset support from derekn@vw.ece.cmu.edu
- *	- add ioctls to get/set interface timings on various interfaces
- *	- add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
+ *	- add Promise DC4030VL support from peterd@pnd-pc.demon.co.uk
  *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *	- add new HT6560B code from malafoss@snakemail.hut.fi
- */
+*/
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -225,13 +238,12 @@
 
 #include "ide.h"
 
-       ide_hwif_t	ide_hwifs[MAX_HWIFS];		/* hwif info */
 static ide_hwgroup_t	*irq_to_hwgroup [16];
 static const byte	ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
 
 static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168};
 static const byte	default_irqs[MAX_HWIFS]     = {14, 15, 11, 10};
-static int		disallow_unmask = 0;	/* for buggy hardware */
+       int		ide_disallow_unmask = 0;	/* for buggy hardware */
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
@@ -303,6 +315,7 @@
 		ide_hwif_t *hwif = &ide_hwifs[h];
 
 		/* fill in any non-zero initial values */
+		hwif->index     = h;
 		hwif->noprobe	= (h > 1);
 		hwif->io_base	= default_io_base[h];
 		hwif->ctl_port	= hwif->io_base ? hwif->io_base+0x206 : 0x000;
@@ -357,10 +370,11 @@
 {
 	unsigned short io_base  = HWIF(drive)->io_base;
 	unsigned short data_reg = io_base+IDE_DATA_OFFSET;
+	byte io_32bit = drive->io_32bit;
 
-	if (drive->vlb_32bit) {
+	if (io_32bit) {
 #ifdef VLB_SYNC
-		if (drive->vlb_sync) {
+		if (io_32bit & 2) {
 			cli();
 			do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
 			insl(data_reg, buffer, wcount);
@@ -380,10 +394,11 @@
 {
 	unsigned short io_base  = HWIF(drive)->io_base;
 	unsigned short data_reg = io_base+IDE_DATA_OFFSET;
+	byte io_32bit = drive->io_32bit;
 
-	if (drive->vlb_32bit) {
+	if (io_32bit) {
 #ifdef VLB_SYNC
-		if (drive->vlb_sync) {
+		if (io_32bit & 2) {
 			cli();
 			do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
 			outsl(data_reg, buffer, wcount);
@@ -396,50 +411,6 @@
 		outsw(data_reg, buffer, wcount<<1);
 }
 
-#if SUPPORT_HT6560B
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- *
- * Apparently, systems with multiple CMD640 chips may need something similar..
- *
- * This algorithm courtesy of malafoss@snakemail.hut.fi
- *
- * At least one user has reported that this code can confuse the floppy
- * controller and/or driver -- perhaps this should be changed to use
- * a read-modify-write sequence, so as not to disturb other bits in the reg?
- */
-
-void ide_hwif_select (ide_hwif_t *hwif)
-{
-	static byte current_select = 0;
-
-	if (hwif->select != current_select) {
-		byte t;
-		unsigned long flags;
-		save_flags (flags);
-		cli();
-		current_select = hwif->select;
-		(void) inb(0x3e6);
-		(void) inb(0x3e6);
-		(void) inb(0x3e6);
-		/*
-		 * Avoid clobbering existing bits at 0x3e6:
-		 *	bit5 (0x20) - disables fast interface speed
-		 *	bit0 (0x01) - enables secondary interface
-		 *	we don't touch any other bits
-		 */
-		t = inb(0x3e6);
-		t &= (~0x21);
-		t |= (current_select & 0x21);
-		outb(t,0x3e6);
-		restore_flags (flags);
-	}
-}
-#endif /* SUPPORT_HT6560B */
-
 /*
  * This should get invoked any time we exit the driver to
  * wait for an interrupt response from a drive.  handler() points
@@ -713,12 +684,13 @@
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *rdrive = &hwif->drives[unit];
+		rdrive->special.all = 0;
 		rdrive->special.b.set_geometry = 1;
 		rdrive->special.b.recalibrate  = 1;
-		rdrive->special.b.set_multmode = 0;
 		if (OK_TO_RESET_CONTROLLER)
 			rdrive->mult_count = 0;
 		if (!rdrive->keep_settings) {
+			rdrive->using_dma = 0;
 			rdrive->mult_req = 0;
 			rdrive->unmask = 0;
 		}
@@ -900,14 +872,6 @@
 	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
 		rq->errors |= ERROR_RESET;	/* Mmmm.. timing problem */
 
-#ifdef CONFIG_BLK_DEV_TRITON
-	if (rq->errors > 3 && drive->using_dma) {	/* DMA troubles? */
-		drive->using_dma = 0;
-		printk("%s: DMA disabled\n", drive->name);
-		--rq->errors;
-		return;
-	}
-#endif /* CONFIG_BLK_DEV_TRITON */
 	if (rq->errors >= ERROR_MAX)
 		ide_end_request(0, HWGROUP(drive));
 	else {
@@ -1035,7 +999,7 @@
 }
 
 /*
- * write_intr() is the handler for disk multwrite interrupts
+ * multwrite_intr() is the handler for disk multwrite interrupts
  */
 static void multwrite_intr (ide_drive_t *drive)
 {
@@ -1134,12 +1098,12 @@
 
 /*
  * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- * commands to a drive.  It used to do much more, but has been scaled back
- * in recent updates, and could be completely eliminated with a bit more effort.
+ * commands to a drive.  It used to do much more, but has been scaled back.
  */
 static inline void do_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
+next:
 #ifdef DEBUG
 	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
@@ -1157,6 +1121,12 @@
 		if (drive->media == ide_disk) {
 			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
 		}
+	} else if (s->b.set_pio) {
+		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+		s->b.set_pio = 0;
+		if (tuneproc != NULL)
+			tuneproc(drive, drive->pio_req);
+		goto next;
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->media == ide_disk) {
@@ -1342,19 +1312,17 @@
 	}
 	block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
 #if FAKE_FDISK_FOR_EZDRIVE
-	if (block == 0 && drive->ezdrive) {
-		block = 1;
-		printk("%s: [EZD] accessing sector 1 in place of sector 0\n", drive->name);
-	}
+	if (block == 0 && drive->remap_0_to_1)
+		block = 1;  /* redirect MBR access to EZ-Drive partn table */
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
 	((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
+#ifdef CONFIG_BLK_DEV_HT6560B
+	if (hwif->selectproc)
+		hwif->selectproc (drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
 #if (DISK_RECOVERY_TIME > 0)
 	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
-#if SUPPORT_HT6560B
-	if (hwif->select)
-		ide_hwif_select (hwif);
-#endif
 
 #ifdef CONFIG_BLK_DEV_IDETAPE
 	POLL_HWIF_TAPE_DRIVE;	/* macro from ide-tape.h */
@@ -1377,7 +1345,6 @@
 				ide_do_rw_cdrom (drive, block);
 				return;
 #endif /* CONFIG_BLK_DEV_IDECD */
-
 #ifdef CONFIG_BLK_DEV_IDETAPE
 			case ide_tape:
 				idetape_do_request (drive, rq, block);
@@ -1546,14 +1513,14 @@
 	 */
 	do {
 		if (hwif->irq == irq) {
-#if SUPPORT_HT6560B
-			if (hwif->select)
-				ide_hwif_select (hwif);
-#endif
 			for (unit = 0; unit < MAX_DRIVES; ++unit) {
 				ide_drive_t *drive = &hwif->drives[unit];
 				if (!drive->present)
 					continue;
+#ifdef CONFIG_BLK_DEV_HT6560B
+				if (hwif->selectproc)
+					hwif->selectproc (drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
 				if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT))
 					(void) ide_dump_status(drive, "unexpected_intr", stat);
 				if ((stat & DRQ_STAT))
@@ -1561,6 +1528,10 @@
 			}
 		}
 	} while ((hwif = hwif->next) != hwgroup->hwif);
+#ifdef CONFIG_BLK_DEV_HT6560B
+	if (hwif->selectproc)
+		hwif->selectproc (hwgroup->drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
 }
 
 /*
@@ -1607,8 +1578,7 @@
 				if (drive->present)
 					return drive;
 			} else if (major == IDE0_MAJOR && unit < 4) {
-				printk("ide: probable bad entry for /dev/hd%c%d\n",
-				 'a' + unit, MINOR(i_rdev) & PARTN_MASK);
+				printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit);
 				printk("ide: to fix it, run:  /usr/src/linux/drivers/block/MAKEDEV.ide\n");
 			}
 			break;
@@ -1889,8 +1859,8 @@
 		case HDIO_GET_DMA:
 			return write_fs_long(arg, drive->using_dma);
 
-		case HDIO_GET_CHIPSET:
-			return write_fs_long(arg, drive->chipset);
+		case HDIO_GET_32BIT:
+			return write_fs_long(arg, drive->io_32bit);
 
 		case HDIO_GET_MULTCOUNT:
 			return write_fs_long(arg, drive->mult_count);
@@ -1918,7 +1888,7 @@
 		case HDIO_SET_NOWERR:
 			if (arg > 1)
 				return -EINVAL;
-		case HDIO_SET_CHIPSET:
+		case HDIO_SET_32BIT:
 			if (!suser())
 				return -EACCES;
 			if ((MINOR(inode->i_rdev) & PARTN_MASK))
@@ -1937,7 +1907,7 @@
 					drive->keep_settings = arg;
 					break;
 				case HDIO_SET_UNMASKINTR:
-					if (arg && disallow_unmask) {
+					if (arg && ide_disallow_unmask) {
 						restore_flags(flags);
 						return -EPERM;
 					}
@@ -1946,12 +1916,10 @@
 				case HDIO_SET_NOWERR:
 					drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
 					break;
-				case HDIO_SET_CHIPSET:
-					drive->chipset   = arg;
-					drive->vlb_32bit = (arg & 1);
-					drive->vlb_sync  = (arg & 2) >> 1;
+				case HDIO_SET_32BIT:
+					drive->io_32bit = arg;
 #ifndef VLB_SYNC
-					if (drive->vlb_sync)
+					if (arg & 2)
 						printk("%s: VLB_SYNC not supported by this kernel\n", drive->name);
 #endif
 					break;
@@ -1997,6 +1965,19 @@
 			}
 			return err;
 		}
+		case HDIO_SET_PIO_MODE:
+			if (!suser())
+				return -EACCES;
+			if (MINOR(inode->i_rdev) & PARTN_MASK)
+				return -EINVAL;
+			if (!HWIF(drive)->tuneproc)
+				return -ENOSYS;
+			save_flags(flags);
+			cli();
+			drive->pio_req = (int) arg;
+			drive->special.b.set_pio = 1;
+			restore_flags(flags);
+			return 0;
 
 		RO_IOCTLS(inode->i_rdev, arg);
 
@@ -2098,7 +2079,7 @@
 		byte type = (id->config >> 8) & 0x1f;
 		printk("%s: %s, ATAPI ", drive->name, id->model);
 		switch (type) {
-			case 0:				/* Early cdrom models used zero */
+			case 0:		/* Early cdrom models used zero */
 			case 5:
 #ifdef CONFIG_BLK_DEV_IDECD
 				printk ("CDROM drive\n");
@@ -2128,9 +2109,11 @@
 				break;
 #endif /* CONFIG_BLK_DEV_IDETAPE */
 			default:
+				drive->present = 0;
 				printk("Type %d - Unknown device\n", type);
 				return;
 		}
+		drive->present = 0;
 		printk("- not supported by this kernel\n");
 		return;
 	}
@@ -2208,17 +2191,12 @@
 			printk(", DMA");
 	}
 	printk("\n");
-#ifdef CONFIG_BLK_DEV_CMD640
-	{
-		extern void cmd640_tune_drive (ide_drive_t *);
-		cmd640_tune_drive(drive);	/* but can we tune a fish? */
-	}
-#endif
 }
 
 /*
  * Delay for *at least* 10ms.  As we don't know how much time is left
  * until the next tick occurs, we wait an extra tick to be safe.
+ * This is used only during the probing/polling for drives at boot time.
  */
 static void delay_10ms (void)
 {
@@ -2271,7 +2249,12 @@
 	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
 		cli();			/* some systems need this */
 		do_identify(drive, cmd); /* drive returned ID */
-		rc = 0;			/* success */
+		if (drive->present && (drive->media == ide_disk || drive->media == ide_cdrom)) {
+			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+			if (tuneproc != NULL && drive->autotune == 1)
+				tuneproc(drive, 255);	/* auto-tune PIO mode */
+		}
+		rc = 0;			/* drive responded with ID */
 	} else
 		rc = 2;			/* drive refused ID */
 	if (!HWIF(drive)->irq) {
@@ -2314,10 +2297,10 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-#if SUPPORT_HT6560B
-	if (HWIF(drive)->select)
-		ide_hwif_select (HWIF(drive));
-#endif
+#ifdef CONFIG_BLK_DEV_HT6560B
+	if (HWIF(drive)->selectproc)
+		HWIF(drive)->selectproc (drive);
+#endif /* CONFIG_BLK_DEV_HT6560B */
 	OUT_BYTE(drive->select.all,IDE_SELECT_REG);	/* select target drive */
 	delay_10ms();				/* wait for BUSY_STAT */
 	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
@@ -2435,99 +2418,6 @@
 	}
 }
 
-#if SUPPORT_DTC2278
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * From: mlord@bnr.ca -- this chipset is now forced to use the "serialize" feature,
- * which hopefully will make it more reliable to use.. maybe it has the same bugs
- * as the CMD640B and RZ1000 ??
- */
-
-#if SET_DTC2278_MODE4
-static void sub22 (char b, char c)
-{
-	int i;
-
-	for(i = 0; i < 3; ++i) {
-		inb(0x3f6);
-		outb_p(b,0xb0);
-		inb(0x3f6);
-		outb_p(c,0xb4);
-		inb(0x3f6);
-		if(inb(0xb4) == c) {
-			outb_p(7,0xb0);
-			inb(0x3f6);
-			return;	/* success */
-		}
-	}
-}
-#endif /* SET_DTC2278_MODE4 */
-
-static void init_dtc2278 (void)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-#if SET_DTC2278_MODE4
-	/*
-	 * This enables PIO mode4 (3?) on the first interface
-	 */
-	sub22(1,0xc3);
-	sub22(0,0xa0);
-#endif /* SET_DTC2278_MODE4 */
-	/*
-	 * This enables the second interface
-	 */
-	outb_p(4,0xb0);
-	inb(0x3f6);
-	outb_p(0x20,0xb4);
-	inb(0x3f6);
-	restore_flags(flags);
-}
-#endif /* SUPPORT_DTC2278 */
-
-#ifdef SUPPORT_QD6580
-/*
- * QDI QD6580 EIDE controller fast support by Colten Edwards.
- * no net access but I can be reached at pje120@cs.usask.ca
- *
- * I suppose that a IOCTL could be used for this and other
- * cards like it to modify the speed using hdparm.  Someday..
- */
-static void init_qd6580 (void)
-{
-	unsigned long flags;
-
-	/* looks like   0x4f is fast
-	 *              0x3f is medium
-	 *              0x2f is slower
-	 *              0x1f is slower yet
-	 *              ports are 0xb0 0xb2 and 0xb3
-	 */
-
-	save_flags(flags);
-	cli();
-	outb_p(0x8d,0xb0);
-	outb_p(0x0 ,0xb2);
-	outb_p(0x4f,0xb3);	/* select "fast" 0x4f */
-	inb(0x3f6);
-	restore_flags(flags);
-}
-#endif /* SUPPORT_QD6580 */
-
-#ifdef SUPPORT_UMC8672
-#include "umc8672.c"	/* until we tidy up the interface some more */
-#endif
-
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -2602,6 +2492,12 @@
  * "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
  * "hdx=cdrom"		: drive is present, and is a cdrom drive
  * "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
+ * "hdx=autotune"	: driver will attempt to tune interface speed
+ *				to the fastest PIO mode supported,
+ *				if possible for this drive only.
+ *				Not fully supported by all chipset types,
+ *				and quite likely to cause trouble with
+ *				older/odd IDE drives.
  *
  * "idex=noprobe"	: do not attempt to access/use this interface
  * "idex=base"		: probe for an interface at the addr specified,
@@ -2609,24 +2505,31 @@
  *				and "ctl" is assumed to be "base"+0x206
  * "idex=base,ctl"	: specify both base and ctl
  * "idex=base,ctl,irq"	: specify base, ctl, and irq number
+ * "idex=autotune"	: driver will attempt to tune interface speed
+ *				to the fastest PIO mode supported,
+ *				for all drives on this interface.
+ *				Not fully supported by all chipset types,
+ *				and quite likely to cause trouble with
+ *				older/odd IDE drives.
+ * "idex=noautotune"	: driver will NOT attempt to tune interface speed
+ *				This is the default for most chipsets,
+ *				except the cmd640.
  *
- * The following two are valid ONLY on ide0 or ide1,
+ * The following two are valid ONLY on ide0,
  * and the defaults for the base,ctl ports must not be altered.
  *
- * "idex=serialize"	: do not overlap operations on ide0 and ide1.
- * "idex=dtc2278"	: enables use of DTC2278 secondary i/f
- * "idex=ht6560b"	: enables use of HT6560B secondary i/f
- * "idex=cmd640_vlb"	: required for VLB cards with the CMD640 chip
+ * "ide0=serialize"	: do not overlap operations on ide0 and ide1.
+ * "ide0=dtc2278"	: probe/support DTC2278 interface
+ * "ide0=ht6560b"	: probe/support HT6560B interface
+ * "ide0=cmd640_vlb"	: *REQUIRED* for VLB cards with the CMD640 chip
  *			  (not for PCI -- automatically detected)
- *
- * This option is valid ONLY on ide0, and the defaults for the base,ctl ports
- * must not be altered.
- *
- * "ide0=qd6580"	: select "fast" interface speed on a qd6580 interface
+ * "ide0=qd6580"	: probe/support qd6580 interface
+ * "ide0=ali14xx"	: probe/support ali14xx chipsets (ALI M1439, M1443, M1445)
+ * "ide0=umc8672"	: probe/support umc8672 chipsets
  */
 void ide_setup (char *s)
 {
-	int vals[3];
+	int i, vals[3];
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
 	unsigned int hw, unit;
@@ -2640,7 +2543,8 @@
 	 * Look for drive options:  "hdx="
 	 */
 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
-		const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize", NULL};
+		const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize",
+						"autotune", "noautotune", NULL};
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
 		unit = unit % MAX_DRIVES;
@@ -2662,12 +2566,19 @@
 			case -4: /* "serialize" */
 				printk(" -- USE \"ide%c=serialize\" INSTEAD", '0'+hw);
 				goto do_serialize;
+			case -5: /* "autotune" */
+				drive->autotune = 1;
+				goto done;
+			case -6: /* "noautotune" */
+				drive->autotune = 2;
+				goto done;
 			case 3: /* cyl,head,sect */
 				drive->media	= ide_disk;
 				drive->cyl	= drive->bios_cyl  = vals[0];
 				drive->head	= drive->bios_head = vals[1];
 				drive->sect	= drive->bios_sect = vals[2];
 				drive->present	= 1;
+				drive->forced_geom = 1;
 				hwif->noprobe = 0;
 				goto done;
 			default:
@@ -2678,69 +2589,97 @@
 	 * Look for interface options:  "idex="
 	 */
 	if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) {
-		const char *ide_words[] = {"noprobe", "serialize", "dtc2278", "ht6560b",
-					"cmd640_vlb", "qd6580", "umc8672", NULL};
+		/*
+		 * Be VERY CAREFUL changing this: note hardcoded indexes below
+		 */
+		const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune",
+			"qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", NULL};
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
+		i = match_parm(&s[4], ide_words, vals, 3);
+
+		/*
+		 * Cryptic check to ensure chipset not already set for hwif:
+		 */
+		if (i != -1 && i != -2) {
+			if (hwif->chipset != ide_unknown)
+				goto bad_option;
+			if (i < 0 && ide_hwifs[1].chipset != ide_unknown)
+				goto bad_option;
+		}
+		/*
+		 * Interface keywords work only for ide0:
+		 */
+		if (i <= -6 && hw != 0)
+			goto bad_hwif;
 
-		switch (match_parm(&s[4], ide_words, vals, 3)) {
-#if SUPPORT_UMC8672
-			case -7: /* "umc8672" */
-				if (hw != 0) goto bad_hwif;
+		switch (i) {
+#ifdef CONFIG_BLK_DEV_ALI14XX
+			case -10: /* "ali14xx" */
+			{
+				extern void init_ali14xx (void);
+				init_ali14xx();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_ALI14XX */
+#ifdef CONFIG_BLK_DEV_UMC8672
+			case -9: /* "umc8672" */
+			{
+				extern void init_umc8672 (void);
 				init_umc8672();
 				goto done;
-#endif /* SUPPORT_UMC8672 */
-#if SUPPORT_QD6580
-			case -6: /* "qd6580" */
-				if (hw != 0) goto bad_hwif;
-				init_qd6580();
+			}
+#endif /* CONFIG_BLK_DEV_UMC8672 */
+#ifdef CONFIG_BLK_DEV_DTC2278
+			case -8: /* "dtc2278" */
+			{
+				extern void init_dtc2278 (void);
+				init_dtc2278();
 				goto done;
-#endif /* SUPPORT_QD6580 */
+			}
+#endif /* CONFIG_BLK_DEV_DTC2278 */
 #ifdef CONFIG_BLK_DEV_CMD640
-			case -5: /* "cmd640_vlb" */
-				{
-				extern int cmd640_vlb;
-				if (hw > 1) goto bad_hwif;
-					cmd640_vlb = 1;
-				}
-				break;
+			case -7: /* "cmd640_vlb" */
+			{
+				extern int cmd640_vlb; /* flag for cmd640.c */
+				cmd640_vlb = 1;
+				goto done;
+			}
 #endif /* CONFIG_BLK_DEV_CMD640 */
-#if SUPPORT_HT6560B
-			case -4: /* "ht6560b" */
-				if (hw > 1) goto bad_hwif;
-				/*
-				 * Using 0x1c and 0x1d apparently selects a
-				 * faster interface speed than 0x3c and 0x3d.
-				 * (bit5 (0x20) selects fast speed when set)
-				 * (bit0 (0x01) selects second interface)
-				 *
-				 * Need to set these per-drive, rather than
-				 * per-hwif, and also add an ioctl to select
-				 * between them.
-				 */
-				if (check_region(0x3e6,1)) {
-					printk(" -- HT6560 PORT 0x3e6 ALREADY IN USE");
-					goto done;
-				}
-				request_region(0x3e6, 1, hwif->name);
-				ide_hwifs[0].select = 0x1c;
-				ide_hwifs[1].select = 0x3d;
-				goto do_serialize;
-#endif /* SUPPORT_HT6560B */
-#if SUPPORT_DTC2278
-			case -3: /* "dtc2278" */
-				if (hw > 1) goto bad_hwif;
-				init_dtc2278();
-				goto do_serialize;
-#endif /* SUPPORT_DTC2278 */
+#ifdef CONFIG_BLK_DEV_HT6560B
+			case -6: /* "ht6560b" */
+			{
+				extern void init_ht6560b (void);
+				init_ht6560b();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_HT6560B */
+#if CONFIG_BLK_DEV_QD6580
+			case -5: /* "qd6580" (no secondary i/f) */
+			{
+				extern void init_qd6580 (void);
+				init_qd6580();
+				goto done;
+			}
+#endif /* CONFIG_BLK_DEV_QD6580 */
+			case -4: /* "noautotune" */
+				hwif->drives[0].autotune = 2;
+				hwif->drives[1].autotune = 2;
+				goto done;
+			case -3: /* "autotune" */
+				hwif->drives[0].autotune = 1;
+				hwif->drives[1].autotune = 1;
+				goto done;
 			case -2: /* "serialize" */
 			do_serialize:
 				if (hw > 1) goto bad_hwif;
 				ide_hwifs[0].serialized = 1;
 				goto done;
+
 			case -1: /* "noprobe" */
 				hwif->noprobe = 1;
 				goto done;
+
 			case 1:	/* base */
 				vals[1] = vals[0] + 0x206; /* default ctl */
 			case 2: /* base,ctl */
@@ -2749,8 +2688,14 @@
 				hwif->io_base  = vals[0];
 				hwif->ctl_port = vals[1];
 				hwif->irq      = vals[2];
-				hwif->noprobe = 0;
+				hwif->noprobe  = 0;
+				hwif->chipset  = ide_generic;
 				goto done;
+
+			case 0: goto bad_option;
+			default:
+				printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
+				return;
 		}
 	}
 bad_option:
@@ -2764,19 +2709,35 @@
 
 /*
  * 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.
+ * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
+ *
+ * The second parameter, "xparm", determines exactly how the translation 
+ * will be handled:
+ *		 0 = convert to CHS with fewer than 1024 cyls
+ *			using the same method as Ontrack DiskManager.
+ *		 1 = same as "0", plus offset everything by 63 sectors.
+ *		-1 = similar to "0", plus redirect sector 0 to sector 1.
+ *		>1 = convert to a CHS geometry with "xparm" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not 
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
  */
-int ide_xlate_1024 (kdev_t i_rdev, int offset, const char *msg)
+int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
 {
 	ide_drive_t *drive;
 	static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
 	const byte *heads = head_vals;
 	unsigned long tracks;
 
-	if ((drive = get_info_ptr(i_rdev)) == NULL)
+	if ((drive = get_info_ptr(i_rdev)) == NULL || 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 (drive->id) {
 		drive->cyl  = drive->id->cyls;
 		drive->head = drive->id->heads;
@@ -2789,25 +2750,31 @@
 
 	tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
 	drive->bios_sect = 63;
-	while (drive->bios_cyl >= 1024) {
-		drive->bios_head = *heads;
+	if (xparm > 1) {
+		drive->bios_head = xparm;
 		drive->bios_cyl = tracks / drive->bios_head;
-		if (0 == *++heads)
-			break;
-	}
-	if (offset) {
+	} else {
+		while (drive->bios_cyl >= 1024) {
+			drive->bios_head = *heads;
+			drive->bios_cyl = tracks / drive->bios_head;
+			if (0 == *++heads)
+				break;
+		}
 #if FAKE_FDISK_FOR_EZDRIVE
-		if (offset == -1)
-			drive->ezdrive = 1;
-		else
+		if (xparm == -1) {
+			drive->remap_0_to_1 = 1;
+			msg = "0->1";
+		} else
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
-		{
+		if (xparm == 1) {
 			drive->sect0 = 63;
 			drive->bios_cyl = (tracks - 1) / drive->bios_head;
+			msg = "+63";
 		}
+		printk("[remap %s] ", msg);
 	}
 	drive->part[0].nr_sects = current_capacity(drive);
-	printk("%s [%d/%d/%d]", msg, drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return 1;
 }
 
@@ -2940,37 +2907,7 @@
 };
 
 #ifdef CONFIG_PCI
-
-#if SUPPORT_RZ1000
-
-static void ide_pci_access_error (int rc)
-{
-	printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
-}
-
-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, &reg))) {
-		ide_pci_access_error (rc);
-	} else if (!(reg & 1)) {
-		printk("not enabled\n");
-	} else {
-		if ((rc = pcibios_read_config_word(bus, fn, 0x40, &reg))
-		 || (rc =  pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff)))
-		{
-			ide_pci_access_error (rc);
-			ide_hwifs[0].serialized = 1;
-			disallow_unmask = 1;
-			printk("serialized, disabled unmasking\n");
-		} else
-			printk("disabled read-ahead\n");
-	}
-}
-#endif /* SUPPORT_RZ1000 */
+#if defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON)
 
 typedef void (ide_pci_init_proc_t)(byte, byte);
 
@@ -2992,27 +2929,44 @@
 	restore_flags(flags);
 }
 
+#endif /* defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON) */
+#endif /* CONFIG_PCI */
+
 /*
  * 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)
+static void probe_for_hwifs (void)
 {
-#if SUPPORT_RZ1000
-	ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0);
-#endif
-#ifdef CONFIG_BLK_DEV_TRITON
+#ifdef CONFIG_PCI
 	/*
-	 * Apparently the BIOS32 services on Intel motherboards are buggy,
-	 * and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us.
-	 * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0, and then add 1.
+	 * Find/initialize PCI IDE interfaces
 	 */
-	ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
+	if (pcibios_present()) {
+#ifdef CONFIG_BLK_DEV_RZ1000
+		ide_pci_init_proc_t init_rz1000;
+		ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0);
+#endif /* CONFIG_BLK_DEV_RZ1000 */
+#ifdef CONFIG_BLK_DEV_TRITON
+		/*
+		 * Apparently the BIOS32 services on Intel motherboards are
+		 * buggy and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us.
+		 * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0,
+		 * and then add 1.
+		 */
+		ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
+#endif /* CONFIG_BLK_DEV_TRITON */
+	}
+#endif /* CONFIG_PCI */
+#ifdef CONFIG_BLK_DEV_CMD640
+	{
+		extern void ide_probe_for_cmd640x (void);
+		ide_probe_for_cmd640x();
+	}
 #endif
 }
-#endif /* CONFIG_PCI */
 
 /*
  * This is gets invoked once during initialization, to set *everything* up
@@ -3023,22 +2977,9 @@
 
 	init_ide_data ();
 	/*
-	 * First, we determine what hardware is present
-	 */
-
-#ifdef CONFIG_PCI
-	/*
-	 * Find/initialize PCI IDE interfaces
+	 * Probe for special "known" interface chipsets
 	 */
-	if (pcibios_present())
-		ide_init_pci ();
-#endif /* CONFIG_PCI */
-#ifdef CONFIG_BLK_DEV_CMD640
-	{
-		extern void ide_probe_for_cmd640x (void);
-		ide_probe_for_cmd640x();
-	}
-#endif
+	probe_for_hwifs ();
 
 	/*
 	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this