[PATCH v1 1/1] nvme-tcp: fix wrong status on deferred digest error

Xixin Liu <[email protected]>
Newsgroups org.infradead.lists.linux-nvme,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
A C2HData digest error stores a host status code in req status. Without
DATA_SUCCESS the request is completed later from the rsp path, which
passed that value straight into complete and could report the wrong
status code.

Keep req status as a host status code. On the rsp path, shift left when
a host error was already stored, otherwise use the completion status
field.

Fixes: 1ba2e507f55c ("nvme-tcp: Do not reset transport on data digest errors")
Signed-off-by: Xixin Liu <[email protected]>
---
 drivers/nvme/host/tcp.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

--- a/drivers/nvme/host/tcp.c	2026-08-26 09:24:50.988099281 +0800
+++ b/drivers/nvme/host/tcp.c	2026-08-26 09:25:12.474510519 +0800
@@ -73,7 +73,7 @@
 	u32			h2cdata_left;
 	u32			h2cdata_offset;
 	u16			ttag;
-	__le16			status;
+	u16			status;
 	struct list_head	entry;
 	struct llist_node	lentry;
 	__le32			ddgst;
@@ -617,6 +617,7 @@
 {
 	struct nvme_tcp_request *req;
 	struct request *rq;
+	__le16 status;
 
 	rq = nvme_find_rq(nvme_tcp_tagset(queue), cqe->command_id);
 	if (!rq) {
@@ -628,10 +629,12 @@
 	}
 
 	req = blk_mq_rq_to_pdu(rq);
-	if (req->status == cpu_to_le16(NVME_SC_SUCCESS))
-		req->status = cqe->status;
+	if (req->status != NVME_SC_SUCCESS)
+		status = cpu_to_le16(req->status << 1);
+	else
+		status = cqe->status;
 
-	if (!nvme_try_complete_req(rq, req->status, cqe->result))
+	if (!nvme_try_complete_req(rq, status, cqe->result))
 		nvme_complete_rq(rq);
 	queue->nr_cqe++;
 
@@ -961,8 +964,7 @@
 			queue->ddgst_remaining = NVME_TCP_DIGEST_LENGTH;
 		} else {
 			if (pdu->hdr.flags & NVME_TCP_F_DATA_SUCCESS) {
-				nvme_tcp_end_request(rq,
-						le16_to_cpu(req->status));
+				nvme_tcp_end_request(rq, req->status);
 				queue->nr_cqe++;
 			}
 			nvme_tcp_init_recv_ctx(queue);
@@ -996,7 +998,7 @@
 					pdu->command_id);
 		struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
 
-		req->status = cpu_to_le16(NVME_SC_DATA_XFER_ERROR);
+		req->status = NVME_SC_DATA_XFER_ERROR;
 
 		dev_err(queue->ctrl->ctrl.device,
 			"data digest error: recv %#x expected %#x\n",
@@ -1009,7 +1011,7 @@
 					pdu->command_id);
 		struct nvme_tcp_request *req = blk_mq_rq_to_pdu(rq);
 
-		nvme_tcp_end_request(rq, le16_to_cpu(req->status));
+		nvme_tcp_end_request(rq, req->status);
 		queue->nr_cqe++;
 	}
 
@@ -2733,7 +2735,7 @@
 		return ret;
 
 	req->state = NVME_TCP_SEND_CMD_PDU;
-	req->status = cpu_to_le16(NVME_SC_SUCCESS);
+	req->status = NVME_SC_SUCCESS;
 	req->offset = 0;
 	req->data_sent = 0;
 	req->pdu_len = 0;
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.