- 确认命令ATA还是ATAPI
先看这个Ahci Port Register,这里记录了第一个D2H(Device to Host) Register FIS(Frame Information Structure)。
再看SATA 3.5a 11.2,不管是reset还是init,都要通过FIS send status,这就是第一个FIS了,且不管是good还是bad,Field LBA和Count都一致。所以,PxSIG对应的ATA是00000101h,ATAPI是EB140101h。
- Command - Identify (Packet) Device
根据ATA/ATAPI Command Set - 3,Identify Device is for ATA and ATAPI,Identify Packet Device is for ATAPI。Identify数据包含有关可选功能和命令支持的信息,如果host发出一个不支持的命令,device应当返回已终止的命令。
接下来该发命令了,先了解一下相关内容。device和host有两种数据交互方式,PIO和DMA。PIO - Programmed Input/Output,指处理器参与数据搬运。DMA都很熟悉了,DMA控制器参与。然后就是这种数据结构称为FIS,这里只介绍使用到的FIS结构。Register Host to Device FIS(type 27h),根据描述可知 Identify Device属于Register Host to Device FIS类型。
从右往左,地址从低到高。
再结合ATA/ATATPI command set - 3中 input
FIS Type 27h。PM Port和Ahci CAP(00h) Supports Port Multiplier(bit17)有关,我这边不支持。R是Reserved,应该填0。C表示来自host command(1b)还是device control(0b)。Command ECh。Features Count和LBA全是N/A。Device bit4定义很模糊就不管了。其他ICC和Auxiliary如下都是not present,还有一个control在ATA/ATAPI command set 3里没有说明,不过这个是device control用的,host应该用不到。Command FIS 至此填充完毕。
- 利用Ahci发送Command
再看看Ahci bar5内存空间
无处不在的指针,梳理一下。Ahci Pcie bar5地址中存放了Port Registers,最多支持32个,一般一个Port接一个SATA设备。Port Register中记录了Port x Command List Base Address和Port x FIS Base Address。Port x Command List有32个Command slot,command slot记录了command table base address。Port x FIS,详见Ahci 4.2.1。
接下来就要填充这些区域了,Command FIS Length (CFL)以Dword为单位,从最上面图10.5.5.1中知道这边填5,Clear Busy upon R_OK ©置1,Physical Region Descriptor Byte Count (PRDBC)这个是要从device接收的字节数,Identify命令需要接受512个字节,一个Physical Region Descriptor Table (PRDT)最多4MB,所以Physical Region Descriptor Table Length (PRDTL)是1。Command Table Base Address用自己分配的地址。
Command Table里CFIS用Identify Device FIS,ACMD用不到,PRDT只有一个,DBA是用来接收Device返回的Identify Data的,DBC是实际大小减一,I是Interrupt on Completion。
把所有数据准备好后,在Port空闲时发送,最后等待发送完毕。
代码的话直接调用UEFI接口就好了,然后参照Spec解析。