首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

[元带你学NVME协议] NVME 读一个 IO 是怎么完成的?

  • 24-03-08 05:20
  • 2827
  • 14095
blog.csdn.net

 传送门:  >>>  总目录

主页:元存储的博客_CSDN博客

前言

Host是如何读取NVMe SSD上数据的?一个读I/O又有多少步操作?
“八步。”NVMe协议这样回答。这是个非常底层的问题,其整个流程不仅涉及NVMe协议本身,其中命令和I/O数据传输的机制还与PCIe协议等内容息息相关。理解一个NVMe SSD的I/O处理流程将为SSD使用和优化打下基础。今天我们就走进一个NVMe SSD的读I/O。


1 概念


在介绍NVMe SSD的读IO处理流程之前,需要往下一层到达PCIe层。无论是NVMe的命令本身,还是要传输的数据,最终都会被封装成为TLP包进行传输。AIC、U.2以及M.2等形态的NVMe SSD也都是借助PCIe插槽与host进行交互的。


PCI Express Layered Model
上图就详细说明了PCIe 协议中每层的内容。后文中我们会通过一个trace记录,结合NVMe记录和TLP包信息对NVMe的读I/O进行解读。
NVMe协议通过下图描述了一个完整的命令处理流程:

 

本文使用的是《NVM ExpressTM Revision 1.2a》(以下简称“NVMe协议”),严谨起见,在此注明版本,需要说明的是不同的NVMe协议版本在读操作中没有本质的不同,也不会影响到本文的描述。
本文介绍的是NVMe over PCIe的读I/O,不涉及NVMe over Fabrics或者其他网络传输。

为了更好的理解上图中命令处理过程的细节,我们总结如下:

  1. 一个I/O命令执行过程中,host和SSD是两个主角。读I/O也就是host发起读请求,SSD响应请求,并且将数据写到host指定的内存地址上的过程。
  2. Submission Queue 和Completion Queue是host内存中的两个队列,host通过Submission Queue告知SSD的Controller要处理的命令,Controller通过Completion Queue告知Host已经被处理完毕的命令以及这些命令执行的状态。
    需要补充的是, NVMe的命令分为Admin Command和NVM Command,Admin Command执行一些SSD管控操作,比如Namespace管理和固件升级等,系统中只有一对Admin Submission Queue和Admin Completion Queue;NVM Command用于执行读写等I/O命令,可以有多对I/O Submission Queue和I/O Completion Queue。


 前文介绍了一些概念和部分操作细节,接下来是更为形象和深入的解读。在此我们还要借助协议分析仪,分析仪的职责是将host和SSD传输的0和1翻译成人话,借助支持NVMe协议的分析仪,我们获得了一条读I/O的Trace记录,如下图(每行信息记录都可以进一步展开看到相应的TLP包和DLLP包的信息):



分析仪可以对host和SSD之间传输的数据进行解析,并按照PCIe和NVMe的规范进行展示。有了这张图,我们就可以更为直观的看到每一步host和SSD都做了什么。接下来就开始了。首先是这条命令执行过程信息的概览。

可以看出,这次我们使用的设备是一个3.2TB的PBlaze5 916 NVMe SSD(以下简称为“PBlaze5”)。host从SSD上读出了1024dwords(4KiB)数据,这段数据在SSD上起始地址(SLBA)是0x8,一共8个LBA(NLB=0x7,这一参数为0’s based value)。数据将从SSD传输到0xFEB84000(PRP1)这个地址上,最终这个操作成功了(SC为Successful Completion)。

名词&概念
SLBA(Starting LBA):数据在SSD上的起始地址,这里的值是0x8。
NLB(Number of Logical Blocks):读取数据的blocks数,这里的值是0x7,需要指出的是这是一个0’s based value,所以最终传的是8个block。
NSID(Namespace Identifier):指明了此次读操作的namespace id,这里值为0x1。

命令信息被存放在ID为0x004C的Submission Queue(SQID)中,SSD处理完毕的信息会存放在ID为0x004C的Completion Queue(CQID)中。此外,这条记录还标注出了SSD在服务器上的ID(Device ID)等信息。

