Mass Storage¶
Roles: device and host. TinyUSB implements the USB Mass Storage Bulk-Only Transport (BOT) and common SCSI commands. It exposes logical blocks; a filesystem such as FatFs is a separate application layer.
Device¶
Enable CFG_TUD_MSC and set CFG_TUD_MSC_EP_BUFSIZE. The driver supports
a single Mass Storage function, so add one TUD_MSC_DESCRIPTOR. Multiple
logical units (LUNs) share that function and are selected through the lun
callback argument.
CFG_TUD_MSC_EP_BUFSIZE has no default and is required when MSC is enabled.
It is the class transfer-buffer size, not the media capacity. Using at least
one logical block is efficient; larger values improve large transfers at the
cost of static RAM. It must be at least 64 and below 65535 bytes, and should be
a multiple of the bulk endpoint’s maximum packet size (512 at high speed) so
that READ10/WRITE10 data is split only on packet boundaries. Keep it
consistent with controller/DMA constraints.
The application must implement tud_msc_test_unit_ready_cb(),
tud_msc_capacity_cb(), tud_msc_read10_cb(), tud_msc_write10_cb()
and tud_msc_scsi_cb(). The other callbacks below have weak defaults.
Callback |
Purpose |
|---|---|
|
Fill the INQUIRY response and return its length. The older
|
|
Report whether media is present and usable. |
|
Return the logical block count and block size. |
|
Read |
|
Write |
|
Handle commands not implemented by the class driver. |
|
Returns the number of LUNs (default 1); the driver reports this minus one to the host. Implement it for multiple LUNs. |
|
Reports write protection before WRITE10. |
|
Handles load/eject and start/stop requests, including safe-eject policy. |
Read and write callbacks may cover only part of a logical block; honor both
lba and offset instead of assuming one callback per block.
TUD_MSC_RET_ERROR from read10/write10 overwrites the stored sense with
NOT READY / MEDIUM NOT PRESENT. For other command callbacks, such as
tud_msc_scsi_cb(), set useful sense data with tud_msc_set_sense()
before returning an error.
For temporarily busy media, return TUD_MSC_RET_BUSY; TinyUSB will invoke
the callback again with the same parameters. For true background I/O, return
TUD_MSC_RET_ASYNC and later call tud_msc_async_io_done() with the byte
count or error. Do not report a write complete until data has reached the
durability level promised by the product: finish that storage work before
returning success from tud_msc_write10_cb() or calling
tud_msc_async_io_done(). tud_msc_write10_complete_cb() runs only after
the host has received the command status, so a cache flush there is
best-effort and cannot make an acknowledged write durable.
See CDC + MSC for a RAM disk and MSC Dual LUN for multiple LUNs.
Host¶
Set CFG_TUH_MSC to 1 to enable the driver; it keeps state for every device
address, so CFG_TUH_DEVICE_MAX sets how many Mass Storage devices can be
used at once. CFG_TUH_MSC_MAXLUN is the LUN limit per device. After
tuh_msc_mount_cb(dev_addr), query cached geometry with
tuh_msc_get_block_count() and tuh_msc_get_block_size().
Pass a LUN below both tuh_msc_get_maxlun() and CFG_TUH_MSC_MAXLUN: the
LUN argument is not range-checked, and tuh_msc_get_maxlun() returns the
LUN count the device reports without clamping it. CFG_TUH_MSC_MAXLUN
defaults to 4 and allocates cached state per possible LUN for each of the
CFG_TUH_DEVICE_MAX addresses. Enumeration only reads the geometry of
LUN 0, so other LUNs read back as 0.
tuh_msc_read10() and tuh_msc_write10() are asynchronous. Keep the
buffer valid, correctly aligned, cache coherent, and accessible to the USB
controller until the tuh_msc_complete_cb_t callback runs. Check
tuh_msc_ready() before starting another command and check
cb_data->csw->status in the completion callback. The callback has no
separate USB transfer result, so it does not report transfer failures on its
own.
Host API or callback |
What it does |
|---|---|
|
Tests whether the MSC device is present or currently able to accept a new SCSI command. |
|
Returns the device-reported LUN count and the geometry cached during enumeration (LUN 0 only). |
|
Queues an integral number of logical blocks and completes through the
supplied callback. Returns |
|
Queues standard SCSI identification or detailed-error requests into an application-owned response buffer. |
|
Queues a caller-built command block wrapper for commands without a convenience API. |
|
Announces cached capacity availability or invalidates all filesystem and media state for the address. |
TinyUSB does not mount a filesystem automatically. Connect the sector API to
your filesystem’s disk I/O layer and invalidate that state in
tuh_msc_umount_cb(). The MSC File Explorer
example demonstrates this with FatFs.
Practical notes¶
Hosts cache filesystem data. Physical removal or firmware reset without an eject/unmount can lose data even when USB transfers succeeded.
Use the medium-present and write-protect responses consistently; mismatched capacity or readiness information causes repeated SCSI recovery traffic.
Validate every LUN and block range before calculating a storage address.
Specification used: USB Mass Storage Class Bulk-Only Transport, Revision 1.0. Command formats and sense data come from the applicable SCSI command set.