蛋蛋讀NVMe之三

原創內容,轉載請注明:  [http://www.od-music.com]  謝謝!

有個人一直在思考三個問題:我是誰?我從哪里來?我要去哪里?

你猜這個人最后怎么著?

成了哲學家?

瘋了?

瘋了的哲學家?

我覺得無外乎這三種結果了。

相比人的世界,這三個問題在NVMe的世界就很容易得到答案了,至少不會把人逼瘋。

我是數據,我從Host來,要到SSD去,或者,我從SSD來,要去到Host。

Host如果想往SSD上寫入用戶數據,需要告訴SSD寫入什么數據,寫入多少數據,以及數據源在內存中的什么位置,這些信息包含在Host向SSD發送的Write命令中。每筆用戶數據對應著一個叫做LBA(Logical Block Address)的東西,Write命令通過指定LBA來告訴SSD寫入的是什么數據。對NVMe/PCIe來說,SSD收到Write命令后,通過PCIe去Host的內存數據所在位置讀取數據,然后把這些數據寫入到閃存中,同時得到LBA與閃存位置的映射關系。

Host如果想讀取SSD上的用戶數據,同樣需要告訴SSD需要什么數據,需要多少數據,以及數據最后需要放到Host內存的哪個位置上去,這些信息包含在Host向SSD發送的Read命令中。SSD根據LBA,查找映射表,找到對應閃存物理位置,然后讀取閃存獲得數據。數據從閃存讀上來以后,對NVMe/PCIe來說,SSD會通過PCIe把數據寫入到Host指定的內存中。這樣就完成了Host對SSD的讀訪問。

在上面的描述中,大家有沒有注意到一個問題,那就是Host在與SSD的數據傳輸過程中,Host是被動的一方,SSD是主動的一方。你Host需要數據,是我SSD主動把數據寫入到你的內存中;你Host寫數據,同樣是我SSD主動去你Host的內存中取數據,然后寫入到閃存。SSD跟快遞小哥一樣辛勞,不僅送貨上門,還上門取件。之前蛋蛋還為Host不能讀取DB打抱不平,現在看來,Host不值得同情,太懶了。

無論送貨上門,還是上門取件,你都需要告訴快遞小哥你的地址,不然茫茫人海,快遞小哥怎么就能找到你呢?同樣的,Host你不親自傳輸數據,那總該告訴我SSD去你內存中什么地方取用戶數據,或者要把數據寫入到你內存中的什么位置。你在告訴快遞小哥送貨地址或者取件地址時,會說XX路XX號XX弄XX樓XX室,也可能會說XX小區XX樓XX室,anyway,快遞小哥能找到就行。Host也有兩種方式來告訴SSD數據所在內存位置,一是PRP (Physical Region Page, 不是P2P!),二是SGL (Scatter/Gather List)。不過,后者感覺不怎么友善,因為怎么聽起來都像”死過來”(SGL)。當然了,也可能是我誤會了,人家只是在說”送過來”。

先說PRP。

NVMe把Host的內存劃分為一個一個頁(Page),頁的大小可以是4KB,8KB,16KB… 128MB。

PRP是什么,長什么樣呢?

PRP Entry本質就是一個64位內存物理地址,只不過把這個物理地址分成兩部分:頁起始地址和頁內偏移。最后兩bit是0,說明PRP表示的物理地址只能四字節對齊訪問。頁內偏移可以是0,也可以是個非零的值。

PRP Entry描述的是一段連續的物理內存的起始地址。如果需要描述若干個不連續的物理內存呢?那就需要若干個PRP Entry。把若干個PRP Entry鏈接起來,就成了PRP List。

是的,正如你所見,PRP List中的每個PRP Entry的偏移量都必須是0,PRP List中的每個PRP Entry都是描述一個物理頁。它們不允許有相同的物理頁,不然SSD往同一個物理頁寫入幾次的數據,導致先寫入的數據被覆蓋。

每個NVMe命令中有兩個域:PRP1和PRP2,Host就是通過這兩個域告訴SSD數據在內存中的位置或者數據需要寫入的地址。

PRP1和PRP2有可能指向數據所在位置,也可能指向PRP List。類似C語言中的指針概念,PRP1和PRP2可能是指針,也可能是指針的指針,還有可能是指針的指針的指針。別管你包的有多嚴實,根據不同的命令,SSD總能一層一層的剝下包裝,找到數據在內存的真正物理地址。SSD善解人衣。

下面是一個PRP1指向PRP List的示例:

PRP1指向一個PRP List,PRP List位于Page 200,頁內偏移50的位置。SSD確定PRP1是個指向PRP List的指針后,就會去Host內存中(Page 200,Offset 50)把PRP List取過來。獲得PRP List后,就獲得數據的真正物理地址,SSD然后就會往這些物理地址讀入或者寫入數據。

對Admin命令來說,它只用PRP告訴SSD內存物理地址;對I/O 命令來說,除了用PRP,Host還可以用SGL的方式來告訴SSD數據在內存中寫入或者讀取的物理地址。

Host在命令中會告訴SSD采用何種方式。具體來說,如果命令當中DW0[15:14]是0,就是PRP的方式,否則就是SGL的方式。

SGL是什么?SGL是一個數據結構,用以描述一段數據空間,這個空間可以是數據源所在的空間,也可以是數據目標空間。SGL(Scatter Gather List)首先是個List,是個鏈表,由一個或者多個SGL Segment組成,而每個SGL Segment又由一個或者多個SGL Descriptor組成。SGL Descriptor是SGL最基本的單元,它描述了一段連續的物理內存空間:起始地址+空間大小。

每個SGL Descriptor大小是16字節。一塊內存空間,可以用來放用戶數據,也可以用來放SGL Segment,根據這段空間的不同用途,SGL Descriptor也分幾種類型。

有4種SGL Descriptor,一種是Data Block,這個好理解,就是描述的這段空間是用戶數據空間;一種是Segment描述符。SGL不是由SGL Segment組成的鏈表嗎?既然是鏈表,前面一個Segment就需要有個指針指向下一個Segment,這個指針就是SGL Segment描述符,它描述的是它下個Segment所在的空間。特別地,對鏈表當中倒數第二個Segment,它的SGL Segment描述符我們把它叫做SGL Last Segment描述符。它本質還是SGL Segment描述符,描述的還是SGL Segment所在的空間。為什么需要把倒數第二個SGL Segment描述符單獨的定義成一種類型呢?我認為是讓SSD在解析SGL的時候,碰到SGL Last Segment描述符,就知道鏈表快到頭了,后面只有一個Segement了。那么,SGL Bit Bucket是什么鬼?它只對Host讀有用,用以告訴SSD,你往這個內存寫入的東西我是不要的。好吧,你既然不要,我也就不傳了。

說了這么多,可能有點暈,結合下張圖,可能會更明白點。

如果還是暈,看個例子吧。

這個例子中,假設Host需要往SSD中讀取13KB的數據,其中真正只需要11KB數據,這11KB的數據需要放到3個大小不同的內存中,分別是:3KB,4KB和4KB。

無論是PRP還是SGL,本質都是描述內存中的一段數據空間,這段數據空間在物理上可能連續的,也可能是不連續的。Host在命令中設置好PRP或者SGL,告訴SSD數據源在內存的什么位置,或者從閃存上讀取的數據應該放到內存的什么位置。

大家也許跟我有個同樣的疑問(自作多情?),那就是,既然有PRP,為什么還需要SGL?事實上,NVMe1.0的時候的確只有PRP,SGL是NVMe1.1之后引入的。SGL和PRP本質的區別在哪?下圖道出了真相:一段數據空間,對PRP來說,它只能映射到一個個物理頁,而對SGL來說,它可以映射到任意大小的連續物理空間。

啊

這章就到這吧。下面《蛋蛋讀NVMe之四》,蛋蛋會帶大家走基層,看看一個NVMe讀寫命令在PCIe層是怎樣實現的。精彩繼續,不要錯過。

分類目錄 SSD, 技術文章.
掃一掃二維碼或者微信搜索公眾號ssdfans關注(添加朋友->點最下面的公眾號->搜索ssdfans),可以經??吹絊SD技術和產業的文章(SSD Fans只推送干貨)。
ssdfans微信群介紹
技術討論群 覆蓋2000多位中國和世界華人圈SSD以及存儲技術精英
固件、軟件、測試群 固件、軟件和測試技術討論
異構計算群 討論人工智能和GPU、FPGA、CPU異構計算
ASIC-FPGA群 芯片和FPGA硬件技術討論群
閃存器件群 NAND、3D XPoint等固態存儲介質技術討論
企業級 企業級SSD、企業級存儲
銷售群 全國SSD供應商都在這里,砍砍價,會比某東便宜20%
工作求職群 存儲行業換工作,發招聘,要關注各大公司招聘信息,趕快來
高管群 各大SSD相關存儲公司高管和創始人、投資人

想加入這些群,請微信掃描下面二維碼,或搜索nanoarchplus,加阿呆為微信好友,介紹你的昵稱-單位-職務,注明群名,拉你進群。SSD業界需要什么幫助,也可以找阿呆聊。