Files
rt-thread/documentation/6.components/device-driver/block/blk.md
T
GuEe-GUI cfda3b3d1a
doc_doxygen / doxygen_doc generate (push) Has been cancelled
doc_doxygen / deploy (push) Has been cancelled
[docs] device-driver: add DM subsystem docs and expand INDEX
Add Doxygen pages for RT-Thread device-model drivers: platform/OFW,
DM core (bus, dm, power), clk/regulator/reset/power-domain, PCI/PIC,
Phye, DMA/hwcache, block/SCSI/ATA/NVMe/UFS/SDIO, SCMI, RPMsg,
mailbox, NVMem, NUMA, syscon, thermal, input/LED/IIO/graphic, and
related power/charger/supply docs.
Expand device-driver INDEX.md with ~90 @subpage entries so all new
pages appear in the driver chapter navigation.
Update existing UART/SPI/RTC/pin/framework/dtc pages: UART docs moved
from serial/ to uart/ (uart + uart_dm + uart_earlycon); SPI and RTC
gain DM companion pages; pin links to pin_dm; framework points at DM
topics.
Focus on registration/probe flow and in-tree APIs; no standalone
VirtIO subsystem page (transport code still incomplete).
Test plan: build Doxygen for documentation/ and verify device-driver
INDEX links resolve without missing @ref/@subpage warnings.

Signed-off-by: GuEe-GUI <2991707448@qq.com>
2026-05-28 16:09:55 +08:00

11 KiB
Raw Blame History

@page page_device_blk Block layer (blk)

Block storage subsystem

The blk layer turns a single physical storage backend into one or more RT-Thread block devices that applications and DFS can open, read/write by sector, and control with standard IOCTLs. Hardware drivers implement struct rt_blk_disk_ops on an embedded struct rt_blk_disk; the core registers the disk, scans partition tables, and creates child volumes (struct rt_blk_device) such as sda1 or mmcsd0p1.

Header: components/drivers/include/drivers/blk.h. IOCTLs and geometry: components/drivers/include/drivers/classes/block.h. Core: components/drivers/block/blk.c, blk_dev.c, blk_partition.c.

Architecture

  [NVMe / SDIO / SCSI SD / … driver]
              │ rt_blk_disk_ops (read/write/getgeome/…)
              ▼
       struct rt_blk_disk  ← rt_hw_blk_disk_register()
              │ rt_blk_disk_probe_partition()  (inside register)
              ▼
   struct rt_blk_device × N  ← disk_add_blk_dev() / blk_dev.c
              │ rt_device_read/write (sector-relative)
              ▼
        DFS / applications / POSIX devio
Layer Struct Document
Physical disk struct rt_blk_disk @ref page_device_disk
Partition table (on-disk metadata) @ref page_device_partitions
Volume (partition) struct rt_blk_device This page — application-facing nodes

Both disk and volume nodes use RT_Device_Class_Block. Applications normally open volumes (sda1), not the raw disk device, unless probing created a single full-disk volume with partno == 0.

Kconfig

Option Role
RT_USING_BLK Master switch for components/drivers/block/
RT_BLK_PARTITION_EFI GPT / protective MBR parser (partitions/efi.c)
RT_BLK_PARTITION_DFS Legacy DFS superblock layout on sector 0 (partitions/dfs.c, needs RT_USING_DFS)

rt_hw_blk_disk_register always calls rt_blk_disk_probe_partition; partition scan errors are ignored (register still succeeds).


Access block devices (applications)

Same usage model as other char/block devices: find → open → read/write → control → close. Sector index is 0-based within the opened device (for a partition device, sector 0 is the start of that partition).

Find device

rt_device_t rt_device_find(const char *name);
Parameter Description
name Volume name, e.g. sda0, sda1, mmcsd0, nvme0n1 (from DM naming — see @ref page_device_disk)
Return Device handle, or RT_NULL if not found
#define BLK_DEV_NAME   "sda1"
rt_device_t blk = rt_device_find(BLK_DEV_NAME);

