aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/libata-core.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 49d26675932..12717fa5e88 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3338,7 +3338,11 @@ static void ata_wait_spinup(struct ata_port *ap, unsigned long deadline)
* @ap: ATA port to be reset
* @deadline: deadline jiffies for the operation
*
- * @ap is about to be reset. Initialize it.
+ * @ap is about to be reset. Initialize it. Failure from
+ * prereset makes libata abort whole reset sequence and give up
+ * that port, so prereset should be best-effort. It does its
+ * best to prepare for reset sequence but if things go wrong, it
+ * should just whine, not fail.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3368,19 +3372,23 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
rc = sata_phy_resume(ap, timing, deadline);
- if (rc && rc != -EOPNOTSUPP) {
- /* phy resume failed */
+ /* whine about phy resume failure but proceed */
+ if (rc && rc != -EOPNOTSUPP)
ata_port_printk(ap, KERN_WARNING, "failed to resume "
"link for reset (errno=%d)\n", rc);
- return rc;
- }
}
/* Wait for !BSY if the controller can wait for the first D2H
* Reg FIS and we don't know that no device is attached.
*/
- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
- ata_wait_ready(ap, deadline);
+ if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+ rc = ata_wait_ready(ap, deadline);
+ if (rc) {
+ ata_port_printk(ap, KERN_WARNING, "device not ready "
+ "(errno=%d), forcing hardreset\n", rc);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+ }
return 0;
}