ide: use mutex instead of ide_setting_sem semaphore in IDE driver
[safe/jmp/linux-2.6] / drivers / ide / ide.c
index b2cc437..5744146 100644 (file)
 #define        REVISION        "Revision: 7.00alpha2"
 #define        VERSION         "Id: ide.c 7.00a2 20020906"
 
-#undef REALLY_SLOW_IO          /* most systems can safely undef this */
-
 #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>
@@ -172,23 +168,24 @@ static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
 
 static int idebus_parameter;   /* holds the "idebus=" parameter */
 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);
+DEFINE_MUTEX(ide_cfg_mtx);
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 #endif
 
-#ifdef CONFIG_IDEDMA_AUTO
 int noautodma = 0;
-#else
-int noautodma = 1;
-#endif
 
 EXPORT_SYMBOL(noautodma);
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
@@ -218,9 +215,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
        hwif->bus_state = BUSSTATE_ON;
 
        hwif->atapi_dma = 0;            /* disable all atapi dma */ 
-       hwif->ultra_mask = 0x80;        /* disable all ultra */
-       hwif->mwdma_mask = 0x80;        /* disable all mwdma */
-       hwif->swdma_mask = 0x80;        /* disable all swdma */
 
        init_completion(&hwif->gendev_rel_comp);
 
@@ -307,9 +301,7 @@ static void __init init_ide_data (void)
 #endif
        }
 #ifdef CONFIG_IDE_ARM
-       initializing = 1;
        ide_arm_init();
-       initializing = 0;
 #endif
 }
 
@@ -355,10 +347,6 @@ static int ide_system_bus_speed(void)
        return system_bus_speed;
 }
 
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_ide_root;
-#endif
-
 static struct resource* hwif_request_region(ide_hwif_t *hwif,
                                            unsigned long addr, int num)
 {
@@ -385,9 +373,8 @@ int ide_hwif_request_regions(ide_hwif_t *hwif)
        unsigned long addr;
        unsigned int i;
 
-       if (hwif->mmio == 2)
+       if (hwif->mmio)
                return 0;
-       BUG_ON(hwif->mmio == 1);
        addr = hwif->io_ports[IDE_CONTROL_OFFSET];
        if (addr && !hwif_request_region(hwif, addr, 1))
                goto control_region_busy;
@@ -434,7 +421,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif)
 {
        u32 i = 0;
 
-       if (hwif->mmio == 2)
+       if (hwif->mmio)
                return;
        if (hwif->io_ports[IDE_CONTROL_OFFSET])
                release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
@@ -452,7 +439,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.
  */
 
@@ -483,6 +470,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 
        hwif->tuneproc                  = tmp_hwif->tuneproc;
        hwif->speedproc                 = tmp_hwif->speedproc;
+       hwif->udma_filter               = tmp_hwif->udma_filter;
        hwif->selectproc                = tmp_hwif->selectproc;
        hwif->reset_poll                = tmp_hwif->reset_poll;
        hwif->pre_reset                 = tmp_hwif->pre_reset;
@@ -503,23 +491,22 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->ide_dma_end               = tmp_hwif->ide_dma_end;
        hwif->ide_dma_check             = tmp_hwif->ide_dma_check;
        hwif->ide_dma_on                = tmp_hwif->ide_dma_on;
-       hwif->ide_dma_off_quietly       = tmp_hwif->ide_dma_off_quietly;
+       hwif->dma_off_quietly           = tmp_hwif->dma_off_quietly;
        hwif->ide_dma_test_irq          = tmp_hwif->ide_dma_test_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;
-       hwif->ide_dma_timeout           = tmp_hwif->ide_dma_timeout;
+       hwif->ide_dma_clear_irq         = tmp_hwif->ide_dma_clear_irq;
+       hwif->dma_host_on               = tmp_hwif->dma_host_on;
+       hwif->dma_host_off              = tmp_hwif->dma_host_off;
+       hwif->dma_lost_irq              = tmp_hwif->dma_lost_irq;
+       hwif->dma_timeout               = tmp_hwif->dma_timeout;
 
        hwif->OUTB                      = tmp_hwif->OUTB;
        hwif->OUTBSYNC                  = tmp_hwif->OUTBSYNC;
        hwif->OUTW                      = tmp_hwif->OUTW;
-       hwif->OUTL                      = tmp_hwif->OUTL;
        hwif->OUTSW                     = tmp_hwif->OUTSW;
        hwif->OUTSL                     = tmp_hwif->OUTSL;
 
        hwif->INB                       = tmp_hwif->INB;
        hwif->INW                       = tmp_hwif->INW;
-       hwif->INL                       = tmp_hwif->INL;
        hwif->INSW                      = tmp_hwif->INSW;
        hwif->INSL                      = tmp_hwif->INSL;
 
@@ -541,18 +528,18 @@ 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;
 
        hwif->hwif_data                 = tmp_hwif->hwif_data;
 }
 
 /**
- *     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
@@ -565,8 +552,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.
@@ -577,7 +564,7 @@ void ide_unregister(unsigned int index)
 {
        ide_drive_t *drive;
        ide_hwif_t *hwif, *g;
-       static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
+       static ide_hwif_t tmp_hwif; /* protected by ide_cfg_mtx */
        ide_hwgroup_t *hwgroup;
        int irq_count = 0, unit;
 
