162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * libata-acpi.c 462306a36Sopenharmony_ci * Provides ACPI support for PATA/SATA. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2006 Intel Corp. 762306a36Sopenharmony_ci * Copyright (C) 2006 Randy Dunlap 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/ata.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/acpi.h> 1762306a36Sopenharmony_ci#include <linux/libata.h> 1862306a36Sopenharmony_ci#include <linux/pci.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2162306a36Sopenharmony_ci#include <scsi/scsi_device.h> 2262306a36Sopenharmony_ci#include "libata.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciunsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT; 2562306a36Sopenharmony_cimodule_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644); 2662306a36Sopenharmony_ciMODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define NO_PORT_MULT 0xffff 2962306a36Sopenharmony_ci#define SATA_ADR(root, pmp) (((root) << 16) | (pmp)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define REGS_PER_GTF 7 3262306a36Sopenharmony_cistruct ata_acpi_gtf { 3362306a36Sopenharmony_ci u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ 3462306a36Sopenharmony_ci} __packed; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void ata_acpi_clear_gtf(struct ata_device *dev) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci kfree(dev->gtf_cache); 3962306a36Sopenharmony_ci dev->gtf_cache = NULL; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct ata_acpi_hotplug_context { 4362306a36Sopenharmony_ci struct acpi_hotplug_context hp; 4462306a36Sopenharmony_ci union { 4562306a36Sopenharmony_ci struct ata_port *ap; 4662306a36Sopenharmony_ci struct ata_device *dev; 4762306a36Sopenharmony_ci } data; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/** 5362306a36Sopenharmony_ci * ata_dev_acpi_handle - provide the acpi_handle for an ata_device 5462306a36Sopenharmony_ci * @dev: the acpi_handle returned will correspond to this device 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * Returns the acpi_handle for the ACPI namespace object corresponding to 5762306a36Sopenharmony_ci * the ata_device passed into the function, or NULL if no such object exists 5862306a36Sopenharmony_ci * or ACPI is disabled for this device due to consecutive errors. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ciacpi_handle ata_dev_acpi_handle(struct ata_device *dev) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci return dev->flags & ATA_DFLAG_ACPI_DISABLED ? 6362306a36Sopenharmony_ci NULL : ACPI_HANDLE(&dev->tdev); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* @ap and @dev are the same as ata_acpi_handle_hotplug() */ 6762306a36Sopenharmony_cistatic void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci if (dev) 7062306a36Sopenharmony_ci dev->flags |= ATA_DFLAG_DETACH; 7162306a36Sopenharmony_ci else { 7262306a36Sopenharmony_ci struct ata_link *tlink; 7362306a36Sopenharmony_ci struct ata_device *tdev; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ata_for_each_link(tlink, ap, EDGE) 7662306a36Sopenharmony_ci ata_for_each_dev(tdev, tlink, ALL) 7762306a36Sopenharmony_ci tdev->flags |= ATA_DFLAG_DETACH; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci ata_port_schedule_eh(ap); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * ata_acpi_handle_hotplug - ACPI event handler backend 8562306a36Sopenharmony_ci * @ap: ATA port ACPI event occurred 8662306a36Sopenharmony_ci * @dev: ATA device ACPI event occurred (can be NULL) 8762306a36Sopenharmony_ci * @event: ACPI event which occurred 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * All ACPI bay / device realted events end up in this function. If 9062306a36Sopenharmony_ci * the event is port-wide @dev is NULL. If the event is specific to a 9162306a36Sopenharmony_ci * device, @dev points to it. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Hotplug (as opposed to unplug) notification is always handled as 9462306a36Sopenharmony_ci * port-wide while unplug only kills the target device on device-wide 9562306a36Sopenharmony_ci * event. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * LOCKING: 9862306a36Sopenharmony_ci * ACPI notify handler context. May sleep. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, 10162306a36Sopenharmony_ci u32 event) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct ata_eh_info *ehi = &ap->link.eh_info; 10462306a36Sopenharmony_ci int wait = 0; 10562306a36Sopenharmony_ci unsigned long flags; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci spin_lock_irqsave(ap->lock, flags); 10862306a36Sopenharmony_ci /* 10962306a36Sopenharmony_ci * When dock driver calls into the routine, it will always use 11062306a36Sopenharmony_ci * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and 11162306a36Sopenharmony_ci * ACPI_NOTIFY_EJECT_REQUEST for remove 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci switch (event) { 11462306a36Sopenharmony_ci case ACPI_NOTIFY_BUS_CHECK: 11562306a36Sopenharmony_ci case ACPI_NOTIFY_DEVICE_CHECK: 11662306a36Sopenharmony_ci ata_ehi_push_desc(ehi, "ACPI event"); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ata_ehi_hotplugged(ehi); 11962306a36Sopenharmony_ci ata_port_freeze(ap); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case ACPI_NOTIFY_EJECT_REQUEST: 12262306a36Sopenharmony_ci ata_ehi_push_desc(ehi, "ACPI event"); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci ata_acpi_detach_device(ap, dev); 12562306a36Sopenharmony_ci wait = 1; 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci spin_unlock_irqrestore(ap->lock, flags); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (wait) 13262306a36Sopenharmony_ci ata_port_wait_eh(ap); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct ata_device *dev = ata_hotplug_data(adev->hp).dev; 13862306a36Sopenharmony_ci ata_acpi_handle_hotplug(dev->link->ap, dev, event); 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event); 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, 14962306a36Sopenharmony_ci u32 event) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct kobject *kobj = NULL; 15262306a36Sopenharmony_ci char event_string[20]; 15362306a36Sopenharmony_ci char *envp[] = { event_string, NULL }; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (dev) { 15662306a36Sopenharmony_ci if (dev->sdev) 15762306a36Sopenharmony_ci kobj = &dev->sdev->sdev_gendev.kobj; 15862306a36Sopenharmony_ci } else 15962306a36Sopenharmony_ci kobj = &ap->dev->kobj; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (kobj) { 16262306a36Sopenharmony_ci snprintf(event_string, 20, "BAY_EVENT=%d", event); 16362306a36Sopenharmony_ci kobject_uevent_env(kobj, KOBJ_CHANGE, envp); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct ata_device *dev = ata_hotplug_data(adev->hp).dev; 17562306a36Sopenharmony_ci ata_acpi_uevent(dev->link->ap, dev, event); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* bind acpi handle to pata port */ 17962306a36Sopenharmony_civoid ata_acpi_bind_port(struct ata_port *ap) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); 18262306a36Sopenharmony_ci struct acpi_device *adev; 18362306a36Sopenharmony_ci struct ata_acpi_hotplug_context *context; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) 18662306a36Sopenharmony_ci return; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci acpi_preset_companion(&ap->tdev, host_companion, ap->port_no); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) 19162306a36Sopenharmony_ci ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci adev = ACPI_COMPANION(&ap->tdev); 19462306a36Sopenharmony_ci if (!adev || adev->hp) 19562306a36Sopenharmony_ci return; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci context = kzalloc(sizeof(*context), GFP_KERNEL); 19862306a36Sopenharmony_ci if (!context) 19962306a36Sopenharmony_ci return; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci context->data.ap = ap; 20262306a36Sopenharmony_ci acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock, 20362306a36Sopenharmony_ci ata_acpi_ap_uevent); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_civoid ata_acpi_bind_dev(struct ata_device *dev) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct ata_port *ap = dev->link->ap; 20962306a36Sopenharmony_ci struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); 21062306a36Sopenharmony_ci struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); 21162306a36Sopenharmony_ci struct acpi_device *parent, *adev; 21262306a36Sopenharmony_ci struct ata_acpi_hotplug_context *context; 21362306a36Sopenharmony_ci u64 adr; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * For both sata/pata devices, host companion device is required. 21762306a36Sopenharmony_ci * For pata device, port companion device is also required. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci if (libata_noacpi || !host_companion || 22062306a36Sopenharmony_ci (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion)) 22162306a36Sopenharmony_ci return; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (ap->flags & ATA_FLAG_ACPI_SATA) { 22462306a36Sopenharmony_ci if (!sata_pmp_attached(ap)) 22562306a36Sopenharmony_ci adr = SATA_ADR(ap->port_no, NO_PORT_MULT); 22662306a36Sopenharmony_ci else 22762306a36Sopenharmony_ci adr = SATA_ADR(ap->port_no, dev->link->pmp); 22862306a36Sopenharmony_ci parent = host_companion; 22962306a36Sopenharmony_ci } else { 23062306a36Sopenharmony_ci adr = dev->devno; 23162306a36Sopenharmony_ci parent = port_companion; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci acpi_preset_companion(&dev->tdev, parent, adr); 23562306a36Sopenharmony_ci adev = ACPI_COMPANION(&dev->tdev); 23662306a36Sopenharmony_ci if (!adev || adev->hp) 23762306a36Sopenharmony_ci return; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci context = kzalloc(sizeof(*context), GFP_KERNEL); 24062306a36Sopenharmony_ci if (!context) 24162306a36Sopenharmony_ci return; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci context->data.dev = dev; 24462306a36Sopenharmony_ci acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock, 24562306a36Sopenharmony_ci ata_acpi_dev_uevent); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/** 24962306a36Sopenharmony_ci * ata_acpi_dissociate - dissociate ATA host from ACPI objects 25062306a36Sopenharmony_ci * @host: target ATA host 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * This function is called during driver detach after the whole host 25362306a36Sopenharmony_ci * is shut down. 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * LOCKING: 25662306a36Sopenharmony_ci * EH context. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_civoid ata_acpi_dissociate(struct ata_host *host) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci int i; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Restore initial _GTM values so that driver which attaches 26362306a36Sopenharmony_ci * afterward can use them too. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci for (i = 0; i < host->n_ports; i++) { 26662306a36Sopenharmony_ci struct ata_port *ap = host->ports[i]; 26762306a36Sopenharmony_ci const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (ACPI_HANDLE(&ap->tdev) && gtm) 27062306a36Sopenharmony_ci ata_acpi_stm(ap, gtm); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/** 27562306a36Sopenharmony_ci * ata_acpi_gtm - execute _GTM 27662306a36Sopenharmony_ci * @ap: target ATA port 27762306a36Sopenharmony_ci * @gtm: out parameter for _GTM result 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Evaluate _GTM and store the result in @gtm. 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci * LOCKING: 28262306a36Sopenharmony_ci * EH context. 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci * RETURNS: 28562306a36Sopenharmony_ci * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ciint ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; 29062306a36Sopenharmony_ci union acpi_object *out_obj; 29162306a36Sopenharmony_ci acpi_status status; 29262306a36Sopenharmony_ci int rc = 0; 29362306a36Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(&ap->tdev); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (!handle) 29662306a36Sopenharmony_ci return -EINVAL; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci status = acpi_evaluate_object(handle, "_GTM", NULL, &output); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci rc = -ENOENT; 30162306a36Sopenharmony_ci if (status == AE_NOT_FOUND) 30262306a36Sopenharmony_ci goto out_free; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci rc = -EINVAL; 30562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 30662306a36Sopenharmony_ci ata_port_err(ap, "ACPI get timing mode failed (AE 0x%x)\n", 30762306a36Sopenharmony_ci status); 30862306a36Sopenharmony_ci goto out_free; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci out_obj = output.pointer; 31262306a36Sopenharmony_ci if (out_obj->type != ACPI_TYPE_BUFFER) { 31362306a36Sopenharmony_ci ata_port_warn(ap, "_GTM returned unexpected object type 0x%x\n", 31462306a36Sopenharmony_ci out_obj->type); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci goto out_free; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) { 32062306a36Sopenharmony_ci ata_port_err(ap, "_GTM returned invalid length %d\n", 32162306a36Sopenharmony_ci out_obj->buffer.length); 32262306a36Sopenharmony_ci goto out_free; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci memcpy(gtm, out_obj->buffer.pointer, sizeof(struct ata_acpi_gtm)); 32662306a36Sopenharmony_ci rc = 0; 32762306a36Sopenharmony_ci out_free: 32862306a36Sopenharmony_ci kfree(output.pointer); 32962306a36Sopenharmony_ci return rc; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_acpi_gtm); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/** 33562306a36Sopenharmony_ci * ata_acpi_stm - execute _STM 33662306a36Sopenharmony_ci * @ap: target ATA port 33762306a36Sopenharmony_ci * @stm: timing parameter to _STM 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Evaluate _STM with timing parameter @stm. 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * LOCKING: 34262306a36Sopenharmony_ci * EH context. 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * RETURNS: 34562306a36Sopenharmony_ci * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ciint ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci acpi_status status; 35062306a36Sopenharmony_ci struct ata_acpi_gtm stm_buf = *stm; 35162306a36Sopenharmony_ci struct acpi_object_list input; 35262306a36Sopenharmony_ci union acpi_object in_params[3]; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci in_params[0].type = ACPI_TYPE_BUFFER; 35562306a36Sopenharmony_ci in_params[0].buffer.length = sizeof(struct ata_acpi_gtm); 35662306a36Sopenharmony_ci in_params[0].buffer.pointer = (u8 *)&stm_buf; 35762306a36Sopenharmony_ci /* Buffers for id may need byteswapping ? */ 35862306a36Sopenharmony_ci in_params[1].type = ACPI_TYPE_BUFFER; 35962306a36Sopenharmony_ci in_params[1].buffer.length = 512; 36062306a36Sopenharmony_ci in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id; 36162306a36Sopenharmony_ci in_params[2].type = ACPI_TYPE_BUFFER; 36262306a36Sopenharmony_ci in_params[2].buffer.length = 512; 36362306a36Sopenharmony_ci in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci input.count = 3; 36662306a36Sopenharmony_ci input.pointer = in_params; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci status = acpi_evaluate_object(ACPI_HANDLE(&ap->tdev), "_STM", 36962306a36Sopenharmony_ci &input, NULL); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (status == AE_NOT_FOUND) 37262306a36Sopenharmony_ci return -ENOENT; 37362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 37462306a36Sopenharmony_ci ata_port_err(ap, "ACPI set timing mode failed (status=0x%x)\n", 37562306a36Sopenharmony_ci status); 37662306a36Sopenharmony_ci return -EINVAL; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_acpi_stm); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/** 38462306a36Sopenharmony_ci * ata_dev_get_GTF - get the drive bootup default taskfile settings 38562306a36Sopenharmony_ci * @dev: target ATA device 38662306a36Sopenharmony_ci * @gtf: output parameter for buffer containing _GTF taskfile arrays 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * This applies to both PATA and SATA drives. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * The _GTF method has no input parameters. 39162306a36Sopenharmony_ci * It returns a variable number of register set values (registers 39262306a36Sopenharmony_ci * hex 1F1..1F7, taskfiles). 39362306a36Sopenharmony_ci * The <variable number> is not known in advance, so have ACPI-CA 39462306a36Sopenharmony_ci * allocate the buffer as needed and return it, then free it later. 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * LOCKING: 39762306a36Sopenharmony_ci * EH context. 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * RETURNS: 40062306a36Sopenharmony_ci * Number of taskfiles on success, 0 if _GTF doesn't exist. -EINVAL 40162306a36Sopenharmony_ci * if _GTF is invalid. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_cistatic int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci acpi_status status; 40662306a36Sopenharmony_ci struct acpi_buffer output; 40762306a36Sopenharmony_ci union acpi_object *out_obj; 40862306a36Sopenharmony_ci int rc = 0; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* if _GTF is cached, use the cached value */ 41162306a36Sopenharmony_ci if (dev->gtf_cache) { 41262306a36Sopenharmony_ci out_obj = dev->gtf_cache; 41362306a36Sopenharmony_ci goto done; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* set up output buffer */ 41762306a36Sopenharmony_ci output.length = ACPI_ALLOCATE_BUFFER; 41862306a36Sopenharmony_ci output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* _GTF has no input parameters */ 42162306a36Sopenharmony_ci status = acpi_evaluate_object(ata_dev_acpi_handle(dev), "_GTF", NULL, 42262306a36Sopenharmony_ci &output); 42362306a36Sopenharmony_ci out_obj = dev->gtf_cache = output.pointer; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 42662306a36Sopenharmony_ci if (status != AE_NOT_FOUND) { 42762306a36Sopenharmony_ci ata_dev_warn(dev, "_GTF evaluation failed (AE 0x%x)\n", 42862306a36Sopenharmony_ci status); 42962306a36Sopenharmony_ci rc = -EINVAL; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci goto out_free; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (!output.length || !output.pointer) { 43562306a36Sopenharmony_ci ata_dev_dbg(dev, "Run _GTF: length or ptr is NULL (0x%llx, 0x%p)\n", 43662306a36Sopenharmony_ci (unsigned long long)output.length, 43762306a36Sopenharmony_ci output.pointer); 43862306a36Sopenharmony_ci rc = -EINVAL; 43962306a36Sopenharmony_ci goto out_free; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (out_obj->type != ACPI_TYPE_BUFFER) { 44362306a36Sopenharmony_ci ata_dev_warn(dev, "_GTF unexpected object type 0x%x\n", 44462306a36Sopenharmony_ci out_obj->type); 44562306a36Sopenharmony_ci rc = -EINVAL; 44662306a36Sopenharmony_ci goto out_free; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (out_obj->buffer.length % REGS_PER_GTF) { 45062306a36Sopenharmony_ci ata_dev_warn(dev, "unexpected _GTF length (%d)\n", 45162306a36Sopenharmony_ci out_obj->buffer.length); 45262306a36Sopenharmony_ci rc = -EINVAL; 45362306a36Sopenharmony_ci goto out_free; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci done: 45762306a36Sopenharmony_ci rc = out_obj->buffer.length / REGS_PER_GTF; 45862306a36Sopenharmony_ci if (gtf) { 45962306a36Sopenharmony_ci *gtf = (void *)out_obj->buffer.pointer; 46062306a36Sopenharmony_ci ata_dev_dbg(dev, "returning gtf=%p, gtf_count=%d\n", 46162306a36Sopenharmony_ci *gtf, rc); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci return rc; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci out_free: 46662306a36Sopenharmony_ci ata_acpi_clear_gtf(dev); 46762306a36Sopenharmony_ci return rc; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/** 47162306a36Sopenharmony_ci * ata_acpi_gtm_xfermask - determine xfermode from GTM parameter 47262306a36Sopenharmony_ci * @dev: target device 47362306a36Sopenharmony_ci * @gtm: GTM parameter to use 47462306a36Sopenharmony_ci * 47562306a36Sopenharmony_ci * Determine xfermask for @dev from @gtm. 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * LOCKING: 47862306a36Sopenharmony_ci * None. 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * RETURNS: 48162306a36Sopenharmony_ci * Determined xfermask. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ciunsigned int ata_acpi_gtm_xfermask(struct ata_device *dev, 48462306a36Sopenharmony_ci const struct ata_acpi_gtm *gtm) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci unsigned int xfer_mask = 0; 48762306a36Sopenharmony_ci unsigned int type; 48862306a36Sopenharmony_ci int unit; 48962306a36Sopenharmony_ci u8 mode; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* we always use the 0 slot for crap hardware */ 49262306a36Sopenharmony_ci unit = dev->devno; 49362306a36Sopenharmony_ci if (!(gtm->flags & 0x10)) 49462306a36Sopenharmony_ci unit = 0; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* PIO */ 49762306a36Sopenharmony_ci mode = ata_timing_cycle2mode(ATA_SHIFT_PIO, gtm->drive[unit].pio); 49862306a36Sopenharmony_ci xfer_mask |= ata_xfer_mode2mask(mode); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* See if we have MWDMA or UDMA data. We don't bother with 50162306a36Sopenharmony_ci * MWDMA if UDMA is available as this means the BIOS set UDMA 50262306a36Sopenharmony_ci * and our error changedown if it works is UDMA to PIO anyway. 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ci if (!(gtm->flags & (1 << (2 * unit)))) 50562306a36Sopenharmony_ci type = ATA_SHIFT_MWDMA; 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci type = ATA_SHIFT_UDMA; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci mode = ata_timing_cycle2mode(type, gtm->drive[unit].dma); 51062306a36Sopenharmony_ci xfer_mask |= ata_xfer_mode2mask(mode); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return xfer_mask; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci/** 51762306a36Sopenharmony_ci * ata_acpi_cbl_80wire - Check for 80 wire cable 51862306a36Sopenharmony_ci * @ap: Port to check 51962306a36Sopenharmony_ci * @gtm: GTM data to use 52062306a36Sopenharmony_ci * 52162306a36Sopenharmony_ci * Return 1 if the @gtm indicates the BIOS selected an 80wire mode. 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ciint ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct ata_device *dev; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ENABLED) { 52862306a36Sopenharmony_ci unsigned int xfer_mask, udma_mask; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci xfer_mask = ata_acpi_gtm_xfermask(dev, gtm); 53162306a36Sopenharmony_ci ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (udma_mask & ~ATA_UDMA_MASK_40C) 53462306a36Sopenharmony_ci return 1; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void ata_acpi_gtf_to_tf(struct ata_device *dev, 54262306a36Sopenharmony_ci const struct ata_acpi_gtf *gtf, 54362306a36Sopenharmony_ci struct ata_taskfile *tf) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci ata_tf_init(dev, tf); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; 54862306a36Sopenharmony_ci tf->protocol = ATA_PROT_NODATA; 54962306a36Sopenharmony_ci tf->error = gtf->tf[0]; /* 0x1f1 */ 55062306a36Sopenharmony_ci tf->nsect = gtf->tf[1]; /* 0x1f2 */ 55162306a36Sopenharmony_ci tf->lbal = gtf->tf[2]; /* 0x1f3 */ 55262306a36Sopenharmony_ci tf->lbam = gtf->tf[3]; /* 0x1f4 */ 55362306a36Sopenharmony_ci tf->lbah = gtf->tf[4]; /* 0x1f5 */ 55462306a36Sopenharmony_ci tf->device = gtf->tf[5]; /* 0x1f6 */ 55562306a36Sopenharmony_ci tf->status = gtf->tf[6]; /* 0x1f7 */ 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic int ata_acpi_filter_tf(struct ata_device *dev, 55962306a36Sopenharmony_ci const struct ata_taskfile *tf, 56062306a36Sopenharmony_ci const struct ata_taskfile *ptf) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci if (dev->gtf_filter & ATA_ACPI_FILTER_SETXFER) { 56362306a36Sopenharmony_ci /* libata doesn't use ACPI to configure transfer mode. 56462306a36Sopenharmony_ci * It will only confuse device configuration. Skip. 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci if (tf->command == ATA_CMD_SET_FEATURES && 56762306a36Sopenharmony_ci tf->feature == SETFEATURES_XFER) 56862306a36Sopenharmony_ci return 1; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (dev->gtf_filter & ATA_ACPI_FILTER_LOCK) { 57262306a36Sopenharmony_ci /* BIOS writers, sorry but we don't wanna lock 57362306a36Sopenharmony_ci * features unless the user explicitly said so. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* DEVICE CONFIGURATION FREEZE LOCK */ 57762306a36Sopenharmony_ci if (tf->command == ATA_CMD_CONF_OVERLAY && 57862306a36Sopenharmony_ci tf->feature == ATA_DCO_FREEZE_LOCK) 57962306a36Sopenharmony_ci return 1; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* SECURITY FREEZE LOCK */ 58262306a36Sopenharmony_ci if (tf->command == ATA_CMD_SEC_FREEZE_LOCK) 58362306a36Sopenharmony_ci return 1; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* SET MAX LOCK and SET MAX FREEZE LOCK */ 58662306a36Sopenharmony_ci if ((!ptf || ptf->command != ATA_CMD_READ_NATIVE_MAX) && 58762306a36Sopenharmony_ci tf->command == ATA_CMD_SET_MAX && 58862306a36Sopenharmony_ci (tf->feature == ATA_SET_MAX_LOCK || 58962306a36Sopenharmony_ci tf->feature == ATA_SET_MAX_FREEZE_LOCK)) 59062306a36Sopenharmony_ci return 1; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (tf->command == ATA_CMD_SET_FEATURES && 59462306a36Sopenharmony_ci tf->feature == SETFEATURES_SATA_ENABLE) { 59562306a36Sopenharmony_ci /* inhibit enabling DIPM */ 59662306a36Sopenharmony_ci if (dev->gtf_filter & ATA_ACPI_FILTER_DIPM && 59762306a36Sopenharmony_ci tf->nsect == SATA_DIPM) 59862306a36Sopenharmony_ci return 1; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* inhibit FPDMA non-zero offset */ 60162306a36Sopenharmony_ci if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_OFFSET && 60262306a36Sopenharmony_ci (tf->nsect == SATA_FPDMA_OFFSET || 60362306a36Sopenharmony_ci tf->nsect == SATA_FPDMA_IN_ORDER)) 60462306a36Sopenharmony_ci return 1; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* inhibit FPDMA auto activation */ 60762306a36Sopenharmony_ci if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_AA && 60862306a36Sopenharmony_ci tf->nsect == SATA_FPDMA_AA) 60962306a36Sopenharmony_ci return 1; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/** 61662306a36Sopenharmony_ci * ata_acpi_run_tf - send taskfile registers to host controller 61762306a36Sopenharmony_ci * @dev: target ATA device 61862306a36Sopenharmony_ci * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) 61962306a36Sopenharmony_ci * @prev_gtf: previous command 62062306a36Sopenharmony_ci * 62162306a36Sopenharmony_ci * Outputs ATA taskfile to standard ATA host controller. 62262306a36Sopenharmony_ci * Writes the control, feature, nsect, lbal, lbam, and lbah registers. 62362306a36Sopenharmony_ci * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, 62462306a36Sopenharmony_ci * hob_lbal, hob_lbam, and hob_lbah. 62562306a36Sopenharmony_ci * 62662306a36Sopenharmony_ci * This function waits for idle (!BUSY and !DRQ) after writing 62762306a36Sopenharmony_ci * registers. If the control register has a new value, this 62862306a36Sopenharmony_ci * function also waits for idle after writing control and before 62962306a36Sopenharmony_ci * writing the remaining registers. 63062306a36Sopenharmony_ci * 63162306a36Sopenharmony_ci * LOCKING: 63262306a36Sopenharmony_ci * EH context. 63362306a36Sopenharmony_ci * 63462306a36Sopenharmony_ci * RETURNS: 63562306a36Sopenharmony_ci * 1 if command is executed successfully. 0 if ignored, rejected or 63662306a36Sopenharmony_ci * filtered out, -errno on other errors. 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_cistatic int ata_acpi_run_tf(struct ata_device *dev, 63962306a36Sopenharmony_ci const struct ata_acpi_gtf *gtf, 64062306a36Sopenharmony_ci const struct ata_acpi_gtf *prev_gtf) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct ata_taskfile *pptf = NULL; 64362306a36Sopenharmony_ci struct ata_taskfile tf, ptf, rtf; 64462306a36Sopenharmony_ci unsigned int err_mask; 64562306a36Sopenharmony_ci const char *descr; 64662306a36Sopenharmony_ci int rc; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if ((gtf->tf[0] == 0) && (gtf->tf[1] == 0) && (gtf->tf[2] == 0) 64962306a36Sopenharmony_ci && (gtf->tf[3] == 0) && (gtf->tf[4] == 0) && (gtf->tf[5] == 0) 65062306a36Sopenharmony_ci && (gtf->tf[6] == 0)) 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci ata_acpi_gtf_to_tf(dev, gtf, &tf); 65462306a36Sopenharmony_ci if (prev_gtf) { 65562306a36Sopenharmony_ci ata_acpi_gtf_to_tf(dev, prev_gtf, &ptf); 65662306a36Sopenharmony_ci pptf = &ptf; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci descr = ata_get_cmd_name(tf.command); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (!ata_acpi_filter_tf(dev, &tf, pptf)) { 66262306a36Sopenharmony_ci rtf = tf; 66362306a36Sopenharmony_ci err_mask = ata_exec_internal(dev, &rtf, NULL, 66462306a36Sopenharmony_ci DMA_NONE, NULL, 0, 0); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci switch (err_mask) { 66762306a36Sopenharmony_ci case 0: 66862306a36Sopenharmony_ci ata_dev_dbg(dev, 66962306a36Sopenharmony_ci "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x" 67062306a36Sopenharmony_ci "(%s) succeeded\n", 67162306a36Sopenharmony_ci tf.command, tf.feature, tf.nsect, tf.lbal, 67262306a36Sopenharmony_ci tf.lbam, tf.lbah, tf.device, descr); 67362306a36Sopenharmony_ci rc = 1; 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci case AC_ERR_DEV: 67762306a36Sopenharmony_ci ata_dev_info(dev, 67862306a36Sopenharmony_ci "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x" 67962306a36Sopenharmony_ci "(%s) rejected by device (Stat=0x%02x Err=0x%02x)", 68062306a36Sopenharmony_ci tf.command, tf.feature, tf.nsect, tf.lbal, 68162306a36Sopenharmony_ci tf.lbam, tf.lbah, tf.device, descr, 68262306a36Sopenharmony_ci rtf.status, rtf.error); 68362306a36Sopenharmony_ci rc = 0; 68462306a36Sopenharmony_ci break; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci default: 68762306a36Sopenharmony_ci ata_dev_err(dev, 68862306a36Sopenharmony_ci "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x" 68962306a36Sopenharmony_ci "(%s) failed (Emask=0x%x Stat=0x%02x Err=0x%02x)", 69062306a36Sopenharmony_ci tf.command, tf.feature, tf.nsect, tf.lbal, 69162306a36Sopenharmony_ci tf.lbam, tf.lbah, tf.device, descr, 69262306a36Sopenharmony_ci err_mask, rtf.status, rtf.error); 69362306a36Sopenharmony_ci rc = -EIO; 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci ata_dev_info(dev, 69862306a36Sopenharmony_ci "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x" 69962306a36Sopenharmony_ci "(%s) filtered out\n", 70062306a36Sopenharmony_ci tf.command, tf.feature, tf.nsect, tf.lbal, 70162306a36Sopenharmony_ci tf.lbam, tf.lbah, tf.device, descr); 70262306a36Sopenharmony_ci rc = 0; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci return rc; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/** 70862306a36Sopenharmony_ci * ata_acpi_exec_tfs - get then write drive taskfile settings 70962306a36Sopenharmony_ci * @dev: target ATA device 71062306a36Sopenharmony_ci * @nr_executed: out parameter for the number of executed commands 71162306a36Sopenharmony_ci * 71262306a36Sopenharmony_ci * Evaluate _GTF and execute returned taskfiles. 71362306a36Sopenharmony_ci * 71462306a36Sopenharmony_ci * LOCKING: 71562306a36Sopenharmony_ci * EH context. 71662306a36Sopenharmony_ci * 71762306a36Sopenharmony_ci * RETURNS: 71862306a36Sopenharmony_ci * Number of executed taskfiles on success, 0 if _GTF doesn't exist. 71962306a36Sopenharmony_ci * -errno on other errors. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_cistatic int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct ata_acpi_gtf *gtf = NULL, *pgtf = NULL; 72462306a36Sopenharmony_ci int gtf_count, i, rc; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* get taskfiles */ 72762306a36Sopenharmony_ci rc = ata_dev_get_GTF(dev, >f); 72862306a36Sopenharmony_ci if (rc < 0) 72962306a36Sopenharmony_ci return rc; 73062306a36Sopenharmony_ci gtf_count = rc; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* execute them */ 73362306a36Sopenharmony_ci for (i = 0; i < gtf_count; i++, gtf++) { 73462306a36Sopenharmony_ci rc = ata_acpi_run_tf(dev, gtf, pgtf); 73562306a36Sopenharmony_ci if (rc < 0) 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci if (rc) { 73862306a36Sopenharmony_ci (*nr_executed)++; 73962306a36Sopenharmony_ci pgtf = gtf; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci ata_acpi_clear_gtf(dev); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (rc < 0) 74662306a36Sopenharmony_ci return rc; 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci/** 75162306a36Sopenharmony_ci * ata_acpi_push_id - send Identify data to drive 75262306a36Sopenharmony_ci * @dev: target ATA device 75362306a36Sopenharmony_ci * 75462306a36Sopenharmony_ci * _SDD ACPI object: for SATA mode only 75562306a36Sopenharmony_ci * Must be after Identify (Packet) Device -- uses its data 75662306a36Sopenharmony_ci * ATM this function never returns a failure. It is an optional 75762306a36Sopenharmony_ci * method and if it fails for whatever reason, we should still 75862306a36Sopenharmony_ci * just keep going. 75962306a36Sopenharmony_ci * 76062306a36Sopenharmony_ci * LOCKING: 76162306a36Sopenharmony_ci * EH context. 76262306a36Sopenharmony_ci * 76362306a36Sopenharmony_ci * RETURNS: 76462306a36Sopenharmony_ci * 0 on success, -ENOENT if _SDD doesn't exist, -errno on failure. 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_cistatic int ata_acpi_push_id(struct ata_device *dev) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci struct ata_port *ap = dev->link->ap; 76962306a36Sopenharmony_ci acpi_status status; 77062306a36Sopenharmony_ci struct acpi_object_list input; 77162306a36Sopenharmony_ci union acpi_object in_params[1]; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci ata_dev_dbg(dev, "%s: ix = %d, port#: %d\n", 77462306a36Sopenharmony_ci __func__, dev->devno, ap->port_no); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* Give the drive Identify data to the drive via the _SDD method */ 77762306a36Sopenharmony_ci /* _SDD: set up input parameters */ 77862306a36Sopenharmony_ci input.count = 1; 77962306a36Sopenharmony_ci input.pointer = in_params; 78062306a36Sopenharmony_ci in_params[0].type = ACPI_TYPE_BUFFER; 78162306a36Sopenharmony_ci in_params[0].buffer.length = sizeof(dev->id[0]) * ATA_ID_WORDS; 78262306a36Sopenharmony_ci in_params[0].buffer.pointer = (u8 *)dev->id; 78362306a36Sopenharmony_ci /* Output buffer: _SDD has no output */ 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* It's OK for _SDD to be missing too. */ 78662306a36Sopenharmony_ci swap_buf_le16(dev->id, ATA_ID_WORDS); 78762306a36Sopenharmony_ci status = acpi_evaluate_object(ata_dev_acpi_handle(dev), "_SDD", &input, 78862306a36Sopenharmony_ci NULL); 78962306a36Sopenharmony_ci swap_buf_le16(dev->id, ATA_ID_WORDS); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (status == AE_NOT_FOUND) 79262306a36Sopenharmony_ci return -ENOENT; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 79562306a36Sopenharmony_ci ata_dev_warn(dev, "ACPI _SDD failed (AE 0x%x)\n", status); 79662306a36Sopenharmony_ci return -EIO; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return 0; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/** 80362306a36Sopenharmony_ci * ata_acpi_on_resume - ATA ACPI hook called on resume 80462306a36Sopenharmony_ci * @ap: target ATA port 80562306a36Sopenharmony_ci * 80662306a36Sopenharmony_ci * This function is called when @ap is resumed - right after port 80762306a36Sopenharmony_ci * itself is resumed but before any EH action is taken. 80862306a36Sopenharmony_ci * 80962306a36Sopenharmony_ci * LOCKING: 81062306a36Sopenharmony_ci * EH context. 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_civoid ata_acpi_on_resume(struct ata_port *ap) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); 81562306a36Sopenharmony_ci struct ata_device *dev; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (ACPI_HANDLE(&ap->tdev) && gtm) { 81862306a36Sopenharmony_ci /* _GTM valid */ 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* restore timing parameters */ 82162306a36Sopenharmony_ci ata_acpi_stm(ap, gtm); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* _GTF should immediately follow _STM so that it can 82462306a36Sopenharmony_ci * use values set by _STM. Cache _GTF result and 82562306a36Sopenharmony_ci * schedule _GTF. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ALL) { 82862306a36Sopenharmony_ci ata_acpi_clear_gtf(dev); 82962306a36Sopenharmony_ci if (ata_dev_enabled(dev) && 83062306a36Sopenharmony_ci ata_dev_acpi_handle(dev) && 83162306a36Sopenharmony_ci ata_dev_get_GTF(dev, NULL) >= 0) 83262306a36Sopenharmony_ci dev->flags |= ATA_DFLAG_ACPI_PENDING; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci } else { 83562306a36Sopenharmony_ci /* SATA _GTF needs to be evaulated after _SDD and 83662306a36Sopenharmony_ci * there's no reason to evaluate IDE _GTF early 83762306a36Sopenharmony_ci * without _STM. Clear cache and schedule _GTF. 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ALL) { 84062306a36Sopenharmony_ci ata_acpi_clear_gtf(dev); 84162306a36Sopenharmony_ci if (ata_dev_enabled(dev)) 84262306a36Sopenharmony_ci dev->flags |= ATA_DFLAG_ACPI_PENDING; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci int d_max_in = ACPI_STATE_D3_COLD; 85062306a36Sopenharmony_ci if (!runtime) 85162306a36Sopenharmony_ci goto out; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* 85462306a36Sopenharmony_ci * For ATAPI, runtime D3 cold is only allowed 85562306a36Sopenharmony_ci * for ZPODD in zero power ready state 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_ci if (dev->class == ATA_DEV_ATAPI && 85862306a36Sopenharmony_ci !(zpodd_dev_enabled(dev) && zpodd_zpready(dev))) 85962306a36Sopenharmony_ci d_max_in = ACPI_STATE_D3_HOT; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ciout: 86262306a36Sopenharmony_ci return acpi_pm_device_sleep_state(&dev->tdev, NULL, d_max_in); 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void sata_acpi_set_state(struct ata_port *ap, pm_message_t state) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci bool runtime = PMSG_IS_AUTO(state); 86862306a36Sopenharmony_ci struct ata_device *dev; 86962306a36Sopenharmony_ci acpi_handle handle; 87062306a36Sopenharmony_ci int acpi_state; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ENABLED) { 87362306a36Sopenharmony_ci handle = ata_dev_acpi_handle(dev); 87462306a36Sopenharmony_ci if (!handle) 87562306a36Sopenharmony_ci continue; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (!(state.event & PM_EVENT_RESUME)) { 87862306a36Sopenharmony_ci acpi_state = ata_acpi_choose_suspend_state(dev, runtime); 87962306a36Sopenharmony_ci if (acpi_state == ACPI_STATE_D0) 88062306a36Sopenharmony_ci continue; 88162306a36Sopenharmony_ci if (runtime && zpodd_dev_enabled(dev) && 88262306a36Sopenharmony_ci acpi_state == ACPI_STATE_D3_COLD) 88362306a36Sopenharmony_ci zpodd_enable_run_wake(dev); 88462306a36Sopenharmony_ci acpi_bus_set_power(handle, acpi_state); 88562306a36Sopenharmony_ci } else { 88662306a36Sopenharmony_ci if (runtime && zpodd_dev_enabled(dev)) 88762306a36Sopenharmony_ci zpodd_disable_run_wake(dev); 88862306a36Sopenharmony_ci acpi_bus_set_power(handle, ACPI_STATE_D0); 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */ 89462306a36Sopenharmony_cistatic void pata_acpi_set_state(struct ata_port *ap, pm_message_t state) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct ata_device *dev; 89762306a36Sopenharmony_ci acpi_handle port_handle; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci port_handle = ACPI_HANDLE(&ap->tdev); 90062306a36Sopenharmony_ci if (!port_handle) 90162306a36Sopenharmony_ci return; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* channel first and then drives for power on and vica versa 90462306a36Sopenharmony_ci for power off */ 90562306a36Sopenharmony_ci if (state.event & PM_EVENT_RESUME) 90662306a36Sopenharmony_ci acpi_bus_set_power(port_handle, ACPI_STATE_D0); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci ata_for_each_dev(dev, &ap->link, ENABLED) { 90962306a36Sopenharmony_ci acpi_handle dev_handle = ata_dev_acpi_handle(dev); 91062306a36Sopenharmony_ci if (!dev_handle) 91162306a36Sopenharmony_ci continue; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ? 91462306a36Sopenharmony_ci ACPI_STATE_D0 : ACPI_STATE_D3_COLD); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (!(state.event & PM_EVENT_RESUME)) 91862306a36Sopenharmony_ci acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci/** 92262306a36Sopenharmony_ci * ata_acpi_set_state - set the port power state 92362306a36Sopenharmony_ci * @ap: target ATA port 92462306a36Sopenharmony_ci * @state: state, on/off 92562306a36Sopenharmony_ci * 92662306a36Sopenharmony_ci * This function sets a proper ACPI D state for the device on 92762306a36Sopenharmony_ci * system and runtime PM operations. 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_civoid ata_acpi_set_state(struct ata_port *ap, pm_message_t state) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci if (ap->flags & ATA_FLAG_ACPI_SATA) 93262306a36Sopenharmony_ci sata_acpi_set_state(ap, state); 93362306a36Sopenharmony_ci else 93462306a36Sopenharmony_ci pata_acpi_set_state(ap, state); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci/** 93862306a36Sopenharmony_ci * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration 93962306a36Sopenharmony_ci * @dev: target ATA device 94062306a36Sopenharmony_ci * 94162306a36Sopenharmony_ci * This function is called when @dev is about to be configured. 94262306a36Sopenharmony_ci * IDENTIFY data might have been modified after this hook is run. 94362306a36Sopenharmony_ci * 94462306a36Sopenharmony_ci * LOCKING: 94562306a36Sopenharmony_ci * EH context. 94662306a36Sopenharmony_ci * 94762306a36Sopenharmony_ci * RETURNS: 94862306a36Sopenharmony_ci * Positive number if IDENTIFY data needs to be refreshed, 0 if not, 94962306a36Sopenharmony_ci * -errno on failure. 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_ciint ata_acpi_on_devcfg(struct ata_device *dev) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct ata_port *ap = dev->link->ap; 95462306a36Sopenharmony_ci struct ata_eh_context *ehc = &ap->link.eh_context; 95562306a36Sopenharmony_ci int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; 95662306a36Sopenharmony_ci int nr_executed = 0; 95762306a36Sopenharmony_ci int rc; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (!ata_dev_acpi_handle(dev)) 96062306a36Sopenharmony_ci return 0; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* do we need to do _GTF? */ 96362306a36Sopenharmony_ci if (!(dev->flags & ATA_DFLAG_ACPI_PENDING) && 96462306a36Sopenharmony_ci !(acpi_sata && (ehc->i.flags & ATA_EHI_DID_HARDRESET))) 96562306a36Sopenharmony_ci return 0; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* do _SDD if SATA */ 96862306a36Sopenharmony_ci if (acpi_sata) { 96962306a36Sopenharmony_ci rc = ata_acpi_push_id(dev); 97062306a36Sopenharmony_ci if (rc && rc != -ENOENT) 97162306a36Sopenharmony_ci goto acpi_err; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* do _GTF */ 97562306a36Sopenharmony_ci rc = ata_acpi_exec_tfs(dev, &nr_executed); 97662306a36Sopenharmony_ci if (rc) 97762306a36Sopenharmony_ci goto acpi_err; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci dev->flags &= ~ATA_DFLAG_ACPI_PENDING; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* refresh IDENTIFY page if any _GTF command has been executed */ 98262306a36Sopenharmony_ci if (nr_executed) { 98362306a36Sopenharmony_ci rc = ata_dev_reread_id(dev, 0); 98462306a36Sopenharmony_ci if (rc < 0) { 98562306a36Sopenharmony_ci ata_dev_err(dev, 98662306a36Sopenharmony_ci "failed to IDENTIFY after ACPI commands\n"); 98762306a36Sopenharmony_ci return rc; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci acpi_err: 99462306a36Sopenharmony_ci /* ignore evaluation failure if we can continue safely */ 99562306a36Sopenharmony_ci if (rc == -EINVAL && !nr_executed && !ata_port_is_frozen(ap)) 99662306a36Sopenharmony_ci return 0; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* fail and let EH retry once more for unknown IO errors */ 99962306a36Sopenharmony_ci if (!(dev->flags & ATA_DFLAG_ACPI_FAILED)) { 100062306a36Sopenharmony_ci dev->flags |= ATA_DFLAG_ACPI_FAILED; 100162306a36Sopenharmony_ci return rc; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci dev->flags |= ATA_DFLAG_ACPI_DISABLED; 100562306a36Sopenharmony_ci ata_dev_warn(dev, "ACPI: failed the second time, disabled\n"); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci /* We can safely continue if no _GTF command has been executed 100862306a36Sopenharmony_ci * and port is not frozen. 100962306a36Sopenharmony_ci */ 101062306a36Sopenharmony_ci if (!nr_executed && !ata_port_is_frozen(ap)) 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return rc; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci/** 101762306a36Sopenharmony_ci * ata_acpi_on_disable - ATA ACPI hook called when a device is disabled 101862306a36Sopenharmony_ci * @dev: target ATA device 101962306a36Sopenharmony_ci * 102062306a36Sopenharmony_ci * This function is called when @dev is about to be disabled. 102162306a36Sopenharmony_ci * 102262306a36Sopenharmony_ci * LOCKING: 102362306a36Sopenharmony_ci * EH context. 102462306a36Sopenharmony_ci */ 102562306a36Sopenharmony_civoid ata_acpi_on_disable(struct ata_device *dev) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci ata_acpi_clear_gtf(dev); 102862306a36Sopenharmony_ci} 1029