From: Ana Bobillo <[email protected]>

usb_stor_get_info() takes the block size from the READ CAPACITY reply of
the device as it is. Once blk_post_probe() refuses a block size that
blk_valid_blksz() rejects, at the end of this series, such a device would
fail to probe there, and usb_stor_probe_device() would stop, skipping the
other LUNs of the device.

Check the block size where it is read, and treat a LUN reporting one
that blk_valid_blksz() rejects as unusable, as for a LUN that is not
ready, saying which LUN is skipped. This also covers the legacy (non-BLK)
path, which calls part_init() itself.

Add a test where the sandbox flash stick reports an unsupported block
size.

Signed-off-by: Ana Bobillo <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---
(no changes since v2)

Changes in v2:
- Move the READ CAPACITY fallback fix to a patch of its own (Simon)
- Name the LUN in the message (Simon)
- Check for that message in the test, with UTF_CONSOLE (Simon)

 arch/sandbox/include/asm/test.h  | 10 +++++++
 common/usb_storage.c             |  5 ++++
 drivers/usb/emul/sandbox_flash.c |  8 +++++
 test/dm/usb.c                    | 51 ++++++++++++++++++++++++++++++++
 4 files changed, 74 insertions(+)

diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 0438790028b..e5590d01a92 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -123,6 +123,16 @@ long sandbox_i2c_rtc_get_set_base_time(struct udevice 
*dev, long base_time);
 
 int sandbox_usb_keyb_add_string(struct udevice *dev, const char *str);
 
+/**
+ * sandbox_flash_set_block_size() - Set the block size a flash stick reports
+ *
+ * @dev:       USB flash-stick emulator
+ * @block_size:        Block size in bytes
+ *
+ * The host reads it when it next probes the stick's mass-storage device.
+ */
+void sandbox_flash_set_block_size(struct udevice *dev, int block_size);
+
 /**
  * sandbox_osd_get_mem() - get the internal memory of a sandbox OSD
  *
diff --git a/common/usb_storage.c b/common/usb_storage.c
index f7c96195b59..6bada2b309b 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -1513,6 +1513,11 @@ int usb_stor_get_info(struct usb_device *dev, struct 
us_data *ss,
        blksz = be32_to_cpu(cap[1]);
 
        debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz);
+       if (!blk_valid_blksz(blksz)) {
+               printf("LUN %d: unsupported block size %u, skipping\n",
+                      dev_desc->lun, blksz);
+               return 0;
+       }
        dev_desc->lba = capacity;
        dev_desc->blksz = blksz;
        dev_desc->log2blksz = LOG2(dev_desc->blksz);
diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c
index b5176bb30ce..02e0901050f 100644
--- a/drivers/usb/emul/sandbox_flash.c
+++ b/drivers/usb/emul/sandbox_flash.c
@@ -13,6 +13,7 @@
 #include <scsi.h>
 #include <scsi_emul.h>
 #include <usb.h>
+#include <asm/test.h>
 
 /*
  * This driver emulates a flash stick using the UFI command specification and
@@ -357,6 +358,13 @@ static int sandbox_flash_probe(struct udevice *dev)
        return 0;
 }
 
+void sandbox_flash_set_block_size(struct udevice *dev, int block_size)
+{
+       struct sandbox_flash_priv *priv = dev_get_priv(dev);
+
+       priv->eminfo.block_size = block_size;
+}
+
 static int sandbox_flash_remove(struct udevice *dev)
 {
        struct sandbox_flash_priv *priv = dev_get_priv(dev);
diff --git a/test/dm/usb.c b/test/dm/usb.c
index fa894c1096e..79a85b11910 100644
--- a/test/dm/usb.c
+++ b/test/dm/usb.c
@@ -84,6 +84,57 @@ static int dm_test_usb_flash(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_usb_flash, UTF_SCAN_PDATA | UTF_SCAN_FDT);
 
+/* Test that a flash stick reporting an unsupported block size is refused */
+static int dm_test_usb_flash_blksz(struct unit_test_state *uts)
+{
+       static const struct {
+               int blksz;
+               bool ok;
+       } cases[] = {
+               { 256, false },
+               { 520, false },
+               { 2 * BLK_MAX_BLKSZ, false },
+               { SZ_4K, true },
+       };
+       struct udevice *dev, *emul, *blk;
+       struct blk_desc *desc;
+       int i, ret;
+
+       state_set_skip_delays(true);
+       ut_assertok(usb_init());
+       ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev));
+       ut_assertok(uclass_get_device_by_name(UCLASS_USB_EMUL, "flash-stick@0",
+                                             &emul));
+
+       for (i = 0; i < ARRAY_SIZE(cases); i++) {
+               /* Probe the stick again, so that it reads the block size */
+               console_record_reset();
+               sandbox_flash_set_block_size(emul, cases[i].blksz);
+               ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
+               ut_assertok(device_chld_unbind(dev, NULL));
+               ut_assertok(device_probe(dev));
+
+               ret = device_find_first_child_by_uclass(dev, UCLASS_BLK, &blk);
+               if (!cases[i].ok) {
+                       /* usb_stor_get_info() refuses the LUN */
+                       ut_assert_nextline("LUN 0: unsupported block size %d, 
skipping",
+                                          cases[i].blksz);
+                       ut_assert_console_end();
+                       ut_asserteq(-ENODEV, ret);
+                       continue;
+               }
+               ut_assert_console_end();
+               ut_assertok(ret);
+               desc = dev_get_uclass_plat(blk);
+               ut_asserteq(cases[i].blksz, desc->blksz);
+       }
+
+       ut_assertok(usb_stop());
+
+       return 0;
+}
+DM_TEST(dm_test_usb_flash_blksz, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE);
+
 /* test that we can handle multiple storage devices */
 static int dm_test_usb_multi(struct unit_test_state *uts)
 {

Reply via email to