[PATCH] cmd: ums: Switch HW partition before block access

Christoph Niedermaier cniedermaier at dh-electronics.com
Fri Apr 24 17:21:33 CEST 2026


From: Marek Vasut <marex at nabladev.com>
Sent: Friday, April 24, 2026 5:34 AM
> An UMS session with eMMC device specifier "ums C mmc dev.part1,dev.part2"
> exposes the same eMMC HW partition 'part2' twice instead of exposing both
> HW partitions 'part1' and 'part2'. Fix this by switching the eMMC HW
> partition before block device read/write access.
> 
> An eMMC is represented by a single struct blk_desc, with the currently
> selected HW partition being stored in this struct blk_desc. Each call to
> part_get_info_by_dev_and_name_or_num() with partition string dev[.partN]
> does trigger HW partition switch by calling blk_get_device_part_str() ->
> blk_get_device_part_str() -> get_dev_hwpart() -> get_dev_hwpart() ->
> blk_dselect_hwpart(). The ums_init() iterates over the device specifier
> string and calls part_get_info_by_dev_and_name_or_num() in a loop for
> each dev[.partN] entry used as the partition string. If the device
> specifier string contains more than one dev[.partN] partition strings
> for the same dev device, then it is the HW partition described in the
> last dev[.partN] partition string entry that is accessed for all dev
> device partition strings in the device specifier string, because that
> last dev[.partN] partition string entry was the last one that triggered
> blk_dselect_hwpart() call for that device.
> 
> To access the expected HW partition for every dev[.partN] partition string
> entry, it is necessary to call blk_dselect_hwpart() before each block read
> or write. Store HW partition described for each dev[.partN] partition string
> in struct ums and use the stored value to make it so.
> 
> The blk_dselect_hwpart() does test whether the currently selected HW
> partition is already configured in hardware and does not reconfigure
> the hardware if that is the case, therefore for the majority of block
> reads and writes, blk_dselect_hwpart() is a no-op with negligible
> performance impact.
> 
> Example reproducer is listed below. The last sector of both eMMC HW BOOT
> partitions is populated with distinct test pattern and UMS is launched:
> 
> "
> => mmc dev 1 1 ; mmc read $loadaddr 0x1fff 1 ; md $loadaddr 4
> switch to partitions #1, OK
> mmc1(part 1) is current device
> MMC read: dev # 1, block # 8191, count 1 ... 1 blocks read: OK
> 84000000: 1234abcd 1234abcd 1234abcd 1234abcd  ..4...4...4...4.
> 
> => mmc dev 1 2 ; mmc read $loadaddr 0x1fff 1 ; md $loadaddr 4
> switch to partitions #2, OK
> mmc1(part 2) is current device
> MMC read: dev # 1, block # 8191, count 1 ... 1 blocks read: OK
> 84000000: 567890ef 567890ef 567890ef 567890ef  ..xV..xV..xV..xV
> 
> => ums 0 mmc 1.1,1.2
> UMS: LUN 0, dev mmc 1, hwpart 1, sector 0x0, count 0x2000
> UMS: LUN 1, dev mmc 1, hwpart 2, sector 0x0, count 0x2000
> "
> 
> Read of the two block devices on host without this fix produces
> identical data present in HW BOOT partition 2:
> 
> "
> $ dd if=/dev/sdX of=mmc-a.bin ; dd if=/dev/sdY of=mmc-b.bin
> $ hexdump -C mmc-a.bin | tail -n 3 | head -n 1 ; \
>   hexdump -C mmc-b.bin | tail -n 3 | head -n 1
> 003ffe00  ef 90 78 56 ef 90 78 56  ef 90 78 56 ef 90 78 56  |..xV..xV..xV..xV|
> 003ffe00  ef 90 78 56 ef 90 78 56  ef 90 78 56 ef 90 78 56  |..xV..xV..xV..xV|
> "
> 
> Read of the two block devices on host with this fix produces the
> expected distinct data from either HW BOOT partition 1 or 2:
> 
> "
> $ dd if=/dev/sdX of=mmc-a.bin ; dd if=/dev/sdY of=mmc-b.bin
> $ hexdump -C mmc-a.bin | tail -n 3 | head -n 1 ; \
>   hexdump -C mmc-b.bin | tail -n 3 | head -n 1
> 003ffe00  cd ab 34 12 cd ab 34 12  cd ab 34 12 cd ab 34 12  |..4...4...4...4.|
> 003ffe00  ef 90 78 56 ef 90 78 56  ef 90 78 56 ef 90 78 56  |..xV..xV..xV..xV|
> "
> 
> Reported-by: Christoph Niedermaier <cniedermaier at dh-electronics.com>
> Signed-off-by: Marek Vasut <marex at nabladev.com>
> ---
> Cc: Lukasz Majewski <lukma at denx.de>
> Cc: Mattijs Korpershoek <mkorpershoek at kernel.org>
> Cc: Tom Rini <trini at konsulko.com>
> Cc: u-boot at lists.denx.de
> ---
>  cmd/usb_mass_storage.c     | 11 +++++++++++
>  include/usb_mass_storage.h |  1 +
>  2 files changed, 12 insertions(+)
> 
> diff --git a/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c
> index 47e8b70cd10..e8b87045bdc 100644
> --- a/cmd/usb_mass_storage.c
> +++ b/cmd/usb_mass_storage.c
> @@ -24,6 +24,11 @@ static int ums_read_sector(struct ums *ums_dev,
>  {
>         struct blk_desc *block_dev = &ums_dev->block_dev;
>         lbaint_t blkstart = start + ums_dev->start_sector;
> +       int ret;
> +
> +       ret = blk_dselect_hwpart(block_dev, ums_dev->hwpart);
> +       if (ret && ret != -ENOSYS)
> +               return ret;
> 
>         return blk_dread(block_dev, blkstart, blkcnt, buf);
>  }
> @@ -33,6 +38,11 @@ static int ums_write_sector(struct ums *ums_dev,
>  {
>         struct blk_desc *block_dev = &ums_dev->block_dev;
>         lbaint_t blkstart = start + ums_dev->start_sector;
> +       int ret;
> +
> +       ret = blk_dselect_hwpart(block_dev, ums_dev->hwpart);
> +       if (ret && ret != -ENOSYS)
> +               return ret;
> 
>         return blk_dwrite(block_dev, blkstart, blkcnt, buf);
>  }
> @@ -110,6 +120,7 @@ static int ums_init(const char *devtype, const char *devnums_part_str)
>                 snprintf(name, UMS_NAME_LEN, "UMS disk %d", ums_count);
>                 ums[ums_count].name = name;
>                 ums[ums_count].block_dev = *block_dev;
> +               ums[ums_count].hwpart = block_dev->hwpart;
> 
>                 printf("UMS: LUN %d, dev %s %d, hwpart %d, sector %#x, count %#x\n",
>                        ums_count, devtype, ums[ums_count].block_dev.devnum,
> diff --git a/include/usb_mass_storage.h b/include/usb_mass_storage.h
> index 6d83d93cad7..9be704ea8b7 100644
> --- a/include/usb_mass_storage.h
> +++ b/include/usb_mass_storage.h
> @@ -22,6 +22,7 @@ struct ums {
>         unsigned int num_sectors;
>         const char *name;
>         struct blk_desc block_dev;
> +       int hwpart;
>  };
> 
>  int fsg_init(struct ums *ums_devs, int count, struct udevice *udc);

Tested-by: Christoph Niedermaier <cniedermaier at dh-electronics.com>

Thanks and regards
Christoph


More information about the U-Boot mailing list