收藏:NVMe協(xié)議基礎(chǔ)原理介紹


概述:NVM Express(NVMe),或稱非易失性內(nèi)存主機(jī)控制器接口規(guī)范(英語(yǔ):Non Volatile Memory Host Controller Interface Specification,縮寫:NVMHCIS),是一個(gè)邏輯設(shè)備接口規(guī)范。它是與AHCI類似的、基于設(shè)備邏輯接口的總線傳輸協(xié)議規(guī)范(相當(dāng)于通訊協(xié)議中的應(yīng)用層),用于訪問(wèn)通過(guò)PCI Express(PCIe)總線附加的非易失性存儲(chǔ)器介質(zhì)(例如采用閃存的固態(tài)硬盤驅(qū)動(dòng)器),雖然理論上不一定要求 PCIe 總線協(xié)議。
1. 綜述
NVMe over PCIe協(xié)議,定義了NVMe協(xié)議的使用范圍、指令集、寄存器配置規(guī)范等。
1.1 名詞解釋
1.1.1 Namespace
Namespace是一定數(shù)量邏輯塊(LB)的集合,屬性在Identify Controller中的數(shù)據(jù)結(jié)構(gòu)中定義。
1.1.2 Fused Operations
Fused Operations可以理解為聚合操作,只能聚合兩條命令,并且這兩條命令在隊(duì)列中應(yīng)保持相鄰順序。協(xié)議中只有NVM指令才有聚合操作。還需要保證聚合操作的兩條命令讀寫的原子性,參考Compare and Write例子。
1.1.3 指令執(zhí)行順序
除了聚合操作(Fused Operations),每一條SQ中的命令都是獨(dú)立的,不必考慮RAW等數(shù)據(jù)相關(guān)問(wèn)題,即使考慮,也是host應(yīng)該解決的問(wèn)題。
1.1.4 寫單元的原子性
控制器需要支持寫單元的原子性。但有時(shí)也能通過(guò)host配置Write Atomicity feature,減小原子性單元的大小,提高性能。
1.1.5 元數(shù)據(jù)
數(shù)據(jù)的額外信息,相當(dāng)于提供校驗(yàn)功能??蛇x的方式。
1.1.6 仲裁機(jī)制
用來(lái)選擇下一次執(zhí)行的命令的SQ的機(jī)制,三種仲裁方式:
RR(每個(gè)隊(duì)列優(yōu)先級(jí)相同,輪轉(zhuǎn)調(diào)度)
帶權(quán)重的RR(隊(duì)列有4種優(yōu)先級(jí),根據(jù)優(yōu)先級(jí)調(diào)度)
自定義實(shí)現(xiàn)
1.1.7 邏輯塊(LB)
NVMe定義的最小的讀寫單元,2KB、4KB……,用LBA來(lái)標(biāo)識(shí)塊地址,LBA range則表示物理上連續(xù)的邏輯塊集合。
1.1.8 Queue Pair
由SQ(提交隊(duì)列)與CQ(完成隊(duì)列)組成,host通過(guò)SQ提交命令,NVMe Controller通過(guò)CQ提交完成命令。
1.1.9 NVM 子系統(tǒng)
NVM子系統(tǒng)包括控制器、NVM存儲(chǔ)介質(zhì)以及控制器與NVM之間的接口。
1.2 NVMe SSD
1.2.1基本架構(gòu)
整體來(lái)看,NVMe SSD可以分為三部分,host端的驅(qū)動(dòng)(NVMe官網(wǎng)以及l(fā)inux、Windows已經(jīng)集成了相應(yīng)的驅(qū)動(dòng))、PCIe+NVMe實(shí)現(xiàn)的控制器以及FTL+NAND Flash的存儲(chǔ)介質(zhì)。

1.2.2 NVMe控制器
NVMe控制器實(shí)質(zhì)上為DMA + multi Queue,DMA負(fù)責(zé)數(shù)據(jù)搬運(yùn)(指令+用戶數(shù)據(jù)),多隊(duì)列負(fù)責(zé)發(fā)揮閃存的并行能力。

