fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / ide / ide.c
index dae1bd5..8e73fe5 100644 (file)
 
 #define _IDE_C                 /* Tell ide.h it's really us */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
@@ -222,7 +220,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
        hwif->mwdma_mask = 0x80;        /* disable all mwdma */
        hwif->swdma_mask = 0x80;        /* disable all swdma */
 
-       sema_init(&hwif->gendev_rel_sem, 0);
+       init_completion(&hwif->gendev_rel_comp);
 
        default_hwif_iops(hwif);
        default_hwif_transport(hwif);
@@ -242,10 +240,9 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
                drive->name[2]                  = 'a' + (index * MAX_DRIVES) + unit;
                drive->max_failures             = IDE_DEFAULT_MAX_FAILURES;
                drive->using_dma                = 0;
-               drive->is_flash                 = 0;
                drive->vdma                     = 0;
                INIT_LIST_HEAD(&drive->list);
-               sema_init(&drive->gendev_rel_sem, 0);
+               init_completion(&drive->gendev_rel_comp);
        }
 }
 
@@ -453,7 +450,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif)
  *     @hwif: hwif to update
  *     @tmp_hwif: template
  *
- *     Restore hwif to a previous state by copying most settngs
+ *     Restore hwif to a previous state by copying most settings
  *     from the template.
  */
 
@@ -506,6 +503,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->ide_dma_on                = tmp_hwif->ide_dma_on;
        hwif->ide_dma_off_quietly       = tmp_hwif->ide_dma_off_quietly;
        hwif->ide_dma_test_irq          = tmp_hwif->ide_dma_test_irq;
+       hwif->ide_dma_clear_irq         = tmp_hwif->ide_dma_clear_irq;
        hwif->ide_dma_host_on           = tmp_hwif->ide_dma_host_on;
        hwif->ide_dma_host_off          = tmp_hwif->ide_dma_host_off;
        hwif->ide_dma_lostirq           = tmp_hwif->ide_dma_lostirq;
@@ -542,9 +540,10 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->dma_vendor3               = tmp_hwif->dma_vendor3;
        hwif->dma_prdtable              = tmp_hwif->dma_prdtable;
 
-       hwif->dma_extra                 = tmp_hwif->dma_extra;
        hwif->config_data               = tmp_hwif->config_data;
        hwif->select_data               = tmp_hwif->select_data;
+       hwif->extra_base                = tmp_hwif->extra_base;
+       hwif->extra_ports               = tmp_hwif->extra_ports;
        hwif->autodma                   = tmp_hwif->autodma;
        hwif->udma_four                 = tmp_hwif->udma_four;
        hwif->no_dsc                    = tmp_hwif->no_dsc;
@@ -553,7 +552,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 }
 
 /**
- *     ide_unregister          -       free an ide interface
+ *     ide_unregister          -       free an IDE interface
  *     @index: index of interface (will change soon to a pointer)
  *
  *     Perform the final unregister of an IDE interface. At the moment
@@ -566,8 +565,8 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
  *     deadlocking the IDE layer. The shutdown callback is called
  *     before we take the lock and free resources. It is up to the
  *     caller to be sure there is no pending I/O here, and that
- *     the interfce will not be reopened (present/vanishing locking
- *     isnt yet done btw). After we commit to the final kill we
+ *     the interface will not be reopened (present/vanishing locking
+ *     isn't yet done BTW). After we commit to the final kill we
  *     call the cleanup callback with the ide locks held.
  *
  *     Unregister restores the hwif structures to the default state.
@@ -593,16 +592,11 @@ 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);
+               wait_for_completion(&drive->gendev_rel_comp);
                spin_lock_irq(&ide_lock);
        }
        hwif->present = 0;
@@ -662,7 +656,7 @@ void ide_unregister(unsigned int index)
        /* More messed up locking ... */
        spin_unlock_irq(&ide_lock);
        device_unregister(&hwif->gendev);
-       down(&hwif->gendev_rel_sem);
+       wait_for_completion(&hwif->gendev_rel_comp);
 
        /*
         * Remove us from the kernel's knowledge
@@ -682,6 +676,9 @@ void ide_unregister(unsigned int index)
                hwif->dma_status = 0;
                hwif->dma_vendor3 = 0;
                hwif->dma_prdtable = 0;
+
+               hwif->extra_base  = 0;
+               hwif->extra_ports = 0;
        }
 
        /* copy original settings */
