From: Damien Le Moal <dlemoal@kernel.org>
To: "Ewan D. Milne" <emilne@redhat.com>, linux-scsi@vger.kernel.org
Cc: michael.christie@oracle.com, dgilbert@interlog.com, bvanassche@acm.org
Subject: Re: [PATCH v2 7/9] scsi: sd: Check for and retry in case of READ_CAPCITY(10)/(16) returning no data
Date: Fri, 15 Aug 2025 11:50:24 +0900 [thread overview]
Message-ID: <7a503388-d466-491b-aa1e-e56515266eab@kernel.org> (raw)
In-Reply-To: <20250814182907.1501213-8-emilne@redhat.com>
On 8/15/25 03:29, Ewan D. Milne wrote:
> sd_read_capacity_10() and sd_read_capacity_16() do not check for underflow
> and can extract invalid (e.g. zero) data when a malfunctioning device does
> not actually transfer any data, but returnes a good status otherwise.
> Check for this and retry, and log a message and return -EINVAL if we can't
> get the capacity information.
>
> We encountered a device that did this once but returned good data afterwards.
>
> See similar commit 5cd3bbfad088 ("[SCSI] retry with missing data for INQUIRY")
>
> Signed-off-by: Ewan D. Milne <emilne@redhat.com>
> ---
> drivers/scsi/sd.c | 56 ++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 48 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index f1ab2409ea3e..20b5eebba968 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -2639,6 +2639,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
> [13] = RC16_LEN,
> };
> struct scsi_sense_hdr sshdr;
> + int count, resid;
> struct scsi_failure failure_defs[] = {
> /*
> * Do not retry Invalid Command Operation Code or Invalid
> @@ -2689,6 +2690,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
> };
> const struct scsi_exec_args exec_args = {
> .sshdr = &sshdr,
> + .resid = &resid,
> .failures = &failures,
> };
> int sense_valid = 0;
> @@ -2700,11 +2702,23 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
> if (sdp->no_read_capacity_16)
> return -EINVAL;
>
> - memset(buffer, 0, buflen);
> + for (count = 0; count < 3; ++count) {
> + memset(buffer, 0, buflen);
>
> - the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer,
> - RC16_LEN, SD_TIMEOUT, sdkp->max_retries,
> - &exec_args);
> + the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN,
> + buffer, RC16_LEN, SD_TIMEOUT,
> + sdkp->max_retries, &exec_args);
> +
> + if ((the_result == 0) && (resid == RC16_LEN)) {
You do not need the inner parenthesis. Also, it seems to me that this check
should simply be:
if (resid)
Because any incomplete read capacity buffer is bound to be invalid.
> + /*
> + * if nothing was transferred, we try
> + * again. It's a workaround for a broken
> + * device.
> + */
> + continue;
> + }
> + break;
> + }
>
> if (the_result > 0) {
> if (media_not_present(sdkp, &sshdr))
> @@ -2728,6 +2742,12 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
> return -EINVAL;
> }
>
> + if (resid == RC16_LEN) {
> + sd_printk(KERN_ERR, sdkp,
> + "Read Capacity(16) returned good status but no data");
Shouldn't this be a warning instead of error ? After all, there was no error...
And I would prefer seeing a warning for a bad device. The message would also be
better mentioning that this is the device fault.
> + return -EINVAL;
> + }
> +
> sector_size = get_unaligned_be32(&buffer[8]);
> lba = get_unaligned_be64(&buffer[0]);
>
> @@ -2770,6 +2790,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
> {
> static const u8 cmd[10] = { READ_CAPACITY };
> struct scsi_sense_hdr sshdr;
> + int count, resid;
> struct scsi_failure failure_defs[] = {
> /* Do not retry Medium Not Present */
> {
> @@ -2804,17 +2825,30 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
> };
> const struct scsi_exec_args exec_args = {
> .sshdr = &sshdr,
> + .resid = &resid,
> .failures = &failures,
> };
> int the_result;
> sector_t lba;
> unsigned sector_size;
>
> - memset(buffer, 0, buflen);
> + for (count = 0; count < 3; ++count) {
> + memset(buffer, 0, buflen);
>
> - the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer,
> - 8, SD_TIMEOUT, sdkp->max_retries,
> - &exec_args);
> + the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN,
> + buffer, RC10_LEN, SD_TIMEOUT,
> + sdkp->max_retries, &exec_args);
> +
> + if ((the_result == 0) && (resid == RC16_LEN)) {
Same comment here: if (resid) ?
> + /*
> + * if nothing was transferred, we try
> + * again. It's a workaround for a broken
> + * device.
> + */
> + continue;
> + }
> + break;
> + }
>
> if (the_result > 0) {
> if (media_not_present(sdkp, &sshdr))
> @@ -2827,6 +2861,12 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
> return -EINVAL;
> }
>
> + if (resid == RC10_LEN) {
> + sd_printk(KERN_ERR, sdkp,
> + "Read Capacity(10) returned good status but no data");
> + return -EINVAL;
> + }
> +
> sector_size = get_unaligned_be32(&buffer[4]);
> lba = get_unaligned_be32(&buffer[0]);
>
--
Damien Le Moal
Western Digital Research
next prev parent reply other threads:[~2025-08-15 2:50 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-14 18:28 [PATCH v2 0/9] Retry READ CAPACITY(10)/(16) with good status but no data Ewan D. Milne
2025-08-14 18:28 ` [PATCH v2 1/9] scsi: Explicitly specify .ascq = 0x00 for ASC 0x28/0x29 scsi_failures Ewan D. Milne
2025-08-14 18:29 ` [PATCH v2 2/9] scsi: sd: Explicitly specify .ascq = SCMD_FAILURE_ASCQ_ANY for ASC 0x3a Ewan D. Milne
2025-08-14 21:24 ` Bart Van Assche
2025-08-15 19:17 ` Ewan Milne
2025-08-14 18:29 ` [PATCH v2 3/9] scsi: sd: Pass buffer length as argument to sd_read_capacity() et al Ewan D. Milne
2025-08-14 21:31 ` Bart Van Assche
2025-08-15 2:43 ` Damien Le Moal
2025-08-15 18:53 ` Ewan Milne
2025-08-14 18:29 ` [PATCH v2 4/9] scsi: sd: Have scsi-ml retry read_capacity_16 errors Ewan D. Milne
2025-08-14 21:33 ` Bart Van Assche
2025-08-14 18:29 ` [PATCH v2 5/9] scsi: sd: Avoid passing potentially uninitialized "sense_valid" to read_capacity_error() Ewan D. Milne
2025-08-14 21:34 ` Bart Van Assche
2025-08-14 18:29 ` [PATCH v2 6/9] scsi: sd: Remove checks for -EOVERFLOW in sd_read_capacity() Ewan D. Milne
2025-08-14 21:36 ` Bart Van Assche
2025-08-14 18:29 ` [PATCH v2 7/9] scsi: sd: Check for and retry in case of READ_CAPCITY(10)/(16) returning no data Ewan D. Milne
2025-08-14 21:37 ` Bart Van Assche
2025-08-15 2:50 ` Damien Le Moal [this message]
2025-08-15 18:31 ` Ewan Milne
2025-08-14 18:29 ` [PATCH v2 8/9] scsi: Simplify nested if conditional in scsi_probe_lun() Ewan D. Milne
2025-08-14 21:37 ` Bart Van Assche
2025-08-15 2:50 ` Damien Le Moal
2025-08-14 18:29 ` [PATCH v2 9/9] scsi: scsi_debug: Add option to suppress returned data but return good status Ewan D. Milne
2025-08-14 21:41 ` Bart Van Assche
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=7a503388-d466-491b-aa1e-e56515266eab@kernel.org \
--to=dlemoal@kernel.org \
--cc=bvanassche@acm.org \
--cc=dgilbert@interlog.com \
--cc=emilne@redhat.com \
--cc=linux-scsi@vger.kernel.org \
--cc=michael.christie@oracle.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.