@@ -585,20 +572,15 @@ void ide_unregister(unsigned int index)
 
        BUG_ON(in_interrupt());
        BUG_ON(irqs_disabled());
-       down(&ide_cfg_sem);
+       mutex_lock(&ide_cfg_mtx);
        spin_lock_irq(&ide_lock);
        hwif = &ide_hwifs[index];
        if (!hwif->present)
                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);
                wait_for_completion(&drive->gendev_rel_comp);
@@ -608,7 +590,7 @@ void ide_unregister(unsigned int index)
 
        spin_unlock_irq(&ide_lock);
 
-       destroy_proc_ide_interface(hwif);
+       ide_proc_unregister_port(hwif);
 
        hwgroup = hwif->hwgroup;
        /*
@@ -681,6 +663,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 */
@@ -694,7 +679,7 @@ void ide_unregister(unsigned int index)
 
 abort:
        spin_unlock_irq(&ide_lock);
-       up(&ide_cfg_sem);
+       mutex_unlock(&ide_cfg_mtx);
 }
 
 EXPORT_SYMBOL(ide_unregister);
@@ -726,6 +711,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) {
@@ -756,6 +742,7 @@ void ide_setup_ports (      hw_regs_t *hw,
 /**
  *     ide_register_hw_with_fixup      -       register IDE interface
  *     @hw: hardware registers
+ *     @initializing: set while initializing built-in drivers
  *     @hwifp: pointer to returned hwif
  *     @fixup: fixup function
  *
@@ -765,7 +752,9 @@ void ide_setup_ports (      hw_regs_t *hw,
  *     Returns -1 on error.
  */
 
-int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
+int ide_register_hw_with_fixup(hw_regs_t *hw, int initializing,
+                              ide_hwif_t **hwifp,
+                              void(*fixup)(ide_hwif_t *hwif))
 {
        int index, retry = 1;
        ide_hwif_t *hwif;
@@ -806,7 +795,7 @@ found:
 
        if (!initializing) {
                probe_hwif_init_with_fixup(hwif, fixup);
-               create_proc_ide_interfaces();
+               ide_proc_register_port(hwif);
        }
 
        if (hwifp)
@@ -817,9 +806,9 @@ found:
 
 EXPORT_SYMBOL(ide_register_hw_with_fixup);
 
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, int initializing, ide_hwif_t **hwifp)
 {
-       return ide_register_hw_with_fixup(hw, hwifp, NULL);
+       return ide_register_hw_with_fixup(hw, initializing, hwifp, NULL);
 }
 
 EXPORT_SYMBOL(ide_register_hw);
@@ -828,207 +817,9 @@ EXPORT_SYMBOL(ide_register_hw);
  *     Locks for IDE setting functionality
  */
 
-DECLARE_MUTEX(ide_setting_sem);
-
-/**
- *     __ide_add_setting       -       add an ide setting option
- *     @drive: drive to use
- *     @name: setting name
- *     @rw: true if the function is read write
- *     @read_ioctl: function to call on read
- *     @write_ioctl: function to call on write
- *     @data_type: type of data
- *     @min: range minimum
- *     @max: range maximum
- *     @mul_factor: multiplication scale
- *     @div_factor: divison scale
- *     @data: private data field
- *     @set: setting
- *     @auto_remove: setting auto removal flag
- *
- *     Removes the setting named from the device if it is present.
- *     The function takes the settings_lock to protect against 
- *     parallel changes. This function must not be called from IRQ
- *     context. Returns 0 on success or -1 on failure.
- *
- *     BUGS: This code is seriously over-engineered. There is also
- *     magic about how the driver specific features are setup. If
- *     a driver is attached we assume the driver settings are auto
- *     remove.
- */
-
-static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
-{
-       ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
-
-       down(&ide_setting_sem);
-       while ((*p) && strcmp((*p)->name, name) < 0)
-               p = &((*p)->next);
-       if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
-               goto abort;
-       if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
-               goto abort;
-       strcpy(setting->name, name);
-       setting->rw = rw;
-       setting->read_ioctl = read_ioctl;
-       setting->write_ioctl = write_ioctl;
-       setting->data_type = data_type;
-       setting->min = min;
-       setting->max = max;
-       setting->mul_factor = mul_factor;
-       setting->div_factor = div_factor;
-       setting->data = data;
-       setting->set = set;
-       
-       setting->next = *p;
-       if (auto_remove)
-               setting->auto_remove = 1;
-       *p = setting;
-       up(&ide_setting_sem);
-       return 0;
-abort:
-       up(&ide_setting_sem);
-       kfree(setting);
-       return -1;
-}
-
-int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
-{
-       return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
-}
-
-EXPORT_SYMBOL(ide_add_setting);
-
-/**
- *     __ide_remove_setting    -       remove an ide setting option
- *     @drive: drive to use
- *     @name: setting name
- *
- *     Removes the setting named from the device if it is present.
- *     The caller must hold the setting semaphore.
- */
-static void __ide_remove_setting (ide_drive_t *drive, char *name)
-{
-       ide_settings_t **p, *setting;
-
-       p = (ide_settings_t **) &drive->settings;
+DEFINE_MUTEX(ide_setting_mtx);
 
-       while ((*p) && strcmp((*p)->name, name))
-               p = &((*p)->next);
-       if ((setting = (*p)) == NULL)
-               return;
-
-       (*p) = setting->next;
-       
-       kfree(setting->name);
-       kfree(setting);
-}
-
-/**
- *     ide_find_setting_by_ioctl       -       find a drive specific ioctl
- *     @drive: drive to scan
- *     @cmd: ioctl command to handle
- *
- *     Scan's the device setting table for a matching entry and returns
- *     this or NULL if no entry is found. The caller must hold the
- *     setting semaphore
- */
-static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
-{
-       ide_settings_t *setting = drive->settings;
-
-       while (setting) {
-               if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
-                       break;
-               setting = setting->next;
-       }
-       
-       return setting;
-}
-
-/**
- *     ide_find_setting_by_name        -       find a drive specific setting
- *     @drive: drive to scan
- *     @name: setting name
- *
- *     Scan's the device setting table for a matching entry and returns
- *     this or NULL if no entry is found. The caller must hold the
- *     setting semaphore
- */
-ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
-{
-       ide_settings_t *setting = drive->settings;
-
-       while (setting) {
-               if (strcmp(setting->name, name) == 0)
-                       break;
-               setting = setting->next;
-       }
-       return setting;
-}
-
-/**
- *     auto_remove_settings    -       remove driver specific settings
- *     @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.
- */
-static void auto_remove_settings (ide_drive_t *drive)
-{
-       ide_settings_t *setting;
-repeat:
-       setting = drive->settings;
-       while (setting) {
-               if (setting->auto_remove) {
-                       __ide_remove_setting(drive, setting->name);
-                       goto repeat;
-               }
-               setting = setting->next;
-       }
-}
-
-/**
- *     ide_read_setting        -       read an IDE setting
- *     @drive: drive to read from
- *     @setting: drive setting
- *
- *     Read a drive setting and return the value. The caller
- *     must hold the ide_setting_sem when making this call.
- *
- *     BUGS: the data return and error are the same return value
- *     so an error -EINVAL and true return of the same value cannot
- *     be told apart
- */
-int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
-{
-       int             val = -EINVAL;
-       unsigned long   flags;
-
-       if ((setting->rw & SETTING_READ)) {
-               spin_lock_irqsave(&ide_lock, flags);
-               switch(setting->data_type) {
-                       case TYPE_BYTE:
-                               val = *((u8 *) setting->data);
-                               break;
-                       case TYPE_SHORT:
-                               val = *((u16 *) setting->data);
-                               break;
-                       case TYPE_INT:
-                       case TYPE_INTA:
-                               val = *((u32 *) setting->data);
-                               break;
-               }
-               spin_unlock_irqrestore(&ide_lock, flags);
-       }
-       return val;
-}
+EXPORT_SYMBOL_GPL(ide_setting_mtx);
 
 /**
  *     ide_spin_wait_hwgroup   -       wait for group
@@ -1063,61 +854,14 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive)
 
 EXPORT_SYMBOL(ide_spin_wait_hwgroup);
 
-/**
- *     ide_write_setting       -       read an IDE setting
- *     @drive: drive to read from
- *     @setting: drive setting
- *     @val: value
- *
- *     Write a drive setting if it is possible. The caller
- *     must hold the ide_setting_sem when making this call.
- *
- *     BUGS: the data return and error are the same return value
- *     so an error -EINVAL and true return of the same value cannot
- *     be told apart
- *
- *     FIXME:  This should be changed to enqueue a special request
- *     to the driver to change settings, and then wait on a sema for completion.
- *     The current scheme of polling is kludgy, though safe enough.
- */
-
-int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
+int set_io_32bit(ide_drive_t *drive, int arg)
 {
-       int i;
-       u32 *p;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-       if (!(setting->rw & SETTING_WRITE))
+       if (drive->no_io_32bit)
                return -EPERM;
-       if (val < setting->min || val > setting->max)
+
+       if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
                return -EINVAL;
-       if (setting->set)
-               return setting->set(drive, val);
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-       switch (setting->data_type) {
-               case TYPE_BYTE:
-                       *((u8 *) setting->data) = val;
-                       break;
-               case TYPE_SHORT:
-                       *((u16 *) setting->data) = val;
-                       break;
-               case TYPE_INT:
-                       *((u32 *) setting->data) = val;
-                       break;
-               case TYPE_INTA:
-                       p = (u32 *) setting->data;
-                       for (i = 0; i < 1 << PARTN_BITS; i++, p++)
-                               *p = val;
-                       break;
-       }
-       spin_unlock_irq(&ide_lock);
-       return 0;
-}
 
-static int set_io_32bit(ide_drive_t *drive, int arg)
-{
        drive->io_32bit = arg;
 #ifdef CONFIG_BLK_DEV_DTC2278
        if (HWIF(drive)->chipset == ide_dtc2278)
@@ -1126,30 +870,75 @@ static int set_io_32bit(ide_drive_t *drive, int arg)
        return 0;
 }
 
-static int set_using_dma (ide_drive_t *drive, int arg)
+static int set_ksettings(ide_drive_t *drive, int arg)
+{
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
+       if (ide_spin_wait_hwgroup(drive))
+               return -EBUSY;
+       drive->keep_settings = arg;
+       spin_unlock_irq(&ide_lock);
+
+       return 0;
+}
+
+int set_using_dma(ide_drive_t *drive, int arg)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
+       ide_hwif_t *hwif = drive->hwif;
+       int err = -EPERM;
+
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
        if (!drive->id || !(drive->id->capability & 1))
-               return -EPERM;
-       if (HWIF(drive)->ide_dma_check == NULL)
-               return -EPERM;
+               goto out;
+
+       if (hwif->ide_dma_check == NULL)
+               goto out;
+
+       err = -EBUSY;
+       if (ide_spin_wait_hwgroup(drive))
+               goto out;
+       /*
+        * set ->busy flag, unlock and let it ride
+        */
+       hwif->hwgroup->busy = 1;
+       spin_unlock_irq(&ide_lock);
+
+       err = 0;
+
        if (arg) {
-               if (HWIF(drive)->ide_dma_check(drive)) return -EIO;
-               if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
-       } else {
-               if (__ide_dma_off(drive))
-                       return -EIO;
-       }
-       return 0;
+               hwif->dma_off_quietly(drive);
+               if (ide_set_dma(drive) || hwif->ide_dma_on(drive))
+                       err = -EIO;
+       } else
+               ide_dma_off(drive);
+
+       /*
+        * lock, clear ->busy flag and unlock before leaving
+        */
+       spin_lock_irq(&ide_lock);
+       hwif->hwgroup->busy = 0;
+       spin_unlock_irq(&ide_lock);
+out:
+       return err;
 #else
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
        return -EPERM;
 #endif
 }
 
