nvm用标准sata ahci码_AHCI系列(1)

AHCI系列打算分两篇文章写,这篇主要集中在介绍AHCI System Memory Structures,由于涉及到协议的历史变迁,如果单纯只看AHCI本身,很多东西无法理解透彻,所以加了很多背景知识介绍,以及AHCI使用的一些shadow寄存器的由来。只是覆盖这些,文章都已经很长了,所以软件流程和非常重要的OOB就放到下一篇文章吧。涉及的协议包括ATA8-ACS,SATA, AHCI,均可去官网下载。

上篇文章“xHCI那些事儿”中简介SCSI有一张图介绍了Linux的层次,本文再拿来用一下。在block device驱动下面有三个框,SCSI/IDE/others(串口并口等)。目前高速存储设备的接口有三大类:IDE、SCSI、USB,其中常见的USB设备之一,U盘使用的就是SCSI协议,常用的SATA机械硬盘也叫IDE盘,先用一段篇幅简单区分下SCSI/IDE/SATA几种协议。

185ee88f780e8df1e7dd42b814c03aa7.png

首先了解下SATA名字的由来,serial AT attachment,最早的ATA-1/IDE是用于286(PC-AT,对比8086的第一代PC,使用了高级技术,Advanced Technology)的AT总线的硬盘驱动器。和之前的硬盘驱动器最大的区别在于,硬盘控制器是集成在驱动器上的(之前的硬盘和控制卡是分离的,需要把硬盘安装在控制卡上)。因为是AT总线上的附加设备,所以叫AT-Attachment,缩写ATA。同时又因为集成了硬盘控制器,所以叫整合驱动器设备(IDE,即把“硬盘控制器”与“盘体”集成在一起的硬盘驱动器)。

因为ATA协议仅仅针对硬盘设备制定,而此时市场上的CD-ROM/磁带机/可移动存储等设备都需要使用其他专用接口或者昂贵的SCSI接口,因此SFF(Small Form Factor committee,小型计算委员会)参考SCSI协议,制定了在ATA接口上使用的ATAPI协议。ATAPI是与ATA命令集完全不同的另外一种协议,把SCSI命令的一个子集打包成数据包,由控制器发送给IDE设备。因为是基于ATA的数据包接口,所以又称为ATA Package Interface。打个比方就是ATA设备学了一门外语(SCSI),并且都用这门外语和主机交流。

SCSI制定了一系列的通用接口命令,用于和不同类型的设备进行交互。大体上可以分为检测/控制类,数据写入类,数据读取类,以及双向数据传输(同时读和写)类。为了实现这些命令和SCSI设备交互,通常需要单独的SCSI控制器或者主板集成SCSI控制芯片。SATA、SAS则是分别把ATA和SCSI从并行通信改成串行通信。

总结一下这段历史,SATA/SAS是串行的ATA/SCSI,SATA在大部分语境下几乎等于IDE。SCSI设备比ATA设备更贵,性能更好,但是需要额外的设备,而更便宜的ATA为了支持SCSI设备,开发了ATAPI命令集,该命令集包装了SCSI命令集。好了,妈妈再也不用担心我傻傻分不清了。

先看AHCI的定义:AHCI is a hardwaremechanism that allows software to communicate with Serial ATA devices. AHCI isa PCI class device that acts as a data movement engine between system memoryand Serial ATA devices。一个完整的计算机系统包括CPU,内存和IO,IO接口上连着外设,CPU想要读数据时,在内存中腾出一片空间,并把地址写入外设开放给CPU的相应寄存器(一般会映射到CPU的MMIO空间),然后向IO发送读命令,IO将该命令传给外设,外设解析命令,从自身的存储介质上取到数据,然后外设通过物理层和链路层将数据传输给IO的硬件,IO的硬件以DMA方式将数据搬运到CPU指定内存空间,同时硬件把相应状态写入寄存器供CPU检查。同时AHCI也支持PIO的搬运方式,比如IDENTIFYPACKET DEVICE命令就是通过PIO方式读回512B的ID数据,由于PIO搬运数据过程中需要CPU全程参与,会产生大量访存操作,同时纠错能力也非常有限,AHCI协议强烈建议不使用这种方式。具体对应到AHCI的设计上来,IO的硬件叫HBA(hostbus adapter),CPU存放命令和指定内存的数据结构叫commandlist,硬件返回的状态存放在数据结构receivedFIS,我们来逐条分析。

