From: Ana Bobillo <[email protected]>

scsi_detect_dev() takes the block size from the READ CAPACITY reply of
the device as it is. do_scsi_scan_one() then hands it to
blk_create_devicef() as an int, which drops the upper bits of the
unsigned long, so the block layer may not even see the value the device
reported.

Check the block size where it is read, so that no block device is
created for a disk reporting one that blk_valid_blksz() rejects.

Add a test where the sandbox SCSI disk reports an unsupported block
size.

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

 arch/sandbox/include/asm/test.h | 10 +++++++++
 drivers/scsi/sandbox_scsi.c     |  8 +++++++
 drivers/scsi/scsi.c             |  4 ++++
 test/dm/scsi.c                  | 37 +++++++++++++++++++++++++++++++++
 4 files changed, 59 insertions(+)

diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index e5590d01a92..76e2f11b059 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -133,6 +133,16 @@ int sandbox_usb_keyb_add_string(struct udevice *dev, const 
char *str);
  */
 void sandbox_flash_set_block_size(struct udevice *dev, int block_size);
 
+/**
+ * sandbox_scsi_set_block_size() - Set the block size a SCSI disk reports
+ *
+ * @dev:       Sandbox SCSI controller
+ * @block_size:        Block size in bytes
+ *
+ * The host reads it when it next scans the bus.
+ */
+void sandbox_scsi_set_block_size(struct udevice *dev, int block_size);
+
 /**
  * sandbox_osd_get_mem() - get the internal memory of a sandbox OSD
  *
diff --git a/drivers/scsi/sandbox_scsi.c b/drivers/scsi/sandbox_scsi.c
index 5f0b01d86d5..34fc7cda915 100644
--- a/drivers/scsi/sandbox_scsi.c
+++ b/drivers/scsi/sandbox_scsi.c
@@ -14,6 +14,7 @@
 #include <malloc.h>
 #include <scsi.h>
 #include <scsi_emul.h>
+#include <asm/test.h>
 
 enum {
        SANDBOX_SCSI_BLOCK_LEN          = 512,
@@ -118,6 +119,13 @@ static int sandbox_scsi_probe(struct udevice *dev)
        return 0;
 }
 
+void sandbox_scsi_set_block_size(struct udevice *dev, int block_size)
+{
+       struct sandbox_scsi_priv *priv = dev_get_priv(dev);
+
+       priv->eminfo.block_size = block_size;
+}
+
 static int sandbox_scsi_remove(struct udevice *dev)
 {
        struct sandbox_scsi_priv *priv = dev_get_priv(dev);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 736dccfcbff..55d68cc701a 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -543,6 +543,10 @@ static int scsi_detect_dev(struct udevice *dev, int 
target, int lun,
                scsi_print_error(pccb);
                return -EINVAL;
        }
+       if (!blk_valid_blksz(blksz)) {
+               printf("Unsupported block size %lu\n", blksz);
+               return -EINVAL;
+       }
        dev_desc->lba = capacity;
        dev_desc->blksz = blksz;
        dev_desc->log2blksz = LOG2(dev_desc->blksz);
diff --git a/test/dm/scsi.c b/test/dm/scsi.c
index 66859c991df..7617ee54893 100644
--- a/test/dm/scsi.c
+++ b/test/dm/scsi.c
@@ -6,6 +6,7 @@
 #include <dm.h>
 #include <part.h>
 #include <scsi.h>
+#include <asm/test.h>
 #include <dm/test.h>
 #include <test/test.h>
 #include <test/ut.h>
@@ -36,3 +37,39 @@ static int dm_test_scsi_base(struct unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_scsi_base, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
+/* Test that a disk reporting an unsupported block size is refused */
+static int dm_test_scsi_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, *blk;
+       struct blk_desc *desc;
+       int i, ret;
+
+       ut_assertok(uclass_first_device_err(UCLASS_SCSI, &dev));
+
+       for (i = 0; i < ARRAY_SIZE(cases); i++) {
+               sandbox_scsi_set_block_size(dev, cases[i].blksz);
+               ut_assertok(scsi_scan(false));
+
+               ret = device_find_first_child_by_uclass(dev, UCLASS_BLK, &blk);
+               if (!cases[i].ok) {
+                       ut_asserteq(-ENODEV, ret);
+                       continue;
+               }
+               ut_assertok(ret);
+               desc = dev_get_uclass_plat(blk);
+               ut_asserteq(cases[i].blksz, desc->blksz);
+       }
+
+       return 0;
+}
+DM_TEST(dm_test_scsi_blksz, UTF_SCAN_PDATA | UTF_SCAN_FDT);

Reply via email to