Skip to content

Commit 321da3d

Browse files
scsi: sd: usb_storage: uas: Access media prior to querying device properties
It has been observed that some USB/UAS devices return generic properties hardcoded in firmware for mode pages for a period of time after a device has been discovered. The reported properties are either garbage or they do not accurately reflect the characteristics of the physical storage device attached in the case of a bridge. Prior to commit 1e02939 ("scsi: sd: Reorganize DIF/DIX code to avoid calling revalidate twice") we would call revalidate several times during device discovery. As a result, incorrect values would eventually get replaced with ones accurately describing the attached storage. When we did away with the redundant revalidate pass, several cases were reported where devices reported nonsensical values or would end up in write-protected state. An initial attempt at addressing this issue involved introducing a delayed second revalidate invocation. However, this approach still left some devices reporting incorrect characteristics. Tasos Sahanidis debugged the problem further and identified that introducing a READ operation prior to MODE SENSE fixed the problem and that it wasn't a timing issue. Issuing a READ appears to cause the devices to update their state to reflect the actual properties of the storage media. Device properties like vendor, model, and storage capacity appear to be correctly reported from the get-go. It is unclear why these devices defer populating the remaining characteristics. Match the behavior of a well known commercial operating system and trigger a READ operation prior to querying device characteristics to force the device to populate the mode pages. The additional READ is triggered by a flag set in the USB storage and UAS drivers. We avoid issuing the READ for other transport classes since some storage devices identify Linux through our particular discovery command sequence. Link: https://lore.kernel.org/r/[email protected] Fixes: 1e02939 ("scsi: sd: Reorganize DIF/DIX code to avoid calling revalidate twice") Cc: [email protected] Reported-by: Tasos Sahanidis <[email protected]> Reviewed-by: Ewan D. Milne <[email protected]> Reviewed-by: Bart Van Assche <[email protected]> Tested-by: Tasos Sahanidis <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 379a58c commit 321da3d

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

drivers/scsi/sd.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3407,6 +3407,24 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp,
34073407
return true;
34083408
}
34093409

3410+
static void sd_read_block_zero(struct scsi_disk *sdkp)
3411+
{
3412+
unsigned int buf_len = sdkp->device->sector_size;
3413+
char *buffer, cmd[10] = { };
3414+
3415+
buffer = kmalloc(buf_len, GFP_KERNEL);
3416+
if (!buffer)
3417+
return;
3418+
3419+
cmd[0] = READ_10;
3420+
put_unaligned_be32(0, &cmd[2]); /* Logical block address 0 */
3421+
put_unaligned_be16(1, &cmd[7]); /* Transfer 1 logical block */
3422+
3423+
scsi_execute_cmd(sdkp->device, cmd, REQ_OP_DRV_IN, buffer, buf_len,
3424+
SD_TIMEOUT, sdkp->max_retries, NULL);
3425+
kfree(buffer);
3426+
}
3427+
34103428
/**
34113429
* sd_revalidate_disk - called the first time a new disk is seen,
34123430
* performs disk spin up, read_capacity, etc.
@@ -3446,7 +3464,13 @@ static int sd_revalidate_disk(struct gendisk *disk)
34463464
*/
34473465
if (sdkp->media_present) {
34483466
sd_read_capacity(sdkp, buffer);
3449-
3467+
/*
3468+
* Some USB/UAS devices return generic values for mode pages
3469+
* until the media has been accessed. Trigger a READ operation
3470+
* to force the device to populate mode pages.
3471+
*/
3472+
if (sdp->read_before_ms)
3473+
sd_read_block_zero(sdkp);
34503474
/*
34513475
* set the default to rotational. All non-rotational devices
34523476
* support the block characteristics VPD page, which will

drivers/usb/storage/scsiglue.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ static int slave_configure(struct scsi_device *sdev)
179179
*/
180180
sdev->use_192_bytes_for_3f = 1;
181181

182+
/*
183+
* Some devices report generic values until the media has been
184+
* accessed. Force a READ(10) prior to querying device
185+
* characteristics.
186+
*/
187+
sdev->read_before_ms = 1;
188+
182189
/*
183190
* Some devices don't like MODE SENSE with page=0x3f,
184191
* which is the command used for checking if a device

drivers/usb/storage/uas.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,13 @@ static int uas_slave_configure(struct scsi_device *sdev)
878878
if (devinfo->flags & US_FL_CAPACITY_HEURISTICS)
879879
sdev->guess_capacity = 1;
880880

881+
/*
882+
* Some devices report generic values until the media has been
883+
* accessed. Force a READ(10) prior to querying device
884+
* characteristics.
885+
*/
886+
sdev->read_before_ms = 1;
887+
881888
/*
882889
* Some devices don't like MODE SENSE with page=0x3f,
883890
* which is the command used for checking if a device

include/scsi/scsi_device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ struct scsi_device {
208208
unsigned use_10_for_rw:1; /* first try 10-byte read / write */
209209
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
210210
unsigned set_dbd_for_ms:1; /* Set "DBD" field in mode sense */
211+
unsigned read_before_ms:1; /* perform a READ before MODE SENSE */
211212
unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */
212213
unsigned no_write_same:1; /* no WRITE SAME command */
213214
unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */

0 commit comments

Comments
 (0)