-static int set_pio_mode (ide_drive_t *drive, int arg)
+int set_pio_mode(ide_drive_t *drive, int arg)
 {
        struct request rq;
 
+       if (arg < 0 || arg > 255)
+               return -EINVAL;
+
        if (!HWIF(drive)->tuneproc)
                return -ENOSYS;
        if (drive->special.b.set_tune)
@@ -1161,42 +950,20 @@ static int set_pio_mode (ide_drive_t *drive, int arg)
        return 0;
 }
 
-static int set_xfer_rate (ide_drive_t *drive, int arg)
+static int set_unmaskirq(ide_drive_t *drive, int arg)
 {
-       int err = ide_wait_cmd(drive,
-                       WIN_SETFEATURES, (u8) arg,
-                       SETFEATURES_XFER, 0, NULL);
+       if (drive->no_unmask)
+               return -EPERM;
 
-       if (!err && arg) {
-               ide_set_xfer_rate(drive, (u8) arg);
-               ide_driveid_update(drive);
-       }
-       return err;
-}
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
 
-/**
- *     ide_add_generic_settings        -       generic ide settings
- *     @drive: drive being configured
- *
- *     Add the generic parts of the system settings to the /proc files and
- *     ioctls for this IDE device. The caller must not be holding the
- *     ide_setting_sem.
- */
+       if (ide_spin_wait_hwgroup(drive))
+               return -EBUSY;
+       drive->unmask = arg;
+       spin_unlock_irq(&ide_lock);
 
