PATCH: update ide core
Alan Cox (alan@lxorguk.ukuu.org.uk)
Fri, 21 Mar 2003 20:45:21 GMT
- New style ide-default driver
- Don't attach non existant drives
- DRIVER()==NULL checks can go
- Ioctl checks that were missing are now in
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux-2.5.65/drivers/ide/ide.c linux-2.5.65-ac2/drivers/ide/ide.c
--- linux-2.5.65/drivers/ide/ide.c	2003-03-03 19:20:09.000000000 +0000
+++ linux-2.5.65-ac2/drivers/ide/ide.c	2003-03-20 18:23:19.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide.c		Version 7.00alpha1	August 19 2002
+ *  linux/drivers/ide/ide.c		Version 7.00beta2	Mar 05 2003
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -177,6 +177,7 @@
 static int system_bus_speed;	/* holds what we think is VESA/PCI bus speed */
 static int initializing;	/* set while initializing built-in drivers */
 
+DECLARE_MUTEX(ide_cfg_sem);
 spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
@@ -214,6 +215,8 @@
 EXPORT_SYMBOL(idetape);
 EXPORT_SYMBOL(idescsi);
 
+extern ide_driver_t idedefault_driver;
+static void setup_driver_defaults (ide_drive_t *drive);
 
 /*
  * Do not even *think* about calling this!
@@ -271,6 +274,8 @@
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
 		drive->using_dma		= 0;
 		drive->is_flash			= 0;
+		drive->driver			= &idedefault_driver;
+		setup_driver_defaults(drive);
 		drive->vdma			= 0;
 		INIT_LIST_HEAD(&drive->list);
 	}
@@ -349,9 +354,7 @@
 {
 	if (!drive->present)
 		return 0;
-	if (drive->driver != NULL)
-		return DRIVER(drive)->capacity(drive);
-	return 0;
+	return DRIVER(drive)->capacity(drive);
 }
 
 EXPORT_SYMBOL(current_capacity);
@@ -580,17 +583,19 @@
  
 void ide_unregister (unsigned int index)
 {
-	ide_drive_t *drive, *d;
+	ide_drive_t *drive;
 	ide_hwif_t *hwif, *g;
 	ide_hwgroup_t *hwgroup;
 	int irq_count = 0, unit, i;
-	unsigned long flags;
 	ide_hwif_t old_hwif;
 
 	if (index >= MAX_HWIFS)
 		BUG();
 		
-	spin_lock_irqsave(&ide_lock, flags);
+	BUG_ON(in_interrupt());
+	BUG_ON(irqs_disabled());
+	down(&ide_cfg_sem);
+	spin_lock_irq(&ide_lock);
 	hwif = &ide_hwifs[index];
 	if (!hwif->present)
 		goto abort;
@@ -600,25 +605,23 @@
 			continue;
 		if (drive->usage)
 			goto abort;
-		if (drive->driver != NULL && DRIVER(drive)->shutdown(drive))
+		if (DRIVER(drive)->shutdown(drive))
 			goto abort;
 	}
 	hwif->present = 0;
 	
-	spin_unlock_irqrestore(&ide_lock, flags);
+	spin_unlock_irq(&ide_lock);
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
 		if (!drive->present)
 			continue;
-		if (drive->driver != NULL)
-			DRIVER(drive)->cleanup(drive);
+		DRIVER(drive)->cleanup(drive);
 	}
 	
 #ifdef CONFIG_PROC_FS
 	destroy_proc_ide_drives(hwif);
 #endif
-	spin_lock_irqsave(&ide_lock, flags);
 	hwgroup = hwif->hwgroup;
 
 	/*
@@ -633,6 +636,7 @@
 	if (irq_count == 1)
 		free_irq(hwif->irq, hwgroup);
 
+	spin_lock_irq(&ide_lock);
 	/*
 	 * Note that we only release the standard ports,
 	 * and do not even try to handle any extra ports
@@ -644,7 +648,6 @@
 	 * Remove us from the hwgroup, and free
 	 * the hwgroup if we were the only member
 	 */
-	d = hwgroup->drive;
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		drive = &hwif->drives[i];
 		if (drive->de) {
@@ -653,11 +656,23 @@
 		}
 		if (!drive->present)
 			continue;
-		while (hwgroup->drive->next != drive)
-			hwgroup->drive = hwgroup->drive->next;
-		hwgroup->drive->next = drive->next;
-		if (hwgroup->drive == drive)
+		if (drive == drive->next) {
+			/* special case: last drive from hwgroup. */
+			BUG_ON(hwgroup->drive != drive);
 			hwgroup->drive = NULL;
+		} else {
+			ide_drive_t *walk;
+
+			walk = hwgroup->drive;
+			while (walk->next != drive)
+				walk = walk->next;
+			walk->next = drive->next;
+			if (hwgroup->drive == drive) {
+				hwgroup->drive = drive->next;
+				hwgroup->hwif = HWIF(hwgroup->drive);
+			}
+		}
+		BUG_ON(hwgroup->drive == drive);
 		if (drive->id != NULL) {
 			kfree(drive->id);
 			drive->id = NULL;
@@ -665,15 +680,28 @@
 		drive->present = 0;
 		blk_cleanup_queue(&drive->queue);
 	}
