1 implement ata_acpi_push_id(), which is used to set _SDD 2 invoke ata_acpi_push_id() in ata_dev_configure() Signed-off-by: Zhao Forrest <forrest.zhao@xxxxxxxxx> --- drivers/scsi/libata-acpi.c | 97 ++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libata-core.c | 8 ++++ drivers/scsi/libata.h | 5 ++ 3 files changed, 110 insertions(+), 0 deletions(-) a52b4e04c0b9467f0993ed4c367fcd575e6a936f diff --git a/drivers/scsi/libata-acpi.c b/drivers/scsi/libata-acpi.c index cf7eeb1..d0b7c44 100644 --- a/drivers/scsi/libata-acpi.c +++ b/drivers/scsi/libata-acpi.c @@ -652,3 +652,100 @@ int ata_acpi_exec_tfs(struct ata_port *a } EXPORT_SYMBOL_GPL(ata_acpi_exec_tfs); +/** + * ata_acpi_push_id - send Identify data to a 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. + */ +int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + acpi_handle handle; + acpi_integer pcidevfn; + int err = -ENODEV; + struct device *dev = ap->host_set->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 (!(ap->flags & ATA_FLAG_SATA)) { + printk(KERN_DEBUG "%s: skipping for PATA mode\n", + __FUNCTION__); + return 0; + } + + if (ata_msg_probe(ap)) + printk(KERN_DEBUG + "%s: ap->id: %d, ix = %d, port#: %d, hard_port#: %d\n", + __FUNCTION__, ap->id, ix, + ap->port_no, ap->hard_port_no); + + /* Don't continue if not a SATA device. */ + if (!ata_id_is_sata(atadev->id)) { + if (ata_msg_probe(ap)) + printk(KERN_DEBUG "%s: ata_id_is_sata is False\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)) + printk(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)) + printk(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); + 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)) + printk(KERN_DEBUG + "ata%u(%u): %s _SDD error: status = 0x%x\n", + ap->id, ap->device->devno, + __FUNCTION__, status); + } +out: + return err; +} +EXPORT_SYMBOL_GPL(ata_acpi_push_id); + diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index cd4cf97..1c60369 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1505,6 +1505,14 @@ int ata_dev_configure(struct ata_device 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/scsi/libata.h b/drivers/scsi/libata.h index d9743e0..62bb568 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -123,6 +123,7 @@ extern int do_drive_get_GTF(struct ata_p extern int do_drive_set_taskfiles(struct ata_port *ap, struct ata_device *atadev, unsigned int gtf_length, unsigned long gtf_address); 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 do_drive_get_GTF(struct ata_port *ap, int ix, unsigned int *gtf_length, unsigned long *gtf_address, @@ -140,6 +141,10 @@ static inline int ata_acpi_exec_tfs(stru { return 0; } +static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + return 0; +} #endif #endif /* __LIBATA_H__ */ -- 1.2.6 - : send the line "unsubscribe linux-ide" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html