HBA:作为AHCI的host device,一个HBA最多支持32个ports,但port上可以插port multiplier,在Intel架构和嵌入式架构中的位置分别如下两图所示 

b8eb5d341d469953ab9959c5a80318f7.png26f81ed142d7141b92440e05d88c590c.png

在IA架构中,AHCI通常作为某个PCI EP的function存在,因此初始化AHCI的第一步是配置其PCI配置空间。支持以下feature

8d897bcddde73ec1fa499cbca4ffe069.png

HBA的内存空间如下图所示

6649fc67e2dc9a334d42dfb114e4dec1.png4c087d74f0deb4751a7b361607714c43.png

其中Commandlist数据结构如下图所示

43e02982c6efd19479837623950b2858.png4ae19e36e604239becfe764c950d79a4.png

首先解释Command list的几个重要字段,DW0是Description Information,PRDTL用于指定PRDT的长度(每个PRDT Entry最多可以传输4MB数据),PMP指定HBA的port number,如果是直插设备写0,A指定是否ATAPI设备,R指定command是reset命令,控制IDE控制器的Control寄存器的SRST位,P指定是否预取PRDT Entry或者ATAPI命令,W指定命令是读还是写操作。DW1是Command Status,软件写0初始化,每次传输完成硬件更新为已完成传输的Bytes数。DW2/3是command table的地址。

再看下Command table的重要数据结构,首先CFIS具体格式由SATA协议规定,比如host to devcie的寄存器传输格式如图

cde1fafb70fe7accfd55d5cf6597a081.png

其中Command字段是commandregister的shadow,需要CPU填入ATA命令;Control字段是devicecontrol register的shadow,需要CPU填入控制字符;Byte1的PM portbits指定portnumber,需要和commandlist的PMP区分一下;C bit为1表示此次寄存器传输是由于更新了command寄存器,为0表示是由于更新了devicecontrol register。较新的AHCI协议将Task file改称Commandand Control Block Register了,commandregister和devicecontrol register到底是谁的shadow,AHCI协议是没有明说的。先看AHCI协议的一张图

3be352912e255fbc4d653e7cafcd1cdd.png

图中左侧是legacyinterface连接外设和PCIBus,这种所谓的legacyinterface就是IDE控制器,主流的主板上都有两个IDE控制器,分别是primary和secondary,X86的IO空间专门为他们预留了位置,PrimaryIDE controller: 1F0h to 1F7h and 3F6h to 3F7h;Secondary IDE controller: 170h to 177hand 376h to 377h。这些寄存器的分配如下

d1f0fe370ea51b52fc2b26020a43b7de.png

Status寄存器从高到低为

70898f667ee09de487f5772d30b84588.png

Error寄存器从高到低为

e031438846b144928fd4c023ca89ed32.png

Device control寄存器BIT1=nIEN(中断使能位),BIT2=SRST(软复位)。

Legacy Interface操作SATA的方式就是配置上述寄存器,比如执行命令IDENTIFYDRIVE从SATA读512B数据的Intel格式汇编代码如图所示

374d74404956a7ae60ebd7453eb33574.png

30b5fa4465ae5c2a2d9bf46ce1f66f19.png

可以看到这段汇编大量使用IN/OUT访问IO space来check状态和发送命令,最后的指令REPINSW重复256次INSW,将长度为2B的数据从DX指定的外设端口(0x1F0)输入字到由DI指定的存储器中(buffer),完成这一系列操作后,512B的ID数据就存到buffer中了。这种访问IO space和SATA通信的古老方法现在已经基本看不到了,但FIS字段的大部分内容还是拷贝自IO space,也就是所谓的shadow寄存器。

Command table中剩下的ACMD和PROT也非常重要,ACMD用于ATAPI设备,典型的如CD-ROM,笔者在上一篇介绍XHCI的文章中说过,U盘也是使用SCSI命令集,该命令有12B和16B两种格式,BYTE[0]是真正的命令,后11/15B都是该命令的参数,MassStorage协议使用CBW将它包起来,CBW的BYTE[0]是一个magic number用来标记这是一个包含SCSI的CBW。AHCI也使用类似的方式将SCSI命令集包成一个packets,软件在填入ATAPI相关的CFIS之后,还要额外在ACMD填入12B/16B的SCSI命令序列。SCSI设备简单的初始化包括Inquiry--Testunit read--Readcapacity三步,常见的SCSI命令集如下图。

d15c66c4943624532267e83cc45ca0e8.png

