git: 2be8ce8405ed - main - ufshci: Add functions for UTP Task Management

From: Warner Losh <imp_at_FreeBSD.org>
Date: Sat, 16 Aug 2025 18:09:23 UTC
The branch main has been updated by imp:

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

commit 2be8ce8405ed8e9a9417ca5c3198bbc9a67a825b
Author:     Jaeyoon Choi <j_yoon.choi@samsung.com>
AuthorDate: 2025-08-16 17:40:30 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2025-08-16 18:09:15 +0000

    ufshci: Add functions for UTP Task Management
    
    This commit adds UTP Task Management Request functions and revisits the
    UTR/UTRM construction logic.
    It also introduces ufshci_ctrlr_cmd_send_task_mgmt_request(), which
    will be used for timeout handling in a follow-up commit.
    
    Test: I temporarily added the code below to the ufshci_ctrlr_start()
    function to test it on a Galaxy Book S.
    ```
    static void
    ufshci_ctrlr_start(struct ufshci_controller *ctrlr)
    {
    ...
            /* Test: Task Mangement Request */
            ufshci_printf(ctrlr,
                "Test: Task Mangement Request\n");
            struct ufshci_completion_poll_status status;
            status.done = 0;
            ufshci_ctrlr_cmd_send_task_mgmt_request(ctrlr,
                ufshci_completion_poll_cb, &status,
                UFSHCI_TASK_MGMT_FUNCTION_QUERY_TASK, 0, 0, 0);
            ufshci_completion_poll(&status);
            if (status.error) {
                    ufshci_printf(ctrlr,
                        "ufshci_ctrlr_cmd_send_task_mgmt_request failed!\n");
                    return;
            }
            uint32_t service_response;
            service_response =
                status.cpl.response_upiu.task_mgmt_response_upiu.output_param1;
            ufshci_printf(ctrlr, "Task Management Service Response = 0x%x\n",
                service_response);
    ...
    }
    ```
    
    Sponsored by:           Samsung Electronics
    Reviewed by:            imp
    Differential Revision:  https://reviews.freebsd.org/D51506
---
 sys/dev/ufshci/ufshci.h           | 104 +++++++++++++++++++++++++----
 sys/dev/ufshci/ufshci_ctrlr.c     |  33 ++++++----
 sys/dev/ufshci/ufshci_ctrlr_cmd.c |  26 ++++++++
 sys/dev/ufshci/ufshci_private.h   |  36 ++++++++---
 sys/dev/ufshci/ufshci_req_queue.c | 123 +++++++++++++++++++++++------------
 sys/dev/ufshci/ufshci_req_sdb.c   | 133 +++++++++++++++++++++++++-------------
 6 files changed, 337 insertions(+), 118 deletions(-)

diff --git a/sys/dev/ufshci/ufshci.h b/sys/dev/ufshci/ufshci.h
index 9f0faaadeb57..b96d82ff836e 100644
--- a/sys/dev/ufshci/ufshci.h
+++ b/sys/dev/ufshci/ufshci.h
@@ -160,19 +160,19 @@ enum ufshci_data_direction {
 	UFSHCI_DATA_DIRECTION_RESERVED = 0b11,
 };
 
