4. UFS命令协议(Command Set)与UPIU结构
说到UFS的通信,核心就是两个东西:命令协议和UPIU。命令协议告诉你“能发什么指令”,UPIU告诉你“指令长什么样子、怎么打包”。这两个搞清楚了,UFS协议层你就算入门了。
我记得刚开始接触UFS时,总觉得UPIU结构很复杂。后来调了一个月的协议分析仪,慢慢就摸透了。说白了,UPIU就是UFS设备之间通信的“信封”,命令、数据、响应都装在里面。
4.1 UFS命令集概览
UFS的命令集主要来自SCSI体系,但做了一些裁剪和扩展。我把它分成三大类:
- 基本命令:INQUIRY、READ(10)、WRITE(10)、READ CAPACITY等
- 任务管理功能:ABORT TASK、LOGICAL UNIT RESET等
- UFS特定命令:比如QUERY REQUEST,用来操作设备描述符和标志
为什么会这样设计?UFS想复用SCSI成熟的上层软件栈,让存储厂商能快速迁移。你想想看,如果完全重新发明一套命令,那驱动和文件系统都得重写,成本太高了。
实际项目中,我们最常见的是READ/WRITE命令和QUERY REQUEST。我曾经遇到一个卡死问题,设备就是不响应READ命令,最后查出是UPIU的LUN字段填错了。嗯,这种低级错误在新手身上很常见。
4.2 UPIU — 统一协议的“信封”
UPIU全称UFS Protocol Information Unit。每个UPIU固定是32字节,但可以带额外的数据。
先看通用格式:
| 字节偏移 | 字段名 | 说明 |
|---|---|---|
| 0 | Transaction Type | 事务类型,决定UPIU的用途 |
| 1 | Flags | 各种标志位,比如EOD、OCS |
| 2-3 | LUN | 逻辑单元号 |
| 4-7 | Task Tag | 任务标签,用于匹配请求和响应 |
| 8-11 | Initiator ID / ICC | 发起端标识和命令控制 |
| 12-31 | 特定内容 | 根据事务类型不同而变化 |
4.3 四种核心事务类型
UPIU的事务类型(Transaction Type)决定了它的功能。常用的有这四种:
- NOP OUT / NOP IN:链路保活,就像网络里的ping
- COMMAND / RESPONSE:发命令和收响应,最常用
- DATA OUT / DATA IN:写数据和读数据
- TASK MANAGEMENT REQ / RESP:任务管理,比如终止某个任务
让我重点讲一下COMMAND类型的UPIU。它的字节12以后直接放的就是SCSI CDB(Command Descriptor Block)。比如一个READ(10)命令,CDB里会包含起始LBA和传输长度。
// 一个典型的COMMAND UPIU结构示例
// Transaction Type = 0x01 (COMMAND)
// Flags = 0x00
// LUN = 0x00
// Task Tag = 0x0001
// 字节12开始是CDB:
// 0x28 -> READ(10) 操作码
// 0x00 0x00 0x00 0x00 -> LBA高4字节
// 0x00 0x00 0x00 0x01 -> 传输长度为1个LBA
// 剩下的CDB字节填充0
我曾经被一个兼容性问题坑过。某个品牌的UFS设备对CDB中的保留位检查很严格,只要不是0就直接返回错误。而我们的驱动偏偏在那里填了一个非零值。排查了两天才发现,后来我就在驱动里加了CDB清零的步骤。
4.4 数据流与控制流的交互
一个完整的读写流程是这样的:
- 主机发送COMMAND UPIU,告诉设备要读哪个LBA
- 设备处理命令,准备好数据
- 设备发送DATA IN UPIU(一个或多个),把数据传给主机
- 最后发送RESPONSE UPIU,表示传输完成并报告状态
写操作流程类似,只是数据流方向相反:主机先发COMMAND,然后发DATA OUT,最后设备回RESPONSE。
任务管理流程简单一些:主机发TASK MANAGEMENT REQ UPIU,设备回TASK MANAGEMENT RESP UPIU。不需要数据阶段。
在第4章里,我们只会讲单命令交互。多命令并发、乱序完成这些复杂场景,后面有专门的章节讲。
4.5 版本差异:UFS 2.x vs 3.x vs 4.0
| 特性 | UFS 2.x | UFS 3.x | UFS 4.0 |
|---|---|---|---|
| 基本UPIU大小 | 32字节 | 32字节 | 32字节 |
| 最大数据段 | 取决于M-PHY速率 | 更大,支持HS-Gear4 | 更大,支持HS-Gear5 |
| 命令集 | SCSI + 扩展 | 同左,增加了大容量支持 | 增加了ZNS/UFS专有命令 |
| QUERY REQUEST | 基础支持 | 增加了扩展标志 | 增加了更多描述符 |
核心的UPIU结构在版本间基本没变。主要变化在数据速率、链路宽度和上层功能扩展。所以你现在学的UPIU知识,往后几年都不会过时。
4.6 验证要点总结
做一致性测试时,我建议重点检查以下几点:
- Transaction Type:是否在允许范围内,是否与UPIU内容匹配
- Task Tag:同一个交互中是否保持一致,有没有重复使用未完成的标签
- LUN:是否指向有效的逻辑单元
- CDB内容:操作码是否支持,参数是否合法
- Data Segment Length:与实际传输的数据长度是否一致
- OCS(Overall Command Status):响应中的状态码是否正确
核心原则:UPIU是UFS协议层最基础的通信单元。验证的目标就是确保双方“说得通、听得懂、不丢包、不错位”。我说的“不丢包”是指Task Tag不丢失;“不错位”是指CMD与RSP正确匹配。
这张图把整个流程串起来了:主机发起COMMAND → 设备处理 → 数据交互 → 最终应答。任务管理则更直接,一对请求-响应搞定。