git: 1066d5e15f08 - main - ufshci: tell CAM when the controller is gone for good

From: Jaeyoon Choi <jaeyoon_at_FreeBSD.org>
Date: Tue, 03 Nov 2026 04:33:51 UTC
The branch main has been updated by jaeyoon:

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

commit 1066d5e15f086df9849bab7a95edb69fcbad3310
Author:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2026-11-03 04:25:06 +0000
Commit:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2026-11-03 04:29:45 +0000

    ufshci: tell CAM when the controller is gone for good
    
    When the controller failed for good, CAM was not told, so its disks
    stayed and every command to them failed.
    
    Post AC_LOST_DEVICE from the failure path so CAM removes them.
    
    Reviewed by:            imp
    Sponsored by:           Samsung Electronics
    Differential Revision:  https://reviews.freebsd.org/D61120
---
 sys/dev/ufshci/ufshci_ctrlr.c   |  2 ++
 sys/dev/ufshci/ufshci_private.h |  1 +
 sys/dev/ufshci/ufshci_sim.c     | 19 +++++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index 0f44c6e04991..e37764f874b9 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -27,6 +27,8 @@ ufshci_ctrlr_fail(struct ufshci_controller *ctrlr)
 
 	ufshci_req_queue_fail(ctrlr, &ctrlr->task_mgmt_req_queue);
 	ufshci_req_queue_fail(ctrlr, &ctrlr->transfer_req_queue);
+
+	ufshci_sim_controller_failed(ctrlr);
 }
 
 /* Some controllers require a reinit after switching to the max gear. */
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index 110d8a7757ca..69ff9c7f8f51 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -448,6 +448,7 @@ uint8_t ufshci_sim_translate_scsi_to_ufs_lun(lun_id_t scsi_lun);
 uint64_t ufshci_sim_translate_ufs_to_scsi_lun(uint8_t ufs_lun);
 int ufshci_sim_attach(struct ufshci_controller *ctrlr);
 void ufshci_sim_detach(struct ufshci_controller *ctrlr);
+void ufshci_sim_controller_failed(struct ufshci_controller *ctrlr);
 void ufshci_sim_release_wlun_periph(struct ufshci_controller *ctrlr);
 struct cam_periph *ufshci_sim_find_periph(struct ufshci_controller *ctrlr,
     uint8_t wlun);
diff --git a/sys/dev/ufshci/ufshci_sim.c b/sys/dev/ufshci/ufshci_sim.c
index 848fa753428e..edbb4930cb78 100644
--- a/sys/dev/ufshci/ufshci_sim.c
+++ b/sys/dev/ufshci/ufshci_sim.c
@@ -423,6 +423,25 @@ ufshci_sim_release_wlun_periph(struct ufshci_controller *ctrlr)
 	}
 }
 
+void
+ufshci_sim_controller_failed(struct ufshci_controller *ctrlr)
+{
+	/* Attach may fail before the path is set up. */
+	if (ctrlr->ufshci_path == NULL)
+		return;
+
+	/*
+	 * Hand the loss to CAM. The event goes to every periph on the
+	 * devices under the path, where cam_periph_async() invalidates
+	 * each one, so da(4) detaches and the disk node goes away rather
+	 * than pointing at a controller that answers nothing. The path
+	 * stored at attach covers the whole bus, so one post reaches
+	 * every logical unit. xpt_async clones the path, so the stored
+	 * one survives the call.
+	 */
+	xpt_async(AC_LOST_DEVICE, ctrlr->ufshci_path, NULL);
+}
+
 void
 ufshci_sim_detach(struct ufshci_controller *ctrlr)
 {