From: Stanley Jhu <[email protected]>

Wire up Task Management Request (TMR) and MCQ submission queue cleanup
handling for transfer requests held by x-fault-inject-tag according to
x-fault-inject-mode:

- "abort-success": UFS_QUERY_TASK returns
  UFS_UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED. UFS_ABORT_TASK cancels the
  underlying SCSI request and marks the MCQ request in error state for
  SQRTC.ICU cleanup (or clears the legacy UTRL slot), then returns
  UFS_UPIU_TASK_MANAGEMENT_FUNC_COMPL.
- "abort-failed": UFS_ABORT_TASK returns
  UFS_UPIU_TASK_MANAGEMENT_FUNC_FAILED while keeping the request held.
- "in-transition": UFS_QUERY_TASK releases the held transfer request
  and executes it through the normal SCSI command path, completing
  with genuine device I/O and CQE generation, while returning
  UFS_UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED per SAM-5 task set rules.
  UFS_ABORT_TASK releases the held request to generic abort processing.
- "timeout": UFS_ABORT_TASK skips completion so the host driver hits
  its TMR timeout path.

Also clear u->held_req and disarm active_fault_inject_tag when an MCQ
submission queue containing the held request is cleaned up via
ufs_mcq_sq_cleanup().

Signed-off-by: Stanley Jhu <[email protected]>
Reviewed-by: Jeuk Kim <[email protected]>
Signed-off-by: Jeuk Kim <[email protected]>
---
 hw/ufs/ufs.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 1 deletion(-)

diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 1a5bc54eac4..83d5fc24414 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -37,6 +37,7 @@
 #define UFS_HID_PROGRESS_COMPLETE 100
 
 static void ufs_exec_req(UfsRequest *req);
+static void ufs_fault_inject_execute_held_req(UfsRequest *hreq);
 static void ufs_clear_req(UfsRequest *req);
 static void ufs_mcq_process_cq(void *opaque);
 
@@ -797,6 +798,67 @@ static void ufs_fault_inject_hce_reset(UfsHc *u)
     }
 }
 
+static bool ufs_fault_inject_tmr(UfsHc *u, uint8_t tm_func, uint8_t lun,
+                                 uint32_t task_tag, uint8_t *tm_resp,
+                                 bool *skip_completion)
+{
+    UfsRequest *hreq = u->held_req;
+
+    *skip_completion = false;
+    if (!hreq || task_tag != u->active_fault_inject_tag ||
+        hreq->req_upiu.header.lun != lun) {
+        return false;
+    }
+
+    if (tm_func == UFS_QUERY_TASK) {
+        if (u->params.fault_inject_mode == UFS_FAULT_INJECT_IN_TRANSITION) {
+            u->held_req = NULL;
+            u->active_fault_inject_tag = UFS_FAULT_INJECT_TAG_NONE;
+            u->params.fault_inject_tag = UFS_FAULT_INJECT_TAG_NONE;
+            ufs_fault_inject_execute_held_req(hreq);
+            return false;
+        }
+        /*
+         * Generic QUERY TASK in ufs_process_tmr() will check
+         * ufs_find_req_by_tag() and return SUCCEEDED for the held request.
+         */
+        return false;
+    }
+
+    if (tm_func == UFS_ABORT_TASK) {
+        if (u->params.fault_inject_mode == UFS_FAULT_INJECT_ABORT_FAILED) {
+            *tm_resp = UFS_UPIU_TASK_MANAGEMENT_FUNC_FAILED;
+            return true;
+        }
+        if (u->params.fault_inject_mode == UFS_FAULT_INJECT_TIMEOUT) {
+            *skip_completion = true;
+            return true;
+        }
+
+        /*
+         * UFS_FAULT_INJECT_ABORT_SUCCESS, UFS_FAULT_INJECT_IN_TRANSITION,
+         * or default:
+         * Release the fault-injection hold, then let generic ABORT TASK
+         * in ufs_process_tmr() handle cancellation.
+         */
+        u->held_req = NULL;
+        u->active_fault_inject_tag = UFS_FAULT_INJECT_TAG_NONE;
+        u->params.fault_inject_tag = UFS_FAULT_INJECT_TAG_NONE;
+        return false;
+    }
+
+    return false;
+}
+
+static void ufs_fault_inject_sq_cleanup(UfsHc *u, UfsRequest *req)
+{
+    if (u->held_req == req) {
+        u->held_req = NULL;
+        u->active_fault_inject_tag = UFS_FAULT_INJECT_TAG_NONE;
+        u->params.fault_inject_tag = UFS_FAULT_INJECT_TAG_NONE;
+    }
+}
+
 static bool ufs_fault_inject_exec_req(UfsRequest *req)
 {
     UfsHc *u = req->hc;
@@ -980,6 +1042,7 @@ static void ufs_process_tmr(UfsHc *u, uint32_t val)
             UtpTaskReqDesc desc;
             uint8_t tm_func, tm_resp, lun;
             uint32_t task_tag;
+            bool skip_completion = false;
 
             if (ufs_addr_read(u, desc_addr, &desc, sizeof(desc))) {
                 continue;
@@ -989,7 +1052,12 @@ static void ufs_process_tmr(UfsHc *u, uint32_t val)
             lun = desc.upiu_req.req_header.lun;
             task_tag = be32_to_cpu(desc.upiu_req.input_param2);
 
-            if (tm_func == UFS_QUERY_TASK) {
+            if (ufs_fault_inject_tmr(u, tm_func, lun, task_tag, &tm_resp,
+                                     &skip_completion)) {
+                if (skip_completion) {
+                    continue;
+                }
+            } else if (tm_func == UFS_QUERY_TASK) {
                 UfsRequest *req = ufs_find_req_by_tag(u, lun, task_tag);
 
                 if (req) {
@@ -1257,6 +1325,7 @@ static void ufs_mcq_sq_cleanup(UfsHc *u, uint8_t qid)
         }
 
         if (req) {
+            ufs_fault_inject_sq_cleanup(u, req);
             if (req->sreq != NULL) {
                 SCSIRequest *sreq = req->sreq;
                 req->sreq = NULL;
@@ -2537,6 +2606,16 @@ static void ufs_exec_req(UfsRequest *req)
     }
 }
 
+static void ufs_fault_inject_execute_held_req(UfsRequest *hreq)
+{
+    UfsReqResult req_result;
+
+    req_result = ufs_exec_scsi_cmd(hreq);
+    if (req_result != UFS_REQUEST_NO_COMPLETE) {
+        ufs_complete_req(hreq, req_result);
+    }
+}
+
 static void ufs_process_req(void *opaque)
 {
     UfsHc *u = opaque;
-- 
2.43.0


Reply via email to