diff options
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 57 |
1 files changed, 43 insertions, 14 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 22ff51bdbc8a..4a28420efff2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2232,7 +2232,7 @@ retry: * Some drives were very specific about that exact sequence. * * Note that ATA4 says lba is mandatory so the second check - * shoud never trigger. + * should never trigger. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { err_mask = ata_dev_init_params(dev, id[3], id[6]); @@ -3211,6 +3211,7 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) int ata_timing_compute(struct ata_device *adev, unsigned short speed, struct ata_timing *t, int T, int UT) { + const u16 *id = adev->id; const struct ata_timing *s; struct ata_timing p; @@ -3228,14 +3229,18 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, * PIO/MW_DMA cycle timing. */ - if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ + if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ memset(&p, 0, sizeof(p)); + if (speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) { - if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO]; - else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY]; - } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { - p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN]; - } + if (speed <= XFER_PIO_2) + p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO]; + else if ((speed <= XFER_PIO_4) || + (speed == XFER_PIO_5 && !ata_id_is_cfa(id))) + p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY]; + } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) + p.cycle = id[ATA_ID_EIDE_DMA_MIN]; + ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B); } @@ -3790,21 +3795,45 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, int sata_link_resume(struct ata_link *link, const unsigned long *params, unsigned long deadline) { + int tries = ATA_LINK_RESUME_TRIES; u32 scontrol, serror; int rc; if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) return rc; - scontrol = (scontrol & 0x0f0) | 0x300; + /* + * Writes to SControl sometimes get ignored under certain + * controllers (ata_piix SIDPR). Make sure DET actually is + * cleared. + */ + do { + scontrol = (scontrol & 0x0f0) | 0x300; + if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) + return rc; + /* + * Some PHYs react badly if SStatus is pounded + * immediately after resuming. Delay 200ms before + * debouncing. + */ + msleep(200); + + /* is SControl restored correctly? */ + if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) + return rc; + } while ((scontrol & 0xf0f) != 0x300 && --tries); - if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) - return rc; + if ((scontrol & 0xf0f) != 0x300) { + ata_link_printk(link, KERN_ERR, + "failed to resume link (SControl %X)\n", + scontrol); + return 0; + } - /* Some PHYs react badly if SStatus is pounded immediately - * after resuming. Delay 200ms before debouncing. - */ - msleep(200); + if (tries < ATA_LINK_RESUME_TRIES) + ata_link_printk(link, KERN_WARNING, + "link resume succeeded after %d retries\n", + ATA_LINK_RESUME_TRIES - tries); if ((rc = sata_link_debounce(link, params, deadline))) return rc; |