-enum ufshci_overall_command_status {
-	UFSHCI_OCS_SUCCESS = 0x0,
-	UFSHCI_OCS_INVALID_COMMAND_TABLE_ATTRIBUTES = 0x01,
-	UFSHCI_OCS_INVALID_PRDT_ATTRIBUTES = 0x02,
-	UFSHCI_OCS_MISMATCH_DATA_BUFFER_SIZE = 0x03,
-	UFSHCI_OCS_MISMATCH_RESPONSE_UPIU_SIZE = 0x04,
-	UFSHCI_OCS_COMMUNICATION_FAILURE_WITHIN_UIC_LAYERS = 0x05,
-	UFSHCI_OCS_ABORTED = 0x06,
-	UFSHCI_OCS_HOST_CONTROLLER_FATAL_ERROR = 0x07,
-	UFSHCI_OCS_DEVICE_FATAL_ERROR = 0x08,
-	UFSHCI_OCS_INVALID_CRYPTO_CONFIGURATION = 0x09,
-	UFSHCI_OCS_GENERAL_CRYPTO_ERROR = 0x0A,
-	UFSHCI_OCS_INVALID = 0xF,
+enum ufshci_utr_overall_command_status {
+	UFSHCI_UTR_OCS_SUCCESS = 0x0,
+	UFSHCI_UTR_OCS_INVALID_COMMAND_TABLE_ATTRIBUTES = 0x01,
+	UFSHCI_UTR_OCS_INVALID_PRDT_ATTRIBUTES = 0x02,
+	UFSHCI_UTR_OCS_MISMATCH_DATA_BUFFER_SIZE = 0x03,
+	UFSHCI_UTR_OCS_MISMATCH_RESPONSE_UPIU_SIZE = 0x04,
+	UFSHCI_UTR_OCS_COMMUNICATION_FAILURE_WITHIN_UIC_LAYERS = 0x05,
+	UFSHCI_UTR_OCS_ABORTED = 0x06,
+	UFSHCI_UTR_OCS_HOST_CONTROLLER_FATAL_ERROR = 0x07,
+	UFSHCI_UTR_OCS_DEVICE_FATAL_ERROR = 0x08,
+	UFSHCI_UTR_OCS_INVALID_CRYPTO_CONFIGURATION = 0x09,
+	UFSHCI_UTR_OCS_GENERAL_CRYPTO_ERROR = 0x0A,
+	UFSHCI_UTR_OCS_INVALID = 0xF,
 };
 
 struct ufshci_utp_xfer_req_desc {
@@ -271,6 +271,18 @@ _Static_assert(sizeof(struct ufshci_utp_cmd_desc) ==
 #define UFSHCI_UTP_TASK_MGMT_REQ_SIZE  32
 #define UFSHCI_UTP_TASK_MGMT_RESP_SIZE 32
 
+enum ufshci_utmr_overall_command_status {
+	UFSHCI_UTMR_OCS_SUCCESS = 0x0,
+	UFSHCI_UTMR_OCS_INVALID_TASK_MANAGEMENT_FUNCTION_ATTRIBUTES = 0x01,
+	UFSHCI_UTMR_OCS_MISMATCH_TASK_MANAGEMENT_REQUEST_SIZE = 0x02,
+	UFSHCI_UTMR_OCS_MISMATCH_TASK_MANAGEMENT_RESPONSE_SIZE = 0x03,
+	UFSHCI_UTMR_OCS_PEER_COMMUNICATION_FAILURE = 0x04,
+	UFSHCI_UTMR_OCS_ABORTED = 0x05,
+	UFSHCI_UTMR_OCS_FATAL_ERROR = 0x06,
+	UFSHCI_UTMR_OCS_DEVICE_FATAL_ERROR = 0x07,
+	UFSHCI_UTMR_OCS_INVALID = 0xF,
+};
+
 /* UFSHCI spec 4.1, section 6.3.1 "UTP Task Management Request Descriptor" */
 struct ufshci_utp_task_mgmt_req_desc {
 	/* dword 0 */
@@ -356,6 +368,7 @@ struct ufshci_upiu {
 _Static_assert(sizeof(struct ufshci_upiu) == 512,
     "ufshci_upiu must be 512 bytes");
 
+/* UFS Spec 4.1, section 10.7.1 "COMMAND UPIU" */
 struct ufshci_cmd_command_upiu {
 	/* dword 0-2 */
 	struct ufshci_upiu_header header;
@@ -376,6 +389,7 @@ _Static_assert(sizeof(struct ufshci_cmd_command_upiu) % UFSHCI_UPIU_ALIGNMENT ==
 	0,
     "UPIU requires 64-bit alignment");
 
+/* UFS Spec 4.1, section 10.7.2 "RESPONSE UPIU" */
 struct ufshci_cmd_response_upiu {
 	/* dword 0-2 */
 	struct ufshci_upiu_header header;
@@ -403,6 +417,69 @@ _Static_assert(sizeof(struct ufshci_cmd_response_upiu) %
 	0,
     "UPIU requires 64-bit alignment");
 
+enum task_management_function {
+	UFSHCI_TASK_MGMT_FUNCTION_ABORT_TASK = 0x01,
+	UFSHCI_TASK_MGMT_FUNCTION_ABORT_TASK_SET = 0x02,
+	UFSHCI_TASK_MGMT_FUNCTION_CLEAR_TASK_SET = 0x04,
+	UFSHCI_TASK_MGMT_FUNCTION_LOGICAL_UNIT_RESET = 0x08,
+	UFSHCI_TASK_MGMT_FUNCTION_QUERY_TASK = 0x80,
+	UFSHCI_TASK_MGMT_FUNCTION_QUERY_TASKSET = 0x81,
+};
+
+/* UFS Spec 4.1, section 10.7.6 "TASK MANAGEMENT REQUEST UPIU" */
+struct ufshci_task_mgmt_request_upiu {
+	/* dword 0-2 */
+	struct ufshci_upiu_header header;
+	/* dword 3 */
+	uint32_t input_param1; /* (Big-endian) */
+	/* dword 4 */
+	uint32_t input_param2; /* (Big-endian) */
+	/* dword 5 */
+	uint32_t input_param3; /* (Big-endian) */
+	/* dword 6-7 */
+	uint8_t reserved[8];
+} __packed __aligned(4);
+
+_Static_assert(sizeof(struct ufshci_task_mgmt_request_upiu) == 32,
+    "bad size for ufshci_task_mgmt_request_upiu");
+_Static_assert(sizeof(struct ufshci_task_mgmt_request_upiu) <=
+	UFSHCI_UTP_XFER_RESP_SIZE,
+    "bad size for ufshci_task_mgmt_request_upiu");
+_Static_assert(sizeof(struct ufshci_task_mgmt_request_upiu) %
+	    UFSHCI_UPIU_ALIGNMENT ==
+	0,
+    "UPIU requires 64-bit alignment");
+
+enum task_management_service_response {
+	UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_COMPLETE = 0x00,
+	UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_NOT_SUPPORTED = 0x04,
+	UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_FAILED = 0x05,
+	UFSHCI_TASK_MGMT_SERVICE_RESPONSE_FUNCTION_SUCCEEDED = 0x08,
+	UFSHCI_TASK_MGMT_SERVICE_RESPONSE_INCORRECT_LUN = 0x09,
+};
+
+/* UFS Spec 4.1, section 10.7.7 "TASK MANAGEMENT RESPONSE UPIU" */
+struct ufshci_task_mgmt_response_upiu {
+	/* dword 0-2 */
+	struct ufshci_upiu_header header;
+	/* dword 3 */
+	uint32_t output_param1; /* (Big-endian) */
+	/* dword 4 */
+	uint32_t output_param2; /* (Big-endian) */
+	/* dword 5-7 */
+	uint8_t reserved[12];
+} __packed __aligned(4);
+
+_Static_assert(sizeof(struct ufshci_task_mgmt_response_upiu) == 32,
+    "bad size for ufshci_task_mgmt_response_upiu");
+_Static_assert(sizeof(struct ufshci_task_mgmt_response_upiu) <=
+	UFSHCI_UTP_XFER_RESP_SIZE,
+    "bad size for ufshci_task_mgmt_response_upiu");
+_Static_assert(sizeof(struct ufshci_task_mgmt_response_upiu) %
+	    UFSHCI_UPIU_ALIGNMENT ==
+	0,
+    "UPIU requires 64-bit alignment");
+
 /* UFS Spec 4.1, section 10.7.8 "QUERY REQUEST UPIU" */
 enum ufshci_query_function {
 	UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
@@ -554,6 +631,7 @@ union ufshci_reponse_upiu {
 	struct ufshci_upiu_header header;
 	struct ufshci_cmd_response_upiu cmd_response_upiu;
 	struct ufshci_query_response_upiu query_response_upiu;
+	struct ufshci_task_mgmt_response_upiu task_mgmt_response_upiu;
 	struct ufshci_nop_in_upiu nop_in_upiu;
 };
 
diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index 55d8363d3287..37bd32665b2b 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -154,12 +154,12 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev)
 	/* TODO: Initialize interrupt Aggregation Control Register (UTRIACR) */
 
 	/* Allocate and initialize UTP Task Management Request List. */
-	error = ufshci_utm_req_queue_construct(ctrlr);
+	error = ufshci_utmr_req_queue_construct(ctrlr);
 	if (error)
 		return (error);
 
 	/* Allocate and initialize UTP Transfer Request List or SQ/CQ. */
-	error = ufshci_ut_req_queue_construct(ctrlr);
+	error = ufshci_utr_req_queue_construct(ctrlr);
 	if (error)
 		return (error);
 
@@ -179,8 +179,8 @@ ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev)
 	/* TODO: Flush In-flight IOs */
 
 	/* Release resources */
-	ufshci_utm_req_queue_destroy(ctrlr);
-	ufshci_ut_req_queue_destroy(ctrlr);
+	ufshci_utmr_req_queue_destroy(ctrlr);
+	ufshci_utr_req_queue_destroy(ctrlr);
 
 	if (ctrlr->tag)
 		bus_teardown_intr(ctrlr->dev, ctrlr->res, ctrlr->tag);
@@ -215,8 +215,8 @@ ufshci_ctrlr_reset(struct ufshci_controller *ctrlr)
 	ufshci_mmio_write_4(ctrlr, ie, 0);
 
 	/* Release resources */
-	ufshci_utm_req_queue_destroy(ctrlr);
-	ufshci_ut_req_queue_destroy(ctrlr);
+	ufshci_utmr_req_queue_destroy(ctrlr);
+	ufshci_utr_req_queue_destroy(ctrlr);
 
 	/* Reset Host Controller */
 	error = ufshci_ctrlr_enable_host_ctrlr(ctrlr);
@@ -232,18 +232,27 @@ ufshci_ctrlr_reset(struct ufshci_controller *ctrlr)
 	ufshci_mmio_write_4(ctrlr, ie, ie);
 
 	/* Allocate and initialize UTP Task Management Request List. */
-	error = ufshci_utm_req_queue_construct(ctrlr);
+	error = ufshci_utmr_req_queue_construct(ctrlr);
 	if (error)
 		return (error);
 
 	/* Allocate and initialize UTP Transfer Request List or SQ/CQ. */
-	error = ufshci_ut_req_queue_construct(ctrlr);
+	error = ufshci_utr_req_queue_construct(ctrlr);
 	if (error)
 		return (error);
 
 	return (0);
 }
 
+int
+ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr,
+    struct ufshci_request *req)
+{
+	return (
+	    ufshci_req_queue_submit_request(&ctrlr->task_mgmt_req_queue, req,
+		/*is_admin*/ false));
+}
+
 int
 ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr,
     struct ufshci_request *req)
@@ -360,8 +369,8 @@ ufshci_ctrlr_start_config_hook(void *arg)
 
 	TSENTER();
 
-	if (ufshci_utm_req_queue_enable(ctrlr) == 0 &&
-	    ufshci_ut_req_queue_enable(ctrlr) == 0)
+	if (ufshci_utmr_req_queue_enable(ctrlr) == 0 &&
+	    ufshci_utr_req_queue_enable(ctrlr) == 0)
 		ufshci_ctrlr_start(ctrlr);
 	else
 		ufshci_ctrlr_fail(ctrlr, false);
@@ -445,9 +454,9 @@ ufshci_ctrlr_poll(struct ufshci_controller *ctrlr)
 	}
 	/* UTP Task Management Request Completion Status */
 	if (is & UFSHCIM(UFSHCI_IS_REG_UTMRCS)) {
-		ufshci_printf(ctrlr, "TODO: Implement UTMR completion\n");
 		ufshci_mmio_write_4(ctrlr, is, UFSHCIM(UFSHCI_IS_REG_UTMRCS));
-		/* TODO: Implement UTMR completion */
+		ufshci_req_queue_process_completions(
+		    &ctrlr->task_mgmt_req_queue);
 	}
 	/* UTP Transfer Request Completion Status */
 	if (is & UFSHCIM(UFSHCI_IS_REG_UTRCS)) {
diff --git a/sys/dev/ufshci/ufshci_ctrlr_cmd.c b/sys/dev/ufshci/ufshci_ctrlr_cmd.c
index ddf28c58fa88..71d163d998af 100644
--- a/sys/dev/ufshci/ufshci_ctrlr_cmd.c
+++ b/sys/dev/ufshci/ufshci_ctrlr_cmd.c
@@ -7,6 +7,32 @@
 
 #include "ufshci_private.h"
 
+void
+ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr,
+    ufshci_cb_fn_t cb_fn, void *cb_arg, uint8_t function, uint8_t lun,
+    uint8_t task_tag, uint8_t iid)
+{
+	struct ufshci_request *req;
+	struct ufshci_task_mgmt_request_upiu *upiu;
+
+	req = ufshci_allocate_request_vaddr(NULL, 0, M_WAITOK, cb_fn, cb_arg);
+
+	req->request_size = sizeof(struct ufshci_task_mgmt_request_upiu);
+	req->response_size = sizeof(struct ufshci_task_mgmt_response_upiu);
+
+	upiu = (struct ufshci_task_mgmt_request_upiu *)&req->request_upiu;
+	memset(upiu, 0, req->request_size);
+	upiu->header.trans_type =
+	    UFSHCI_UPIU_TRANSACTION_CODE_TASK_MANAGEMENT_REQUEST;
+	upiu->header.lun = lun;
+	upiu->header.ext_iid_or_function = function;
+	upiu->input_param1 = lun;
+	upiu->input_param2 = task_tag;
+	upiu->input_param3 = iid;
+
+	ufshci_ctrlr_submit_task_mgmt_request(ctrlr, req);
+}
+
 void
 ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr, ufshci_cb_fn_t cb_fn,
     void *cb_arg)
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index ac58d44102a0..1a2742ae2e80 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -125,6 +125,8 @@ struct ufshci_qops {
 	    struct ufshci_tracker **tr);
 	void (*ring_doorbell)(struct ufshci_controller *ctrlr,
 	    struct ufshci_tracker *tr);
+	bool (*is_doorbell_cleared)(struct ufshci_controller *ctrlr,
+	    uint8_t slot);
 	void (*clear_cpl_ntf)(struct ufshci_controller *ctrlr,
 	    struct ufshci_tracker *tr);
 	bool (*process_cpl)(struct ufshci_req_queue *req_queue);
@@ -143,7 +145,10 @@ struct ufshci_hw_queue {
 	int domain;
 	int cpu;
 
-	struct ufshci_utp_xfer_req_desc *utrd;
+	union {
+		struct ufshci_utp_xfer_req_desc *utrd;
+		struct ufshci_utp_task_mgmt_req_desc *utmrd;
+	};
 
 	bus_dma_tag_t dma_tag_queue;
 	bus_dmamap_t queuemem_map;
@@ -333,6 +338,8 @@ int ufshci_ctrlr_reset(struct ufshci_controller *ctrlr);
 void ufshci_ctrlr_start_config_hook(void *arg);
 void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr);
 
+int ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr,
+    struct ufshci_request *req);
 int ufshci_ctrlr_submit_admin_request(struct ufshci_controller *ctrlr,
     struct ufshci_request *req);
 int ufshci_ctrlr_submit_io_request(struct ufshci_controller *ctrlr,
@@ -351,6 +358,9 @@ int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr);
 int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr);
 
 /* Controller Command */
