Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 01 Dec 2025 06:23:26 +0000
From:      Jaeyoon Choi <jaeyoon@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 31407551c3d4 - main - ufshci: Add a check for WLUN during driver initialization
Message-ID:  <692d345e.22563.31bf9335@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by jaeyoon:

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

commit 31407551c3d4d29905f77abddac3fd9b649e166b
Author:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2025-12-01 04:39:49 +0000
Commit:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2025-12-01 04:41:03 +0000

    ufshci: Add a check for WLUN during driver initialization
    
    This patch checks whether wlun is registered as a periph device.
    It also implements a function to issue an SSU.
    
    Reviewed by:            imp (mentor)
    Sponsored by:           Samsung Electronics
    Differential Revision:  https://reviews.freebsd.org/D53923
---
 sys/dev/ufshci/ufshci_ctrlr.c   |  12 ++---
 sys/dev/ufshci/ufshci_dev.c     |  14 ++++-
 sys/dev/ufshci/ufshci_private.h |  14 +++++
 sys/dev/ufshci/ufshci_sim.c     | 114 +++++++++++++++++++++++++++++++++++++++-
 sys/dev/ufshci/ufshci_sysctl.c  |   4 ++
 5 files changed, 150 insertions(+), 8 deletions(-)

diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index 35663b480cfa..1ffa99255088 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -79,12 +79,6 @@ ufshci_ctrlr_start(struct ufshci_controller *ctrlr, bool resetting)
 		return;
 	}
 
-	/* Initialize UFS Power Mode */
-	if (ufshci_dev_init_ufs_power_mode(ctrlr) != 0) {
-		ufshci_ctrlr_fail(ctrlr);
-		return;
-	}
-
 	/* Read Controller Descriptor (Device, Geometry) */
 	if (ufshci_dev_get_descriptor(ctrlr) != 0) {
 		ufshci_ctrlr_fail(ctrlr);
@@ -109,6 +103,12 @@ ufshci_ctrlr_start(struct ufshci_controller *ctrlr, bool resetting)
 		return;
 	}
 
+	/* Initialize UFS Power Mode */
+	if (ufshci_dev_init_ufs_power_mode(ctrlr) != 0) {
+		ufshci_ctrlr_fail(ctrlr);
+		return;
+	}
+
 	TSEXIT();
 }
 
diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c
index 975468e5156f..9696e8ea8091 100644
--- a/sys/dev/ufshci/ufshci_dev.c
+++ b/sys/dev/ufshci/ufshci_dev.c
@@ -455,8 +455,20 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
 int
 ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr)
 {
-	/* TODO: Need to implement */
+	ctrlr->ufs_dev.power_mode_supported = false;
 
+	if (ctrlr->quirks & UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS)
+		return (0);
+
+	ctrlr->ufs_device_wlun_periph = ufshci_sim_find_periph(ctrlr,
+	    UFSHCI_WLUN_UFS_DEVICE);
+	if (ctrlr->ufs_device_wlun_periph == NULL) {
+		ufshci_printf(ctrlr,
+		    "Well-known LUN `UFS Device (0x50)` not found\n");
+		return (0);
+	}
+
+	ctrlr->ufs_dev.power_mode_supported = true;
 	return (0);
 }
 
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index 3cee021880a8..22e77c9b9326 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -31,6 +31,8 @@
 
 #include <machine/bus.h>
 
+#include <cam/cam.h>
+
 #include "ufshci.h"
 
 MALLOC_DECLARE(M_UFSHCI);
@@ -247,6 +249,9 @@ struct ufshci_device {
 	uint32_t wb_user_space_config_option;
 	uint8_t wb_dedicated_lu;
 	uint32_t write_booster_flush_threshold;
+
+	/* Power mode */
+	bool power_mode_supported;
 };
 
 /*
@@ -274,6 +279,9 @@ struct ufshci_controller {
 	struct cam_sim *ufshci_sim;
 	struct cam_path *ufshci_path;
 
+	struct cam_periph *ufs_device_wlun_periph;
+	struct mtx ufs_device_wlun_mtx;
+
 	struct mtx sc_mtx;
 	uint32_t sc_unit;
 	uint8_t sc_name[16];
@@ -371,8 +379,14 @@ void ufshci_completion_poll_cb(void *arg, const struct ufshci_completion *cpl,
     bool error);
 
 /* SIM */
+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);
+struct cam_periph *ufshci_sim_find_periph(struct ufshci_controller *ctrlr,
+    uint8_t wlun);
+int ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start,
+    int pwr_cond, bool immed);
 
 /* Controller */
 int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev);
diff --git a/sys/dev/ufshci/ufshci_sim.c b/sys/dev/ufshci/ufshci_sim.c
index db2e194b699b..0cd691de47e2 100644
--- a/sys/dev/ufshci/ufshci_sim.c
+++ b/sys/dev/ufshci/ufshci_sim.c
@@ -10,9 +10,11 @@
 #include <cam/cam.h>
 #include <cam/cam_ccb.h>
 #include <cam/cam_debug.h>
+#include <cam/cam_periph.h>
 #include <cam/cam_sim.h>
 #include <cam/cam_xpt_sim.h>
 #include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
 
 #include "ufshci_private.h"
 