-	if (d->present)
-		hwgroup->drive = d;
-	while (hwgroup->hwif->next != hwif)
-		hwgroup->hwif = hwgroup->hwif->next;
-	hwgroup->hwif->next = hwif->next;
-	if (hwgroup->hwif == hwif)
+	if (hwif->next == hwif) {
 		kfree(hwgroup);
-	else
-		hwgroup->hwif = HWIF(hwgroup->drive);
+		BUG_ON(hwgroup->hwif != hwif);
+	} else {
+		/* There is another interface in hwgroup.
+		 * Unlink us, and set hwgroup->drive and ->hwif to
+		 * something sane.
+		 */
+		g = hwgroup->hwif;
+		while (g->next != hwif)
+			g = g->next;
+		g->next = hwif->next;
+		if (hwgroup->hwif == hwif) {
+			/* Chose a random hwif for hwgroup->hwif.
+			 * It's guaranteed that there are no drives
+			 * left in the hwgroup.
+			 */
+			BUG_ON(hwgroup->drive != NULL);
+			hwgroup->hwif = g;
+		}
+		BUG_ON(hwgroup->hwif == hwif);
+	}
 
 #if !defined(CONFIG_DMA_NONPCI)
 	if (hwif->dma_base) {
@@ -813,7 +841,8 @@
 
 	hwif->hwif_data			= old_hwif.hwif_data;
 abort:
-	spin_unlock_irqrestore(&ide_lock, flags);
+	spin_unlock_irq(&ide_lock);
+	up(&ide_cfg_sem);
 }
 
 EXPORT_SYMBOL(ide_unregister);
@@ -998,7 +1027,7 @@
 	setting->set = set;
 	
 	setting->next = *p;
-	if (drive->driver)
+	if (drive->driver != &idedefault_driver)
 		setting->auto_remove = 1;
 	*p = setting;
 	up(&ide_setting_sem);
@@ -1304,15 +1334,9 @@
 		return 0;
 	}
 
-	if (drive->driver != NULL) {
-#if 0
-		ide_unregister_subdriver(drive);
-#else
-		if (DRIVER(drive)->cleanup(drive)) {
-			drive->scsi = 0;
-			return 0;
-		}
-#endif
+	if (DRIVER(drive)->cleanup(drive)) {
+		drive->scsi = 0;
+		return 0;
 	}
 
 	drive->scsi = (u8) arg;
@@ -1353,7 +1377,7 @@
 	mdelay(50);
 #else
 	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/20);
+	schedule_timeout(1+HZ/20);
 #endif /* CONFIG_BLK_DEV_IDECS */
 }
 
@@ -1375,7 +1399,7 @@
 {
 	if (!drive->present || drive->usage || drive->dead)
 		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+	if (DRIVER(drive)->cleanup(drive))
 		goto abort;
 	strncpy(drive->driver_req, driver, 9);
 	if (ata_attach(drive)) {
@@ -1387,7 +1411,7 @@
 	} else {
 		drive->driver_req[0] = 0;
 	}
-	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+	if (DRIVER(drive)!= &idedefault_driver && !strcmp(DRIVER(drive)->name, driver))
 		return 0;
 abort:
 	return 1;
@@ -1412,10 +1436,12 @@
 		spin_lock(&drivers_lock);
 		module_put(driver->owner);
 	}
+	drive->gendev.driver = &idedefault_driver.gen_driver;
 	spin_unlock(&drivers_lock);
+	if(idedefault_driver.attach(drive) != 0)
+		panic("ide: default attach failed");
 	spin_lock(&drives_lock);
 	list_add_tail(&drive->list, &ata_unused);
-	drive->gendev.driver = NULL;
 	spin_unlock(&drives_lock);
 	return 1;
 }
@@ -1476,7 +1502,7 @@
 		case HDIO_GET_IDENTITY:
 			if (bdev != bdev->bd_contains)
 				return -EINVAL;
-			if (drive->id == NULL)
+			if (drive->id_read == 0)
 				return -ENOMSG;
 			if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
 				return -EFAULT;
@@ -1521,7 +1547,7 @@
 		case HDIO_SCAN_HWIF:
 		{
 			int args[3];
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (!capable(CAP_SYS_RAWIO)) return -EACCES;
 			if (copy_from_user(args, (void *)arg, 3 * sizeof(int)))
 				return -EFAULT;
 			if (ide_register(args[0], args[1], args[2]) == -1)
@@ -1529,14 +1555,12 @@
 			return 0;
 		}
 	        case HDIO_UNREGISTER_HWIF:
-			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+			if (!capable(CAP_SYS_RAWIO)) return -EACCES;
 			/* (arg > MAX_HWIFS) checked in function */
 			ide_unregister(arg);
 			return 0;
 		case HDIO_SET_NICE:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (drive->driver == NULL)