2. PCIe寄存器配置
NVMe over PCIe,通過(guò)利用PCIe總線實(shí)現(xiàn)數(shù)據(jù)交互的功能,實(shí)現(xiàn)對(duì)物理層的抽象功能。
2.1 PCIe總線的基本結(jié)構(gòu)
PCIe總線分為三層,物理層,數(shù)據(jù)鏈路層,處理層(類似于計(jì)算機(jī)網(wǎng)絡(luò)的分層結(jié)構(gòu)),通過(guò)包來(lái)轉(zhuǎn)發(fā)數(shù)據(jù)。NVMe協(xié)議定義的內(nèi)容相當(dāng)于PCIe的上一層應(yīng)用層,處于應(yīng)用層。PCIe給NVMe提供了底層的抽象。
NVMe SSD相當(dāng)于一個(gè)PCIe的端設(shè)備(EP)。

2.2 寄存器配置
在協(xié)議中主要定義了PC header、PCI Capabilities和PCI Express Extended Capabilities三部分內(nèi)容。
具體在host內(nèi)存中會(huì)占有4KB,結(jié)構(gòu)如下:

2.2.1 PCI header
PCI header有兩種類型,type0表示設(shè)備,type1表示橋。NVMe 控制器屬于EP,所以定義為type0的類型。共64KB,如下圖:

2.2.2 PCI Capabilities
這里配置了PCI Capbilities,包括電源管理、中斷管理(MSI、MSI-X)、PCIe Capbilities。
2.2.3 PCI Express Extended Capabilities
這里配置有關(guān)錯(cuò)誤恢復(fù)等高級(jí)功能。
3. NVMe寄存器配置
3.1 寄存器定義
NVMe寄存器主要分為兩部分,一部分定義了Controller整體屬性,一部分用來(lái)存放每組隊(duì)列的頭尾DB寄存器。
CAP——控制器能力,定義了內(nèi)存頁(yè)大小的最大最小值、支持的I/O指令集、DB寄存器步長(zhǎng)、等待時(shí)間界限、仲裁機(jī)制、隊(duì)列是否物理上連續(xù)、隊(duì)列大?。?/span>
VS——版本號(hào),定義了控制器實(shí)現(xiàn)NVMe協(xié)議的版本號(hào);
INTMS——中斷掩碼,每個(gè)bit對(duì)應(yīng)一個(gè)中斷向量,使用MSI-X中斷時(shí),此寄存器無(wú)效;
INTMC——中斷有效,每個(gè)bit對(duì)應(yīng)一個(gè)中斷向量,使用MSI-X中斷時(shí),此寄存器無(wú)效;
CC——控制器配置,定義了I/O SQ和CQ隊(duì)列元素大小、關(guān)機(jī)狀態(tài)提醒、仲裁機(jī)制、內(nèi)存頁(yè)大小、支持的I/O指令集、使能;
CSTS——控制器狀態(tài),包括關(guān)機(jī)狀態(tài)、控制器致命錯(cuò)誤、就緒狀態(tài);
AQA——Admin 隊(duì)列屬性,包括SQ大小和CQ大?。?/span>
ASQ——Admin SQ基地址;
ACQ——Admin CQ基地址;
1000h之后的寄存器定義了隊(duì)列的頭、尾DB寄存器。
3.2 寄存器理解
CAP寄存器標(biāo)識(shí)的是Controller具有多少能力,而CC寄存器則是指當(dāng)前Controller選擇了哪些能力,可以理解為CC是CAP的一個(gè)子集;如果重啟(reset)的話,可以更換CC配置;
CC.EN置一,表示Controller已經(jīng)可以開(kāi)始處理NVM命令,從1到0表示Controller重啟;
CC.EN與CSTS.RDY關(guān)系密切,CSTS.RDY總是在CC.EN之后由Controller改變,其他不符合執(zhí)行順序的操作都將產(chǎn)生未定義的行為;
Admin隊(duì)列有host直接創(chuàng)建,AQA、ASQ、ACQ三個(gè)寄存器標(biāo)識(shí)了Admin隊(duì)列,而其他I/O隊(duì)列則有Admin命令創(chuàng)建(eg,創(chuàng)建I/O CQ命令);
Admin隊(duì)列的頭、尾DB寄存器標(biāo)識(shí)為0,其他I/O隊(duì)列標(biāo)識(shí)由host按照一定規(guī)則分配;只有16bit的有效位,是因?yàn)殛?duì)列深度最大64K。
4. 內(nèi)存數(shù)據(jù)結(jié)構(gòu)
4.1 SQ與CQ的詳細(xì)定義
4.1.1 空隊(duì)列