@@ -76,7 +78,7 @@ ufshci_sim_illegal_request(union ccb *ccb)
  * The SCSI LUN format and the UFS UPIU LUN format are different.
  * This function converts the SCSI LUN format to the UFS UPIU LUN format.
  */
-static uint8_t
+uint8_t
 ufshci_sim_translate_scsi_to_ufs_lun(lun_id_t scsi_lun)
 {
 	const int address_format_offset = 8;
@@ -94,6 +96,19 @@ ufshci_sim_translate_scsi_to_ufs_lun(lun_id_t scsi_lun)
 	return (scsi_lun & UFSHCI_UPIU_UNIT_NUMBER_ID_MASK);
 }
 
+uint64_t
+ufshci_sim_translate_ufs_to_scsi_lun(uint8_t ufs_lun)
+{
+	/* Logical unit */
+	if (!(ufs_lun & UFSHCI_UPIU_WLUN_ID_MASK)) {
+		return ufs_lun;
+	}
+
+	/* Well known logical unit */
+	return (((uint64_t)ufs_lun & ~UFSHCI_UPIU_WLUN_ID_MASK) |
+	    (RPL_LUNDATA_ATYP_EXTLUN | RPL_LUNDATA_EXT_EAM_WK) << 8);
+}
+
 static void
 ufshchi_sim_scsiio(struct cam_sim *sim, union ccb *ccb)
 {
@@ -396,3 +411,100 @@ ufshci_sim_detach(struct ufshci_controller *ctrlr)
 		ctrlr->ufshci_sim = NULL;
 	}
 }
+
+struct cam_periph *
+ufshci_sim_find_periph(struct ufshci_controller *ctrlr, uint8_t wlun)
+{
+	struct cam_path *path;
+	struct cam_periph *periph = NULL;
+	uint64_t scsi_lun;
+	uint64_t timeout;
+
+	scsi_lun = ufshci_sim_translate_ufs_to_scsi_lun(wlun);
+
+	if (xpt_create_path(&path, /*periph*/ NULL,
+		cam_sim_path(ctrlr->ufshci_sim), 0, scsi_lun) != CAM_REQ_CMP) {
+		return NULL;
+	}
+
+	/* Wait for the perip device to be found */
+	timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms);
+
+	while (1) {
+		xpt_path_lock(path);
+		periph = cam_periph_find(path, "pass");
+		xpt_path_unlock(path);
+
+		if (periph) {
+			xpt_free_path(path);
+			break;
+		}
+
+		if (timeout - ticks < 0) {
+			ufshci_printf(ctrlr,
+			    "Failed to find the Well known LUN(0x%x)\n", wlun);
+			break;
+		}
+
+		pause_sbt("ufshci_find_periph", ustosbt(100), 0, C_PREL(1));
+	}
+
+	return periph;
+}
+
+/* This function is called during suspend/resume. */
+int
+ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start,
+    int power_condition, bool immed)
+{
+	struct cam_periph *periph = ctrlr->ufs_device_wlun_periph;
+	union ccb *ccb;
+	int err;
+
+	/* Acquire periph reference */
+	if (periph && cam_periph_acquire(periph) != 0) {
+		periph = NULL;
+	}
+
+	if (periph == NULL) {
+		/* If the periph device does not exist, it will try to find it
+		 * again */
+		periph = ufshci_sim_find_periph(ctrlr,
+		    (uint8_t)UFSHCI_WLUN_UFS_DEVICE);
+		if (periph)
+			ctrlr->ufs_device_wlun_periph = periph;
+	}
+
+	if (periph == NULL) {
+		ufshci_printf(ctrlr,
+		    "Well-known LUN `UFS Device (0x50)` not found\n");
+		return ENODEV;
+	}
+	cam_periph_lock(periph);
+	ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
+	if (!ccb) {
+		cam_periph_unlock(periph);
+		cam_periph_release(periph);
+		return ENOMEM;
+	}
+
+	scsi_start_stop(&ccb->csio,
+	    /*retries*/ 4,
+	    /*cbfcnp*/ NULL,
+	    /*tag_action*/ MSG_SIMPLE_Q_TAG,
+	    /*start*/ start ? 1 : 0,
+	    /*load_eject*/ 0,
+	    /*immediate*/ immed ? 1 : 0,
+	    /*power_condition*/ power_condition, SSD_MIN_SIZE,
+	    ctrlr->device_init_timeout_in_ms);
+
+	ccb->ccb_h.flags |= CAM_DIR_NONE | CAM_DEV_QFRZDIS;
+
+	err = cam_periph_runccb(ccb, NULL, 0, SF_RETRY_UA, NULL);
+
+	cam_periph_unlock(periph);
+	/* Release periph reference */
+	cam_periph_release(periph);
+
+	return (err == 0) ? 0 : EIO;
+}
diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c
index 56bc06b13f3c..3ec4ea935464 100644
--- a/sys/dev/ufshci/ufshci_sysctl.c
+++ b/sys/dev/ufshci/ufshci_sysctl.c
@@ -197,6 +197,10 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr)
 	    &dev->wb_user_space_config_option, 0,
 	    "WriteBooster preserve user space mode");
 
+	SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "power_mode_supported",
+	    CTLFLAG_RD, &dev->power_mode_supported, 0,
+	    "Device power mode support");
+
 	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period",
 	    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period,
 	    0, ufshci_sysctl_timeout_period, "IU",


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?692d345e.22563.31bf9335>