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 特定内容 根据事务类型不同而变化
个人技巧:调试时先看Transaction Type和Task Tag。这两个字段对上了,后续分析才有意义。我习惯在协议分析仪里按Task Tag过滤,这样能快速找到成对的CMD和RSP。

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清零的步骤。

避坑指南:COMMAND UPIU的Data Segment Length字段要特别注意。如果是从设备写数据,这个字段表示将要发送的DATA OUT UPIU的数据长度;如果是读数据,则是从设备将要返回的DATA IN UPIU的数据长度。我曾见过两端长度不一致导致超时,所以一致性检查时要严格比对。

4.4 数据流与控制流的交互

一个完整的读写流程是这样的:

  1. 主机发送COMMAND UPIU,告诉设备要读哪个LBA
  2. 设备处理命令,准备好数据
  3. 设备发送DATA IN UPIU(一个或多个),把数据传给主机
  4. 最后发送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正确匹配。

UFS命令与UPIU结构关系图 主机 (Initiator) 设备 (Target) 命令执行流程 1. COMMAND UPIU 解析并处理命令 准备数据/执行 2. DATA IN/OUT 3. RESPONSE UPIU 任务管理 TASK MGMT REQ TASK MGMT RESP UPIU事务类型决定行为

这张图把整个流程串起来了:主机发起COMMAND → 设备处理 → 数据交互 → 最终应答。任务管理则更直接,一对请求-响应搞定。

我个人的习惯是:在做协议层测试时,先在脑海里过一遍这个流程图。每个箭头都对应一组UPIU,每个UPIU都有固定的字段和取值。当你把一个场景的所有UPIU列出来,验证点自然就清晰了。