diff options
Diffstat (limited to 'drivers/ide/ide.c')
-rw-r--r-- | drivers/ide/ide.c | 307 |
1 files changed, 25 insertions, 282 deletions
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 973dec799b5c..dae1bd5b8c3e 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -196,8 +196,6 @@ ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ EXPORT_SYMBOL(ide_hwifs); -static struct list_head ide_drives = LIST_HEAD_INIT(ide_drives); - /* * Do not even *think* about calling this! */ @@ -358,54 +356,6 @@ static int ide_system_bus_speed(void) return system_bus_speed; } -/* - * drives_lock protects the list of drives, drivers_lock the - * list of drivers. Currently nobody takes both at once. - */ - -static DEFINE_SPINLOCK(drives_lock); -static DEFINE_SPINLOCK(drivers_lock); -static LIST_HEAD(drivers); - -/* Iterator for the driver list. */ - -static void *m_start(struct seq_file *m, loff_t *pos) -{ - struct list_head *p; - loff_t l = *pos; - spin_lock(&drivers_lock); - list_for_each(p, &drivers) - if (!l--) - return list_entry(p, ide_driver_t, drivers); - return NULL; -} - -static void *m_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct list_head *p = ((ide_driver_t *)v)->drivers.next; - (*pos)++; - return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers); -} - -static void m_stop(struct seq_file *m, void *v) -{ - spin_unlock(&drivers_lock); -} - -static int show_driver(struct seq_file *m, void *v) -{ - ide_driver_t *driver = v; - seq_printf(m, "%s version %s\n", driver->name, driver->version); - return 0; -} - -struct seq_operations ide_drivers_op = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_driver -}; - #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_ide_root; #endif @@ -630,7 +580,7 @@ void ide_unregister(unsigned int index) ide_hwif_t *hwif, *g; static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */ ide_hwgroup_t *hwgroup; - int irq_count = 0, unit, i; + int irq_count = 0, unit; BUG_ON(index >= MAX_HWIFS); @@ -643,23 +593,22 @@ void ide_unregister(unsigned int index) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; - if (!drive->present) + if (!drive->present) { + if (drive->devfs_name[0] != '\0') { + devfs_remove(drive->devfs_name); + drive->devfs_name[0] = '\0'; + } continue; - if (drive->usage || DRIVER(drive)->busy) - goto abort; - drive->dead = 1; + } + spin_unlock_irq(&ide_lock); + device_unregister(&drive->gendev); + down(&drive->gendev_rel_sem); + spin_lock_irq(&ide_lock); } hwif->present = 0; spin_unlock_irq(&ide_lock); - for (unit = 0; unit < MAX_DRIVES; ++unit) { - drive = &hwif->drives[unit]; - if (!drive->present) - continue; - DRIVER(drive)->cleanup(drive); - } - destroy_proc_ide_interface(hwif); hwgroup = hwif->hwgroup; @@ -687,44 +636,6 @@ void ide_unregister(unsigned int index) * Remove us from the hwgroup, and free * the hwgroup if we were the only member */ - for (i = 0; i < MAX_DRIVES; ++i) { - drive = &hwif->drives[i]; - if (drive->devfs_name[0] != '\0') { - devfs_remove(drive->devfs_name); - drive->devfs_name[0] = '\0'; - } - if (!drive->present) - continue; - 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; - } - drive->present = 0; - /* Messed up locking ... */ - spin_unlock_irq(&ide_lock); - blk_cleanup_queue(drive->queue); - device_unregister(&drive->gendev); - down(&drive->gendev_rel_sem); - spin_lock_irq(&ide_lock); - drive->queue = NULL; - } if (hwif->next == hwif) { BUG_ON(hwgroup->hwif != hwif); kfree(hwgroup); @@ -1304,73 +1215,6 @@ int system_bus_clock (void) EXPORT_SYMBOL(system_bus_clock); -/* - * Locking is badly broken here - since way back. That sucker is - * root-only, but that's not an excuse... The real question is what - * exclusion rules do we want here. - */ -int ide_replace_subdriver (ide_drive_t *drive, const char *driver) -{ - if (!drive->present || drive->usage || drive->dead) - goto abort; - if (DRIVER(drive)->cleanup(drive)) - goto abort; - strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); - if (ata_attach(drive)) { - spin_lock(&drives_lock); - list_del_init(&drive->list); - spin_unlock(&drives_lock); - drive->driver_req[0] = 0; - ata_attach(drive); - } else { - drive->driver_req[0] = 0; - } - if (drive->driver && !strcmp(drive->driver->name, driver)) - return 0; -abort: - return 1; -} - -/** - * ata_attach - attach an ATA/ATAPI device - * @drive: drive to attach - * - * Takes a drive that is as yet not assigned to any midlayer IDE - * driver (or is assigned to the default driver) and figures out - * which driver would like to own it. If nobody claims the drive - * then it is automatically attached to the default driver used for - * unclaimed objects. - * - * A return of zero indicates attachment to a driver, of one - * attachment to the default driver. - * - * Takes drivers_lock. - */ - -int ata_attach(ide_drive_t *drive) -{ - struct list_head *p; - spin_lock(&drivers_lock); - list_for_each(p, &drivers) { - ide_driver_t *driver = list_entry(p, ide_driver_t, drivers); - if (!try_module_get(driver->owner)) - continue; - spin_unlock(&drivers_lock); - if (driver->attach(drive) == 0) { - module_put(driver->owner); - drive->gendev.driver = &driver->gen_driver; - return 0; - } - spin_lock(&drivers_lock); - module_put(driver->owner); - } - drive->gendev.driver = NULL; - spin_unlock(&drivers_lock); - if (ide_register_subdriver(drive, NULL)) - panic("ide: default attach failed"); - return 1; -} - static int generic_ide_suspend(struct device *dev, pm_message_t state) { ide_drive_t *drive = dev->driver_data; @@ -2013,27 +1857,11 @@ static void __init probe_for_hwifs (void) #endif } -int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver) +void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver) { - unsigned long flags; - - spin_lock_irqsave(&ide_lock, flags); - if (!drive->present || drive->driver != NULL || - drive->usage || drive->dead) { - spin_unlock_irqrestore(&ide_lock, flags); - return 1; - } - drive->driver = driver; - spin_unlock_irqrestore(&ide_lock, flags); - spin_lock(&drives_lock); - list_add_tail(&drive->list, driver ? &driver->drives : &ide_drives); - spin_unlock(&drives_lock); -// printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name); #ifdef CONFIG_PROC_FS - if (driver) - ide_add_proc_entries(drive->proc, driver->proc, drive); + ide_add_proc_entries(drive->proc, driver->proc, drive); #endif - return 0; } EXPORT_SYMBOL(ide_register_subdriver); @@ -2041,136 +1869,51 @@ EXPORT_SYMBOL(ide_register_subdriver); /** * ide_unregister_subdriver - disconnect drive from driver * @drive: drive to unplug + * @driver: driver * * Disconnect a drive from the driver it was attached to and then * clean up the various proc files and other objects attached to it. * - * Takes ide_setting_sem, ide_lock and drives_lock. + * Takes ide_setting_sem and ide_lock. * Caller must hold none of the locks. - * - * No locking versus subdriver unload because we are moving to the - * default driver anyway. Wants double checking. */ -int ide_unregister_subdriver (ide_drive_t *drive) +void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver) { unsigned long flags; down(&ide_setting_sem); spin_lock_irqsave(&ide_lock, flags); - if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) { - spin_unlock_irqrestore(&ide_lock, flags); - up(&ide_setting_sem); - return 1; - } #ifdef CONFIG_PROC_FS - ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc); + ide_remove_proc_entries(drive->proc, driver->proc); #endif auto_remove_settings(drive); - drive->driver = NULL; spin_unlock_irqrestore(&ide_lock, flags); up(&ide_setting_sem); - spin_lock(&drives_lock); - list_del_init(&drive->list); - spin_unlock(&drives_lock); - /* drive will be added to &ide_drives in ata_attach() */ - return 0; } EXPORT_SYMBOL(ide_unregister_subdriver); -static int ide_drive_remove(struct device * dev) -{ - ide_drive_t * drive = container_of(dev,ide_drive_t,gendev); - DRIVER(drive)->cleanup(drive); - return 0; -} - -/** - * ide_register_driver - register IDE device driver - * @driver: the IDE device driver - * - * Register a new device driver and then scan the devices - * on the IDE bus in case any should be attached to the - * driver we have just registered. If so attach them. - * - * Takes drivers_lock and drives_lock. - */ - -int ide_register_driver(ide_driver_t *driver) -{ - struct list_head list; - struct list_head *list_loop; - struct list_head *tmp_storage; - - spin_lock(&drivers_lock); - list_add(&driver->drivers, &drivers); - spin_unlock(&drivers_lock); - - INIT_LIST_HEAD(&list); - spin_lock(&drives_lock); - list_splice_init(&ide_drives, &list); - spin_unlock(&drives_lock); - - list_for_each_safe(list_loop, tmp_storage, &list) { - ide_drive_t *drive = container_of(list_loop, ide_drive_t, list); - list_del_init(&drive->list); - if (drive->present) - ata_attach(drive); - } - driver->gen_driver.name = (char *) driver->name; - driver->gen_driver.bus = &ide_bus_type; - driver->gen_driver.remove = ide_drive_remove; - return driver_register(&driver->gen_driver); -} - -EXPORT_SYMBOL(ide_register_driver); - -/** - * ide_unregister_driver - unregister IDE device driver - * @driver: the IDE device driver - * - * Called when a driver module is being unloaded. We reattach any - * devices to whatever driver claims them next (typically the default - * driver). - * - * Takes drivers_lock and called functions will take ide_setting_sem. - */ - -void ide_unregister_driver(ide_driver_t *driver) -{ - ide_drive_t *drive; - - spin_lock(&drivers_lock); - list_del(&driver->drivers); - spin_unlock(&drivers_lock); - - driver_unregister(&driver->gen_driver); - - while(!list_empty(&driver->drives)) { - drive = list_entry(driver->drives.next, ide_drive_t, list); - if (driver->cleanup(drive)) { - printk(KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); - BUG(); - } - ata_attach(drive); - } -} - -EXPORT_SYMBOL(ide_unregister_driver); - /* * Probe module */ EXPORT_SYMBOL(ide_lock); +static int ide_bus_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + struct bus_type ide_bus_type = { .name = "ide", + .match = ide_bus_match, .suspend = generic_ide_suspend, .resume = generic_ide_resume, }; +EXPORT_SYMBOL_GPL(ide_bus_type); + /* * This is gets invoked once during initialization, to set *everything* up */ |