4.1.2 滿隊(duì)列
判斷隊(duì)列滿可以有多種方法,協(xié)議中規(guī)定的是頭指針比尾指針大一,所以隊(duì)列滿時(shí),空余一個(gè)元素。

4.1.3 隊(duì)列性質(zhì)
1. 隊(duì)列大小有16bit,最小隊(duì)列大小為2個(gè)元素(因?yàn)闈M隊(duì)列的定義方式,所以最小為2個(gè)元素),對(duì)于I/O隊(duì)列,最大隊(duì)列大小為64k;對(duì)于Admin隊(duì)列,最大隊(duì)列為4k;
2. QID來(lái)標(biāo)識(shí)唯一ID,16bit,由host分配;
3. host可以修改隊(duì)列優(yōu)先級(jí)(如果支持的話),共四級(jí),U、H、M、L;
4.2 仲裁機(jī)制
4.2.1 RR
RR仲裁,Admin SQ與I/O SQ優(yōu)先級(jí)相同,控制器每次可以選擇一個(gè)隊(duì)列中的多個(gè)命令(Arbitration Burst setting)。

4.2.2 帶有優(yōu)先權(quán)的RR
有3個(gè)嚴(yán)格的優(yōu)先權(quán),Priority1 > Priority2 > Priority3,在這三個(gè)優(yōu)先級(jí)隊(duì)列中,高優(yōu)先級(jí)的隊(duì)列中如果有命令,則優(yōu)先執(zhí)行(非搶占式)。

4.2.3 其他仲裁方式
Vendor Specific。
4.3 數(shù)據(jù)尋址方式(PRP和SGL)
4.3.1 PRP
NVMe把Host的內(nèi)存分為頁(yè)的集合,頁(yè)的大小在CC寄存器中配置,PRP是一個(gè)64位的內(nèi)存物理地址指針,結(jié)構(gòu)如下:

最后兩位為0,指四字節(jié)對(duì)齊;(n:2)位表示頁(yè)內(nèi)內(nèi)偏移。
舉個(gè)例子,內(nèi)存頁(yè)大小位4KB,則(11:2)表示頁(yè)內(nèi)偏移。
PRP尋址有兩種方式,直接用PRP指針尋址,通過(guò)PRP List尋址。當(dāng)使用PRP List尋址時(shí),偏移必須為0h,每一個(gè)PRP條目表示一個(gè)內(nèi)存頁(yè),如下:

Admin命令的數(shù)據(jù)地址只能采取PRP的方式,I/O命令的數(shù)據(jù)地址既可以采取PRP的方式,又可以采取SGL的方式。Host在命令中會(huì)告訴Controller采用何種方式。具體來(lái)說(shuō),如果命令當(dāng)中DW0[15:14]是0,就是PRP的方式,否則就是SGL的方式。
命令的Dword6~Dword9只定義了PRP1、PRP2兩個(gè)數(shù)據(jù)指針,通過(guò)PRP條目可以指向PRP List。如下圖:

在上面的例子中,PRP1直接指向內(nèi)存頁(yè),PRP2指向PRP List存在的地址,在PRP List中存有數(shù)據(jù)的真正的地址。
更詳細(xì)的說(shuō):
協(xié)議中PRP Entry是一個(gè)指向物理內(nèi)存頁(yè)的指針。PRP被用作NVMe Controller和PC內(nèi)存之間進(jìn)行數(shù)據(jù)傳輸。PRPEntry是固定大小的(8B)。
首先,明確兩個(gè)概念,PRP Entry 為PRP指針,PRP List為PRP列表指針,示意圖如下:


根據(jù)每次傳輸數(shù)據(jù)的大小,以及PRP指針的偏移(offset)可以分為以下五種情況:

4.3.2 SGL
SGL是另外一種索引內(nèi)存的數(shù)據(jù)結(jié)構(gòu)。SGL由若干個(gè)SGL段組成,SGL段又由若干個(gè)SGL描述符組成,所以SGL描述符是SGL數(shù)據(jù)結(jié)構(gòu)的基本單位。
目前定義的SGL描述符有6種:
SGL 數(shù)據(jù)描述符,用來(lái)索引數(shù)據(jù)塊地址,host內(nèi)存;
SGL 垃圾數(shù)據(jù)描述符,用來(lái)索引無(wú)用數(shù)據(jù);
SGL 段描述符,用來(lái)索引下一個(gè)SGL段;
SGL 最后一個(gè)段描述符,用來(lái)索引最后一個(gè)SGL段;
keyed SGL 數(shù)據(jù)描述符;
Transport SGL 數(shù)據(jù)描述符;

