1

My usb storage device has a 64kB (limited by hardware) buffer used to cache reads/writes which means it can only cache up to 128 blocks(512B) of memory. The SCSI Write-10 command has a total-blocks field that can be up to 256 blocks (128kB). When originally testing the product on Windows 11 it never writes more than 128 blocks at a time but when tested on Linux it sometimes writes more than 128 blocks, which causes the microcontroller to crash.

Is there a way to tell the host OS not to request more than 128 blocks?

I have implemented block limit VPD page, and it works well on Windows 10/11. I even set the block limit to be 64 blocks, it's OK! However, on Linux or MacOS, the host does not appear to be running the block limits command. So what can I do?

7
  • Please provide enough code so others can better understand or reproduce the problem.
    – Community Bot
    Commented Jul 10 at 14:33
  • Have you tried to write 128 to max_sectors sysfs file in Linux? planykao.blogspot.com/2010/10/linux-usb-maxsectors.html
    – 0andriy
    Commented Jul 11 at 11:14
  • Thanks for your reply. I have tried this method and this problem can indeed be solved to some extent. But I want some ways that don't need to change the Linux kernel. Just like what have been implemented on Windows(SCSI inquiry with VPD page = 0xB0 block limit ) Commented Jul 11 at 11:47
  • When answering in the comments, use @nickname approach to notify the respective user.
    – 0andriy
    Commented Jul 11 at 20:33
  • @0andriy Sorry, I'm a beginner. Thanks for your reminding. Commented Jul 12 at 0:34

1 Answer 1

0

Unfortunately, there really isn't great control over the max read and write sizes for USB storage devices. I think your best bet may be to override the unusual_devs flags for your device by adding a quirk to the usb_storage module. There's an existing flag US_FL_MAX_SECTORS_64 that limits it to 64 sectors, which, while not optimal, should make the device actually work. This winds up being implemented in drivers/usb/storage/scsiglue.c:slave_configure():

/*
 * Many devices have trouble transferring more than 32KB at a time,
 * while others have trouble with more than 64K. At this time we
 * are limiting both to 32K (64 sectores).
 */
if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) {
    unsigned int max_sectors = 64;

    if (us->fflags & US_FL_MAX_SECTORS_MIN)
        max_sectors = PAGE_SIZE >> 9;
    if (queue_max_hw_sectors(sdev->request_queue) > max_sectors)
        blk_queue_max_hw_sectors(sdev->request_queue,
                      max_sectors);

You set this flag by adding it into the quirks option in the module parameters. If your device's VID and PID are 0x1234 and 0x5678, then you'd do this:

echo 'options usb-storage quirks=1234:5678:m' | sudo tee -a /etc/modprobe.d/my-usb-device-quirks.conf

Then reload the module.

2
  • Thanks for your reply. I didn't make that clear in the question. Actually, I don't want to make any change on the Linux host. What I expect is that the device can be plugged and played without any other operation. But your reply is a new view for me. I have the source code of my storage device. Could I make some changes at the source code in advance to make it? Commented Jul 12 at 0:41
  • @user26314708 I don't think so, sadly. At least, I'm not aware of a way. This is a change that would have to be made to the kernel itself or in the configuration of the module. Commented Jul 12 at 1:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.