libata-acpi: improve ACPI disabling

* If _GTF evalution fails, it's pointless to retry.  If nothing else
  is wrong, just ignore the error.

* After disabling ACPI, return success iff the number of executed _GTF
  command equals zero.  Otherwise, tell EH to retry.  This change
  fixes bogus 1 return bug where ata_acpi_on_devcfg() expects the
  caller to reload IDENTIFY data and continue but the caller
  interprets it as an error.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Tejun Heo 2007-12-15 15:05:04 +09:00 committed by Jeff Garzik
parent 398e07826b
commit 66fa7f2158

View File

@ -346,8 +346,8 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm);
* EH context. * EH context.
* *
* RETURNS: * RETURNS:
* Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't * Number of taskfiles on success, 0 if _GTF doesn't exist. -EINVAL
* contain valid data. * if _GTF is invalid.
*/ */
static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
{ {
@ -380,6 +380,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
ata_dev_printk(dev, KERN_WARNING, ata_dev_printk(dev, KERN_WARNING,
"_GTF evaluation failed (AE 0x%x)\n", "_GTF evaluation failed (AE 0x%x)\n",
status); status);
rc = -EINVAL;
} }
goto out_free; goto out_free;
} }
@ -391,6 +392,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
__FUNCTION__, __FUNCTION__,
(unsigned long long)output.length, (unsigned long long)output.length,
output.pointer); output.pointer);
rc = -EINVAL;
goto out_free; goto out_free;
} }
@ -398,6 +400,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
ata_dev_printk(dev, KERN_WARNING, ata_dev_printk(dev, KERN_WARNING,
"_GTF unexpected object type 0x%x\n", "_GTF unexpected object type 0x%x\n",
out_obj->type); out_obj->type);
rc = -EINVAL;
goto out_free; goto out_free;
} }
@ -405,6 +408,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
ata_dev_printk(dev, KERN_WARNING, ata_dev_printk(dev, KERN_WARNING,
"unexpected _GTF length (%d)\n", "unexpected _GTF length (%d)\n",
out_obj->buffer.length); out_obj->buffer.length);
rc = -EINVAL;
goto out_free; goto out_free;
} }
@ -531,6 +535,7 @@ static int taskfile_load_raw(struct ata_device *dev,
/** /**
* ata_acpi_exec_tfs - get then write drive taskfile settings * ata_acpi_exec_tfs - get then write drive taskfile settings
* @dev: target ATA device * @dev: target ATA device
* @nr_executed: out paramter for the number of executed commands
* *
* Evaluate _GTF and excute returned taskfiles. * Evaluate _GTF and excute returned taskfiles.
* *
@ -538,16 +543,19 @@ static int taskfile_load_raw(struct ata_device *dev,
* EH context. * EH context.
* *
* RETURNS: * RETURNS:
* Number of executed taskfiles on success, 0 if _GTF doesn't exist or * Number of executed taskfiles on success, 0 if _GTF doesn't exist.
* doesn't contain valid data. -errno on other errors. * -errno on other errors.
*/ */
static int ata_acpi_exec_tfs(struct ata_device *dev) static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed)
{ {
struct ata_acpi_gtf *gtf = NULL; struct ata_acpi_gtf *gtf = NULL;
int gtf_count, i, rc; int gtf_count, i, rc;
/* get taskfiles */ /* get taskfiles */
gtf_count = ata_dev_get_GTF(dev, &gtf); rc = ata_dev_get_GTF(dev, &gtf);
if (rc < 0)
return rc;
gtf_count = rc;
/* execute them */ /* execute them */
for (i = 0, rc = 0; i < gtf_count; i++) { for (i = 0, rc = 0; i < gtf_count; i++) {
@ -559,12 +567,12 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
tmp = taskfile_load_raw(dev, gtf++); tmp = taskfile_load_raw(dev, gtf++);
if (!rc) if (!rc)
rc = tmp; rc = tmp;
(*nr_executed)++;
} }
ata_acpi_clear_gtf(dev); ata_acpi_clear_gtf(dev);
if (rc == 0)
return gtf_count;
return rc; return rc;
} }
@ -700,6 +708,7 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
struct ata_port *ap = dev->link->ap; struct ata_port *ap = dev->link->ap;
struct ata_eh_context *ehc = &ap->link.eh_context; struct ata_eh_context *ehc = &ap->link.eh_context;
int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
int nr_executed = 0;
int rc; int rc;
if (!dev->acpi_handle) if (!dev->acpi_handle)
@ -718,14 +727,14 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
} }
/* do _GTF */ /* do _GTF */
rc = ata_acpi_exec_tfs(dev); rc = ata_acpi_exec_tfs(dev, &nr_executed);
if (rc < 0) if (rc)
goto acpi_err; goto acpi_err;
dev->flags &= ~ATA_DFLAG_ACPI_PENDING; dev->flags &= ~ATA_DFLAG_ACPI_PENDING;
/* refresh IDENTIFY page if any _GTF command has been executed */ /* refresh IDENTIFY page if any _GTF command has been executed */
if (rc > 0) { if (nr_executed) {
rc = ata_dev_reread_id(dev, 0); rc = ata_dev_reread_id(dev, 0);
if (rc < 0) { if (rc < 0) {
ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY "
@ -737,18 +746,26 @@ int ata_acpi_on_devcfg(struct ata_device *dev)
return 0; return 0;
acpi_err: acpi_err:
/* let EH retry on the first failure, disable ACPI on the second */ /* ignore evaluation failure if we can continue safely */
if (dev->flags & ATA_DFLAG_ACPI_FAILED) { if (rc == -EINVAL && !nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN))
ata_dev_printk(dev, KERN_WARNING, "ACPI on devcfg failed the " return 0;
"second time, disabling (errno=%d)\n", rc);
dev->acpi_handle = NULL; /* fail and let EH retry once more for unknown IO errors */
if (!(dev->flags & ATA_DFLAG_ACPI_FAILED)) {
/* if port is working, request IDENTIFY reload and continue */ dev->flags |= ATA_DFLAG_ACPI_FAILED;
if (!(ap->pflags & ATA_PFLAG_FROZEN)) return rc;
rc = 1;
} }
dev->flags |= ATA_DFLAG_ACPI_FAILED;
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; return rc;
} }