2、UFS协议基础:UFS架构、物理层、链路层、传输层、命令集与描述符
UFS(Universal Flash Storage)并不是一条简单的“高速串行线”,而是一套分层明确的存储协议栈。它借鉴了 SCSI 的命令模型,又采用 MIPI 的物理与链路规范,最终在主机与闪存设备之间形成一条可寻址、可并发、可管理的存储通路。理解 UFS 协议基础,是后续做 UFS 到 PCIe 桥接时判断“哪些语义必须保留、哪些可以映射、哪些必须转换”的前提。
一、UFS 分层架构:从应用命令到物理信号
UFS 协议自上而下大致分为四层:应用层/命令层、传输层、链路层和物理层。主机侧由 UFS 主机控制器驱动(UFSHCD)和块层发起请求,设备侧由 UFS 设备控制器解析并访问 NAND 阵列。各层职责如下:
- 应用/命令层:定义 UPIU(UFS Protocol Information Unit)中的命令、任务管理、查询请求等语义,承载 SCSI 命令集。
- 传输层:负责 UPIU 的封装、解封装、标签(Task Tag)管理、命令队列与响应匹配。
- 链路层:负责 UniPro 帧的成帧、CRC 校验、重传、流控与 Lane 管理。
- 物理层:定义 M-PHY 的电气特性、Lane 数量、速率档位(Gear)与功耗状态。
这四层不是孤立存在的。一次读命令从主机发出,会依次经过命令层生成 UPIU、传输层分配 Tag、链路层打包成 UniPro 帧、物理层通过 M-PHY Lane 发送;设备侧则反向逐层解析,最终返回数据与响应。桥接设计中最容易出错的地方,往往不是某一层单独实现,而是层与层之间的状态同步。
二、物理层与链路层:M-PHY 与 UniPro 的协作
UFS 物理层采用 MIPI M-PHY,支持 HS(High Speed)和 LS(Low Speed)两种模式。HS 模式下常见 Gear 1 至 Gear 4,单 Lane 速率从约 1.25 Gbps 到 11.6 Gbps 不等;实际带宽还取决于 Lane 数量(通常 1 或 2 Lane)和双向独立配置。链路层则基于 MIPI UniPro,负责把上层 UPIU 封装为 UniPro 帧,并完成 CRC 校验、确认与重传。
这里有一个关键点:M-PHY 的“Gear”变化和 UniPro 的“Lane”管理是两套状态机,但它们必须协同。例如,当链路空闲时,M-PHY 可能进入 Hibern8 低功耗状态;一旦有命令到达,链路层需要先唤醒物理层,再恢复帧传输。桥接设备如果只做协议转换而不跟踪这些状态,就会出现“命令已发出但设备未唤醒”的超时问题。
三、传输层与命令集:UPIU、Task Tag 与 SCSI
UFS 传输层的核心是 UPIU。每个 UPIU 包含事务类型、Task Tag、数据段等字段。主机可以同时发出多个命令,每个命令分配唯一 Task Tag,设备按 Tag 返回响应。这种机制让 UFS 支持命令队列,从而提升并发性能。
UFS 命令集主要基于 SCSI。常见的命令包括:
| 命令 | 作用 | 典型 UPIU 类型 |
|---|---|---|
| READ(10) / READ(16) | 从设备读取逻辑块数据 | COMMAND UPIU + DATA IN UPIU |
| WRITE(10) / WRITE(16) | 向设备写入逻辑块数据 | COMMAND UPIU + DATA OUT UPIU |
| INQUIRY | 查询设备基本信息 | COMMAND UPIU + DATA IN UPIU |
| TEST UNIT READY | 检查设备是否就绪 | COMMAND UPIU + RESPONSE UPIU |
| REQUEST SENSE | 获取错误详情 | COMMAND UPIU + DATA IN UPIU |
除了 SCSI 命令,UFS 还定义了查询请求(Query Request),用于读写设备描述符、配置属性、设置标志等。查询请求不经过块数据通路,而是通过独立的 UPIU 类型完成,常用于初始化、电源管理和错误恢复。
四、描述符与属性:设备如何被识别和配置
UFS 设备通过描述符(Descriptor)向主机描述自身能力。描述符是只读或可写的数据结构,主机在枚举阶段读取它们,以决定使用哪些配置。常见描述符包括:
- Device Descriptor:设备整体信息,如 UFS 版本、Lane 数量、容量等。
- Configuration Descriptor:可配置项,如 Lane 数量、Gear 速率、电源模式。
- Unit Descriptor:逻辑单元信息,如 LUN 编号、容量、写保护状态。
- Geometry Descriptor:存储介质几何信息,如块大小、可擦除块数量。
- Health Descriptor:设备健康状态,如寿命、温度、错误计数。
属性(Attribute)则是可读写的运行时参数,例如 bCurrentPowerMode、bActiveICCLevel、bRefClkFreq 等。标志(Flag)用于控制设备行为,如 fDeviceInit、fPurgeEnable。主机通过 Query Request 读写这些描述符、属性和标志,完成设备初始化与动态管理。
// 示例:通过 Query Request 读取 Device Descriptor
// 伪代码,展示 UPIU 字段结构
Query Request UPIU:
Transaction Type = QUERY_REQUEST
Query Function = READ_DESCRIPTOR
Descriptor ID = DEVICE_DESCRIPTOR
Index = 0
Selector = 0
Data Segment = 返回的描述符内容
五、案例与误区:桥接场景下的常见问题
假设我们要把 UFS 设备桥接到 PCIe 主机。主机通过 PCIe 发出 NVMe 或自定义命令,桥接芯片需要将其转换为 UFS UPIU。此时最容易出现的误区有三个:
- 忽略 Task Tag 生命周期:UFS 的 Tag 是有限资源,桥接层如果只做命令转发而不跟踪响应回收,会导致 Tag 耗尽,后续命令无法下发。
- 混淆描述符与属性访问:描述符通常只读,属性可读写,但两者都通过 Query Request 访问。桥接层若把描述符读取当作普通数据读取,可能返回错误长度或错误类型。
- 忽略电源状态同步:UFS 设备可能处于 Sleep 或 PowerDown 状态,桥接层必须先发唤醒或查询状态,再发数据命令,否则会出现链路超时。
总结来说,UFS 协议基础可以概括为:物理层提供 Lane 与 Gear,链路层保证可靠传输,传输层用 UPIU 和 Task Tag 管理并发,命令层承载 SCSI 与查询请求,描述符和属性则让主机能够识别并配置设备。只有把这五部分串起来理解,才能在 UFS 到 PCIe 桥接中做出正确的语义映射与状态管理。