usb: gadget: UMS: support multiple sector sizes

UFS storage often uses a 4096-byte sector size, add support for dynamic
sector sizes based loosely on the Linux implementation.

Support for dynamic sector sizes changes the types used in some
divisions, resulting in the compiler attempting to use
libgcc helpers (__aeabi_ldivmod).
Replace these divisions with calls to lldiv() to handle this correctly.

Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Link: https://lore.kernel.org/r/20240320-b4-qcom-usb-v4-4-41be480172e1@linaro.org
[mkorpershoek: squashed the lldiv() fix from caleb]
Signed-off-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
This commit is contained in:
Caleb Connolly
2024-03-20 14:30:50 +00:00
committed by Mattijs Korpershoek
parent 341a172ef7
commit 304fa0aa44
4 changed files with 66 additions and 53 deletions

View File

@@ -88,10 +88,6 @@ static int ums_init(const char *devtype, const char *devnums_part_str)
if (!strchr(devnum_part_str, ':')) if (!strchr(devnum_part_str, ':'))
partnum = 0; partnum = 0;
/* f_mass_storage.c assumes SECTOR_SIZE sectors */
if (block_dev->blksz != SECTOR_SIZE)
goto cleanup;
ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums)); ums_new = realloc(ums, (ums_count + 1) * sizeof(*ums));
if (!ums_new) if (!ums_new)
goto cleanup; goto cleanup;

View File

