diff options
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r-- | drivers/ata/libata-acpi.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index bb7c5f1085cc..b3025a7d71e3 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -47,6 +47,39 @@ static void ata_acpi_clear_gtf(struct ata_device *dev) | |||
47 | dev->gtf_cache = NULL; | 47 | dev->gtf_cache = NULL; |
48 | } | 48 | } |
49 | 49 | ||
50 | static acpi_handle ap_acpi_handle(struct ata_port *ap) | ||
51 | { | ||
52 | if (ap->flags & ATA_FLAG_ACPI_SATA) | ||
53 | return NULL; | ||
54 | |||
55 | /* | ||
56 | * If acpi bind operation has already happened, we can get the handle | ||
57 | * for the port by checking the corresponding scsi_host device's | ||
58 | * firmware node, otherwise we will need to find out the handle from | ||
59 | * its parent's acpi node. | ||
60 | */ | ||
61 | if (ap->scsi_host) | ||
62 | return DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev); | ||
63 | else | ||
64 | return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), | ||
65 | ap->port_no); | ||
66 | } | ||
67 | |||
68 | static acpi_handle dev_acpi_handle(struct ata_device *dev) | ||
69 | { | ||
70 | acpi_integer adr; | ||
71 | struct ata_port *ap = dev->link->ap; | ||
72 | |||
73 | if (ap->flags & ATA_FLAG_ACPI_SATA) { | ||
74 | if (!sata_pmp_attached(ap)) | ||
75 | adr = SATA_ADR(ap->port_no, NO_PORT_MULT); | ||
76 | else | ||
77 | adr = SATA_ADR(ap->port_no, dev->link->pmp); | ||
78 | return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), adr); | ||
79 | } else | ||
80 | return acpi_get_child(ap_acpi_handle(ap), dev->devno); | ||
81 | } | ||
82 | |||
50 | /** | 83 | /** |
51 | * ata_acpi_associate_sata_port - associate SATA port with ACPI objects | 84 | * ata_acpi_associate_sata_port - associate SATA port with ACPI objects |
52 | * @ap: target SATA port | 85 | * @ap: target SATA port |
@@ -1018,3 +1051,107 @@ void ata_acpi_on_disable(struct ata_device *dev) | |||
1018 | { | 1051 | { |
1019 | ata_acpi_clear_gtf(dev); | 1052 | ata_acpi_clear_gtf(dev); |
1020 | } | 1053 | } |
1054 | |||
1055 | static int compat_pci_ata(struct ata_port *ap) | ||
1056 | { | ||
1057 | struct device *dev = ap->tdev.parent; | ||
1058 | struct pci_dev *pdev; | ||
1059 | |||
1060 | if (!is_pci_dev(dev)) | ||
1061 | return 0; | ||
1062 | |||
1063 | pdev = to_pci_dev(dev); | ||
1064 | |||
1065 | if ((pdev->class >> 8) != PCI_CLASS_STORAGE_SATA && | ||
1066 | (pdev->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
1067 | return 0; | ||
1068 | |||
1069 | return 1; | ||
1070 | } | ||
1071 | |||
1072 | static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle) | ||
1073 | { | ||
1074 | if (ap->flags & ATA_FLAG_ACPI_SATA) | ||
1075 | return -ENODEV; | ||
1076 | |||
1077 | *handle = acpi_get_child(DEVICE_ACPI_HANDLE(ap->tdev.parent), | ||
1078 | ap->port_no); | ||
1079 | |||
1080 | if (!*handle) | ||
1081 | return -ENODEV; | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, | ||
1087 | acpi_handle *handle) | ||
1088 | { | ||
1089 | struct ata_device *ata_dev; | ||
1090 | |||
1091 | if (ap->flags & ATA_FLAG_ACPI_SATA) | ||
1092 | ata_dev = &ap->link.device[sdev->channel]; | ||
1093 | else | ||
1094 | ata_dev = &ap->link.device[sdev->id]; | ||
1095 | |||
1096 | *handle = dev_acpi_handle(ata_dev); | ||
1097 | |||
1098 | if (!*handle) | ||
1099 | return -ENODEV; | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static int is_ata_port(const struct device *dev) | ||
1105 | { | ||
1106 | return dev->type == &ata_port_type; | ||
1107 | } | ||
1108 | |||
1109 | static struct ata_port *dev_to_ata_port(struct device *dev) | ||
1110 | { | ||
1111 | while (!is_ata_port(dev)) { | ||
1112 | if (!dev->parent) | ||
1113 | return NULL; | ||
1114 | dev = dev->parent; | ||
1115 | } | ||
1116 | return to_ata_port(dev); | ||
1117 | } | ||
1118 | |||
1119 | static int ata_acpi_find_device(struct device *dev, acpi_handle *handle) | ||
1120 | { | ||
1121 | struct ata_port *ap = dev_to_ata_port(dev); | ||
1122 | |||
1123 | if (!ap) | ||
1124 | return -ENODEV; | ||
1125 | |||
1126 | if (!compat_pci_ata(ap)) | ||
1127 | return -ENODEV; | ||
1128 | |||
1129 | if (scsi_is_host_device(dev)) | ||
1130 | return ata_acpi_bind_host(ap, handle); | ||
1131 | else if (scsi_is_sdev_device(dev)) { | ||
1132 | struct scsi_device *sdev = to_scsi_device(dev); | ||
1133 | |||
1134 | return ata_acpi_bind_device(ap, sdev, handle); | ||
1135 | } else | ||
1136 | return -ENODEV; | ||
1137 | } | ||
1138 | |||
1139 | static int ata_acpi_find_dummy(struct device *dev, acpi_handle *handle) | ||
1140 | { | ||
1141 | return -ENODEV; | ||
1142 | } | ||
1143 | |||
1144 | static struct acpi_bus_type ata_acpi_bus = { | ||
1145 | .find_bridge = ata_acpi_find_dummy, | ||
1146 | .find_device = ata_acpi_find_device, | ||
1147 | }; | ||
1148 | |||
1149 | int ata_acpi_register(void) | ||
1150 | { | ||
1151 | return scsi_register_acpi_bus_type(&ata_acpi_bus); | ||
1152 | } | ||
1153 | |||
1154 | void ata_acpi_unregister(void) | ||
1155 | { | ||
1156 | scsi_unregister_acpi_bus_type(&ata_acpi_bus); | ||
1157 | } | ||