diff --git a/[refs] b/[refs] index 7ee621554e23..14a78861e387 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 284e423811495f632a7a334b2b93caba07d4f778 +refs/heads/master: 32529e0128923e42126b5d14e444c18295a452ba diff --git a/trunk/drivers/ide/ide-cd.c b/trunk/drivers/ide/ide-cd.c index f0bd242e030f..4f7ce7056228 100644 --- a/trunk/drivers/ide/ide-cd.c +++ b/trunk/drivers/ide/ide-cd.c @@ -3255,12 +3255,16 @@ sector_t ide_cdrom_capacity (ide_drive_t *drive) return capacity * sectors_per_frame; } -static int ide_cd_remove(struct device *dev) +static +int ide_cdrom_cleanup(ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); struct cdrom_info *info = drive->driver_data; - ide_unregister_subdriver(drive, info->driver); + if (ide_unregister_subdriver(drive)) { + printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n", + __FUNCTION__, drive->name); + return 1; + } del_gendisk(info->disk); @@ -3293,7 +3297,7 @@ static void ide_cd_release(struct kref *kref) kfree(info); } -static int ide_cd_probe(struct device *); +static int ide_cdrom_attach (ide_drive_t *drive); #ifdef CONFIG_PROC_FS static int proc_idecd_read_capacity @@ -3316,20 +3320,19 @@ static ide_proc_entry_t idecd_proc[] = { static ide_driver_t ide_cdrom_driver = { .owner = THIS_MODULE, - .gen_driver = { - .name = "ide-cdrom", - .bus = &ide_bus_type, - .probe = ide_cd_probe, - .remove = ide_cd_remove, - }, + .name = "ide-cdrom", .version = IDECD_VERSION, .media = ide_cdrom, + .busy = 0, .supports_dsc_overlap = 1, + .cleanup = ide_cdrom_cleanup, .do_request = ide_do_rw_cdrom, .end_request = ide_end_request, .error = __ide_error, .abort = __ide_abort, .proc = idecd_proc, + .attach = ide_cdrom_attach, + .drives = LIST_HEAD_INIT(ide_cdrom_driver.drives), }; static int idecd_open(struct inode * inode, struct file * file) @@ -3415,9 +3418,8 @@ static char *ignore = NULL; module_param(ignore, charp, 0400); MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); -static int ide_cd_probe(struct device *dev) +static int ide_cdrom_attach (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); struct cdrom_info *info; struct gendisk *g; struct request_sense sense; @@ -3451,8 +3453,11 @@ static int ide_cd_probe(struct device *dev) ide_init_disk(g, drive); - ide_register_subdriver(drive, &ide_cdrom_driver); - + if (ide_register_subdriver(drive, &ide_cdrom_driver)) { + printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", + drive->name); + goto out_put_disk; + } memset(info, 0, sizeof (struct cdrom_info)); kref_init(&info->kref); @@ -3465,6 +3470,7 @@ static int ide_cd_probe(struct device *dev) drive->driver_data = info; + DRIVER(drive)->busy++; g->minors = 1; snprintf(g->devfs_name, sizeof(g->devfs_name), "%s/cd", drive->devfs_name); @@ -3472,7 +3478,8 @@ static int ide_cd_probe(struct device *dev) g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE; if (ide_cdrom_setup(drive)) { struct cdrom_device_info *devinfo = &info->devinfo; - ide_unregister_subdriver(drive, &ide_cdrom_driver); + DRIVER(drive)->busy--; + ide_unregister_subdriver(drive); if (info->buffer != NULL) kfree(info->buffer); if (info->toc != NULL) @@ -3485,6 +3492,7 @@ static int ide_cd_probe(struct device *dev) drive->driver_data = NULL; goto failed; } + DRIVER(drive)->busy--; cdrom_read_toc(drive, &sense); g->fops = &idecd_ops; @@ -3492,20 +3500,23 @@ static int ide_cd_probe(struct device *dev) add_disk(g); return 0; +out_put_disk: + put_disk(g); out_free_cd: kfree(info); failed: - return -ENODEV; + return 1; } static void __exit ide_cdrom_exit(void) { - driver_unregister(&ide_cdrom_driver.gen_driver); + ide_unregister_driver(&ide_cdrom_driver); } static int ide_cdrom_init(void) { - return driver_register(&ide_cdrom_driver.gen_driver); + ide_register_driver(&ide_cdrom_driver); + return 0; } module_init(ide_cdrom_init); diff --git a/trunk/drivers/ide/ide-disk.c b/trunk/drivers/ide/ide-disk.c index 3302cd8eab4c..5d54f7756100 100644 --- a/trunk/drivers/ide/ide-disk.c +++ b/trunk/drivers/ide/ide-disk.c @@ -1024,16 +1024,14 @@ static void ide_cacheflush_p(ide_drive_t *drive) printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); } -static int ide_disk_remove(struct device *dev) +static int idedisk_cleanup (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); struct ide_disk_obj *idkp = drive->driver_data; struct gendisk *g = idkp->disk; ide_cacheflush_p(drive); - - ide_unregister_subdriver(drive, idkp->driver); - + if (ide_unregister_subdriver(drive)) + return 1; del_gendisk(g); ide_disk_put(idkp); @@ -1054,7 +1052,7 @@ static void ide_disk_release(struct kref *kref) kfree(idkp); } -static int ide_disk_probe(struct device *dev); +static int idedisk_attach(ide_drive_t *drive); static void ide_device_shutdown(struct device *dev) { @@ -1084,23 +1082,27 @@ static void ide_device_shutdown(struct device *dev) dev->bus->suspend(dev, PMSG_SUSPEND); } +/* + * IDE subdriver functions, registered with ide.c + */ static ide_driver_t idedisk_driver = { .owner = THIS_MODULE, .gen_driver = { - .name = "ide-disk", - .bus = &ide_bus_type, - .probe = ide_disk_probe, - .remove = ide_disk_remove, .shutdown = ide_device_shutdown, }, + .name = "ide-disk", .version = IDEDISK_VERSION, .media = ide_disk, + .busy = 0, .supports_dsc_overlap = 0, + .cleanup = idedisk_cleanup, .do_request = ide_do_rw_disk, .end_request = ide_end_request, .error = __ide_error, .abort = __ide_abort, .proc = idedisk_proc, + .attach = idedisk_attach, + .drives = LIST_HEAD_INIT(idedisk_driver.drives), }; static int idedisk_open(struct inode *inode, struct file *filp) @@ -1197,9 +1199,8 @@ static struct block_device_operations idedisk_ops = { MODULE_DESCRIPTION("ATA DISK Driver"); -static int ide_disk_probe(struct device *dev) +static int idedisk_attach(ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); struct ide_disk_obj *idkp; struct gendisk *g; @@ -1221,7 +1222,10 @@ static int ide_disk_probe(struct device *dev) ide_init_disk(g, drive); - ide_register_subdriver(drive, &idedisk_driver); + if (ide_register_subdriver(drive, &idedisk_driver)) { + printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); + goto out_put_disk; + } memset(idkp, 0, sizeof(*idkp)); @@ -1235,6 +1239,7 @@ static int ide_disk_probe(struct device *dev) drive->driver_data = idkp; + DRIVER(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", @@ -1242,7 +1247,7 @@ static int ide_disk_probe(struct device *dev) drive->attach = 0; } else drive->attach = 1; - + DRIVER(drive)->busy--; g->minors = 1 << PARTN_BITS; strcpy(g->devfs_name, drive->devfs_name); g->driverfs_dev = &drive->gendev; @@ -1252,20 +1257,22 @@ static int ide_disk_probe(struct device *dev) add_disk(g); return 0; +out_put_disk: + put_disk(g); out_free_idkp: kfree(idkp); failed: - return -ENODEV; + return 1; } static void __exit idedisk_exit (void) { - driver_unregister(&idedisk_driver.gen_driver); + ide_unregister_driver(&idedisk_driver); } static int idedisk_init (void) { - return driver_register(&idedisk_driver.gen_driver); + return ide_register_driver(&idedisk_driver); } module_init(idedisk_init); diff --git a/trunk/drivers/ide/ide-floppy.c b/trunk/drivers/ide/ide-floppy.c index c949e98df4b6..36c0b74a4e45 100644 --- a/trunk/drivers/ide/ide-floppy.c +++ b/trunk/drivers/ide/ide-floppy.c @@ -1865,13 +1865,13 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy) idefloppy_add_settings(drive); } -static int ide_floppy_remove(struct device *dev) +static int idefloppy_cleanup (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); idefloppy_floppy_t *floppy = drive->driver_data; struct gendisk *g = floppy->disk; - ide_unregister_subdriver(drive, floppy->driver); + if (ide_unregister_subdriver(drive)) + return 1; del_gendisk(g); @@ -1916,24 +1916,26 @@ static ide_proc_entry_t idefloppy_proc[] = { #endif /* CONFIG_PROC_FS */ -static int ide_floppy_probe(struct device *); +static int idefloppy_attach(ide_drive_t *drive); +/* + * IDE subdriver functions, registered with ide.c + */ static ide_driver_t idefloppy_driver = { .owner = THIS_MODULE, - .gen_driver = { - .name = "ide-floppy", - .bus = &ide_bus_type, - .probe = ide_floppy_probe, - .remove = ide_floppy_remove, - }, + .name = "ide-floppy", .version = IDEFLOPPY_VERSION, .media = ide_floppy, + .busy = 0, .supports_dsc_overlap = 0, + .cleanup = idefloppy_cleanup, .do_request = idefloppy_do_request, .end_request = idefloppy_do_end_request, .error = __ide_error, .abort = __ide_abort, .proc = idefloppy_proc, + .attach = idefloppy_attach, + .drives = LIST_HEAD_INIT(idefloppy_driver.drives), }; static int idefloppy_open(struct inode *inode, struct file *filp) @@ -2120,9 +2122,8 @@ static struct block_device_operations idefloppy_ops = { .revalidate_disk= idefloppy_revalidate_disk }; -static int ide_floppy_probe(struct device *dev) +static int idefloppy_attach (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); idefloppy_floppy_t *floppy; struct gendisk *g; @@ -2151,7 +2152,10 @@ static int ide_floppy_probe(struct device *dev) ide_init_disk(g, drive); - ide_register_subdriver(drive, &idefloppy_driver); + if (ide_register_subdriver(drive, &idefloppy_driver)) { + printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); + goto out_put_disk; + } memset(floppy, 0, sizeof(*floppy)); @@ -2165,8 +2169,9 @@ static int ide_floppy_probe(struct device *dev) drive->driver_data = floppy; + DRIVER(drive)->busy++; idefloppy_setup (drive, floppy); - + DRIVER(drive)->busy--; g->minors = 1 << PARTN_BITS; g->driverfs_dev = &drive->gendev; strcpy(g->devfs_name, drive->devfs_name); @@ -2176,17 +2181,19 @@ static int ide_floppy_probe(struct device *dev) add_disk(g); return 0; +out_put_disk: + put_disk(g); out_free_floppy: kfree(floppy); failed: - return -ENODEV; + return 1; } MODULE_DESCRIPTION("ATAPI FLOPPY Driver"); static void __exit idefloppy_exit (void) { - driver_unregister(&idefloppy_driver.gen_driver); + ide_unregister_driver(&idefloppy_driver); } /* @@ -2195,7 +2202,8 @@ static void __exit idefloppy_exit (void) static int idefloppy_init (void) { printk("ide-floppy driver " IDEFLOPPY_VERSION "\n"); - return driver_register(&idefloppy_driver.gen_driver); + ide_register_driver(&idefloppy_driver); + return 0; } module_init(idefloppy_init); diff --git a/trunk/drivers/ide/ide-probe.c b/trunk/drivers/ide/ide-probe.c index 5d876f53c697..554473a95cf7 100644 --- a/trunk/drivers/ide/ide-probe.c +++ b/trunk/drivers/ide/ide-probe.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -697,13 +696,13 @@ static int wait_hwif_ready(ide_hwif_t *hwif) SELECT_DRIVE(&hwif->drives[0]); hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); mdelay(2); - rc = ide_wait_not_busy(hwif, 35000); + rc = ide_wait_not_busy(hwif, 10000); if (rc) return rc; SELECT_DRIVE(&hwif->drives[1]); hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); mdelay(2); - rc = ide_wait_not_busy(hwif, 35000); + rc = ide_wait_not_busy(hwif, 10000); /* Exit function with master reselected (let's be sane) */ SELECT_DRIVE(&hwif->drives[0]); @@ -919,7 +918,7 @@ int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif) want them on default or a new "empty" class for hotplug reprobing ? */ if (drive->present) { - device_register(&drive->gendev); + ata_attach(drive); } } } @@ -1280,51 +1279,10 @@ void ide_init_disk(struct gendisk *disk, ide_drive_t *drive) EXPORT_SYMBOL_GPL(ide_init_disk); -static void ide_remove_drive_from_hwgroup(ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; - - 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 = hwgroup->drive->hwif; - } - } - BUG_ON(hwgroup->drive == drive); -} - static void drive_release_dev (struct device *dev) { ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); - spin_lock_irq(&ide_lock); - if (drive->devfs_name[0] != '\0') { - devfs_remove(drive->devfs_name); - drive->devfs_name[0] = '\0'; - } - ide_remove_drive_from_hwgroup(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); - spin_lock_irq(&ide_lock); - drive->queue = NULL; - spin_unlock_irq(&ide_lock); - up(&drive->gendev_rel_sem); } @@ -1348,6 +1306,7 @@ static void init_gendisk (ide_hwif_t *hwif) drive->gendev.driver_data = drive; drive->gendev.release = drive_release_dev; if (drive->present) { + device_register(&drive->gendev); sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d", (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, @@ -1453,7 +1412,7 @@ int ideprobe_init (void) hwif->chipset = ide_generic; for (unit = 0; unit < MAX_DRIVES; ++unit) if (hwif->drives[unit].present) - device_register(&hwif->drives[unit].gendev); + ata_attach(&hwif->drives[unit]); } } return 0; diff --git a/trunk/drivers/ide/ide-proc.c b/trunk/drivers/ide/ide-proc.c index 4063d2c34e3d..4b1e43b4118b 100644 --- a/trunk/drivers/ide/ide-proc.c +++ b/trunk/drivers/ide/ide-proc.c @@ -307,41 +307,17 @@ static int proc_ide_read_driver (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; - struct device *dev = &drive->gendev; - ide_driver_t *ide_drv; + ide_driver_t *driver = drive->driver; int len; - down_read(&dev->bus->subsys.rwsem); - if (dev->driver) { - ide_drv = container_of(dev->driver, ide_driver_t, gen_driver); + if (driver) { len = sprintf(page, "%s version %s\n", - dev->driver->name, ide_drv->version); + driver->name, driver->version); } else len = sprintf(page, "ide-default version 0.9.newide\n"); - up_read(&dev->bus->subsys.rwsem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) -{ - struct device *dev = &drive->gendev; - int ret = 1; - - down_write(&dev->bus->subsys.rwsem); - device_release_driver(dev); - /* FIXME: device can still be in use by previous driver */ - strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); - device_attach(dev); - drive->driver_req[0] = 0; - if (dev->driver == NULL) - device_attach(dev); - if (dev->driver && !strcmp(dev->driver->name, driver)) - ret = 0; - up_write(&dev->bus->subsys.rwsem); - - return ret; -} - static int proc_ide_write_driver (struct file *file, const char __user *buffer, unsigned long count, void *data) { @@ -512,32 +488,16 @@ void destroy_proc_ide_interface(ide_hwif_t *hwif) } } -static int proc_print_driver(struct device_driver *drv, void *data) -{ - ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver); - struct seq_file *s = data; - - seq_printf(s, "%s version %s\n", drv->name, ide_drv->version); - - return 0; -} - -static int ide_drivers_show(struct seq_file *s, void *p) -{ - bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver); - return 0; -} - +extern struct seq_operations ide_drivers_op; static int ide_drivers_open(struct inode *inode, struct file *file) { - return single_open(file, &ide_drivers_show, NULL); + return seq_open(file, &ide_drivers_op); } - static struct file_operations ide_drivers_operations = { .open = ide_drivers_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; void proc_ide_create(void) diff --git a/trunk/drivers/ide/ide-tape.c b/trunk/drivers/ide/ide-tape.c index 5a3dc46008e6..482544854985 100644 --- a/trunk/drivers/ide/ide-tape.c +++ b/trunk/drivers/ide/ide-tape.c @@ -4681,12 +4681,21 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) idetape_add_settings(drive); } -static int ide_tape_remove(struct device *dev) +static int idetape_cleanup (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); idetape_tape_t *tape = drive->driver_data; + unsigned long flags; + + spin_lock_irqsave(&ide_lock, flags); + if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage || + tape->first_stage != NULL || tape->merge_stage_size) { + spin_unlock_irqrestore(&ide_lock, flags); + return 1; + } - ide_unregister_subdriver(drive, tape->driver); + spin_unlock_irqrestore(&ide_lock, flags); + DRIVER(drive)->busy = 0; + (void) ide_unregister_subdriver(drive); ide_unregister_region(tape->disk); @@ -4701,8 +4710,6 @@ static void ide_tape_release(struct kref *kref) ide_drive_t *drive = tape->drive; struct gendisk *g = tape->disk; - BUG_ON(tape->first_stage != NULL || tape->merge_stage_size); - drive->dsc_overlap = 0; drive->driver_data = NULL; devfs_remove("%s/mt", drive->devfs_name); @@ -4740,24 +4747,26 @@ static ide_proc_entry_t idetape_proc[] = { #endif -static int ide_tape_probe(struct device *); +static int idetape_attach(ide_drive_t *drive); +/* + * IDE subdriver functions, registered with ide.c + */ static ide_driver_t idetape_driver = { .owner = THIS_MODULE, - .gen_driver = { - .name = "ide-tape", - .bus = &ide_bus_type, - .probe = ide_tape_probe, - .remove = ide_tape_remove, - }, + .name = "ide-tape", .version = IDETAPE_VERSION, .media = ide_tape, + .busy = 1, .supports_dsc_overlap = 1, + .cleanup = idetape_cleanup, .do_request = idetape_do_request, .end_request = idetape_end_request, .error = __ide_error, .abort = __ide_abort, .proc = idetape_proc, + .attach = idetape_attach, + .drives = LIST_HEAD_INIT(idetape_driver.drives), }; /* @@ -4820,9 +4829,8 @@ static struct block_device_operations idetape_block_ops = { .ioctl = idetape_ioctl, }; -static int ide_tape_probe(struct device *dev) +static int idetape_attach (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); idetape_tape_t *tape; struct gendisk *g; int minor; @@ -4857,7 +4865,10 @@ static int ide_tape_probe(struct device *dev) ide_init_disk(g, drive); - ide_register_subdriver(drive, &idetape_driver); + if (ide_register_subdriver(drive, &idetape_driver)) { + printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); + goto out_put_disk; + } memset(tape, 0, sizeof(*tape)); @@ -4891,11 +4902,12 @@ static int ide_tape_probe(struct device *dev) ide_register_region(g); return 0; - +out_put_disk: + put_disk(g); out_free_tape: kfree(tape); failed: - return -ENODEV; + return 1; } MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); @@ -4903,7 +4915,7 @@ MODULE_LICENSE("GPL"); static void __exit idetape_exit (void) { - driver_unregister(&idetape_driver.gen_driver); + ide_unregister_driver(&idetape_driver); unregister_chrdev(IDETAPE_MAJOR, "ht"); } @@ -4916,7 +4928,8 @@ static int idetape_init (void) printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); return -EBUSY; } - return driver_register(&idetape_driver.gen_driver); + ide_register_driver(&idetape_driver); + return 0; } module_init(idetape_init); diff --git a/trunk/drivers/ide/ide.c b/trunk/drivers/ide/ide.c index dae1bd5b8c3e..973dec799b5c 100644 --- a/trunk/drivers/ide/ide.c +++ b/trunk/drivers/ide/ide.c @@ -196,6 +196,8 @@ 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! */ @@ -356,6 +358,54 @@ 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 @@ -580,7 +630,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; + int irq_count = 0, unit, i; BUG_ON(index >= MAX_HWIFS); @@ -593,22 +643,23 @@ void ide_unregister(unsigned int index) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; - if (!drive->present) { - if (drive->devfs_name[0] != '\0') { - devfs_remove(drive->devfs_name); - drive->devfs_name[0] = '\0'; - } + if (!drive->present) continue; - } - spin_unlock_irq(&ide_lock); - device_unregister(&drive->gendev); - down(&drive->gendev_rel_sem); - spin_lock_irq(&ide_lock); + if (drive->usage || DRIVER(drive)->busy) + goto abort; + drive->dead = 1; } 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; @@ -636,6 +687,44 @@ 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); @@ -1215,6 +1304,73 @@ 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; @@ -1857,11 +2013,27 @@ static void __init probe_for_hwifs (void) #endif } -void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver) +int 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 - ide_add_proc_entries(drive->proc, driver->proc, drive); + if (driver) + ide_add_proc_entries(drive->proc, driver->proc, drive); #endif + return 0; } EXPORT_SYMBOL(ide_register_subdriver); @@ -1869,51 +2041,136 @@ 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 and ide_lock. + * Takes ide_setting_sem, ide_lock and drives_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. */ -void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver) +int ide_unregister_subdriver (ide_drive_t *drive) { 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->proc); + ide_remove_proc_entries(drive->proc, DRIVER(drive)->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); -/* - * Probe module +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. */ -EXPORT_SYMBOL(ide_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); +} -static int ide_bus_match(struct device *dev, struct device_driver *drv) +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) { - return 1; + 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); + 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 */ diff --git a/trunk/drivers/scsi/ide-scsi.c b/trunk/drivers/scsi/ide-scsi.c index 83f062ed9082..2e2486b035dd 100644 --- a/trunk/drivers/scsi/ide-scsi.c +++ b/trunk/drivers/scsi/ide-scsi.c @@ -179,18 +179,8 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne return; } count = min(pc->sg->length - pc->b_count, bcount); - if (PageHighMem(pc->sg->page)) { - unsigned long flags; - - local_irq_save(flags); - buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); - kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = page_address(pc->sg->page) + pc->sg->offset; - drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); - } + buf = page_address(pc->sg->page) + pc->sg->offset; + drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; @@ -211,18 +201,8 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign return; } count = min(pc->sg->length - pc->b_count, bcount); - if (PageHighMem(pc->sg->page)) { - unsigned long flags; - - local_irq_save(flags); - buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; - drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); - kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = page_address(pc->sg->page) + pc->sg->offset; - drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); - } + buf = page_address(pc->sg->page) + pc->sg->offset; + drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; @@ -733,6 +713,7 @@ static void idescsi_add_settings(ide_drive_t *drive) */ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi) { + DRIVER(drive)->busy++; if (drive->id && (drive->id->config & 0x0060) == 0x20) set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags); set_bit(IDESCSI_TRANSFORM, &scsi->transform); @@ -741,16 +722,17 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi) set_bit(IDESCSI_LOG_CMD, &scsi->log); #endif /* IDESCSI_DEBUG_LOG */ idescsi_add_settings(drive); + DRIVER(drive)->busy--; } -static int ide_scsi_remove(struct device *dev) +static int idescsi_cleanup (ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); struct Scsi_Host *scsihost = drive->driver_data; struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost); struct gendisk *g = scsi->disk; - ide_unregister_subdriver(drive, scsi->driver); + if (ide_unregister_subdriver(drive)) + return 1; ide_unregister_region(g); @@ -764,7 +746,7 @@ static int ide_scsi_remove(struct device *dev) return 0; } -static int ide_scsi_probe(struct device *); +static int idescsi_attach(ide_drive_t *drive); #ifdef CONFIG_PROC_FS static ide_proc_entry_t idescsi_proc[] = { @@ -775,22 +757,24 @@ static ide_proc_entry_t idescsi_proc[] = { # define idescsi_proc NULL #endif +/* + * IDE subdriver functions, registered with ide.c + */ static ide_driver_t idescsi_driver = { .owner = THIS_MODULE, - .gen_driver = { - .name = "ide-scsi", - .bus = &ide_bus_type, - .probe = ide_scsi_probe, - .remove = ide_scsi_remove, - }, + .name = "ide-scsi", .version = IDESCSI_VERSION, .media = ide_scsi, + .busy = 0, .supports_dsc_overlap = 0, .proc = idescsi_proc, + .attach = idescsi_attach, + .cleanup = idescsi_cleanup, .do_request = idescsi_do_request, .end_request = idescsi_end_request, .error = idescsi_atapi_error, .abort = idescsi_atapi_abort, + .drives = LIST_HEAD_INIT(idescsi_driver.drives), }; static int idescsi_ide_open(struct inode *inode, struct file *filp) @@ -837,6 +821,8 @@ static struct block_device_operations idescsi_ops = { .ioctl = idescsi_ide_ioctl, }; +static int idescsi_attach(ide_drive_t *drive); + static int idescsi_slave_configure(struct scsi_device * sdp) { /* Configure detected device */ @@ -1109,9 +1095,8 @@ static struct scsi_host_template idescsi_template = { .proc_name = "ide-scsi", }; -static int ide_scsi_probe(struct device *dev) +static int idescsi_attach(ide_drive_t *drive) { - ide_drive_t *drive = to_ide_device(dev); idescsi_scsi_t *idescsi; struct Scsi_Host *host; struct gendisk *g; @@ -1127,7 +1112,7 @@ static int ide_scsi_probe(struct device *dev) !drive->present || drive->media == ide_disk || !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t)))) - return -ENODEV; + return 1; g = alloc_disk(1 << PARTN_BITS); if (!g) @@ -1153,19 +1138,20 @@ static int ide_scsi_probe(struct device *dev) idescsi->host = host; idescsi->disk = g; g->private_data = &idescsi->driver; - ide_register_subdriver(drive, &idescsi_driver); - err = 0; - idescsi_setup(drive, idescsi); - g->fops = &idescsi_ops; - ide_register_region(g); - err = scsi_add_host(host, &drive->gendev); + err = ide_register_subdriver(drive, &idescsi_driver); if (!err) { - scsi_scan_host(host); - return 0; + idescsi_setup (drive, idescsi); + g->fops = &idescsi_ops; + ide_register_region(g); + err = scsi_add_host(host, &drive->gendev); + if (!err) { + scsi_scan_host(host); + return 0; + } + /* fall through on error */ + ide_unregister_region(g); + ide_unregister_subdriver(drive); } - /* fall through on error */ - ide_unregister_region(g); - ide_unregister_subdriver(drive, &idescsi_driver); put_disk(g); out_host_put: @@ -1175,12 +1161,12 @@ static int ide_scsi_probe(struct device *dev) static int __init init_idescsi_module(void) { - return driver_register(&idescsi_driver.gen_driver); + return ide_register_driver(&idescsi_driver); } static void __exit exit_idescsi_module(void) { - driver_unregister(&idescsi_driver.gen_driver); + ide_unregister_driver(&idescsi_driver); } module_init(init_idescsi_module); diff --git a/trunk/drivers/scsi/libata-core.c b/trunk/drivers/scsi/libata-core.c index ee9b96da841e..63d3f70d06e1 100644 --- a/trunk/drivers/scsi/libata-core.c +++ b/trunk/drivers/scsi/libata-core.c @@ -2071,7 +2071,7 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) sg = qc->sg; sg->page = virt_to_page(buf); sg->offset = (unsigned long) buf & ~PAGE_MASK; - sg_dma_len(sg) = buflen; + sg->length = buflen; } void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, @@ -2101,11 +2101,12 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc) dma_addr_t dma_address; dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt, - sg_dma_len(sg), dir); + sg->length, dir); if (dma_mapping_error(dma_address)) return -1; sg_dma_address(sg) = dma_address; + sg_dma_len(sg) = sg->length; DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg), qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); @@ -2310,7 +2311,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) qc->cursect++; qc->cursg_ofs++; - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { + if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) { qc->cursg++; qc->cursg_ofs = 0; } @@ -2347,7 +2348,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) page = nth_page(page, (offset >> PAGE_SHIFT)); offset %= PAGE_SIZE; - count = min(sg_dma_len(sg) - qc->cursg_ofs, bytes); + count = min(sg->length - qc->cursg_ofs, bytes); /* don't cross page boundaries */ count = min(count, (unsigned int)PAGE_SIZE - offset); @@ -2358,7 +2359,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) qc->curbytes += count; qc->cursg_ofs += count; - if (qc->cursg_ofs == sg_dma_len(sg)) { + if (qc->cursg_ofs == sg->length) { qc->cursg++; qc->cursg_ofs = 0; } @@ -2371,7 +2372,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) kunmap(page); if (bytes) { - if (qc->cursg_ofs < sg_dma_len(sg)) + if (qc->cursg_ofs < sg->length) goto next_page; goto next_sg; } diff --git a/trunk/include/linux/ide.h b/trunk/include/linux/ide.h index 336d6e509f59..9cfc0999becb 100644 --- a/trunk/include/linux/ide.h +++ b/trunk/include/linux/ide.h @@ -664,6 +664,7 @@ typedef struct ide_drive_s { struct request *rq; /* current request */ struct ide_drive_s *next; /* circular list of hwgroup drives */ + struct ide_driver_s *driver;/* (ide_driver_t *) */ void *driver_data; /* extra driver data */ struct hd_driveid *id; /* drive model identification info */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ @@ -757,8 +758,6 @@ typedef struct ide_drive_s { struct semaphore gendev_rel_sem; /* to deal with device release() */ } ide_drive_t; -#define to_ide_device(dev)container_of(dev, ide_drive_t, gendev) - #define IDE_CHIPSET_PCI_MASK \ ((1<> (c)) & 1) @@ -1087,20 +1086,28 @@ enum { */ typedef struct ide_driver_s { struct module *owner; + const char *name; const char *version; u8 media; + unsigned busy : 1; unsigned supports_dsc_overlap : 1; + int (*cleanup)(ide_drive_t *); ide_startstop_t (*do_request)(ide_drive_t *, struct request *, sector_t); int (*end_request)(ide_drive_t *, int, int); ide_startstop_t (*error)(ide_drive_t *, struct request *rq, u8, u8); ide_startstop_t (*abort)(ide_drive_t *, struct request *rq); int (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); ide_proc_entry_t *proc; + int (*attach)(ide_drive_t *); void (*ata_prebuilder)(ide_drive_t *); void (*atapi_prebuilder)(ide_drive_t *); struct device_driver gen_driver; + struct list_head drives; + struct list_head drivers; } ide_driver_t; +#define DRIVER(drive) ((drive)->driver) + int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long); /* @@ -1321,6 +1328,8 @@ extern void ide_init_subdrivers(void); void ide_init_disk(struct gendisk *, ide_drive_t *); +extern int ata_attach(ide_drive_t *); + extern int ideprobe_init(void); extern void ide_scan_pcibus(int scan_direction) __init; @@ -1333,8 +1342,11 @@ extern void default_hwif_iops(ide_hwif_t *); extern void default_hwif_mmiops(ide_hwif_t *); extern void default_hwif_transport(ide_hwif_t *); -void ide_register_subdriver(ide_drive_t *, ide_driver_t *); -void ide_unregister_subdriver(ide_drive_t *, ide_driver_t *); +int ide_register_driver(ide_driver_t *driver); +void ide_unregister_driver(ide_driver_t *driver); +int ide_register_subdriver(ide_drive_t *, ide_driver_t *); +int ide_unregister_subdriver (ide_drive_t *drive); +int ide_replace_subdriver(ide_drive_t *drive, const char *driver); #define ON_BOARD 1 #define NEVER_BOARD 0