git: c9827f1528a6 - main - ufshci: handle controller command submit failures

Jaeyoon Choi <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7937f6.1cfd8.2c48fc91__28073.0792948574$1786329124$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by jaeyoon:

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

commit c9827f1528a69664f4031e1c511b2e7022601a7c
Author:     Jaeyoon Choi <[email protected]>
AuthorDate: 2026-08-10 01:34:06 +0000
Commit:     Jaeyoon Choi <[email protected]>
CommitDate: 2026-08-10 02:28:47 +0000

    ufshci: handle controller command submit failures
    
    Return submission errors from the controller command helpers and
    propagate them to polled callers before waiting for completion. Free
    requests that never enter a hardware queue so failure paths do not leak
    or panic after the poll timeout.
    
    Sponsored by:           Samsung Electronics
    Reviewed by:            imp (mentor)
    Differential Revision:  https://reviews.freebsd.org/D58655
---
 sys/dev/ufshci/ufshci_ctrlr.c     |  7 +++++-
 sys/dev/ufshci/ufshci_ctrlr_cmd.c | 29 ++++++++++++++++++-----
 sys/dev/ufshci/ufshci_dev.c       | 48 +++++++++++++++++++++++++++++----------
 sys/dev/ufshci/ufshci_private.h   |  6 ++---
 sys/dev/ufshci/ufshci_req_queue.c | 16 +++++++++----
 5 files changed, 79 insertions(+), 27 deletions(-)

diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index b271720efb52..cb5549f8e7c9 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -494,9 +494,14 @@ int
 ufshci_ctrlr_send_nop(struct ufshci_controller *ctrlr)
 {
 	struct ufshci_completion_poll_status status;
+	int error;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_nop(ctrlr, ufshci_completion_poll_cb, &status);
+	error = ufshci_ctrlr_cmd_send_nop(ctrlr, ufshci_completion_poll_cb,
+	    &status);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr, "ufshci_ctrlr_send_nop failed!\n");
diff --git a/sys/dev/ufshci/ufshci_ctrlr_cmd.c b/sys/dev/ufshci/ufshci_ctrlr_cmd.c
index cac01894c062..2e85cfa4b5b0 100644
--- a/sys/dev/ufshci/ufshci_ctrlr_cmd.c
+++ b/sys/dev/ufshci/ufshci_ctrlr_cmd.c
@@ -7,15 +7,18 @@
 
 #include "ufshci_private.h"
 
-void
+int
 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;
+	int error;
 
 	req = ufshci_allocate_request_vaddr(NULL, 0, M_NOWAIT, cb_fn, cb_arg);
+	if (req == NULL)
+		return (ENOMEM);
 
 	req->request_size = sizeof(struct ufshci_task_mgmt_request_upiu);
 	req->response_size = sizeof(struct ufshci_task_mgmt_response_upiu);
@@ -30,15 +33,20 @@ ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr,
 	upiu->input_param2 = task_tag;
 	upiu->input_param3 = iid;
 
-	ufshci_ctrlr_submit_task_mgmt_request(ctrlr, req);
+	error = ufshci_ctrlr_submit_task_mgmt_request(ctrlr, req);
+	if (error)
+		ufshci_free_request(req);
+
+	return (error);
 }
 