@@ -727,6 +724,7 @@ void ide_setup_ports (      hw_regs_t *hw,
 {
        int i;
 
+       memset(hw, 0, sizeof(hw_regs_t));
        for (i = 0; i < IDE_NR_PORTS; i++) {
                if (offsets[i] == -1) {
                        switch(i) {
@@ -803,6 +801,7 @@ found:
        hwif->irq = hw->irq;
        hwif->noprobe = 0;
        hwif->chipset = hw->chipset;
+       hwif->gendev.parent = hw->dev;
 
        if (!initializing) {
                probe_hwif_init_with_fixup(hwif, fixup);
@@ -864,9 +863,8 @@ static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int r
        down(&ide_setting_sem);
        while ((*p) && strcmp((*p)->name, name) < 0)
                p = &((*p)->next);
-       if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+       if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
                goto abort;
-       memset(setting, 0, sizeof(*setting));
        if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
                goto abort;
        strcpy(setting->name, name);
@@ -889,8 +887,7 @@ static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int r
        return 0;
 abort:
        up(&ide_setting_sem);
-       if (setting)
-               kfree(setting);
+       kfree(setting);
        return -1;
 }
 
@@ -977,8 +974,8 @@ ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
  *     @drive: drive
  *
  *     Automatically remove all the driver specific settings for this
- *     drive. This function may sleep and must not be called from IRQ
- *     context. The caller must hold ide_setting_sem.
+ *     drive. This function may not be called from IRQ context. The
+ *     caller must hold ide_setting_sem.
  */
  
 static void auto_remove_settings (ide_drive_t *drive)
@@ -1215,7 +1212,7 @@ int system_bus_clock (void)
 
 EXPORT_SYMBOL(system_bus_clock);
 
-static int generic_ide_suspend(struct device *dev, pm_message_t state)
+static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
        ide_drive_t *drive = dev->driver_data;
        struct request rq;
@@ -1225,11 +1222,13 @@ static int generic_ide_suspend(struct device *dev, pm_message_t state)
        memset(&rq, 0, sizeof(rq));
        memset(&rqpm, 0, sizeof(rqpm));
        memset(&args, 0, sizeof(args));
-       rq.flags = REQ_PM_SUSPEND;
+       rq.cmd_type = REQ_TYPE_PM_SUSPEND;
        rq.special = &args;
-       rq.pm = &rqpm;
+       rq.data = &rqpm;
        rqpm.pm_step = ide_pm_state_start_suspend;
-       rqpm.pm_state = state;
+       if (mesg.event == PM_EVENT_PRETHAW)
+               mesg.event = PM_EVENT_FREEZE;
+       rqpm.pm_state = mesg.event;
 
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1244,11 +1243,11 @@ static int generic_ide_resume(struct device *dev)
        memset(&rq, 0, sizeof(rq));
        memset(&rqpm, 0, sizeof(rqpm));
        memset(&args, 0, sizeof(args));
-       rq.flags = REQ_PM_RESUME;
+       rq.cmd_type = REQ_TYPE_PM_RESUME;
        rq.special = &args;
-       rq.pm = &rqpm;
+       rq.data = &rqpm;
        rqpm.pm_step = ide_pm_state_start_resume;
-       rqpm.pm_state = 0;
+       rqpm.pm_state = PM_EVENT_ON;
 
        return ide_do_drive_cmd(drive, &rq, ide_head_wait);
 }
@@ -1279,19 +1278,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
        up(&ide_setting_sem);
 
        switch (cmd) {
-               case HDIO_GETGEO:
-               {
-                       struct hd_geometry geom;
-                       if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-                       geom.heads = drive->bios_head;
-                       geom.sectors = drive->bios_sect;
-                       geom.cylinders = (u16)drive->bios_cyl; /* truncate */
-                       geom.start = get_start_sect(bdev);
-                       if (copy_to_user(p, &geom, sizeof(struct hd_geometry)))
-                               return -EFAULT;
-                       return 0;
-               }
-
                case HDIO_OBSOLETE_IDENTITY:
                case HDIO_GET_IDENTITY:
                        if (bdev != bdev->bd_contains)
@@ -1379,10 +1365,14 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
 
                        spin_lock_irqsave(&ide_lock, flags);
 
+                       if (HWGROUP(drive)->resetting) {
+                               spin_unlock_irqrestore(&ide_lock, flags);
+                               return -EBUSY;
+                       }
+
                        ide_abort(drive, "drive reset");
 
-                       if(HWGROUP(drive)->handler)
-                               BUG();
+                       BUG_ON(HWGROUP(drive)->handler);
                                
                        /* Ensure nothing gets queued after we
                           drop the lock. Reset will clear the busy */
@@ -1561,7 +1551,7 @@ static int __init ide_setup(char *s)
                const char *hd_words[] = {
                        "none", "noprobe", "nowerr", "cdrom", "serialize",
                        "autotune", "noautotune", "minus8", "swapdata", "bswap",
-                       "minus11", "remap", "remap63", "scsi", NULL };
+                       "noflush", "remap", "remap63", "scsi", NULL };
                unit = s[2] - 'a';
                hw   = unit / MAX_DRIVES;
                unit = unit % MAX_DRIVES;
@@ -1600,6 +1590,9 @@ static int __init ide_setup(char *s)
                        case -10: /* "bswap" */
                                drive->bswap = 1;
                                goto done;
+                       case -11: /* noflush */
+                               drive->noflush = 1;
+                               goto done;
                        case -12: /* "remap" */
                                drive->remap_0_to_1 = 1;
                                goto done;
@@ -1789,8 +1782,9 @@ done:
        return 1;
 }
 
-extern void pnpide_init(void);
-extern void h8300_ide_init(void);
+extern void __init pnpide_init(void);
+extern void __exit pnpide_exit(void);
+extern void __init h8300_ide_init(void);
 
 /*
  * probe_for_hwifs() finds/initializes "known" IDE interfaces
@@ -1882,11 +1876,22 @@ 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);
 #ifdef CONFIG_PROC_FS
        ide_remove_proc_entries(drive->proc, driver->proc);
 #endif
+       down(&ide_setting_sem);
+       spin_lock_irqsave(&ide_lock, flags);
+       /*
+        * ide_setting_sem protects the settings list
+        * ide_lock protects the use of settings
+        *
+        * so we need to hold both, ide_settings_sem because we want to
+        * modify the settings list, and ide_lock because we cannot take
+        * a setting out that is being used.
+        *
+        * OTOH both ide_{read,write}_setting are only ever used under
+        * ide_setting_sem.
+        */
        auto_remove_settings(drive);
        spin_unlock_irqrestore(&ide_lock, flags);
        up(&ide_setting_sem);
@@ -1905,9 +1910,100 @@ static int ide_bus_match(struct device *dev, struct device_driver *drv)
        return 1;
 }
 
+static char *media_string(ide_drive_t *drive)
+{
+       switch (drive->media) {
+       case ide_disk:
+               return "disk";
+       case ide_cdrom:
+               return "cdrom";
+       case ide_tape:
+               return "tape";
+       case ide_floppy:
+               return "floppy";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       return sprintf(buf, "%s\n", media_string(drive));
+}
+
+static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       return sprintf(buf, "%s\n", drive->name);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       return sprintf(buf, "ide:m-%s\n", media_string(drive));
+}
+
+static struct device_attribute ide_dev_attrs[] = {
+       __ATTR_RO(media),
+       __ATTR_RO(drivename),
+       __ATTR_RO(modalias),
+       __ATTR_NULL
+};
+
+static int ide_uevent(struct device *dev, char **envp, int num_envp,
+                     char *buffer, int buffer_size)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       int i = 0;
+       int length = 0;
+
+       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+                      "MEDIA=%s", media_string(drive));
+       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+                      "DRIVENAME=%s", drive->name);
+       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+                      "MODALIAS=ide:m-%s", media_string(drive));
+       envp[i] = NULL;
+       return 0;
+}
+
+static int generic_ide_probe(struct device *dev)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       ide_driver_t *drv = to_ide_driver(dev->driver);
+
+       return drv->probe ? drv->probe(drive) : -ENODEV;
+}
+
+static int generic_ide_remove(struct device *dev)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       ide_driver_t *drv = to_ide_driver(dev->driver);
+
+       if (drv->remove)
+               drv->remove(drive);
+
+       return 0;
+}
+
+static void generic_ide_shutdown(struct device *dev)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       ide_driver_t *drv = to_ide_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(drive);
+}
+
 struct bus_type ide_bus_type = {
        .name           = "ide",
        .match          = ide_bus_match,
+       .uevent         = ide_uevent,
+       .probe          = generic_ide_probe,
+       .remove         = generic_ide_remove,
+       .shutdown       = generic_ide_shutdown,
+       .dev_attrs      = ide_dev_attrs,
        .suspend        = generic_ide_suspend,
        .resume         = generic_ide_resume,
 };
@@ -1919,11 +2015,16 @@ EXPORT_SYMBOL_GPL(ide_bus_type);
  */
 static int __init ide_init(void)
 {
+       int ret;
+
        printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-       devfs_mk_dir("ide");
        system_bus_speed = ide_system_bus_speed();
 
-       bus_register(&ide_bus_type);
+       ret = bus_register(&ide_bus_type);
+       if (ret < 0) {
+               printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
+               return ret;
+       }
 
        init_ide_data();
 
@@ -1982,23 +2083,26 @@ static void __init parse_options (char *line)
        }
 }
 
-int init_module (void)
+int __init init_module (void)
 {
        parse_options(options);
        return ide_init();
 }
 
-void cleanup_module (void)
+void __exit cleanup_module (void)
 {
        int index;
 
        for (index = 0; index < MAX_HWIFS; ++index)
                ide_unregister(index);
 
+#ifdef CONFIG_BLK_DEV_IDEPNP
+       pnpide_exit();
+#endif
+
 #ifdef CONFIG_PROC_FS
        proc_ide_destroy();
 #endif
-       devfs_remove("ide");
 
        bus_unregister(&ide_bus_type);
 }