Page MenuHomeFreeBSD

D53923.id167340.diff
No OneTemporary

D53923.id167340.diff

diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -79,12 +79,6 @@
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 @@
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
--- a/sys/dev/ufshci/ufshci_dev.c
+++ b/sys/dev/ufshci/ufshci_dev.c
@@ -455,8 +455,20 @@
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
--- 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 @@
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 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 @@
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
--- 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 @@
* 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 @@
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 @@
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
--- a/sys/dev/ufshci/ufshci_sysctl.c
+++ b/sys/dev/ufshci/ufshci_sysctl.c
@@ -197,6 +197,10 @@
&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",

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 21, 12:29 AM (12 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27102133
Default Alt Text
D53923.id167340.diff (6 KB)

Event Timeline