-void ide_add_generic_settings (ide_drive_t *drive)
-{
-/*
- *                       drive         setting name            read/write access                               read ioctl              write ioctl             data type       min     max                             mul_factor      div_factor      data pointer                    set function
- */
-       __ide_add_setting(drive,        "io_32bit",             drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT,         HDIO_SET_32BIT,         TYPE_BYTE,      0,      1 + (SUPPORT_VLB_SYNC << 1),    1,              1,              &drive->io_32bit,               set_io_32bit,   0);
-       __ide_add_setting(drive,        "keepsettings",         SETTING_RW,                                     HDIO_GET_KEEPSETTINGS,  HDIO_SET_KEEPSETTINGS,  TYPE_BYTE,      0,      1,                              1,              1,              &drive->keep_settings,          NULL,           0);
-       __ide_add_setting(drive,        "nice1",                SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->nice1,                  NULL,           0);
-       __ide_add_setting(drive,        "pio_mode",             SETTING_WRITE,                                  -1,                     HDIO_SET_PIO_MODE,      TYPE_BYTE,      0,      255,                            1,              1,              NULL,                           set_pio_mode,   0);
-       __ide_add_setting(drive,        "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   HDIO_GET_UNMASKINTR,    HDIO_SET_UNMASKINTR,    TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL,           0);
-       __ide_add_setting(drive,        "using_dma",            SETTING_RW,                                     HDIO_GET_DMA,           HDIO_SET_DMA,           TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma,  0);
-       __ide_add_setting(drive,        "init_speed",           SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL,           0);
-       __ide_add_setting(drive,        "current_speed",        SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          set_xfer_rate,  0);
-       __ide_add_setting(drive,        "number",               SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL,           0);
+       return 0;
 }
 
 /**
@@ -1213,21 +980,28 @@ 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;
+       ide_hwif_t *hwif = HWIF(drive);
        struct request rq;
        struct request_pm_state rqpm;
        ide_task_t args;
 
+       /* Call ACPI _GTM only once */
+       if (!(drive->dn % 2))
+               ide_acpi_get_timing(hwif);
+
        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.event;
+       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);
 }