PRDT是用于数据传输的散列/聚合表,其entry长度由PRDTL指定。SATA利用散列/聚合表链接数据,传输数据则需要FPDMA和NCQ。

其中DMA散列聚合表技术是与block DMA方式相对应的一种DMA方式,在DMA传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但在有的计算机体系中,连续的存储器地址在物理上不一定是连续的,则DMA传输要分成多次完成。如果传输完一块物理连续的数据后发起一次中断,同时主机进行下一块物理连续的传输,则这种方式即为block DMA方式。scatter/gather方式则不同,它是用一个链表描述物理不连续的存储器,然后把链表首地址告诉DMA master。DMA master传输完一块物理连续的数据后,就不用再发中断了,而是根据链表传输下一块物理连续的数据,最后发起一次中断。

NCQ(Native Command Queuing)设计的初衷是乱序执行命令序列,以减少磁盘的旋转圈数,host一次发布多条命令,当所有命令都完成后,一起返回一个完整log,log中用TAG区分不同的命令,需要SATA支持READFPDMA QUEUED/ WRITE FPDMA QUEUED/ General Purpose Logging等feature。AHCI协议举了一个例子如下图,命令1-2-3-4要读四次数据,如果顺序执行磁盘要转4.25圈,而如果乱序1-3-2-4执行,则只需要旋转2.25圈,就能读完所有数据。当然这种技术仅用于机械硬盘,对于NANDflash这种使用字线和位线电子编程的硬盘,完全不需要机械旋转,有更优秀的算法用于FTL层来提升性能,笔者之前的工作与此紧密相关。

26e4921235b1613c71a5013b40ec4700.png

SATA Spec中还定义了三个特殊的功能来加强NCQ的性能:

1,Race-Free Status Return: 无竞争状态返回机制,允许任何指令任何时间报告执行状态,此外,多个命令执行完毕信息可以打包一起回传。

2,Interrupt Aggregation: 在DMA传输模式下,硬盘通知传输结束,会引起一个中断(Interrupt),造成延迟。所以,SATAspec提供中断聚集机制。如果硬盘同时间内完成多组命令,这些命令完成所引起的中断就可以聚集在一起,大幅减少中断的数目,这对于降低中断延迟有极大的贡献。

3,First-Party DMA(FPDMA): SATA允许硬盘端通过DMAsetup FIS直接对Host控制器送出数据传输请求,DMA引擎就可以直接进行资料传输,这个过程中并不需要Host端软件的介入。

下面对比一下普通DMA和NCQ DMA实现方式的区别。普通DMA由host下发WRITEDMA(EXT)/READ DMA(EXT)触发,commandsequence如下图

f16f6450e9502abe47eb1f675d8a00dc.pngcdc2109de13a3119ba574b7003f39b72.png

FPDMA由host下发WRITEFPDMA QUEUED/READ FPDMA QUEUED触发,command sequence如下图

d9fb8b9ea6105bf542e00429a9dcea70.png562bfeea6d028beb5e8a969811a05830.png

如果一个FIS包含的PDRT不足以传输所有数据,将会有多个Data FIS sequence。而为了实现NCQ,AHCI则需要利用Portx Serial ATA Active (SCR3: SActive)寄存器的32bits来标记host下发命令的active状态,比如下发了2个命令,command slot为1和3,则软件需要将SActive初始化为0x5表示当前commandlist的slot1 slot3是active状态。同时device需要为每一个commandslot给host发送DMA SetupFIS用来提醒host建立DMA hardware context,这个步骤只在context将要发生变化时才需要,所以这个FIS是NCQ专用的。在每个command slot数据传输完成后,device需要发送SetDevice Bits FIS,通知host该slot执行完成,硬件需要自动清除SActive对应的位,软件通过查询该bit确认数据传输完毕。通过SActive寄存器,DMASetup FIS和SetDevice Bits FIS,AHCI实现了NCQ的握手机制。

最后看下AHCI System Memory Structures的最后一部分,ReceivedFIS,如下图所示

a4a3cc651dd8ecbe80134a1dd2371bbd.png

DMA Setup FIS用于NCQ,前文已经介绍,PIO Setup FIS用于PIO传输,典型的PIO写如下图所示,PIOSetup FIS用于提醒hostCPU参与数据传输,任何PIO相关的传输都需要device首先发送这个FIS。

27df0d6f33e2bab79e0d3675e663067c.png

D2H Register FIS在NCQ也出现过,用于和host交换command和status寄存器信息,比如是否busy等。SetDevice Bits FIS用于通知hostNCQ完成情况。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值