Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5040ab67 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata: retry link resume if necessary



Interestingly, when SIDPR is used in ata_piix, writes to DET in
SControl sometimes get ignored leading to detection failure.  Update
sata_link_resume() such that it reads back SControl after clearing DET
and retry if it's not clear.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Reported-by: default avatarfengxiangjun <fengxiangjun@neusoft.com>
Reported-by: default avatarJim Faulkner <jfaulkne@ccs.neu.edu>
Cc: stable@kernel.org
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 0b67c743
Loading
Loading
Loading
Loading
+31 −7
Original line number Diff line number Diff line
@@ -3790,22 +3790,46 @@ 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;

	/*
	 * 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.
		/*
		 * 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 ((scontrol & 0xf0f) != 0x300) {
		ata_link_printk(link, KERN_ERR,
				"failed to resume link (SControl %X)\n",
				scontrol);
		return 0;
	}

	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;

+3 −0
Original line number Diff line number Diff line
@@ -354,6 +354,9 @@ enum {
	/* max tries if error condition is still set after ->error_handler */
	ATA_EH_MAX_TRIES	= 5,

	/* sometimes resuming a link requires several retries */
	ATA_LINK_RESUME_TRIES	= 5,

	/* how hard are we gonna try to probe/recover devices */
	ATA_PROBE_MAX_TRIES	= 3,
	ATA_EH_DEV_TRIES	= 3,