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

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

diff -u --recursive --new-file v2.0.10/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.46  Jul 23, 1996
+ *  linux/drivers/block/ide.c	Version 5.49  Aug  4, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -246,6 +246,16 @@
  *			include mc68000 patches from Geert Uytterhoeven
  *			add Gadi's fix for PCMCIA cdroms
  * Version 5.46		remove the mc68000 #ifdefs for 2.0.x
+ * Version 5.47		fix set_tune race condition
+ *			fix bug in earlier PCMCIA cdrom update
+ * Version 5.48		if def'd, invoke CMD640_DUMP_REGS when irq probe fails
+ *			lengthen the do_reset1() pulse, for laptops
+ *			add idebus=xx parameter for cmd640 and ali chipsets
+ *			no_unmask flag now per-drive instead of per-hwif
+ *			fix tune_req so that it gets done immediately
+ *			fix missing restore_flags() in ide_ioctl
+ *			prevent use of io_32bit on cmd640 with no prefetch
+ * Version 5.49		fix minor quirks in probing routines
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -294,6 +304,13 @@
 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	idebus_parameter; /* holds the "idebus=" parameter */
+static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+
+/*
+ * This is declared extern in ide.h, for access by other IDE modules:
+ */
+ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
@@ -402,6 +419,32 @@
 
 	for (index = 0; index < MAX_HWIFS; ++index)
 		init_hwif_data(index);
+
+	idebus_parameter = 0;
+	system_bus_speed = 0;
+}
+
+/*
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in Mhz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time through.
+ */
+int ide_system_bus_speed (void)
+{
+	if (!system_bus_speed) {
+		if (idebus_parameter)
+			system_bus_speed = idebus_parameter;	/* user supplied value */
+#ifdef CONFIG_PCI
+		else if (pcibios_present())
+			system_bus_speed = 40;	/* safe default value for PCI */
+#endif /* CONFIG_PCI */
+		else
+			system_bus_speed = 50;	/* safe default value for VESA and PCI */
+		printk("ide: Assuming %dMhz system bus speed for PIO modes; override with idebus=xx\n", system_bus_speed);
+	}
+	return system_bus_speed;
 }
 
 #if SUPPORT_VLB_SYNC
@@ -770,9 +813,9 @@
 	 * recover from reset very quickly, saving us the first 50ms wait time.
 	 */
 	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
-	udelay(5);			/* more than enough time */
+	udelay(10);			/* more than enough time */
 	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
-	udelay(5);			/* more than enough time */
+	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler (drive, &reset_pollfunc, HZ/20);
 #endif	/* OK_TO_RESET_CONTROLLER */
@@ -1183,7 +1226,7 @@
 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
@@ -1201,12 +1244,11 @@
 		s->b.recalibrate = 0;
 		if (drive->media == ide_disk && !IS_PROMISE_DRIVE)
 			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
-	} else if (s->b.set_pio) {
+	} else if (s->b.set_tune) {
 		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-		s->b.set_pio = 0;
+		s->b.set_tune = 0;
 		if (tuneproc != NULL)
-			tuneproc(drive, drive->pio_req);
-		goto next;
+			tuneproc(drive, drive->tune_req);
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->media == ide_disk) {
@@ -1639,6 +1681,7 @@
 				if (!drive->present)
 					continue;
 				SELECT_DRIVE(hwif,drive);
+				udelay(100);  /* Ugly, but wait_stat() may not be safe here */
 				if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {
 					/* Try to not flood the console with msgs */
 					static unsigned long last_msgtime = 0;
@@ -1653,6 +1696,7 @@
 		}
 	} while ((hwif = hwif->next) != hwgroup->hwif);
 	SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */
+	udelay(100);  /* Ugly, but wait_stat() may not be safe here */
 }
 
 /*
@@ -1917,10 +1961,6 @@
 	if (drive->media != ide_disk)
 		drive->part[0].start_sect = -1;
 	resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
-#ifdef CONFIG_BLK_DEV_IDECD
-	if (drive->media == ide_cdrom)
-		ide_cdrom_setup(drive);
-#endif /* CONFIG_BLK_DEV_IDECD */
 
 	drive->busy = 0;
 	wake_up(&drive->wqueue);
