summaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorKristen Carlson Accardi <kristen.c.accardi@intel.com>2006-09-28 11:29:12 -0700
committerJeff Garzik <jeff@garzik.org>2007-02-16 13:32:41 -0500
commit7ea1fbc2a2449bc034a3d255f36f2e5486d52fe8 (patch)
treeefa06ba55094924f27e7598b393a46b8c2753ec0 /drivers/ata
parent11ef697b37e3c85ce1ac21f7711babf1f5b12784 (diff)
downloadlinux-7ea1fbc2a2449bc034a3d255f36f2e5486d52fe8.tar.gz
linux-7ea1fbc2a2449bc034a3d255f36f2e5486d52fe8.tar.bz2
linux-7ea1fbc2a2449bc034a3d255f36f2e5486d52fe8.zip
[PATCH] libata: ACPI _SDD support
_SDD (Set Device Data) is an ACPI method that is used to tell the firmware what the identify data is of the device that is attached to the port. It is an optional method, and it's ok for it to be missing. Because of this, we always return success from the routine that calls this method, even if the execution fails. Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Jeff Garzik <jeff@garzik.org> (cherry picked from 39aa79e0a1f5f2e28aa341f035940746a98b45b1 commit)
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-acpi.c96
-rw-r--r--drivers/ata/libata-core.c8
-rw-r--r--drivers/ata/libata.h5
3 files changed, 109 insertions, 0 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 7b740fe1721b..f2fd0dda70f2 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -600,3 +600,99 @@ int ata_acpi_exec_tfs(struct ata_port *ap)
return ret;
}
+/**
+ * ata_acpi_push_id - send Identify data to drive
+ * @ap: the ata_port for the drive
+ * @ix: drive index
+ *
+ * _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.
+ */
+int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
+{
+ 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;
+
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: ap->id: %d, ix = %d, port#: %d\n",
+ __FUNCTION__, ap->id, 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;
+ }
+ }
+
+ /* 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;
+ /* 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);
+
+ err = ACPI_FAILURE(status) ? -EIO : 0;
+ if (err < 0) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "ata%u(%u): %s _SDD error: status = 0x%x\n",
+ ap->id, ap->device->devno,
+ __FUNCTION__, status);
+ }
+
+ /* always return success */
+out:
+ return 0;
+}
+
+
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 785bf50488e9..90081e5ea80e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1737,6 +1737,14 @@ int ata_dev_configure(struct ata_device *dev)
if (ap->ops->dev_config)
ap->ops->dev_config(ap, dev);
+ /* set _SDD */
+ rc = ata_acpi_push_id(ap, dev->devno);
+ if (rc) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n",
+ rc);
+ goto err_out_nosup;
+ }
+
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
__FUNCTION__, ata_chk_status(ap));
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ea02903e8503..0ad7781d72a3 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -91,11 +91,16 @@ extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
/* libata-acpi.c */
#ifdef CONFIG_SATA_ACPI
extern int ata_acpi_exec_tfs(struct ata_port *ap);
+extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix);
#else
static inline int ata_acpi_exec_tfs(struct ata_port *ap)
{
return 0;
}
+static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
+{
+ return 0;
+}
#endif
/* libata-scsi.c */