目录
Data SGL Length Invalid & Metadata SGL Length Invalid
SGL Last Segment descriptor(3h)
Keyed SGL Data Block descriptor(4h)
Transport SGL Data Block descriptor(5h)
MSDBD(Maximum SGL Data Block Descriptors)
简介
SGL,Scatter Gather List,分散聚集列表,一种 NVMe 规定的数据结构,用于描述数据缓冲区,在数据传输过程中起着关键作用。
消费级 SSD 一般都不支持,企业级 SSD 一般都会支持。
NVMe over Fabrics中,要求所有 commands(Fabrics,Admin,I/O)都用 SGL。
NVMe over PCIe中,则 I/O cmd 支持 SGL 和 PRP,Admin cmd 只支持 PRP。
详细描述
基本结构
SGL:由一个或多个 SGL Segment 组成。
SGL Segment:每个 SGL Segment是一个 64 位对齐的数据结构,包含一个或多个 SGL Descriptor,用于描述数据缓冲区的全部、部分或无数据,以及下一个 SGL Segment(如果有)。
SGL Descriptor:是 SGL 最基本的单元。每个大小为 16 bytes。
示例
下图为 NVMe spec 中给出的一个 SGL 读示例。先来看个示例,然后再去逐个搞懂。
逻辑块大小为 512B,总访问长度为 13 KiB(从 LBA x+26 可以看出数据传输长度为 26,即 26 个 512B,等于 13 KiB),但仅 11 KiB 被传输到主机。通过三个 SGL 段描述数据传输的内存位置,其中包含三个数据块描述符,长度分别为 3 KiB、4 KiB 和 4 KiB,还有一个位桶描述符指定忽略 2 KiB 的逻辑块数据。
The three SGL segments contain a total of three Data Block descriptors with lengths of 3 KiB, 4 KiB, and 4 KiB respectively. Segment 1 of the Destination SGL contains a Bit Bucket descriptor with a length of 2 KiB that specifies to not transfer (i.e., ignore) 2 KiB of logical block data from the NVM. Segment 1 of the destination SGL also contains a Last Segment descriptor specifying that the segment pointed to by the descriptor is the last SGL segment.
SGL Descriptor
每个 SGL Descriptor 的 16 byte 数据结构如下,主要分为两部分:
- SGL Identifier:表示 SGL Descriptor 的类型。又分了 Type 和 Sub Type。
- Descriptor Type Specific:根据不同 Type 来定义该字段的数据结构及表示含义。
SGL Identifier
SGL Descriptor Type
主要使用的有如下几种:
- 【00h】SGL Data Block descriptor
- 【01h】SGL Bit Bucket descriptor
- 【02h】SGL Segment descriptor
- 【03h】SGL Last Segment descriptor
SGL Descriptor Sub Type
- Type 为 1h,协议规定 Sub Type 必须为 0h。
- Type 为 1h 或 4h ,Sub Type 为 1h 时:controller 应 abort 该命令,并返回状态码 SGL Descriptor Type Invalid。
- Type 为 0h,2h,3h ,4h 时,Sub Type 为 0h 时:Adress 字段指定了数据块的 starting 64-bit memory byte address。
- Type 为 0h,2h,3h 时,Sub Type 为 1h 时:Adress 字段不再明确指定数据块的起始地址,而是包含一个可能是数据传输起始位置的偏移量。可以灵活地指定数据再内存中的相对位置,增加数据传输灵活性。
SGL Descriptor Type Invalid
SGL Data Block descriptor(0h)
SGL Identifier:详见本文章节 SGL Identifier
Address:8 byte。详见本文章节 SGL Descriptor Sub Type 和 dword alignment。
Length:对齐要求详见本文章节 dword alignment。长度限制:如果 Address 字段的值加上 Length 字段的值大于 1_00000000_00000000h,那么该 SGL 数据块描述符将被视为存在 “Data SGL Length Invalid(数据 SGL 长度无效)” 或 “Metadata SGL Length Invalid(元数据 SGL 长度无效)” 的错误。
注意:当 SGL 描述符所有位被设置为 0h,即成为一种特殊的 SGL Data Block descriptor,其 Address 和 Length 均为 0h ,这种特殊状态的描述符被定义为 NULL descriptor。实际应用中,NULL 描述符可用于表示特定含义,如指示数据传输的结束、标记某个操作不需要实际数据传输,或在特定的数据结构中作为占位符使用等。
Data SGL Length Invalid & Metadata SGL Length Invalid
SGL Bit Bucket descriptor(1h)
关于地址信息,没有 Address 字段,仅有 Length 字段。
Length:
- 指定要丢弃的数据量。为 0h 时,表示不丢弃任何数据。
- 根据数据流向不同
-
- read from Controller to Host(destination data buffer):指定丢弃的源数据 bytes 数目。丢弃的数据不需要传递给 Host。
- write from Host to Controller(source data buffer):此时 Length 被视作 0h 处理,即该字段无效。Bit Bucket descriptor 对 write 操作无效。
- 数据传输长度计算:
-
- destination data buffer 中,该长度包含在指定传输的数据长度内。
- source data buffer 中,该长度不包含在 NLB 指定的传输长度内。
SGL Segment descriptor(2h)
用于描述下一个 SGL Segment,最后一个除外。
Address、Length、SGL Identifier 都跟 Data Block descriptor 的一致。
SGL Last Segment descriptor(3h)
用于描述最后一个 SGL Segment。
Address、Length、SGL Identifier 都跟 Data Block descriptor 的一致。
Keyed SGL Data Block descriptor(4h)
包含了一个 32-bit 密钥(Key),用于数据加密、解密或数据块的身份验证等操作。
可指定的最大长度为(16 MiB - 1)。
使用这种 descriptor 进行访问时,需要借助其中的密钥。因此有助于保障内存访问的安全性。
Adress 字段只能指定数据块的 starting 64-bit memory byte address
Transport SGL Data Block descriptor(5h)
指定了一个数据块,由 NVMe 传输层通过特定的传输机制和数据缓冲区进行传输。
关于地址信息,没有 Address 字段,仅有 Length 字段。
相关配置
是否支持 SGL
由 Identify Controller Data Structure 来告知,如下图。
SGLS(SGL Support)
如果 Bytes 539:536 为 0 ,则不支持 SGL。反之,则支持。
dword alignment
如果 bit 01:10 设定为 10b,则 Data Blocks 需要 4 byte 对齐。即 Data Block 描述符中的 Address 和 Length 的最低 2 位都应清 0。
如果这两位没有清 0,则 Controller 可能会报告 Invalid Field in Command。
如果 Controller 没有报告错误,那么 Contoller 便是仍按照已清 0 的情况来处理数据。但可能存在风险。
Invalid Field in Command
SDT(SGL Descriptor Threshold)
SDT,SGL Descriptor Threshold,该字段告诉 host 单条 cmd 内推荐的 SGL descriptors 最大 个数是多少。如果该字段为 0,则表示没有推荐值上报。
如果超过 SDT,则 controller 性能可能降低。
SDT 应该小于 MSDBD。
MSDBD(Maximum SGL Data Block Descriptors)
表示了 host 被允许在一个数据包内放置的 SGL Data Block descriptors 或 Keyed SGL Data Block descriptors 的最大个数。
注意事项
- 数据缓冲区的总长度需 >= 请求传输的数据量。如果请求的数据量大于 SGL 描述的 Data Block 和 Bit Bucket 的总长度,那么数据不会被传输。
- 最后一个 SGL Segment 是特殊的 SGL Segment,不包含 SGL Segment descriptor,也不包含 SGL Last Segement Descriptor。
Reference
NVM Express® Base Specification, Revision 2.0e
结语
SGL作为NVM Express中用于描述数据缓冲区的关键数据结构,在数据传输过程中起着不可或缺的作用。从SGL的整体架构来看,它涵盖了多种类型的描述符,包括SGL数据块描述符、SGL位桶描述符、SGL段描述符等,每种描述符都有其特定的用途和规范。这些描述符相互配合,能够精确地定义数据在内存中的位置、长度以及传输方式,无论是简单的数据块传输,还是复杂的数据缓冲区布局,SGL都能提供有效的支持。
在实际应用场景中,SGL的重要性尤为凸显。在数据读取和写入操作中,通过合理配置SGL描述符,可以实现高效的数据传输,减少数据传输错误的发生。同时,SGL在处理不同类型的存储设备和传输协议时,展现出了良好的适应性。例如,在NVMe over Fabrics环境下,SGL是数据传输的重要手段,其规范的设计确保了在复杂网络环境下数据的准确传输。
然而,SGL的正确使用依赖于对其各个字段和描述符的深入理解。从地址字段的不同解释(根据子类型确定是绝对地址还是偏移量),到长度字段的严格要求(如对齐和粒度限制),再到描述符类型和子类型的精确匹配,任何一个环节的错误都可能导致数据传输失败或出现错误。因此,无论是主机软件开发者还是控制器硬件设计者,都需要严格遵循SGL的规范要求,以确保系统的稳定性和可靠性。
随着存储技术的不断发展,NVM Express规范也在持续演进,SGL作为其中的关键部分,也可能会面临新的挑战和需求。未来,SGL可能需要进一步优化以适应更高性能的存储设备和更复杂的传输场景。例如,随着存储容量的不断增大和数据传输速度的提升,SGL可能需要在描述符的管理和数据传输的效率方面进行改进,以满足日益增长的数据处理需求。同时,随着新的NVMe传输协议的出现,SGL也需要不断扩展和完善,以支持新的功能和特性。