在上面SGL例子中,共有3個(gè)SGL段,用到了4種SGL描述符。Host需要往SSD中讀取13KB的數(shù)據(jù),其中真正只需要11KB數(shù)據(jù),這11KB的數(shù)據(jù)需要放到3個(gè)大小不同的內(nèi)存中,分別是:3KB,4KB和4KB。
4.3.3 比較PRP與SGL
無(wú)論是PRP還是SGL,本質(zhì)都是描述內(nèi)存中的一段數(shù)據(jù)空間,這段數(shù)據(jù)空間在物理上可能連續(xù)的,也可能是不連續(xù)的。Host在命令中設(shè)置好PRP或者SGL,告訴Controller數(shù)據(jù)源在內(nèi)存的什么位置,或者從閃存上讀取的數(shù)據(jù)應(yīng)該放到內(nèi)存的什么位置。
SGL和PRP本質(zhì)的區(qū)別在于,一段數(shù)據(jù)空間,對(duì)PRP來(lái)說(shuō),它只能映射到一個(gè)個(gè)物理頁(yè),而對(duì)SGL來(lái)說(shuō),它可以映射到任意大小的連續(xù)物理空間,具有更大的靈活性,也能夠描述更大的數(shù)據(jù)空間。如下圖:

5. NVMe協(xié)議定義的命令
5.0 命令執(zhí)行過(guò)程
命令由host提交到內(nèi)存中的SQ隊(duì)列中,更新TDBxSQ后,NVMe控制器通過(guò)DMA的方式將SQ中的命令(怎么取,如何取,取多少,因設(shè)計(jì)而異)取到控制器緩沖區(qū),執(zhí)行命令;執(zhí)行完成后,根據(jù)執(zhí)行狀態(tài),組裝完成命令,仍然通過(guò)DMA的方式將完成命令寫入內(nèi)存CQ的隊(duì)列中;NVMe控制器通過(guò)MSI-X中斷方式通知host已完成命令;最后,host處理CQ命令,更新控制器中HDBxCQ,標(biāo)識(shí)著命令真正完成。
5.1 命令分類
命令分為Admin指令與NVM指令(I/O指令)。
Admin指令只能提交到Admin Controller中,主要負(fù)責(zé)管理NVMe控制器,也包含對(duì)NVM的一些控制指令。
NVM 指令只能提交到I/O Controller中,主要負(fù)責(zé)完成數(shù)據(jù)的傳輸。
在1.0e版本中,Admin指令有15條(3條與NVM相關(guān)),NVM指令有6條;在1.3d版本中,Admin指令有15條(3條與NVM相關(guān)),NVM指令有11條。
5.2 命令通用格式
命令均為64字節(jié),具有相同的格式,某些字段根據(jù)命令的不同有不同的定義。
Dword0 | CID、傳輸方式、聚合操作、操作碼 |
1 | NID(命名空間ID) |
2 | 保留 |
3 | 保留 |
4、5 | 元數(shù)據(jù)指針(MPTR) |
6-9 | 數(shù)據(jù)指針(DPTR) |
10-15 | 根據(jù)命令指定 |
完成命令同樣具有相同的格式,某些字段根據(jù)命令的不同有不同的定義。
Dword0 | 根據(jù)命令指定 |
1 | 保留 |
2 | SQID、SQ頭指針 |
3 | 狀態(tài)域、P位、CID |
5.3 Admin 指令
Admin指令與NVM指令根據(jù)放置的的隊(duì)列組(Queue Pair)來(lái)區(qū)分,Admin指令在Admin CQ與SQ里,NVM指令在I/O CQ與SQ里。
通過(guò)Dword0中的8位操作碼定義不同指令,注意并不是絕對(duì)的順序增加(eg,沒(méi)有03h)。每一種指令都對(duì)應(yīng)有其完成命令,通過(guò)SQID(提交隊(duì)列ID)+CID(命令I(lǐng)D)唯一標(biāo)識(shí)完成的命令。
操作碼 | 指令 | 作用 |
00h | 刪除I/O SQ, | 釋放SQ空間 |
01h | 創(chuàng)建 I/O SQ, | 保存host分配給SQ的地址、隊(duì)列優(yōu)先權(quán)、隊(duì)列大小 |
02h | 獲取日志, | 返回所選日志頁(yè)于緩沖區(qū) |
04h | 刪除 I/O CQ, | 釋放CQ空間 |
05h | 創(chuàng)建 I/O CQ, | 保存host分配給CQ的地址、中斷向量、隊(duì)列大小等 |
06h | Identify | 返回關(guān)于controller與namespace能力和狀態(tài)的數(shù)據(jù)結(jié)構(gòu)(2k字節(jié)) |
08h | 撤銷, | 用來(lái)撤銷之前完成的指令,best-effort |
09h | 設(shè)置features | 根據(jù)FID設(shè)置相應(yīng)的features |
0Ah | 獲取 features, | 根據(jù)FID返回隊(duì)列數(shù)量、仲裁信息等 |
0Ch | 異步事件請(qǐng)求, | Controller向host報(bào)告運(yùn)行信息(error or health) |
10h | 固件激活, | 驗(yàn)證下載的鏡像,提交到Firmware Slot(1-7)中 |
11h | 固件鏡像下載, | 下載固件鏡像 |
Note:
Admin隊(duì)列是通過(guò)配置ASQ等寄存器創(chuàng)建的
先創(chuàng)建CQ再創(chuàng)建SQ
5.4 NVM指令
NVMe控制器讀寫的最小單元是LB,層次圖如下:

