|
@@ -34,62 +34,25 @@ struct ata_acpi_gtf {
|
|
|
u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
|
|
|
} __packed;
|
|
|
|
|
|
-/*
|
|
|
- * Helper - belongs in the PCI layer somewhere eventually
|
|
|
- */
|
|
|
-static int is_pci_dev(struct device *dev)
|
|
|
-{
|
|
|
- return (dev->bus == &pci_bus_type);
|
|
|
-}
|
|
|
-
|
|
|
static void ata_acpi_clear_gtf(struct ata_device *dev)
|
|
|
{
|
|
|
kfree(dev->gtf_cache);
|
|
|
dev->gtf_cache = NULL;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * ata_ap_acpi_handle - provide the acpi_handle for an ata_port
|
|
|
- * @ap: the acpi_handle returned will correspond to this port
|
|
|
- *
|
|
|
- * Returns the acpi_handle for the ACPI namespace object corresponding to
|
|
|
- * the ata_port passed into the function, or NULL if no such object exists
|
|
|
- */
|
|
|
-acpi_handle ata_ap_acpi_handle(struct ata_port *ap)
|
|
|
-{
|
|
|
- if (ap->flags & ATA_FLAG_ACPI_SATA)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- return ap->scsi_host ?
|
|
|
- DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev) : NULL;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(ata_ap_acpi_handle);
|
|
|
-
|
|
|
/**
|
|
|
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device
|
|
|
- * @dev: the acpi_device returned will correspond to this port
|
|
|
+ * @dev: the acpi_handle returned will correspond to this device
|
|
|
*
|
|
|
* Returns the acpi_handle for the ACPI namespace object corresponding to
|
|
|
* the ata_device passed into the function, or NULL if no such object exists
|
|
|
+ * or ACPI is disabled for this device due to consecutive errors.
|
|
|
*/
|
|
|
acpi_handle ata_dev_acpi_handle(struct ata_device *dev)
|
|
|
{
|
|
|
- acpi_integer adr;
|
|
|
- struct ata_port *ap = dev->link->ap;
|
|
|
-
|
|
|
- if (libata_noacpi || dev->flags & ATA_DFLAG_ACPI_DISABLED)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- if (ap->flags & ATA_FLAG_ACPI_SATA) {
|
|
|
- if (!sata_pmp_attached(ap))
|
|
|
- adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
|
|
|
- else
|
|
|
- adr = SATA_ADR(ap->port_no, dev->link->pmp);
|
|
|
- return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), adr);
|
|
|
- } else
|
|
|
- return acpi_get_child(ata_ap_acpi_handle(ap), dev->devno);
|
|
|
+ return dev->flags & ATA_DFLAG_ACPI_DISABLED ?
|
|
|
+ NULL : ACPI_HANDLE(&dev->tdev);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(ata_dev_acpi_handle);
|
|
|
|
|
|
/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
|
|
|
static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
|
|
@@ -156,10 +119,8 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
|
|
|
|
|
|
spin_unlock_irqrestore(ap->lock, flags);
|
|
|
|
|
|
- if (wait) {
|
|
|
+ if (wait)
|
|
|
ata_port_wait_eh(ap);
|
|
|
- flush_work(&ap->hotplug_task.work);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
|
|
@@ -216,37 +177,55 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
|
|
|
.uevent = ata_acpi_ap_uevent,
|
|
|
};
|
|
|
|
|
|
-void ata_acpi_hotplug_init(struct ata_host *host)
|
|
|
+/* bind acpi handle to pata port */
|
|
|
+void ata_acpi_bind_port(struct ata_port *ap)
|
|
|
{
|
|
|
- int i;
|
|
|
+ acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
|
|
|
|
|
|
- for (i = 0; i < host->n_ports; i++) {
|
|
|
- struct ata_port *ap = host->ports[i];
|
|
|
- acpi_handle handle;
|
|
|
- struct ata_device *dev;
|
|
|
+ if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle)
|
|
|
+ return;
|
|
|
|
|
|
- if (!ap)
|
|
|
- continue;
|
|
|
+ ACPI_HANDLE_SET(&ap->tdev, acpi_get_child(host_handle, ap->port_no));
|
|
|
|
|
|
- handle = ata_ap_acpi_handle(ap);
|
|
|
- if (handle) {
|
|
|
- /* we might be on a docking station */
|
|
|
- register_hotplug_dock_device(handle,
|
|
|
- &ata_acpi_ap_dock_ops, ap,
|
|
|
- NULL, NULL);
|
|
|
- }
|
|
|
+ if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
|
|
|
+ ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
|
|
|
|
|
- ata_for_each_dev(dev, &ap->link, ALL) {
|
|
|
- handle = ata_dev_acpi_handle(dev);
|
|
|
- if (!handle)
|
|
|
- continue;
|
|
|
+ /* we might be on a docking station */
|
|
|
+ register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
|
|
|
+ &ata_acpi_ap_dock_ops, ap, NULL, NULL);
|
|
|
+}
|
|
|
|
|
|
- /* we might be on a docking station */
|
|
|
- register_hotplug_dock_device(handle,
|
|
|
- &ata_acpi_dev_dock_ops,
|
|
|
- dev, NULL, NULL);
|
|
|
- }
|
|
|
+void ata_acpi_bind_dev(struct ata_device *dev)
|
|
|
+{
|
|
|
+ struct ata_port *ap = dev->link->ap;
|
|
|
+ acpi_handle port_handle = ACPI_HANDLE(&ap->tdev);
|
|
|
+ acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
|
|
|
+ acpi_handle parent_handle;
|
|
|
+ u64 adr;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For both sata/pata devices, host handle is required.
|
|
|
+ * For pata device, port handle is also required.
|
|
|
+ */
|
|
|
+ if (libata_noacpi || !host_handle ||
|
|
|
+ (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (ap->flags & ATA_FLAG_ACPI_SATA) {
|
|
|
+ if (!sata_pmp_attached(ap))
|
|
|
+ adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
|
|
|
+ else
|
|
|
+ adr = SATA_ADR(ap->port_no, dev->link->pmp);
|
|
|
+ parent_handle = host_handle;
|
|
|
+ } else {
|
|
|
+ adr = dev->devno;
|
|
|
+ parent_handle = port_handle;
|
|
|
}
|
|
|
+
|
|
|
+ ACPI_HANDLE_SET(&dev->tdev, acpi_get_child(parent_handle, adr));
|
|
|
+
|
|
|
+ register_hotplug_dock_device(ata_dev_acpi_handle(dev),
|
|
|
+ &ata_acpi_dev_dock_ops, dev, NULL, NULL);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -270,18 +249,34 @@ void ata_acpi_dissociate(struct ata_host *host)
|
|
|
struct ata_port *ap = host->ports[i];
|
|
|
const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
|
|
|
|
|
|
- if (ata_ap_acpi_handle(ap) && gtm)
|
|
|
+ if (ACPI_HANDLE(&ap->tdev) && gtm)
|
|
|
ata_acpi_stm(ap, gtm);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle,
|
|
|
- struct ata_acpi_gtm *gtm)
|
|
|
+/**
|
|
|
+ * ata_acpi_gtm - execute _GTM
|
|
|
+ * @ap: target ATA port
|
|
|
+ * @gtm: out parameter for _GTM result
|
|
|
+ *
|
|
|
+ * Evaluate _GTM and store the result in @gtm.
|
|
|
+ *
|
|
|
+ * LOCKING:
|
|
|
+ * EH context.
|
|
|
+ *
|
|
|
+ * RETURNS:
|
|
|
+ * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
|
|
|
+ */
|
|
|
+int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
|
|
|
{
|
|
|
struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
|
|
|
union acpi_object *out_obj;
|
|
|
acpi_status status;
|
|
|
int rc = 0;
|
|
|
+ acpi_handle handle = ACPI_HANDLE(&ap->tdev);
|
|
|
+
|
|
|
+ if (!handle)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
status = acpi_evaluate_object(handle, "_GTM", NULL, &output);
|
|
|
|
|
@@ -317,27 +312,6 @@ static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle,
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * ata_acpi_gtm - execute _GTM
|
|
|
- * @ap: target ATA port
|
|
|
- * @gtm: out parameter for _GTM result
|
|
|
- *
|
|
|
- * Evaluate _GTM and store the result in @gtm.
|
|
|
- *
|
|
|
- * LOCKING:
|
|
|
- * EH context.
|
|
|
- *
|
|
|
- * RETURNS:
|
|
|
- * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
|
|
|
- */
|
|
|
-int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
|
|
|
-{
|
|
|
- if (ata_ap_acpi_handle(ap))
|
|
|
- return __ata_acpi_gtm(ap, ata_ap_acpi_handle(ap), gtm);
|
|
|
- else
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
EXPORT_SYMBOL_GPL(ata_acpi_gtm);
|
|
|
|
|
|
/**
|
|
@@ -374,8 +348,8 @@ int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm)
|
|
|
input.count = 3;
|
|
|
input.pointer = in_params;
|
|
|
|
|
|
- status = acpi_evaluate_object(ata_ap_acpi_handle(ap), "_STM", &input,
|
|
|
- NULL);
|
|
|
+ status = acpi_evaluate_object(ACPI_HANDLE(&ap->tdev), "_STM",
|
|
|
+ &input, NULL);
|
|
|
|
|
|
if (status == AE_NOT_FOUND)
|
|
|
return -ENOENT;
|
|
@@ -850,7 +824,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
|
|
|
const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
|
|
|
struct ata_device *dev;
|
|
|
|
|
|
- if (ata_ap_acpi_handle(ap) && gtm) {
|
|
|
+ if (ACPI_HANDLE(&ap->tdev) && gtm) {
|
|
|
/* _GTM valid */
|
|
|
|
|
|
/* restore timing parameters */
|
|
@@ -894,8 +868,7 @@ static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime)
|
|
|
d_max_in = ACPI_STATE_D3_HOT;
|
|
|
|
|
|
out:
|
|
|
- return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev,
|
|
|
- NULL, d_max_in);
|
|
|
+ return acpi_pm_device_sleep_state(&dev->tdev, NULL, d_max_in);
|
|
|
}
|
|
|
|
|
|
static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state)
|
|
@@ -932,7 +905,7 @@ static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state)
|
|
|
struct ata_device *dev;
|
|
|
acpi_handle port_handle;
|
|
|
|
|
|
- port_handle = ata_ap_acpi_handle(ap);
|
|
|
+ port_handle = ACPI_HANDLE(&ap->tdev);
|
|
|
if (!port_handle)
|
|
|
return;
|
|
|
|
|
@@ -1063,109 +1036,16 @@ void ata_acpi_on_disable(struct ata_device *dev)
|
|
|
ata_acpi_clear_gtf(dev);
|
|
|
}
|
|
|
|
|
|
-static int compat_pci_ata(struct ata_port *ap)
|
|
|
-{
|
|
|
- struct device *dev = ap->tdev.parent;
|
|
|
- struct pci_dev *pdev;
|
|
|
-
|
|
|
- if (!is_pci_dev(dev))
|
|
|
- return 0;
|
|
|
-
|
|
|
- pdev = to_pci_dev(dev);
|
|
|
-
|
|
|
- if ((pdev->class >> 8) != PCI_CLASS_STORAGE_SATA &&
|
|
|
- (pdev->class >> 8) != PCI_CLASS_STORAGE_IDE)
|
|
|
- return 0;
|
|
|
-
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
-static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
|
|
|
-{
|
|
|
- if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- *handle = acpi_get_child(DEVICE_ACPI_HANDLE(ap->tdev.parent),
|
|
|
- ap->port_no);
|
|
|
-
|
|
|
- if (!*handle)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- if (__ata_acpi_gtm(ap, *handle, &ap->__acpi_init_gtm) == 0)
|
|
|
- ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
|
|
|
- acpi_handle *handle)
|
|
|
-{
|
|
|
- struct ata_device *ata_dev;
|
|
|
-
|
|
|
- if (ap->flags & ATA_FLAG_ACPI_SATA) {
|
|
|
- if (!sata_pmp_attached(ap))
|
|
|
- ata_dev = &ap->link.device[sdev->id];
|
|
|
- else
|
|
|
- ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id];
|
|
|
- }
|
|
|
- else {
|
|
|
- ata_dev = &ap->link.device[sdev->id];
|
|
|
- }
|
|
|
-
|
|
|
- *handle = ata_dev_acpi_handle(ata_dev);
|
|
|
-
|
|
|
- if (!*handle)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int is_ata_port(const struct device *dev)
|
|
|
-{
|
|
|
- return dev->type == &ata_port_type;
|
|
|
-}
|
|
|
-
|
|
|
-static struct ata_port *dev_to_ata_port(struct device *dev)
|
|
|
-{
|
|
|
- while (!is_ata_port(dev)) {
|
|
|
- if (!dev->parent)
|
|
|
- return NULL;
|
|
|
- dev = dev->parent;
|
|
|
- }
|
|
|
- return to_ata_port(dev);
|
|
|
-}
|
|
|
-
|
|
|
-static int ata_acpi_find_device(struct device *dev, acpi_handle *handle)
|
|
|
-{
|
|
|
- struct ata_port *ap = dev_to_ata_port(dev);
|
|
|
-
|
|
|
- if (!ap)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- if (!compat_pci_ata(ap))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- if (scsi_is_host_device(dev))
|
|
|
- return ata_acpi_bind_host(ap, handle);
|
|
|
- else if (scsi_is_sdev_device(dev)) {
|
|
|
- struct scsi_device *sdev = to_scsi_device(dev);
|
|
|
-
|
|
|
- return ata_acpi_bind_device(ap, sdev, handle);
|
|
|
- } else
|
|
|
- return -ENODEV;
|
|
|
-}
|
|
|
-
|
|
|
-static struct acpi_bus_type ata_acpi_bus = {
|
|
|
- .name = "ATA",
|
|
|
- .find_device = ata_acpi_find_device,
|
|
|
-};
|
|
|
-
|
|
|
-int ata_acpi_register(void)
|
|
|
+void ata_scsi_acpi_bind(struct ata_device *dev)
|
|
|
{
|
|
|
- return scsi_register_acpi_bus_type(&ata_acpi_bus);
|
|
|
+ acpi_handle handle = ata_dev_acpi_handle(dev);
|
|
|
+ if (handle)
|
|
|
+ acpi_dev_pm_add_dependent(handle, &dev->sdev->sdev_gendev);
|
|
|
}
|
|
|
|
|
|
-void ata_acpi_unregister(void)
|
|
|
+void ata_scsi_acpi_unbind(struct ata_device *dev)
|
|
|
{
|
|
|
- scsi_unregister_acpi_bus_type(&ata_acpi_bus);
|
|
|
+ acpi_handle handle = ata_dev_acpi_handle(dev);
|
|
|
+ if (handle)
|
|
|
+ acpi_dev_pm_remove_dependent(handle, &dev->sdev->sdev_gendev);
|
|
|
}
|