diff options
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r-- | drivers/ata/libata-acpi.c | 96 |
1 files changed, 96 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) | |||
600 | return ret; | 600 | return ret; |
601 | } | 601 | } |
602 | 602 | ||
603 | /** | ||
604 | * ata_acpi_push_id - send Identify data to drive | ||
605 | * @ap: the ata_port for the drive | ||
606 | * @ix: drive index | ||
607 | * | ||
608 | * _SDD ACPI object: for SATA mode only | ||
609 | * Must be after Identify (Packet) Device -- uses its data | ||
610 | * ATM this function never returns a failure. It is an optional | ||
611 | * method and if it fails for whatever reason, we should still | ||
612 | * just keep going. | ||
613 | */ | ||
614 | int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) | ||
615 | { | ||
616 | acpi_handle handle; | ||
617 | acpi_integer pcidevfn; | ||
618 | int err; | ||
619 | struct device *dev = ap->host->dev; | ||
620 | struct ata_device *atadev = &ap->device[ix]; | ||
621 | u32 dev_adr; | ||
622 | acpi_status status; | ||
623 | struct acpi_object_list input; | ||
624 | union acpi_object in_params[1]; | ||
625 | |||
626 | if (noacpi) | ||
627 | return 0; | ||
628 | |||
629 | if (ata_msg_probe(ap)) | ||
630 | ata_dev_printk(atadev, KERN_DEBUG, | ||
631 | "%s: ap->id: %d, ix = %d, port#: %d\n", | ||
632 | __FUNCTION__, ap->id, ix, ap->port_no); | ||
633 | |||
634 | /* Don't continue if not a SATA device. */ | ||
635 | if (!(ap->cbl == ATA_CBL_SATA)) { | ||
636 | if (ata_msg_probe(ap)) | ||
637 | ata_dev_printk(atadev, KERN_DEBUG, | ||
638 | "%s: Not a SATA device\n", __FUNCTION__); | ||
639 | goto out; | ||
640 | } | ||
641 | |||
642 | /* Don't continue if device has no _ADR method. | ||
643 | * _SDD is intended for known motherboard devices. */ | ||
644 | err = sata_get_dev_handle(dev, &handle, &pcidevfn); | ||
645 | if (err < 0) { | ||
646 | if (ata_msg_probe(ap)) | ||
647 | ata_dev_printk(atadev, KERN_DEBUG, | ||
648 | "%s: sata_get_dev_handle failed (%d\n", | ||
649 | __FUNCTION__, err); | ||
650 | goto out; | ||
651 | } | ||
652 | |||
653 | /* Get this drive's _ADR info, if not already known */ | ||
654 | if (!atadev->obj_handle) { | ||
655 | dev_adr = SATA_ADR_RSVD; | ||
656 | err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev, | ||
657 | &dev_adr); | ||
658 | if (err < 0 || dev_adr == SATA_ADR_RSVD || | ||
659 | !atadev->obj_handle) { | ||
660 | if (ata_msg_probe(ap)) | ||
661 | ata_dev_printk(atadev, KERN_DEBUG, | ||
662 | "%s: get_sata_adr failed: " | ||
663 | "err=%d, dev_adr=%u, obj_handle=0x%p\n", | ||
664 | __FUNCTION__, err, dev_adr, | ||
665 | atadev->obj_handle); | ||
666 | goto out; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | /* Give the drive Identify data to the drive via the _SDD method */ | ||
671 | /* _SDD: set up input parameters */ | ||
672 | input.count = 1; | ||
673 | input.pointer = in_params; | ||
674 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
675 | in_params[0].buffer.length = sizeof(atadev->id[0] * ATA_ID_WORDS); | ||
676 | in_params[0].buffer.pointer = (u8 *)atadev->id; | ||
677 | /* Output buffer: _SDD has no output */ | ||
678 | |||
679 | /* It's OK for _SDD to be missing too. */ | ||
680 | swap_buf_le16(atadev->id, ATA_ID_WORDS); | ||
681 | status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL); | ||
682 | swap_buf_le16(atadev->id, ATA_ID_WORDS); | ||
683 | |||
684 | err = ACPI_FAILURE(status) ? -EIO : 0; | ||
685 | if (err < 0) { | ||
686 | if (ata_msg_probe(ap)) | ||
687 | ata_dev_printk(atadev, KERN_DEBUG, | ||
688 | "ata%u(%u): %s _SDD error: status = 0x%x\n", | ||
689 | ap->id, ap->device->devno, | ||
690 | __FUNCTION__, status); | ||
691 | } | ||
692 | |||
693 | /* always return success */ | ||
694 | out: | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | |||