请求/响应侧错误检测整体架构:
IBA 使用分层错误管理架构 (LEMA) 方法。每个级别负责检测和管理适合该层的错误,然后再将数据包或消息传递到堆栈中的下一层。因此,传输层会响应传输特有的错误,包括数据包头中的错误和无法正确传输消息。在传输层中检测到的错误会报告给传输的客户端。在本节中,传输层与其客户端之间的接口在概念上显示为发送或接收队列。对于 HCA,传输通过将完成代码写入完成队列 (CQ) 上的完成队列条目 (CQE) 来向其客户端指示错误。与往常一样,TCA 可以根据自己的需要自由报告错误(或不报告)。为了简化讨论,将分别讨论请求方和响应方的错误行为。这会导致以下部分中描述请求方和响应方错误的摘要表之间出现少量重复。具体而言,当响应方检测到错误并报告给请求方时,就会发生重叠。然而,这些重叠区域严格限于可靠的服务类别。请求者向其客户端报告的错误分为两类。
第一类是本地检测错误;即仅由请求者端检测到的错误。本地检测错误的一个例子是请求者在发送请求期间访问其自己的本地内存时检测到的保护故障。
第二类是远程检测错误,即响应者检测到的错误,并通过响应数据包中的 NAK 综合征报告给请求者。远程检测错误仅适用于可靠的服务类别(可靠连接和可靠数据报)。
虽然请求者端有两类错误(本地和远程检测),但响应者端只有本地检测错误。响应本地检测到的错误,响应者端可能需要向请求者报告错误,或者可能需要向其本地客户端报告错误,或者两者兼而有之,或者两者都不报告。向谁报告错误取决于服务类别(可靠还是不可靠)以及检测到的具体错误。以下各节的重点是根据向传输层客户端报告错误的方式以及发送(接收)队列在检测到错误后必须表现出的行为对所有错误进行分类。因此,本节不仅根据检测到错误的位置进行分类,还根据向谁报告错误进行分类
关键词
对于 HCA,IBA 软件接口定义了三种可以通过 verbs 层报告的错误类型。这些错误称为立即错误、完成错误和异步错误。在这三种错误类型中,传输层只能报告完成错误或异步错误。这是因为在 WQE 发布到传输层之前,verbs 层就会检测到立即错误。表 58 传输层检测到的软件错误类型(第 424 页)总结了 IBA 传输可以检测并报告给 verbs 层的错误类型。有关这些错误类型的更多信息,请参见 10.10.2 错误处理机制(第 563 页)
表 58 传输层检测到的软件错误类型
完成错误有两类:接口检查和处理错误。接口检查是在将数据放入链接之前检测到提供给通道接口的信息中的错误。处理错误是在通道接口处理工作请求期间遇到的错误
如上所述,请求者检测到源自本地或远程的错误
本地检测到的错误反映了请求方通道接口中发生的错误情况、响应方的响应缺失(超时)或序列错误或 RNR NAK 的重试次数过多。请求方本地检测到的错误可能发生在请求数据包生成期间、响应数据包处理期间或由于超时。
C9-209:对于使用 RC、UC 或 UD 服务的 HCA 请求方以及使用 UD 服务的 TCA 请求方,请求方应采取以下行为。对于在传输请求数据包期间检测到的本地检测到的传输错误,CA 应停止受影响 QP 的传输,应存储与错误相关的状态,直到任何先前未完成的 WQE 完成,并最终完成受影响的 WQE。如果错误类型需要,QP 应进入错误状态。
o9-149:如果 TCA 请求方实施可靠连接或不可靠连接服务或 XRC 服务,则应采取以下行为。对于在传输请求数据包期间检测到的本地检测到的传输错误,CA 应停止受影响的 QP 的传输,应存储与错误相关的状态,直到任何先前未完成的 WQE 完成,并最终完成受影响的 WQE。如果错误类型要求,QP 应置于错误状态。
o9-150:如果 CA 请求者实施可靠数据报或 XRC 服务,则其行为应如下。对于在传输请求数据包期间检测到的本地检测到的传输错误,CA 应停止受影响的 EEC 的传输,应存储与错误相关的状态,直到任何先前未完成的 WQE 完成,并最终完成受影响的 WQE。如果错误类型要求,EEC 应置于错误状态。这是维持 WQE 的有序完成并确保在发生错误的 WQE 中正确报告错误所必需的
C9-210:对于使用可靠连接服务的 HCA,为了检测过度重试,请求者应维护 RNR NAK 和错误重试计数器,这些计数器执行第 425 页 9.9.2.1.1 请求者错误重试计数器中描述的逻辑功能。
o9-151:如果 CA 请求者实施可靠数据报服务或 XRC 服务,或者 TCA 请求者实施可靠连接服务,则请求者应按如下方式行事。为了检测过度重试,请求者应维护 RNR NAK 和错误重试计数器,这些计数器执行第 425 页 9.9.2.1.1 请求者错误重试计数器中描述的逻辑功能。实现可以以任何方式实现这些重试计数器,但为了清楚起见,这里将它们描述为倒数计数器,初始化为在终止操作并创建最终完成错误之前允许的重试次数。有关在 HCA 中对这些计数器进行编程的信息,请参见第 468 页上的 10.2.4.3 修改队列对属性。每次响应方返回 RNR NAK 时,RNR NAK 重试计数器都会递减。如果请求方的 RNR NAK 重试计数器为零,并且收到 RNR NAK 数据包,则会发生 RNR NAK 重试错误。每次清除 RNR NAK(即返回 RNR NAK 以外的确认消息)时,都会重新加载重试计数器。以下情况的一个例外是如果 RNR NAK 重试计数器设置为 7。此值表示无限重试,计数器不会递减。每次请求方由于本地确认超时、NAK 序列错误或隐含 NAK 而必须重试数据包时,错误重试计数器都会递减。如果请求方的重试计数器递减为零,则可能实现以下两种情况之一。如果不支持自动路径迁移,或者已经完成,则应在完成时报告“传输重试计数器超出”错误。
o9-152:如果 CA 支持自动路径迁移,则在可能可恢复的错误及其重试之后,请求者可以迁移连接或 EE 上下文并再次执行错误重试,然后最终报告错误完成。有关更多信息,请参阅第 1200 页的 17.2.8 自动路径迁移。每次正确确认数据包时,应重新加载重试计数器
当响应者向请求者报告错误时,就会发生远程检测错误。远程检测错误是可靠服务类别所独有的。远程检测错误通过确认消息中携带的 NAK 代码报告。但是,并非所有 NAK 代码都会导致向请求者的客户端报告错误。在可能的 NAK 代码中,有两个(NAK-序列错误和 NAK-RNR)表示应由请求者自动重试的操作。NAK-序列错误和 NAK-RNR 以外的 NAK 代码表示必须立即向请求者的客户端报告且无法重试的失败
下表 59 列出了请求方检测到的所有错误,包括本地和远程检测到的错误。如果错误是由请求方本地检测到的,则标有“综合征(Syndrome)”的列包含“本地检测到的错误”符号。如果错误是由响应方远程检测到的,则此列列出响应方返回的 NAK 综合征。故障行为类指定请求方向其客户端报告错误所采取的操作。每个故障行为类在下面的第 9.9.2.4.1 至 9.9.2.4.5 节中指定。为方便起见,下面第 430 页的表 60 请求方故障行为类摘要中总结了六种可能的故障行为类(A/B/C/D/E/F)。C9-211:此合规声明已过时,已被 C9-211.1.1:取代。 C9-211.1.1:对于已实施的传输服务子集,请求者应符合表 59 中规定的错误行为。此外,请求者的发送队列应按照表 60 中所示的每个故障行为类别和每个请求者类别故障描述进行操作
a. 第 9 章中定义的 A 类现在被解释为也支持 XRC INI QP(即,无论在哪里读 RC,都应将其解释为 RC 或 XRC INI)。
b. 本地操作错误往往非常特定于实现;并非所有 CA 都可能具有或检测到这些错误。
c. 我们故意“重载”此 RD 特定的 NAK 综合征,因为它符合所讨论错误的本质。由于这是 XRC QP,因此不会造成混淆。
d. 例如;RDMA 读取而不是确认,RDMA 读取的 AETH 中的 NAK 代码,或“RDMA 读取响应最后”而不是中间。请注意,存在一些特定例外情况,实现可以选择不将其视为不良响应,这些例外情况包括:在请求者生成了重复的 RDMA 读取请求的情况下,RDMA 读取响应操作码无序,或者收到 ACK 而不是原子响应的 RDMA 读取响应。此 ACK 可能是响应者发送的未经请求的 ACK 的结果,该 ACK 在预期的 RDMA READ 或原子响应之前到达请求者。请求者可以丢弃此 ACK 数据包而不会产生任何不良影响。例如,第 9 章中定义的 E 类现在被解释为也支持 XRC INI QP(即,无论在哪里读取 RC,都应将其解释为 RC 或 XRC INI)
6大类请求侧故障:
a. 此类错误可能会导致整个 HCA 无法继续工作,在这种情况下,队列错误状态可能未知
b. B 类和 D 类类似,但 D 类仅适用于可靠数据报服务,并且还指定请求者的 EE 上下文转换为错误状态
c. 类 A 和 E 看起来类似,但类 A 需要重试,类 E 不采取任何措施
请求者必须实现五种不同的错误响应行为。对于任何给定的错误执行哪种行为如上表 59 所示。本节指定了错误响应行为
A 类错误是那些可以通过重试机制由传输恢复的错误。如果重试成功,则对传输的客户端(例如动词层)没有明显影响。唯一的 A 类错误是数据包序列错误、隐含 NAK 序列错误、本地确认超时错误和 RNR NAK。数据包序列错误和 RNR NAK 都是远程检测到的。本地确认超时错误和隐含 NAK 序列错误由请求者在本地检测到
C9-212:对于使用可靠连接服务的 HCA,每次传输重试请求者 A 类错误时,它都应减少重试计数器。有一个与数据包序列错误和本地确认超时错误相关联的重试计数器,以及与 RNR NAK 相关联的另一个重试计数器。只要重试计数未过期,传输就可以继续重试这些错误。重试这些错误的协议在第 304 页的第 9.7 节可靠服务中给出。
o9-153:如果 TCA 请求者实现可靠连接服务,或者 CA 请求者实现可靠数据报服务或 XRC 服务,则每次请求者重试请求者 A 类错误时,它都应减少重试计数器。有一个重试计数器与数据包序列错误和本地确认超时错误相关联,还有一个不同的重试计数器与 RNR NAK 相关联。只要重试计数没有过期,传输就可以继续重试这些错误。重试这些错误的协议在第 304 页的第 9.7 节可靠服务中给出。
C9-213:对于使用可靠连接服务的 HCA 请求者,由于请求者 A 类错误是可恢复的,因此除非重试计数过期,否则请求者不得将它们报告给传输的客户端。
o9-154:如果 TCA 请求者实施可靠连接服务,或者 CA 请求者实施可靠数据报服务或 XRC 服务,由于请求者 A 类错误是可恢复的,因此除非重试计数到期,否则请求者不得将其报告给传输的客户端。有关重试计数到期后如何报告 HCA 错误的讨论,请参阅第 563 页上的第 10.10.2.2 节完成错
上图为: 请求测A类错误驱动处理逻辑
C9-214:响应请求者 B 类错误,对于可靠数据报以外的服务,请求者应完成当前错误的 WQE,将发送队列SQ转换为错误状态,并将发布到发送队列的任何后续 WQE 标记为已刷新(flushed)。
o9-154.a1:对于实施可靠数据报服务的 CA,响应请求者 B 类错误,请求者应执行第 392 页第 9.7.8.5 节处理 QP 错误 - RESYNC 中描述的操作。如果按照所述 RESYNC 过程,消息仍然有错误,请求者应完成当前错误的 WQE,将发送队列转换为错误状态,并将发布到发送队列的任何后续 WQE 标记为已刷新。对于 HCA,错误发布为“完成 - 处理类型(“Completion - Processing type)”,并带有适当的错误类型(有关更多详细信息,请参阅第 563 页上的 10.10.2.2 完成错误)。传输层应将队列转换为错误状态,以防止在客户端(例如,HCA 的动词层)在发现发生错误之前将更多 WQE 发布到发送队列时可能发生的竞争条件。这与第 484 页上的图 127 QP/EE 上下文状态图所示的发送队列状态图一致。最后,发送队列中失败 WQE 后面的所有 WQE 也以“已完成 - 错误刷新”状态完成。对于 RC 或 XRC 模式,请注意,其中一些请求可能已由请求者提交到线路,甚至可能已由响应者执行和完成。无法阻止这种情况,因为响应者可能在请求者检测到本地错误之前执行了请求。因此,必须将响应者的本地状态视为未知。对于可靠的数据报服务,请求者的 EE 上下文终止当前消息传输,向当前调度的发送队列发出错误信号,并从调度程序中删除当前调度的发送队列。然后,EE 上下文调度下一个发送队列请求服务并继续。导致错误的发送队列的行为如上所述。
C9-215:当发送队列处于错误状态时,它必须默默丢弃到达的任何确认消息
以下为B类错误处理逻辑:
由于 C 类错误无法与任何特定 WQE 关联,因此无法将特定 WQE 标记为错误完成。
C9-216:如果请求者 C 类错误可与 QP 关联,则发送队列应转换为错误状态,且所有未完成的 WQE 都以“已完成 - 错误刷新(Completed - Flushed in Error)”状态完成。
o9-155:如果 CA 请求者实现可靠数据报服务,并且如果请求者 C 类错误可与 EE 上下文关联,则其发送端应转换为错误状态,对于 HCA,发布的错误为“关联异步错误(Affiliated Asynchronous Error)”。有关 HCA 错误报告的更多详细信息,请参阅第 692 页上的 11.6.3.2 关联异步错误。如果请求者 C 类错误无法与特定资源关联,则可能无法详细报告错误,甚至根本无法报告错误。在这种情况下,请参阅第 695 页上的 11.6.3.4 无关异步错误,了解 HCA 错误处理
D 类错误仅发生在可靠数据报服务中。
o9-156:如果 CA 请求者实施可靠数据报服务,则其行为应如下。对于请求者 D 类错误,传输应将请求者的 EE 上下文转换为错误状态,终止当前消息传输,向当前安排的发送队列发出错误信号,并取消当前安排的发送队列的排队。在保持错误状态的同时,EE 上下文继续将任何其他发送队列请求服务转换为错误状态。每个发送队列 (QP) 的行为都像 B 类错误一样;它将其当前 WQE 标记为错误完成,将 QP 转换为错误状态,并刷新所有后续 WQE, 参考如下处理逻辑:
当请求者收到带有 PSN 的确认消息,而该消息的 PSN 与其预期 PSN 不匹配时,就会发生 E 类错误。这些错误只发生在可靠的服务类别中。这些错误不会报告给上层。带有意外 PSN 的确认消息被认为是“幽灵(ghost)”确认消息或重复确认消息。幽灵确认消息是已在结构中存在足够长时间的确认消息,以至于在连接被破坏和随后建立新连接后仍能幸存下来。当请求者认为其原始请求消息已在结构中丢失,并重新发送请求消息时,就会发生重复确认消息。如果两条请求消息最终都到达响应者,响应者可能会为每条请求消息生成一条确认消息。
C9-217:对于使用可靠连接服务的 HCA 请求者,在响应请求者 E 类错误时,请求者应丢弃确认消息。但是,此规则有一个例外。对于可靠连接服务,响应者可以使用重复确认消息将端到端流量控制信用传送给请求者(“未经请求的确认”)。因此,如果确认消息的 PSN 比请求者的预期 PSN 小一,则请求者必须恢复端到端信用并丢弃消息的剩余部分。此行为在第 371 页的 9.7.7.2 节“端到端(消息级别)流量控制”中详细说明。
o9-157:如果 TCA 请求者实施可靠连接服务,或者 CA 请求者实施可靠数据报服务或 XRC 服务,则在响应请求者 E 类错误时,请求者应丢弃确认消息。但是,此规则有一个例外。对于可靠连接服务,响应者可以使用重复确认消息将端到端流量控制信用传送给请求者(“未经请求的确认” unsolicited acknowledge)。因此,如果确认消息的 PSN 比请求者的预期 PSN 小 1,则请求者必须恢复端到端信用并丢弃消息的其余部分。此行为在第 371 页的 9.7.7.2 端到端(消息级)流控制中详细说明。应该注意的是,即使确认是真正的幽灵,信用错误,信用机制最终也会恢复,不会向上层报告任何错误
C9-218:当 CQ 无法访问或已满,并尝试完成 WQE 时,将发生请求者 F 类错误。受影响的 QP 应移至错误状态,并生成相关异步错误,如第 691 页 11.6.3.1 关联异步事件中所述。当前 WQE 和任何后续 WQE 都处于未知状态
表 61 列出了响应器必须检测到的错误,以及每个错误的故障行为类。故障行为类指定响应器是否返回 NAK 代码、是否将错误报告给本地客户端以及接收队列的后续行为。综合征列列出了返回给请求者的 NAK 代码。为方便起见,故障行为类的摘要显示在表 62 响应器故障类行为摘要(第 439 页)中。可靠服务的错误检测在第 304 页的 9.7 节可靠服务中描述,不可靠服务的错误检测在第 402 页的 9.8 节不可靠服务中指定。
C9-219:此合规声明已过时,已被 C9-219.1.1:取代。
C9-219.1.1:对于已实施的传输服务子集,响应者应符合表 61 中规定的错误行为。此外,响应者的接收队列应按照表 62 和以下每个子部分中所示的每个故障行为类别的规定行事
a. Q_Key 违规需要增加计数器和潜在陷阱(potential trap),如第 470 页的 10.2.5 Q_Keys 中所述
b. 我们故意“重载”此 RD 特定 NAK 综合征,因为它符合所讨论错误的本质。由于这是 XRC QP,因此不会造成混淆。
c. 不支持生成 RNR-NAK 的 TCA 不应简单地将响应延迟超过通常的响应时间。
d. 在不可靠连接模式下,立即执行的 RDMA 写入可能会执行数据包的 RDMA 写入部分,然后丢弃“立即(immediate)”部分,因为没有可用的 WQE。
d. 对于某些 RD 错误情况,响应者最好能够选择错误地完成接收 WQE,而不是将 WQE 留在接收队列中。对于这些情况,响应者可以使用 F 类响应者行为而不是 B 类错误行为。F 类与 B 类的主要区别在于它允许错误地完成接收 WQE
表62: 响应侧故障13大类型汇总
a. 仅当打开发送和 RDMA WRITE 并使用即时数据时,WQE 才会完成。
b. 当前接收 WQE 的处置取决于接收队列是否与共享接收队列相关联。请参阅第 444 页上的第 9.9.3.1.6 节“响应器类 E 故障行为”以了解完整详细信息和相关合规性声明。
c. 后续接收 WQE 的处置取决于接收队列是否与共享接收队列相关联。请参阅第 444 页上的第 9.9.3.1.6 节“响应器类 E 故障行为”以了解完整详细信息和相关合规性声明。
d. 此错误类导致 EEC 进入错误状态。
e. 接收 WQE 永远不会发布到 XRC TGT QP
响应方一共有 13 类故障行为。故障行为根据是否向响应方的客户端报告错误、是否通过 NAK 代码向请求方报告错误以及是否从接收队列中使用 WQE 进行分组
A 类错误可追溯到格式错误或无效的 WQE,或与接收方 QP 相关的其他错误。这些错误不是由发送方引起的。
C9-220:对于响应方 A 类错误,应将错误报告给响应方的客户端,QP 将进入错误状态,并且对于可靠服务,将生成“NAK-远程操作错误”。对于可靠数据报服务,EEC 将继续运行。如果响应方是 HCA,则这些错误将作为“完成错误”或“关联异步错误”报告给动词层。有关完成错误的讨论,请参阅第 563 页上的 10.10.2.2 完成错误,有关异步错误的讨论,请参阅第 564 页上的 10.10.2.3 异步错误。如果响应方检测到 A 类错误,其行为如下:
o9-157.2.1:除了上面针对 A 类错误描述的错误行为之外,如果与共享接收队列关联的 QP 检测到 A 类错误,则最初检测到错误的 WQE 以及发送和接收队列上的所有后续 WQE(包括同一接收队列随后从关联的共享接收队列中获取的 WQE)都应标记为错误。检测到错误的 QP 应转换为错误状态。共享接收队列的状态不得改变,共享同一 SRQ 的任何其他接收队列的状态也不得改变。
o9-157.2.2:如果共享接收队列检测到 A 类错误,则应向响应方的客户端报告该错误,并将 QP 置于错误状态。如果响应者是 HCA,则这些错误将作为“完成错误”或“关联异步错误”报告给动词层。请注意,如果错误是由共享接收队列检测到的(而不是由接收队列检测到的),则可能不会返回“NAK-远程操作错误”,因为 SRQ 不需要生成确认。这与接收队列检测到错误的情况略有不同,在这种情况下,接收队列需要返回“NAK-远程操作错误”。
o9-157.2.3:如果接收队列尝试从处于错误状态的共享接收队列中获取 WQE,则 QP 应转换为错误状态。如果响应者是 HCA,则此错误将作为“关联异步错误”报告给动词层
B 类错误会报告给请求者,但不会报告给响应者的本地客户端。
C9-221:对于使用可靠连接服务的 HCA 请求者,以及对于响应者 B 类响应者端错误,传输应生成 NAK 代码,但不得使用接收队列中的 WQE 或将接收队列转换为错误状态。
o9-158:如果 TCA 响应者实现可靠连接服务,或者 CA 响应者实现可靠数据报服务或 XRC 服务,则其行为如下。对于响应者 B 类响应者端错误,传输应生成 NAK 代码,但不得使用接收队列中的 WQE 或将接收队列转换为错误状态。请注意,此故障行为类仅限于可靠服务。如果响应者检测到 B 类错误,则其行为如下:
C9-222:此合规性声明已过时,已被 C9-222.1.1 取代:。
C9-222.1.1:对于使用可靠连接服务的 HCA 响应者,对于 C 类响应者端错误,应通过生成适当的 NAK 代码将错误报告给请求者,如第 436 页表 61 响应者错误行为摘要中所述。如果错误与特定 QP 相关但与该接收队列上的特定 WQE 无关(例如,在执行没有即时数据的 RDMA 写入请求时发生错误),则应将错误作为关联异步错误报告给响应者的客户端。有关详细信息,请参阅第 564 页第 10.10.2.3 节异步错误。如果错误与给定接收队列上的特定 WQE 相关,则应将 QP 置于错误状态,并将错误作为完成错误报告给响应者的客户端。请参阅第 563 页上的第 10.10.2.2 节“完成错误”。
o9-159:此合规性声明已过时,已被 o9-159.1.1 取代:。
o9-159.1.1:如果 TCA 响应器实施可靠连接服务,则对于 C 类响应器端错误,应将错误报告给响应器的客户端,并将 QP 置于错误状态。还应通过生成适当的 NAK 代码向请求者报告 C 类错误,如第 436 页上的表 61“响应器错误行为摘要”中所述。接收队列的行为如下:
有关 HCA 错误报告的更多详细信息,请参阅第 563 页上的第 10.10.2.2 节“完成错误”
C9-223:此合规性声明已过时,并由 C9-223.1.1 取代。
C9-223.1.1:导致响应者 D 类错误的入站请求数据包应导致传输按照 9.9.3.1.4 中的规定做出响应:响应者 D 类故障行为。在这种情况下,传输应:
• 默默丢弃数据包(详见 9.6:数据包传输报头验证)
• 不向请求者生成 ACK 或 NAK 代码
• 不通知响应者的客户端
导致 D1 类错误的入站请求数据包仅在“不可靠连接”模式下发生。
C9-224:对于使用不可靠连接服务的 HCA 响应者,导致响应者 D1 类错误的入站请求数据包应导致传输按照 9.9.3.1.5:响应者 D1 类故障行为中规定的方式做出响应。在这种情况下,传输应:
• 默默丢弃数据包
• 不通知响应者的客户端
• 终止当前消息而不使用当前接收 WQE(如果有)
• 等待新消息的第一个数据包(可能大于预期的 PSN。)
如果当前数据包(导致 D1 类错误)的 BTH 操作码为“first”或“only”;则应将其视为新消息的第一个数据包。应重置当前 WQE(如果有)以接受下一个传入的发送或 RDMA WRITE 和即时消息。“当前消息”是指自最近收到的“first”或“only”OpCode 以来收到的所有数据包,不包括当前数据包(导致 D1 类错误)。 “新消息”由带有“first”或“only”BTH 操作码的数据包表示。
o9-160:如果 TCA 响应器实现不可靠连接服务,则它应符合前面合规声明中描述的 D1 类 HCA 响应器行为
此故障类别主要用于特定请求数据包的故障不应影响接收队列继续接收消息的能力的服务。
o9-161:如果 CA 实施可靠数据报服务,则响应者 E 类错误应导致响应者执行以下操作:
合规声明 o9-161.2.1:定义更严格的要求,仅适用于与共享接收队列关联的接收队列。
o9-161.2.1:如果 QP 实施不可靠数据报服务并与共享接收队列相关联,则响应者 E 类错误将导致响应者执行以下操作:
o9-161.2.2:如果 QP 实施不可靠连接服务并与共享接收队列相关联,则响应者 E 类错误将导致响应者执行以下操作:
F 类错误行为仅适用于 RD 服务,用于向请求者返回 NAK 代码并完成错误 WQE。在多种情况下,实现可以选择 B 类错误行为或 F 类错误行为。对于这些情况,B 类和 F 类之间唯一的实质性差异在于接收 WQE 的处置,接收 WQE 要么错误完成,要么留在接收队列中以供重复使用。对于许多实现,完成错误接收 WQE 要简单得多。o9-162:此合规性声明已过时,已被 o9-162.1.1 取代:
o9-162.1.1:如果 CA 实现可靠数据报服务,则应向请求者和(当涉及接收 WQE 时)响应者的客户端报告响应者 F 类错误。传输应向请求者返回第 436 页表 61 中定义的相应 NAK 代码,并错误地完成当前 WQE(如果有)。接收队列应继续运行,而不会转换为错误状态。对于 HCA,报告的错误是“完成 - 处理错误”。EEC 和目标 QP 均保持运行。接收队列的行为如下:
当 CQ 无法访问或已满,并且尝试完成 WQE 时,会发生 G 类错误。C9-225:当 CQ 无法访问或已满,并且尝试完成 WQE 时,会发生响应者 G 类错误。受影响的 QP 应移至错误状态,并生成附属异步错误,如第 692 页 11.6.3.2 附属异步错误中所述。当前 WQE 和任何后续 WQE 都处于未知状态。
H 类错误可追溯到与接收方 EEC 相关的本地错误。这些错误不是由发送方引起的。对于响应者 H 类错误,应将错误报告给响应者的客户端,并将 EEC 置于错误状态。当前活动的 WQE 应以错误方式完成。如果响应者是 HCA,这些错误将作为完成错误(请参见第 563 页上的第 10.10.2.2 节完成错误)或附属异步错误(请参见第 564 页上的第 10.10.2.3 节异步错误)报告给verbs层。
此类本地检测到的错误仅发生在 RC QP 中。J 类错误会报告给响应者端客户端,但不会通过 NAK 代码报告给请求者。当响应者收到带有 Invalidate 的 SEND 请求(最后带有 Invalidate 的 SEND 或仅带有 Invalidate 的 SEND)时,如果 IETH 中包含无效的 R_Key,则会发生响应者 J 类错误。就错误优先级而言,在报告 R_Key 违规之前,会先报告与验证数据包头和执行搭载了 In 验证的 SEND 操作相关的所有其他错误。
o9-162.2.1:以下陈述构成了检测和报告与带有 Invalidate 请求的 SEND 相关的 R_Key 违规的要求:
对于 HCA XRC TGT QP,对于 K 类响应器端错误,应通过生成适当的 NAK 代码将错误报告给请求者,如第 436 页的表 61 响应器错误行为摘要中所述。应将错误作为附属异步错误报告给响应者的客户端。有关详细信息,请参见第 690 页的第 11.6.3 节,并且应将 XRC TGT QP 置于错误状态。此外,如果错误与给定 XRC SRQ 上的特定 WQE 相关,则会在 XRC SRQ CQ 中生成完成错误。将 XRC TGT QP 置于错误状态的结果是,相同或不同 XRC SRQ 中的其他接收 WQE 可能会出现错误完成。
当 CQ 无法访问或已满,并且尝试完成 XRC SRQ 上的 WQE 时,会发生 L 类错误。接收数据包的 XRC TGT QP 应移至错误状态,并生成相关异步错误,如第 690 页第 11.6.3 节所述。当前 WQE 以及相关 XRC SRQ 上的任何后续 WQE 都处于未知状态,并且 XRC SRQ 移至错误状态。将 XRC TGT QP 置于错误状态的结果是,不同 XRC SRQ 上的其他接收 WQE 可能会出现错误。
此类本地检测到的错误仅发生在 XRC TGT QP 中。M 类错误会报告给响应者端客户端,但不会通过 NAK 代码报告给请求者。当响应方收到带有 Invalidate 的 SEND 请求(最后带有 Invalidate 的 SEND 或仅带有 Invalidate 的 SEND)时,如果 IETH 中包含无效的 R_Key,则会发生响应方 M 类错误。就错误优先级而言,与 vali 相关的所有其他错误在报告 R_Key 违规之前,必须先更新数据包头并执行搭载了 Invalidate 的 SEND 操作。以下陈述构成了检测和报告与带有 Invalidate 的 SEND 请求相关的 R_Key 违规的要求:
static void irdma_process_aeq(struct irdma_pci_f *rf)
{
struct irdma_sc_dev *dev = &rf->sc_dev;
struct irdma_aeq *aeq = &rf->aeq;
struct irdma_sc_aeq *sc_aeq = &aeq->sc_aeq;
struct irdma_aeqe_info aeinfo;
struct irdma_aeqe_info *info = &aeinfo;
int ret;
struct irdma_qp *iwqp = NULL;
struct irdma_cq *iwcq = NULL;
struct irdma_sc_qp *qp = NULL;
struct irdma_qp_host_ctx_info *ctx_info = NULL;
struct irdma_device *iwdev = rf->iwdev;
unsigned long flags;
u32 aeqcnt = 0;
if (!sc_aeq->size)
return;
do {
memset(info, 0, sizeof(*info));
ret = irdma_sc_get_next_aeqe(sc_aeq, info); // 获取下一个AEQE条目
if (ret)
break;
aeqcnt++;
ibdev_dbg(&iwdev->ibdev,
"AEQ: ae_id = 0x%x bool qp=%d qp_id = %d tcp_state=%d iwarp_state=%d ae_src=%d\n",
info->ae_id, info->qp, info->qp_cq_id, info->tcp_state,
info->iwarp_state, info->ae_src);
if (info->qp) { // 如果异步事件与QP相关
spin_lock_irqsave(&rf->qptable_lock, flags);
iwqp = rf->qp_table[info->qp_cq_id];
if (!iwqp) {
spin_unlock_irqrestore(&rf->qptable_lock,
flags);
if (info->ae_id == IRDMA_AE_QP_SUSPEND_COMPLETE) {
atomic_dec(&iwdev->vsi.qp_suspend_reqs);
wake_up(&iwdev->suspend_wq);
continue;
}
ibdev_dbg(&iwdev->ibdev, "AEQ: qp_id %d is already freed\n",
info->qp_cq_id);
continue;
}
irdma_qp_add_ref(&iwqp->ibqp);
spin_unlock_irqrestore(&rf->qptable_lock, flags);
qp = &iwqp->sc_qp;
spin_lock_irqsave(&iwqp->lock, flags);
iwqp->hw_tcp_state = info->tcp_state; // 设置QP的TCP状态
iwqp->hw_iwarp_state = info->iwarp_state;
if (info->ae_id != IRDMA_AE_QP_SUSPEND_COMPLETE)
iwqp->last_aeq = info->ae_id;
spin_unlock_irqrestore(&iwqp->lock, flags);
ctx_info = &iwqp->ctx_info;
} else {
if (info->ae_id != IRDMA_AE_CQ_OPERATION_ERROR)
continue;
}
switch (info->ae_id) {
struct irdma_cm_node *cm_node;
case IRDMA_AE_LLP_CONNECTION_ESTABLISHED: // CM建连
cm_node = iwqp->cm_node;
if (cm_node->accept_pend) {
atomic_dec(&cm_node->listener->pend_accepts_cnt);
cm_node->accept_pend = 0;
}
iwqp->rts_ae_rcvd = 1;
wake_up_interruptible(&iwqp->waitq);
break;
case IRDMA_AE_LLP_FIN_RECEIVED:
case IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE:
if (qp->term_flags)
break;
if (atomic_inc_return(&iwqp->close_timer_started) == 1) {
iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSE_WAIT;
if (iwqp->hw_tcp_state == IRDMA_TCP_STATE_CLOSE_WAIT &&
iwqp->ibqp_state == IB_QPS_RTS) {
irdma_next_iw_state(iwqp,
IRDMA_QP_STATE_CLOSING,
0, 0, 0);
irdma_cm_disconn(iwqp); // CM异常断连
}
irdma_schedule_cm_timer(iwqp->cm_node,
(struct irdma_puda_buf *)iwqp,
IRDMA_TIMER_TYPE_CLOSE,
1, 0);
}
break;
case IRDMA_AE_LLP_CLOSE_COMPLETE:
if (qp->term_flags)
irdma_terminate_done(qp, 0);
else
irdma_cm_disconn(iwqp);
break;
case IRDMA_AE_BAD_CLOSE:
case IRDMA_AE_RESET_SENT:
irdma_next_iw_state(iwqp, IRDMA_QP_STATE_ERROR, 1, 0,
0);
irdma_cm_disconn(iwqp);
break;
case IRDMA_AE_LLP_CONNECTION_RESET:
if (atomic_read(&iwqp->close_timer_started))
break;
irdma_cm_disconn(iwqp);
break;
case IRDMA_AE_QP_SUSPEND_COMPLETE:
if (iwqp->iwdev->vsi.tc_change_pending) {
if (!atomic_dec_return(&qp->vsi->qp_suspend_reqs))
wake_up(&iwqp->iwdev->suspend_wq);
}
if (iwqp->suspend_pending) {
iwqp->suspend_pending = false;
wake_up(&iwqp->iwdev->suspend_wq);
}
break;
case IRDMA_AE_TERMINATE_SENT:
irdma_terminate_send_fin(qp);
break;
case IRDMA_AE_LLP_TERMINATE_RECEIVED:
irdma_terminate_received(qp, info);
break;
case IRDMA_AE_CQ_OPERATION_ERROR:
ibdev_err(&iwdev->ibdev,
"Processing an iWARP related AE for CQ misc = 0x%04X\n",
info->ae_id);
spin_lock_irqsave(&rf->cqtable_lock, flags);
iwcq = rf->cq_table[info->qp_cq_id];
if (!iwcq) {
spin_unlock_irqrestore(&rf->cqtable_lock,
flags);
ibdev_dbg(to_ibdev(dev),
"cq_id %d is already freed\n", info->qp_cq_id);
continue;
}
irdma_cq_add_ref(&iwcq->ibcq);
spin_unlock_irqrestore(&rf->cqtable_lock, flags);
if (iwcq->ibcq.event_handler) {
struct ib_event ibevent;
ibevent.device = iwcq->ibcq.device;
ibevent.event = IB_EVENT_CQ_ERR;
ibevent.element.cq = &iwcq->ibcq;
iwcq->ibcq.event_handler(&ibevent,
iwcq->ibcq.cq_context);
}
irdma_cq_rem_ref(&iwcq->ibcq);
break;
case IRDMA_AE_RESET_NOT_SENT:
case IRDMA_AE_LLP_DOUBT_REACHABILITY:
case IRDMA_AE_RESOURCE_EXHAUSTION:
break;
case IRDMA_AE_PRIV_OPERATION_DENIED:
case IRDMA_AE_STAG_ZERO_INVALID:
case IRDMA_AE_IB_RREQ_AND_Q1_FULL:
case IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION:
case IRDMA_AE_DDP_UBE_INVALID_MO:
case IRDMA_AE_DDP_UBE_INVALID_QN:
case IRDMA_AE_DDP_NO_L_BIT:
case IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
case IRDMA_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
case IRDMA_AE_ROE_INVALID_RDMA_READ_REQUEST:
case IRDMA_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
case IRDMA_AE_INVALID_ARP_ENTRY:
case IRDMA_AE_INVALID_TCP_OPTION_RCVD:
case IRDMA_AE_STALE_ARP_ENTRY:
case IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR:
case IRDMA_AE_LLP_SEGMENT_TOO_SMALL:
case IRDMA_AE_LLP_SYN_RECEIVED:
case IRDMA_AE_LLP_TOO_MANY_RETRIES:
case IRDMA_AE_LCE_QP_CATASTROPHIC:
case IRDMA_AE_LCE_FUNCTION_CATASTROPHIC:
case IRDMA_AE_LLP_TOO_MANY_RNRS:
case IRDMA_AE_LCE_CQ_CATASTROPHIC:
case IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG:
default:
ibdev_err(&iwdev->ibdev, "abnormal ae_id = 0x%x bool qp=%d qp_id = %d, ae_src=%d\n",
info->ae_id, info->qp, info->qp_cq_id, info->ae_src);
if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
ctx_info->roce_info->err_rq_idx_valid = info->rq;
if (info->rq) {
ctx_info->roce_info->err_rq_idx = info->wqe_idx;
irdma_sc_qp_setctx_roce(&iwqp->sc_qp, iwqp->host_ctx.va,
ctx_info);
}
irdma_set_flush_fields(qp, info); // 设置下刷QP字段, 断开CM连接
irdma_cm_disconn(iwqp);
break;
}
ctx_info->iwarp_info->err_rq_idx_valid = info->rq;
if (info->rq) {
ctx_info->iwarp_info->err_rq_idx = info->wqe_idx;
ctx_info->tcp_info_valid = false;
ctx_info->iwarp_info_valid = true;
irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va,
ctx_info);
}
if (iwqp->hw_iwarp_state != IRDMA_QP_STATE_RTS &&
iwqp->hw_iwarp_state != IRDMA_QP_STATE_TERMINATE) {
irdma_next_iw_state(iwqp, IRDMA_QP_STATE_ERROR, 1, 0, 0);
irdma_cm_disconn(iwqp);
} else {
irdma_terminate_connection(qp, info);
}
break;
}
if (info->qp)
irdma_qp_rem_ref(&iwqp->ibqp);
} while (1);
if (aeqcnt)
irdma_sc_repost_aeq_entries(dev, aeqcnt); // 通知硬件
}
int irdma_sc_get_next_aeqe(struct irdma_sc_aeq *aeq,
struct irdma_aeqe_info *info)
{
u64 temp, compl_ctx;
__le64 *aeqe;
u8 ae_src;
u8 polarity;
aeqe = IRDMA_GET_CURRENT_AEQ_ELEM(aeq); // 获取当前AEQE
get_64bit_val(aeqe, 8, &temp);
polarity = (u8)FIELD_GET(IRDMA_AEQE_VALID, temp);
if (aeq->polarity != polarity)
return -ENOENT;
/* Ensure AEQE contents are read after valid bit is checked */
dma_rmb();
get_64bit_val(aeqe, 0, &compl_ctx);
print_hex_dump_debug("WQE: AEQ_ENTRY WQE", DUMP_PREFIX_OFFSET, 16, 8,
aeqe, 16, false);
ae_src = (u8)FIELD_GET(IRDMA_AEQE_AESRC, temp);
info->wqe_idx = (u16)FIELD_GET(IRDMA_AEQE_WQDESCIDX, temp);
info->qp_cq_id = (u32)FIELD_GET(IRDMA_AEQE_QPCQID_LOW, temp) |
((u32)FIELD_GET(IRDMA_AEQE_QPCQID_HI, temp) << 18);
info->ae_id = (u16)FIELD_GET(IRDMA_AEQE_AECODE, temp);
info->tcp_state = (u8)FIELD_GET(IRDMA_AEQE_TCPSTATE, temp);
info->iwarp_state = (u8)FIELD_GET(IRDMA_AEQE_IWSTATE, temp);
info->q2_data_written = (u8)FIELD_GET(IRDMA_AEQE_Q2DATA, temp);
info->aeqe_overflow = (bool)FIELD_GET(IRDMA_AEQE_OVERFLOW, temp);
info->ae_src = ae_src;
switch (info->ae_id) {
case IRDMA_AE_PRIV_OPERATION_DENIED:
case IRDMA_AE_AMP_INVALIDATE_TYPE1_MW:
case IRDMA_AE_AMP_MWBIND_ZERO_BASED_TYPE1_MW:
case IRDMA_AE_AMP_FASTREG_INVALID_PBL_HPS_CFG:
case IRDMA_AE_AMP_FASTREG_PBLE_MISMATCH:
case IRDMA_AE_UDA_XMIT_DGRAM_TOO_LONG:
case IRDMA_AE_UDA_XMIT_BAD_PD:
case IRDMA_AE_UDA_XMIT_DGRAM_TOO_SHORT:
case IRDMA_AE_BAD_CLOSE:
case IRDMA_AE_RDMA_READ_WHILE_ORD_ZERO:
case IRDMA_AE_STAG_ZERO_INVALID:
case IRDMA_AE_IB_RREQ_AND_Q1_FULL:
case IRDMA_AE_IB_INVALID_REQUEST:
case IRDMA_AE_WQE_UNEXPECTED_OPCODE:
case IRDMA_AE_IB_REMOTE_ACCESS_ERROR:
case IRDMA_AE_IB_REMOTE_OP_ERROR:
case IRDMA_AE_DDP_UBE_INVALID_DDP_VERSION:
case IRDMA_AE_DDP_UBE_INVALID_MO:
case IRDMA_AE_DDP_UBE_INVALID_QN:
case IRDMA_AE_DDP_NO_L_BIT:
case IRDMA_AE_RDMAP_ROE_INVALID_RDMAP_VERSION:
case IRDMA_AE_RDMAP_ROE_UNEXPECTED_OPCODE:
case IRDMA_AE_ROE_INVALID_RDMA_READ_REQUEST:
case IRDMA_AE_ROE_INVALID_RDMA_WRITE_OR_READ_RESP:
case IRDMA_AE_ROCE_RSP_LENGTH_ERROR:
case IRDMA_AE_INVALID_ARP_ENTRY:
case IRDMA_AE_INVALID_TCP_OPTION_RCVD:
case IRDMA_AE_STALE_ARP_ENTRY:
case IRDMA_AE_INVALID_AH_ENTRY:
case IRDMA_AE_LLP_RECEIVED_MPA_CRC_ERROR:
case IRDMA_AE_LLP_SEGMENT_TOO_SMALL:
case IRDMA_AE_LLP_TOO_MANY_RETRIES:
case IRDMA_AE_LLP_DOUBT_REACHABILITY:
case IRDMA_AE_LLP_CONNECTION_ESTABLISHED:
case IRDMA_AE_RESET_SENT:
case IRDMA_AE_TERMINATE_SENT:
case IRDMA_AE_RESET_NOT_SENT:
case IRDMA_AE_LCE_QP_CATASTROPHIC:
case IRDMA_AE_QP_SUSPEND_COMPLETE:
case IRDMA_AE_UDA_L4LEN_INVALID:
info->qp = true;
info->compl_ctx = compl_ctx;
break;
case IRDMA_AE_LCE_CQ_CATASTROPHIC:
info->cq = true;
info->compl_ctx = compl_ctx << 1;
ae_src = IRDMA_AE_SOURCE_RSVD;
break;
case IRDMA_AE_ROCE_EMPTY_MCG:
case IRDMA_AE_ROCE_BAD_MC_IP_ADDR:
case IRDMA_AE_ROCE_BAD_MC_QPID:
case IRDMA_AE_MCG_QP_PROTOCOL_MISMATCH:
fallthrough;
case IRDMA_AE_LLP_CONNECTION_RESET:
case IRDMA_AE_LLP_SYN_RECEIVED:
case IRDMA_AE_LLP_FIN_RECEIVED:
case IRDMA_AE_LLP_CLOSE_COMPLETE:
case IRDMA_AE_LLP_TERMINATE_RECEIVED:
case IRDMA_AE_RDMAP_ROE_BAD_LLP_CLOSE:
ae_src = IRDMA_AE_SOURCE_RSVD;
info->qp = true;
info->compl_ctx = compl_ctx;
break;
default:
break;
}
switch (ae_src) {
case IRDMA_AE_SOURCE_RQ:
case IRDMA_AE_SOURCE_RQ_0011:
info->qp = true;
info->rq = true;
info->compl_ctx = compl_ctx;
break;
case IRDMA_AE_SOURCE_CQ:
case IRDMA_AE_SOURCE_CQ_0110:
case IRDMA_AE_SOURCE_CQ_1010:
case IRDMA_AE_SOURCE_CQ_1110:
info->cq = true;
info->compl_ctx = compl_ctx << 1;
break;
case IRDMA_AE_SOURCE_SQ:
case IRDMA_AE_SOURCE_SQ_0111:
info->qp = true;
info->sq = true;
info->compl_ctx = compl_ctx;
break;
case IRDMA_AE_SOURCE_IN_RR_WR:
case IRDMA_AE_SOURCE_IN_RR_WR_1011:
info->qp = true;
info->compl_ctx = compl_ctx;
info->in_rdrsp_wr = true;
break;
case IRDMA_AE_SOURCE_OUT_RR:
case IRDMA_AE_SOURCE_OUT_RR_1111:
info->qp = true;
info->compl_ctx = compl_ctx;
info->out_rdrsp = true;
break;
case IRDMA_AE_SOURCE_RSVD:
default:
break;
}
IRDMA_RING_MOVE_TAIL(aeq->aeq_ring);
if (!IRDMA_RING_CURRENT_TAIL(aeq->aeq_ring))
aeq->polarity ^= 1;
return 0;
}
IB_SPEC(1.4)第9章
Linux irdma驱动
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。