@@ -1235,46 +1009,59 @@ static int generic_ide_suspend(struct device *dev, pm_message_t state)
 static int generic_ide_resume(struct device *dev)
 {
        ide_drive_t *drive = dev->driver_data;
+       ide_hwif_t *hwif = HWIF(drive);
        struct request rq;
        struct request_pm_state rqpm;
        ide_task_t args;
+       int err;
+
+       /* Call ACPI _STM only once */
+       if (!(drive->dn % 2))
+               ide_acpi_push_timing(hwif);
+
+       ide_acpi_exec_tfs(drive);
 
        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 = PM_EVENT_ON;
 
-       return ide_do_drive_cmd(drive, &rq, ide_head_wait);
+       err = ide_do_drive_cmd(drive, &rq, ide_head_wait);
+
+       if (err == 0 && dev->driver) {
+               ide_driver_t *drv = to_ide_driver(dev->driver);
+
+               if (drv->resume)
+                       drv->resume(drive);
+       }
+
+       return err;
 }
 
 int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
                        unsigned int cmd, unsigned long arg)
 {
-       ide_settings_t *setting;
+       unsigned long flags;
        ide_driver_t *drv;
-       int err = 0;
        void __user *p = (void __user *)arg;
+       int err = 0, (*setfunc)(ide_drive_t *, int);
+       u8 *val;
 
-       down(&ide_setting_sem);
-       if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
-               if (cmd == setting->read_ioctl) {
-                       err = ide_read_setting(drive, setting);
-                       up(&ide_setting_sem);
-                       return err >= 0 ? put_user(err, (long __user *)arg) : err;
-               } else {
-                       if (bdev != bdev->bd_contains)
-                               err = -EINVAL;
-                       else
-                               err = ide_write_setting(drive, setting, arg);
-                       up(&ide_setting_sem);
-                       return err;
-               }
+       switch (cmd) {
+       case HDIO_GET_32BIT:        val = &drive->io_32bit;      goto read_val;
+       case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val;
+       case HDIO_GET_UNMASKINTR:   val = &drive->unmask;        goto read_val;
+       case HDIO_GET_DMA:          val = &drive->using_dma;     goto read_val;
+       case HDIO_SET_32BIT:        setfunc = set_io_32bit;      goto set_val;
+       case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings;     goto set_val;
+       case HDIO_SET_PIO_MODE:     setfunc = set_pio_mode;      goto set_val;
+       case HDIO_SET_UNMASKINTR:   setfunc = set_unmaskirq;     goto set_val;
+       case HDIO_SET_DMA:          setfunc = set_using_dma;     goto set_val;
        }
-       up(&ide_setting_sem);
 
        switch (cmd) {
                case HDIO_OBSOLETE_IDENTITY:
@@ -1328,7 +1115,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        ide_init_hwif_ports(&hw, (unsigned long) args[0],
                                            (unsigned long) args[1], NULL);
                        hw.irq = args[2];
-                       if (ide_register_hw(&hw, NULL) == -1)
+                       if (ide_register_hw(&hw, 0, NULL) == -1)
                                return -EIO;
                        return 0;
                }
@@ -1364,10 +1151,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 */
@@ -1399,6 +1190,28 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                default:
                        return -EINVAL;
        }