-void
+int
 ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr, ufshci_cb_fn_t cb_fn,
     void *cb_arg)
 {
 	struct ufshci_request *req;
 	struct ufshci_nop_out_upiu *upiu;
+	int error;
 
 	req = ufshci_allocate_request_vaddr(NULL, 0, M_WAITOK, cb_fn, cb_arg);
 
@@ -50,15 +58,20 @@ ufshci_ctrlr_cmd_send_nop(struct ufshci_controller *ctrlr, ufshci_cb_fn_t cb_fn,
 	memset(upiu, 0, req->request_size);
 	upiu->header.trans_type = UFSHCI_UPIU_TRANSACTION_CODE_NOP_OUT;
 
-	ufshci_ctrlr_submit_transfer_request(ctrlr, req);
+	error = ufshci_ctrlr_submit_transfer_request(ctrlr, req);
+	if (error)
+		ufshci_free_request(req);
+
+	return (error);
 }
 
-void
+int
 ufshci_ctrlr_cmd_send_query_request(struct ufshci_controller *ctrlr,
     ufshci_cb_fn_t cb_fn, void *cb_arg, struct ufshci_query_param param)
 {
 	struct ufshci_request *req;
 	struct ufshci_query_request_upiu *upiu;
+	int error;
 
 	req = ufshci_allocate_request_vaddr(NULL, 0, M_WAITOK, cb_fn, cb_arg);
 
@@ -77,5 +90,9 @@ ufshci_ctrlr_cmd_send_query_request(struct ufshci_controller *ctrlr,
 	upiu->value_64 = param.value;
 	upiu->length = param.desc_size;
 
-	ufshci_ctrlr_submit_transfer_request(ctrlr, req);
+	error = ufshci_ctrlr_submit_transfer_request(ctrlr, req);
+	if (error)
+		ufshci_free_request(req);
+
+	return (error);
 }
diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c
index 0fedbca9a90e..c53d9b71ba2c 100644
--- a/sys/dev/ufshci/ufshci_dev.c
+++ b/sys/dev/ufshci/ufshci_dev.c
@@ -19,6 +19,7 @@ ufshci_dev_read_descriptor(struct ufshci_controller *ctrlr,
 {
 	struct ufshci_completion_poll_status status;
 	struct ufshci_query_param param;
+	int error;
 
 	param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
 	param.opcode = UFSHCI_QUERY_OPCODE_READ_DESCRIPTOR;
@@ -29,8 +30,11 @@ ufshci_dev_read_descriptor(struct ufshci_controller *ctrlr,
 	param.desc_size = desc_size;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
-	    &status, param);
+	error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
+	    ufshci_completion_poll_cb, &status, param);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr,
@@ -74,6 +78,7 @@ ufshci_dev_read_flag(struct ufshci_controller *ctrlr,
 {
 	struct ufshci_completion_poll_status status;
 	struct ufshci_query_param param;
+	int error;
 
 	param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
 	param.opcode = UFSHCI_QUERY_OPCODE_READ_FLAG;
@@ -83,8 +88,11 @@ ufshci_dev_read_flag(struct ufshci_controller *ctrlr,
 	param.value = 0;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
-	    &status, param);
+	error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
+	    ufshci_completion_poll_cb, &status, param);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr, "ufshci_dev_read_flag failed!\n");
@@ -102,6 +110,7 @@ ufshci_dev_set_flag(struct ufshci_controller *ctrlr,
 {
 	struct ufshci_completion_poll_status status;
 	struct ufshci_query_param param;
+	int error;
 
 	param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
 	param.opcode = UFSHCI_QUERY_OPCODE_SET_FLAG;
@@ -111,8 +120,11 @@ ufshci_dev_set_flag(struct ufshci_controller *ctrlr,
 	param.value = 0;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
-	    &status, param);
+	error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
+	    ufshci_completion_poll_cb, &status, param);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr, "ufshci_dev_set_flag failed!\n");
@@ -128,6 +140,7 @@ ufshci_dev_clear_flag(struct ufshci_controller *ctrlr,
 {
 	struct ufshci_completion_poll_status status;
 	struct ufshci_query_param param;
+	int error;
 
 	param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
 	param.opcode = UFSHCI_QUERY_OPCODE_CLEAR_FLAG;
@@ -137,8 +150,11 @@ ufshci_dev_clear_flag(struct ufshci_controller *ctrlr,
 	param.value = 0;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
-	    &status, param);
+	error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
+	    ufshci_completion_poll_cb, &status, param);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr, "ufshci_dev_clear_flag failed!\n");
@@ -155,6 +171,7 @@ ufshci_dev_read_attribute(struct ufshci_controller *ctrlr,
 {
 	struct ufshci_completion_poll_status status;
 	struct ufshci_query_param param;
+	int error;
 
 	param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
 	param.opcode = UFSHCI_QUERY_OPCODE_READ_ATTRIBUTE;
@@ -164,8 +181,11 @@ ufshci_dev_read_attribute(struct ufshci_controller *ctrlr,
 	param.value = 0;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
-	    &status, param);
+	error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
+	    ufshci_completion_poll_cb, &status, param);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr, "ufshci_dev_read_attribute failed!\n");
@@ -184,6 +204,7 @@ ufshci_dev_write_attribute(struct ufshci_controller *ctrlr,
 {
 	struct ufshci_completion_poll_status status;
 	struct ufshci_query_param param;
+	int error;
 
 	param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
 	param.opcode = UFSHCI_QUERY_OPCODE_WRITE_ATTRIBUTE;
@@ -193,8 +214,11 @@ ufshci_dev_write_attribute(struct ufshci_controller *ctrlr,
 	param.value = value;
 
 	status.done = 0;
-	ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
-	    &status, param);
+	error = ufshci_ctrlr_cmd_send_query_request(ctrlr,
+	    ufshci_completion_poll_cb, &status, param);
+	if (error)
+		return (error);
+
 	ufshci_completion_poll(&status);
 	if (status.error) {
 		ufshci_printf(ctrlr, "ufshci_dev_write_attribute failed!\n");
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index 8d18fab982d7..d4c4140f82ae 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -479,12 +479,12 @@ int ufshci_dev_link_state_transition(struct ufshci_controller *ctrlr,
     enum ufshci_uic_link_state target_state);
 
 /* Controller Command */
-void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr,
+int 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,
+int 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,
+int ufshci_ctrlr_cmd_send_query_request(struct ufshci_controller *ctrlr,
     ufshci_cb_fn_t cb_fn, void *cb_arg, struct ufshci_query_param param);
 void ufshci_ctrlr_cmd_send_scsi_command(struct ufshci_controller *ctrlr,
     ufshci_cb_fn_t cb_fn, void *cb_arg, uint8_t *cmd_ptr, uint8_t cmd_len,
diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
index 395801274f0e..371b9c520979 100644
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -632,11 +632,17 @@ ufshci_req_queue_timeout(void *arg)
 				ufshci_printf(ctrlr,
 				    "Recovery step 1: Timeout occurred. aborting the task(%d).\n",
 				    tr->req->request_upiu.header.task_tag);
-				ufshci_ctrlr_cmd_send_task_mgmt_request(ctrlr,
-				    ufshci_abort_complete, tr,
-				    UFSHCI_TASK_MGMT_FUNCTION_ABORT_TASK,
-				    tr->req->request_upiu.header.lun,
-				    tr->req->request_upiu.header.task_tag, 0);
+				if (ufshci_ctrlr_cmd_send_task_mgmt_request(ctrlr,
+					ufshci_abort_complete, tr,
+					UFSHCI_TASK_MGMT_FUNCTION_ABORT_TASK,
+					tr->req->request_upiu.header.lun,
+					tr->req->request_upiu.header.task_tag,
+					0) != 0) {
+					ufshci_req_queue_timeout_recovery(ctrlr,
+					    hwq);
+					idle = false;
+					break;
+				}
 			} else {
 				/* Recovery Step 2-5 */
 				ufshci_req_queue_timeout_recovery(ctrlr, hwq);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.