-				return -EPERM;
 			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
 				return -EPERM;
 			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
@@ -1550,18 +1574,26 @@
 		{
 			unsigned long flags;
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-#if 1
+			
+			/*
+			 *	Abort the current command on the
+			 *	group if there is one, taking
+			 *	care not to allow anything else
+			 *	to be queued and to die on the
+			 *	spot if we miss one somehow
+			 */
+
 			spin_lock_irqsave(&ide_lock, flags);
-			if ( HWGROUP(drive)->handler != NULL) {
-				printk(KERN_ERR "%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler);
-				(void) HWGROUP(drive)->handler(drive);
-//				HWGROUP(drive)->handler = NULL;
-				HWGROUP(drive)->expiry	= NULL;
-				del_timer(&HWGROUP(drive)->timer);
-			}
+			
+			DRIVER(drive)->abort(drive, "drive reset");
+			if(HWGROUP(drive)->handler)
+				BUG();
+				
+			/* Ensure nothing gets queued after we
+			   drop the lock. Reset will clear the busy */
+		   
+			HWGROUP(drive)->busy = 1;
 			spin_unlock_irqrestore(&ide_lock, flags);
-
-#endif
 			(void) ide_do_reset(drive);
 			if (drive->suspend_reset) {
 /*
@@ -1593,9 +1625,8 @@
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			if (HWIF(drive)->busproc)
-				HWIF(drive)->busproc(drive, (int)arg);
-			return 0;
-
+				return HWIF(drive)->busproc(drive, (int)arg);
+			return -EOPNOTSUPP;
 		default:
 			return -EINVAL;
 	}
@@ -2193,7 +2224,7 @@
  
 static int default_shutdown(ide_drive_t *drive)
 {
-	if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) {
+	if (drive->usage || DRIVER(drive)->busy) {
 		return 1;
 	}
 	drive->dead = 1;
@@ -2261,6 +2292,11 @@
 	return 0;
 }
 
+static ide_startstop_t default_abort (ide_drive_t *drive, const char *msg)
+{
+	return ide_abort(drive, msg);
+}
+
 static void setup_driver_defaults (ide_drive_t *drive)
 {
 	ide_driver_t *d = drive->driver;
@@ -2272,6 +2308,7 @@
 	if (d->end_request == NULL)	d->end_request = default_end_request;
 	if (d->sense == NULL)		d->sense = default_sense;
 	if (d->error == NULL)		d->error = default_error;
+	if (d->abort == NULL)		d->abort = default_abort;
 	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
 	if (d->capacity == NULL)	d->capacity = default_capacity;
 	if (d->special == NULL)		d->special = default_special;
@@ -2282,9 +2319,11 @@
 {
 	unsigned long flags;
 	
+	BUG_ON(drive->driver == NULL);
+	
 	spin_lock_irqsave(&ide_lock, flags);
 	if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
-	    drive->driver != NULL || drive->usage || drive->dead) {
+	    drive->driver != &idedefault_driver || drive->usage || drive->dead) {
 		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
 	}
@@ -2294,6 +2333,7 @@
 	spin_lock(&drives_lock);
 	list_add(&drive->list, &driver->drives);
 	spin_unlock(&drives_lock);
+//	printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name);
 	if ((drive->autotune == IDE_TUNE_DEFAULT) ||
 		(drive->autotune == IDE_TUNE_AUTO)) {
 		/* DMA timings and setup moved to ide-probe.c */
@@ -2318,7 +2358,7 @@
 	unsigned long flags;
 	
 	spin_lock_irqsave(&ide_lock, flags);
-	if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) {
+	if (drive->usage || drive->driver == &idedefault_driver || DRIVER(drive)->busy) {
 		spin_unlock_irqrestore(&ide_lock, flags);
 		return 1;
 	}
@@ -2330,10 +2370,12 @@
 	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
 #endif
 	auto_remove_settings(drive);
-	drive->driver = NULL;
+	drive->driver = &idedefault_driver;
+	setup_driver_defaults(drive);
 	spin_unlock_irqrestore(&ide_lock, flags);
 	spin_lock(&drives_lock);
 	list_del_init(&drive->list);
+	list_add(&drive->list, &drive->driver->drives);
 	spin_unlock(&drives_lock);
 	return 0;
 }
@@ -2343,10 +2385,7 @@
 static int ide_drive_remove(struct device * dev)
 {
 	ide_drive_t * drive = container_of(dev,ide_drive_t,gendev);
-	ide_driver_t * driver = drive->driver;
-
-	if (driver && driver->cleanup)
-		driver->cleanup(drive);
+	DRIVER(drive)->cleanup(drive);
 	return 0;
 }
 
@@ -2366,7 +2405,8 @@
 	while (!list_empty(&list)) {
 		ide_drive_t *drive = list_entry(list.next, ide_drive_t, list);
 		list_del_init(&drive->list);
-		ata_attach(drive);
+		if (drive->present)
+			ata_attach(drive);
 	}
 	driver->gen_driver.name = (char *) driver->name;
 	driver->gen_driver.bus = &ide_bus_type;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/