+
+read_val:
+       mutex_lock(&ide_setting_mtx);
+       spin_lock_irqsave(&ide_lock, flags);
+       err = *val;
+       spin_unlock_irqrestore(&ide_lock, flags);
+       mutex_unlock(&ide_setting_mtx);
+       return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+       if (bdev != bdev->bd_contains)
+               err = -EINVAL;
+       else {
+               if (!capable(CAP_SYS_ADMIN))
+                       err = -EACCES;
+               else {
+                       mutex_lock(&ide_setting_mtx);
+                       err = setfunc(drive, arg);
+                       mutex_unlock(&ide_setting_mtx);
+               }
+       }
+       return err;
 }
 
 EXPORT_SYMBOL(generic_ide_ioctl);
@@ -1468,23 +1281,23 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
 }
 
 #ifdef CONFIG_BLK_DEV_ALI14XX
-static int __initdata probe_ali14xx;
+extern int probe_ali14xx;
 extern int ali14xx_init(void);
 #endif
 #ifdef CONFIG_BLK_DEV_UMC8672
-static int __initdata probe_umc8672;
+extern int probe_umc8672;
 extern int umc8672_init(void);
 #endif
 #ifdef CONFIG_BLK_DEV_DTC2278
-static int __initdata probe_dtc2278;
+extern int probe_dtc2278;
 extern int dtc2278_init(void);
 #endif
 #ifdef CONFIG_BLK_DEV_HT6560B
