diff options
-rw-r--r-- | drivers/ata/libata-core.c | 38 | ||||
-rw-r--r-- | include/linux/libata.h | 3 |
2 files changed, 34 insertions, 7 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 22ff51bdbc8a..6728328f3bea 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -3790,21 +3790,45 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, | |||
3790 | int sata_link_resume(struct ata_link *link, const unsigned long *params, | 3790 | int sata_link_resume(struct ata_link *link, const unsigned long *params, |
3791 | unsigned long deadline) | 3791 | unsigned long deadline) |
3792 | { | 3792 | { |
3793 | int tries = ATA_LINK_RESUME_TRIES; | ||
3793 | u32 scontrol, serror; | 3794 | u32 scontrol, serror; |
3794 | int rc; | 3795 | int rc; |
3795 | 3796 | ||
3796 | if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) | 3797 | if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) |
3797 | return rc; | 3798 | return rc; |
3798 | 3799 | ||
3799 | scontrol = (scontrol & 0x0f0) | 0x300; | 3800 | /* |
3801 | * Writes to SControl sometimes get ignored under certain | ||
3802 | * controllers (ata_piix SIDPR). Make sure DET actually is | ||
3803 | * cleared. | ||
3804 | */ | ||
3805 | do { | ||
3806 | scontrol = (scontrol & 0x0f0) | 0x300; | ||
3807 | if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) | ||
3808 | return rc; | ||
3809 | /* | ||
3810 | * Some PHYs react badly if SStatus is pounded | ||
3811 | * immediately after resuming. Delay 200ms before | ||
3812 | * debouncing. | ||
3813 | */ | ||
3814 | msleep(200); | ||
3800 | 3815 | ||
3801 | if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) | 3816 | /* is SControl restored correctly? */ |
3802 | return rc; | 3817 | if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) |
3818 | return rc; | ||
3819 | } while ((scontrol & 0xf0f) != 0x300 && --tries); | ||
3803 | 3820 | ||
3804 | /* Some PHYs react badly if SStatus is pounded immediately | 3821 | if ((scontrol & 0xf0f) != 0x300) { |
3805 | * after resuming. Delay 200ms before debouncing. | 3822 | ata_link_printk(link, KERN_ERR, |
3806 | */ | 3823 | "failed to resume link (SControl %X)\n", |
3807 | msleep(200); | 3824 | scontrol); |
3825 | return 0; | ||
3826 | } | ||
3827 | |||
3828 | if (tries < ATA_LINK_RESUME_TRIES) | ||
3829 | ata_link_printk(link, KERN_WARNING, | ||
3830 | "link resume succeeded after %d retries\n", | ||
3831 | ATA_LINK_RESUME_TRIES - tries); | ||
3808 | 3832 | ||
3809 | if ((rc = sata_link_debounce(link, params, deadline))) | 3833 | if ((rc = sata_link_debounce(link, params, deadline))) |
3810 | return rc; | 3834 | return rc; |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 6a9c4ddd3d95..73112250862c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -354,6 +354,9 @@ enum { | |||
354 | /* max tries if error condition is still set after ->error_handler */ | 354 | /* max tries if error condition is still set after ->error_handler */ |
355 | ATA_EH_MAX_TRIES = 5, | 355 | ATA_EH_MAX_TRIES = 5, |
356 | 356 | ||
357 | /* sometimes resuming a link requires several retries */ | ||
358 | ATA_LINK_RESUME_TRIES = 5, | ||
359 | |||
357 | /* how hard are we gonna try to probe/recover devices */ | 360 | /* how hard are we gonna try to probe/recover devices */ |
358 | ATA_PROBE_MAX_TRIES = 3, | 361 | ATA_PROBE_MAX_TRIES = 3, |
359 | ATA_EH_DEV_TRIES = 3, | 362 | ATA_EH_DEV_TRIES = 3, |