kprobes: check CONFIG_FREEZER instead of CONFIG_PM
[safe/jmp/linux-2.6] / drivers / ide / ide-acpi.c
index 1eb7349..d8f295b 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * ide-acpi.c
  * Provides ACPI support for IDE drives.
  *
  * Copyright (C) 2005 Intel Corp.
 #include <acpi/acpi.h>
 #include <linux/ide.h>
 #include <linux/pci.h>
+#include <linux/dmi.h>
 
 #include <acpi/acpi_bus.h>
-#include <acpi/acnames.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acexcep.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
 
 #define REGS_PER_GTF           7
 struct taskfile_array {
@@ -39,7 +33,6 @@ struct GTM_buffer {
 };
 
 struct ide_acpi_drive_link {
-       ide_drive_t     *drive;
        acpi_handle      obj_handle;
        u8               idbuff[512];
 };
@@ -56,14 +49,55 @@ struct ide_acpi_hwif_link {
 /* note: adds function name and KERN_DEBUG */
 #ifdef DEBUGGING
 #define DEBPRINT(fmt, args...) \
-               printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+               printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
 #else
 #define DEBPRINT(fmt, args...) do {} while (0)
 #endif /* DEBUGGING */
 
-extern int ide_noacpi;
-extern int ide_noacpitfs;
-extern int ide_noacpionboot;
+static int ide_noacpi;
+module_param_named(noacpi, ide_noacpi, bool, 0);
+MODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
+
+static int ide_acpigtf;
+module_param_named(acpigtf, ide_acpigtf, bool, 0);
+MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
+
+static int ide_acpionboot;
+module_param_named(acpionboot, ide_acpionboot, bool, 0);
+MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
+
+static bool ide_noacpi_psx;
+static int no_acpi_psx(const struct dmi_system_id *id)
+{
+       ide_noacpi_psx = true;
+       printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);
+       return 0;
+}
+
+static const struct dmi_system_id ide_acpi_dmi_table[] = {
+       /* Bug 9673. */
+       /* We should check if this is because ACPI NVS isn't save/restored. */
+       {
+               .callback = no_acpi_psx,
+               .ident    = "HP nx9005",
+               .matches  = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),
+                       DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")
+               },
+       },
+
+       { }     /* terminate list */
+};
+
+static int ide_acpi_blacklist(void)
+{
+       static int done;
+       if (done)
+               return 0;
+       done = 1;
+       dmi_check_system(ide_acpi_dmi_table);
+       return 0;
+}
 
 /**
  * ide_get_dev_handle - finds acpi_handle and PCI device.function
@@ -139,7 +173,7 @@ err:
 static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
 {
        struct device           *dev = hwif->gendev.parent;
-       acpi_handle             dev_handle;
+       acpi_handle             uninitialized_var(dev_handle);
        acpi_integer            pcidevfn;
        acpi_handle             chan_handle;
        int                     err;
@@ -178,7 +212,7 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
  */
 static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
 {
-       ide_hwif_t      *hwif = HWIF(drive);
+       ide_hwif_t      *hwif = drive->hwif;
        int              port;
        acpi_handle      drive_handle;
 
@@ -223,7 +257,7 @@ static int do_drive_get_GTF(ide_drive_t *drive,
        acpi_status                     status;
        struct acpi_buffer              output;
        union acpi_object               *out_obj;
-       ide_hwif_t                      *hwif = HWIF(drive);
+       ide_hwif_t                      *hwif = drive->hwif;
        struct device                   *dev = hwif->gendev.parent;
        int                             err = -ENODEV;
        int                             port;
@@ -247,20 +281,10 @@ static int do_drive_get_GTF(ide_drive_t *drive,
 
        port = hwif->channel ? drive->dn - 2: drive->dn;
 
-       if (!drive->acpidata) {
-               if (port == 0) {
-                       drive->acpidata = &hwif->acpidata->master;
-                       hwif->acpidata->master.drive = drive;
-               } else {
-                       drive->acpidata = &hwif->acpidata->slave;
-                       hwif->acpidata->slave.drive = drive;
-               }
-       }
-
        DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
                 hwif->name, dev->bus_id, port, hwif->channel);
 
-       if (!drive->present) {
+       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) {
                DEBPRINT("%s drive %d:%d not present\n",
                         hwif->name, hwif->channel, port);
                goto out;
@@ -287,7 +311,7 @@ static int do_drive_get_GTF(ide_drive_t *drive,
        if (ACPI_FAILURE(status)) {
                printk(KERN_DEBUG
                       "%s: Run _GTF error: status = 0x%x\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                goto out;
        }
 
@@ -313,7 +337,7 @@ static int do_drive_get_GTF(ide_drive_t *drive,
            out_obj->buffer.length % REGS_PER_GTF) {
                printk(KERN_ERR
                       "%s: unexpected GTF length (%d) or addr (0x%p)\n",
-                      __FUNCTION__, out_obj->buffer.length,
+                      __func__, out_obj->buffer.length,
                       out_obj->buffer.pointer);
                err = -ENOENT;
                kfree(output.pointer);
@@ -349,28 +373,20 @@ static int taskfile_load_raw(ide_drive_t *drive,
               gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
 
        memset(&args, 0, sizeof(ide_task_t));
-       args.command_type = IDE_DRIVE_TASK_NO_DATA;
-       args.data_phase   = TASKFILE_IN;
-       args.handler      = &task_no_data_intr;
 
        /* convert gtf to IDE Taskfile */
-       args.tfRegister[1] = gtf->tfa[0];       /* 0x1f1 */
-       args.tfRegister[2] = gtf->tfa[1];       /* 0x1f2 */
-       args.tfRegister[3] = gtf->tfa[2];       /* 0x1f3 */
-       args.tfRegister[4] = gtf->tfa[3];       /* 0x1f4 */
-       args.tfRegister[5] = gtf->tfa[4];       /* 0x1f5 */
-       args.tfRegister[6] = gtf->tfa[5];       /* 0x1f6 */
-       args.tfRegister[7] = gtf->tfa[6];       /* 0x1f7 */
-
-       if (ide_noacpitfs) {
+       memcpy(&args.tf_array[7], &gtf->tfa, 7);
+       args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+       if (!ide_acpigtf) {
                DEBPRINT("_GTF execution disabled\n");
                return err;
        }
 
-       err = ide_raw_taskfile(drive, &args, NULL);
+       err = ide_no_data_taskfile(drive, &args);
        if (err)
-               printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
-                      __FUNCTION__, err);
+               printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
+                      __func__, err);
 
        return err;
 }
@@ -398,8 +414,9 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
 
        DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
 
-       if (!drive->present)
+       if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                goto out;
+
        if (!gtf_count)         /* shouldn't be here */
                goto out;
 
@@ -408,7 +425,7 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
 
        if (gtf_length % REGS_PER_GTF) {
                printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
-                      __FUNCTION__, gtf_length);
+                      __func__, gtf_length);
                goto out;
        }
 
@@ -469,7 +486,6 @@ int ide_acpi_exec_tfs(ide_drive_t *drive)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
 
 /**
  * ide_acpi_get_timing - get the channel (controller) timings
@@ -532,9 +548,10 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
            out_obj->buffer.length != sizeof(struct GTM_buffer)) {
                kfree(output.pointer);
                printk(KERN_ERR
-                      "%s: unexpected _GTM length (0x%x)[should be 0x%x] or addr (0x%p)\n",
-                      __FUNCTION__, out_obj->buffer.length,
-                      sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+                       "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+                       "addr (0x%p)\n",
+                       __func__, out_obj->buffer.length,
+                       sizeof(struct GTM_buffer), out_obj->buffer.pointer);
                return;
        }
 
@@ -554,7 +571,6 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
 
        kfree(output.pointer);
 }
-EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
 
 /**
  * ide_acpi_push_timing - set the channel (controller) timings
@@ -563,7 +579,7 @@ EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
  * This function executes the _STM ACPI method for the target channel.
  *
  * _STM requires Identify Drive data, which has to passed as an argument.
- * Unfortunately hd_driveid is a mangled version which we can't readily
+ * Unfortunately drive->id is a mangled version which we can't readily
  * use; hence we'll get the information afresh.
  */
 void ide_acpi_push_timing(ide_hwif_t *hwif)
@@ -593,10 +609,10 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        in_params[0].buffer.length = sizeof(struct GTM_buffer);
        in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
        in_params[1].type = ACPI_TYPE_BUFFER;
-       in_params[1].buffer.length = sizeof(struct hd_driveid);
+       in_params[1].buffer.length = ATA_ID_WORDS * 2;
        in_params[1].buffer.pointer = (u8 *)&master->idbuff;
        in_params[2].type = ACPI_TYPE_BUFFER;
-       in_params[2].buffer.length = sizeof(struct hd_driveid);
+       in_params[2].buffer.length = ATA_ID_WORDS * 2;
        in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
        /* Output buffer: _STM has no output */
 
@@ -608,7 +624,46 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        }
        DEBPRINT("_STM status: %d\n", status);
 }
-EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_set_state - set the channel power state
+ * @hwif: target IDE interface
+ * @on: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ide_acpi_set_state(ide_hwif_t *hwif, int on)
+{
+       ide_drive_t *drive;
+       int i;
+
+       if (ide_noacpi || ide_noacpi_psx)
+               return;
+
+       DEBPRINT("ENTER:\n");
+
+       if (!hwif->acpidata) {
+               DEBPRINT("no ACPI data for %s\n", hwif->name);
+               return;
+       }
+       /* channel first and then drives for power on and verse versa for power off */
+       if (on)
+               acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
+
+       ide_port_for_each_dev(i, drive, hwif) {
+               if (!drive->acpidata->obj_handle)
+                       drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+
+               if (drive->acpidata->obj_handle &&
+                   (drive->dev_flags & IDE_DFLAG_PRESENT)) {
+                       acpi_bus_set_power(drive->acpidata->obj_handle,
+                               on? ACPI_STATE_D0: ACPI_STATE_D3);
+               }
+       }
+       if (!on)
+               acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+}
 
 /**
  * ide_acpi_init - initialize the ACPI link for an IDE interface
@@ -623,10 +678,7 @@ EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
  */
 void ide_acpi_init(ide_hwif_t *hwif)
 {
-       int unit;
-       int                     err;
-       struct ide_acpi_drive_link      *master;
-       struct ide_acpi_drive_link      *slave;
+       ide_acpi_blacklist();
 
        hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
        if (!hwif->acpidata)
@@ -637,60 +689,56 @@ void ide_acpi_init(ide_hwif_t *hwif)
                DEBPRINT("no ACPI object for %s found\n", hwif->name);
                kfree(hwif->acpidata);
                hwif->acpidata = NULL;
-               return;
        }
+}
+
+void ide_acpi_port_init_devices(ide_hwif_t *hwif)
+{
+       ide_drive_t *drive;
+       int i, err;
+
+       if (hwif->acpidata == NULL)
+               return;
 
        /*
         * The ACPI spec mandates that we send information
         * for both drives, regardless whether they are connected
         * or not.
         */
-       hwif->acpidata->master.drive = &hwif->drives[0];
-       hwif->drives[0].acpidata = &hwif->acpidata->master;
-       master = &hwif->acpidata->master;
-
-       hwif->acpidata->slave.drive = &hwif->drives[1];
-       hwif->drives[1].acpidata = &hwif->acpidata->slave;
-       slave = &hwif->acpidata->slave;
-
+       hwif->devices[0]->acpidata = &hwif->acpidata->master;
+       hwif->devices[1]->acpidata = &hwif->acpidata->slave;
 
        /*
         * Send IDENTIFY for each drive
         */
-       if (master->drive->present) {
-               err = taskfile_lib_get_identify(master->drive, master->idbuff);
-               if (err) {
-                       DEBPRINT("identify device %s failed (%d)\n",
-                                master->drive->name, err);
-               }
-       }
+       ide_port_for_each_dev(i, drive, hwif) {
+               memset(drive->acpidata, 0, sizeof(*drive->acpidata));
+
+               if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+                       continue;
 
-       if (slave->drive->present) {
-               err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
-               if (err) {
+               err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
+               if (err)
                        DEBPRINT("identify device %s failed (%d)\n",
-                                slave->drive->name, err);
-               }
+                                drive->name, err);
        }
 
-       if (ide_noacpionboot) {
+       if (!ide_acpionboot) {
                DEBPRINT("ACPI methods disabled on boot\n");
                return;
        }
 
+       /* ACPI _PS0 before _STM */
+       ide_acpi_set_state(hwif, 1);
        /*
         * ACPI requires us to call _STM on startup
         */
        ide_acpi_get_timing(hwif);
        ide_acpi_push_timing(hwif);
 
-       for (unit = 0; unit < MAX_DRIVES; ++unit) {
-               ide_drive_t *drive = &hwif->drives[unit];
-
-               if (drive->present) {
+       ide_port_for_each_dev(i, drive, hwif) {
+               if (drive->dev_flags & IDE_DFLAG_PRESENT)
                        /* Execute ACPI startup code */
                        ide_acpi_exec_tfs(drive);
-               }
        }
 }
-EXPORT_SYMBOL_GPL(ide_acpi_init);