-static int __initdata probe_ht6560b;
+extern int probe_ht6560b;
 extern int ht6560b_init(void);
 #endif
 #ifdef CONFIG_BLK_DEV_QD65XX
-static int __initdata probe_qd65xx;
+extern int probe_qd65xx;
 extern int qd65xx_init(void);
 #endif
 
@@ -1531,22 +1344,40 @@ static int __init ide_setup(char *s)
                return 1;
        }
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
        if (!strcmp(s, "ide=reverse")) {
                ide_scan_direction = 1;
                printk(" : Enabled support for IDE inverse scan order.\n");
                return 1;
        }
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+       if (!strcmp(s, "ide=noacpi")) {
+               //printk(" : Disable IDE ACPI support.\n");
+               ide_noacpi = 1;
+               return 1;
+       }
+       if (!strcmp(s, "ide=acpigtf")) {
+               //printk(" : Enable IDE ACPI _GTF support.\n");
+               ide_noacpitfs = 0;
+               return 1;
+       }
+       if (!strcmp(s, "ide=acpionboot")) {
+               //printk(" : Call IDE ACPI methods on boot.\n");
+               ide_noacpionboot = 0;
+               return 1;
+       }
+#endif /* CONFIG_BLK_DEV_IDEACPI */
 
        /*
         * Look for drive options:  "hdx="
         */
        if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
                const char *hd_words[] = {
-                       "none", "noprobe", "nowerr", "cdrom", "serialize",
+                       "none", "noprobe", "nowerr", "cdrom", "minus5",
                        "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;
@@ -1572,9 +1403,6 @@ static int __init ide_setup(char *s)
                                drive->ready_stat = 0;
                                hwif->noprobe = 0;
                                goto done;
-                       case -5: /* "serialize" */
-                               printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
-                               goto do_serialize;
                        case -6: /* "autotune" */
                                drive->autotune = IDE_TUNE_AUTO;
                                goto obsolete_option;
@@ -1585,6 +1413,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;
@@ -1632,7 +1463,7 @@ static int __init ide_setup(char *s)
                 * (-8, -9, -10) are reserved to ease the hardcoding.
                 */
                static const char *ide_words[] = {
-                       "noprobe", "serialize", "autotune", "noautotune", 
+                       "noprobe", "serialize", "minus3", "minus4",
                        "reset", "dma", "ata66", "minus8", "minus9",
                        "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
                        "dtc2278", "umc8672", "ali14xx", NULL };
@@ -1703,12 +1534,17 @@ static int __init ide_setup(char *s)
                                hwif->chipset = mate->chipset = ide_4drives;
                                mate->irq = hwif->irq;
                                memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
-                               goto do_serialize;
+                               hwif->mate = mate;
+                               mate->mate = hwif;
+                               hwif->serialized = mate->serialized = 1;
+                               goto obsolete_option;
                        }
 #endif /* CONFIG_BLK_DEV_4DRIVES */
                        case -10: /* minus10 */
                        case -9: /* minus9 */
                        case -8: /* minus8 */
