diff --git a/lib/nvmf/tcp.c b/lib/nvmf/tcp.c index 93687a161..cd45ac5e6 100644 --- a/lib/nvmf/tcp.c +++ b/lib/nvmf/tcp.c @@ -2177,6 +2177,23 @@ spdk_nvmf_tcp_req_parse_sgl(struct spdk_nvmf_tcp_transport *ttransport, return -1; } +static int +nvmf_tcp_pdu_verify_dif(struct nvme_tcp_pdu *pdu, + const struct spdk_dif_ctx *dif_ctx) +{ + struct spdk_dif_error err_blk = {}; + int rc; + + rc = spdk_dif_verify_stream(pdu->data_iov, pdu->data_iovcnt, + 0, pdu->data_len, pdu->dif_ctx, &err_blk); + if (rc != 0) { + SPDK_ERRLOG("DIF error detected. type=%d, offset=%" PRIu32 "\n", + err_blk.err_type, err_blk.err_offset); + } + + return rc; +} + static void spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair, struct spdk_nvmf_tcp_req *tcp_req) @@ -2184,6 +2201,7 @@ spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair, struct nvme_tcp_pdu *rsp_pdu; struct spdk_nvme_tcp_c2h_data_hdr *c2h_data; uint32_t plen, pdo, alignment; + int rc; SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "enter\n"); @@ -2228,6 +2246,21 @@ spdk_nvmf_tcp_send_c2h_data(struct spdk_nvmf_tcp_qpair *tqpair, nvme_tcp_pdu_set_data_buf(rsp_pdu, tcp_req->req.iov, tcp_req->req.iovcnt, c2h_data->datao, c2h_data->datal); + if (spdk_unlikely(rsp_pdu->dif_ctx != NULL)) { + rc = nvmf_tcp_pdu_verify_dif(rsp_pdu, rsp_pdu->dif_ctx); + if (rc != 0) { + /* Data digest error detected by the NVMe/TCP target is treated as non-fatal + * transport error because the cause will be outside the NVMe/TCP target. + * + * On the other hand, treat DIF check error as fatal transport error here + * here because the error is caused by the target itself. Fatal NVMe/TCP + * transport error is handled by terminating the connection. + */ + tqpair->state = NVME_TCP_QPAIR_STATE_EXITING; + return; + } + } + tcp_req->c2h_data_offset += c2h_data->datal; if (tcp_req->c2h_data_offset == tcp_req->req.length) { SPDK_DEBUGLOG(SPDK_LOG_NVMF_TCP, "Last pdu for tcp_req=%p on tqpair=%p\n", tcp_req, tqpair);