git: b83a22eb9d3c - main - ufshci: add debug aids for driving the recovery path
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 03 Nov 2026 04:33:42 UTC
The branch main has been updated by jaeyoon:
URL: https://cgit.FreeBSD.org/src/commit/?id=b83a22eb9d3c3e621d2096b0f5988c1e09f6ddc5
commit b83a22eb9d3c3e621d2096b0f5988c1e09f6ddc5
Author: Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2026-11-03 04:15:35 +0000
Commit: Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2026-11-03 04:29:42 +0000
ufshci: add debug aids for driving the recovery path
The reset and recovery paths only run when the hardware fails, so they
never ran on an emulated controller. The failure path also took the
controller offline without logging anything.
Add the force_reset, drop_next_ios and drop_next_admins sysctls to
drive these paths, and log when the controller fails. The aborts the
watchdog sends must go out, so the task management queue is never
dropped.
Reviewed by: imp
Sponsored by: Samsung Electronics
Differential Revision: https://reviews.freebsd.org/D61112
---
share/man/man4/ufshci.4 | 14 +++++++++++++-
sys/dev/ufshci/ufshci_ctrlr.c | 2 ++
sys/dev/ufshci/ufshci_private.h | 4 ++++
sys/dev/ufshci/ufshci_req_queue.c | 27 +++++++++++++++++++++++++++
sys/dev/ufshci/ufshci_sysctl.c | 35 +++++++++++++++++++++++++++++++++++
5 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/share/man/man4/ufshci.4 b/share/man/man4/ufshci.4
index 47992440134f..9ea642fa31ee 100644
--- a/share/man/man4/ufshci.4
+++ b/share/man/man4/ufshci.4
@@ -7,7 +7,7 @@
.\"
.\" Author: Jaeyoon Choi <j_yoon.choi@samsung.com>
.\"
-.Dd July 17, 2025
+.Dd October 23, 2026
.Dt UFSHCI 4
.Os
.Sh NAME
@@ -182,6 +182,18 @@ nodes are currently implemented:
(R) Number of trackers in the UTP transfer queue.
.It Va dev.ufshci.0.ioq.0.num_entries
(R) Number of entries in the UTP transfer queue.
+.It Va dev.ufshci.0.force_reset
+(RW) Write a non-zero value to reset the controller now.
+This is a debug aid for exercising the recovery path.
+.It Va dev.ufshci.0.drop_next_ios
+(RW) Number of I/O requests whose doorbell the driver drops, so that they
+time out and drive the recovery path.
+This is a debug aid.
+.It Va dev.ufshci.0.drop_next_admins
+(RW) Number of admin requests whose doorbell the driver drops.
+The driver waits for its own admin requests while it brings the
+controller up, so this stalls a reset the way a dead link does.
+This is a debug aid.
.El
.Sh SEE ALSO
.Xr cam 4 ,
diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index 58f101ea27f6..99b29c637e33 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -23,6 +23,8 @@ ufshci_ctrlr_fail(struct ufshci_controller *ctrlr)
if (atomic_swap_32(&ctrlr->is_failed, 1) != 0)
return;
+ ufshci_printf(ctrlr, "controller failed, rejecting new requests\n");
+
ufshci_req_queue_fail(ctrlr, &ctrlr->task_mgmt_req_queue);
ufshci_req_queue_fail(ctrlr, &ctrlr->transfer_req_queue);
}
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index d3a02f45f271..872518ee30b3 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -412,6 +412,10 @@ struct ufshci_controller {
uint32_t max_rx_lanes;
uint32_t is_failed;
+
+ /* Debug aids: requests left to drop, per I/O and admin. */
+ uint32_t debug_drop_ios;
+ uint32_t debug_drop_admins;
};
#define ufshci_mmio_offsetof(reg) offsetof(struct ufshci_registers, reg)
diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
index add399e98ed2..ee73a0ca5462 100644
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -681,6 +681,20 @@ ufshci_req_queue_timeout(void *arg)
}
}
+static bool
+ufshci_req_queue_debug_drop(struct ufshci_controller *ctrlr,
+ struct ufshci_request *req)
+{
+ uint32_t *count;
+
+ count = req->is_admin ? &ctrlr->debug_drop_admins :
+ &ctrlr->debug_drop_ios;
+ if (*count == 0)
+ return (false);
+ (*count)--;
+ return (true);
+}
+
/*
* Submit the tracker to the hardware.
*/
@@ -757,6 +771,19 @@ ufshci_req_queue_submit_tracker(struct ufshci_req_queue *req_queue,
tr->slot_state = UFSHCI_SLOT_STATE_SCHEDULED;
+ /*
+ * Debug aid: leave the request for the watchdog to find. The
+ * aborts the watchdog then sends must go out, so the task
+ * management queue is never dropped.
+ */
+ if (!req_queue->is_task_mgmt &&
+ __predict_false(ufshci_req_queue_debug_drop(ctrlr, req))) {
+ ufshci_printf(ctrlr,
+ "debug: dropped the doorbell for task tag %u\n",
+ req->request_upiu.header.task_tag);
+ return;
+ }
+
/* Ring the doorbell */
req_queue->qops.ring_doorbell(ctrlr, tr);
}
diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c
index a113e951798e..a2f71ab62b05 100644
--- a/sys/dev/ufshci/ufshci_sysctl.c
+++ b/sys/dev/ufshci/ufshci_sysctl.c
@@ -123,6 +123,26 @@ ufshci_sysctl_ahit(SYSCTL_HANDLER_ARGS)
return (sysctl_handle_64(oidp, &timer, 0, req));
}
+/*
+ * Debug aid. Reset the controller on demand so a test can drive the
+ * recovery path without waiting for a real failure.
+ */
+static int
+ufshci_sysctl_force_reset(SYSCTL_HANDLER_ARGS)
+{
+ struct ufshci_controller *ctrlr = arg1;
+ int error, val = 0;
+
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+
+ if (val != 0)
+ ufshci_ctrlr_reset(ctrlr);
+
+ return (0);
+}
+
static void
ufshci_sysctl_initialize_queue(struct ufshci_hw_queue *hwq,
struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree)
@@ -262,6 +282,21 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr)
0, ufshci_sysctl_timeout_period, "IU",
"Timeout period for I/O queues (in seconds)");
+ SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "force_reset",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, ctrlr, 0,
+ ufshci_sysctl_force_reset, "I",
+ "Reset the controller now (debug aid)");
+
+ SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "drop_next_ios",
+ CTLFLAG_RW, &ctrlr->debug_drop_ios, 0,
+ "Drop the doorbell for this many I/O requests so they time out "
+ "(debug aid)");
+
+ SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "drop_next_admins",
+ CTLFLAG_RW, &ctrlr->debug_drop_admins, 0,
+ "Drop the doorbell for this many admin requests so the driver's "
+ "own bring-up stalls (debug aid)");
+
SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cmds",
CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0,
ufshci_sysctl_num_cmds, "IU", "Number of commands submitted");