Linux ATA/IDE development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: tongzhiwei <tongzhiwei@cmss.chinamobile.com>
Cc: linux-ide@vger.kernel.org, dlemoal@kernel.org, cassel@kernel.org
Subject: Re: [PATCH v2] ata: libata: skip sata_down_spd_limit() when no device is present
Date: Tue, 20 Oct 2026 08:32:19 +0000	[thread overview]
Message-ID: <sashiko-outbox-178562@kernel.org> (raw)
In-Reply-To: <20261020032054.430-1-tongzhiwei@cmss.chinamobile.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ata: libata: sata_down_spd_limit() DET == 0 check breaks link recovery
- [Medium] ata: libata: sata_down_spd_limit() DET check fails on replug and LPM
--

commit 2169b3134adb850a6a9a8662fa4f3cc24faf938a
Author: tongzhiwei <tongzhiwei@cmss.chinamobile.com>

ata: libata: skip sata_down_spd_limit() when no device is present

This commit changes sata_down_spd_limit() to return -EINVAL when reading
SCR_STATUS indicates that the SStatus DET field is 0, intending to prevent
probe attempts during a hot-unplug from lowering sata_spd_limit.

>     ata: libata: skip sata_down_spd_limit() when no device is present
>     
>     A hot-unplug goes through ata_eh_schedule_probe() -> ata_dev_init() ->
>     sata_spd = 0.  After commit 69f2c9346313 ("ata: libata: Fix
>     sata_down_spd_limit() when no link speed is reported"), when the device
>     is unplugged, every probe lowers sata_spd_limit.  This breaks
>     commit 2dc0b46b5ea3 ("libata: sata_down_spd_limit should return
>     if driver has not recorded sstatus speed").
>     
>     As a result, when the device is plugged back in, it is limited to a
>     low speed that is never recovered.
>     
>     Use the SStatus DET field to detect the no-device case and bail out
>     of sata_down_spd_limit() when no device is present (DET == 0).
>     
>     Fixes: 69f2c9346313 ("ata: libata: Fix sata_down_spd_limit() when no link speed is reported")
>     Assisted-by: LLM
>     Signed-off-by: tongzhiwei <tongzhiwei@cmss.chinamobile.com>

[Severity: Medium]
Is this description of how sata_spd_limit persists across hot-unplug probes
accurate, and does checking for (sstatus & 0xf) == 0 inside
sata_down_spd_limit() actually avoid the speed drop when a drive is plugged
back in?

At the beginning of every ata_eh_schedule_probe() call, ata_dev_init()
already resets link->sata_spd_limit back to link->hw_sata_spd_limit:

drivers/ata/libata-eh.c:ata_eh_schedule_probe()
    ata_eh_detach_dev(dev);
    ata_dev_init(dev);
    ...
    ata_ering_record(&dev->ering, 0, AC_ERR_OTHER);
    ata_ering_map(&dev->ering, ata_count_probe_trials_cb, &trials);

    if (trials > ATA_EH_PROBE_TRIALS)
        sata_down_spd_limit(link, 1);

What actually persists across ata_dev_init() is dev->ering, which is only
cleared once ata_dev_read_id() succeeds in ata_eh_revalidate_and_attach().

When a device is hot-unplugged and plugged back in within
ATA_EH_PROBE_TRIAL_INTERVAL (60 seconds), the unplugged probes accumulate
entries in dev->ering. On the subsequent plug-in probe, ata_eh_recover()
calls ata_eh_schedule_probe() before ata_eh_reset(). Because the drive is now
physically attached, SStatus.DET (sstatus & 0xf) is already 0x1 or 0x3 when
ata_eh_schedule_probe() increments trials past ATA_EH_PROBE_TRIALS (2) and
calls sata_down_spd_limit(link, 1). Doesn't (sstatus & 0xf) == 0 evaluate to
false on that plug-in probe and still force the reconnected drive down to
1.5 Gbps?

Also, what happens when Link Power Management (LPM) is enabled on an empty
port (such as ATA_LPM_MED_POWER_WITH_DIPM, ATA_LPM_MIN_POWER_WITH_PARTIAL, or
ATA_LPM_MIN_POWER)? In drivers/ata/libata-sata.c:sata_link_scr_lpm():

		} else {
			/* empty port, power off */
			scontrol &= ~0xf;
			scontrol |= (0x1 << 2);
		}

sata_link_scr_lpm() sets SControl.DET to 0x4, causing SStatus.DET to report
0x4 (PHY offline) instead of 0x0. Similarly, some controllers leave
SStatus.DET stuck at 0x1 after hot-unplugging, as noted in
sata_link_debounce(). In both cases, wouldn't (sstatus & 0xf) == 0 also be
bypassed while no device is present?

> diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
> index ad40f516c6d43..775da21cbbae7 100644
> --- a/drivers/ata/libata-sata.c
> +++ b/drivers/ata/libata-sata.c
> @@ -549,6 +549,9 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
>  	 * If not, use cached value in link->sata_spd.
>  	 */
>  	rc = sata_scr_read(link, SCR_STATUS, &sstatus);
> +	/* No device present (DET == 0): nothing to recover by lowering speed. */
> +	if (rc == 0 && (sstatus & 0xf) == 0)
> +		return -EINVAL;

[Severity: High]
Won't bailing out of sata_down_spd_limit() on an instantaneous
(sstatus & 0xf) == 0 read break link speed step-down recovery when a
connected device fails speed negotiation or drops its link?

For example, when SStatus.DET is oscillating (such as cycling between 0 and 1
when high-speed negotiation fails), sata_link_debounce() returns -EPIPE so
that the caller lowers the link speed:

drivers/ata/libata-sata.c:sata_link_debounce()
		/* Check deadline.  If debouncing failed, return
		 * -EPIPE to tell upper layer to lower link speed.
		 */
		if (time_after(jiffies, deadline))
			return -EPIPE;

drivers/ata/libata-eh.c:ata_eh_reset()
	} else if (rc == -EPIPE)
		sata_down_spd_limit(failed_link, 0);

Likewise, ata_eh_reset() calls sata_down_spd_limit(link, 0) when
try == max_tries - 1, ata_eh_schedule_probe() calls
sata_down_spd_limit(link, 1) to recover from failed link speed negotiations
that cause repeated DEVXCHG or PHRDY CHG events, and ata_eh_speed_down()
calls sata_down_spd_limit(link, 0) when a previously established link (with
link->sata_spd recorded) suffers errors and drops.

If sata_scr_read() in sata_down_spd_limit() samples SCR_STATUS while the
dropped or oscillating link has DET == 0, won't this check return -EINVAL and
prevent libata from stepping down link->sata_spd_limit to recover the device?

>  	if (rc == 0 && ata_sstatus_online(sstatus))
>  		spd = (sstatus >> 4) & 0xf;
>  	else

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261020032054.430-1-tongzhiwei@cmss.chinamobile.com?part=1

      reply	other threads:[~2026-10-20  8:32 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-10  7:54 [PATCH] ata: libata: preserve sata_spd link cache across ata_dev_init tongzhiwei
2026-10-10  8:16 ` sashiko-bot
2026-10-15  5:30 ` Damien Le Moal
2026-10-15  7:59   ` Damien Le Moal
2026-10-20  3:20 ` [PATCH v2] ata: libata: skip sata_down_spd_limit() when no device is present tongzhiwei
2026-10-20  8:32   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-178562@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=cassel@kernel.org \
    --cc=dlemoal@kernel.org \
    --cc=linux-ide@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tongzhiwei@cmss.chinamobile.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox