git: d3e5082ce4dc - main - ufshci: tell the controller how long the EHS is

From: Jaeyoon Choi <jaeyoon_at_FreeBSD.org>
Date: Tue, 15 Sep 2026 01:47:46 UTC
The branch main has been updated by jaeyoon:

URL: https://cgit.FreeBSD.org/src/commit/?id=d3e5082ce4dcb154cbf50cba05d8f1dbbd55a5fc

commit d3e5082ce4dcb154cbf50cba05d8f1dbbd55a5fc
Author:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2026-09-15 01:37:30 +0000
Commit:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2026-09-15 01:44:32 +0000

    ufshci: tell the controller how long the EHS is
    
    The transfer request descriptor has a field for the total Extra Header
    Segment length. The driver left it at zero. A request that carried an
    EHS went out as the bare command UPIU, and the device answered a request
    it had only seen part of.
    
    Fill the field from the request UPIU header, which already carries the
    same length. Every other path sets it to zero, so nothing else changes.
    An EHS is the first thing that makes a request vary in size, so assert
    that the request and the response still fit in the command descriptor.
    
    Reviewed by:    imp (mentor)
    Sponsored by:   Samsung Electronics
    Differential Revision:  https://reviews.freebsd.org/D59557
---
 sys/dev/ufshci/ufshci_req_queue.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
index 886cf9aff77f..f1b145f9791b 100644
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -425,7 +425,7 @@ static void
 ufshci_req_queue_fill_utr_descriptor(struct ufshci_utp_xfer_req_desc *desc,
     uint8_t data_direction, const uint64_t paddr, const uint16_t response_off,
     const uint16_t response_len, const uint16_t prdt_off,
-    const uint16_t prdt_entry_cnt)
+    const uint16_t prdt_entry_cnt, const uint8_t total_ehs_length)
 {
 	uint8_t command_type;
 	/* Value to convert bytes to dwords */
@@ -441,6 +441,7 @@ ufshci_req_queue_fill_utr_descriptor(struct ufshci_utp_xfer_req_desc *desc,
 	desc->command_type = command_type;
 	desc->data_direction = data_direction;
 	desc->interrupt = true;
+	desc->total_ehs_length = total_ehs_length;
 	/* Set the initial value to Invalid. */
 	desc->overall_command_status = UFSHCI_UTR_OCS_INVALID;
 	desc->utp_command_descriptor_base_address = (uint32_t)(paddr &
@@ -719,6 +720,9 @@ ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue,
 		ufshci_req_queue_fill_utmr_descriptor(&tr->hwq->utmrd[slot_num],
 		    req);
 	} else {
+		KASSERT(req->request_size <= UFSHCI_UTP_XFER_REQ_SIZE &&
+		    req->response_size <= UFSHCI_UTP_XFER_RESP_SIZE,
+		    ("UPIU does not fit in the UTP command descriptor"));
 		request_len = req->request_size;
 		response_off = UFSHCI_UTP_XFER_REQ_SIZE;
 		response_len = req->response_size;
@@ -741,7 +745,8 @@ ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue,
 		ucd_paddr = tr->ucd_bus_addr;
 		ufshci_req_queue_fill_utr_descriptor(&tr->hwq->utrd[slot_num],
 		    data_direction, ucd_paddr, response_off, response_len,
-		    tr->prdt_off, tr->prdt_entry_cnt);
+		    tr->prdt_off, tr->prdt_entry_cnt,
+		    req->request_upiu.header.ehs_length);
 
 		bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);