+void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr,
+    ufshci_cb_fn_t cb_fn, void *cb_arg, uint8_t function, uint8_t lun,
+    uint8_t task_tag, uint8_t iid);
 void ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr,
     ufshci_cb_fn_t cb_fn, void *cb_arg);
 void ufshci_ctrlr_cmd_send_query_request(struct ufshci_controller *ctrlr,
@@ -361,12 +371,12 @@ void ufshci_ctrlr_cmd_send_scsi_command(struct ufshci_controller *ctrlr,
 
 /* Request Queue */
 bool ufshci_req_queue_process_completions(struct ufshci_req_queue *req_queue);
-int ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr);
-int ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr);
-void ufshci_utm_req_queue_destroy(struct ufshci_controller *ctrlr);
-void ufshci_ut_req_queue_destroy(struct ufshci_controller *ctrlr);
-int ufshci_utm_req_queue_enable(struct ufshci_controller *ctrlr);
-int ufshci_ut_req_queue_enable(struct ufshci_controller *ctrlr);
+int ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr);
+int ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr);
+void ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr);
+void ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr);
+int ufshci_utmr_req_queue_enable(struct ufshci_controller *ctrlr);
+int ufshci_utr_req_queue_enable(struct ufshci_controller *ctrlr);
 void ufshci_req_queue_fail(struct ufshci_controller *ctrlr,
     struct ufshci_hw_queue *hwq);
 int ufshci_req_queue_submit_request(struct ufshci_req_queue *req_queue,
@@ -385,9 +395,17 @@ int ufshci_req_sdb_enable(struct ufshci_controller *ctrlr,
     struct ufshci_req_queue *req_queue);
 int ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue,
     struct ufshci_tracker **tr);
-void ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr,
+void ufshci_req_sdb_utmr_ring_doorbell(struct ufshci_controller *ctrlr,
+    struct ufshci_tracker *tr);
+void ufshci_req_sdb_utr_ring_doorbell(struct ufshci_controller *ctrlr,
+    struct ufshci_tracker *tr);
+bool ufshci_req_sdb_utmr_is_doorbell_cleared(struct ufshci_controller *ctrlr,
+    uint8_t slot);
+bool ufshci_req_sdb_utr_is_doorbell_cleared(struct ufshci_controller *ctrlr,
+    uint8_t slot);
+void ufshci_req_sdb_utmr_clear_cpl_ntf(struct ufshci_controller *ctrlr,
     struct ufshci_tracker *tr);
-void ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr,
+void ufshci_req_sdb_utr_clear_cpl_ntf(struct ufshci_controller *ctrlr,
     struct ufshci_tracker *tr);
 bool ufshci_req_sdb_process_cpl(struct ufshci_req_queue *req_queue);
 int ufshci_req_sdb_get_inflight_io(struct ufshci_controller *ctrlr);
diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
index cc9a2ddae768..bb6efa6d2ccc 100644
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -19,21 +19,36 @@
 static void ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue,
     struct ufshci_tracker *tr, enum ufshci_data_direction data_direction);
 