Open / close

rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag);
rt_err_t rt_device_close(rt_device_t dev);
oflag Notes
RT_DEVICE_OFLAG_RDONLY Always valid
RT_DEVICE_OFLAG_WRONLY Fails on disk/volume if backend is read-only (ops->write == NULL sets read_only)

Opening a partition device (rt_blk_device) internally opens the parent disk (blk_dev_openrt_device_open(&blk->disk->parent)).

Read / write (sectors)

rt_ssize_t rt_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_ssize_t rt_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);

For block class devices, pos is the starting sector number, size is sector count (not bytes).

Parameter Partition volume Whole disk
pos 0 … sector_count - 1 (relative to partition) 0 … disk capacity 1
size Sectors to transfer Same
Return Sectors actually transferred, or negative error Same
#define SECTOR_SIZE   512
rt_uint8_t buf[SECTOR_SIZE];

if (rt_device_read(blk, 0, buf, 1) == 1)
{
    /* one sector at LBA 0 of this partition */
}

Control (IOCTL)

rt_err_t rt_device_control(rt_device_t dev, int cmd, void *args);

Standard commands (classes/block.h)

Command args type Partition volume Raw disk
RT_DEVICE_CTRL_BLK_GETGEOME struct rt_device_blk_geometry * sector_count = partition size; bytes_per_sector from disk Full disk geometry
RT_DEVICE_CTRL_BLK_SYNC ignored Flushes parent disk ops->sync under lock
RT_DEVICE_CTRL_BLK_ERASE ignored Only if disk->partitions <= 1; else -RT_EIO May remove all partitions then ops->erase
RT_DEVICE_CTRL_BLK_AUTOREFRESH rt_bool_t * / pointer treated as enable flag Delegates to disk if single partition ops->autorefresh
RT_DEVICE_CTRL_BLK_PARTITION struct dfs_partition * Copies blk->partition -RT_EINVAL on disk node

DFS helpers (blk_dfs.h)

Command Role
RT_DEVICE_CTRL_BLK_SSIZEGET Fills *(rt_off_t *)args with bytes per sector
RT_DEVICE_CTRL_ALL_BLK_SSIZEGET Total byte size = sectors × bytes_per_sector (used by DFS v2 POSIX layer)

Vendor-specific IOCTLs pass through disk->ops->control(disk, blk, cmd, args) on the volume path; on the disk path blk is NULL.

Geometry structure

struct rt_device_blk_geometry {
    rt_uint64_t sector_count;
    rt_uint32_t bytes_per_sector;
    rt_uint32_t block_size;   /* erase block size for flash-style media */
};

Partition volumes (rt_blk_device)

Defined in blk.h when DFS headers are available.

Field Meaning
disk Parent rt_blk_disk
sector_start / sector_count Slice on the physical disk (LBA range)
partno Index used in device name (%sp%d / %s%d)
partition struct dfs_partition for DFS mount; partition.lockdisk->usr_lock
list Node on disk->part_nodes

blk_dev.c forwarding

Operation Behavior
read/write Translates to disk->parent at sector_start + pos
GETGEOME Disk geometry with sector_count replaced by partition length
SYNC rt_device_control(&disk->parent, SYNC)
ERASE / AUTOREFRESH Allowed only when disk->partitions <= 1

Device naming (DM)

disk_add_blk_dev (blk_dev.c):

  • If disk names last character is 'a''z' (e.g. sda): volume name sdap1 (%sp%d).
  • Otherwise (e.g. mmcsd0, nvme0n1): mmcsd0p1, nvme0n1p2 (%s%d).

Each volume gets its own rt_dm_ida_alloc(disk->ida) slot under the same master_id as the disk.


DFS integration

When RT_USING_DFS and RT_USING_POSIX_DEVIO (and DFS v2 as implemented in-tree), blk_dfs.c registers file operations that:

  1. On open: GETGEOME + ALL_BLK_SSIZEGET for file size.
  2. On read/write: byte-oriented I/O with unaligned head/tail sector handling via a bounce sector buffer.
  3. ioctl: forwards to rt_device_control.