@@ -240,6 +240,7 @@
/* #define DUMP_MSGS */ /* #define DUMP_MSGS */
#include <config.h> #include <config.h>
#include <div64.h>
#include <hexdump.h> #include <hexdump.h>
#include <log.h> #include <log.h>
#include <malloc.h> #include <malloc.h>
@@ -724,12 +725,13 @@ static int do_read(struct fsg_common *common)
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL; return -EINVAL;
} }
file_offset = ((loff_t) lba) << 9; file_offset = ((loff_t)lba) << curlun->blkbits;
/* Carry out the file reads */ /* Carry out the file reads */
amount_left = common->data_size_from_cmnd; amount_left = common->data_size_from_cmnd;
if (unlikely(amount_left == 0)) if (unlikely(amount_left == 0)) {
return -EIO; /* No default reply */ return -EIO; /* No default reply */
}
for (;;) { for (;;) {
@@ -768,13 +770,13 @@ static int do_read(struct fsg_common *common)
/* Perform the read */ /* Perform the read */
rc = ums[common->lun].read_sector(&ums[common->lun], rc = ums[common->lun].read_sector(&ums[common->lun],
file_offset / SECTOR_SIZE, lldiv(file_offset, curlun->blksize),
amount / SECTOR_SIZE, lldiv(amount, curlun->blksize),
(char __user *)bh->buf); (char __user *)bh->buf);
if (!rc) if (!rc)
return -EIO; return -EIO;
nread = rc * SECTOR_SIZE; nread = rc * curlun->blksize;
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset, (unsigned long long) file_offset,
@@ -787,7 +789,7 @@ static int do_read(struct fsg_common *common)
} else if (nread < amount) { } else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n", LDBG(curlun, "partial file read: %d/%u\n",
(int) nread, amount); (int) nread, amount);
nread -= (nread & 511); /* Round down to a block */ nread -= (nread & (curlun->blksize - 1)); /* Round down to a block */
} }
file_offset += nread; file_offset += nread;
amount_left -= nread; amount_left -= nread;
@@ -861,7 +863,7 @@ static int do_write(struct fsg_common *common)
/* Carry out the file writes */ /* Carry out the file writes */
get_some_more = 1; get_some_more = 1;
file_offset = usb_offset = ((loff_t) lba) << 9; file_offset = usb_offset = ((loff_t)lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd; amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd; amount_left_to_write = common->data_size_from_cmnd;
@@ -893,7 +895,7 @@ static int do_write(struct fsg_common *common)
curlun->info_valid = 1; curlun->info_valid = 1;
continue; continue;
} }
amount -= (amount & 511); amount -= (amount & (curlun->blksize - 1));
if (amount == 0) { if (amount == 0) {
/* Why were we were asked to transfer a /* Why were we were asked to transfer a
@@ -942,12 +944,12 @@ static int do_write(struct fsg_common *common)
/* Perform the write */ /* Perform the write */
rc = ums[common->lun].write_sector(&ums[common->lun], rc = ums[common->lun].write_sector(&ums[common->lun],
file_offset / SECTOR_SIZE, lldiv(file_offset, curlun->blksize),
amount / SECTOR_SIZE, lldiv(amount, curlun->blksize),
(char __user *)bh->buf); (char __user *)bh->buf);
if (!rc) if (!rc)
return -EIO; return -EIO;
nwritten = rc * SECTOR_SIZE; nwritten = rc * curlun->blksize;
VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset, (unsigned long long) file_offset,
@@ -960,7 +962,7 @@ static int do_write(struct fsg_common *common)
} else if (nwritten < amount) { } else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n", LDBG(curlun, "partial file write: %d/%u\n",
(int) nwritten, amount); (int) nwritten, amount);
nwritten -= (nwritten & 511); nwritten -= (nwritten & (curlun->blksize - 1));
/* Round down to a block */ /* Round down to a block */
} }
file_offset += nwritten; file_offset += nwritten;
@@ -1034,8 +1036,8 @@ static int do_verify(struct fsg_common *common)
return -EIO; /* No default reply */ return -EIO; /* No default reply */
/* Prepare to carry out the file verify */ /* Prepare to carry out the file verify */
amount_left = verification_length << 9; amount_left = verification_length << curlun->blkbits;
file_offset = ((loff_t) lba) << 9; file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */ /* Write out all the dirty buffers before invalidating them */
@@ -1058,12 +1060,12 @@ static int do_verify(struct fsg_common *common)
/* Perform the read */ /* Perform the read */
rc = ums[common->lun].read_sector(&ums[common->lun], rc = ums[common->lun].read_sector(&ums[common->lun],
file_offset / SECTOR_SIZE, lldiv(file_offset, curlun->blksize),
amount / SECTOR_SIZE, lldiv(amount, curlun->blksize),
(char __user *)bh->buf); (char __user *)bh->buf);
if (!rc) if (!rc)
return -EIO; return -EIO;
nread = rc * SECTOR_SIZE; nread = rc * curlun->blksize;
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset, (unsigned long long) file_offset,
@@ -1075,7 +1077,7 @@ static int do_verify(struct fsg_common *common)
} else if (nread < amount) { } else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n", LDBG(curlun, "partial file verify: %d/%u\n",
(int) nread, amount); (int) nread, amount);
nread -= (nread & 511); /* Round down to a sector */ nread -= (nread & (curlun->blksize - 1)); /* Round down to a sector */
} }
if (nread == 0) { if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
@@ -1183,7 +1185,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */ /* Max logical block */
put_unaligned_be32(512, &buf[4]); /* Block length */ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
return 8; return 8;
} }
@@ -1370,7 +1372,7 @@ static int do_read_format_capacities(struct fsg_common *common,
put_unaligned_be32(curlun->num_sectors, &buf[0]); put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */ /* Number of blocks */
put_unaligned_be32(512, &buf[4]); /* Block length */ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
buf[4] = 0x02; /* Current capacity */ buf[4] = 0x02; /* Current capacity */
return 12; return 12;
} }
@@ -1781,6 +1783,16 @@ static int check_command(struct fsg_common *common, int cmnd_size,
return 0; return 0;
} }
/* wrapper of check_command for data size in blocks handling */
static int check_command_size_in_blocks(struct fsg_common *common,
int cmnd_size, enum data_direction data_dir,
unsigned int mask, int needs_medium, const char *name)
{
common->data_size_from_cmnd <<= common->luns[common->lun].blkbits;
return check_command(common, cmnd_size, data_dir,
mask, needs_medium, name);
}
static int do_scsi_command(struct fsg_common *common) static int do_scsi_command(struct fsg_common *common)
{ {
@@ -1865,8 +1877,8 @@ static int do_scsi_command(struct fsg_common *common)
case SC_READ_6: case SC_READ_6:
i = common->cmnd[4]; i = common->cmnd[4];
common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; common->data_size_from_cmnd = (i == 0 ? 256 : i);
reply = check_command(common, 6, DATA_DIR_TO_HOST, reply = check_command_size_in_blocks(common, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1, (7<<1) | (1<<4), 1,
"READ(6)"); "READ(6)");
if (reply == 0) if (reply == 0)
@@ -1875,8 +1887,8 @@ static int do_scsi_command(struct fsg_common *common)
case SC_READ_10: case SC_READ_10:
common->data_size_from_cmnd = common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]) << 9; get_unaligned_be16(&common->cmnd[7]);
reply = check_command(common, 10, DATA_DIR_TO_HOST, reply = check_command_size_in_blocks(common, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1, (1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)"); "READ(10)");
if (reply == 0) if (reply == 0)
@@ -1885,8 +1897,8 @@ static int do_scsi_command(struct fsg_common *common)
case SC_READ_12: case SC_READ_12:
common->data_size_from_cmnd = common->data_size_from_cmnd =
get_unaligned_be32(&common->cmnd[6]) << 9; get_unaligned_be32(&common->cmnd[6]);
reply = check_command(common, 12, DATA_DIR_TO_HOST, reply = check_command_size_in_blocks(common, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1, (1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)"); "READ(12)");
if (reply == 0) if (reply == 0)
@@ -1983,8 +1995,8 @@ static int do_scsi_command(struct fsg_common *common)
case SC_WRITE_6: case SC_WRITE_6:
i = common->cmnd[4]; i = common->cmnd[4];
common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; common->data_size_from_cmnd = (i == 0 ? 256 : i);
reply = check_command(common, 6, DATA_DIR_FROM_HOST, reply = check_command_size_in_blocks(common, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1, (7<<1) | (1<<4), 1,
"WRITE(6)"); "WRITE(6)");
if (reply == 0) if (reply == 0)
@@ -1993,8 +2005,8 @@ static int do_scsi_command(struct fsg_common *common)
case SC_WRITE_10: case SC_WRITE_10:
common->data_size_from_cmnd = common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]) << 9; get_unaligned_be16(&common->cmnd[7]);
reply = check_command(common, 10, DATA_DIR_FROM_HOST, reply = check_command_size_in_blocks(common, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1, (1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)"); "WRITE(10)");
if (reply == 0) if (reply == 0)
@@ -2003,8 +2015,8 @@ static int do_scsi_command(struct fsg_common *common)
case SC_WRITE_12: case SC_WRITE_12:
common->data_size_from_cmnd = common->data_size_from_cmnd =
get_unaligned_be32(&common->cmnd[6]) << 9; get_unaligned_be32(&common->cmnd[6]);
reply = check_command(common, 12, DATA_DIR_FROM_HOST, reply = check_command_size_in_blocks(common, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1, (1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)"); "WRITE(12)");
if (reply == 0) if (reply == 0)
@@ -2497,7 +2509,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
for (i = 0; i < nluns; i++) { for (i = 0; i < nluns; i++) {
common->luns[i].removable = 1; common->luns[i].removable = 1;
rc = fsg_lun_open(&common->luns[i], ums[i].num_sectors, ""); rc = fsg_lun_open(&common->luns[i], ums[i].num_sectors, ums->block_dev.blksz, "");
if (rc) if (rc)
goto error_luns; goto error_luns;
} }

View File

@@ -269,6 +269,7 @@ struct device_attribute { int i; };
#define ETOOSMALL 525 #define ETOOSMALL 525
#include <log.h> #include <log.h>
#include <linux/log2.h>
#include <usb_mass_storage.h> #include <usb_mass_storage.h>
#include <dm/device_compat.h> #include <dm/device_compat.h>
@@ -290,6 +291,8 @@ struct fsg_lun {
u32 sense_data; u32 sense_data;
u32 sense_data_info; u32 sense_data_info;
u32 unit_attention_data; u32 unit_attention_data;
unsigned int blkbits;
unsigned int blksize; /* logical block size of bound block device */
struct device dev; struct device dev;
}; };
@@ -566,7 +569,7 @@ static struct usb_gadget_strings fsg_stringtab = {
*/ */
static int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors, static int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors,
const char *filename) unsigned int sector_size, const char *filename)
{ {
int ro; int ro;
@@ -574,9 +577,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, unsigned int num_sectors,
ro = curlun->initially_ro; ro = curlun->initially_ro;
curlun->ro = ro; curlun->ro = ro;
curlun->file_length = num_sectors << 9; curlun->file_length = num_sectors * sector_size;
curlun->num_sectors = num_sectors; curlun->num_sectors = num_sectors;
debug("open backing file: %s\n", filename); curlun->blksize = sector_size;
curlun->blkbits = order_base_2(sector_size >> 9) + 9;
debug("blksize: %u\n", sector_size);
debug("open backing file: '%s'\n", filename);
return 0; return 0;
} }

View File

@@ -7,7 +7,6 @@
#ifndef __USB_MASS_STORAGE_H__ #ifndef __USB_MASS_STORAGE_H__
#define __USB_MASS_STORAGE_H__ #define __USB_MASS_STORAGE_H__
#define SECTOR_SIZE 0x200
#include <part.h> #include <part.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>