+                       case -4:
+                       case -3:
                                goto bad_option;
                        case -7: /* ata66 */
 #ifdef CONFIG_BLK_DEV_IDEPCI
@@ -1723,16 +1559,7 @@ static int __init ide_setup(char *s)
                        case -5: /* "reset" */
                                hwif->reset = 1;
                                goto obsolete_option;
-                       case -4: /* "noautotune" */
-                               hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
-                               hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
-                               goto obsolete_option;
-                       case -3: /* "autotune" */
-                               hwif->drives[0].autotune = IDE_TUNE_AUTO;
-                               hwif->drives[1].autotune = IDE_TUNE_AUTO;
-                               goto obsolete_option;
                        case -2: /* "serialize" */
-                       do_serialize:
                                hwif->mate = &ide_hwifs[hw^1];
                                hwif->mate->mate = hwif;
                                hwif->serialized = hwif->mate->serialized = 1;
@@ -1774,17 +1601,18 @@ 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
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
        ide_scan_pcibus(ide_scan_direction);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 
 #ifdef CONFIG_ETRAX_IDE
        {
@@ -1800,8 +1628,8 @@ static void __init probe_for_hwifs (void)
 #endif /* CONFIG_BLK_DEV_CMD640 */
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
        {
-               extern void pmac_ide_probe(void);
-               pmac_ide_probe();
+               extern int pmac_ide_probe(void);
+               (void)pmac_ide_probe();
        }
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
 #ifdef CONFIG_BLK_DEV_GAYLE
@@ -1842,43 +1670,6 @@ static void __init probe_for_hwifs (void)
 #endif
 }
 
-void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
-#ifdef CONFIG_PROC_FS
-       ide_add_proc_entries(drive->proc, driver->proc, drive);
-#endif
-}
-
-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.
- *     Caller must hold none of the locks.
- */
-
-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
-       auto_remove_settings(drive);
-       spin_unlock_irqrestore(&ide_lock, flags);
-       up(&ide_setting_sem);
-}
-
-EXPORT_SYMBOL(ide_unregister_subdriver);
-
 /*
  * Probe module
  */
@@ -1901,6 +1692,8 @@ static char *media_string(ide_drive_t *drive)
                return "tape";
        case ide_floppy:
                return "floppy";
+       case ide_optical:
+               return "optical";
        default:
                return "UNKNOWN";
        }
@@ -1995,17 +1788,20 @@ 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();
 
-#ifdef CONFIG_PROC_FS
-       proc_ide_root = proc_mkdir("ide", NULL);
-#endif
+       proc_ide_create();
 
 #ifdef CONFIG_BLK_DEV_ALI14XX
        if (probe_ali14xx)
@@ -2028,14 +1824,9 @@ static int __init ide_init(void)
                (void)qd65xx_init();
 #endif
 
-       initializing = 1;
        /* Probe for special PCI and other "known" interface chipsets. */
        probe_for_hwifs();
-       initializing = 0;
 
-#ifdef CONFIG_PROC_FS
-       proc_ide_create();
-#endif
        return 0;
 }
 
@@ -2058,23 +1849,24 @@ 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_PROC_FS
-       proc_ide_destroy();
+#ifdef CONFIG_BLK_DEV_IDEPNP
+       pnpide_exit();
 #endif
-       devfs_remove("ide");
+
+       proc_ide_destroy();
 
        bus_unregister(&ide_bus_type);
 }