diff options
author | Tejun Heo <htejun@gmail.com> | 2007-12-15 15:05:05 +0900 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-12-17 20:33:15 -0500 |
commit | 0e8634bf8e48e50aa96c7e7becafcf9d98c1a28d (patch) | |
tree | b49e1130fe721d4be4530c5a458b9e39199b4696 /drivers | |
parent | 66fa7f2158e84530aa4a1839a3500d6bdb231301 (diff) | |
download | linux-0e8634bf8e48e50aa96c7e7becafcf9d98c1a28d.tar.bz2 |
libata-acpi: improve _GTF execution error handling and reporting
As _GTF commands can't transfer data, device error never signals
transfer error. It indicates that the device vetoed the operation, so
it's meaningless to retry.
This patch makes libata-acpi to report and continue on device errors
when executing _GTF commands. Also commands rejected by device don't
contribute to the number of _GTF commands executed.
While at it, update _GTF execution reporting such that all successful
commands are logged at KERN_DEBUG and rename taskfile_load_raw() to
ata_acpi_run_tf() for consistency.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/libata-acpi.c | 77 |
1 files changed, 46 insertions, 31 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 5932ae24ddc1..d4cb557a727d 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -466,7 +466,7 @@ int ata_acpi_cbl_80wire(struct ata_port *ap) EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); /** - * taskfile_load_raw - send taskfile registers to host controller + * ata_acpi_run_tf - send taskfile registers to host controller * @dev: target ATA device * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) * @@ -485,14 +485,17 @@ EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); * EH context. * * RETURNS: - * 0 on success, -errno on failure. + * 1 if command is executed successfully. 0 if ignored or rejected, + * -errno on other errors. */ -static int taskfile_load_raw(struct ata_device *dev, - const struct ata_acpi_gtf *gtf) +static int ata_acpi_run_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf) { - struct ata_port *ap = dev->link->ap; struct ata_taskfile tf, 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) @@ -512,24 +515,39 @@ static int taskfile_load_raw(struct ata_device *dev, 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, 0); - if (err_mask) { - ata_dev_printk(dev, KERN_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; + + 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; } - return 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); + + return rc; } /** @@ -558,22 +576,19 @@ static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed) 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; - - (*nr_executed)++; + for (i = 0; i < gtf_count; i++) { + rc = ata_acpi_run_tf(dev, gtf++); + if (rc < 0) + break; + if (rc) + (*nr_executed)++; } ata_acpi_clear_gtf(dev); - return rc; + if (rc < 0) + return rc; + return 0; } /** |