diff options
Diffstat (limited to 'drivers/ata/pata_acpi.c')
-rw-r--r-- | drivers/ata/pata_acpi.c | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c new file mode 100644 index 000000000000..5d3920f6fd69 --- /dev/null +++ b/drivers/ata/pata_acpi.c | |||
@@ -0,0 +1,395 @@ | |||
1 | /* | ||
2 | * ACPI PATA driver | ||
3 | * | ||
4 | * (c) 2007 Red Hat <alan@redhat.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/blkdev.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <scsi/scsi_host.h> | ||
15 | #include <acpi/acpi_bus.h> | ||
16 | #include <acpi/acnames.h> | ||
17 | #include <acpi/acnamesp.h> | ||
18 | #include <acpi/acparser.h> | ||
19 | #include <acpi/acexcep.h> | ||
20 | #include <acpi/acmacros.h> | ||
21 | #include <acpi/actypes.h> | ||
22 | |||
23 | #include <linux/libata.h> | ||
24 | #include <linux/ata.h> | ||
25 | |||
26 | #define DRV_NAME "pata_acpi" | ||
27 | #define DRV_VERSION "0.2.3" | ||
28 | |||
29 | struct pata_acpi { | ||
30 | struct ata_acpi_gtm gtm; | ||
31 | void *last; | ||
32 | unsigned long mask[2]; | ||
33 | }; | ||
34 | |||
35 | /** | ||
36 | * pacpi_pre_reset - check for 40/80 pin | ||
37 | * @ap: Port | ||
38 | * @deadline: deadline jiffies for the operation | ||
39 | * | ||
40 | * Perform the PATA port setup we need. | ||
41 | */ | ||
42 | |||
43 | static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline) | ||
44 | { | ||
45 | struct ata_port *ap = link->ap; | ||
46 | struct pata_acpi *acpi = ap->private_data; | ||
47 | if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0) | ||
48 | return -ENODEV; | ||
49 | |||
50 | return ata_std_prereset(link, deadline); | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * pacpi_cable_detect - cable type detection | ||
55 | * @ap: port to detect | ||
56 | * | ||
57 | * Perform device specific cable detection | ||
58 | */ | ||
59 | |||
60 | static int pacpi_cable_detect(struct ata_port *ap) | ||
61 | { | ||
62 | struct pata_acpi *acpi = ap->private_data; | ||
63 | |||
64 | if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA)) | ||
65 | return ATA_CBL_PATA80; | ||
66 | else | ||
67 | return ATA_CBL_PATA40; | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * pacpi_error_handler - Setup and error handler | ||
72 | * @ap: Port to handle | ||
73 | * | ||
74 | * LOCKING: | ||
75 | * None (inherited from caller). | ||
76 | */ | ||
77 | |||
78 | static void pacpi_error_handler(struct ata_port *ap) | ||
79 | { | ||
80 | return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, | ||
81 | NULL, ata_std_postreset); | ||
82 | } | ||
83 | |||
84 | /* Welcome to ACPI, bring a bucket */ | ||
85 | static const unsigned int pio_cycle[7] = { | ||
86 | 600, 383, 240, 180, 120, 100, 80 | ||
87 | }; | ||
88 | static const unsigned int mwdma_cycle[5] = { | ||
89 | 480, 150, 120, 100, 80 | ||
90 | }; | ||
91 | static const unsigned int udma_cycle[7] = { | ||
92 | 120, 80, 60, 45, 30, 20, 15 | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * pacpi_discover_modes - filter non ACPI modes | ||
97 | * @adev: ATA device | ||
98 | * @mask: proposed modes | ||
99 | * | ||
100 | * Try the modes available and see which ones the ACPI method will | ||
101 | * set up sensibly. From this we get a mask of ACPI modes we can use | ||
102 | */ | ||
103 | |||
104 | static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) | ||
105 | { | ||
106 | int unit = adev->devno; | ||
107 | struct pata_acpi *acpi = ap->private_data; | ||
108 | int i; | ||
109 | u32 t; | ||
110 | unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); | ||
111 | |||
112 | struct ata_acpi_gtm probe; | ||
113 | |||
114 | probe = acpi->gtm; | ||
115 | |||
116 | /* We always use the 0 slot for crap hardware */ | ||
117 | if (!(probe.flags & 0x10)) | ||
118 | unit = 0; | ||
119 | |||
120 | ata_acpi_gtm(ap, &probe); | ||
121 | |||
122 | /* Start by scanning for PIO modes */ | ||
123 | for (i = 0; i < 7; i++) { | ||
124 | t = probe.drive[unit].pio; | ||
125 | if (t <= pio_cycle[i]) { | ||
126 | mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | /* See if we have MWDMA or UDMA data. We don't bother with MWDMA | ||
132 | if UDMA is availabe as this means the BIOS set UDMA and our | ||
133 | error changedown if it works is UDMA to PIO anyway */ | ||
134 | if (probe.flags & (1 << (2 * unit))) { | ||
135 | /* MWDMA */ | ||
136 | for (i = 0; i < 5; i++) { | ||
137 | t = probe.drive[unit].dma; | ||
138 | if (t <= mwdma_cycle[i]) { | ||
139 | mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | } else { | ||
144 | /* UDMA */ | ||
145 | for (i = 0; i < 7; i++) { | ||
146 | t = probe.drive[unit].dma; | ||
147 | if (t <= udma_cycle[i]) { | ||
148 | mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | if (mask & (0xF8 << ATA_SHIFT_UDMA)) | ||
154 | ap->cbl = ATA_CBL_PATA80; | ||
155 | return mask; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * pacpi_mode_filter - mode filter for ACPI | ||
160 | * @adev: device | ||
161 | * @mask: mask of valid modes | ||
162 | * | ||
163 | * Filter the valid mode list according to our own specific rules, in | ||
164 | * this case the list of discovered valid modes obtained by ACPI probing | ||
165 | */ | ||
166 | |||
167 | static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) | ||
168 | { | ||
169 | struct pata_acpi *acpi = adev->link->ap->private_data; | ||
170 | return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * pacpi_set_piomode - set initial PIO mode data | ||
175 | * @ap: ATA interface | ||
176 | * @adev: ATA device | ||
177 | */ | ||
178 | |||
179 | static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) | ||
180 | { | ||
181 | int unit = adev->devno; | ||
182 | struct pata_acpi *acpi = ap->private_data; | ||
183 | |||
184 | if(!(acpi->gtm.flags & 0x10)) | ||
185 | unit = 0; | ||
186 | |||
187 | /* Now stuff the nS values into the structure */ | ||
188 | acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; | ||
189 | ata_acpi_stm(ap, &acpi->gtm); | ||
190 | /* See what mode we actually got */ | ||
191 | ata_acpi_gtm(ap, &acpi->gtm); | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * pacpi_set_dmamode - set initial DMA mode data | ||
196 | * @ap: ATA interface | ||
197 | * @adev: ATA device | ||
198 | */ | ||
199 | |||
200 | static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) | ||
201 | { | ||
202 | int unit = adev->devno; | ||
203 | struct pata_acpi *acpi = ap->private_data; | ||
204 | |||
205 | if(!(acpi->gtm.flags & 0x10)) | ||
206 | unit = 0; | ||
207 | |||
208 | /* Now stuff the nS values into the structure */ | ||
209 | if (adev->dma_mode >= XFER_UDMA_0) { | ||
210 | acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; | ||
211 | acpi->gtm.flags |= (1 << (2 * unit)); | ||
212 | } else { | ||
213 | acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; | ||
214 | acpi->gtm.flags &= ~(1 << (2 * unit)); | ||
215 | } | ||
216 | ata_acpi_stm(ap, &acpi->gtm); | ||
217 | /* See what mode we actually got */ | ||
218 | ata_acpi_gtm(ap, &acpi->gtm); | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * pacpi_qc_issue_prot - command issue | ||
223 | * @qc: command pending | ||
224 | * | ||
225 | * Called when the libata layer is about to issue a command. We wrap | ||
226 | * this interface so that we can load the correct ATA timings if | ||
227 | * neccessary. | ||
228 | */ | ||
229 | |||
230 | static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) | ||
231 | { | ||
232 | struct ata_port *ap = qc->ap; | ||
233 | struct ata_device *adev = qc->dev; | ||
234 | struct pata_acpi *acpi = ap->private_data; | ||
235 | |||
236 | if (acpi->gtm.flags & 0x10) | ||
237 | return ata_qc_issue_prot(qc); | ||
238 | |||
239 | if (adev != acpi->last) { | ||
240 | pacpi_set_piomode(ap, adev); | ||
241 | if (adev->dma_mode) | ||
242 | pacpi_set_dmamode(ap, adev); | ||
243 | acpi->last = adev; | ||
244 | } | ||
245 | return ata_qc_issue_prot(qc); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * pacpi_port_start - port setup | ||
250 | * @ap: ATA port being set up | ||
251 | * | ||
252 | * Use the port_start hook to maintain private control structures | ||
253 | */ | ||
254 | |||
255 | static int pacpi_port_start(struct ata_port *ap) | ||
256 | { | ||
257 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
258 | struct pata_acpi *acpi; | ||
259 | |||
260 | int ret; | ||
261 | |||
262 | if (ap->acpi_handle == NULL) | ||
263 | return -ENODEV; | ||
264 | |||
265 | acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL); | ||
266 | if (ap->private_data == NULL) | ||
267 | return -ENOMEM; | ||
268 | acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]); | ||
269 | acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]); | ||
270 | ret = ata_sff_port_start(ap); | ||
271 | if (ret < 0) | ||
272 | return ret; | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static struct scsi_host_template pacpi_sht = { | ||
278 | .module = THIS_MODULE, | ||
279 | .name = DRV_NAME, | ||
280 | .ioctl = ata_scsi_ioctl, | ||
281 | .queuecommand = ata_scsi_queuecmd, | ||
282 | .can_queue = ATA_DEF_QUEUE, | ||
283 | .this_id = ATA_SHT_THIS_ID, | ||
284 | .sg_tablesize = LIBATA_MAX_PRD, | ||
285 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | ||
286 | .emulated = ATA_SHT_EMULATED, | ||
287 | .use_clustering = ATA_SHT_USE_CLUSTERING, | ||
288 | .proc_name = DRV_NAME, | ||
289 | .dma_boundary = ATA_DMA_BOUNDARY, | ||
290 | .slave_configure = ata_scsi_slave_config, | ||
291 | .slave_destroy = ata_scsi_slave_destroy, | ||
292 | /* Use standard CHS mapping rules */ | ||
293 | .bios_param = ata_std_bios_param, | ||
294 | }; | ||
295 | |||
296 | static const struct ata_port_operations pacpi_ops = { | ||
297 | .set_piomode = pacpi_set_piomode, | ||
298 | .set_dmamode = pacpi_set_dmamode, | ||
299 | .mode_filter = pacpi_mode_filter, | ||
300 | |||
301 | /* Task file is PCI ATA format, use helpers */ | ||
302 | .tf_load = ata_tf_load, | ||
303 | .tf_read = ata_tf_read, | ||
304 | .check_status = ata_check_status, | ||
305 | .exec_command = ata_exec_command, | ||
306 | .dev_select = ata_std_dev_select, | ||
307 | |||
308 | .freeze = ata_bmdma_freeze, | ||
309 | .thaw = ata_bmdma_thaw, | ||
310 | .error_handler = pacpi_error_handler, | ||
311 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
312 | .cable_detect = pacpi_cable_detect, | ||
313 | |||
314 | /* BMDMA handling is PCI ATA format, use helpers */ | ||
315 | .bmdma_setup = ata_bmdma_setup, | ||
316 | .bmdma_start = ata_bmdma_start, | ||
317 | .bmdma_stop = ata_bmdma_stop, | ||
318 | .bmdma_status = ata_bmdma_status, | ||
319 | .qc_prep = ata_qc_prep, | ||
320 | .qc_issue = pacpi_qc_issue_prot, | ||
321 | .data_xfer = ata_data_xfer, | ||
322 | |||
323 | /* Timeout handling */ | ||
324 | .irq_handler = ata_interrupt, | ||
325 | .irq_clear = ata_bmdma_irq_clear, | ||
326 | .irq_on = ata_irq_on, | ||
327 | |||
328 | /* Generic PATA PCI ATA helpers */ | ||
329 | .port_start = pacpi_port_start, | ||
330 | }; | ||
331 | |||
332 | |||
333 | /** | ||
334 | * pacpi_init_one - Register ACPI ATA PCI device with kernel services | ||
335 | * @pdev: PCI device to register | ||
336 | * @ent: Entry in pacpi_pci_tbl matching with @pdev | ||
337 | * | ||
338 | * Called from kernel PCI layer. | ||
339 | * | ||
340 | * LOCKING: | ||
341 | * Inherited from PCI layer (may sleep). | ||
342 | * | ||
343 | * RETURNS: | ||
344 | * Zero on success, or -ERRNO value. | ||
345 | */ | ||
346 | |||
347 | static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) | ||
348 | { | ||
349 | static const struct ata_port_info info = { | ||
350 | .sht = &pacpi_sht, | ||
351 | .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, | ||
352 | |||
353 | .pio_mask = 0x1f, | ||
354 | .mwdma_mask = 0x07, | ||
355 | .udma_mask = 0x7f, | ||
356 | |||
357 | .port_ops = &pacpi_ops, | ||
358 | }; | ||
359 | const struct ata_port_info *ppi[] = { &info, NULL }; | ||
360 | return ata_pci_init_one(pdev, ppi); | ||
361 | } | ||
362 | |||
363 | static const struct pci_device_id pacpi_pci_tbl[] = { | ||
364 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, | ||
365 | { } /* terminate list */ | ||
366 | }; | ||
367 | |||
368 | static struct pci_driver pacpi_pci_driver = { | ||
369 | .name = DRV_NAME, | ||
370 | .id_table = pacpi_pci_tbl, | ||
371 | .probe = pacpi_init_one, | ||
372 | .remove = ata_pci_remove_one, | ||
373 | .suspend = ata_pci_device_suspend, | ||
374 | .resume = ata_pci_device_resume, | ||
375 | }; | ||
376 | |||
377 | static int __init pacpi_init(void) | ||
378 | { | ||
379 | return pci_register_driver(&pacpi_pci_driver); | ||
380 | } | ||
381 | |||
382 | static void __exit pacpi_exit(void) | ||
383 | { | ||
384 | pci_unregister_driver(&pacpi_pci_driver); | ||
385 | } | ||
386 | |||
387 | module_init(pacpi_init); | ||
388 | module_exit(pacpi_exit); | ||
389 | |||
390 | MODULE_AUTHOR("Alan Cox"); | ||
391 | MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode"); | ||
392 | MODULE_LICENSE("GPL"); | ||
393 | MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl); | ||
394 | MODULE_VERSION(DRV_VERSION); | ||
395 | |||