libata: improve ATA ACPI support, take#3
PATCH 1/1 libata: improve ATA ACPI support, take#3
Hello,
This is the third take of improve-ata-acpi. Except for regeneration to fit the current libata-dev#upstream[U], there's no change from the last take[L].
Jeff, the first two fixes possible problem when HPA is used. I think these two should go into 2.6.22.
Thanks.
--
tejun
[U] b9a3b4d1453689f2927668fcdc4827fdccf44d1b
[L] http://thread.gmane.org/gmane.linux.acpi.devel/22819
PATCH 1/9 libata: separate out ata_dev_reread_id()
Separate out ata_dev_reread_id() from ata_dev_revalidate(). ata_dev_reread_id() reads IDENTIFY page and determines whether the same device is still there. ata_dev_revalidate() reconfigures after reread completes. This will be used by ACPI update.
--- drivers/ata/libata-core.c | 47 ++++++++++++++++++++++++++++++++------------ drivers/ata/libata.h | 3 +- 2 files changed, 36 insertions(+), 14 deletions(-)
drivers/ata/libata-core.c +34 -13
@@ -3675,8 +3675,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, }/** -* ata_dev_revalidate - Revalidate ATA device -* @dev: device to revalidate +* ata_dev_reread_id - Re-read IDENTIFY data +* @adev: target ATA device * @readid_flags: read ID flags * * Re-read IDENTIFY page and make sure @dev is still attached to
@@ -3688,29 +3688,50 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,* RETURNS: * 0 on success, negative errno otherwise */ -int ata_dev_revalidate (struct ata_device *dev,unsigned int readid_flags) +int ata_dev_reread_id (struct ata_device *dev,unsigned int readid_flags) {unsigned int class = dev->class;u16 *id = (void *)dev->ap->sector_buf;int rc; -if (!ata_dev_enabled (dev)) { - rc = -ENODEV ; - goto fail; - } -/* read ID data */ rc =ata_dev_read_id (dev, &class, readid_flags, id);if (rc) - goto fail; +return rc;/* is the device still there? */ -if (!ata_dev_same_device (dev, class, id)) { - rc = -ENODEV ; - goto fail; - } +if (!ata_dev_same_device (dev, class, id)) +return -ENODEV ;memcpy (dev->id, id,sizeof (id[0 ]) *ATA_ID_WORDS ); +return 0 ; +} + +/** +* ata_dev_revalidate - Revalidate ATA device +* @dev: device to revalidate +* @readid_flags: read ID flags +* +* Re-read IDENTIFY page, make sure @dev is still attached to the +* port and reconfigure it according to the new IDENTIFY page. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* 0 on success, negative errno otherwise +*/ +int ata_dev_revalidate (struct ata_device *dev,unsigned int readid_flags) +{ +int rc; + +if (!ata_dev_enabled (dev)) +return -ENODEV ; + +/* re-read ID */ + rc =ata_dev_reread_id (dev, readid_flags); +if (rc) + goto fail;/* configure device according to the new ID */ rc =ata_dev_configure (dev);
drivers/ata/libata.h +2 -1
@@ -76,7 +76,8 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev,extern unsigned int ata_do_simple_cmd (struct ata_device *dev,u8 cmd);extern int ata_dev_read_id (struct ata_device *dev,unsigned int *p_class,unsigned int flags,u16 *id); -extern int ata_dev_revalidate (struct ata_device *dev,unsigned int flags); +extern int ata_dev_reread_id (struct ata_device *dev,unsigned int readid_flags); +extern int ata_dev_revalidate (struct ata_device *dev,unsigned int readid_flags);extern int ata_dev_configure (struct ata_device *dev);extern int sata_down_spd_limit (struct ata_port *ap);extern int sata_set_spd_needed (struct ata_port *ap);
Signature · 1 line
1.5.0.3
PATCH 2/9 libata: during revalidation, check n_sectors after device is configured
In reply to Tejun HeoDevice might be resized during ata_dev_configure() due to HPA or (later) ACPI _GTF. Currently it's worked around by caching n_sectors before turning off HPA. The cached original size is overwritten if the device is reconfigured without being hardreset - which always happens after configuring trasnfer mode. If the device gets hardreset for some reason after that, revalidation fails with -ENODEV.
This patch makes size checking more robust by moving n_sectors check from ata_dev_reread_id() to ata_dev_revalidate() after the device is fully configured. No matter what happens during configuration, a device must have the same n_sectors after fully configured to be treated as the same device.
--- drivers/ata/libata-core.c | 33 +++++++++++++++------------------ include/linux/libata.h | 1 - 2 files changed, 15 insertions(+), 19 deletions(-)
drivers/ata/libata-core.c +15 -18
@@ -1919,7 +1919,6 @@ int ata_dev_configure(struct ata_device *dev)snprintf (revbuf,7 ,"ATA-%d" ,ata_id_major_version (id)); dev->n_sectors =ata_id_n_sectors (id); - dev->n_sectors_boot = dev->n_sectors;/* SCSI only uses 4-char revisions, dump full 8 chars from ATA */ ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
@@ -3632,7 +3631,6 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,const u16 *old_id = dev->id;unsigned char model[2 ][ATA_ID_PROD_LEN +1 ];unsigned char serial[2 ][ATA_ID_SERNO_LEN +1 ]; -u64 new_n_sectors;if (dev->class != new_class) { ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
@@ -3644,7 +3642,6 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,ata_id_c_string (new_id, model[1 ],ATA_ID_PROD ,sizeof (model[1 ]));ata_id_c_string (old_id, serial[0 ],ATA_ID_SERNO ,sizeof (serial[0 ]));ata_id_c_string (new_id, serial[1 ],ATA_ID_SERNO ,sizeof (serial[1 ])); - new_n_sectors =ata_id_n_sectors (new_id);if (strcmp (model[0 ], model[1 ])) { ata_dev_printk(dev, KERN_INFO, "model number mismatch "
@@ -3658,19 +3655,6 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,return 0 ; } -if (dev->class ==ATA_DEV_ATA && dev->n_sectors != new_n_sectors) { -ata_dev_printk (dev,KERN_INFO ,"n_sectors mismatch " -"%llu != %llu\n" , - (unsigned long long )dev->n_sectors, - (unsigned long long )new_n_sectors); -/* Are we the boot time size - if so we appear to be the -same disk at this point and our HPA got reapplied */ -if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors - &&ata_id_hpa_enabled (new_id)) -return 1 ; -return 0 ; - } -return 1 ; }
@@ -3723,6 +3707,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)*/ int ata_dev_revalidate (struct ata_device *dev,unsigned int readid_flags) { +u64 n_sectors = dev->n_sectors;int rc;if (!ata_dev_enabled (dev))
@@ -3735,8 +3720,20 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)/* configure device according to the new ID */ rc =ata_dev_configure (dev); -if (rc ==0 ) -return 0 ; +if (rc) + goto fail; + +/* verify n_sectors hasn't changed */ +if (dev->class ==ATA_DEV_ATA && dev->n_sectors != n_sectors) { +ata_dev_printk (dev,KERN_INFO ,"n_sectors mismatch " +"%llu != %llu\n" , + (unsigned long long )n_sectors, + (unsigned long long )dev->n_sectors); + rc = -ENODEV ; + goto fail; + } + +return 0 ; fail:ata_dev_printk (dev,KERN_ERR ,"revalidation failed (errno=%d)\n" , rc);
include/linux/libata.h +0 -1
@@ -431,7 +431,6 @@ struct ata_device {struct scsi_device *sdev;/* attached SCSI device */ /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ u64 n_sectors;/* size of device, if ATA */ -u64 n_sectors_boot;/* size of ATA device at startup */ unsigned int class;/* ATA_DEV_xxx */ u16 id[ATA_ID_WORDS ];/* IDENTIFY xxx DEVICE data */ u8 pio_mode;
Signature · 1 line
1.5.0.3
PATCH 3/9 libata-acpi: add ATA_FLAG_ACPI_SATA port flag
In reply to Tejun HeoWhether a controller needs IDE or SATA ACPI hierarchy is determined by the programming interface of the controller not by whether the controller is SATA or PATA, or it supports slave device or not. This patch adds ATA_FLAG_ACPI_SATA port flags which tells libata-acpi that the port needs SATA ACPI nodes, and sets the flag for ahci and sata_sil24.
--- drivers/ata/ahci.c | 3 ++- drivers/ata/libata-acpi.c | 10 +++++----- drivers/ata/sata_sil24.c | 3 ++- include/linux/libata.h | 1 + 4 files changed, 10 insertions(+), 7 deletions(-)
drivers/ata/ahci.c +2 -1
@@ -173,7 +173,8 @@ enum {AHCI_FLAG_COMMON =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY |ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | - ATA_FLAG_SKIP_D2H_BSY, +ATA_FLAG_SKIP_D2H_BSY | + ATA_FLAG_ACPI_SATA, };struct ahci_cmd_hdr {
drivers/ata/libata-acpi.c +5 -5
@@ -321,7 +321,7 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length,/* Don't continue if device has no _ADR method. * _GTF is intended for known motherboard devices. */ -if (!(ap->cbl ==ATA_CBL_SATA )) { +if (!(ap->flags &ATA_FLAG_ACPI_SATA )) { err =pata_get_dev_handle (gdev, &dev_handle, &pcidevfn);if (err <0 ) {if (ata_msg_probe (ap))
@@ -343,7 +343,7 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length,/* Get this drive's _ADR info. if not already known. */ if (!dev->obj_handle) { -if (!(ap->cbl ==ATA_CBL_SATA )) { +if (!(ap->flags &ATA_FLAG_ACPI_SATA )) {/* get child objects of dev_handle == channel objects, * + _their_ children == drive objects */ /* channel is ap->port_no */
@@ -528,7 +528,7 @@ static int do_drive_set_taskfiles(struct ata_device *dev,ata_dev_printk (dev,KERN_DEBUG ,"%s: ENTER: port#: %d\n" , __FUNCTION__, ap->port_no); -if (libata_noacpi || !(ap->cbl ==ATA_CBL_SATA )) +if (libata_noacpi || !(ap->flags &ATA_FLAG_ACPI_SATA ))return 0 ;if (!ata_dev_enabled (dev) || (ap->flags &ATA_FLAG_DISABLED ))
@@ -578,7 +578,7 @@ int ata_acpi_exec_tfs(struct ata_port *ap)* we should not run GTF on PATA devices since some * PATA require execution of GTM/STM before GTF. */ -if (!(ap->cbl ==ATA_CBL_SATA )) +if (!(ap->flags &ATA_FLAG_ACPI_SATA ))return 0 ;for (ix =0 ; ix <ATA_MAX_DEVICES ; ix++) {
@@ -641,7 +641,7 @@ int ata_acpi_push_id(struct ata_device *dev) __FUNCTION__, dev->devno, ap->port_no);/* Don't continue if not a SATA device. */ -if (!(ap->cbl ==ATA_CBL_SATA )) { +if (!(ap->flags &ATA_FLAG_ACPI_SATA )) {if (ata_msg_probe (ap))ata_dev_printk (dev,KERN_DEBUG ,"%s: Not a SATA device\n" , __FUNCTION__);
drivers/ata/sata_sil24.c +2 -1
@@ -237,7 +237,8 @@ enum {/* host flags */ SIL24_COMMON_FLAGS =ATA_FLAG_SATA |ATA_FLAG_NO_LEGACY |ATA_FLAG_MMIO |ATA_FLAG_PIO_DMA | -ATA_FLAG_NCQ |ATA_FLAG_SKIP_D2H_BSY , +ATA_FLAG_NCQ |ATA_FLAG_SKIP_D2H_BSY | +ATA_FLAG_ACPI_SATA ,SIL24_FLAG_PCIX_IRQ_WOC = (1 <<24 ),/* IRQ loss errata on PCI-X */ IRQ_STAT_4PORTS = 0xf,
include/linux/libata.h +1 -0
@@ -173,6 +173,7 @@ enum {ATA_FLAG_SETXFER_POLLING = (1 <<14 ),/* use polling for SETXFER */ ATA_FLAG_IGN_SIMPLEX = (1 <<15 ),/* ignore SIMPLEX */ ATA_FLAG_NO_IORDY = (1 <<16 ),/* controller lacks iordy */ +ATA_FLAG_ACPI_SATA = (1 <<17 ),/* need native SATA ACPI layout */ /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be
Signature · 1 line
1.5.0.3
PATCH 4/9 libata-acpi: implement ata_acpi_associate()
In reply to Tejun Heo* Add acpi_handle to ata_host and ata_port. Rename ata_device->obj_handle to ->acpi_handle and move it above such that it doesn't get cleared on reconfiguration.
* Replace ACPI node association which ata_acpi_associate() which is called once during host initialization. Unlike the previous implementation, ata_acpi_associate() uses ATA_FLAG_ACPI_SATA to choose between IDE or SATA ACPI hierarchy and uses simple child look up instead of recursive walk to match the nodes. This is way safer and simpler. Please read the following message for more info.
http://article.gmane.org/gmane.linux.ide/17554
--- drivers/ata/libata-acpi.c | 369 ++++++--------------------------------------- drivers/ata/libata-core.c | 3 + drivers/ata/libata.h | 2 + include/linux/libata.h | 13 +- 4 files changed, 63 insertions(+), 324 deletions(-)
drivers/ata/libata-acpi.c +49 -320
@@ -24,10 +24,8 @@#include <acpi/acmacros.h> #include <acpi/actypes.h> -#define SATA_ROOT_PORT (x) (((x) >> 16) & 0xffff) -#define SATA_PORT_NUMBER (x) ((x) & 0xffff)/* or NO_PORT_MULT */ #define NO_PORT_MULT 0xffff -#define SATA_ADR_RSVD 0xffffffff +#define SATA_ADR (root,pmp) (((root) << 16) | (pmp))#define REGS_PER_GTF 7struct taskfile_array {
@@ -42,230 +40,64 @@ static int is_pci_dev(struct device *dev)return (dev->bus == &pci_bus_type); } -/** -* 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 -* -* 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. -* -* Returns 0 on success, <0 on error. -*/ -static int sata_get_dev_handle (struct device *dev,acpi_handle *handle, -acpi_integer *pcidevfn) +static 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 ; +acpi_integer adr =SATA_ADR (ap->port_no,NO_PORT_MULT ); + + ap->device->acpi_handle =acpi_get_child (ap->host->acpi_handle, adr); } -/** -* 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 -* -* The PATA and SATA versions of this function are different. -* -* Returns 0 on success, <0 on error. -*/ -static int pata_get_dev_handle (struct device *dev,acpi_handle *handle, -acpi_integer *pcidevfn) +static void ata_acpi_associate_ide_port (struct ata_port *ap) { -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 ; - - pdev =to_pci_dev (dev); - - bus = pdev->bus->number; - devnum =PCI_SLOT (pdev->devfn); - func =PCI_FUNC (pdev->devfn); - - dev_handle =DEVICE_ACPI_HANDLE (dev); - parent_handle =DEVICE_ACPI_HANDLE (dev->parent); - - status =acpi_get_object_info (parent_handle, &buffer); -if (ACPI_FAILURE (status)) - goto err; - - 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; - } +int max_devices, i; -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; -}; + ap->acpi_handle =acpi_get_child (ap->host->acpi_handle, ap->port_no); +if (!ap->acpi_handle) +return ; -static acpi_status get_devices (acpi_handle handle, -u32 level,void *context,void **return_value) -{ -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; - } + max_devices =1 ; +if (ap->flags &ATA_FLAG_SLAVE_POSS ) + max_devices++; -/* if basepath is not yet known, ignore this object */ -if (!winfo->basepath_len) - goto out; +for (i =0 ; i < max_devices; i++) { +struct ata_device *dev = &ap->device[i]; -/* 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; - } + dev->acpi_handle =acpi_get_child (ap->acpi_handle, i); } -out: -kfree (dinfo); -out2: -kfree (pathname); - -ret: -return status; } -/* 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) +/** +* 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. +* +* LOCKING: +* EH context. +* +* RETURNS: +* 0 on success, -errno on failure. +*/ +void ata_acpi_associate (struct ata_host *host) { -acpi_status status; -struct walk_info *winfo; -int err = -ENOMEM ; +int i; - winfo =kzalloc (sizeof (struct walk_info ),GFP_KERNEL ); -if (!winfo) - goto out; +if (!is_pci_dev (host->dev) || libata_noacpi) +return ; - 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; + host->acpi_handle =DEVICE_ACPI_HANDLE (host->dev); +if (!host->acpi_handle) +return ; - status =acpi_get_devices (NULL , get_devices, winfo,NULL ); -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 ; +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); } -kfree (winfo); -out: -return err; }/**
@@ -290,20 +122,15 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, {struct ata_port *ap = dev->ap;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 *gdev = ap->host->dev;int err = -ENODEV ; *gtf_length =0 ; *gtf_address =0UL ; *obj_loc =0UL ; -if (libata_noacpi) +if (!dev->acpi_handle)return 0 ;if (ata_msg_probe (ap))
@@ -319,78 +146,14 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, goto out; } -/* Don't continue if device has no _ADR method. -* _GTF is intended for known motherboard devices. */ -if (!(ap->flags &ATA_FLAG_ACPI_SATA )) { - err =pata_get_dev_handle (gdev, &dev_handle, &pcidevfn); -if (err <0 ) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG , -"%s: pata_get_dev_handle failed (%d)\n" , - __FUNCTION__, err); - goto out; - } - }else { - err =sata_get_dev_handle (gdev, &dev_handle, &pcidevfn); -if (err <0 ) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,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 (!dev->obj_handle) { -if (!(ap->flags &ATA_FLAG_ACPI_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 (dev,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, dev->devno); -if (!drive_handle) { - err = -ENODEV ; - goto out; - } - dev_adr = dev->devno; - dev->obj_handle = drive_handle; - }else {/* for SATA mode */ - dev_adr =SATA_ADR_RSVD ; - err =get_sata_adr (gdev, dev_handle, pcidevfn,0 , - ap, dev, &dev_adr); - } -if (err <0 || dev_adr ==SATA_ADR_RSVD || - !dev->obj_handle) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG , -"%s: get_sata/pata_adr failed: " -"err=%d, dev_adr=%u, obj_handle=0x%p\n" , - __FUNCTION__, err, dev_adr, - dev->obj_handle); - goto out; - } - } -/* Setting up output buffer */ output.length =ACPI_ALLOCATE_BUFFER ; output.pointer =NULL ;/* ACPI-CA sets this; save/free it later */ /* _GTF has no input parameters */ err = -EIO ; - status =acpi_evaluate_object (dev->obj_handle,"_GTF" , -NULL , &output); + status =acpi_evaluate_object (dev->acpi_handle,"_GTF" , +NULL , &output);if (ACPI_FAILURE (status)) {if (ata_msg_probe (ap)) ata_dev_printk(dev, KERN_DEBUG,
@@ -528,7 +291,7 @@ static int do_drive_set_taskfiles(struct ata_device *dev,ata_dev_printk (dev,KERN_DEBUG ,"%s: ENTER: port#: %d\n" , __FUNCTION__, ap->port_no); -if (libata_noacpi || !(ap->flags &ATA_FLAG_ACPI_SATA )) +if (!(ap->flags &ATA_FLAG_ACPI_SATA ))return 0 ;if (!ata_dev_enabled (dev) || (ap->flags &ATA_FLAG_DISABLED ))
@@ -571,8 +334,6 @@ int ata_acpi_exec_tfs(struct ata_port *ap)unsigned long gtf_address;unsigned long obj_loc; -if (libata_noacpi) -return 0 ;/* * TBD - implement PATA support. For now, * we should not run GTF on PATA devices since some
@@ -624,16 +385,12 @@ int ata_acpi_exec_tfs(struct ata_port *ap)int ata_acpi_push_id (struct ata_device *dev) {struct ata_port *ap = dev->ap; -acpi_handle handle; -acpi_integer pcidevfn;int err; -struct device *gdev = ap->host->dev; -u32 dev_adr;acpi_status status;struct acpi_object_list input;union acpi_object in_params[1 ]; -if (libata_noacpi) +if (!dev->acpi_handle)return 0 ;if (ata_msg_probe (ap))
@@ -648,34 +405,6 @@ int ata_acpi_push_id(struct ata_device *dev) goto out; } -/* Don't continue if device has no _ADR method. -* _SDD is intended for known motherboard devices. */ - err =sata_get_dev_handle (gdev, &handle, &pcidevfn); -if (err <0 ) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,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 (!dev->obj_handle) { - dev_adr =SATA_ADR_RSVD ; - err =get_sata_adr (gdev, handle, pcidevfn, dev->devno, ap, dev, - &dev_adr); -if (err <0 || dev_adr ==SATA_ADR_RSVD || - !dev->obj_handle) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG , -"%s: get_sata_adr failed: " -"err=%d, dev_adr=%u, obj_handle=0x%p\n" , - __FUNCTION__, err, dev_adr, - dev->obj_handle); - goto out; - } - } -/* Give the drive Identify data to the drive via the _SDD method */ /* _SDD: set up input parameters */ input.count =1 ;
@@ -687,7 +416,7 @@ int ata_acpi_push_id(struct ata_device *dev)/* It's OK for _SDD to be missing too. */ swap_buf_le16 (dev->id,ATA_ID_WORDS ); - status =acpi_evaluate_object (dev->obj_handle,"_SDD" , &input,NULL ); + status =acpi_evaluate_object (dev->acpi_handle,"_SDD" , &input,NULL );swap_buf_le16 (dev->id,ATA_ID_WORDS ); err =ACPI_FAILURE (status) ? -EIO :0 ;
drivers/ata/libata-core.c +3 -0
@@ -6311,6 +6311,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)if (rc)return rc; +/* associate with ACPI nodes */ +ata_acpi_associate (host); +/* set cable, sata_spd_limit and report */ for (i =0 ; i < host->n_ports; i++) {struct ata_port *ap = host->ports[i];
drivers/ata/libata.h +2 -0
@@ -99,9 +99,11 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);/* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI +extern void ata_acpi_associate (struct ata_host *host);extern int ata_acpi_exec_tfs (struct ata_port *ap);extern int ata_acpi_push_id (struct ata_device *dev);#else +static inline void ata_acpi_associate (struct ata_host *host) { }static inline int ata_acpi_exec_tfs (struct ata_port *ap) {return 0 ;
include/linux/libata.h +9 -4
@@ -364,6 +364,9 @@ struct ata_host {void *private_data;const struct ata_port_operations *ops;unsigned long flags; +#ifdef CONFIG_ATA_ACPI +acpi_handle acpi_handle; +#endif struct ata_port *simplex_claimed;/* channel owning the DMA */ struct ata_port *ports[0 ]; };
@@ -430,6 +433,9 @@ struct ata_device {unsigned int devno;/* 0 or 1 */ unsigned long flags;/* ATA_DFLAG_xxx */ struct scsi_device *sdev;/* attached SCSI device */ +#ifdef CONFIG_ATA_ACPI +acpi_handle acpi_handle; +#endif /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ u64 n_sectors;/* size of device, if ATA */ unsigned int class;/* ATA_DEV_xxx */
@@ -458,10 +464,6 @@ struct ata_device {struct ata_ering ering;int spdn_cnt;unsigned int horkage;/* List of broken features */ -#ifdef CONFIG_ATA_ACPI -/* ACPI objects info */ -acpi_handle obj_handle; -#endif };/* Offset into struct ata_device. Fields above it are maintained
@@ -550,6 +552,9 @@ struct ata_port {void *private_data; +#ifdef CONFIG_ATA_ACPI +acpi_handle acpi_handle; +#endif u8 sector_buf[ATA_SECT_SIZE ];/* owned by EH */ };
Signature · 1 line
1.5.0.3
PATCH 5/9 libata-acpi: clean up ata_acpi_exec_tfs()
In reply to Tejun HeoThis patch cleans up ata_acpi_exec_tfs() and its friends.
* Rename taskfile_array to ata_acpi_gtf and make it __packed as it's used as argument to ACPI method, and use pointer to ata_acpi_gtf and number of taskfiles to represent _GTF taskfiles instead of a pointer casted into unsigned long and byte count. This makes argument re-checking in do_drive_set_taskfiles() unnecessary.
* Pointer in void * not in unsigned long.
* Clean up do_drive_get_GTF() error handling and make do_drive_get_GTF() return number of taskfiles on success, 0 if _GTF doesn't exist or doesn't contain valid ata. -errno on other errors.
* Remove superflous check for acpi->buffer.pointer.
* Update taskfile_load_raw() such that printed messages look similar to the messages printed by ata_eh_report().
* s/do_drive_get_GTF/ata_dev_get_GTF/
s/do_drive_set_taskfiles/ata_dev_set_taskfiles/
--- drivers/ata/libata-acpi.c | 226 ++++++++++++++++++++++----------------------- 1 files changed, 111 insertions(+), 115 deletions(-)
drivers/ata/libata-acpi.c +111 -115
@@ -28,9 +28,9 @@#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
@@ -101,10 +101,10 @@ void ata_acpi_associate(struct ata_host *host) }/** -* do_drive_get_GTF - get the drive bootup default taskfile settings +* ata_dev_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device -* @gtf_length: number of bytes of _GTF data returned at @gtf_address -* @gtf_address: buffer containing _GTF taskfile arrays +* @gtf: output parameter for buffer containing _GTF taskfile arrays +* @ptr_to_free: pointer which should be freed * * This applies to both PATA and SATA drives. *
@@ -114,24 +114,28 @@ void ata_acpi_associate(struct ata_host *host)* The <variable number> 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 or doesn't +* contain valid data. -errno on other errors. */ -static int do_drive_get_GTF (struct ata_device *dev,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, +void **ptr_to_free) {struct ata_port *ap = dev->ap;acpi_status status;struct acpi_buffer output;union acpi_object *out_obj; -int err = -ENODEV ; +int rc =0 ; - *gtf_length =0 ; - *gtf_address =0UL ; - *obj_loc =0UL ; +/* set up output buffer */ + output.length =ACPI_ALLOCATE_BUFFER ; + output.pointer =NULL ;/* ACPI-CA sets this; save/free it later */ if (!dev->acpi_handle) -return 0 ; + goto out_free;if (ata_msg_probe (ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
@@ -143,23 +147,20 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length,"ata_dev_present: %d, PORT_DISABLED: %lu\n" , __FUNCTION__,ata_dev_enabled (dev), ap->flags & ATA_FLAG_DISABLED); - goto out; + goto out_free; } -/* Setting up output buffer */ - output.length =ACPI_ALLOCATE_BUFFER ; - output.pointer =NULL ;/* ACPI-CA sets this; save/free it later */ -/* _GTF has no input parameters */ - err = -EIO ; - status =acpi_evaluate_object (dev->acpi_handle,"_GTF" , -NULL , &output); + status =acpi_evaluate_object (dev->acpi_handle,"_GTF" ,NULL , &output); +if (ACPI_FAILURE (status)) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,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 = -EIO ; + } + goto out_free; }if (!output.length || !output.pointer) {
@@ -169,43 +170,43 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, __FUNCTION__, (unsigned long long )output.length, output.pointer); -kfree (output.pointer); - goto out; + 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 (dev,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; + rc = -EINVAL ; + goto out_free; } -if (!out_obj->buffer.length || !out_obj->buffer.pointer || - out_obj->buffer.length %REGS_PER_GTF ) { +if (out_obj->buffer.length %REGS_PER_GTF ) {if (ata_msg_drv (ap))ata_dev_printk (dev,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; + 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; + *ptr_to_free = out_obj; + *gtf = (void *)out_obj->buffer.pointer; + rc = out_obj->buffer.length /REGS_PER_GTF ; +if (ata_msg_probe (ap))ata_dev_printk (dev,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; +"gtf=%p, gtf_count=%d, ptr_to_free=%p\n" , + __FUNCTION__, *gtf, rc, *ptr_to_free); +return rc; + + out_free: +kfree (output.pointer); +return rc; }/**
@@ -224,68 +225,78 @@ out:* function also waits for idle after writing control and before * writing the remaining registers. * -* LOCKING: TBD: -* Inherited from caller. +* LOCKING: +* EH context. +* +* RETURNS: +* 0 on success, -errno on failure. */ -static void taskfile_load_raw (struct ata_device *dev, -const struct taskfile_array *gtf) +static int taskfile_load_raw (struct ata_device *dev, +const struct ata_acpi_gtf *gtf) {struct ata_port *ap = dev->ap; -struct ata_taskfile tf; -unsigned int err; +struct ata_taskfile tf, rtf; +unsigned int err_mask; -if (ata_msg_probe (ap)) -ata_dev_printk (dev,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 ; +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 ;ata_tf_init (dev, &tf);/* convert gtf to tf */ tf.flags |=ATA_TFLAG_ISADDR |ATA_TFLAG_DEVICE ;/* TBD */ tf.protocol =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 (dev, &tf,NULL ,DMA_NONE ,NULL ,0 ); -if (err &&ata_msg_probe (ap)) + 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 */ + +if (ata_msg_probe (ap)) +ata_dev_printk (dev,KERN_DEBUG ,"executing ACPI cmd " +"%02x/%02x:%02x:%02x:%02x:%02x:%02x\n" , + tf.command, tf.feature, tf.nsect, + tf.lbal, tf.lbam, tf.lbah, tf.device); + + rtf = tf; + err_mask =ata_exec_internal (dev, &rtf,NULL ,DMA_NONE ,NULL ,0 ); +if (err_mask) {ata_dev_printk (dev,KERN_ERR , -"%s: ata_exec_internal failed: %u\n" , - __FUNCTION__, err); +"ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " +"(Emask=0x%x Stat=0x%02x Err=0x%02x)\n" , + tf.command, tf.feature, tf.nsect, tf.lbal, tf.lbam, + tf.lbah, tf.device, err_mask, rtf.command, rtf.feature); +return -EIO ; + } + +return 0 ; }/** -* do_drive_set_taskfiles - write the drive taskfile settings from _GTF +* ata_dev_set_taskfiles - write the drive taskfile settings from _GTF * @dev: target ATA device -* @gtf_length: total number of bytes of _GTF taskfiles -* @gtf_address: location of _GTF taskfile arrays +* @gtf: pointer to array of _GTF taskfiles to execute +* @gtf_count: number of taskfiles * * This applies to both PATA and SATA drives. * -* Write {gtf_address, length gtf_length} in groups of -* REGS_PER_GTF bytes. +* Execute taskfiles in @gtf. +* +* LOCKING: +* EH context. +* +* RETURNS: +* 0 on success, -errno on failure. */ -static int do_drive_set_taskfiles (struct ata_device *dev, -unsigned int gtf_length, -unsigned long gtf_address) +static int ata_dev_set_taskfiles (struct ata_device *dev, +struct ata_acpi_gtf *gtf,int gtf_count) {struct ata_port *ap = dev->ap; -int err = -ENODEV ; -int gtf_count = gtf_length /REGS_PER_GTF ;int ix; -struct taskfile_array *gtf;if (ata_msg_probe (ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
@@ -295,29 +306,13 @@ static int do_drive_set_taskfiles(struct ata_device *dev,return 0 ;if (!ata_dev_enabled (dev) || (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 (dev,KERN_ERR , -"%s: unexpected GTF length (%d)\n" , - __FUNCTION__, gtf_length); - goto out; - } +return -ENODEV ; -for (ix =0 ; ix < gtf_count; ix++) { - gtf = (struct taskfile_array *) - (gtf_address + ix *REGS_PER_GTF ); +/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ +for (ix =0 ; ix < gtf_count; ix++) +taskfile_load_raw (dev, gtf++); -/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ -taskfile_load_raw (dev, gtf); - } - - err =0 ; -out: -return err; +return 0 ; }/**
@@ -328,11 +323,7 @@ out:*/ int ata_acpi_exec_tfs (struct ata_port *ap) { -int ix; -int ret =0 ; -unsigned int gtf_length; -unsigned long gtf_address; -unsigned long obj_loc; +int ix, ret =0 ;/* * TBD - implement PATA support. For now,
@@ -344,12 +335,16 @@ int ata_acpi_exec_tfs(struct ata_port *ap)for (ix =0 ; ix <ATA_MAX_DEVICES ; ix++) {struct ata_device *dev = &ap->device[ix]; +struct ata_acpi_gtf *gtf =NULL ; +int gtf_count; +void *ptr_to_free =NULL ;if (!ata_dev_enabled (dev))continue ; - ret =do_drive_get_GTF (dev, >f_length, >f_address, - &obj_loc); + ret =ata_dev_get_GTF (dev, >f, &ptr_to_free); +if (ret ==0 ) +continue ;if (ret <0 ) {if (ata_msg_probe (ap)) ata_port_printk(ap, KERN_DEBUG,
@@ -357,9 +352,10 @@ int ata_acpi_exec_tfs(struct ata_port *ap) __FUNCTION__, ret);break ; } + gtf_count = ret; - ret =do_drive_set_taskfiles (dev, gtf_length, gtf_address); -kfree ((void *)obj_loc); + ret =ata_dev_set_taskfiles (dev, gtf, gtf_count); +kfree (ptr_to_free);if (ret <0 ) {if (ata_msg_probe (ap)) ata_port_printk(ap, KERN_DEBUG,
Signature · 1 line
1.5.0.3
PATCH 6/9 libata-acpi: miscellaneous cleanups
In reply to Tejun Heo* Add missing LOCKING: and RETURNS: to function comment.
* Don't conditionalize warning messages with ata_msg_probe(). Print directly with KERN_WARNING.
* Drop duplicate debug messages.
--- drivers/ata/libata-acpi.c | 51 ++++++++++++++++++++------------------------ 1 files changed, 23 insertions(+), 28 deletions(-)
drivers/ata/libata-acpi.c +23 -28
@@ -175,21 +175,17 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, out_obj = output.pointer;if (out_obj->type !=ACPI_TYPE_BUFFER ) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG ,"%s: Run _GTF: " -"error: expected object type of " -" ACPI_TYPE_BUFFER, got 0x%x\n" , - __FUNCTION__, out_obj->type); +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 %REGS_PER_GTF ) { -if (ata_msg_drv (ap)) -ata_dev_printk (dev,KERN_ERR , -"%s: unexpected GTF length (%d) or addr (0x%p)\n" , - __FUNCTION__, out_obj->buffer.length, - out_obj->buffer.pointer); +ata_dev_printk (dev,KERN_WARNING , +"unexpected _GTF length (%d)\n" , + out_obj->buffer.length); rc = -EINVAL ; goto out_free; }
@@ -320,6 +316,12 @@ static int ata_dev_set_taskfiles(struct ata_device *dev,* @ap: the ata_port for the drive * * This applies to both PATA and SATA drives. +* +* LOCKING: +* EH context. +* +* RETURNS: +* 0 on success, -errno on failure. */ int ata_acpi_exec_tfs (struct ata_port *ap) {
@@ -345,24 +347,14 @@ int ata_acpi_exec_tfs(struct ata_port *ap) ret =ata_dev_get_GTF (dev, >f, &ptr_to_free);if (ret ==0 )continue ; -if (ret <0 ) { -if (ata_msg_probe (ap)) -ata_port_printk (ap,KERN_DEBUG , -"%s: get_GTF error (%d)\n" , - __FUNCTION__, ret); +if (ret <0 )break ; - } gtf_count = ret; ret =ata_dev_set_taskfiles (dev, gtf, gtf_count);kfree (ptr_to_free); -if (ret <0 ) { -if (ata_msg_probe (ap)) -ata_port_printk (ap,KERN_DEBUG , -"%s: set_taskfiles error (%d)\n" , - __FUNCTION__, ret); +if (ret <0 )break ; - } }return ret;
@@ -377,6 +369,12 @@ int ata_acpi_exec_tfs(struct ata_port *ap)* 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_device *dev) {
@@ -416,12 +414,9 @@ int ata_acpi_push_id(struct ata_device *dev)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 (dev,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:
Signature · 1 line
1.5.0.3
PATCH 7/9 libata: reimplement ACPI invocation
In reply to Tejun HeoThis patch reimplements ACPI invocation such that, instead of exporting ACPI details to the rest of libata, ACPI event handlers - ata_acpi_on_resume() and ata_acpi_on_devcfg() - are used. These two functions are responsible for determining whether specific ACPI method is used and when.
On resume, _GTF is scheduled by setting ATA_DFLAG_ACPI_PENDING device flag. This is done this way to avoid performing the action on wrong device device (device swapping while suspended).
On every ata_dev_configure(), ata_acpi_on_devcfg() is called, which performs _SDD and _GTF. _GTF is performed only after resuming and, if SATA, hardreset as the ACPI spec specifies. As _GTF may contain arbitrary commands, IDENTIFY page is re-read after _GTF taskfiles are executed.
If one of ACPI methods fails, ata_acpi_on_devcfg() retries on the first failure. If it fails again on the second try, ACPI is disabled on the device. Note that successful configuration clears ACPI failed status.
With all feature checks moved to the above two functions, do_drive_set_taskfiles() is trivial and thus collapsed into ata_acpi_exec_tfs(), which is now static and converted to return the number of executed taskfiles to be used by ata_acpi_on_resume(). As failures are handled properly, ata_acpi_push_id() now returns -errno on errors instead of unconditional zero.
--- drivers/ata/libata-acpi.c | 204 +++++++++++++++++++++++++++----------------- drivers/ata/libata-core.c | 16 ++-- drivers/ata/libata-eh.c | 3 + drivers/ata/libata.h | 14 +-- include/linux/libata.h | 2 + 5 files changed, 140 insertions(+), 99 deletions(-)
drivers/ata/libata-acpi.c +125 -79
@@ -273,91 +273,47 @@ static int taskfile_load_raw(struct ata_device *dev, }/** -* ata_dev_set_taskfiles - write the drive taskfile settings from _GTF -* @dev: target ATA device -* @gtf: pointer to array of _GTF taskfiles to execute -* @gtf_count: number of taskfiles -* -* This applies to both PATA and SATA drives. -* -* Execute taskfiles in @gtf. -* -* LOCKING: -* EH context. -* -* RETURNS: -* 0 on success, -errno on failure. -*/ -static int ata_dev_set_taskfiles (struct ata_device *dev, -struct ata_acpi_gtf *gtf,int gtf_count) -{ -struct ata_port *ap = dev->ap; -int ix; - -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG ,"%s: ENTER: port#: %d\n" , - __FUNCTION__, ap->port_no); - -if (!(ap->flags &ATA_FLAG_ACPI_SATA )) -return 0 ; - -if (!ata_dev_enabled (dev) || (ap->flags &ATA_FLAG_DISABLED )) -return -ENODEV ; - -/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ -for (ix =0 ; ix < gtf_count; ix++) -taskfile_load_raw (dev, gtf++); - -return 0 ; -} - -/** * ata_acpi_exec_tfs - get then write drive taskfile settings -* @ap: the ata_port for the drive +* @dev: target ATA device * -* This applies to both PATA and SATA drives. +* Evaluate _GTF and excute returned taskfiles. * * LOCKING: * EH context. * * RETURNS: -* 0 on success, -errno on failure. +* Number of executed taskfiles on success, 0 if _GTF doesn't exist or +* doesn't contain valid data. -errno on other errors. */ -int ata_acpi_exec_tfs (struct ata_port *ap) +static int ata_acpi_exec_tfs (struct ata_device *dev) { -int ix, ret =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->flags &ATA_FLAG_ACPI_SATA )) -return 0 ; - -for (ix =0 ; ix <ATA_MAX_DEVICES ; ix++) { -struct ata_device *dev = &ap->device[ix]; -struct ata_acpi_gtf *gtf =NULL ; -int gtf_count; -void *ptr_to_free =NULL ; - -if (!ata_dev_enabled (dev)) -continue ; - - ret =ata_dev_get_GTF (dev, >f, &ptr_to_free); -if (ret ==0 ) -continue ; -if (ret <0 ) -break ; - gtf_count = ret; - - ret =ata_dev_set_taskfiles (dev, gtf, gtf_count); -kfree (ptr_to_free); -if (ret <0 ) -break ; +struct ata_acpi_gtf *gtf =NULL ; +void *ptr_to_free =NULL ; +int gtf_count, i, rc; + +/* get taskfiles */ + rc =ata_dev_get_GTF (dev, >f, &ptr_to_free); +if (rc <0 ) +return rc; + gtf_count = rc; + +/* execute them */ +for (i =0 , rc =0 ; i < gtf_count; i++) { +int tmp; + +/* ACPI errors are eventually ignored. Run till the +* end even after errors. +*/ + tmp =taskfile_load_raw (dev, gtf++); +if (!rc) + rc = tmp; } -return ret; +kfree (ptr_to_free); + +if (rc ==0 ) +return gtf_count; +return rc; }/**
@@ -376,7 +332,7 @@ int ata_acpi_exec_tfs(struct ata_port *ap)* RETURNS: * 0 on success, -errno on failure. */ -int ata_acpi_push_id (struct ata_device *dev) +static int ata_acpi_push_id (struct ata_device *dev) {struct ata_port *ap = dev->ap;int err;
@@ -396,7 +352,7 @@ int ata_acpi_push_id(struct ata_device *dev)if (ata_msg_probe (ap))ata_dev_printk (dev,KERN_DEBUG ,"%s: Not a SATA device\n" , __FUNCTION__); - goto out; +return 0 ; }/* Give the drive Identify data to the drive via the _SDD method */
@@ -418,9 +374,99 @@ int ata_acpi_push_id(struct ata_device *dev)ata_dev_printk (dev,KERN_WARNING ,"ACPI _SDD failed (AE 0x%x)\n" , status); -/* always return success */ -out: -return 0 ; +return err; +} + +/** +* 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) +{ +int i; + +/* schedule _GTF */ +for (i =0 ; i <ATA_MAX_DEVICES ; i++) + ap->device[i].flags |=ATA_DFLAG_ACPI_PENDING ; } +/** +* 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->ap; +struct ata_eh_context *ehc = &ap->eh_context; +int acpi_sata = ap->flags &ATA_FLAG_ACPI_SATA ; +int rc; + +/* XXX: _STM isn't implemented yet, skip if IDE for now */ +if (!acpi_sata) +return 0 ; +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); +if (rc <0 ) + goto acpi_err; + + dev->flags &= ~ATA_DFLAG_ACPI_PENDING ; + +/* refresh IDENTIFY page if any _GTF command has been executed */ +if (rc >0 ) { + 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: +/* let EH retry on the first failure, disable ACPI on the second */ +if (dev->flags &ATA_DFLAG_ACPI_FAILED ) { +ata_dev_printk (dev,KERN_WARNING ,"ACPI on devcfg failed the " +"second time, disabling (errno=%d)\n" , rc); + + dev->acpi_handle =NULL ; + +/* if port is working, request IDENTIFY reload and continue */ +if (!(ap->pflags &ATA_PFLAG_FROZEN )) + rc =1 ; + } + dev->flags |=ATA_DFLAG_ACPI_FAILED ; +return rc; +}
drivers/ata/libata-core.c +6 -10
@@ -1851,7 +1851,8 @@ static void ata_dev_config_ncq(struct ata_device *dev,int ata_dev_configure (struct ata_device *dev) {struct ata_port *ap = dev->ap; -int print_info = ap->eh_context.i.flags &ATA_EHI_PRINTINFO ; +struct ata_eh_context *ehc = &ap->eh_context; +int print_info = ehc->i.flags &ATA_EHI_PRINTINFO ;const u16 *id = dev->id;unsigned int xfer_mask;char revbuf[7 ];/* XYZ-99\0 */
@@ -1868,15 +1869,10 @@ int ata_dev_configure(struct ata_device *dev)if (ata_msg_probe (ap))ata_dev_printk (dev,KERN_DEBUG ,"%s: ENTER\n" , __FUNCTION__); -/* set _SDD */ - rc =ata_acpi_push_id (dev); -if (rc) { -ata_dev_printk (dev,KERN_WARNING ,"failed to set _SDD(%d)\n" , - rc); - } - -/* retrieve and execute the ATA task file of _GTF */ -ata_acpi_exec_tfs (ap); +/* let ACPI work its magic */ + rc =ata_acpi_on_devcfg (dev); +if (rc) +return rc;/* print device capabilities */ if (ata_msg_probe (ap))
drivers/ata/libata-eh.c +3 -0
@@ -2210,6 +2210,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)if (ap->ops->port_resume) rc = ap->ops->port_resume (ap); +/* tell ACPI that we're resuming */ +ata_acpi_on_resume (ap); +/* report result */ spin_lock_irqsave (ap->lock, flags); ap->pflags &= ~(ATA_PFLAG_PM_PENDING |ATA_PFLAG_SUSPENDED );
drivers/ata/libata.h +4 -10
@@ -100,18 +100,12 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);/* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI extern void ata_acpi_associate (struct ata_host *host); -extern int ata_acpi_exec_tfs (struct ata_port *ap); -extern int ata_acpi_push_id (struct ata_device *dev); +extern void ata_acpi_on_resume (struct ata_port *ap); +extern int ata_acpi_on_devcfg (struct ata_device *adev);#else static inline void ata_acpi_associate (struct ata_host *host) { } -static inline int ata_acpi_exec_tfs (struct ata_port *ap) -{ -return 0 ; -} -static inline int ata_acpi_push_id (struct ata_device *dev) -{ -return 0 ; -} +static inline void ata_acpi_on_resume (struct ata_port *ap) { } +static inline int ata_acpi_on_devcfg (struct ata_device *adev) {return 0 ; }#endif /* libata-scsi.c */
include/linux/libata.h +2 -0
@@ -136,6 +136,8 @@ enum {ATA_DFLAG_CDB_INTR = (1 <<2 ),/* device asserts INTRQ when ready for CDB */ ATA_DFLAG_NCQ = (1 <<3 ),/* device supports NCQ */ ATA_DFLAG_FLUSH_EXT = (1 <<4 ),/* do FLUSH_EXT instead of FLUSH */ +ATA_DFLAG_ACPI_PENDING = (1 <<5 ),/* ACPI resume action pending */ +ATA_DFLAG_ACPI_FAILED = (1 <<6 ),/* ACPI on devcfg has failed */ ATA_DFLAG_CFG_MASK = (1 <<8 ) -1 , ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
Signature · 1 line
1.5.0.3
PATCH 8/9 libata-acpi: remove redundant checks
In reply to Tejun HeoRemove remaining unnecessary feature and status checks.
--- drivers/ata/libata-acpi.c | 23 ----------------------- 1 files changed, 0 insertions(+), 23 deletions(-)
drivers/ata/libata-acpi.c +0 -23
@@ -134,22 +134,10 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, output.length =ACPI_ALLOCATE_BUFFER ; output.pointer =NULL ;/* ACPI-CA sets this; save/free it later */ -if (!dev->acpi_handle) - goto out_free; -if (ata_msg_probe (ap))ata_dev_printk (dev,KERN_DEBUG ,"%s: ENTER: port#: %d\n" , __FUNCTION__, ap->port_no); -if (!ata_dev_enabled (dev) || (ap->flags &ATA_FLAG_DISABLED )) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG ,"%s: ERR: " -"ata_dev_present: %d, PORT_DISABLED: %lu\n" , - __FUNCTION__,ata_dev_enabled (dev), - ap->flags &ATA_FLAG_DISABLED ); - goto out_free; - } -/* _GTF has no input parameters */ status =acpi_evaluate_object (dev->acpi_handle,"_GTF" ,NULL , &output);
@@ -340,21 +328,10 @@ static int ata_acpi_push_id(struct ata_device *dev)struct acpi_object_list input;union acpi_object in_params[1 ]; -if (!dev->acpi_handle) -return 0 ; -if (ata_msg_probe (ap))ata_dev_printk (dev,KERN_DEBUG ,"%s: ix = %d, port#: %d\n" , __FUNCTION__, dev->devno, ap->port_no); -/* Don't continue if not a SATA device. */ -if (!(ap->flags &ATA_FLAG_ACPI_SATA )) { -if (ata_msg_probe (ap)) -ata_dev_printk (dev,KERN_DEBUG , -"%s: Not a SATA device\n" , __FUNCTION__); -return 0 ; - } -/* Give the drive Identify data to the drive via the _SDD method */ /* _SDD: set up input parameters */ input.count =1 ;
Signature · 1 line
1.5.0.3
PATCH 9/9 libata-acpi: implement _GTM/_STM support
In reply to Tejun HeoImplement _GTM/_STM support. acpi_gtm is added to ata_port which stores _GTM parameters over suspend/resume cycle. A new hook ata_acpi_on_suspend() is responsible for storing _GTM parameters during suspend. _STM is executed in ata_acpi_on_resume(). With this change, invoking _GTF is safe on IDE hierarchy and acpi_sata check before _GTF is removed.
ata_acpi_gtm() and ata_acpi_stm() implementation is taken from Alan Cox's pata_acpi implementation. ata_acpi_gtm() is fixed such that the result parameter is not shifted by sizeof(union acpi_object).
--- drivers/ata/libata-acpi.c | 153 +++++++++++++++++++++++++++++++++++++++++++- drivers/ata/libata-eh.c | 8 ++- drivers/ata/libata.h | 2 + include/linux/libata.h | 13 ++++ 4 files changed, 171 insertions(+), 5 deletions(-)
drivers/ata/libata-acpi.c +149 -4
@@ -101,6 +101,108 @@ void ata_acpi_associate(struct ata_host *host) }/** +* 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. +*/ +static int ata_acpi_gtm (const struct ata_port *ap,struct ata_acpi_gtm *gtm) +{ +struct acpi_buffer output = { .length =ACPI_ALLOCATE_BUFFER }; +union acpi_object *out_obj; +acpi_status status; +int rc =0 ; + + 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; + } + + 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; + } + +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; +} + +/** +* 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. +*/ +static int ata_acpi_stm (const struct ata_port *ap,struct ata_acpi_gtm *stm) +{ +acpi_status status; +struct acpi_object_list input; +union acpi_object in_params[3 ]; + + in_params[0 ].type =ACPI_TYPE_BUFFER ; + in_params[0 ].buffer.length =sizeof (struct ata_acpi_gtm ); + in_params[0 ].buffer.pointer = (u8 *)stm; +/* 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->device[0 ].id; + in_params[2 ].type =ACPI_TYPE_BUFFER ; + in_params[2 ].buffer.length =512 ; + in_params[2 ].buffer.pointer = (u8 *)ap->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)) { +ata_port_printk (ap,KERN_ERR , +"ACPI set timing mode failed (status=0x%x)\n" , status); +return -EINVAL ; + } +return 0 ; +} + +/** * ata_dev_get_GTF - get the drive bootup default taskfile settings * @dev: target ATA device * @gtf: output parameter for buffer containing _GTF taskfile arrays
@@ -355,6 +457,46 @@ static int ata_acpi_push_id(struct ata_device *dev) }/** +* 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) +{ +unsigned long flags; +int rc; + +/* proceed iff per-port acpi_handle is valid */ +if (!ap->acpi_handle) +return 0 ; +BUG_ON (ap->flags &ATA_FLAG_ACPI_SATA ); + +/* store timing parameters */ + rc =ata_acpi_gtm (ap, &ap->acpi_gtm); + +spin_lock_irqsave (ap->lock, flags); +if (rc ==0 ) + ap->pflags |=ATA_PFLAG_GTM_VALID ; +else + ap->pflags &= ~ATA_PFLAG_GTM_VALID ; +spin_unlock_irqrestore (ap->lock, flags); + +if (rc == -ENOENT ) + rc =0 ; +return rc; +} + +/** * ata_acpi_on_resume - ATA ACPI hook called on resume * @ap: target ATA port *
@@ -368,6 +510,13 @@ void ata_acpi_on_resume(struct ata_port *ap) {int i; +if (ap->acpi_handle && (ap->pflags &ATA_PFLAG_GTM_VALID )) { +BUG_ON (ap->flags &ATA_FLAG_ACPI_SATA ); + +/* restore timing parameters */ +ata_acpi_stm (ap, &ap->acpi_gtm); + } +/* schedule _GTF */ for (i =0 ; i <ATA_MAX_DEVICES ; i++) ap->device[i].flags |=ATA_DFLAG_ACPI_PENDING ;
@@ -394,10 +543,6 @@ int ata_acpi_on_devcfg(struct ata_device *dev)int acpi_sata = ap->flags &ATA_FLAG_ACPI_SATA ;int rc; -/* XXX: _STM isn't implemented yet, skip if IDE for now */ -if (!acpi_sata) -return 0 ; -if (!dev->acpi_handle)return 0 ;
drivers/ata/libata-eh.c +7 -1
@@ -2157,19 +2157,25 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)WARN_ON (ap->pflags &ATA_PFLAG_SUSPENDED ); +/* tell ACPI we're suspending */ + rc =ata_acpi_on_suspend (ap); +if (rc) + goto out; +/* suspend */ ata_eh_freeze_port (ap);if (ap->ops->port_suspend) rc = ap->ops->port_suspend (ap, ap->pm_mesg); + out:/* report result */ spin_lock_irqsave (ap->lock, flags); ap->pflags &= ~ATA_PFLAG_PM_PENDING ;if (rc ==0 ) ap->pflags |=ATA_PFLAG_SUSPENDED ; -else +else if (ap->pflags &ATA_PFLAG_FROZEN )ata_port_schedule_eh (ap);if (ap->pm_result) {
drivers/ata/libata.h +2 -0
@@ -100,10 +100,12 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);/* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI extern void ata_acpi_associate (struct ata_host *host); +extern int ata_acpi_on_suspend (struct ata_port *ap);extern void ata_acpi_on_resume (struct ata_port *ap);extern int ata_acpi_on_devcfg (struct ata_device *adev);#else static inline void ata_acpi_associate (struct ata_host *host) { } +static inline int ata_acpi_on_suspend (struct ata_port *ap) {return 0 ; }static inline void ata_acpi_on_resume (struct ata_port *ap) { }static inline int ata_acpi_on_devcfg (struct ata_device *adev) {return 0 ; }#endif
include/linux/libata.h +13 -0
@@ -198,6 +198,7 @@ enum {ATA_PFLAG_FLUSH_PORT_TASK = (1 <<16 ),/* flush port task */ ATA_PFLAG_SUSPENDED = (1 <<17 ),/* port is suspended (power) */ ATA_PFLAG_PM_PENDING = (1 <<18 ),/* PM operation pending */ +ATA_PFLAG_GTM_VALID = (1 <<19 ),/* acpi_gtm data valid */ /* struct ata_queued_cmd flags */ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
@@ -494,6 +495,17 @@ struct ata_eh_context {unsigned int did_probe_mask; }; +struct ata_acpi_drive +{ +u32 pio; +u32 dma; +} __packed; + +struct ata_acpi_gtm { +struct ata_acpi_drive drive[2 ]; +u32 flags; +} __packed; +struct ata_port {struct Scsi_Host *scsi_host;/* our co-allocated scsi host */ const struct ata_port_operations *ops;
@@ -556,6 +568,7 @@ struct ata_port {#ifdef CONFIG_ATA_ACPI acpi_handle acpi_handle; +struct ata_acpi_gtm acpi_gtm;#endif u8 sector_buf[ATA_SECT_SIZE ];/* owned by EH */ };
Signature · 1 line
1.5.0.3
Quoted 5 lines · On Tue, 15 May 2007 03:28:15 +0900 Tejun Heo <[email protected]> wrote:
Hello,
This is the third take of improve-ata-acpi. Except for regeneration to fit the current libata-dev#upstream[U], there's no change from the last take[L].
Looks good to me within the constraints of the actual hardware and ACPI "design".
Alan
Re: [PATCH 1/9] libata: separate out ata_dev_reread_id()
In reply to Tejun HeoQuoted 10 lines · Tejun Heo
Separate out
ata_dev_reread_id()fromata_dev_revalidate().ata_dev_reread_id()reads IDENTIFY page and determines whether the same device is still there.ata_dev_revalidate()reconfigures after reread completes. This will be used by ACPI update.Signed-off-by Tejun Heo <[email protected]>--- drivers/ata/libata-core.c | 47 ++++++++++++++++++++++++++++++++------------ drivers/ata/libata.h | 3 +- 2 files changed, 36 insertions(+), 14 deletions(-)
applied 1-3 to #upstream-fixes
Re: [PATCH 4/9] libata-acpi: implement ata_acpi_associate()
In reply to Tejun HeoQuoted 13 lines · Tejun Heo
* Add
acpi_handletoata_hostandata_port. Renameata_device->obj_handleto ->acpi_handle and move it above such that it doesn't get cleared on reconfiguration.* Replace ACPI node association which
ata_acpi_associate()which is called once during host initialization. Unlike the previous implementation,ata_acpi_associate()usesATA_FLAG_ACPI_SATAto choose between IDE or SATA ACPI hierarchy and uses simple child look up instead of recursive walk to match the nodes. This is way safer and simpler. Please read the following message for more info.
Quoted 7 lines
Signed-off-by Tejun Heo <[email protected]>--- drivers/ata/libata-acpi.c | 369 ++++++--------------------------------------- drivers/ata/libata-core.c | 3 + drivers/ata/libata.h | 2 + include/linux/libata.h | 13 +- 4 files changed, 63 insertions(+), 324 deletions(-)
applied 4-9 to #upstream