NVMe 队列模型
- 3.3NVM Queue Models
- 3.3.1基于内存的传输队列模型
- 3.3.1.1队列设置与初始化
- 3.3.1.2Queue的使用
- 3.3.1.2.1Completion Queue Flow Control
- 3.3.1.3Queue Abort
- 3.3.1.4Empty Queue
- 3.3.1.5Full Queue
- 3.3.2基于消息的传输队列模型
- 3.3.2.1胶囊和数据传输
- 3.3.2.1.1Command Capsules
- 3.3.2.1.2响应胶囊
- 3.3.2.1.3数据传输
- 3.3.2.1.3.1命令胶囊内的数据和 SGL 位置
- 3.3.2.1.3.2数据传输示例
- 3.3.2.2建Queue
- 3.3.2.3Queue 的初始化和Queue State
- 3.3.2.4I/O Queue的删除
- 3.3.2.5Submission Queue Flow Control Negotiation
- 3.3.2.6Submission Queue Flow Control
- 3.3.2.7Submission Queue Head Pointer更新优化
- 3.3.2.8Completion Queue 注意事项
- 3.3.2.9Transport Requirements
3.3NVM Queue Models
NVM Express 接口基于成对的Submission和Completion Queue机制。主机软件将命令放入Submission Queue中。控制器将完成放入相关的Completion Queue中。当使用基于内存的传输队列模型时,多个Submission Queues可以使用相同的Completion Queue。当使用基于消息的传输队列模型时,每个Submission Queue都映射到一个Completion Queue。
3.3.1基于内存的传输队列模型
3.3.1.1队列设置与初始化
要设置和初始化 I/O Submission Queues 和 I/O Completion Queues 以供使用,主机软件遵循以下步骤:
-
通过适当初始化 Admin Queue Attributes(AQA)、Admin Submission Queue Base Address(ASQ) 和 Admin Completion Queue Base Address(ACQ) 寄存器来配置 Admin Submission 和 Completion Queues;
-
配置 I/O Submission Queues(CC.IOSQES)和 I/O Completion Queues(CC.IOCQES)的大小;
-
提交 Set Features 命令,其中 Number of Queues 属性设置为请求的 I/O Submission Queues数和 I/O Completion Queues 数。此 Set Features 命令的完成队列条目表示控制器分配的 I/O Submission Queues 和 I/O Completion Queues 的数量;
-
确定每个队列支持的最大条目数(CAP.MQES)以及队列是否需要物理上连续(CAP.CQR);
-
使用Create I/O Completion Queue命令在控制器分配数量和支持的队列属性(最大条目和物理连续要求)的限制内创建I/O Completion Queue;和
-
使用 Create I/O Submission Queue 命令在控制器分配数量和支持的队列属性(最大条目数和物理连续要求)的限制内创建 I/O Submission Queue。
在此过程结束时,I/O Submission Queues 和 I/O Completion Queues 已设置并初始化,可用于完成 I/O 命令。
3.3.1.2Queue的使用
基于内存的传输队列的条目提交者使用当前的尾部条目指针来标识下一个打开的队列槽。提交者在将新条目放入开放队列槽后递增尾部条目指针。如果 Tail 条目指针增量超过队列大小,Tail 条目将滚动到0。只要不满足完整队列条件,提交者就可以继续将条目放入空闲队列槽中(请参阅第 3.3.1.5 节)。
注意:提交者应考虑队列环绕条件。
基于内存的传输队列上条目的消费者使用当前的 Head 条目指针来标识包含要使用的下一个条目的插槽。消费者在消费队列中的下一个条目后递增 Head 条目指针。如果头条目指针增量超过队列大小,则头条目指针将滚动到0。只要不满足 Empty queue 条件,消费者就可以继续消费队列中的条目(参见第 3.3.1.3 节)。
注意:消费者应考虑队列环绕条件。
创建和删除基于内存的传输 Submission Queue 和相关的 Completion Queues 需要由主机软件正确排序。主机软件在创建任何关联的 Submission Queues 之前创建 Completion Queue。在创建关联的 Completion Queue 后,可以随时创建 Submission Queues。主机软件会在删除 Completion Queue 之前删除所有关联的 Submission Queues。要中止提交到提交队列主机软件的所有命令,请为该队列发出 Delete I/O Submission Queue 命令(请参阅第 3.3.1.3 节)。
主机软件写入 Submission Queue Tail Doorbell 和 Completion Queue Head Doorbell(请参阅 NVMe over PCIe Transport Specification 中的 Transport Specific Controller Properties 部分)以将相应条目指针的新值传达给控制器。如果主机软件将无效值写入 Submission Queue Tail Doorbell 或Completion Queue Head Doorbell 寄存器并且 Asynchronous Event Request 命令未完成,则将异步事件发布到 Admin Completion Queue,状态码为 Invalid Doorbell Write Value。然后关联的队列被主机软件删除并重新创建。对于遇到此错误的提交队列,控制器可能会完成之前使用过的命令;没有额外的命令被消耗。这种情况可能是由于主机软件试图将条目添加到完整的 Submission Queue 或从空的Completion Queue 中删除条目。
主机软件检查内存中的完成队列条目Phase Tag(P) 位以确定是否已发布新的完成队列条目。Completion Queue Tail 指针仅由控制器内部使用,对主机不可见。控制器使用完成队列条目中的 SQ Head Pointer (SQHD) 字段将 Submission Queue Head Pointer 的新值传递给主机。新的 SQHD 值表示提交队列条目已被消耗,但不表示任何命令的执行或完成。请参阅第 3.3.3.2 节。 当主机向关联的 Submission Queue Tail Doorbell 写入一个新值时,提交队列条目被提交给控制器,该值指示 Submission Queue Tail Pointer 已移动到或超过放置该提交队列条目的插槽。Submission Queue Tail Doorbell 可能指示一个或多个提交队列条目已被提交。
当提交完成队列条目指示 Submission Queue Head Pointer 移过放置该提交队列条目的槽时,控制器已使用提交队列条目。完成队列条目可以指示一个或多个提交队列条目已被消耗。
当控制器将完成队列条目写入下一个空闲的 Completion Queue 插槽时,将其在内存中的先前Phase Tag(P)位反转,然后将完成队列条目发布到 Completion Queue。控制器可以向主机生成中断以指示一个或多个完成队列条目已被发布。
主机使用完成队列条目后,主机使用新值写入关联的 Completion Queue Head Doorbell,该新值指示 Completion Queue Head Pointer 已移过放置完成队列条目的插槽。Completion Queue Head Doorbell 写入可能指示一个或多个完成队列条目已被消耗。
一旦提交队列条目或完成队列条目被消耗,放置它的槽是空闲的并且可以重用。在提交该条目之后但在该条目被使用之前更改该提交队列条目会导致未定义的行为。在发布该条目之后但在该条目被使用之前更改完成队列条目会导致未定义的行为。
3.3.1.2.1Completion Queue Flow Control
如果 Completion Queue 中没有空闲槽,则控制器不应将状态发布到该 Completion Queue,直到有槽可用。在这种情况下,控制器可能会停止处理与受影响的 Completion Queue 相关的其他提交队列条目,直到槽可用。控制器应继续处理与受影响的 Completion Queue 无关的其他 Submission Queues。
3.3.1.3Queue Abort
要中止大量命令,建议的过程是删除并重新创建 I/O Submission Queue。具体来说,要中止提交到 I/O Submission Queue 主机软件的所有命令,应该为该队列发出删除 I/O Submission Queue 命令。在队列被成功删除后,表明所有命令都已完成或中止,然后主机软件应通过提交 Create I/O Submission Queue 命令来重新创建队列。主机软件然后可以将命令重新提交到相关的 I/O Submission Queue。
3.3.1.4Empty Queue
当 Head 条目指针等于 Tail 条目指针时,队列为空。Figure 77 定义了 Empty Queue 条件。
3.3.1.5Full Queue
当 Head 比 Tail 多 1 时,队列已满。队列满时的条目数比队列大小小一。Figure 78 定义了 Full Queue 条件。
注意:在确定队列是否已满时,应考虑队列环绕条件。
3.3.2基于消息的传输队列模型
对于 NVMe over Fabrics,队列是用于在主机和控制器之间发送胶囊的单向通信通道。主机使用 Submission Queues 将命令胶囊(参见第 3.3.2.1.1 节)发送到控制器。控制器使用 Completion Queues 将响应胶囊(参见第 3.3.2.1.2 节)发送到主机。Submission和 Completion Queues是使用 Connect 命令成对创建的(请参阅第 3.3.2.2 节)。
NVMe Transport 负责将命令胶囊传送到控制器,并以特定传输的方式通知控制器胶囊到达。
主机提交到 Submission Queue 和将该胶囊传输到控制器之间更改命令胶囊会导致未定义的行为。
NVMe Transports 不需要提供任何额外的端到端流控制。特定的 NVMe Transports 可能需要低级别的flow control 来避免拥塞并提高可靠性;任何此类额外的 NVMe Transport flow control 都超出了本规范的范围。
Submission Queues(参阅 3.3.2.1.1、3.3.2.6 和 3.3.2.7 节)和 Completion Queues(参阅 3.3.2.1.2、3.3.2.8、3.3.1.2.1 节) 的 Flow control 不同。
3.3.2.1胶囊和数据传输
本节描述了支持基于消息的传输队列所必需的胶囊和数据传输机制。在使用基于消息的传输队列模型时,这些机制用于 Fabrics 命令、Admin 命令和 I/O 命令。
胶囊是主机和控制器之间交换的 NVMe 信息单元。胶囊可能包含命令、响应、SGL 和/或数据。数据可以包括用户数据(例如,逻辑块数据和作为逻辑块的连续部分传输的元数据)和与命令相关联的数据结构。
Admin Queue 命令和响应的胶囊大小是固定的,并在 NVMe Transport binding 中定义。控制器在 Identify Controller data structure 中指示主机应与 I/O 命令一起使用的胶囊命令和响应大小。
控制器应支持 Admin Queue 和 I/O Queues 上命令的基于 SGL 的数据传输。数据可以在胶囊内或通过基于底层 NVMe Transport 的内存事务传输,如与命令胶囊相关联的 SGL 描述符中所示。NVMe Transport 支持的 SGL 类型在 NVMe Transport binding 规范中指定。
未使用和未保留的胶囊字段(例如,胶囊大于命令/响应和相关数据)的值是未定义的,并且不应由接收者解释。
3.3.2.1.1Command Capsules
命令胶囊从主机发送到控制器。它包含一个提交队列条目 (SQE),并且可以选择包含数据或 SGL。SQE 大小为 64 字节,包含要执行的 Admin 命令、I/O 命令或 Fabrics 命令。
SQE 中的 Command Identifier 字段在与该队列相关的所有未完成的命令中应该是唯一的。如果有数据或额外的 SGL 在胶囊内传输,则 SQE 中的 SGL 描述符包含指定适当Offset地址的Data Block、Segment Descriptor 或 Last Segment Descriptor。当命令是 Fabrics 命令时提交队列条目的定义在Figure 80. 中定义。当命令是 Admin 或 I/O 命令时提交队列条目的定义在第 3.3.3.1 节中定义,其中Metadata Pointer 字段被保留。
3.3.2.1.2响应胶囊
响应胶囊从 NVM 子系统发送到主机。它包含一个完成队列条目 (CQE),并且可以选择包含数据。CQE 是与先前发布的命令胶囊相关的完成队列条目。
如果命令请求数据并且相关命令胶囊中的 SGL 指定了带有Offset的 Data Block 描述符,则数据将包含在响应胶囊中。如果命令胶囊中的 SGL(s) 指定主机内存中的区域,则数据通过内存事务传输。
完成队列条目的大小为 16 字节,并包含一个两字节的状态字段。
Fabrics 命令的完成队列条目的定义在Figure 82 中定义。当命令是 Admin 或 I/O 命令时,完成队列条目的定义在第 3.3.3.2 节中定义,其中 SQ Identifier 和 Phase Tag是保留字段,因为它们未在 NVMe over Fabrics 中使用。SQHD 字段的使用取决于是否为队列对禁用了 SQ flow control,请参阅第 6.3 节。
3.3.2.1.3数据传输
数据可以在胶囊内传输或通过内存传输。SGL 用于指定数据的位置。元数据(如果已传输)是与该元数据相关联的用户数据的连续部分。SGL 描述符(参见第 4.1.2 节)指定命令的数据是通过内存还是在胶囊内传输。在 SQE 之后,胶囊可能包含 SGL 或数据(不是两者的混合)。如果需要额外的 SGL,则 SGL 会在 SQE 之后立即包含在胶囊中。如果在 SGL 描述符中指定了无效偏移量,则应返回 SGL Offset Invalid 状态码。
SGL 应在一个胶囊内得到支持。NVMe Transport binding 规范定义了相应 NVMe Transport 支持的 SGL Descriptor Types 和 Sub Types。NVMe Transport binding 规范还指定主机内存是否支持 SGL。
3.3.2.1.3.1命令胶囊内的数据和 SGL 位置
命令胶囊内的提交队列条目包括一个 SGL 条目。如果在命令包中还有其他 SGL 条目要传输,那么这些条目应该是连续的,并且位于提交队列条目之后。
NVMe Transport binding 规范将数据支持定义为命令胶囊的一部分。控制器通过 Identify Controller data structure 中的 In Capsule Data Offset (ICDOFF) 字段指示命令胶囊内数据的起始位置。
主机应遵循的 SGL 有一些限制:
- 如果 ICDOFF 字段为非0值,则提交队列条目之后的所有 SGL 描述符的总大小不得大于 (ICDOFF * 16);
- 如果提交队列条目之后的 SGL 描述符的总大小大于 (ICDOFF * 16),则控制器应以 Invalid Number of SGL Descriptors 状态码中止命令;
- 主机在胶囊中放置的 SGL Data Block或 Keyed SGL Data Block 描述符不得超过 Identify Controller data structure 中指示的最大值;和
- 如果主机在一个胶囊中放置了比 Identify Controller data structure 中最大 SGL Data Block Descriptors 字段中指示的最大值更多的 Keyed SGL Data Block 描述符中的 SGL Data Block,则控制器应以 Invalid Number of SGL Descriptors 中止命令。
主机应从提交队列条目末尾的byte offset (ICDOFF * 16) 开始命令胶囊中的数据(如果存在)。
3.3.2.1.3.2数据传输示例
Figure 84 和Figure 85 中的数据传输示例显示了 Write 命令的 SGL 示例,其中数据通过内存事务或在胶囊内传输。根据所使用的 NVMe Transport 要求,SGL 可以使用密钥作为数据传输的一部分。
第一个示例显示了一个 8KiB 写入,其中所有数据都通过内存事务传输。在这种情况下,在 CMD.SGL1 的提交队列条目中包含一个 SGL 描述符。SGL 描述符是一个 Keyed SGL Data Block 描述符。如果需要更多 SGL 来完成命令,则额外的 SGL 包含在命令胶囊中。
第二个示例显示了一个 8KiB 写入,其中所有数据都在胶囊内传输。在这种情况下,SGL 描述符是一个 SGL Data Block 描述符,它基于 2h 的 ICDOFF 值指定 20h 的偏移量。
3.3.2.2建Queue
使用基于消息的传输队列模型的控制器使用 Connect 命令(请参阅第 6.3 节)来创建Admin或 I/O Queues。Admin Queue 的创建建立了主机和相应控制器之间的关联。因为建立 Admin Queue 所需的所有信息都包含在Connect命令,基于消息的传输队列模型不支持 Admin Submission Queue Base Address (ASQ)、Admin Completion Queue Base Address (ACQ) 和 Admin Queue Attributes (AQA) 属性。基于消息的传输队列模型不支持与 I/O Queue 创建和删除相关的Admin命令(Create I/O Completion Queue、Create I/O Submission Queue、Delete I/O Completion Queue、Delete I/O Submission Queue)。 在传输任何胶囊或数据之前,在主机和 NVM 子系统之间建立 NVMe Transport 连接。用于建立 NVMe Transport 连接的机制是NVMe Transport 特定的,并由相应的 NVMe Transport binding 规范定义。NVMe Transport 可能需要为每个Admin或 I/O 队列使用单独的 NVMe Transport 连接,或者可以为与特定控制器关联的所有 Admin 和 I/O 队列使用相同的 NVMe Transport 连接。NVMe Transport 还可能要求在建立 NVMe Transport 连接的过程中在主机和控制器之间传递 NVMe 层信息(例如,交换队列大小以适当大小的发送和接收buffers)。
Connect 命令指定 Queue ID 和类型(Admin 或 I/O)、Submission 和 Completion Queues 的大小、队列属性、Host NQN、NVM Subsystem NQN 和 Host Identifier。如果 NVM 子系统支持静态控制器模型,则 Connect 命令可以指定特定控制器。Connect 响应指示连接是否成功建立以及是否需要 NVMe 带内身份验证。
Connect 命令被提交到 Connect 命令创建的同一 Admin Queue 或 I/O Queue。首先创建用于该队列的底层 NVMe Transport 连接,然后通过该 NVMe Transport 连接发送 Connect 命令和响应胶囊。Connect 命令应发送一次到队列。
当 Connect 命令成功完成时,会创建相应的 Submission 和 Completion 队列。如果 Connect 响应中指示需要 NVMe 带内身份验证,则应在队列可用于执行其他 Fabrics 命令、Admin 命令或 I/O 命令之前执行 NVMe 带内身份验证。一旦 Admin Queue 的 Connect 命令成功完成(并且 NVMe 带内身份验证(如果需要)已成功),在控制器准备就绪 (CSTS.RDY = 1) 之前,只能提交 Fabrics 命令。当控制器准备好时,Fabrics 命令和 Admin 命令都可以提交到 Admin Queue。控制器准备就绪后,可以提交 I/O Queue 的 Connect 命令。一旦 I/O Queue 的 Connect 命令成功完成(如果需要,NVMe 带内身份验证也成功),I/O 命令可以提交到队列。
Connect 响应包含分配给主机的控制器 ID。与该控制器创建 I/O Queue 的所有后续 Connect 命令应来自同一主机,使用相同的 NVMe Transport,并具有相同的 Host Identifier、Host NQN 和 NVM Subsystem NQN;如果不满足这些条件中的任何一个,则 Connect 命令将失败。
3.3.2.3Queue 的初始化和Queue State
当 Connect 命令成功完成时,会创建相应的 Admin Submission 和 Completion Queue 或 I/O Submission和 Completion Queues。如果主机发送一个 Connect 命令指定一个已经存在的队列的队列ID,则返回一个 Command Sequence Error 的状态码。
Connect 响应中的 Authentication Requirements(AUTHREQ) 字段指示是否需要 NVMe 带内身份验证。如果 AUTHREQ 被清除为0,则在 Connect 命令成功完成后,创建的队列就可以使用了。如果 AUTHREQ 设置为非0值,则在使用 Authentication Send 和 Authentication Receive Fabrics 命令成功执行 NVMe 带内身份验证后,创建的队列就可以使用了。
如果控制器需要或正在为队列对进行 NVMe 带内身份验证,则控制器应中止在该队列上接收到的所有命令,但状态代码为 Authentication Required 的身份验证命令除外。在队列上成功执行 NVMe 带内身份验证后,控制器应中止该队列上的所有身份验证命令,状态码为 Command Sequence Error。
首次创建 Admin Queue 列时,关联的控制器被disable(即 CC.EN 初始化为“0”)。disable的控制器应中止 Admin Queue 上除 Fabrics 命令之外的所有命令,状态码为 Command Sequence Error。enable 控制器后,除了 Fabrics 命令外,它还应接受所有支持的Admin命令。 如果关联的控制器被disabled,则创建的 I/O 队列将中止所有带有 Command Sequence Error 状态代码的命令。
3.3.2.4I/O Queue的删除
NVMe over Fabrics 会删除单个 I/O Queue,并且可能会删除关联的 NVMe Transport 连接,因为:
- 在主机和控制器之间交换 Disconnect 命令和响应(参见第 6.4 节);要么
- 检测和处理 NVMe Transport 连接上的传输错误。
主机通过在用于创建 Admin Queue 的Connect命令(参见Figure 380)的 CATTR 字段中将bit 3 设置为“1”来表示支持删除单个 I/O Queue。控制器通过在 Identify Controller data structure 的 Identify Controller Attributes 区域的 OFCS 字段中将位 0 设置为“1”来表示支持删除单个 I/O Queue(参见Figure 275)。
如果主机和控制器都支持删除单个 I/O Queue,则单个 I/O Queue的终止仅影响该 I/O Queue(即控制器所有其他的 I/O Queues 及其关联的 NVMe Transport 连接不受影响)。如果主机或控制器不支持删除单个 I/O Queue,则删除单个 I/O Queue 或终止 NVMe Transport 连接会导致关联终止。
NVMe over Fabrics 使用 Disconnect 命令删除单个 I/O Queue。此命令在要删除的 I/O Submission Queue 上发送,并且仅影响该 I/O Submission Queue 及其关联的 I/O Completion Queue(即,其他 I/O Queues 不受影响)。要删除 I/O Queue,请使用该 I/O Queue 的 NVMe Transport 连接。如果与 NVMe Transport 连接关联的所有队列都被删除,则 NVMe Transport 连接可能会在完成 Disconnect 命令后被删除。删除 NVMe Transport 连接所需的操作是transport 特定的。主机和控制器之间的关联不受影响。
如果 Disconnect 命令返回的状态码不是 success,则主机可以使用其他方法删除 I/O Queue,包括:
- 等待供应商特定的时间并重试 Disconnect 命令;
- 删除 NVMe Transport 连接(注意:这可能会影响其他 I/O Queues);
- 执行 Controller Level Reset(注意:这会影响其他 I/O Queues);要么
- 结束主机到控制器的关联。
如果传输需要为每个 Admin 和 I/O Queue 提供单独的 NVMe Transport 连接(请参阅第 3.3.2.2 节),则主机不应删除 NVMe Transport 连接,直到:
- 已将 Disconnect 命令提交到 I/O Submission Queue;和
- 主机在相应的 I/O Completion Queue 上收到了对该 Disconnect 命令的响应,或者在等待该响应时发生了供应商特定的超时(请参阅第 3.9 节)。
如果传输需要为每个 Admin和 I/O Queue提供单独的 NVMe Transport 连接,则控制器不应删除 NVMe Transport 连接,直到:
- 在 I/O Submission Queue 上已收到 Disconnect 命令并由控制器处理;
- 在收到 Disconnect 命令之前,控制器在该 I/O Submission Queue 上收到的命令的响应已发送到主机上的相应 I/O Completion Queue;且
- 该 Disconnect 命令的结果响应已发送到主机上的相应 I/O Completion Queue(即,此响应是最后发送的响应)。建议控制器延迟破坏 NVMe Transport 连接,以便主机有时间接收 Disconnect 命令响应(例如,发生特定传输事件或过去特定传输时间段)。
如果传输对与特定控制器关联的所有 Admin 和 I/O Queues 使用相同的 NVMe Transport 连接(请参阅第 3.3.2.2 节),则删除单个 I/O Queue 对 NVMe Transport 连接没有影响。
Disconnect 命令是控制器为 I/O Queue处理的最后一个 I/O Submission Queue 条目。控制器处理完成或中止Disconnect 命令所在的 I/O Queue 上的所有命令。控制器确定是完成还是中止这些命令中的每一个。
对 Disconnect 命令的响应是主机为 I/O Queue 处理的最后一个 I/O Completion Queue 条目。为避免命令中止,主机应等待 I/O Queue 上未完成的命令完成,然后再发送 Disconnect 命令。
如果控制器检测到 NVMe Transport 连接丢失,则控制器应停止处理在与该 NVMe Transport 连接关联的 I/O Queues 上接收到的所有命令。在控制器检测到 NVMe Transport 连接丢失或发送成功完成 Disconnect 命令之前,控制器可能会继续处理未完成的命令。
如果主机在收到所有提交到相关 I/O Queue 的未完成命令的响应之前检测到 NVMe Transport 连接丢失,则主机无法获得有关这些命令状态的更多信息(例如,每个单独的未完成命令可能已由控制器完成或中止)。如果由于 NVMe Transport 错误导致 NVMe Transport 连接丢失,则在执行与在与该 NVMe Transport连接关联的 I/O 队列上发送的命令相关的恢复操作之前,主机应至少等待以下时间中的较长者:
- NVMe Keep Alive 超时;
- 底层fabric transport 超时(如果有)。
3.3.2.5Submission Queue Flow Control Negotiation
Submission Queue (SQ) 流控制的使用由每个队列对的 Connect 命令和控制器对 Connect 命令的响应协商。除非由于协商而被disabled,否则应使用 SQ 流控制。如果disable SQ 流控制,则在响应 Connect 命令之后,在该队列对的所有 Fabrics 响应胶囊中保留 Submission Queue Head Pointer (SQHD)字段(即,在该队列对的所有后续响应胶囊中,控制器应将 SQHD 字段清为 0h,并且主机应忽略 SQHD 字段)。
如果主机请求为队列对disable SQ 流控制,则主机应调整每个 Submission Queue 的大小,以支持主机一次可以为该 Submission Queue 处理的最大命令数。
Admin Submission Queue 的最大大小在 NVM 子系统的 Discovery Log Page Entry 的 Admin Max SQ Size (ASQSZ) 字段中指定(请参阅第 5.16.1.23 节)。
I/O Submission Queue 的最大大小在控制器的 Controller Capabilities(CAP) 属性的支持的 Maximum Queue Entries Supported (MQES) 字段中指定(请参阅第 3.1.3.1 节)。
Identify Controller data structure 中的 Maximum Outstanding Commands (MAXCMD) 值指示控制器一次为特定 I/O 队列处理的最大命令数。主机可以使用该值来调整 I/O Submission Queues 的大小,并优化每个队列一次提交的命令数量,以实现最佳性能。
如果disable SQ 流控制,则主机应将队列对的未完成命令数限制为小于 Submission Queue 的大小。如果控制器检测到队列对的未完成命令的数量大于或等于 Submission Queue 的大小,则控制器应:
a)停止处理命令并设置
b)Controller Fatal Status (CSTS.CFS) 位为“1”(参见第 9.5 节);
c)终止 NVMe Transport 连接并结束主机和控制器之间的关联
3.3.2.6Submission Queue Flow Control
Submission Queue 有一个Head条目指针和一个Tail条目指针,用于管理队列并确定主机可用于新提交的Submission Queue胶囊的数量。当创建队列时,Head 和 Tail 条目指针被初始化为 0h。对入口指针的所有算术运算和比较都是以队列大小为模执行的,并考虑了队列换行条件。当主机将胶囊添加到队列时,主机会增加 Tail 条目指针。当控制器从队列中移除胶囊时,控制器会增加 Head 条目指针。
Submission Queue Head 指针由控制器维护,并在完成队列条目的 SQHD 字段中与主机通信。主机使用接收到的 SQHD 值进行 Submission Queue 管理(例如,确定 Submission Queue 是否已满)。
提交队列尾条目指针是主机本地的,不与控制器通信。
当 Head 条目指针比 Tail 条目指针多 1 时,提交队列已满(即,增加 Tail 条目指针会导致它回绕到 Head 条目指针的后面)。一个完整的 Submission Queue 包含比队列大小少一个胶囊。只要队列未满,主机就可以继续向提交队列Submission Queue。
如果控制器检测到主机已将命令胶囊提交到完整的提交队列,则控制器应:
a)停止处理命令并将 Controller Fatal Status (CSTS.CFS) 位设置为“1”(参见第 9.5 节);
b)终止 NVMe Transport 连接并结束主机和控制器之间的关联。
当 Head 条目指针等于 Tail 条目指针时,Submission Queue 为空。
3.3.2.7Submission Queue Head Pointer更新优化
Submission Queue Head Pointer 更新优化不适用于禁用Submission Queue (SQ) 流控制的队列对,因为如果禁用 SQ 流控制,则保留 SQHD 字段,请参阅第 3.3.2.5 节和第 6.3 节。
NVMe Transport 可能会忽略响应胶囊的 SQHD 值的传输:
a)包含一个 Generic Command 状态(即,Status Code Type 0h),指示命令成功完成(即,Status Code 00h);
b)不是Connect响应胶囊;和
c)不是 Disconnect 响应胶囊。
如果在响应胶囊中未收到新的 SQHD 值,则主机继续使用其先前的 SQHD 值。因此,在 NVMe 层存在 SQHD 值的逻辑级数,尽管事实上 NVMe Transport 可能不会在每个响应胶囊中实际传输 SQHD 值。
NVMe Transport 可以以任何顺序向主机传递不包含 SQHD 值的响应胶囊。适用的 NVMe Transport binding规范定义了 NVMe Transport 如何指示响应胶囊中是否存在 SQHD 值。
需要在主机上定期更新 SQHD 以避免 Submission Queue (SQ) 饥饿,因为响应中的 SQHD 值传输是释放 SQ 槽以供主机重用的唯一方法。
NVMe Transport 可以在每个响应胶囊中传输 SQHD 值。如果 NVMe Transport 不在每个响应胶囊中传输 SQHD 值,则应定期传输 SQHD 值(例如,在 CQ 上的每 n 个响应胶囊中的至少一个中,其中 n 是相关联的大小的 10% SQ)或更频繁。如果相关 SQ 中 90% 或更多的槽在子系统中被占用,则应始终发送 SQHD 值。
3.3.2.8Completion Queue 注意事项
基于消息的传输队列模型中不使用 Completion Queue 流控制(请参阅第 3.3.1.2.1 节)。基于消息的传输 Completion Queues 不使用Head条目指针或Tail条目指针。
主机应调整每个 Completion Queue 的大小,以支持主机一次针对特定 Submission Queue 可能有的未完成命令的最大数量。Completion Queue 的大小可能大于相应的 Submission Queue 的大小,以适应控制器正在处理的命令的响应以及仍在 Submission Queue 中的命令的响应。
如果 Completion Queue 的大小对于未完成命令的数量来说太小,并且控制器将响应胶囊提交到完整的Completion Queue,那么结果是未定义的。
Identify Controller data structure 中的最大 Maximum Outstanding Commands(MAXCMD) 值指示控制器一次为特定 I/O Queue 处理的最大命令数。主机可以使用该值来调整 I/O Completion Queues 的大小,并优化每个队列一次提交的命令数以实现最佳性能。
控制器提交到 Completion Queue 和将该胶囊传输到主机之间更改响应胶囊会导致未定义的行为。
3.3.2.9Transport Requirements
本节定义了支持 NVMe over Fabrics 实施的所有 NVMe Transports 应满足的要求。
NVMe Transport 可以支持 NVMe Transport 错误检测,并在命令状态值中向 NVMe 层报告错误。控制器可能会在 Error Information Log 中记录 NVMe Transport 特定错误。以低级 NVMe Transport 无法重播或恢复的方式导致消息丢失或数据丢失的传输错误应导致:
- 删除单个 I/O Queues (请参阅第 3.3.2.4 节)并发生 NVMe Transport 级别错误的相关 NVMe Transport 连接;或
- 终止 NVMe Transport 连接以及主机和控制器之间的关联。
NVMe Transport 应通过每个连接在主机和 NVM 子系统(和分配的控制器)之间提供可靠的胶囊传输。NVMe Transport 可以在每个队列上以任何顺序传递命令胶囊,但作为fused操作一部分的 I/O 命令除外(请参阅第 3.4.2 节)。
对于作为 I/O 命令fused操作一部分的命令胶囊,NVMe Transport:
a)应按顺序将每个fused操作的第一个和第二个命令胶囊传送到队列;和
b)在为fused操作发出两个命令胶囊之间,不得为同一Submission Queue交付任何其他命令胶囊。
NVMe Transport 应通过每个连接提供从 NVMe 子系统到主机的响应胶囊的可靠传递。NVMe Transport 应按顺序向主机发出包含 SQ Head Pointer (SQHD) 值的响应胶囊;这包括所有 Connect 响应胶囊和所有 Disconnect 响应胶囊。