-static const struct ufshci_qops sdb_qops = {
+static const struct ufshci_qops sdb_utmr_qops = {
 	.construct = ufshci_req_sdb_construct,
 	.destroy = ufshci_req_sdb_destroy,
 	.get_hw_queue = ufshci_req_sdb_get_hw_queue,
 	.enable = ufshci_req_sdb_enable,
 	.reserve_slot = ufshci_req_sdb_reserve_slot,
 	.reserve_admin_slot = ufshci_req_sdb_reserve_slot,
-	.ring_doorbell = ufshci_req_sdb_ring_doorbell,
-	.clear_cpl_ntf = ufshci_req_sdb_clear_cpl_ntf,
+	.ring_doorbell = ufshci_req_sdb_utmr_ring_doorbell,
+	.is_doorbell_cleared = ufshci_req_sdb_utmr_is_doorbell_cleared,
+	.clear_cpl_ntf = ufshci_req_sdb_utmr_clear_cpl_ntf,
+	.process_cpl = ufshci_req_sdb_process_cpl,
+	.get_inflight_io = ufshci_req_sdb_get_inflight_io,
+};
+
+static const struct ufshci_qops sdb_utr_qops = {
+	.construct = ufshci_req_sdb_construct,
+	.destroy = ufshci_req_sdb_destroy,
+	.get_hw_queue = ufshci_req_sdb_get_hw_queue,
+	.enable = ufshci_req_sdb_enable,
+	.reserve_slot = ufshci_req_sdb_reserve_slot,
+	.reserve_admin_slot = ufshci_req_sdb_reserve_slot,
+	.ring_doorbell = ufshci_req_sdb_utr_ring_doorbell,
+	.is_doorbell_cleared = ufshci_req_sdb_utr_is_doorbell_cleared,
+	.clear_cpl_ntf = ufshci_req_sdb_utr_clear_cpl_ntf,
 	.process_cpl = ufshci_req_sdb_process_cpl,
 	.get_inflight_io = ufshci_req_sdb_get_inflight_io,
 };
 
 int
-ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr)
+ufshci_utmr_req_queue_construct(struct ufshci_controller *ctrlr)
 {
 	struct ufshci_req_queue *req_queue;
 	int error;
@@ -44,7 +59,7 @@ ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr)
 	 */
 	req_queue = &ctrlr->task_mgmt_req_queue;
 	req_queue->queue_mode = UFSHCI_Q_MODE_SDB;
-	req_queue->qops = sdb_qops;
+	req_queue->qops = sdb_utmr_qops;
 
 	error = req_queue->qops.construct(ctrlr, req_queue, UFSHCI_UTRM_ENTRIES,
 	    /*is_task_mgmt*/ true);
@@ -53,21 +68,21 @@ ufshci_utm_req_queue_construct(struct ufshci_controller *ctrlr)
 }
 
 void
-ufshci_utm_req_queue_destroy(struct ufshci_controller *ctrlr)
+ufshci_utmr_req_queue_destroy(struct ufshci_controller *ctrlr)
 {
 	ctrlr->task_mgmt_req_queue.qops.destroy(ctrlr,
 	    &ctrlr->task_mgmt_req_queue);
 }
 
 int
-ufshci_utm_req_queue_enable(struct ufshci_controller *ctrlr)
+ufshci_utmr_req_queue_enable(struct ufshci_controller *ctrlr)
 {
 	return (ctrlr->task_mgmt_req_queue.qops.enable(ctrlr,
 	    &ctrlr->task_mgmt_req_queue));
 }
 
 int
-ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr)
+ufshci_utr_req_queue_construct(struct ufshci_controller *ctrlr)
 {
 	struct ufshci_req_queue *req_queue;
 	int error;
@@ -79,7 +94,7 @@ ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr)
 	 */
 	req_queue = &ctrlr->transfer_req_queue;
 	req_queue->queue_mode = UFSHCI_Q_MODE_SDB;
-	req_queue->qops = sdb_qops;
+	req_queue->qops = sdb_utr_qops;
 
 	error = req_queue->qops.construct(ctrlr, req_queue, UFSHCI_UTR_ENTRIES,
 	    /*is_task_mgmt*/ false);
@@ -88,14 +103,14 @@ ufshci_ut_req_queue_construct(struct ufshci_controller *ctrlr)
 }
 
 void