@@ -2046,7 +2086,7 @@
 					drive->keep_settings = arg;
 					break;
 				case HDIO_SET_UNMASKINTR:
-					if (arg && HWIF(drive)->no_unmask) {
+					if (arg && drive->no_unmask) {
 						restore_flags(flags);
 						return -EPERM;
 					}
@@ -2056,8 +2096,14 @@
 					drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
 					break;
 				case HDIO_SET_32BIT:
-					if (arg > (1 + (SUPPORT_VLB_SYNC<<1)))
+					if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) {
+						restore_flags(flags);
 						return -EINVAL;
+					}
+					if (arg && drive->no_io_32bit) {
+						restore_flags(flags);
+						return -EPERM;
+					}
 					drive->io_32bit = arg;
 #ifdef CONFIG_BLK_DEV_DTC2278
 					if (HWIF(drive)->chipset == ide_dtc2278)
@@ -2123,9 +2169,14 @@
 				return -ENOSYS;
 			save_flags(flags);
 			cli();
-			drive->pio_req = (int) arg;
-			drive->special.b.set_pio = 1;
+			if (drive->special.b.set_tune) {
+				restore_flags(flags);
+				return -EBUSY;
+			}
+			drive->tune_req = (byte) arg;
+			drive->special.b.set_tune = 1;
 			restore_flags(flags);
+			(void) ide_do_drive_cmd (drive, &rq, ide_wait);
 			return 0;
 
 		RO_IOCTLS(inode->i_rdev, arg);
@@ -2431,11 +2482,6 @@
 		save_flags(flags);
 		cli();			/* some systems need this */
 		do_identify(drive, cmd); /* drive returned ID */
-		if (drive->present && drive->media != ide_tape) {
-			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 */
 		(void) GET_STAT();	/* clear drive IRQ */
 		restore_flags(flags);
@@ -2455,12 +2501,12 @@
 		} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
 			printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
 #ifdef CONFIG_BLK_DEV_CMD640
+#ifdef CMD640_DUMP_REGS
 			if (HWIF(drive)->chipset == ide_cmd640) {
-				extern byte (*get_cmd640_reg)(int);
 				printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
-				printk("%s: cmd640 reg 09h == 0x%02x\n", drive->name, get_cmd640_reg(9));
-				printk("%s: cmd640 reg 51h == 0x%02x\n", drive->name, get_cmd640_reg(0x51));
+				CMD640_DUMP_REGS;
 			}
+#endif /* CMD640_DUMP_REGS */
 #endif /* CONFIG_BLK_DEV_CMD640 */
 		}
 	}
@@ -2486,7 +2532,7 @@
 static int do_probe (ide_drive_t *drive, byte cmd)
 {
 	int rc;
-	ide_hwif_t *hwif;
+	ide_hwif_t *hwif = HWIF(drive);
 #ifdef CONFIG_BLK_DEV_IDEATAPI
 	if (drive->present) {	/* avoid waiting for inappropriate probes */
 		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
@@ -2498,12 +2544,12 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	hwif = HWIF(drive);
 	SELECT_DRIVE(hwif,drive);
-	OUT_BYTE(drive->select.all,IDE_SELECT_REG);	/* select target drive */
-	delay_10ms();				/* wait for BUSY_STAT */
+	delay_10ms();		/* allow BUSY_STAT to assert & clear */
+	delay_10ms();
 	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		OUT_BYTE(0xa0,IDE_SELECT_REG);	/* exit with drive0 selected */
+		delay_10ms();		/* allow BUSY_STAT to assert & clear */
 		return 3;    /* no i/f present: avoid killing ethernet cards */
 	}
 
@@ -2665,6 +2711,14 @@
 			}
 		}
 		restore_flags(flags);
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present && drive->media != ide_tape) {
+				ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+				if (tuneproc != NULL && drive->autotune == 1)
+					tuneproc(drive, 255);	/* auto-tune PIO mode */
+			}
+		}
 	}
 }
 
