NVMe概述
NVMe是一個針對基於PCIe的固態硬盤的高性能的、可擴展的主機控制器接口。
NVMe的顯著特征是提供多個隊列來處理I/O命令。單個NVMe設備支持多達64K個I/O 隊列,每個I/O隊列可以管理多達64K個命令。
當主機發出一個I/O命令的時候,主機系統將命令放置到提交隊列(SQ),然后使用門鈴寄存器(DB)通知NVMe設備。
當NVMe設備處理完I/O命令之后,設備將處理結果寫入到完成隊列(CQ),並引發一個中斷通知主機系統。
NVMe使用MSI/MSI-X和中斷聚合來提高中斷處理的性能。
NVMe驅動概述
NVMe驅動是一個C函數庫,可直接鏈接到應用程序從而在應用與NVMe固態硬盤之間提供直接的、零拷貝的數據傳輸。這是完全被動的,意味着不會開啟線程,只是執行來自應用程序本身的函數調用。這套庫函數直接控制NVMe設備,通過將PCI BAR寄存器直接映射到本地進程中然后執行基於內存映射的I/O(MMIO)。I/O是通過隊列對(QP)進行異步提交,其一般的執行流程跟Linux的libaio相比起來,並非完全不同。
NVM Express(NVMe)是一個寄存器級接口,允許帶內主機軟件與NVM子系統通信。NVMe管理界面(NVMe-MI)允許管理控制器通過一個或多個外部接口與NVMe NVM子系統進行帶外通信。
NVMe是一種Host與SSD之間通訊的協議
圖1:NVMe管理接口協議分層
NVMe-MI利用管理組件傳輸協議(MCTP)作為命令傳輸和利用現有的MCTP SMBus / I2C和PCIe綁定物理層。
NVMe是為SSD所生的。NVMe出現之前,SSD絕大多數走的是AHCI和SATA的協議,后者其實是為傳統HDD服務的。與HDD相比,SSD具有更低的延時和更高的性能,AHCI已經不能跟上SSD性能發展的步伐了,已經成為制約SSD性能的瓶頸。
跟ATA spec中定義的命令相比,NVMe的命令個數少了很多,完全是為SSD量身定制的。
NVMe有三寶:Submission Queue (SQ),Completion Queue(CQ)和Doorbell Register (DB)。 SQ和CQ位於Host的內存中,DB則位於SSD的控制器內部。上圖:
SQ和CQ在Host的memory中以及DB在SSD端,上圖中的NVMe Subsystem一般就是SSD。
SQ位於Host內存中,Host要發送命令時,先把准備好的命令放在SQ中,然后通知SSD來取;CQ也是位於Host內存中,一個命令執行完成,成功或失敗,SSD總會往CQ中寫入命令完成狀態。
DB又是干什么用的呢?Host發送命令時,不是直接往SSD中發送命令的,而是把命令准備好放在自己的內存中,那怎么通知SSD來獲取命令執行呢?Host就是通過寫SSD端的DB寄存器來告知SSD的。
1.4架構模型
圖2:單端口PCIe SSD
圖3:帶SMBus / I2C的雙端口PCIe SSD
NVMe管理界面用於發送命令消息,該命令消息由以NVM子系統內的控制器為目標的標准NVMe管理命令組成; 用於訪問NVM子系統中控制器的PCI Express配置,I / O和存儲空間的命令; 和管理接口特定命令,用於清點,配置和監視NVM子系統。
圖4:與單端口PCIe SSD相關的NVM子系統
圖5示出了與圖3中所示的PCIe SSD相對應的示例NVM子系統。NVM子系統,包含一個與PCIe端口0相關聯的控制器和兩個與PCIe端口1相關聯的控制器。存在與每個PCIe端口相關聯的管理端點和SMBus / I2C端口。由於NVM子系統包含管理端點,因此所有控制器都具有關聯的控制器管理接口。
圖5:與帶有SMBus / I2C的雙端口PCIe SSD相關的NVM子系統
管理接口請求消息和響應消息作為MCTP消息傳輸,消息類型通過MCTP設置為NVM Express管理消息(請參閱MCTP ID和代碼規范)。 所有命令消息都源自管理控制器,並從管理端點生成響應消息。
4消息處理模型
NVMe-MI使用請求和響應處理模型。
圖14:NVMe-MI MCTP消息分類
4.1 request消息
request消息是由管理控制器生成的NVMe-MI消息,用於發送給管理端點。
request消息指定管理端點要執行的操作。
4.2 reponse消息
reponse消息是管理端點完成時生成的NVMe-MI消息處理先前發出的request消息。
NVM Express基於配對的提交和完成隊列機制
命令由主機軟件放入提交隊列。完成被放入控制器關聯的完成隊列。多個提交隊列可以使用相同的完成隊列。提交和完成隊列在內存中分配。
存在管理員提交和關聯的完成隊列以用於控制器管理和控制(例如,創建和刪除I / O提交和完成隊列,中止命令,等等)。只有屬於管理員命令集的命令才可以提交給管理員提交隊列。
I / O命令集與I / O隊列對一起使用。該規范定義了一個I / O命令集,命名為NVM命令集。主機選擇一個用於所有I / O隊列的I / O命令集對。
主機軟件創建隊列,最高可達控制器支持的最大值。通常的數量創建的命令隊列基於系統配置和預期的工作負載。例如, 在基於四核處理器的系統上,每個核心可能有一個隊列對,以避免鎖定和確保數據結構在適當的處理器核心緩存中創建。圖1提供了圖形隊列對機制的表示,顯示提交隊列和。之間的1:1映射完成隊列。圖2顯示了多個I / O提交隊列使用相同的示例核心B上的I / O完成隊列。圖1和圖2顯示了之間始終存在1:1管理員提交隊列和管理員完成隊列。
提交隊列(SQ)是一個循環緩沖區,具有主機軟件用於提交的固定插槽大小控制器執行的命令。主機軟件更新相應的SQ Tail門鈴當有一到n個新命令要執行時注冊。之前的SQ Tail值被覆蓋當有新的門鈴寄存器寫入時控制器。控制器按順序提取SQ條目但是,提交隊列可以按任何順序執行這些命令。
4.1.1空隊列
當Head入口指針等於Tail入口指針時,隊列為Empty。圖8定義了Empty隊列條件。
圖8:空隊列定義
4.1.2滿隊列
當Head等於尾部時,隊列為Full。隊列中的條目數full比隊列大小少一個。
圖9定義了完整隊列條件。注意:在確定隊列是否為Full時,應考慮隊列包裝條件。
圖9:完整隊列定義
7控制器架構
主機軟件(Host)通過預先分配的提交隊列向控制器(Controller)提交命令。通過SQ Tail Doorbell寄存器寫入警告控制器新提交的命令。前一個門鈴寄存器值和當前寄存器寫入之間的差異表示已提交的命令數。
控制器從提交隊列中提取命令並將它們發送到NVM子系統進行處理。
命令處理
1.主機將一個或多個命令放置在位於內存中的提交隊列(SQ)的下一個可用的槽位中執行。
2. Host用SQ尾部指針的新值去更新SQ的TailDB寄存器。這告訴了SSD控制器有一個新的命令被提交需要被處理。
3. SSD控制器將命令從SQ中轉移到控制器中以供下一步執行。(從哪一個SQ中取出下一條候選命令去執行的仲裁方法,請參見4.11一節。)
4.控制器接下來執行下一條命令。命令的執行完成可能是亂序的(與提交或開始執行的時間點無關)。
5.在命令完成執行之后,SSD控制器將一個完成隊列條目(CQE)放在相關的完成隊列(CQ)的下一個空閑槽位中。作為CQE的一部分,SSD控制器通過修改完成條目的SQ頭指針指示最新的SQE已經被消費了。每一個新的CQE都有一個從前一個條目中反轉的相位標記(Phase Tag), 以向Host表明這個CQE是一個新條目。
6. SSD控制器給Host產生一個中斷,以表明有一個新的CQE已經產生,可以被消費和處理了。在圖中演示的是MSI-X中斷,然而,中斷也可以是基於PIN或者MSI的中斷。注意:基於中斷聯合設置,可能或不能為每一個新的CQE產生一個中斷。
7. Host消費和處理在CQ中放置的新的CQE。包括基於錯誤情況采取的任何操作。Host繼續消耗和處理CQE,直到它遇到以前消費的一個條目的相位標簽(Phase Tag)從當前完成隊列條目(CQEs)的值中反轉。
8. Host更新CQ的HeadDB寄存器,表明CQE已經被消費了。在更新相關聯的CQ的HeadDB寄存器之前,Host可能消費了多個CQE。
通俗易懂的話總結一下就是:
1. Host寫命令到SQ
2. Host更新SQ的TailDB, 通知SSD取命令
3. SSD收到命令,於是從SQ中取出命令
4. SSD執行命令
5. 命令執行完成后,SSD往CQ中寫入命令執行結果,同時修改CQ的TailDB
6. SSD發短信通知Host命令已經執行完成
7. Host收到命令后,到CQ中查看命令完成狀態
8. Host處理完CQ中的命令執行結果,更新CQ中的HeadDB, 回復SSD, "命令執行結果已經處理完畢,辛苦啦"
NVMe over PCIe和RDMA本質上都是“玩隊列”。 NVMe over PCIe有兩條隊列,一條提交隊列(SQ)和一條完成隊列(CQ);而RDMA有三條隊列,一條發送隊列(SQ),一條接收隊列(RQ)和一條完成隊列(CQ),而一個SQ和一個RQ被稱之為一個QP(隊列對)。
對應nvme驅動代碼位置:
nvme_pcie.c
1.Int nvme_pcie_qpair_submit_request()
TAILQ_INSERT_TAIL(&pqpair->outstanding_tr, tr, tq_list);
(對應app代碼位置:bdev_nvme_submit_request( ) )??是嗎,只是名稱相近?
2. static void nvme_pcie_qpair_complete_tracker()
TAILQ_INSERT_HEAD(&pqpair->free_tr, tr, tq_list);
bdev_nvme.c
static const struct spdk_bdev_fn_table nvmelib_fn_table = { (device function table)
.destruct = bdev_nvme_destruct,
.submit_request = bdev_nvme_submit_request,
.io_type_supported = bdev_nvme_io_type_supported,
.get_io_channel = bdev_nvme_get_io_channel,
.dump_info_json = bdev_nvme_dump_info_json,
.write_config_json = bdev_nvme_write_config_json,
.get_spin_time = bdev_nvme_get_spin_time,
};
static struct spdk_bdev_module nvme_if = {
.name = "nvme",
.module_init = bdev_nvme_library_init,
.module_fini = bdev_nvme_library_fini,
.config_text = bdev_nvme_get_spdk_running_config,
.config_json = bdev_nvme_config_json,
.get_ctx_size = bdev_nvme_get_ctx_size,
};
關於MSI-X,在igb_uio.c里igbuio_msix_mask_irq( )
淺談NVMe與MSI-X
https://blog.csdn.net/wangpeng22/article/details/78390694?locationNum=2&fps=1
https://blog.csdn.net/weijitao/article/details/46566789
http://blog.sina.com.cn/s/blog_6472c4cc0102dskj.html
NVMe制定了Host與SSD之間通訊的命令,以及命令如何執行的。
NVMe有兩種命令,
一種叫Admin Command,用以Host管理和控制SSD;
另外一種就是I/O Command,用以Host和SSD之間數據的傳輸。下面是NVMe1.2支持的命令列表:
NVMe支持的Admin Command:
NVMe支持的I/O Command:
lib/bdev/nvme/bdev_nvme.c
_bdev_nvme_submit_request( )有IO操作的處理,
nvme_ctrlr_ut.c
test_nvme_ctrlr_init_en_1_rdy_0
test_nvme_ctrlr_init_en_1_rdy_1
test_nvme_ctrlr_init_en_0_rdy_0
test_nvme_ctrlr_init_en_0_rdy_1
test_nvme_ctrlr_init_en_0_rdy_0_ams_rr
test_nvme_ctrlr_init_en_0_rdy_0_ams_wrr
test_nvme_ctrlr_init_en_0_rdy_0_ams_vs
test_alloc_io_qpair_rr_1
test_ctrlr_get_default_ctrlr_opts
test_ctrlr_get_default_io_qpair_opts
test_alloc_io_qpair_wrr_1
test_alloc_io_qpair_wrr_2
test_spdk_nvme_ctrlr_update_firmware
test_nvme_ctrlr_fail
test_nvme_ctrlr_construct_intel_support_log_page_list
test_nvme_ctrlr_set_supported_features
test_spdk_nvme_ctrlr_doorbell_buffer_config----5 Admin Command Set
test_nvme_ctrlr_test_active_ns
nvme_ctrlr_cmd_ut.c ----- AdminCommand的功能測試集
test_get_log_pages----5 Admin Command Set
test_set_feature_cmd----5 Admin Command Set
test_set_feature_ns_cmd----5 Admin Command Set
test_get_feature_cmd----5 Admin Command Set
test_get_feature_ns_cmd----5 Admin Command Set
test_abort_cmd----5 Admin Command Set
test_io_raw_cmd
test_io_raw_cmd_with_md
test_namespace_attach----5 Admin Command Set
test_namespace_detach----5 Admin Command Set
test_namespace_create----5 Admin Command Set
test_namespace_delete----5 Admin Command Set
test_format_nvme
test_fw_commit----5 Admin Command Set
test_fw_image_download----5 Admin Command Set