-ufshci_ut_req_queue_destroy(struct ufshci_controller *ctrlr)
+ufshci_utr_req_queue_destroy(struct ufshci_controller *ctrlr)
 {
 	ctrlr->transfer_req_queue.qops.destroy(ctrlr,
 	    &ctrlr->transfer_req_queue);
 }
 
 int
-ufshci_ut_req_queue_enable(struct ufshci_controller *ctrlr)
+ufshci_utr_req_queue_enable(struct ufshci_controller *ctrlr)
 {
 	return (ctrlr->transfer_req_queue.qops.enable(ctrlr,
 	    &ctrlr->transfer_req_queue));
@@ -213,20 +228,30 @@ ufshci_req_queue_complete_tracker(struct ufshci_tracker *tr)
 	struct ufshci_req_queue *req_queue = tr->req_queue;
 	struct ufshci_request *req = tr->req;
 	struct ufshci_completion cpl;
-	struct ufshci_utp_xfer_req_desc *desc;
 	uint8_t ocs;
 	bool retry, error, retriable;
 
 	mtx_assert(&tr->hwq->qlock, MA_NOTOWNED);
 
-	bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
-	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+	/* Copy the response from the Request Descriptor or UTP Command
+	 * Descriptor. */
+	if (req_queue->is_task_mgmt) {
+		cpl.size = tr->response_size;
+		memcpy(&cpl.response_upiu,
+		    (void *)tr->hwq->utmrd[tr->slot_num].response_upiu,
+		    cpl.size);
 
-	cpl.size = tr->response_size;
-	memcpy(&cpl.response_upiu, (void *)tr->ucd->response_upiu, cpl.size);
+		ocs = tr->hwq->utmrd[tr->slot_num].overall_command_status;
+	} else {
+		bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
+		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 
-	desc = &tr->hwq->utrd[tr->slot_num];
-	ocs = desc->overall_command_status;
+		cpl.size = tr->response_size;
+		memcpy(&cpl.response_upiu, (void *)tr->ucd->response_upiu,
+		    cpl.size);
+
+		ocs = tr->hwq->utrd[tr->slot_num].overall_command_status;
+	}
 
 	error = ufshci_req_queue_response_is_error(req_queue, ocs,
 	    &cpl.response_upiu);
@@ -358,7 +383,19 @@ ufshci_req_queue_prepare_prdt(struct ufshci_tracker *tr)
 }
 
 static void
-ufshci_req_queue_fill_descriptor(struct ufshci_utp_xfer_req_desc *desc,
+ufshci_req_queue_fill_utmr_descriptor(
+    struct ufshci_utp_task_mgmt_req_desc *desc, struct ufshci_request *req)
+{
+	memset(desc, 0, sizeof(struct ufshci_utp_task_mgmt_req_desc));
+	desc->interrupt = true;
+	/* Set the initial value to Invalid. */
+	desc->overall_command_status = UFSHCI_UTMR_OCS_INVALID;
+
+	memcpy(desc->request_upiu, &req->request_upiu, req->request_size);
+}
+
+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)
@@ -378,7 +415,7 @@ ufshci_req_queue_fill_descriptor(struct ufshci_utp_xfer_req_desc *desc,
 	desc->data_direction = data_direction;
 	desc->interrupt = true;
 	/* Set the initial value to Invalid. */
-	desc->overall_command_status = UFSHCI_OCS_INVALID;
+	desc->overall_command_status = UFSHCI_UTR_OCS_INVALID;
 	desc->utp_command_descriptor_base_address = (uint32_t)(paddr &
 	    0xffffffff);
 	desc->utp_command_descriptor_base_address_upper = (uint32_t)(paddr >>
@@ -407,26 +444,32 @@ ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue,
 
 	/* TODO: Check timeout */
 
-	request_len = req->request_size;
-	response_off = UFSHCI_UTP_XFER_REQ_SIZE;
-	response_len = req->response_size;
-
-	/* Prepare UTP Command Descriptor */
-	memcpy(tr->ucd, &req->request_upiu, request_len);
-	memset((uint8_t *)tr->ucd + response_off, 0, response_len);
-
-	/* Prepare PRDT */
-	if (req->payload_valid)
-		ufshci_req_queue_prepare_prdt(tr);
-
-	bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
-	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
-
-	/* Prepare UTP Transfer Request Descriptor. */
-	ucd_paddr = tr->ucd_bus_addr;
-	ufshci_req_queue_fill_descriptor(&tr->hwq->utrd[slot_num],
-	    data_direction, ucd_paddr, response_off, response_len, tr->prdt_off,
-	    tr->prdt_entry_cnt);
+	if (req_queue->is_task_mgmt) {
+		/* Prepare UTP Task Management Request Descriptor. */
+		ufshci_req_queue_fill_utmr_descriptor(&tr->hwq->utmrd[slot_num],
+		    req);
+	} else {
+		request_len = req->request_size;
+		response_off = UFSHCI_UTP_XFER_REQ_SIZE;
+		response_len = req->response_size;
+
+		/* Prepare UTP Command Descriptor */
+		memcpy(tr->ucd, &req->request_upiu, request_len);
+		memset((uint8_t *)tr->ucd + response_off, 0, response_len);
+
+		/* Prepare PRDT */
+		if (req->payload_valid)
+			ufshci_req_queue_prepare_prdt(tr);
+
+		/* Prepare UTP Transfer Request Descriptor. */
+		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);
+
+		bus_dmamap_sync(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
+		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+	}
 
 	bus_dmamap_sync(tr->hwq->dma_tag_queue, tr->hwq->queuemem_map,
 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
diff --git a/sys/dev/ufshci/ufshci_req_sdb.c b/sys/dev/ufshci/ufshci_req_sdb.c
index b1f303afaef5..834a459d48e3 100644
--- a/sys/dev/ufshci/ufshci_req_sdb.c
+++ b/sys/dev/ufshci/ufshci_req_sdb.c
@@ -26,12 +26,6 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue)
 		tr = hwq->act_tr[i];
 		bus_dmamap_destroy(req_queue->dma_tag_payload,
 		    tr->payload_dma_map);
-		free(tr, M_UFSHCI);
-	}
-
-	if (hwq->act_tr) {
-		free(hwq->act_tr, M_UFSHCI);
-		hwq->act_tr = NULL;
 	}
 
 	if (req_queue->ucd) {
@@ -76,7 +70,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
     uint32_t num_entries, struct ufshci_controller *ctrlr)
 {
 	struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q];
-	struct ufshci_tracker *tr;
 	size_t ucd_allocsz, payload_allocsz;
 	uint8_t *ucdmem;
 	int i, error;
@@ -134,27 +127,14 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
 		goto out;
 	}
 