NVM指令與Admin指令結(jié)構(gòu)完全相同,也是通過(guò)Dword0中的8位操作碼來(lái)定義不同指令。
操作碼 | 指令 | 作用 |
00h | Flush | 將數(shù)據(jù)(和元數(shù)據(jù))提交到NVM中,所有命令都要執(zhí)行 |
01h | Write | 將數(shù)據(jù)(和元數(shù)據(jù))寫入NVM中 |
02h | Read | 讀NVM中的數(shù)據(jù)(和元數(shù)據(jù)) |
04h | Wirte Uncorrectable | 標(biāo)記無(wú)效數(shù)據(jù)塊 |
05h | Compare | 比較從NVM端讀出的數(shù)據(jù)和比較數(shù)據(jù)緩沖區(qū)的數(shù)據(jù) |
09h | Dataset Management | 標(biāo)識(shí)一定范圍數(shù)據(jù)的特點(diǎn),eg,頻繁讀、頻繁寫(提升性能) |
6 控制器結(jié)構(gòu)
控制器從功能上可以分為三類,I/O、Admin和Discovery。

在實(shí)現(xiàn)過(guò)程中,Admin 控制器只有一個(gè),負(fù)責(zé)管理控制器及其他控制功能??刂破髦皇浅橄蟮母拍?,應(yīng)用于具體的實(shí)現(xiàn)中,可能是一個(gè)具體的模塊,也可能多個(gè)模塊。
控制器主要的作用是實(shí)現(xiàn)對(duì)NVMe定義命令的翻譯,從而實(shí)現(xiàn)數(shù)據(jù)傳輸、狀態(tài)控制等功能。
6.1 命令執(zhí)行過(guò)程
1. host將命令(1條或者多條)寫入提前分配好的SQ中;
2. 更新對(duì)應(yīng)SQ的DB寄存器;
3. NVMe控制器取SQ中命令(通過(guò)HDB和TDB可以判斷是否有未完成命令);
4. NVMe控制器執(zhí)行命令;
5. NVMe 控制器在命令完成后,將完成命令(可能執(zhí)行成功,也可能失敗,但都會(huì)返回完成命令)寫入host內(nèi)存SQ對(duì)應(yīng)的CQ中;
6. NVMe 控制器根據(jù)實(shí)現(xiàn)的中斷方式,提醒host命令已完成;
7. host響應(yīng)中斷,處理完成命令;
8. host 更新對(duì)應(yīng)CQ的DB寄存器。

