NVMe Base 2.4 第 4 章:SQE、CQE、Status、PRP 與 SGL
00.01.一筆 NVMe 命令必須告訴控制器要做什麼、對哪個 namespace 操作,以及資料放在哪裡;完成結果則必須讓主機認出是哪筆命令、結果如何。本篇從這兩個方向拆解 SQE、CQE 與 PRP/SGL。
- namespace
- namespace,主機透過 controller 存取的一份已格式化非揮發性容量。
- NVMe
- Non-Volatile Memory Express,主機與非揮發性記憶體子系統之間的介面規範家族。
- CQE
- Completion Queue Entry,CQ 中的一筆完成結果資料結構。
- PRP
- Physical Region Page,以 memory page 為單位描述 host-addressable data buffer 的 pointer 格式。
- SGL
- Scatter Gather List,以 descriptor 與 segment 描述一段或多段 data buffer 的格式。
- SQE
- Submission Queue Entry,SQ 中的一筆命令資料結構。
這篇的主軸
命令內容 SQE
01-01理解命令識別、操作碼與資料指標的分工。
完成結果 CQE
02-01分開理解新完成項目、命令身分與狀態碼。
資料位址 PRP/SGL
03-01把作業系統的記憶體頁面概念接到 NVMe 資料傳輸。
其他共用資料結構
04-01理解功能值、識別碼、清單與文字的表示方式。
00.02.命令與完成項目是佇列中的記錄,讀寫的資料通常由資料指標指定。先分清楚「命令記錄」與「命令要搬移的資料」,就能理解後面的欄位配置。
把主軸連起來
00.03.把一次操作拆成三份資訊:SQE 說明主機要做什麼,PRP/SGL 描述資料在哪裡,CQE 回報是哪筆命令完成及其結果。識別碼與清單則協助主機選擇正確對象。
00.04.本篇由共同布局逐步深入位元、長度與指標。讀完應能從一個命令範圍算出資料量,選擇正確的指標解讀方式,再利用完成項目找回原命令。每次計算都要先確認單位,而不是只憑欄位名稱推測。
01 SQE 的共用格式與命令欄位
01.01.Common SQE 先固定 CDW0、NSID、metadata/data pointer 與 CDW10-15 的位置。OPC 選 command,CID 建立完成關聯,PSDT 決定 DPTR 解讀方式;只有完成這些 common 欄位後,才應進入個別 command 的 CDW10-15 定義。Figures 92-94 是後續所有 command construction 的座標系。
- metadata
- 隨 logical block 儲存的附加資料,可包含資料保護資訊,也可有其他用途。
- DPTR
- Data Pointer,SQE 中指出 command data buffer 的欄位。
- NSID
- Namespace Identifier,controller 用來指向 namespace 的數值 handle;identifier 不等於 namespace 物件本身。
- PSDT
- PRP or SGL for Data Transfer,CDW0 中決定 DPTR 應按 PRP 或 SGL 解讀的欄位。
- CDW
- CDW(Command Dword);命令中的 32-bit 欄位單位,例如 CDW10 的 10 是欄位 index,不是 byte offset。
- CID
- Command Identifier,與 SQ identifier 合用以辨識 outstanding command。
- Dword
- Dword(Double word);32 bits,也就是 4 bytes。對比 word=16 bits;例如 zero-based dword count=3 代表 4 個 Dwords,也就是 16 bytes。
01.02.Admin 與 I/O common SQE 固定為 64 bytes。CDW0、NSID、data pointer 與 CDW10-15 的通用位置先固定,再由各 command 定義命令專屬內容。
- Admin
- Administrative,建立、設定、查詢或管理 controller 與 queue 的控制路徑。
- I/O
- Input/Output,對 namespace 執行資料輸入與輸出的操作類別。
來源:Base 2.4 §4.1.1
來源:NVME-BASE-2.4, Rev. 2.4, §4.1.1, 文件頁 139-143, PDF 頁 165-169
| SQE 區域 | 主機在這裡描述什麼 | 如何選擇正確的欄位定義 |
|---|---|---|
| CDW0 | 命令身分 與 資料指標選擇欄位 | 所有 commands 共用 |
| NSID | 指定的 namespace 範圍 | 不用時必須依 command 定義清零或使用特殊值 |
| MPTR/DPTR | metadata 與 data buffer | 由 PSDT 與 command 規則決定 |
| CDW10-15 | 命令專用參數 | 不能跨 command 借用語意 |
- MPTR
- Metadata Pointer,SQE 中指出獨立 metadata buffer 的欄位。
02 CQE:新完成項目、命令識別與結果
02.01.host 先用 Phase Tag 判斷 CQ slot 是否是新 completion;確定 ownership 後再用 SQID/CID 找回 command,最後以 SCT 選 status 類別並解 SC、DNR、CRD。Figures 97-109 必須按這個順序讀,否則 stale CQE 或錯誤類別會被當成真實 command failure。
- Host
- 主機;執行作業系統並送出 NVMe 命令的一端。
- CRD
- Command Retry Delay,status 中選擇 controller 建議重試延遲值的欄位。
- DNR
- Do Not Retry,CQE status 中提示以相同 command 重試預期不會成功的 bit。
- SCT
- Status Code Type;指定完成狀態碼所屬類別,需與 SC 一起解讀。
- CQ
- Completion Queue,controller 放入完成結果的完成佇列。
- SC
- Status Code;指定所選 SCT 類別中的完成結果。
02.02.common CQE 至少 16 bytes;若以多次寫入建立 CQE,Phase Tag 必須(shall)在最後一次寫入更新,避免 host 看到半成品。
來源:Base 2.4 §4.2.1
來源:NVME-BASE-2.4, Rev. 2.4, §4.2.1, 文件頁 144-145, PDF 頁 170-171
| 完成狀態欄位 | 回答哪個問題 | 解讀時還需哪些資訊 |
|---|---|---|
| SCT | status 大類 | 一定先解 |
| SC | 類別內具體結果 | 不能脫離 SCT |
| DNR | 同 command 重試預期 | 不是永久硬體故障的同義詞 |
| CRD | 建議 retry delay selector | 只有適用 status 才使用 |
03 PRP 如何描述跨頁資料
03.01.PRP1 可以指向第一個 memory page 內任意 byte,能承載的第一段長度是 page_size - offset。若資料跨過第一頁,PRP2 依剩餘長度代表第二頁或 PRP List;後續 page address 必須符合 page alignment。Figures 110-113 是 address calculation,不只是 pointer 名稱表。
- offset
- offset;從指定起點算出的位移。它回答「離起點多遠」,不等於 index。
03.02.PRP 以固定大小 entry 指向 physical memory page。第一個 entry 可含 page offset;後續 PRP 必須(shall)符合 page alignment,資料長度決定需要幾個 entry。
- page offset
- page offset;資料在第一個記憶體 page 內的起始位移;跨過 page boundary 後,位置由下一個 page pointer 決定。
來源:Base 2.4 §4.3.1
來源:NVME-BASE-2.4, Rev. 2.4, §4.3.1, 文件頁 158-159, PDF 頁 184-185
| 資料跨頁情況 | PRP2 的解讀方式 | 指標與對齊要求 |
|---|---|---|
| 資料不跨第一頁 | 只需 PRP1 | PRP2 不承載下一段 |
| 剩餘資料只需一頁 | PRP2 指第二個 data page | address page-aligned |
| 剩餘資料超過一頁 | PRP2 指 PRP List | list entries 再指 data pages |
04 SGL 的資料與串接描述子
04.01.SGL descriptor 同時包含 type/subtype、address 與 length;Data Block 指向資料,Segment/Last Segment 指向更多 descriptors,Bit Bucket 表示資料不需實際放入 memory。Figures 114-125 應先讀 type,再讀該 type 對 address/length 的語意,不能只沿 address 盲走。
04.02.SGL 由一個以上 descriptor/segment 描述資料 buffer。SGL length 必須(shall)大於等於 requested transfer length;本報告只介紹 PCIe 可用的通用 descriptor。
- PCIe
- PCI Express,NVMe memory-based controller 使用的 transport 與裝置互連。
來源:Base 2.4 §4.3.2
來源:NVME-BASE-2.4, Rev. 2.4, §4.3.2, 文件頁 159-166, PDF 頁 185-192
| 指標或描述子種類 | 位址與長度描述什麼 | 沿指標會找到什麼 |
|---|---|---|
| PRP | 以記憶體頁描述位址 | 第一頁 offset + 後續 page alignment |
| SGL Data Block | 起始位址與資料長度(bytes) | 資料區段可用 descriptor 表示 |
| SGL Segment | 清單位址與清單長度(bytes) | 指向下一層 descriptors,不是 data |
| Bit Bucket | 只消耗 transfer length | 不代表可讀寫的 memory buffer |
05 Feature 值、識別碼、清單與字串
05.01.解讀數值前要先確定它代表什麼:Feature 值具有目前與保存狀態的差別;identifier 具有識別範圍;清單與字串則各有排列及長度規則。
05.02.Feature 可能具有 default、saved、目前值;保存值 支援與跨 reset/power cycle 的 persistence 由 SSFS 與各 Feature capability 判定。
來源:Base 2.4 §4.4
來源:NVME-BASE-2.4, Rev. 2.4, §4.4, 文件頁 166-169, PDF 頁 192-195
| 識別欄位或清單 | 辨認的對象與格式 | 長度及數量如何解讀 |
|---|---|---|
| VID/SSVID | 廠商與 subsystem 廠商識別值 | 按各自欄位辨認對象 |
| SN/MN | 產品序號與型號字串 | 依固定欄位長度與填補規則閱讀 |
| EUI64/NGUID/UUID | 不同格式的物件識別值 | 長度及身分範圍不能互換 |
| Controller List | NUMCIDS 加上 16-bit IDs | 有明確數量欄位 |
| Namespace List | 直接排列 32-bit NSIDs | 沒有 Controller List 的數量標頭 |
- NUMCIDS
- Number of Controller Identifiers;Controller List 中有效 controller IDs 的數量。
- EUI64
- 64-bit Extended Unique Identifier,使用 IEEE 配置空間建立的 64-bit identifier。
- NGUID
- Namespace Globally Unique Identifier,namespace 的 128-bit 全域識別值。
- SSVID
- Subsystem Vendor ID,辨識 subsystem vendor 的 PCI identifier。
- UUID
- Universally Unique Identifier,128-bit identifier;其實際關聯範圍仍由使用它的資料結構決定。
- VID
- Vendor ID,由 PCI-SIG 配置、辨識 vendor 的 identifier。
- MN
- Model Number,辨識產品型號的字串。
- SN
- Serial Number,辨識一個產品實例的序號字串。
接著打開 Spec 看什麼
06.01.以下按概念列出閱讀位置。報告時先用上面的流程說明問題,再打開對應章節看欄位與完整條件。中文教學 HTML 另有本篇全部圖表的逐圖重點、案例與細節。
| 要說明的觀念 | Spec 閱讀位置 |
|---|---|
| SQE 的共用格式與命令欄位 | Base 2.4 §4.1.1 |
| CQE:新完成項目、命令識別與結果 | Base 2.4 §4.2.1 · Base 2.4 §4.2.3 · Base 2.4 §4.2.4 |
| PRP 如何描述跨頁資料 | Base 2.4 §4.3.1 · Base 2.4 §4.1.1 |
| SGL 的資料與串接描述子 | Base 2.4 §4.3.2 · Base 2.4 §4.1.1 |
| Feature 值、識別碼、清單與字串 | Base 2.4 §4.4 · Base 2.4 §4.5 · Base 2.4 §4.6 · Base 2.4 §4.8 |
學完後想一想
1. 2 個 SQ 都使用 CID=5,收到 completion 時該如何分辨命令?
07.01.CID 的唯一性範圍是同一 SQ 的 outstanding commands。完成資訊需要連同 SQ identifier 解讀,才能找到正確 SQ 中的那筆命令。
來源
來源:NVME-BASE-2.4, Rev. 2.4, §4.1.1, 文件頁 140, PDF 頁 166
來源:NVME-BASE-2.4, Rev. 2.4, §4.2.1, 文件頁 144-145, PDF 頁 170-171
2. CQE 的 Phase Tag 符合 host 期待值,是否表示命令成功?
07.02.Phase Tag 讓 host 辨認這個位置的新 completion;是否成功則由 Status Code Type、Status Code 等狀態資訊決定。新資料與成功結果是兩個判斷。
來源
來源:NVME-BASE-2.4, Rev. 2.4, §4.2.4, 文件頁 155-158, PDF 頁 181-184
來源:NVME-BASE-2.4, Rev. 2.4, §4.2.3, 文件頁 145-155, PDF 頁 171-181
3. PRP1 位於 page 中間時,為何跨頁後不能直接延續同一段實體地址?
07.03.PRP1 提供第一段的 page offset;跨頁後由後續 PRP page address 或 PRP List 指定資料位置。Host 的邏輯連續 buffer 不必對應連續的實體 pages。
來源
來源:NVME-BASE-2.4, Rev. 2.4, §4.3.1, 文件頁 158-159, PDF 頁 184-185
4. 為何解讀 DPTR 前要先看 PSDT?
07.04.DPTR 的同一組 bits 可依選定格式表達 PRP 或 SGL。先確認 PSDT 與命令支援條件,才知道應把後續資料當 page pointers 或 segment descriptors。
來源
來源:NVME-BASE-2.4, Rev. 2.4, §4.1.1, 文件頁 140-142, PDF 頁 166-168
來源:NVME-BASE-2.4, Rev. 2.4, §4.3.2, 文件頁 159-166, PDF 頁 185-192


Comments