diff options
Diffstat (limited to 'drivers/ata/libata-sff.c')
-rw-r--r-- | drivers/ata/libata-sff.c | 62 |
1 files changed, 12 insertions, 50 deletions
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 6e8de3c1595e..78912c5011ad 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c | |||
@@ -308,6 +308,17 @@ int ata_sff_busy_sleep(struct ata_port *ap, | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static int ata_sff_check_ready(struct ata_link *link) | ||
312 | { | ||
313 | u8 status = link->ap->ops->sff_check_status(link->ap); | ||
314 | |||
315 | if (!(status & ATA_BUSY)) | ||
316 | return 1; | ||
317 | if (status == 0xff) | ||
318 | return -ENODEV; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
311 | /** | 322 | /** |
312 | * ata_sff_wait_ready - sleep until BSY clears, or timeout | 323 | * ata_sff_wait_ready - sleep until BSY clears, or timeout |
313 | * @link: SFF link to wait ready status for | 324 | * @link: SFF link to wait ready status for |
@@ -324,56 +335,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, | |||
324 | */ | 335 | */ |
325 | int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline) | 336 | int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline) |
326 | { | 337 | { |
327 | struct ata_port *ap = link->ap; | 338 | return ata_wait_ready(link, deadline, ata_sff_check_ready); |
328 | unsigned long start = jiffies; | ||
329 | unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT; | ||
330 | int warned = 0; | ||
331 | |||
332 | if (time_after(nodev_deadline, deadline)) | ||
333 | nodev_deadline = deadline; | ||
334 | |||
335 | while (1) { | ||
336 | u8 status = ap->ops->sff_check_status(ap); | ||
337 | unsigned long now = jiffies; | ||
338 | |||
339 | if (!(status & ATA_BUSY)) | ||
340 | return 0; | ||
341 | |||
342 | /* No device status could be transient. Ignore it if | ||
343 | * link is online. Also, some SATA devices take a | ||
344 | * long time to clear 0xff after reset. For example, | ||
345 | * HHD424020F7SV00 iVDR needs >= 800ms while Quantum | ||
346 | * GoVault needs even more than that. Wait for | ||
347 | * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline. | ||
348 | * | ||
349 | * Note that some PATA controllers (pata_ali) explode | ||
350 | * if status register is read more than once when | ||
351 | * there's no device attached. | ||
352 | */ | ||
353 | if (status == 0xff) { | ||
354 | if (ata_link_online(link)) | ||
355 | status = ATA_BUSY; | ||
356 | else if ((link->ap->flags & ATA_FLAG_SATA) && | ||
357 | !ata_link_offline(link) && | ||
358 | time_before(now, nodev_deadline)) | ||
359 | status = ATA_BUSY; | ||
360 | if (status == 0xff) | ||
361 | return -ENODEV; | ||
362 | } | ||
363 | |||
364 | if (time_after(now, deadline)) | ||
365 | return -EBUSY; | ||
366 | |||
367 | if (!warned && time_after(now, start + 5 * HZ) && | ||
368 | (deadline - now > 3 * HZ)) { | ||
369 | ata_link_printk(link, KERN_WARNING, | ||
370 | "link is slow to respond, please be patient " | ||
371 | "(Status 0x%x)\n", status); | ||
372 | warned = 1; | ||
373 | } | ||
374 | |||
375 | msleep(50); | ||
376 | } | ||
377 | } | 339 | } |
378 | 340 | ||
379 | /** | 341 | /** |