-	hwq->act_tr = malloc_domainset(sizeof(struct ufshci_tracker *) *
-		req_queue->num_entries,
-	    M_UFSHCI, DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK);
-
 	for (i = 0; i < req_queue->num_trackers; i++) {
-		tr = malloc_domainset(sizeof(struct ufshci_tracker), M_UFSHCI,
-		    DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK);
-
 		bus_dmamap_create(req_queue->dma_tag_payload, 0,
-		    &tr->payload_dma_map);
+		    &hwq->act_tr[i]->payload_dma_map);
 
-		tr->req_queue = req_queue;
-		tr->slot_num = i;
-		tr->slot_state = UFSHCI_SLOT_STATE_FREE;
-
-		tr->ucd = (struct ufshci_utp_cmd_desc *)ucdmem;
-		tr->ucd_bus_addr = hwq->ucd_bus_addr[i];
+		hwq->act_tr[i]->ucd = (struct ufshci_utp_cmd_desc *)ucdmem;
+		hwq->act_tr[i]->ucd_bus_addr = hwq->ucd_bus_addr[i];
 
 		ucdmem += sizeof(struct ufshci_utp_cmd_desc);
-
-		hwq->act_tr[i] = tr;
 	}
 
 	return (0);
@@ -163,25 +143,16 @@ out:
 	return (ENOMEM);
 }
 
-static bool
-ufshci_req_sdb_is_doorbell_cleared(struct ufshci_controller *ctrlr,
-    uint8_t slot)
-{
-	uint32_t utrldbr;
-
-	utrldbr = ufshci_mmio_read_4(ctrlr, utrldbr);
-	return (!(utrldbr & (1 << slot)));
-}
-
 int
 ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
     struct ufshci_req_queue *req_queue, uint32_t num_entries, bool is_task_mgmt)
 {
 	struct ufshci_hw_queue *hwq;
-	size_t allocsz;
+	size_t desc_size, alloc_size;
 	uint64_t queuemem_phys;
 	uint8_t *queuemem;
-	int error;
+	struct ufshci_tracker *tr;
+	int i, error;
 
 	req_queue->ctrlr = ctrlr;
 	req_queue->is_task_mgmt = is_task_mgmt;
@@ -209,10 +180,13 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
 	 * Descriptor (UTRD) or UTP Task Management Request Descriptor (UTMRD))
 	 * Note: UTRD/UTMRD format is restricted to 1024-byte alignment.
 	 */
-	allocsz = num_entries * sizeof(struct ufshci_utp_xfer_req_desc);
+	desc_size = is_task_mgmt ?
+	    sizeof(struct ufshci_utp_task_mgmt_req_desc) :
+	    sizeof(struct ufshci_utp_xfer_req_desc);
+	alloc_size = num_entries * desc_size;
 	error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 1024,
 	    ctrlr->page_size, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
-	    allocsz, 1, allocsz, 0, NULL, NULL, &hwq->dma_tag_queue);
+	    alloc_size, 1, alloc_size, 0, NULL, NULL, &hwq->dma_tag_queue);
 	if (error != 0) {
 		ufshci_printf(ctrlr, "request queue tag create failed %d\n",
 		    error);
@@ -227,7 +201,7 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
 	}
 
 	if (bus_dmamap_load(hwq->dma_tag_queue, hwq->queuemem_map, queuemem,
-		allocsz, ufshci_single_map, &queuemem_phys, 0) != 0) {
+		alloc_size, ufshci_single_map, &queuemem_phys, 0) != 0) {
 		ufshci_printf(ctrlr, "failed to load request queue memory\n");
 		bus_dmamem_free(hwq->dma_tag_queue, hwq->utrd,
 		    hwq->queuemem_map);
@@ -238,13 +212,30 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
 	hwq->num_intr_handler_calls = 0;
 	hwq->num_retries = 0;
 	hwq->num_failures = 0;
-	hwq->utrd = (struct ufshci_utp_xfer_req_desc *)queuemem;
 	hwq->req_queue_addr = queuemem_phys;
 
+	/* Allocate trackers */
+	hwq->act_tr = malloc_domainset(sizeof(struct ufshci_tracker *) *
+		req_queue->num_entries,
+	    M_UFSHCI, DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK);
+
+	for (i = 0; i < req_queue->num_trackers; i++) {
+		tr = malloc_domainset(sizeof(struct ufshci_tracker), M_UFSHCI,
+		    DOMAINSET_PREF(req_queue->domain), M_ZERO | M_WAITOK);
+
+		tr->req_queue = req_queue;
+		tr->slot_num = i;
+		tr->slot_state = UFSHCI_SLOT_STATE_FREE;
+
+		hwq->act_tr[i] = tr;
+	}
+
 	if (is_task_mgmt) {
 		/* UTP Task Management Request (UTMR) */
 		uint32_t utmrlba, utmrlbau;
 
+		hwq->utmrd = (struct ufshci_utp_task_mgmt_req_desc *)queuemem;
+
 		utmrlba = hwq->req_queue_addr & 0xffffffff;
 		utmrlbau = hwq->req_queue_addr >> 32;
 		ufshci_mmio_write_4(ctrlr, utmrlba, utmrlba);
@@ -253,6 +244,8 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
 		/* UTP Transfer Request (UTR) */
 		uint32_t utrlba, utrlbau;
 
+		hwq->utrd = (struct ufshci_utp_xfer_req_desc *)queuemem;
+
 		/*
 		 * Allocate physical memory for the command descriptor.
 		 * UTP Transfer Request (UTR) requires memory for a separate
@@ -284,10 +277,22 @@ ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr,
     struct ufshci_req_queue *req_queue)
 {
 	struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q];
+	struct ufshci_tracker *tr;
+	int i;
 
 	if (!req_queue->is_task_mgmt)
 		ufshci_req_sdb_cmd_desc_destroy(&ctrlr->transfer_req_queue);
 
+	for (i = 0; i < req_queue->num_trackers; i++) {
+		tr = hwq->act_tr[i];
+		free(tr, M_UFSHCI);
+	}
+
+	if (hwq->act_tr) {
+		free(hwq->act_tr, M_UFSHCI);
+		hwq->act_tr = NULL;
+	}
+
 	if (hwq->utrd != NULL) {
 		bus_dmamap_unload(hwq->dma_tag_queue, hwq->queuemem_map);
 		bus_dmamem_free(hwq->dma_tag_queue, hwq->utrd,
@@ -389,7 +394,18 @@ ufshci_req_sdb_reserve_slot(struct ufshci_req_queue *req_queue,
 }
 
 void
-ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr,
+ufshci_req_sdb_utmr_clear_cpl_ntf(struct ufshci_controller *ctrlr,
+    struct ufshci_tracker *tr)
+{
+	/*
+	 * NOP
+	 * UTP Task Management does not have a Completion Notification
+	 * Register.
+	 */
+}
+
+void
+ufshci_req_sdb_utr_clear_cpl_ntf(struct ufshci_controller *ctrlr,
     struct ufshci_tracker *tr)
 {
 	uint32_t utrlcnr;
@@ -399,7 +415,19 @@ ufshci_req_sdb_clear_cpl_ntf(struct ufshci_controller *ctrlr,
 }
 
 void
-ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr,
+ufshci_req_sdb_utmr_ring_doorbell(struct ufshci_controller *ctrlr,
+    struct ufshci_tracker *tr)
+{
+	uint32_t utmrldbr = 0;
+
+	utmrldbr |= 1 << tr->slot_num;
+	ufshci_mmio_write_4(ctrlr, utmrldbr, utmrldbr);
+
+	tr->req_queue->hwq[UFSHCI_SDB_Q].num_cmds++;
+}
+
+void
+ufshci_req_sdb_utr_ring_doorbell(struct ufshci_controller *ctrlr,
     struct ufshci_tracker *tr)
 {
 	uint32_t utrldbr = 0;
@@ -408,9 +436,26 @@ ufshci_req_sdb_ring_doorbell(struct ufshci_controller *ctrlr,
 	ufshci_mmio_write_4(ctrlr, utrldbr, utrldbr);
 
 	tr->req_queue->hwq[UFSHCI_SDB_Q].num_cmds++;
+}
+
+bool
+ufshci_req_sdb_utmr_is_doorbell_cleared(struct ufshci_controller *ctrlr,
+    uint8_t slot)
+{
+	uint32_t utmrldbr;
+
+	utmrldbr = ufshci_mmio_read_4(ctrlr, utmrldbr);
+	return (!(utmrldbr & (1 << slot)));
+}
 
-	// utrldbr = ufshci_mmio_read_4(ctrlr, utrldbr);
-	// printf("DB=0x%08x\n", utrldbr);
+bool
+ufshci_req_sdb_utr_is_doorbell_cleared(struct ufshci_controller *ctrlr,
+    uint8_t slot)
+{
+	uint32_t utrldbr;
+
+	utrldbr = ufshci_mmio_read_4(ctrlr, utrldbr);
+	return (!(utrldbr & (1 << slot)));
 }
 
 bool
@@ -435,7 +480,7 @@ ufshci_req_sdb_process_cpl(struct ufshci_req_queue *req_queue)
 		 * is cleared.
 		 */
 		if (tr->slot_state == UFSHCI_SLOT_STATE_SCHEDULED &&
-		    ufshci_req_sdb_is_doorbell_cleared(req_queue->ctrlr,
+		    req_queue->qops.is_doorbell_cleared(req_queue->ctrlr,
 			slot)) {
 			ufshci_req_queue_complete_tracker(tr);
 			done = true;