Mount the volume device name (not the disk) with the appropriate filesystem driver after partition probe.


Drivers already using blk

These drivers embed struct rt_blk_disk, set ops, ida, and call rt_hw_blk_disk_register when media is present:

Driver File Typical name Notable rt_blk_disk fields
NVMe nvme/nvme.c nvme0n1, … parallel_io = RT_TRUE, per-namespace disk, max_partitions = RT_BLK_PARTITION_MAX
SDIO/MMC sdio/dev_block.c host name / mmcsd0p* removable, max_partitions = RT_MMCSD_MAX_PARTITION, sets geometry before register
SCSI disk scsi/scsi_sd.c sda, sdb, … parallel_io from host, READ CAPACITY 10/16, sd_ida
SCSI CD-ROM scsi/scsi_cdrom.c optical media Read-only style backend

AHCI/SATA path: ata/ahci.c exposes SCSI devices; SD card goes through scsi_sd or MMC dev_block, then blk.

Minimal driver pattern

static const struct rt_blk_disk_ops my_blk_ops = {
    .read     = my_read,
    .write    = my_write,
    .getgeome = my_getgeome,
    .sync     = my_sync,
};

static struct rt_dm_ida my_ida = RT_DM_IDA_INIT(MY_DISK);

void my_disk_register(struct my_hw *hw)
{
    struct rt_blk_disk *disk = &hw->blk;

    disk->ops = &my_blk_ops;
    disk->ida = &my_ida;
    disk->parallel_io = RT_FALSE;  /* or RT_TRUE if ops are reentrant */
    rt_dm_dev_set_name(&disk->parent.parent, "sda");  /* example */

    rt_hw_blk_disk_register(disk);  /* also runs partition probe */
}

Details: @ref page_device_disk.


Locks and concurrency

Mechanism Scope
disk->usr_lock (semaphore) Serializes disk read/write/sync when parallel_io == 0
disk->lock (spinlock) Partition list, unregister, erase path
parallel_io == 1 Disk read/write skip usr_lock — backend must be safe for concurrent I/O

Partition volume I/O still goes through the disk node and follows the disks parallel_io / lock rules.


Typical bring-up sequence

  1. Allocate struct rt_blk_disk (often embedded in driver private data).
  2. Implement rt_blk_disk_ops; set ida, name, flags (read_only, removable, parallel_io, max_partitions).
  3. rt_hw_blk_disk_register(disk) — partition probe runs automatically.
  4. Application or init code rt_device_find("sda1"), mount DFS, or run filesystem code.
  5. rt_hw_blk_disk_unregister(disk) after unmount — syncs, removes all volumes, checks ref_count.

To re-scan partitions after media change, unregister, update geometry, register again (or call rt_blk_disk_probe_partition only if disk->partitions == 0).


Driver / BSP quick notes

Topic Guidance
Name before register First character of disk->parent.parent.name must be non-NUL
ida Mandatory with RT_USING_DM; disk and each volume consume IDA slots
Probe errors Ignored at register — check disk->partitions or open volumes explicitly
max_partitions Set RT_BLK_PARTITION_NONE to skip table parsing
Read-only Omit write in ops — core forces read_only
Unmount first unregister returns -RT_EBUSY if ref_count > 0
Erase Disk erase IOCTL removes all partition devices first

See also

  • @ref page_device_disk — rt_blk_disk / rt_blk_disk_ops / register API
  • @ref page_device_partitions — GPT/EFI and DFS parsers
  • @ref page_device_ata — AHCI → SCSI → blk path
  • @ref page_device_nvme
  • @ref page_device_sdio
  • @ref page_device_scsi
  • components/drivers/block/blk.c
  • components/drivers/block/blk_dev.c
  • components/drivers/block/blk_partition.c