本次开发是基于ARM A55芯片AHSATA模块开发firware实现AHCI HBA功能,本篇文章主要讲解AHCI HBA底层的实现流程,具体细节再后续文章中进行针对性的总结。
AHCI HBA独立于SOC芯片以外的AHCI HBA是一个PCI类设备。在主机下为一个SATA controller PCI设备,在controller下可以外挂多个ATA DEVICE。
在linux下输入lspci可以看到controller设备
AHCI HBA在SOC整体位置如下:
常用命令释义
定义 | 解析 |
---|---|
HBA | HBA是“主机总线适配器”的缩写。,即AHCI HBA(AHCI的主机控制器),可以集成在SOC芯片中,也可以是单独的AHCI主机控制器芯片。主机总线适配器是指实现AHCI规范,用于在系统内存和串行ATA设备之间进行通信。 |
AHCI HBA | 独立于SOC芯片以外的AHCI HBA是一个PCI类设备。集成在SOC芯片中的AHCI HBA则使用内部总线访问,只是AHCI寄存器偏移量和功能复合AHCI规范标准。 |
OOB | (Out of Band)信号解析SATA信号链结的建立主要是靠OOB(Out Of Band)的检测实现的,并且向上层Link Layer提供了物理层的链结情况。 |
FIS | FIS是“框架信息结构”的缩写。FIS是指在主机和设备之间传输。传输层不必关心需要传输或接收资讯的多少,只需把要传输的资料封装成FIS 格式,发送到Link Layer,或者把收到的FIS去除封装,提交给Application Layer。 |
command list | 定义HBA处理的位于系统内存中的命令。这是一个列表,可能包含1到32个条目(称为命令槽),并且可以包含任何类型的ATA或ATAPI命令。命令当串行ATA设备的BSY、DRQ和ERR位被清除时,列表将被提前。 |
command slot | 命令槽是命令列表中的一个条目。命令槽包含执行命令,列表中最多支持32个插槽(即条目)。 |
device | 直接连接的物理设备,如硬盘驱动器(HDD)或光盘驱动器(ODD)连接到HBA端口,或通过端口倍增器连接到HBA港口。 |
cs | cs用于描述具有特定命令含义的字段。 |
D2H | D2H是“设备到HBA”的缩写。在串行ATA规范中,此缩写词与“设备到主机”。D2H通常用于描述FIS的传输方向。 |
H2D | H2D是“HBA到设备”的缩写 |
port | HBA上的一个物理端口,带有一组控制DMA和链路操作的寄存器。一个物理端口可能有几个设备通过端口倍增器连接到它。 |
PRD | “Physical Region Descriptor”是“物理区域描述符”的缩写。PRD条目描述了物理位置和要传输的数据长度。描述了在DMA传输期间用作数据来源或目标的内存区域。PRD表通常称为散/聚集列表(scatter/gather list)。 |
PIO | PIO模式是一种通过CPU执行I/O端口指令来进行数据的读写的数据交换模式。是最早先的硬盘数据传输模式,数据传输速率低下。分PIO mode0-6,速率从3.3MB/s到16.6MB/s不等。 |
Port Multiplier | 端口倍增器。SATA 1.0的一个缺点就是可连接性不好,即连接多个硬盘的扩展性不好。因为在SATA 1.0规范中,一个SATA接口只能连接一个设备。SATA的制定者们显然也意识到了这个问题,于是他们在SATA2.0中引入了Port Multiplier的概念。Port Multiplier是一种可以在一个控制器上扩展多个SATA设备的技术,它采用4位(bit)宽度的Port Multiplier端口字段,其中控制端口占用一个地址,因此最多能输出15个设备连接----与并行SCSI相当。 |
NCQ | Native Command Queuing 原生指令序列,对多个命令进行重新排序,减少机械硬盘磁头切换耗时。 |
queue | 显示Serial ATA设备内部的ATA命令队列。这与命令列表的区别在于,当HBA命令列表中的所有命令都是Serial ATA本机排队命令时,队列只能存在于Serial ATA设备中。 |
Task File | 接口寄存器用于向设备发送命令或从设备发送状态。在串行ATA,这些寄存器作为FIS有效载荷字段的一部分进行通信。在ATA规范的后期版本中,这些寄存器可以称为命令和控制块寄存器。 |
System Memory | 计算机系统的DRAM或“主”存储器,用于在主处理器和串行ATA设备之间传递数据和命令信息 |
n/a | n/a用于描述对于特定命令不适用或未使用的字段。 |
SATA3协议一共分为五层:应用层、命令层、传输层、链路层和物理层。
应用层:负责所有ATA命令的解析和执行,向处理器报告硬盘的运行状态,发起数据读写请求,完成硬盘工作模式的设置和读取等。
命令层:负责解析ATA指令,做出相应的回应,并指导传输层构建FIS。
传输层:负责构建和解析FIS,完成组帧和解帧,调整命令层和链路层之间的数据格式,完成主机和设备的命令交互和数据传递。
链路层:SATA链路层执行过程为:主机端发送数据,计算其32bit的CRCR校验和,并将该校验和与发送的有效数据进行加扰,放在有效数据帧的最后一帧,经过8B/10B编码后传输至物理层;设备端接收数据,对接收的有效数据进行8B/10B解码以及解扰操作,计算本组数据的CRC校验和,并与设备端接收的校验和比较。
物理层:物理层位于协议的最底层,其功能是通过OOB(Out-of-Band)信号的检测以及原语交互,实现主机端控制器与设备端控制器的链路初始化和速度协商,并将主机和设备的链路状态向链路层反馈,建立数据通道,实现串并转换、并串转换等操作。目前,Xilinx的高速收发器可支持物理层设计与实现,并且包含了8B/10B编解码等功能。
物理层的下游用两对串行差分信号对连接 SATA device ,上游与链路层之间传输并行信号。物理层进行的主要工作包括:
时钟恢复:与常见的低速通信(例如几十MHz的老式硬盘的ATA并口)和中速通信(例如几百MHz的DDR3、MIPI LVDS)不同,在SATA这种几Gbps的高速率下,各个信号间难以进行对齐,因此SATA不是用用不同的信号线传输时钟,而通过8b10b编码把时钟和数据调制到同一对差分对上,因此物理层的 RX 通道需要使用锁相环 (PLL, 一种模拟电路) 对串行信号的时钟恢复,有了恢复出的时钟,才能对 RX 数据进行正确的采样。串并转换:物理层的 RX 通道需要用恢复出的时钟把RX数据转换成以 10bit 为单位的并行信号;TX通道需要把链路层提供的 10bit 为单位的并行信号转换为串行信号发送出去。例如,对于 3Gbps 的 SATA Gen2 ,转换成的并行信号可以是 150MHz 20bit 位宽,也可以是 75MHz 40bit 位宽。字节对齐:串并转换涉及到如何在串行的 bit 流中界定 10bit 并行单位的边界的问题,SATA 使用一种特殊的 ALIGN 原语来界定 byte 边界,在 8b10b 编码下,ALIGN 原语会产生一种独一无二的 10bit 组合模式,物理层负责识别这种模式,每当遇到这种模式,接收方就知道当前处于一个 10bit 的边界。
本文将链路层和传输层合起来讲,因为二者间耦合度较大,个人认为合起来更好理解。链路层和传输层需要实现:8b10b 编解码、原语生成和检测(包括FIS包边界识别)、加扰/解扰、CRC生成和检验、流控。最后,传输层与上游的命令层使用一种叫 Frame Information Structures (FIS) 的数据包结构进行交互。链路、传输层功能分别说明如下:
8b10b 编解码:物理层RX通道的并行数据是以 10bit 为单位的 8b10b 编码数据,链路层需要把它解码为 8bit (1byte) 的数据;而TX通道需要把 8bit 数据编码为 10bit 。显然 8b10b 编码会导致五分之一的带宽浪费,之所以设计这种冗余,是为了让 0 和 1 尽量均匀地分布,这样接收方才能对信号进行时钟恢复。原语插入和检测:SATA 规定了几种原语 (Primitive) ,每个原语的长度都为 4byte 。原语并不携带数据,而是用来进行通信控制。本文涉及的原语包括 ALIGN, CONT, SYNC, R_RDY, R_IP, R_OK, R_ERR, X_RDY, SOF, EOF, WTRM, HOLD, HOLDA。原语有各自的功能,例如 ALIGN 原语用来进行字节对齐、X_RDY 原语用来告诉对方自己想发送一个 FIS 给对方,SOF 原语用来指示 FIS 的开头、EOF 原语用来指示 FIS 的结尾(通过 SOF 和 EOF 原语,RX通道才能正确地解析出 FIS 数据包的边界)。对于 TX 通道,需要正确地插入原语。对于 RX 通道,需要检测原语,并按原语规定的功能来进行状态机的状态转移。FIS加扰/解扰:加扰器 (Scrambler) 和解扰器能生成一个伪随机数序列,每次复位后,生成的伪随机数序列是固定的。在 TX 通道,待发送的 FIS 数据需要与加扰器生成的伪随机数序列进行按位异或运算,称为加扰;在 RX 通道,收到的 FIS 数据需要与解扰器生成的伪随机序列也进行按位异或运算,称为解扰。因为两次异或后数据不变,确保了先加扰、后解扰后数据能够正确地被恢复。加扰的目的是让 SATA 电缆上传输的数据更加杂乱,从而让电磁辐射更加接近白噪声(而不是集中分布于某个频率),从而减少电磁干扰(EMI)。原语的重复加扰:FIS 加扰只能减少FIS传输过程中的 EMI 。当SATA在传输大量重复原语时,为了减少EMI,需要使用另一种类似的机制:原语的重复加扰。该过程会用到 CONT 原语。CRC生成和检验:TX 通道需要根据 FIS 数据计算出 CRC 并追加在 FIS 的最后;RX 通道需要根据收到的 FIS 数据生成 CRC ,并与收到的 CRC 进行对比(也即CRC检验)。若不匹配,说明 FIS 传输中出现误码,需要丢弃该 FIS 并向上游报告错误。流控:硬盘介质的读写速率与 SATA 接口的速率往往并不匹配,因此传输层规定了流控(Flow Control)机制,流控依赖于 HOLD 和 HOLDA 原语,包括两种流控:
发送方流控:当发送方暂未准备好待发送的 FIS 数据时(例如读硬盘的速率慢于SATA接口速率),发送方可以插入 HOLD 原语来填空,这样就能支持“断断续续”地发送数据。接收方流控:当接收方暂不能接收 FIS 数据时(例如写硬盘的速率慢于SATA接口速率),接收方可以向发送方发送 HOLD 原语,告诉发送方“不要发的这么快,我接受不了了”,发送方就会暂停发送数据并向接收方发送 HOLDA 原语来填空。
命令层:接受上游的读写命令,生成和解析命令FIS,实现硬盘读写操作。SATA 支持 ATA 和 ATAPI 命令集,每个命令集包含多种硬盘读写方式,比如 PIO 方式、 DMA 方式等,因此一个完整的命令层需要实现众多繁杂的命令的状态机,但其目的并不复杂,都是为了用各种方式来实现硬盘读写。本文仅会简单地介绍 DMA 方式:包括如何用 DMA 方式发送和接收 FIS ,从而进行硬盘的读写。
作为HBA卡,AHCI驱动会根据FW提供的golobal sata base寄存器地址(0x25000000)对全局和每个port进行配置。
注意在进行pcie配置时要使能bar5,disable 其他bar空间
port寄存器是针对每个port进行的配置,在SATA GLOBAL BASE的基础上偏移0x100,然后每个port直接间隔0x80,公式如下:
相关寄存器如下:
本文主要讲解了底层firware在开发controller过程中PCIE相关的配置,主要是通过PCIE接口在PCIE建链完成后通过主机Linux内核AHCI驱动去配置controller设备,最终实现在host下可以认到sata controller设备。后续文章会详细介绍底层OOB进行phy link过程以及FIS命令的解析和使用。