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 50e7d749921..a732db726ac 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);