6.2 重啟(Reset)
6.2.1 Controller level
Controller重啟可能發(fā)生在PCIe總線重啟、PCI重啟、控制器CC.EN從1到0重啟。當(dāng)重啟發(fā)生時(shí):
所有的I/O SQ和CQ都被刪除;
所有未完成的指令(Admin和I/O)應(yīng)該執(zhí)行撤銷操作;
Controller處于idele狀態(tài),CSTS.RDY清0;
AQA、ASQ、ACQ不受影響。
重啟后,host操作:
更新寄存器狀態(tài);
將CC.EN置1;
等待CSTS.RDY置1;
使用Admin命令配置Controller;
創(chuàng)建I/O CQ和SQ;
執(zhí)行正常的I/O指令。
6.2.2 Queue level
隊(duì)列水平的重啟,即,刪除該隊(duì)列,再重新創(chuàng)建一個(gè)新隊(duì)列。刪除隊(duì)列的時(shí)候,host應(yīng)該保證隊(duì)列處于idle狀態(tài)(所有命令均已完成——接收到了完成命令),否則的話,可能會(huì)導(dǎo)致CQ接收不到提交命令的完成命令。
6.3 中斷
在Controller完成SQ命令后,根據(jù)執(zhí)行狀態(tài),將結(jié)果組裝成完成命令寫入CQ中,Controller通過(guò)中斷機(jī)制通知Host處理完成命令。
NVMe協(xié)議中支持的中斷方式有4種,pin-based、Single MSI、Multi-message MSI和MSI-X,協(xié)議推薦采用MSI-X中斷方式,能夠支持更多的中斷向量(2K)。
MSI-X允許每一個(gè)CQ發(fā)送自己的中斷信息(相比于發(fā)一條中斷信息提醒全部CQ隊(duì)列有很大的優(yōu)勢(shì))。在產(chǎn)生MSI-X中斷信息前,需要檢查該中斷在相應(yīng)寄存器種不被屏蔽。
6.4 Controller初始化
Controller的初始化過(guò)程:
設(shè)置PCI和PCIe寄存器;
等待CSTS.RDY變?yōu)椋?/span>
配置AQA、ASQ、ACQ寄存器;
配置CC寄存器;
將CC.EN置1;
等待CSTS.RDY置1
Host通過(guò)Identify命令,確定Controller的數(shù)據(jù)結(jié)構(gòu)、確定Namespace的數(shù)據(jù)結(jié)構(gòu);
Host通過(guò)get features(協(xié)議中是set features,待研究)獲取I/O SQ和CQ信息,然后配置中斷機(jī)制;
Host分配適當(dāng)?shù)腎/O CQ、SQ隊(duì)列;
如果Host希望獲取Controller的錯(cuò)誤或健康信息,可以添加異步事件請(qǐng)求命令。
Controller 關(guān)機(jī)
正常關(guān)機(jī):
Host停止提交新的I/O命令,但允許未完成的命令繼續(xù)完成;
Host刪除所有I/O SQ,刪除所有SQ隊(duì)列后,所有未完成的命令將被撤銷;
Host刪除所有I/O CQ;
Host將CC.SHN置01b,表示正常關(guān)機(jī);關(guān)機(jī)程序完成時(shí),將CSTS.SHST置10b。
突然關(guān)機(jī):
Host停止提交新的I/O命令;
Host將CC.SHN置10b,表示突然關(guān)機(jī);關(guān)機(jī)程序完成時(shí),將CSTS.SHST置10b
6.5 host端命令實(shí)例
6.5.1 創(chuàng)建命令

6.5.2 處理完成命令

6.6 NVMe與PCIe交互實(shí)例(分析包結(jié)構(gòu))
以Host發(fā)出read命令為例。
Host準(zhǔn)備了一個(gè)Read命令給SSD:

分析該包,Host需要從起始LBA 0x20E0448(SLBA)上讀取128個(gè)DWORD (512字節(jié))的數(shù)據(jù),讀到哪里去呢?PRP1給出內(nèi)存地址是0x14ACCB000。這個(gè)命令放在編號(hào)為3的SQ里 (SQID = 3),CQ編號(hào)也是3 (CQID = 3)
Host通過(guò)寫SQ的Tail DB,通知Controller來(lái)取命令:

上圖中,上層是NVMe層,下層是PCIe傳輸層的TLP。Host想往SQ Tail DB中寫入的值是5。PCIe是通過(guò)一個(gè)Memory Write TLP來(lái)實(shí)現(xiàn)Host寫CQ的Tail DB的。該Tail DB寄存器映射在Host的內(nèi)存地址為F7C11018,由于NVMe 的寄存器映射到了Host內(nèi)存中,所以可以根據(jù)這個(gè)地址寫入寄存器值。
SSD收到通知,去Host端的SQ中取指。

