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