第一步:**host准备一条命令,并将之加入到内存中的Submission Queue中。**这步属于host自身的行为,还没有开始和SSD交换数据。
第二步:**host告知SSD有新的待处理。**这步操作包含很多细节,前文说过,SQyTDBL(Submission Queue y Tail Doorbell)是Controller Registers信息,映射在host的BAR 0空间中,其具体的地址是0xC6421260,这步中,host更新了这个地址中的值,将Submission Queue中有新记录的信息告知了SSD。

上图展示了host更新SQyTDBL的细节。第一行是NVMe协议层面的内容,下面则是具体的TLP包信息和ACK信息。到这SSD终于知道了有新的需求。
第三步。**SSD取Command。**从上文可知,命令具体内容被存放在Submission Queue中,SSD也知道了有新的命令需要处理,这里SSD首先发起一个Memory Read的请求。

host把命令内容信息通过另一个TLP包返回给SSD。一个Submission Queue记录是64byte,所以,可以看到一共传输了16个dwords,共64Bytes。而这16dwords中的内容翻译出来就是第一行NVMe 的内容,可以看到命令的地址、队列和命令的ID、操作类型(OPC)、数据的地址、以及SSD在系统中的Device ID都在其中了。有了这些内容,SSD就可以往指定的内存地址上写数据了。
第四步:**SSD处理Command。**对于host来讲,这是一个读取数据的操作。对于SSD来讲,就需要将相应的数据(SLBA为0x8,NLB为0x7)使用DMA的方式写到指定的内存地址(PRP1 Address为0xFEB84000)上。

系统的MaxPayloadSize为256bytes,超过就需要分开传输。所以这段1024dwords(4KiB)数据传输操作被拆分成了16个64dwords(256bytes)的TLP包。另一个重要的概念是PRP(Physical Region Page),本例中PRP1是一个host内存中的地址——0xFEB84000。SSD从内存的0xFEB84000开始写,最后一个TLP包的起始地址是0xFEB84F00。
NVMe规定了PRP和SGL两种数据传输方式,后者在NVMe over Fabrics中使用比较普遍,这里不再赘述。采用PRP方式的I/O命令都会有PRP1和PRP2两个地址,它们可以指向一个内存地址,也可以是一个物理地址列表,被称为PRP list,如果传输数据量超过两个内存页,就需要PRP list指明数据存放的地址。本文中例子数据量为4KiB,恰好为Linux的1个内存页大小,所以使用PRP1传一个物理地址就可以。更为复杂的PRP记录规范,可以参看NVMe协议的《Physical Region Page Entry and List》等内容。
第五步,到现在,SSD已经把数据传到了host指定的内存地址上。SSD会把命令执行的状态总结成为一条记录添加在Completion Queue中,具体的操作就是SSD向host内存的Completion Queue中添加一个4dwords(16bytes)的记录。

上图中NVMe返回的信息可见,SSD成功的完成了写,并在Status Code(SC)中记下Successful Completion的信息。如果整个命令过程有错误出现,那么SC也会记录下相应的错误信息。
第六步,**SSD发起中断,**通知host处理Completion Queue中的记录。数据传输完毕,执行状态也记录在了Completion Queue中,SSD通过MSI-X中断告知host做进一步的处理。

第七步。**host会处理相应的Completion Queue中的记录。**但是这部分细节发生在host内部,分析仪的trace记录不会捕捉到具体内容。
第八步。**Host更新内存中Completion Queue y Head Doorbell信息,**相应的Controller Registers中Doorbell信息也会进行更新。至此,一个读I/O已经处理完毕。

NVMe协议中还规定了很多其他的命令,根据其命令类型不同,返回值和对内存的操作也各不相同,但原理和本文中介绍的读I/O相似,相信看完本文,您可以触类旁通,理解NVMe 协议中host和SSD的交互机制。


参考

《深入浅出SSD 固态存储核心技术、原理与实战》第6章 NVMe介绍
《NVM Express Revision 1.2a》

原文出处:版权归原作者所有

让我们走进一个NVMe读I/O - 爱码网

免责声明:

本文根据公开信息整理,旨在介绍更多的存储知识,所载文章仅为作者观点,不构成投资或商用建议。本文仅用于学习交流, 不允许商用。若有疑问或有侵权行为请联系作者处理。

注:本文转载自blog.csdn.net的元存储的文章"https://blog.csdn.net/vagrant0407/article/details/130311307"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top