@@ -2701,9 +2755,11 @@
 		 * Try matching against the supplied keywords,
 		 * and return -(index+1) if we match one
 		 */
-		for (i = 0; *keywords != NULL; ++i) {
-			if (!strcmp(s, *keywords++))
-				return -(i+1);
+		if (keywords != NULL) {
+			for (i = 0; *keywords != NULL; ++i) {
+				if (!strcmp(s, *keywords++))
+					return -(i+1);
+			}
 		}
 		/*
 		 * Look for a series of no more than "max_vals"
@@ -2750,6 +2806,15 @@
  *				and quite likely to cause trouble with
  *				older/odd IDE drives.
  *
+ * "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in Mhz,
+ *				where "xx" is between 25 and 66 inclusive,
+ *				used when tuning chipset PIO modes.
+ *				For PCI bus, 25 is correct for a P75 system,
+ *				30 is correct for P90,P120,P180 systems,
+ *				and 33 is used for P100,P133,P166 systems.
+ *				If in doubt, use idebus=33 for PCI.
+ *				As for VLB, it is safest to not specify it.
+ *
  * "idex=noprobe"	: do not attempt to access/use this interface
  * "idex=base"		: probe for an interface at the addr specified,
  *				where "base" is usually 0x1f0 or 0x170
@@ -2838,10 +2903,25 @@
 				goto bad_option;
 		}
 	}
+
+	if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
+		goto bad_option;
+	/*
+	 * Look for bus speed option:  "idebus="
+	 */
+	if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
+		if (match_parm(&s[6], NULL, vals, 1) != 1)
+			goto bad_option;
+		if (vals[0] >= 25 && vals[0] <= 66)
+			idebus_parameter = vals[0];
+		else
+			printk(" -- BAD BUS SPEED! Expected value from 25 to 66");
+		goto done;
+	}
 	/*
 	 * Look for interface options:  "idex="
 	 */
-	if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) {
+	if (s[3] >= '0' && s[3] <= max_hwif) {
 		/*
 		 * Be VERY CAREFUL changing this: note hardcoded indexes below
 		 */
@@ -2854,17 +2934,19 @@
 		/*
 		 * Cryptic check to ensure chipset not already set for hwif:
 		 */
-		if (i >= 0 || i <= -5) {
+		if (i > 0 || i <= -5) {
 			if (hwif->chipset != ide_unknown)
 				goto bad_option;
-			if (i < 0 && ide_hwifs[1].chipset != ide_unknown)
-				goto bad_option;
+			if (i <= -5) {
+				if (ide_hwifs[1].chipset != ide_unknown)
+					goto bad_option;
+				/*
+				 * Interface keywords work only for ide0:
+				 */
+				if (hw != 0)
+					goto bad_hwif;
+			}
 		}
-		/*
-		 * Interface keywords work only for ide0:
-		 */
-		if (i <= -5 && hw != 0)
-			goto bad_hwif;
 
 		switch (i) {
 #ifdef CONFIG_BLK_DEV_PROMISE
@@ -3329,6 +3411,7 @@
 {
 	int index, i, rc = -1;
 	ide_hwif_t *hwif;
+	ide_drive_t *drive;
 	unsigned long flags;
 
 	save_flags(flags);
@@ -3346,8 +3429,14 @@
 			probe_hwif(hwif);
 			if (!hwif_init(index))
 				break;
-			for (i = 0; i < hwif->gd->nr_real; i++)
+			for (i = 0; i < hwif->gd->nr_real; i++) {
+				drive = &hwif->drives[i];
 				revalidate_disk(MKDEV(hwif->major, i<<PARTN_BITS));
+#ifdef CONFIG_BLK_DEV_IDECD
+				if (drive->present && drive->media == ide_cdrom)
+					ide_cdrom_setup(drive);
+#endif /* CONFIG_BLK_DEV_IDECD */
+			}
 			rc = index;
 			break;
 		}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov