The branch main has been updated by imp:

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

commit 2be8ce8405ed8e9a9417ca5c3198bbc9a67a825b
Author:     Jaeyoon Choi <j_yoon.c...@samsung.com>
AuthorDate: 2025-08-16 17:40:30 +0000
Commit:     Warner Losh <i...@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;

Reply via email to