fpga nvme 寄存器
圖1所示的NVMe多隊列,每個隊列支持64K命令,最多支持64K隊列。這些隊列的設計使得IO命令和對命令的處理不僅可以在同一處理器內核上運行,也可以充分利用多核處理器的并行處理能力。每個應用程序或線程可以有自己的獨立隊列,因此不需要IO鎖定。NVMe還支持MSI-X和中斷控制,避免了CPU中斷處理的瓶頸,實現了系統擴展的可伸縮性。NVMe采用簡化的命令集,相比SAS或SATA,NVMe命令集使用的處理IO請求的指令數量減少了一半,從而在單位CPU指令周期內可以提供更高的IOPS,并且降低主機中IO軟件堆棧的處理延遲。
2 NVMe寄存器
NVMe(Over PCIe)寄存器主要分為兩類,一類是PCIe配置空間寄存器,一類是NVMe控制器相關的寄存器。
a.PCIe配置空間和功能
NVMe PCIe總線寄存器如表1所示,NVMe跟主機CPU的接口主要是基于PCIe總線,使用PCIe的Config和Capability機制。包括PCI/PCIe頭、PCI功能和PCIe擴展功能。
表1 NVMe PCIe配置空間和功能
?
b.NVMe控制器寄存器
NVMe控制器寄存器位于MLBAR/MUBAR寄存器(PCI BAR0和BAR1)中,這些寄存器應映射到支持順序訪問和可變訪問寬度的內存空間。NVMe 1.3d版本的控制器寄存器列表如表2所示。
表2 NVMe 1.3d版本的控制器寄存器列表
| 起始 | 結束 | 縮寫 | 描述 |
| 0h | 7h | CAP | 控制功能 |
| 8h | Bh | VS | 版本 |
| Ch | Fh | INTMS | 中斷屏蔽設置 |
| 10h | 13h | INTMC | 中斷屏蔽清楚 |
| 14h | 17h | CC | 控制器配置 |
| 18h | 1Bh | Reserved | 保留 |
| 1Ch | 1Fh | CSTS | 控制器狀態 |
| 20h | 23h | NSSR | NVM子系統重置(可選) |
| 24h | 27h | AQA | 管理隊列屬性 |
| 28h | 2Fh | ASQ | 管理提交隊列基地址 |
| 30h | 37h | ACQ | 管理完成隊列基地址 |
| 38h | 3Bh | CMBLOC | 控制器存儲緩沖位置(可選) |
| 3Ch | 3Fh | CMBSZ | 控制器存儲緩沖大小(可選) |
| 40h | 43h | BPINFO | 引導分區信息(可選) |
| 44h | 47h | BPRSEL | 引導分區讀選擇(可選) |
| 48h | 4Fh | BPMBL | 引導分區存儲緩沖位置(可選) |
| 50h | EFFh | Reserved | 保留 |
| F00h | FFFh | Reserved | 命令設置具體的寄存器 |
| 1000h | 1003h | SQ0TDBL | 管理SQ0尾Db |
| 1000h + (1 * (4 << CAP.DSTRD)) | 1003h + (1 * (4 << CAP.DSTRD)) | CQ0HDBL | 管理CQ0頭Db |
| 1000h + (2 * (4 << CAP.DSTRD)) | 1003h + (2 * (4 << CAP.DSTRD)) | SQ1TDBL | SQ1尾Db |
| 1000h + (3 * (4 << CAP.DSTRD)) | 1003h + (3 * (4 << CAP.DSTRD)) | CQ1HDBL | CQ1頭Db |
| … | … | … | … |
| 1000h+ (2y * (4 << CAP.DSTRD)) | 1003h + (2y * (4 << CAP.DSTRD)) | SQyTDBL | SQy尾Db |
| 1000h + ((2y + 1) * (4 << CAP.DSTRD)) | 1003h + ((2y + 1) * (4 << CAP.DSTRD)) | CQyHDBL | CQy頭Db |
| 供應商定制寄存器(可選) | |||
| SQ:Submission Queue,提交隊列;CQ:Completion Queue,完成隊列;Db:Doorbell,門鈴。 |
3 NVMe隊列
NVMe的隊列是經典的環形隊列結構,通過提交/完成隊列對來實現隊列的傳輸交互。
a.隊列概述
NVMe使用的是經典的循環隊列結構來傳遞消息(例如,傳遞命令和命令完成通知)。隊列可以映射到任何PCIe可訪問的內存中,通常是放在主機內存。
如圖2,隊列是固定大小的,通過Tail和Head來分別指向寫入和讀取的指針。像通常的隊列數據結構一樣,隊列實際可使用的大小是隊列大小減1,并且用Head等于Tail指示隊列空,用Head等于(Tail+1)除以隊列大小的余數來指示隊列滿。
?如上一節的圖1,根據用途,NVMe隊列有兩類:管理隊列和IO隊列;根據傳輸方向有兩類:提交隊列和完成隊列。具體介紹見表3。
表3 NVMe隊列類型
| 管理 | IO | |
| 提交 | 用于提交管理命令,最大4K項; 用于配置控制器和IO隊列等; 從主機側到控制器側。 | 用于傳輸IO命令,最大64K項; 用于提交IO操作命令; 從主機側到控制器側。 |
| 完成 | 管理命令的完成確認,最大4K項; 從控制器側到主機側; 獨立的MSI-X中斷處理。 | IO命令的完成確認,最大64K項; 從控制器側到主機側; 獨立的MSI-X中斷處理。 |
b.隊列處理流程
NVMe的驅動和設備交互跟Virtio不同:Virtio是在通過一個隊列完成雙向通知交互;而NVMe則采用提交隊列和完成隊列配合完成雙向交互的方式。
如圖3,NVMe隊列處理流程如下(其中主機為軟件驅動,控制器為硬件設備):
(1)主機寫命令到提交隊列項中。
(2)主機寫DB(Doorbell)寄存器,通知控制器有新命令待處理。
(3)控制器從內存中的提交隊列中讀取命令。
(4)控制器執行命令。
(5)控制器更新完成隊列,表示當前的SQ項已經處理。
(6)控制器發MSI-x中斷到主機CPU。
(7)主機處理完成隊列,同步更新提交隊列中的已處理項。
(8)主機寫完成隊列Db到控制器,告知完成隊列項已釋放。
4 NVMe命令結構
我們通過如下一些概念來理解NVMe命令結構:
隊列項的數據格式。NVMe的提交命令固定64字節,完成命令固定16字節。
命令。NVMe命令分為Admin和IO兩類。
NVMe的數據塊組織方式有PRP和SGL兩種。
a.隊列項的數據格式
提交隊列和完成隊列,組成隊列對,協作完成NVMe驅動和設備之間的命令傳輸。提交隊列每一項64字節固定大小,完成隊列每一項16字節固定大小。
提交隊列的數據格式如圖4所示。NVMe提交隊列項的數據格式屬性如下:
Opcode:命令操作碼
FUSE:熔合兩個命令為一條命令
PSDT:PRP或SGL數據傳輸
Command Identifier:命令ID
Namespace Identifier:命名空間ID
Metadata Pointer:元數據指針
PRP entry 1/2:物理區域頁項,對應的由PRP和PRP列表
SGL:散列聚合列表
?完成隊列的數據格式如圖5所示。
圖5 完成隊列項的數據格式
NVMe完成隊列的數據格式屬性如下:
SQ Header pointer:SQ頭指針
SQ Identifier:SQ ID
Command Identifier:命令ID
P:相位標志phase tag,完成隊列沒有head/tail交互,通過相位標志實現完成隊列項的釋放
Status Field:狀態域
b.NVMe命令
NVMe管理類的命令如表4所示。
表4 NVMe管理命令列表
NVMe IO類命令如表5所示。
表5 NVMe IO類命令列表
| 命令 | 必選或可選 | 類別 |
| 創建IO SQ | 必選 | 隊列管理 |
| 刪除IO SQ | 必選 | |
| 創建IO CQ | 必選 | |
| 刪除IO CQ | 必選 | |
| 鑒別 | 必選 | 配置 |
| 獲取特征 | 必選 | |
| 設置特征 | 必選 | |
| 獲取日志頁 | 必選 | 狀態報告 |
| 異步事件請求 | 必選 | |
| 中止 | 必選 | 中止命令 |
| 固件鏡像下載 | 可選 | 固件更新和管理 |
| 固件可用 | 可選 | |
| IO命令集定制命令 | 可選 | IO命令集定制 |
| 供應商定制命令 | 可選 | 供應商定制 |
NVMe IO類命令如表5所示。
表5 NVMe IO類命令列表
| 命令 | 必選或可選 | 類別 |
| 讀 | 必選 | 必選的數據命令 |
| 寫 | 必選 | |
| 清洗 | 必選 | |
| 不可改正的寫 | 可選 | 可選的數據命令 |
| 寫0 | 可選 | |
| 比較 | 可選 | |
| 數據集管理 | 可選 | 數據提示 |
| 預約獲取 | 可選 | 預約命令 |
| 預約寄存器 | 可選 | |
| 預約釋放 | 可選 | |
| 預約報告 | 可選 | |
| 供應商專用命令 | 可選 | 供應商專用 |
c.物理區域頁PRP
PRP本質是一個鏈表,鏈表中的每一個指針都指向一個不超過頁大小的數據塊。PRP為8字節(64bits)固定大小,PRPList則最多可以占滿一整個頁。
PRP1和PRP2的格式如圖6(a)所示。如果是首個PRP,則Offset(偏移量)可能是非零的數據,另外,偏移量是32bits對齊的(即末尾兩位為0)。如圖6(b)所示,在PRP列表中的所有PRP項的偏移量都為0,也即是PRP指針指向頁面起始地址。
?如圖7(a)所示,當數據只有一個或兩個頁面的時候,就不需要使用PRP列表數據結構,直接PRP1和PRP2指向內存頁面。當一個命令指向的數據超過兩個內存頁面的時候,就需要使用PRP列表,圖7(b)所顯式的為使用PRP列表的數據結構。
(b) 范例2:PRP列表指針,指向PRP列表,再指向內存頁面
圖7 PRP數據結構范例
d.散列聚合列表SGL
PRP每個鏈表指針最多指向一個頁大小的數據塊,即使若干個頁在內存連續放置,PRP也需要對應的多個PRP項。為了減少元數據規模,SGL不限制指針指向數據塊的大小,這樣連續的若干個頁的數據,只需要一個SGL項就可以標識。
NVMe中SGL的長度為16字節固定長度,其格式如圖8(a)所示,在最高的第15字節SGL描述符類型域和子類型域標識不同類型的SGL描述符,根據不同的描述符,字節14-0的格式各有不同。SGL描述符類型如圖8(b)所示。
如圖9,NVMe SGL的數據結構是鏈表形式,SQ中的首個SGL段只有1項,為指向下一個SGL段的指針。下一個SGL段包含若干SGL數據塊描述符,SGL段的最后的一個SGL描述符為另一個SGL段指針,指向下一個SGL段。根據傳輸數據大小,在最后一個SGL 段中,所有的SGL描述符都是SGL數據塊描述符。
PRP只能指向單個內存頁,這樣,當要傳輸的數據塊非常大的時候,就需要非常多的PRP項。而SGL可以指向不同大小的數據塊,處于連續內存區域的多個數據塊只需要一個SGL描述符就可以標識。因此,一般情況下,SGL比PRP更高效,更節省描述符資源。
NVMe over PCIe協議,定義了NVMe協議的使用范圍、指令集、寄存器配置規范等。
1.1 名詞解釋
1.1.1 Namespace
Namespace是一定數量邏輯塊(LB)的集合,屬性在Identify Controller中的數據結構中定義。
1.1.2 Fused Operations
Fused Operations可以理解為聚合操作,只能聚合兩條命令,并且這兩條命令在隊列中應保持相鄰順序。協議中只有NVM指令才有聚合操作。還需要保證聚合操作的兩條命令讀寫的原子性,參考Compare and Write例子。
1.1.3 指令執行順序
除了聚合操作(Fused Operations),每一條SQ中的命令都是獨立的,不必考慮RAW等數據相關問題,即使考慮,也是host應該解決的問題。
1.1.4 寫單元的原子性
控制器需要支持寫單元的原子性。但有時也能通過host配置Write Atomicity feature,減小原子性單元的大小,提高性能。
1.1.5 元數據
數據的額外信息,相當于提供校驗功能。可選的方式。
1.1.6 仲裁機制
用來選擇下一次執行的命令的SQ的機制,三種仲裁方式:
-
RR(每個隊列優先級相同,輪轉調度)
-
帶權重的RR(隊列有4種優先級,根據優先級調度)
-
自定義實現
-
1.1.8 Queue Pair
由SQ(提交隊列)與CQ(完成隊列)組成,host通過SQ提交命令,NVMe Controller通過CQ提交完成命令。
1.1.9 NVM 子系統
NVM子系統包括控制器、NVM存儲介質以及控制器與NVM之間的接口。
1.2 NVMe SSD
1.2.1基本架構
整體來看,NVMe SSD可以分為三部分,host端的驅動(NVMe官網以及linux、Windows已經集成了相應的驅動)、PCIe+NVMe實現的控制器以及FTL+NAND Flash的存儲介質。
-
?
1.2.2 NVMe控制器
NVMe控制器實質上為DMA + multi Queue,DMA負責數據搬運(指令+用戶數據),多隊列負責發揮閃存的并行能力。
-
?
2. PCIe寄存器配置
NVMe over PCIe,通過利用PCIe總線實現數據交互的功能,實現對物理層的抽象功能。
2.1 PCIe總線的基本結構
PCIe總線分為三層,物理層,數據鏈路層,處理層(類似于計算機網絡的分層結構),通過包來轉發數據。NVMe協議定義的內容相當于PCIe的上一層應用層,處于應用層。PCIe給NVMe提供了底層的抽象。
NVMe SSD相當于一個PCIe的端設備(EP)。
-
?
2.2 寄存器配置
在協議中主要定義了PC header、PCI Capabilities和PCI Express Extended Capabilities三部分內容。
具體在host內存中會占有4KB,結構如下:
-
?
2.2.1 PCI header
PCI header有兩種類型,type0表示設備,type1表示橋。NVMe 控制器屬于EP,所以定義為type0的類型。共64KB,如下圖:
-
?
2.2.2 PCI Capabilities
這里配置了PCI Capbilities,包括電源管理、中斷管理(MSI、MSI-X)、PCIe Capbilities。
2.2.3 PCI Express Extended Capabilities
這里配置有關錯誤恢復等高級功能。
3. NVMe寄存器配置
3.1 寄存器定義
NVMe寄存器主要分為兩部分,一部分定義了Controller整體屬性,一部分用來存放每組隊列的頭尾DB寄存器。
-
CAP——控制器能力,定義了內存頁大小的最大最小值、支持的I/O指令集、DB寄存器步長、等待時間界限、仲裁機制、隊列是否物理上連續、隊列大小;
-
VS——版本號,定義了控制器實現NVMe協議的版本號;
-
INTMS——中斷掩碼,每個bit對應一個中斷向量,使用MSI-X中斷時,此寄存器無效;
-
INTMC——中斷有效,每個bit對應一個中斷向量,使用MSI-X中斷時,此寄存器無效;
-
CC——控制器配置,定義了I/O SQ和CQ隊列元素大小、關機狀態提醒、仲裁機制、內存頁大小、支持的I/O指令集、使能;
-
CSTS——控制器狀態,包括關機狀態、控制器致命錯誤、就緒狀態;
-
AQA——Admin 隊列屬性,包括SQ大小和CQ大小;
-
ASQ——Admin SQ基地址;
-
ACQ——Admin CQ基地址;
-
1000h之后的寄存器定義了隊列的頭、尾DB寄存器。
-
?3.2 寄存器理解
-
CAP寄存器標識的是Controller具有多少能力,而CC寄存器則是指當前Controller選擇了哪些能力,可以理解為CC是CAP的一個子集;如果重啟(reset)的話,可以更換CC配置;
-
CC.EN置一,表示Controller已經可以開始處理NVM命令,從1到0表示Controller重啟;
-
CC.EN與CSTS.RDY關系密切,CSTS.RDY總是在CC.EN之后由Controller改變,其他不符合執行順序的操作都將產生未定義的行為;
-
Admin隊列有host直接創建,AQA、ASQ、ACQ三個寄存器標識了Admin隊列,而其他I/O隊列則有Admin命令創建(eg,創建I/O CQ命令);
-
Admin隊列的頭、尾DB寄存器標識為0,其他I/O隊列標識由host按照一定規則分配;只有16bit的有效位,是因為隊列深度最大64K。
?4. 內存數據結構
4.1 SQ與CQ的詳細定義
4.1.1 空隊列
?
4.1.2 滿隊列
判斷隊列滿可以有多種方法,協議中規定的是頭指針比尾指針大一,所以隊列滿時,空余一個元素。
?
4.1.3 隊列性質
1. 隊列大小有16bit,最小隊列大小為2個元素(因為滿隊列的定義方式,所以最小為2個元素),對于I/O隊列,最大隊列大小為64k;對于Admin隊列,最大隊列為4k;
2. QID來標識唯一ID,16bit,由host分配;
3. host可以修改隊列優先級(如果支持的話),共四級,U、H、M、L;
4.2 仲裁機制
4.2.1 RR
RR仲裁,Admin SQ與I/O SQ優先級相同,控制器每次可以選擇一個隊列中的多個命令(Arbitration Burst setting)。
?
4.2.2 帶有優先權的RR
有3個嚴格的優先權,Priority1 > Priority2 > Priority3,在這三個優先級隊列中,高優先級的隊列中如果有命令,則優先執行(非搶占式)。
?
4.2.3 其他仲裁方式
Vendor Specific。
4.3 數據尋址方式(PRP和SGL)
4.3.1 PRP
NVMe把Host的內存分為頁的集合,頁的大小在CC寄存器中配置,PRP是一個64位的內存物理地址指針,結構如下:
?
最后兩位為0,指四字節對齊;(n:2)位表示頁內內偏移。
舉個例子,內存頁大小位4KB,則(11:2)表示頁內偏移。
PRP尋址有兩種方式,直接用PRP指針尋址,通過PRP List尋址。當使用PRP List尋址時,偏移必須為0h,每一個PRP條目表示一個內存頁,如下:
?
?
Admin命令的數據地址只能采取PRP的方式,I/O命令的數據地址既可以采取PRP的方式,又可以采取SGL的方式。Host在命令中會告訴Controller采用何種方式。具體來說,如果命令當中DW0[15:14]是0,就是PRP的方式,否則就是SGL的方式。
命令的Dword6~Dword9只定義了PRP1、PRP2兩個數據指針,通過PRP條目可以指向PRP List。如下圖:
?
?
在上面的例子中,PRP1直接指向內存頁,PRP2指向PRP List存在的地址,在PRP List中存有數據的真正的地址。
更詳細的說:
協議中PRP Entry是一個指向物理內存頁的指針。PRP被用作NVMe Controller和PC內存之間進行數據傳輸。PRPEntry是固定大小的(8B)。
首先,明確兩個概念,PRP Entry 為PRP指針,PRP List為PRP列表指針,示意圖如下:
?
?
根據每次傳輸數據的大小,以及PRP指針的偏移(offset)可以分為以下五種情況:
?
?
?
4.3.2 SGL
SGL是另外一種索引內存的數據結構。SGL由若干個SGL段組成,SGL段又由若干個SGL描述符組成,所以SGL描述符是SGL數據結構的基本單位。
目前定義的SGL描述符有6種:
5.4 NVM指令
NVMe控制器讀寫的最小單元是LB,層次圖如下:
?NVM指令與Admin指令結構完全相同,也是通過Dword0中的8位操作碼來定義不同指令。
SGL 數據描述符,用來索引數據塊地址,host內存;
SGL 垃圾數據描述符,用來索引無用數據;
SGL 段描述符,用來索引下一個SGL段;
SGL 最后一個段描述符,用來索引最后一個SGL段;
keyed SGL 數據描述符;
Transport SGL 數據描述符;
?
在上面SGL例子中,共有3個SGL段,用到了4種SGL描述符。Host需要往SSD中讀取13KB的數據,其中真正只需要11KB數據,這11KB的數據需要放到3個大小不同的內存中,分別是:3KB,4KB和4KB。
4.3.3 比較PRP與SGL
無論是PRP還是SGL,本質都是描述內存中的一段數據空間,這段數據空間在物理上可能連續的,也可能是不連續的。Host在命令中設置好PRP或者SGL,告訴Controller數據源在內存的什么位置,或者從閃存上讀取的數據應該放到內存的什么位置。
SGL和PRP本質的區別在于,一段數據空間,對PRP來說,它只能映射到一個個物理頁,而對SGL來說,它可以映射到任意大小的連續物理空間,具有更大的靈活性,也能夠描述更大的數據空間。如下圖:
?
5. NVMe協議定義的命令
5.0 命令執行過程
命令由host提交到內存中的SQ隊列中,更新TDBxSQ后,NVMe控制器通過DMA的方式將SQ中的命令(怎么取,如何取,取多少,因設計而異)取到控制器緩沖區,執行命令;執行完成后,根據執行狀態,組裝完成命令,仍然通過DMA的方式將完成命令寫入內存CQ的隊列中;NVMe控制器通過MSI-X中斷方式通知host已完成命令;最后,host處理CQ命令,更新控制器中HDBxCQ,標識著命令真正完成。
5.1 命令分類
命令分為Admin指令與NVM指令(I/O指令)。
Admin指令只能提交到Admin Controller中,主要負責管理NVMe控制器,也包含對NVM的一些控制指令。
NVM 指令只能提交到I/O Controller中,主要負責完成數據的傳輸。
在1.0e版本中,Admin指令有15條(3條與NVM相關),NVM指令有6條;在1.3d版本中,Admin指令有15條(3條與NVM相關),NVM指令有11條。
5.2 命令通用格式
命令均為64字節,具有相同的格式,某些字段根據命令的不同有不同的定義。
完成命令同樣具有相同的格式,某些字段根據命令的不同有不同的定義。
5.3 Admin 指令
Admin指令與NVM指令根據放置的的隊列組(Queue Pair)來區分,Admin指令在Admin CQ與SQ里,NVM指令在I/O CQ與SQ里。
通過Dword0中的8位操作碼定義不同指令,注意并不是絕對的順序增加(eg,沒有03h)。每一種指令都對應有其完成命令,通過SQID(提交隊列ID)+CID(命令ID)唯一標識完成的命令。
Note:
Admin隊列是通過配置ASQ等寄存器創建的
先創建CQ再創建SQ
6 控制器結構
控制器從功能上可以分為三類,I/O、Admin和Discovery
?
在實現過程中,Admin 控制器只有一個,負責管理控制器及其他控制功能。控制器只是抽象的概念,應用于具體的實現中,可能是一個具體的模塊,也可能多個模塊。
控制器主要的作用是實現對NVMe定義命令的翻譯,從而實現數據傳輸、狀態控制等功能。
6.1 命令執行過程
1. host將命令(1條或者多條)寫入提前分配好的SQ中;
2. 更新對應SQ的DB寄存器;
3. NVMe控制器取SQ中命令(通過HDB和TDB可以判斷是否有未完成命令);
4. NVMe控制器執行命令;
5. NVMe 控制器在命令完成后,將完成命令(可能執行成功,也可能失敗,但都會返回完成命令)寫入host內存SQ對應的CQ中;
6. NVMe 控制器根據實現的中斷方式,提醒host命令已完成;
7. host響應中斷,處理完成命令;
8. host 更新對應CQ的DB寄存器。
?
6.2 重啟(Reset)
6.2.1 Controller level
Controller重啟可能發生在PCIe總線重啟、PCI重啟、控制器CC.EN從1到0重啟。當重啟發生時:
所有的I/O SQ和CQ都被刪除;
所有未完成的指令(Admin和I/O)應該執行撤銷操作;
Controller處于idele狀態,CSTS.RDY清0;
AQA、ASQ、ACQ不受影響。
重啟后,host操作:
更新寄存器狀態;
將CC.EN置1;
等待CSTS.RDY置1;
使用Admin命令配置Controller;
創建I/O CQ和SQ;
執行正常的I/O指令。
6.2.2 Queue level
隊列水平的重啟,即,刪除該隊列,再重新創建一個新隊列。刪除隊列的時候,host應該保證隊列處于idle狀態(所有命令均已完成——接收到了完成命令),否則的話,可能會導致CQ接收不到提交命令的完成命令。
6.3 中斷
在Controller完成SQ命令后,根據執行狀態,將結果組裝成完成命令寫入CQ中,Controller通過中斷機制通知Host處理完成命令。
NVMe協議中支持的中斷方式有4種,pin-based、Single MSI、Multi-message MSI和MSI-X,協議推薦采用MSI-X中斷方式,能夠支持更多的中斷向量(2K)。
MSI-X允許每一個CQ發送自己的中斷信息(相比于發一條中斷信息提醒全部CQ隊列有很大的優勢)。在產生MSI-X中斷信息前,需要檢查該中斷在相應寄存器種不被屏蔽。
6.4 Controller初始化
Controller的初始化過程:
設置PCI和PCIe寄存器;
等待CSTS.RDY變為;
配置AQA、ASQ、ACQ寄存器;
配置CC寄存器;
將CC.EN置1;
等待CSTS.RDY置1
Host通過Identify命令,確定Controller的數據結構、確定Namespace的數據結構;
Host通過get features(協議中是set features,待研究)獲取I/O SQ和CQ信息,然后配置中斷機制;
Host分配適當的I/O CQ、SQ隊列;
如果Host希望獲取Controller的錯誤或健康信息,可以添加異步事件請求命令。
Controller 關機
正常關機:
Host停止提交新的I/O命令,但允許未完成的命令繼續完成;
Host刪除所有I/O SQ,刪除所有SQ隊列后,所有未完成的命令將被撤銷;
Host刪除所有I/O CQ;
Host將CC.SHN置01b,表示正常關機;關機程序完成時,將CSTS.SHST置10b。
突然關機:
Host停止提交新的I/O命令;
Host將CC.SHN置10b,表示突然關機;關機程序完成時,將CSTS.SHST置10b
6.5 host端命令實例
6.5.1 創建命令
?6.5.2 處理完成命令
?
6.6 NVMe與PCIe交互實例(分析包結構)
以Host發出read命令為例。
Host準備了一個Read命令給SSD:
?
分析該包,Host需要從起始LBA 0x20E0448(SLBA)上讀取128個DWORD (512字節)的數據,讀到哪里去呢?PRP1給出內存地址是0x14ACCB000。這個命令放在編號為3的SQ里 (SQID = 3),CQ編號也是3 (CQID = 3)
Host通過寫SQ的Tail DB,通知Controller來取命令:
?上圖中,上層是NVMe層,下層是PCIe傳輸層的TLP。Host想往SQ Tail DB中寫入的值是5。PCIe是通過一個Memory Write TLP來實現Host寫CQ的Tail DB的。該Tail DB寄存器映射在Host的內存地址為F7C11018,由于NVMe 的寄存器映射到了Host內存中,所以可以根據這個地址寫入寄存器值
SSD收到通知,去Host端的SQ中取指
?
PCIe是通過發一個Memory Read TLP到Host的SQ中取指的。可以看到,PCIe需要往Host內存中讀取16個DWORD的數據(一個NVMe指令大小),
SSD執行讀命令,把數據從閃存中讀到緩存中,然后把數據傳給Host:
?
SSD是通過Memory write TLP 把Host命令所需的128個DWORD數據寫入到Host命令所要求的內存中去。SSD每次寫入32個DWORD,一共寫了4次。
SSD往Host的CQ中返回狀態:
?
SSD是通過Memory write TLP 把16個字節的命令完成狀態信息寫入到Host的CQ中。
SSD采用中斷的方式告訴Host去處理CQ
?
上圖使用的是MSI-X中斷方式。這種方式將中斷信息和正常的數據信息一樣,PCIe打包把中斷信息告知Host。SSD還是通過Memory Write TLP把中斷信息告知Host,這個中斷信息長度是1DWORD。
Host處理相應的CQ
Host處理完相應的CQ后,需要更新SSD端的CQ Head DB告知SSD處理
完成:
?
Host還是通過Memory Write TLP更新SSD端的CQ Head DB。
該過程完整的包流程如下:
?
7. NVMe features
7.1 固件(Firmware)更新過程
1. 將固件下載到Controller中(使用 Firmware Image Download命令);
2. Host提交Firmware Activate命令(也可以激活之前版本的Controller鏡像);
3. Controller reset;
4. reset完成后,Host重新初始化Controller,包括Host重新分配I/O隊列,與reset步驟相同。
7.2 元數據(Metadata)傳輸
元數據的使用并沒有強制規定,最經常的使用方法是用做端到端數據的保護信息。有兩種傳輸元數據的方式,一種可以作為LB數據塊的一部分,如下圖:
?
7.3 端到端的數據保護
端到端,一端指主機的內存空間,一端指閃存空間(NVM)。數據傳輸的兩個環節如下圖:
?
?
數據在PCIe上傳輸的時候,由于信道噪聲的存在(說白了就是存在干擾),可能導致數據出錯;另外,Controller閃存之間,數據也可能發生錯誤。采用元數據進行數據的保護是最常用的一種手段。
充當保護數據角色的元數據結構如下:
?其中,Guard為16bit的CRC校驗碼,Application Tag與LBAT相關,Reference Tag將用戶數據和地址(LBA)相關聯。下圖為以512bytes的數據塊為例:
?
那么按照排列組合,共有四種保護情況(1帶2帶、1不帶2不帶、1帶2不帶、1不帶2帶)。但由于協議中控制保護信息的只有兩個字段(1. 是否采用保護 2. PRACT位),只有三種情況,如下圖(是以寫命令為例,讀命令相同):
?
?
總結
以上是生活随笔為你收集整理的fpga nvme 寄存器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flask学习之4:图片验证码
- 下一篇: 清道夫受体-A靶向脂肪酸修饰白蛋白纳米粒