SATA 接口概述与协议基础

做链路误码排查,第一步得搞清楚 SATA 到底是什么东西。说实话,很多人一上来就拿着示波器去量眼图,结果连协议的基本分层都没搞明白,折腾半天也定位不到根因。我个人习惯,先把接口的本质说清楚。

SATA 是什么?

SATA,Serial ATA 的缩写,说白了就是串行的 ATA 总线。它替代了老旧的并行 ATA 总线,把 16 根数据线砍成了 4 根差分线。你想想看,线少意味着干扰源少,信号完整性反而更好做。

我当年刚入行时,有次去产线支持,看到老工程师拿万用表量 ATA 排线的数据线,我就问他为什么不直接看波形。他回了一句:并行总线数据线有十几根,等长、串扰、地弹,哪个问题都够你喝一壶的。后来换成 SATA,排查工作确实轻松不少——不是因为协议简单,而是物理链路结构清晰了许多。

SATA 核心特征:

  • 全双工差分传输(一对发射、一对接收)
  • 点对点连接,每个端口只连一个设备
  • 原生支持热插拔(但实际电路要加保护)
  • 数据传输率从 1.5 Gbps(SATA 1.0)到 16 Gbps(SATA 3.3)

SATA 协议分层模型

SATA 遵守 ISO/OSI 的套路,把通信拆成四层。我把它画成了一张图,你可以边看边对照后面的讲解。

SATA 协议分层模型 应用层 ATA 命令集 / NCQ / FPDMA 传输层 Frame Information Structure (FIS) 链路层 原语 / 帧封装 / 8b/10b / CRC / 扰码 物理层 OOB 信号 / 差分电平 / 时钟恢复 / 阻抗匹配 ⚠ 链路误码排查重点区域 物理层:眼图、抖动、差分电压 → 链路层:CRC 错误、原语超时、8b/10b 违例 传输层 / 应用层的误码往往由物理层和链路层问题引起,不要舍本逐末。

很多人觉得链路误码就是物理层的活,其实链路层才是最早发现错误的地方。我记得有个项目,SATA 盘数据读写偶尔报错,查了三天眼图都正常,最后发现是链路层原语收发时序被芯片内部延迟拉偏了。

物理层:信号能传多远

物理层负责把 0 和 1 变成差分电压摆到线上。SATA 收发器之间没有独立时钟线,全靠接收端从数据流里恢复时钟——这就是 CDR(时钟数据恢复)的活。

参数 SATA 1.0 SATA 2.0 SATA 3.0/3.1
数据传输率 (Gbps) 1.5 3.0 6.0
差分电压 (Vpp) 0.4~0.6 0.4~0.6 0.4~0.6
预加重 无 可选 必需
去加重 无 可选 必需
OOB 信号电平 0.1~0.2 V 0.1~0.2 V 0.1~0.2 V

这里有个坑,我碰过一次。某款主控芯片的预加重默认是关闭的,用在短线上没问题,但客户用的是一米线缆,信号过冲直接被接收端判定为误码。

避坑指南:我曾经在一个 SATA 3.0 项目中忽略去加重参数,导致盘片量产时批量出现 CRC 错误。反复调试才发现发送端去加重强度设成了 -3 dB,而线缆质量又不太好。后来统一改为 -6 dB 并增加预加重补偿,问题就解决了。所以物理层参数的匹配,光看规格书不够,必须结合实际链路做边界测试。

链路层:数据是怎么组织起来的

链路层的核心工作有三块:

  1. 原语(Primitive):用于链路状态机切换,比如 ALIGN、SYNC、R_OK、R_ERR 等。原语是双字(Dword)结构,不经过扰码,是所有数据交换的基础。
  2. 帧(Frame):由 SOF(帧开始) + 数据内容 + CRC + EOF(帧结束)组成。链路层在发送前对数据做 8b/10b 编码 + 扰码,接收端做逆过程。
  3. 误码检测:CRC-32 校验覆盖整个帧(不含原语),一旦接收端算出来的 CRC 和发送端不一致,链路层立即设置 Error 状态,并发送 R_ERR 原语通知对端。

实际测试中,我最常看的是「CRC 错误计数」和「8b/10b 违例计数」。这两个寄存器在 SATA 控制器的链路层状态空间里都有暴露,用 debug 工具读出来,基本能判断问题出在哪一端。

调试小技巧:连着看 CRC 错误计数器,如果数值是随机增长的,大概率物理层有周期性噪声;如果每次大块数据读写时 CRC 错误数飙升,优先检查链路层原语握手时序——我曾经遇到过 SATA 盘的 COMINIT 信号被电容耦合干扰,导致链路层每 100ms 就要重新建链一次。

8b/10b 编码与扰码

SATA 用 8b/10b 编码把 8 位数据变成 10 位符号,保证 DC 平衡和足够多的信号跳变。控制码(K 码)用于标识原语和帧的边界。

控制码名称 编码值 (10 位) 功能
K28.5 001111 1010 或 110000 0101 原语定界符(ALIGN、SYNC 共同前缀)
K27.7 110110 1000 或 001001 0111 SOF 帧开始
K29.7 111010 1000 或 000101 0111 EOF 帧结束
K30.7 110111 1000 或 001000 0111 R_ERR 接收错误

很多人不知道,SATA 在 8b/10b 编码之后还要做一次扰码(Scrambling),目的是打散频谱能量,减少 EMI。但这个扰码用的是线性反馈移位寄存器(LFSR),如果链路丢了一个时钟,接收端 LFSR 就会跑偏,后面的数据全部解错——这就是著名的「失同步型误码」。

我见过一种极端情况:某板卡温升后晶振频率漂移了 300 ppm,接收端 CDR 还能勉强锁住,但 LFSR 同步头被周期性地误判,导致 CRC 错误以每 10 秒一次的频率稳定出现。排查了三天才抓到,最后加了一个温补晶振解决。

小结一下

SATA 的链路误码排查,说白了就是一层层扒:物理层看眼图、差分电压、抖动;链路层看 CRC、原语状态、8b/10b 违例;传输层看 FIS 完整性。底层的数据若错了,上层报的错都是误导信息。后面我们会逐一展开每层的排查方法和工具用法。