X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fata%2Flibata-acpi.c;h=70b77e0899a84848d5da89b736505aaee977f2b2;hb=2d5e94d7ca315f859a0eee1366838e8ad34dd7b2;hp=c428a56e6f315e3e7e221f82c25206129af9acab;hpb=b2526300ab242dc31f9006dbf9a4de40797571bc;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index c428a56..70b77e0 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -6,6 +6,7 @@ * Copyright (C) 2006 Randy Dunlap */ +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include "libata.h" #include @@ -24,15 +26,25 @@ #include #include -#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff) -#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */ +enum { + ATA_ACPI_FILTER_SETXFER = 1 << 0, + ATA_ACPI_FILTER_LOCK = 1 << 1, + + ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER | + ATA_ACPI_FILTER_LOCK, +}; + +static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT; +module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644); +MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock)"); + #define NO_PORT_MULT 0xffff -#define SATA_ADR_RSVD 0xffffffff +#define SATA_ADR(root, pmp) (((root) << 16) | (pmp)) #define REGS_PER_GTF 7 -struct taskfile_array { - u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ -}; +struct ata_acpi_gtf { + u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ +} __packed; /* * Helper - belongs in the PCI layer somewhere eventually @@ -42,238 +54,336 @@ 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; +} + /** - * sata_get_dev_handle - finds acpi_handle and PCI device.function - * @dev: device to locate - * @handle: returned acpi_handle for @dev - * @pcidevfn: return PCI device.func for @dev + * ata_acpi_associate_sata_port - associate SATA port with ACPI objects + * @ap: target SATA port + * + * Look up ACPI objects associated with @ap and initialize acpi_handle + * fields of @ap, the port and devices accordingly. * - * This function is somewhat SATA-specific. Or at least the - * PATA & SATA versions of this function are different, - * so it's not entirely generic code. + * LOCKING: + * EH context. * - * Returns 0 on success, <0 on error. + * RETURNS: + * 0 on success, -errno on failure. */ -static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, - acpi_integer *pcidevfn) +void ata_acpi_associate_sata_port(struct ata_port *ap) { - struct pci_dev *pci_dev; - acpi_integer addr; - - if (!is_pci_dev(dev)) - return -ENODEV; - - pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ - /* Please refer to the ACPI spec for the syntax of _ADR. */ - addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - *pcidevfn = addr; - *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); - if (!*handle) - return -ENODEV; - return 0; + WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA)); + + if (!sata_pmp_attached(ap)) { + acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT); + + ap->link.device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } else { + struct ata_link *link; + + ap->link.device->acpi_handle = NULL; + + ata_port_for_each_link(link, ap) { + acpi_integer adr = SATA_ADR(ap->port_no, link->pmp); + + link->device->acpi_handle = + acpi_get_child(ap->host->acpi_handle, adr); + } + } +} + +static void ata_acpi_associate_ide_port(struct ata_port *ap) +{ + int max_devices, i; + + ap->acpi_handle = acpi_get_child(ap->host->acpi_handle, ap->port_no); + if (!ap->acpi_handle) + return; + + max_devices = 1; + if (ap->flags & ATA_FLAG_SLAVE_POSS) + max_devices++; + + for (i = 0; i < max_devices; i++) { + struct ata_device *dev = &ap->link.device[i]; + + dev->acpi_handle = acpi_get_child(ap->acpi_handle, i); + } + + if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) + ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; +} + +static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, + u32 event) +{ + char event_string[12]; + char *envp[] = { event_string, NULL }; + struct ata_eh_info *ehi; + struct kobject *kobj = NULL; + int wait = 0; + unsigned long flags; + + if (!ap) + ap = dev->link->ap; + ehi = &ap->link.eh_info; + + spin_lock_irqsave(ap->lock, flags); + + switch (event) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + ata_ehi_push_desc(ehi, "ACPI event"); + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + ata_ehi_push_desc(ehi, "ACPI event"); + if (dev) + dev->flags |= ATA_DFLAG_DETACH; + else { + struct ata_link *tlink; + struct ata_device *tdev; + + ata_port_for_each_link(tlink, ap) + ata_link_for_each_dev(tdev, tlink) + tdev->flags |= ATA_DFLAG_DETACH; + } + + ata_port_schedule_eh(ap); + wait = 1; + break; + } + + if (dev) { + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + } else + kobj = &ap->dev->kobj; + + if (kobj) { + sprintf(event_string, "BAY_EVENT=%d", event); + kobject_uevent_env(kobj, KOBJ_CHANGE, envp); + } + + spin_unlock_irqrestore(ap->lock, flags); + + if (wait) + ata_port_wait_eh(ap); +} + +static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_device *dev = data; + + ata_acpi_handle_hotplug(NULL, dev, event); +} + +static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_port *ap = data; + + ata_acpi_handle_hotplug(ap, NULL, event); } /** - * pata_get_dev_handle - finds acpi_handle and PCI device.function - * @dev: device to locate - * @handle: returned acpi_handle for @dev - * @pcidevfn: return PCI device.func for @dev + * ata_acpi_associate - associate ATA host with ACPI objects + * @host: target ATA host + * + * Look up ACPI objects associated with @host and initialize + * acpi_handle fields of @host, its ports and devices accordingly. * - * The PATA and SATA versions of this function are different. + * LOCKING: + * EH context. * - * Returns 0 on success, <0 on error. + * RETURNS: + * 0 on success, -errno on failure. */ -static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, - acpi_integer *pcidevfn) +void ata_acpi_associate(struct ata_host *host) { - unsigned int bus, devnum, func; - acpi_integer addr; - acpi_handle dev_handle, parent_handle; - struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, - .pointer = NULL}; - acpi_status status; - struct acpi_device_info *dinfo = NULL; - int ret = -ENODEV; - struct pci_dev *pdev; - - if (!is_pci_dev(dev)) - return -ENODEV; + int i, j; - pdev = to_pci_dev(dev); + if (!is_pci_dev(host->dev) || libata_noacpi) + return; - bus = pdev->bus->number; - devnum = PCI_SLOT(pdev->devfn); - func = PCI_FUNC(pdev->devfn); + host->acpi_handle = DEVICE_ACPI_HANDLE(host->dev); + if (!host->acpi_handle) + return; - dev_handle = DEVICE_ACPI_HANDLE(dev); - parent_handle = DEVICE_ACPI_HANDLE(dev->parent); + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (host->ports[0]->flags & ATA_FLAG_ACPI_SATA) + ata_acpi_associate_sata_port(ap); + else + ata_acpi_associate_ide_port(ap); + + if (ap->acpi_handle) { + acpi_install_notify_handler(ap->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_ap_notify, ap); + /* we might be on a docking station */ + register_hotplug_dock_device(ap->acpi_handle, + ata_acpi_ap_notify, ap); + } - status = acpi_get_object_info(parent_handle, &buffer); - if (ACPI_FAILURE(status)) - goto err; + for (j = 0; j < ata_link_max_devices(&ap->link); j++) { + struct ata_device *dev = &ap->link.device[j]; - dinfo = buffer.pointer; - if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && - dinfo->address == bus) { - /* ACPI spec for _ADR for PCI bus: */ - addr = (acpi_integer)(devnum << 16 | func); - *pcidevfn = addr; - *handle = dev_handle; - } else { - goto err; + if (dev->acpi_handle) { + acpi_install_notify_handler(dev->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_dev_notify, dev); + /* we might be on a docking station */ + register_hotplug_dock_device(dev->acpi_handle, + ata_acpi_dev_notify, dev); + } + } } - - if (!*handle) - goto err; - ret = 0; -err: - kfree(dinfo); - return ret; } -struct walk_info { /* can be trimmed some */ - struct device *dev; - struct acpi_device *adev; - acpi_handle handle; - acpi_integer pcidevfn; - unsigned int drivenum; - acpi_handle obj_handle; - struct ata_port *ataport; - struct ata_device *atadev; - u32 sata_adr; - int status; - char basepath[ACPI_PATHNAME_MAX]; - int basepath_len; -}; +/** + * ata_acpi_dissociate - dissociate ATA host from ACPI objects + * @host: target ATA host + * + * This function is called during driver detach after the whole host + * is shut down. + * + * LOCKING: + * EH context. + */ +void ata_acpi_dissociate(struct ata_host *host) +{ + int i; -static acpi_status get_devices(acpi_handle handle, - u32 level, void *context, void **return_value) + /* Restore initial _GTM values so that driver which attaches + * afterward can use them too. + */ + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); + + if (ap->acpi_handle && gtm) + ata_acpi_stm(ap, 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) { - acpi_status status; - struct walk_info *winfo = context; - struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; - char *pathname; - struct acpi_buffer buffer; - struct acpi_device_info *dinfo; - - status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); - if (status) - goto ret; - pathname = namebuf.pointer; - - buffer.length = ACPI_ALLOCATE_BUFFER; - buffer.pointer = NULL; - status = acpi_get_object_info(handle, &buffer); - if (ACPI_FAILURE(status)) - goto out2; - - dinfo = buffer.pointer; - - /* find full device path name for pcidevfn */ - if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && - dinfo->address == winfo->pcidevfn) { - if (ata_msg_probe(winfo->ataport)) - ata_dev_printk(winfo->atadev, KERN_DEBUG, - ":%s: matches pcidevfn (0x%llx)\n", - pathname, winfo->pcidevfn); - strlcpy(winfo->basepath, pathname, - sizeof(winfo->basepath)); - winfo->basepath_len = strlen(pathname); - goto out; + struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; + union acpi_object *out_obj; + acpi_status status; + int rc = 0; + + status = acpi_evaluate_object(ap->acpi_handle, "_GTM", NULL, &output); + + rc = -ENOENT; + if (status == AE_NOT_FOUND) + goto out_free; + + rc = -EINVAL; + if (ACPI_FAILURE(status)) { + ata_port_printk(ap, KERN_ERR, + "ACPI get timing mode failed (AE 0x%x)\n", + status); + goto out_free; } - /* if basepath is not yet known, ignore this object */ - if (!winfo->basepath_len) - goto out; - - /* if this object is in scope of basepath, maybe use it */ - if (strncmp(pathname, winfo->basepath, - winfo->basepath_len) == 0) { - if (!(dinfo->valid & ACPI_VALID_ADR)) - goto out; - if (ata_msg_probe(winfo->ataport)) - ata_dev_printk(winfo->atadev, KERN_DEBUG, - "GOT ONE: (%s) root_port = 0x%llx," - " port_num = 0x%llx\n", pathname, - SATA_ROOT_PORT(dinfo->address), - SATA_PORT_NUMBER(dinfo->address)); - /* heuristics: */ - if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) - if (ata_msg_probe(winfo->ataport)) - ata_dev_printk(winfo->atadev, - KERN_DEBUG, "warning: don't" - " know how to handle SATA port" - " multiplier\n"); - if (SATA_ROOT_PORT(dinfo->address) == - winfo->ataport->port_no && - SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) { - if (ata_msg_probe(winfo->ataport)) - ata_dev_printk(winfo->atadev, - KERN_DEBUG, - "THIS ^^^^^ is the requested" - " SATA drive (handle = 0x%p)\n", - handle); - winfo->sata_adr = dinfo->address; - winfo->obj_handle = handle; - } + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + ata_port_printk(ap, KERN_WARNING, + "_GTM returned unexpected object type 0x%x\n", + out_obj->type); + + goto out_free; } -out: - kfree(dinfo); -out2: - kfree(pathname); -ret: - return status; + if (out_obj->buffer.length != sizeof(struct ata_acpi_gtm)) { + ata_port_printk(ap, KERN_ERR, + "_GTM returned invalid length %d\n", + out_obj->buffer.length); + goto out_free; + } + + memcpy(gtm, out_obj->buffer.pointer, sizeof(struct ata_acpi_gtm)); + rc = 0; + out_free: + kfree(output.pointer); + return rc; } -/* Get the SATA drive _ADR object. */ -static int get_sata_adr(struct device *dev, acpi_handle handle, - acpi_integer pcidevfn, unsigned int drive, - struct ata_port *ap, - struct ata_device *atadev, u32 *dev_adr) +EXPORT_SYMBOL_GPL(ata_acpi_gtm); + +/** + * ata_acpi_stm - execute _STM + * @ap: target ATA port + * @stm: timing parameter to _STM + * + * Evaluate _STM with timing parameter @stm. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. + */ +int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm) { - acpi_status status; - struct walk_info *winfo; - int err = -ENOMEM; - - winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL); - if (!winfo) - goto out; - - winfo->dev = dev; - winfo->atadev = atadev; - winfo->ataport = ap; - if (acpi_bus_get_device(handle, &winfo->adev) < 0) - if (ata_msg_probe(ap)) - ata_dev_printk(winfo->atadev, KERN_DEBUG, - "acpi_bus_get_device failed\n"); - winfo->handle = handle; - winfo->pcidevfn = pcidevfn; - winfo->drivenum = drive; + acpi_status status; + struct ata_acpi_gtm stm_buf = *stm; + struct acpi_object_list input; + union acpi_object in_params[3]; - status = acpi_get_devices(NULL, get_devices, winfo, NULL); + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(struct ata_acpi_gtm); + in_params[0].buffer.pointer = (u8 *)&stm_buf; + /* Buffers for id may need byteswapping ? */ + in_params[1].type = ACPI_TYPE_BUFFER; + in_params[1].buffer.length = 512; + in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id; + in_params[2].type = ACPI_TYPE_BUFFER; + in_params[2].buffer.length = 512; + in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id; + + input.count = 3; + input.pointer = in_params; + + status = acpi_evaluate_object(ap->acpi_handle, "_STM", &input, NULL); + + if (status == AE_NOT_FOUND) + return -ENOENT; if (ACPI_FAILURE(status)) { - if (ata_msg_probe(ap)) - ata_dev_printk(winfo->atadev, KERN_DEBUG, - "%s: acpi_get_devices failed\n", - __FUNCTION__); - err = -ENODEV; - } else { - *dev_adr = winfo->sata_adr; - atadev->obj_handle = winfo->obj_handle; - err = 0; + ata_port_printk(ap, KERN_ERR, + "ACPI set timing mode failed (status=0x%x)\n", status); + return -EINVAL; } - kfree(winfo); -out: - return err; + return 0; } +EXPORT_SYMBOL_GPL(ata_acpi_stm); + /** - * do_drive_get_GTF - get the drive bootup default taskfile settings - * @ap: the ata_port for the drive - * @ix: target ata_device (drive) index - * @gtf_length: number of bytes of _GTF data returned at @gtf_address - * @gtf_address: buffer containing _GTF taskfile arrays + * ata_dev_get_GTF - get the drive bootup default taskfile settings + * @dev: target ATA device + * @gtf: output parameter for buffer containing _GTF taskfile arrays * * This applies to both PATA and SATA drives. * @@ -283,427 +393,585 @@ out: * The is not known in advance, so have ACPI-CA * allocate the buffer as needed and return it, then free it later. * - * The returned @gtf_length and @gtf_address are only valid if the - * function return value is 0. + * LOCKING: + * EH context. + * + * RETURNS: + * Number of taskfiles on success, 0 if _GTF doesn't exist. -EINVAL + * if _GTF is invalid. */ -static int do_drive_get_GTF(struct ata_port *ap, int ix, - unsigned int *gtf_length, unsigned long *gtf_address, - unsigned long *obj_loc) +static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) { - acpi_status status; - acpi_handle dev_handle = NULL; - acpi_handle chan_handle, drive_handle; - acpi_integer pcidevfn = 0; - u32 dev_adr; - struct acpi_buffer output; - union acpi_object *out_obj; - struct device *dev = ap->host->dev; - struct ata_device *atadev = &ap->device[ix]; - int err = -ENODEV; - - *gtf_length = 0; - *gtf_address = 0UL; - *obj_loc = 0UL; - - if (noacpi) - return 0; - - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n", - __FUNCTION__, ap->port_no); - - if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: ERR: " - "ata_dev_present: %d, PORT_DISABLED: %lu\n", - __FUNCTION__, ata_dev_enabled(atadev), - ap->flags & ATA_FLAG_DISABLED); - goto out; - } - - /* Don't continue if device has no _ADR method. - * _GTF is intended for known motherboard devices. */ - if (!(ap->cbl == ATA_CBL_SATA)) { - err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn); - if (err < 0) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: pata_get_dev_handle failed (%d)\n", - __FUNCTION__, err); - goto out; - } - } else { - err = sata_get_dev_handle(dev, &dev_handle, &pcidevfn); - if (err < 0) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: sata_get_dev_handle failed (%d\n", - __FUNCTION__, err); - goto out; - } - } - - /* Get this drive's _ADR info. if not already known. */ - if (!atadev->obj_handle) { - if (!(ap->cbl == ATA_CBL_SATA)) { - /* get child objects of dev_handle == channel objects, - * + _their_ children == drive objects */ - /* channel is ap->port_no */ - chan_handle = acpi_get_child(dev_handle, - ap->port_no); - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: chan adr=%d: chan_handle=0x%p\n", - __FUNCTION__, ap->port_no, - chan_handle); - if (!chan_handle) { - err = -ENODEV; - goto out; - } - /* TBD: could also check ACPI object VALID bits */ - drive_handle = acpi_get_child(chan_handle, ix); - if (!drive_handle) { - err = -ENODEV; - goto out; - } - dev_adr = ix; - atadev->obj_handle = drive_handle; - } else { /* for SATA mode */ - dev_adr = SATA_ADR_RSVD; - err = get_sata_adr(dev, dev_handle, pcidevfn, 0, - ap, atadev, &dev_adr); - } - if (err < 0 || dev_adr == SATA_ADR_RSVD || - !atadev->obj_handle) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: get_sata/pata_adr failed: " - "err=%d, dev_adr=%u, obj_handle=0x%p\n", - __FUNCTION__, err, dev_adr, - atadev->obj_handle); - goto out; - } + struct ata_port *ap = dev->link->ap; + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + int rc = 0; + + /* if _GTF is cached, use the cached value */ + if (dev->gtf_cache) { + out_obj = dev->gtf_cache; + goto done; } - /* Setting up output buffer */ + /* set up output buffer */ output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + if (ata_msg_probe(ap)) + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", + __func__, ap->port_no); + /* _GTF has no input parameters */ - err = -EIO; - status = acpi_evaluate_object(atadev->obj_handle, "_GTF", - NULL, &output); + status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); + out_obj = dev->gtf_cache = output.pointer; + if (ACPI_FAILURE(status)) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: Run _GTF error: status = 0x%x\n", - __FUNCTION__, status); - goto out; + if (status != AE_NOT_FOUND) { + ata_dev_printk(dev, KERN_WARNING, + "_GTF evaluation failed (AE 0x%x)\n", + status); + rc = -EINVAL; + } + goto out_free; } if (!output.length || !output.pointer) { if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " "length or ptr is NULL (0x%llx, 0x%p)\n", - __FUNCTION__, + __func__, (unsigned long long)output.length, output.pointer); - kfree(output.pointer); - goto out; + rc = -EINVAL; + goto out_free; } - out_obj = output.pointer; if (out_obj->type != ACPI_TYPE_BUFFER) { - kfree(output.pointer); - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " - "error: expected object type of " - " ACPI_TYPE_BUFFER, got 0x%x\n", - __FUNCTION__, out_obj->type); - err = -ENOENT; - goto out; + ata_dev_printk(dev, KERN_WARNING, + "_GTF unexpected object type 0x%x\n", + out_obj->type); + rc = -EINVAL; + goto out_free; } - if (!out_obj->buffer.length || !out_obj->buffer.pointer || - out_obj->buffer.length % REGS_PER_GTF) { - if (ata_msg_drv(ap)) - ata_dev_printk(atadev, KERN_ERR, - "%s: unexpected GTF length (%d) or addr (0x%p)\n", - __FUNCTION__, out_obj->buffer.length, - out_obj->buffer.pointer); - err = -ENOENT; - goto out; + if (out_obj->buffer.length % REGS_PER_GTF) { + ata_dev_printk(dev, KERN_WARNING, + "unexpected _GTF length (%d)\n", + out_obj->buffer.length); + rc = -EINVAL; + goto out_free; } - *gtf_length = out_obj->buffer.length; - *gtf_address = (unsigned long)out_obj->buffer.pointer; - *obj_loc = (unsigned long)out_obj; - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: returning " - "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", - __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); - err = 0; -out: - return err; + done: + rc = out_obj->buffer.length / REGS_PER_GTF; + if (gtf) { + *gtf = (void *)out_obj->buffer.pointer; + if (ata_msg_probe(ap)) + ata_dev_printk(dev, KERN_DEBUG, + "%s: returning gtf=%p, gtf_count=%d\n", + __func__, *gtf, rc); + } + return rc; + + out_free: + ata_acpi_clear_gtf(dev); + return rc; } /** - * taskfile_load_raw - send taskfile registers to host controller - * @ap: Port to which output is sent - * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) + * ata_acpi_gtm_xfermode - determine xfermode from GTM parameter + * @dev: target device + * @gtm: GTM parameter to use * - * Outputs ATA taskfile to standard ATA host controller using MMIO - * or PIO as indicated by the ATA_FLAG_MMIO flag. - * Writes the control, feature, nsect, lbal, lbam, and lbah registers. - * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, - * hob_lbal, hob_lbam, and hob_lbah. + * Determine xfermask for @dev from @gtm. * - * This function waits for idle (!BUSY and !DRQ) after writing - * registers. If the control register has a new value, this - * function also waits for idle after writing control and before - * writing the remaining registers. + * LOCKING: + * None. * - * LOCKING: TBD: - * Inherited from caller. + * RETURNS: + * Determined xfermask. */ -static void taskfile_load_raw(struct ata_port *ap, - struct ata_device *atadev, - const struct taskfile_array *gtf) +unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev, + const struct ata_acpi_gtm *gtm) { - struct ata_taskfile tf; - unsigned int err; + unsigned long xfer_mask = 0; + unsigned int type; + int unit; + u8 mode; + + /* we always use the 0 slot for crap hardware */ + unit = dev->devno; + if (!(gtm->flags & 0x10)) + unit = 0; + + /* PIO */ + mode = ata_timing_cycle2mode(ATA_SHIFT_PIO, gtm->drive[unit].pio); + xfer_mask |= ata_xfer_mode2mask(mode); + + /* See if we have MWDMA or UDMA data. We don't bother with + * MWDMA if UDMA is available as this means the BIOS set UDMA + * and our error changedown if it works is UDMA to PIO anyway. + */ + if (!(gtm->flags & (1 << (2 * unit)))) + type = ATA_SHIFT_MWDMA; + else + type = ATA_SHIFT_UDMA; - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " - "%02x %02x %02x %02x %02x %02x %02x\n", - __FUNCTION__, - gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], - gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); - - if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) - && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) - && (gtf->tfa[6] == 0)) - return; + mode = ata_timing_cycle2mode(type, gtm->drive[unit].dma); + xfer_mask |= ata_xfer_mode2mask(mode); - ata_tf_init(atadev, &tf); - - /* convert gtf to tf */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ - tf.protocol = atadev->class == ATA_DEV_ATAPI ? - ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; - tf.feature = gtf->tfa[0]; /* 0x1f1 */ - tf.nsect = gtf->tfa[1]; /* 0x1f2 */ - tf.lbal = gtf->tfa[2]; /* 0x1f3 */ - tf.lbam = gtf->tfa[3]; /* 0x1f4 */ - tf.lbah = gtf->tfa[4]; /* 0x1f5 */ - tf.device = gtf->tfa[5]; /* 0x1f6 */ - tf.command = gtf->tfa[6]; /* 0x1f7 */ - - err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0); - if (err && ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_ERR, - "%s: ata_exec_internal failed: %u\n", - __FUNCTION__, err); + return xfer_mask; } +EXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask); /** - * do_drive_set_taskfiles - write the drive taskfile settings from _GTF - * @ap: the ata_port for the drive - * @atadev: target ata_device - * @gtf_length: total number of bytes of _GTF taskfiles - * @gtf_address: location of _GTF taskfile arrays - * - * This applies to both PATA and SATA drives. + * ata_acpi_cbl_80wire - Check for 80 wire cable + * @ap: Port to check + * @gtm: GTM data to use * - * Write {gtf_address, length gtf_length} in groups of - * REGS_PER_GTF bytes. + * Return 1 if the @gtm indicates the BIOS selected an 80wire mode. */ -static int do_drive_set_taskfiles(struct ata_port *ap, - struct ata_device *atadev, unsigned int gtf_length, - unsigned long gtf_address) +int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm) { - int err = -ENODEV; - int gtf_count = gtf_length / REGS_PER_GTF; - int ix; - struct taskfile_array *gtf; + struct ata_device *dev; - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n", - __FUNCTION__, ap->port_no); + ata_link_for_each_dev(dev, &ap->link) { + unsigned long xfer_mask, udma_mask; - if (noacpi || !(ap->cbl == ATA_CBL_SATA)) - return 0; + if (!ata_dev_enabled(dev)) + continue; + + xfer_mask = ata_acpi_gtm_xfermask(dev, gtm); + ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask); - if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) - goto out; - if (!gtf_count) /* shouldn't be here */ - goto out; - - if (gtf_length % REGS_PER_GTF) { - if (ata_msg_drv(ap)) - ata_dev_printk(atadev, KERN_ERR, - "%s: unexpected GTF length (%d)\n", - __FUNCTION__, gtf_length); - goto out; + if (udma_mask & ~ATA_UDMA_MASK_40C) + return 1; } - for (ix = 0; ix < gtf_count; ix++) { - gtf = (struct taskfile_array *) - (gtf_address + ix * REGS_PER_GTF); + return 0; +} +EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); + +static void ata_acpi_gtf_to_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf, + struct ata_taskfile *tf) +{ + ata_tf_init(dev, tf); + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->feature = gtf->tf[0]; /* 0x1f1 */ + tf->nsect = gtf->tf[1]; /* 0x1f2 */ + tf->lbal = gtf->tf[2]; /* 0x1f3 */ + tf->lbam = gtf->tf[3]; /* 0x1f4 */ + tf->lbah = gtf->tf[4]; /* 0x1f5 */ + tf->device = gtf->tf[5]; /* 0x1f6 */ + tf->command = gtf->tf[6]; /* 0x1f7 */ +} - /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ - taskfile_load_raw(ap, atadev, gtf); +static int ata_acpi_filter_tf(const struct ata_taskfile *tf, + const struct ata_taskfile *ptf) +{ + if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_SETXFER) { + /* libata doesn't use ACPI to configure transfer mode. + * It will only confuse device configuration. Skip. + */ + if (tf->command == ATA_CMD_SET_FEATURES && + tf->feature == SETFEATURES_XFER) + return 1; } - err = 0; -out: - return err; + if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) { + /* BIOS writers, sorry but we don't wanna lock + * features unless the user explicitly said so. + */ + + /* DEVICE CONFIGURATION FREEZE LOCK */ + if (tf->command == ATA_CMD_CONF_OVERLAY && + tf->feature == ATA_DCO_FREEZE_LOCK) + return 1; + + /* SECURITY FREEZE LOCK */ + if (tf->command == ATA_CMD_SEC_FREEZE_LOCK) + return 1; + + /* SET MAX LOCK and SET MAX FREEZE LOCK */ + if ((!ptf || ptf->command != ATA_CMD_READ_NATIVE_MAX) && + tf->command == ATA_CMD_SET_MAX && + (tf->feature == ATA_SET_MAX_LOCK || + tf->feature == ATA_SET_MAX_FREEZE_LOCK)) + return 1; + } + + return 0; } /** - * ata_acpi_exec_tfs - get then write drive taskfile settings - * @ap: the ata_port for the drive + * ata_acpi_run_tf - send taskfile registers to host controller + * @dev: target ATA device + * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) * - * This applies to both PATA and SATA drives. + * Outputs ATA taskfile to standard ATA host controller using MMIO + * or PIO as indicated by the ATA_FLAG_MMIO flag. + * Writes the control, feature, nsect, lbal, lbam, and lbah registers. + * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, + * hob_lbal, hob_lbam, and hob_lbah. + * + * This function waits for idle (!BUSY and !DRQ) after writing + * registers. If the control register has a new value, this + * function also waits for idle after writing control and before + * writing the remaining registers. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 1 if command is executed successfully. 0 if ignored, rejected or + * filtered out, -errno on other errors. */ -int ata_acpi_exec_tfs(struct ata_port *ap) +static int ata_acpi_run_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf, + const struct ata_acpi_gtf *prev_gtf) { - int ix; - int ret =0; - unsigned int gtf_length; - unsigned long gtf_address; - unsigned long obj_loc; - - if (noacpi) - return 0; - /* - * TBD - implement PATA support. For now, - * we should not run GTF on PATA devices since some - * PATA require execution of GTM/STM before GTF. - */ - if (!(ap->cbl == ATA_CBL_SATA)) + struct ata_taskfile *pptf = NULL; + struct ata_taskfile tf, ptf, rtf; + unsigned int err_mask; + const char *level; + char msg[60]; + int rc; + + if ((gtf->tf[0] == 0) && (gtf->tf[1] == 0) && (gtf->tf[2] == 0) + && (gtf->tf[3] == 0) && (gtf->tf[4] == 0) && (gtf->tf[5] == 0) + && (gtf->tf[6] == 0)) return 0; - for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { - if (!ata_dev_enabled(&ap->device[ix])) - continue; + ata_acpi_gtf_to_tf(dev, gtf, &tf); + if (prev_gtf) { + ata_acpi_gtf_to_tf(dev, prev_gtf, &ptf); + pptf = &ptf; + } - ret = do_drive_get_GTF(ap, ix, - >f_length, >f_address, &obj_loc); - if (ret < 0) { - if (ata_msg_probe(ap)) - ata_port_printk(ap, KERN_DEBUG, - "%s: get_GTF error (%d)\n", - __FUNCTION__, ret); + if (!ata_acpi_filter_tf(&tf, pptf)) { + rtf = tf; + err_mask = ata_exec_internal(dev, &rtf, NULL, + DMA_NONE, NULL, 0, 0); + + switch (err_mask) { + case 0: + level = KERN_DEBUG; + snprintf(msg, sizeof(msg), "succeeded"); + rc = 1; + break; + + case AC_ERR_DEV: + level = KERN_INFO; + snprintf(msg, sizeof(msg), + "rejected by device (Stat=0x%02x Err=0x%02x)", + rtf.command, rtf.feature); + rc = 0; + break; + + default: + level = KERN_ERR; + snprintf(msg, sizeof(msg), + "failed (Emask=0x%x Stat=0x%02x Err=0x%02x)", + err_mask, rtf.command, rtf.feature); + rc = -EIO; break; } + } else { + level = KERN_INFO; + snprintf(msg, sizeof(msg), "filtered out"); + rc = 0; + } + + ata_dev_printk(dev, level, + "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n", + tf.command, tf.feature, tf.nsect, tf.lbal, + tf.lbam, tf.lbah, tf.device, msg); - ret = do_drive_set_taskfiles(ap, &ap->device[ix], - gtf_length, gtf_address); - kfree((void *)obj_loc); - if (ret < 0) { - if (ata_msg_probe(ap)) - ata_port_printk(ap, KERN_DEBUG, - "%s: set_taskfiles error (%d)\n", - __FUNCTION__, ret); + return rc; +} + +/** + * ata_acpi_exec_tfs - get then write drive taskfile settings + * @dev: target ATA device + * @nr_executed: out paramter for the number of executed commands + * + * Evaluate _GTF and excute returned taskfiles. + * + * LOCKING: + * EH context. + * + * RETURNS: + * Number of executed taskfiles on success, 0 if _GTF doesn't exist. + * -errno on other errors. + */ +static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed) +{ + struct ata_acpi_gtf *gtf = NULL, *pgtf = NULL; + int gtf_count, i, rc; + + /* get taskfiles */ + rc = ata_dev_get_GTF(dev, >f); + if (rc < 0) + return rc; + gtf_count = rc; + + /* execute them */ + for (i = 0; i < gtf_count; i++, gtf++) { + rc = ata_acpi_run_tf(dev, gtf, pgtf); + if (rc < 0) break; + if (rc) { + (*nr_executed)++; + pgtf = gtf; } } - return ret; + ata_acpi_clear_gtf(dev); + + if (rc < 0) + return rc; + return 0; } /** * ata_acpi_push_id - send Identify data to drive - * @ap: the ata_port for the drive - * @ix: drive index + * @dev: target ATA device * * _SDD ACPI object: for SATA mode only * Must be after Identify (Packet) Device -- uses its data * ATM this function never returns a failure. It is an optional * method and if it fails for whatever reason, we should still * just keep going. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. */ -int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +static int ata_acpi_push_id(struct ata_device *dev) { - acpi_handle handle; - acpi_integer pcidevfn; - int err; - struct device *dev = ap->host->dev; - struct ata_device *atadev = &ap->device[ix]; - u32 dev_adr; - acpi_status status; - struct acpi_object_list input; - union acpi_object in_params[1]; - - if (noacpi) - return 0; + struct ata_port *ap = dev->link->ap; + int err; + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[1]; if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", - __FUNCTION__, ix, ap->port_no); - - /* Don't continue if not a SATA device. */ - if (!(ap->cbl == ATA_CBL_SATA)) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: Not a SATA device\n", __FUNCTION__); - goto out; - } - - /* Don't continue if device has no _ADR method. - * _SDD is intended for known motherboard devices. */ - err = sata_get_dev_handle(dev, &handle, &pcidevfn); - if (err < 0) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: sata_get_dev_handle failed (%d\n", - __FUNCTION__, err); - goto out; - } - - /* Get this drive's _ADR info, if not already known */ - if (!atadev->obj_handle) { - dev_adr = SATA_ADR_RSVD; - err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev, - &dev_adr); - if (err < 0 || dev_adr == SATA_ADR_RSVD || - !atadev->obj_handle) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: get_sata_adr failed: " - "err=%d, dev_adr=%u, obj_handle=0x%p\n", - __FUNCTION__, err, dev_adr, - atadev->obj_handle); - goto out; - } - } + ata_dev_printk(dev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", + __func__, dev->devno, ap->port_no); /* Give the drive Identify data to the drive via the _SDD method */ /* _SDD: set up input parameters */ input.count = 1; input.pointer = in_params; in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = sizeof(atadev->id[0]) * ATA_ID_WORDS; - in_params[0].buffer.pointer = (u8 *)atadev->id; + in_params[0].buffer.length = sizeof(dev->id[0]) * ATA_ID_WORDS; + in_params[0].buffer.pointer = (u8 *)dev->id; /* Output buffer: _SDD has no output */ /* It's OK for _SDD to be missing too. */ - swap_buf_le16(atadev->id, ATA_ID_WORDS); - status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL); - swap_buf_le16(atadev->id, ATA_ID_WORDS); + swap_buf_le16(dev->id, ATA_ID_WORDS); + status = acpi_evaluate_object(dev->acpi_handle, "_SDD", &input, NULL); + swap_buf_le16(dev->id, ATA_ID_WORDS); err = ACPI_FAILURE(status) ? -EIO : 0; - if (err < 0) { - if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s _SDD error: status = 0x%x\n", - __FUNCTION__, status); - } + if (err < 0) + ata_dev_printk(dev, KERN_WARNING, + "ACPI _SDD failed (AE 0x%x)\n", status); - /* always return success */ -out: + return err; +} + +/** + * ata_acpi_on_suspend - ATA ACPI hook called on suspend + * @ap: target ATA port + * + * This function is called when @ap is about to be suspended. All + * devices are already put to sleep but the port_suspend() callback + * hasn't been executed yet. Error return from this function aborts + * suspend. + * + * LOCKING: + * EH context. + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int ata_acpi_on_suspend(struct ata_port *ap) +{ + /* nada */ return 0; } +/** + * ata_acpi_on_resume - ATA ACPI hook called on resume + * @ap: target ATA port + * + * This function is called when @ap is resumed - right after port + * itself is resumed but before any EH action is taken. + * + * LOCKING: + * EH context. + */ +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 (ap->acpi_handle && gtm) { + /* _GTM valid */ + + /* restore timing parameters */ + ata_acpi_stm(ap, gtm); + + /* _GTF should immediately follow _STM so that it can + * use values set by _STM. Cache _GTF result and + * schedule _GTF. + */ + ata_link_for_each_dev(dev, &ap->link) { + ata_acpi_clear_gtf(dev); + if (ata_dev_enabled(dev) && + ata_dev_get_GTF(dev, NULL) >= 0) + dev->flags |= ATA_DFLAG_ACPI_PENDING; + } + } else { + /* SATA _GTF needs to be evaulated after _SDD and + * there's no reason to evaluate IDE _GTF early + * without _STM. Clear cache and schedule _GTF. + */ + ata_link_for_each_dev(dev, &ap->link) { + ata_acpi_clear_gtf(dev); + if (ata_dev_enabled(dev)) + dev->flags |= ATA_DFLAG_ACPI_PENDING; + } + } +} + +/** + * ata_acpi_set_state - set the port power state + * @ap: target ATA port + * @state: 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 ata_acpi_set_state(struct ata_port *ap, pm_message_t state) +{ + struct ata_device *dev; + + if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA)) + return; + + /* channel first and then drives for power on and vica versa + for power off */ + if (state.event == PM_EVENT_ON) + acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0); + + ata_link_for_each_dev(dev, &ap->link) { + if (dev->acpi_handle && ata_dev_enabled(dev)) + acpi_bus_set_power(dev->acpi_handle, + state.event == PM_EVENT_ON ? + ACPI_STATE_D0 : ACPI_STATE_D3); + } + if (state.event != PM_EVENT_ON) + acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3); +} + +/** + * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration + * @dev: target ATA device + * + * This function is called when @dev is about to be configured. + * IDENTIFY data might have been modified after this hook is run. + * + * LOCKING: + * EH context. + * + * RETURNS: + * Positive number if IDENTIFY data needs to be refreshed, 0 if not, + * -errno on failure. + */ +int ata_acpi_on_devcfg(struct ata_device *dev) +{ + struct ata_port *ap = dev->link->ap; + struct ata_eh_context *ehc = &ap->link.eh_context; + int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; + int nr_executed = 0; + int rc; + + if (!dev->acpi_handle) + return 0; + + /* do we need to do _GTF? */ + if (!(dev->flags & ATA_DFLAG_ACPI_PENDING) && + !(acpi_sata && (ehc->i.flags & ATA_EHI_DID_HARDRESET))) + return 0; + + /* do _SDD if SATA */ + if (acpi_sata) { + rc = ata_acpi_push_id(dev); + if (rc) + goto acpi_err; + } + + /* do _GTF */ + rc = ata_acpi_exec_tfs(dev, &nr_executed); + if (rc) + goto acpi_err; + + dev->flags &= ~ATA_DFLAG_ACPI_PENDING; + /* refresh IDENTIFY page if any _GTF command has been executed */ + if (nr_executed) { + rc = ata_dev_reread_id(dev, 0); + if (rc < 0) { + ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " + "after ACPI commands\n"); + return rc; + } + } + + return 0; + + acpi_err: + /* ignore evaluation failure if we can continue safely */ + if (rc == -EINVAL && !nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN)) + return 0; + + /* fail and let EH retry once more for unknown IO errors */ + if (!(dev->flags & ATA_DFLAG_ACPI_FAILED)) { + dev->flags |= ATA_DFLAG_ACPI_FAILED; + return rc; + } + + ata_dev_printk(dev, KERN_WARNING, + "ACPI: failed the second time, disabled\n"); + dev->acpi_handle = NULL; + + /* We can safely continue if no _GTF command has been executed + * and port is not frozen. + */ + if (!nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN)) + return 0; + + return rc; +} + +/** + * ata_acpi_on_disable - ATA ACPI hook called when a device is disabled + * @dev: target ATA device + * + * This function is called when @dev is about to be disabled. + * + * LOCKING: + * EH context. + */ +void ata_acpi_on_disable(struct ata_device *dev) +{ + ata_acpi_clear_gtf(dev); +}