PCIe是通過(guò)發(fā)一個(gè)Memory Read TLP到Host的SQ中取指的。可以看到,PCIe需要往Host內(nèi)存中讀取16個(gè)DWORD的數(shù)據(jù)(一個(gè)NVMe指令大?。?,
SSD執(zhí)行讀命令,把數(shù)據(jù)從閃存中讀到緩存中,然后把數(shù)據(jù)傳給Host:

SSD是通過(guò)Memory write TLP 把Host命令所需的128個(gè)DWORD數(shù)據(jù)寫入到Host命令所要求的內(nèi)存中去。SSD每次寫入32個(gè)DWORD,一共寫了4次。
SSD往Host的CQ中返回狀態(tài):

SSD是通過(guò)Memory write TLP 把16個(gè)字節(jié)的命令完成狀態(tài)信息寫入到Host的CQ中。
SSD采用中斷的方式告訴Host去處理CQ:

上圖使用的是MSI-X中斷方式。這種方式將中斷信息和正常的數(shù)據(jù)信息一樣,PCIe打包把中斷信息告知Host。SSD還是通過(guò)Memory Write TLP把中斷信息告知Host,這個(gè)中斷信息長(zhǎng)度是1DWORD。
Host處理相應(yīng)的CQ
Host處理完相應(yīng)的CQ后,需要更新SSD端的CQ Head DB告知SSD處理
完成:

Host還是通過(guò)Memory Write TLP更新SSD端的CQ Head DB。
該過(guò)程完整的包流程如下:

7. NVMe features
7.1 固件(Firmware)更新過(guò)程
1. 將固件下載到Controller中(使用 Firmware Image Download命令);
2. Host提交Firmware Activate命令(也可以激活之前版本的Controller鏡像);
3. Controller reset;
4. reset完成后,Host重新初始化Controller,包括Host重新分配I/O隊(duì)列,與reset步驟相同。
7.2 元數(shù)據(jù)(Metadata)傳輸
元數(shù)據(jù)的使用并沒(méi)有強(qiáng)制規(guī)定,最經(jīng)常的使用方法是用做端到端數(shù)據(jù)的保護(hù)信息。有兩種傳輸元數(shù)據(jù)的方式,一種可以作為L(zhǎng)B數(shù)據(jù)塊的一部分,如下圖:

另一種可以單獨(dú)作為一個(gè)邏輯塊傳輸,如下圖:

7.3 端到端的數(shù)據(jù)保護(hù)
端到端,一端指主機(jī)的內(nèi)存空間,一端指閃存空間(NVM)。數(shù)據(jù)傳輸?shù)膬蓚€(gè)環(huán)節(jié)如下圖:

數(shù)據(jù)在PCIe上傳輸?shù)臅r(shí)候,由于信道噪聲的存在(說(shuō)白了就是存在干擾),可能導(dǎo)致數(shù)據(jù)出錯(cuò);另外,Controller閃存之間,數(shù)據(jù)也可能發(fā)生錯(cuò)誤。采用元數(shù)據(jù)進(jìn)行數(shù)據(jù)的保護(hù)是最常用的一種手段。
充當(dāng)保護(hù)數(shù)據(jù)角色的元數(shù)據(jù)結(jié)構(gòu)如下:

其中,Guard為16bit的CRC校驗(yàn)碼,Application Tag與LBAT相關(guān),Reference Tag將用戶數(shù)據(jù)和地址(LBA)相關(guān)聯(lián)。下圖為以512bytes的數(shù)據(jù)塊為例:

那么按照排列組合,共有四種保護(hù)情況(1帶2帶、1不帶2不帶、1帶2不帶、1不帶2帶)。但由于協(xié)議中控制保護(hù)信息的只有兩個(gè)字段(1. 是否采用保護(hù) 2. PRACT位),只有三種情況,如下圖(是以寫命令為例,讀命令相同):

原文鏈接:
https://zhuanlan.zhihu.com/p/347599423
作者:Fappy
10T 技術(shù)資源大放送!包括但不限于:Linux、虛擬化、容器、云計(jì)算、網(wǎng)絡(luò)、Python、Go 等。在 開(kāi)源Linux 公眾號(hào)內(nèi)回復(fù) 10T,即可免費(fèi)獲取!
有收獲,點(diǎn)個(gè)在看


