Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144634752
D53375.1775915715.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D53375.1775915715.diff
View Options
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -1024,6 +1024,7 @@
/* start/stop */ startstop,
/* load_eject */ loadeject,
/* immediate */ 0,
+ /* power_condition */ SSS_PC_START_VALID,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ timeout ? timeout : 120000);
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -614,6 +614,7 @@
} pi_tmflag;
typedef enum {
+ PIM_WLUNS = 0x400,/* Well known LUNs supported */
PIM_ATA_EXT = 0x200,/* ATA requests can understand ata_ext requests */
PIM_EXTLUNS = 0x100,/* 64bit extended LUNs supported */
PIM_SCANHILO = 0x80, /* Bus scans from high ID to low ID */
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -1791,6 +1791,7 @@
/*start*/TRUE,
/*load/eject*/le,
/*immediate*/FALSE,
+ /*power_condition*/SSS_PC_START_VALID,
SSD_FULL_SIZE,
/*timeout*/50000);
break;
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -4680,6 +4680,7 @@
target->refcount = 1;
target->generation = 0;
target->luns = NULL;
+ target->wluns = NULL;
mtx_init(&target->luns_mtx, "CAM LUNs lock", NULL, MTX_DEF);
timevalclear(&target->last_reset);
/*
diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h
--- a/sys/cam/cam_xpt_internal.h
+++ b/sys/cam/cam_xpt_internal.h
@@ -169,6 +169,7 @@
struct timeval last_reset;
u_int rpl_size;
struct scsi_report_luns_data *luns;
+ struct scsi_report_luns_data *wluns;
struct mtx luns_mtx; /* Protection for luns field. */
};
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -3057,7 +3057,7 @@
uint8_t length[4]; /* length of LUN inventory, in bytes */
uint8_t reserved[4]; /* unused */
/*
- * LUN inventory- we only support the type zero form for now.
+ * LUN inventory- we only support type zero and extended (well-known) formats.
*/
struct scsi_report_luns_lundata luns[0];
};
@@ -4326,7 +4326,8 @@
void scsi_start_stop(struct ccb_scsiio *csio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
uint8_t tag_action, int start, int load_eject,
- int immediate, uint8_t sense_len, uint32_t timeout);
+ int immediate, uint8_t power_condition, uint8_t sense_len,
+ uint32_t timeout);
void scsi_read_attribute(struct ccb_scsiio *csio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
uint8_t tag_action, uint8_t service_action,
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -8984,7 +8984,8 @@
scsi_start_stop(struct ccb_scsiio *csio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
uint8_t tag_action, int start, int load_eject,
- int immediate, uint8_t sense_len, uint32_t timeout)
+ int immediate, uint8_t power_condition, uint8_t sense_len,
+ uint32_t timeout)
{
struct scsi_start_stop_unit *scsi_cmd;
int extra_flags = 0;
@@ -8999,6 +9000,7 @@
}
if (load_eject != 0)
scsi_cmd->how |= SSS_LOEJ;
+ scsi_cmd->how |= power_condition;
if (immediate != 0)
scsi_cmd->byte2 |= SSS_IMMED;
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -3406,6 +3406,7 @@
/* start */ TRUE,
/* load_eject */ load,
/* immediate */ FALSE,
+ /* power_condition */ SSS_PC_START_VALID,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ 50000);
@@ -3434,6 +3435,7 @@
/* start */ FALSE,
/* load_eject */ eject,
/* immediate */ FALSE,
+ /* power_condition */ SSS_PC_START_VALID,
/* sense_len */ SSD_FULL_SIZE,
/* timeout */ 50000);
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -130,6 +130,7 @@
PROBE_TUR,
PROBE_INQUIRY, /* this counts as DV0 for Basic Domain Validation */
PROBE_FULL_INQUIRY,
+ PROBE_REPORT_WLUNS,
PROBE_REPORT_LUNS,
PROBE_MODE_SENSE,
PROBE_SUPPORTED_VPD_LIST,
@@ -148,6 +149,7 @@
"PROBE_TUR",
"PROBE_INQUIRY",
"PROBE_FULL_INQUIRY",
+ "PROBE_REPORT_WLUNS",
"PROBE_REPORT_LUNS",
"PROBE_MODE_SENSE",
"PROBE_SUPPORTED_VPD_LIST",
@@ -567,7 +569,7 @@
static void probedone(struct cam_periph *periph, union ccb *done_ccb);
static void probe_purge_old(struct cam_path *path,
struct scsi_report_luns_data *new,
- probe_flags flags);
+ probe_flags flags, bool is_wlun);
static void probecleanup(struct cam_periph *periph);
static void scsi_find_quirk(struct cam_ed *device);
static void scsi_scan_bus(struct cam_periph *periph, union ccb *ccb);
@@ -817,6 +819,23 @@
/*timeout*/60 * 1000);
break;
}
+ case PROBE_REPORT_WLUNS:
+ {
+ void *rp;
+
+ rp = malloc(periph->path->target->rpl_size,
+ M_CAMXPT, M_NOWAIT | M_ZERO);
+ if (rp == NULL) {
+ xpt_print(periph->path,
+ "Unable to alloc report wluns storage\n");
+ PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS);
+ goto again;
+ }
+ scsi_report_luns(csio, 5, probedone, MSG_SIMPLE_Q_TAG,
+ RPL_REPORT_WELLKNOWN, rp, periph->path->target->rpl_size,
+ SSD_FULL_SIZE, 60000);
+ break;
+ }
case PROBE_REPORT_LUNS:
{
void *rp;
@@ -1162,6 +1181,7 @@
struct cam_path *path;
struct scsi_inquiry_data *inq_buf;
uint32_t priority;
+ struct ccb_pathinq cpi;
CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
@@ -1169,6 +1189,7 @@
path = done_ccb->ccb_h.path;
priority = done_ccb->ccb_h.pinfo.priority;
cam_periph_assert(periph, MA_OWNED);
+ xpt_path_inq(&cpi, path);
switch (softc->action) {
case PROBE_TUR:
@@ -1235,8 +1256,10 @@
SID_ANSI_REV(inq_buf) > SCSI_REV_SPC2 &&
(SCSI_QUIRK(path->device)->quirks &
CAM_QUIRK_NORPTLUNS) == 0) {
- PROBE_SET_ACTION(softc,
- PROBE_REPORT_LUNS);
+ if (cpi.hba_misc & PIM_WLUNS)
+ PROBE_SET_ACTION(softc, PROBE_REPORT_WLUNS);
+ else
+ PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS);
/*
* Start with room for *one* lun.
*/
@@ -1259,7 +1282,10 @@
SID_ANSI_REV(inq_buf) >= SCSI_REV_SPC2 &&
(SCSI_QUIRK(path->device)->quirks &
CAM_QUIRK_NORPTLUNS) == 0) {
- PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS);
+ if (cpi.hba_misc & PIM_WLUNS)
+ PROBE_SET_ACTION(softc, PROBE_REPORT_WLUNS);
+ else
+ PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS);
periph->path->target->rpl_size = 16;
xpt_release_ccb(done_ccb);
xpt_schedule(periph, priority);
@@ -1296,11 +1322,13 @@
xpt_release_ccb(done_ccb);
break;
}
+ case PROBE_REPORT_WLUNS:
case PROBE_REPORT_LUNS:
{
struct ccb_scsiio *csio;
struct scsi_report_luns_data *lp;
u_int nlun, maxlun;
+ bool is_wlun = softc->action == PROBE_REPORT_WLUNS;
csio = &done_ccb->csio;
@@ -1377,7 +1405,7 @@
* This function will also install the new list
* in the target structure.
*/
- probe_purge_old(path, lp, softc->flags);
+ probe_purge_old(path, lp, softc->flags, is_wlun);
lp = NULL;
}
/* The processing above should either exit via a `goto
@@ -1390,7 +1418,9 @@
if (path->device->flags & CAM_DEV_INQUIRY_DATA_VALID &&
(SID_QUAL(inq_buf) == SID_QUAL_LU_CONNECTED ||
SID_QUAL(inq_buf) == SID_QUAL_LU_OFFLINE)) {
- if (INQ_DATA_TQ_ENABLED(inq_buf))
+ if (is_wlun)
+ PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS);
+ else if (INQ_DATA_TQ_ENABLED(inq_buf))
PROBE_SET_ACTION(softc, PROBE_MODE_SENSE);
else
PROBE_SET_ACTION(softc,
@@ -1815,20 +1845,22 @@
static void
probe_purge_old(struct cam_path *path, struct scsi_report_luns_data *new,
- probe_flags flags)
+ probe_flags flags, bool is_wlun)
{
struct cam_path *tp;
- struct scsi_report_luns_data *old;
+ struct scsi_report_luns_data **luns_data, *old;
u_int idx1, idx2, nlun_old, nlun_new;
lun_id_t this_lun;
uint8_t *ol, *nl;
+ luns_data = is_wlun ? &path->target->wluns : &path->target->luns;
+
if (path->target == NULL) {
return;
}
mtx_lock(&path->target->luns_mtx);
- old = path->target->luns;
- path->target->luns = new;
+ old = *luns_data;
+ *luns_data = new;
mtx_unlock(&path->target->luns_mtx);
if (old == NULL)
return;
@@ -1908,11 +1940,16 @@
device->maxtags = quirk->maxtags;
}
+typedef struct {
+ int lun;
+ int wlun;
+} lun_pair;
+
typedef struct {
union ccb *request_ccb;
struct ccb_pathinq *cpi;
int counter;
- int lunindex[0];
+ lun_pair lunindex[0];
} scsi_scan_bus_info;
static void
@@ -1995,7 +2032,8 @@
/* Save some state for use while we probe for devices */
scan_info = (scsi_scan_bus_info *) malloc(sizeof(scsi_scan_bus_info) +
- (work_ccb->cpi.max_target * sizeof (u_int)), M_CAMXPT, M_ZERO|M_NOWAIT);
+ (work_ccb->cpi.max_target * sizeof(lun_pair)),
+ M_CAMXPT, M_ZERO|M_NOWAIT);
if (scan_info == NULL) {
request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
xpt_free_ccb(work_ccb);
@@ -2080,6 +2118,8 @@
path_id_t path_id;
target_id_t target_id;
lun_id_t lun_id;
+ u_int nwluns;
+ bool need_wlun_scan = false;
oldpath = request_ccb->ccb_h.path;
@@ -2093,89 +2133,124 @@
mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
mtx_lock(mtx);
- mtx_lock(&target->luns_mtx);
- if (target->luns) {
- lun_id_t first;
- u_int nluns = scsi_4btoul(target->luns->length) / 8;
- /*
- * Make sure we skip over lun 0 if it's the first member
- * of the list as we've actually just finished probing
- * it.
- */
- CAM_GET_LUN(target->luns, 0, first);
- if (first == 0 && scan_info->lunindex[target_id] == 0) {
- scan_info->lunindex[target_id]++;
- }
-
- /*
- * Skip any LUNs that the HBA can't deal with.
- */
- while (scan_info->lunindex[target_id] < nluns) {
- if (scan_info->cpi->hba_misc & PIM_EXTLUNS) {
- CAM_GET_LUN(target->luns,
- scan_info->lunindex[target_id],
- lun_id);
- break;
- }
+ if (scan_info->cpi->hba_misc & PIM_WLUNS) {
+ /* Scan Well known logical units */
+ mtx_lock(&target->luns_mtx);
- if (CAM_CAN_GET_SIMPLE_LUN(target->luns,
- scan_info->lunindex[target_id])) {
- CAM_GET_SIMPLE_LUN(target->luns,
- scan_info->lunindex[target_id],
- lun_id);
- break;
- }
-
- scan_info->lunindex[target_id]++;
+ if (target->wluns) {
+ nwluns = scsi_4btoul(target->wluns->length) / 8;
+ if (scan_info->lunindex[target_id].wlun < nwluns)
+ need_wlun_scan = true;
}
- if (scan_info->lunindex[target_id] < nluns) {
+ if (need_wlun_scan) {
+ /*
+ * WLUN uses the Extended WLUN address format, so we can handle all of
+ * them.
+ */
+ CAM_GET_LUN(target->wluns, scan_info->lunindex[target_id].wlun, lun_id);
+
mtx_unlock(&target->luns_mtx);
next_target = 0;
CAM_DEBUG(request_ccb->ccb_h.path,
- CAM_DEBUG_PROBE,
- ("next lun to try at index %u is %jx\n",
- scan_info->lunindex[target_id],
- (uintmax_t)lun_id));
- scan_info->lunindex[target_id]++;
+ CAM_DEBUG_PROBE,
+ ("next wlun to try at index %u is %jx\n",
+ scan_info->lunindex[target_id].wlun,
+ (uintmax_t)lun_id));
+ scan_info->lunindex[target_id].wlun++;
} else {
mtx_unlock(&target->luns_mtx);
- /* We're done with scanning all luns. */
+ /* We're done with scanning all wluns. */
}
- } else {
- mtx_unlock(&target->luns_mtx);
- device = request_ccb->ccb_h.path->device;
- /* Continue sequential LUN scan if: */
- /* -- we have more LUNs that need recheck */
- mtx_lock(&target->bus->eb_mtx);
- nextdev = device;
- while ((nextdev = TAILQ_NEXT(nextdev, links)) != NULL)
- if ((nextdev->flags & CAM_DEV_UNCONFIGURED) == 0)
- break;
- mtx_unlock(&target->bus->eb_mtx);
- if (nextdev != NULL) {
- next_target = 0;
- /* -- stop if CAM_QUIRK_NOLUNS is set. */
- } else if (SCSI_QUIRK(device)->quirks & CAM_QUIRK_NOLUNS) {
- next_target = 1;
- /* -- this LUN is connected and its SCSI version
- * allows more LUNs. */
- } else if ((device->flags & CAM_DEV_UNCONFIGURED) == 0) {
- if (lun_id < (CAM_SCSI2_MAXLUN-1) ||
- CAN_SRCH_HI_DENSE(device))
+ }
+
+ if (!need_wlun_scan) {
+ /* Scan logical units */
+ mtx_lock(&target->luns_mtx);
+ if (target->luns) {
+ lun_id_t first;
+ u_int nluns = scsi_4btoul(target->luns->length) / 8;
+
+ /*
+ * Make sure we skip over lun 0 if it's the first member
+ * of the list as we've actually just finished probing
+ * it.
+ */
+ CAM_GET_LUN(target->luns, 0, first);
+ if (first == 0 && scan_info->lunindex[target_id].lun == 0) {
+ scan_info->lunindex[target_id].lun++;
+ }
+
+ /*
+ * Skip any LUNs that the HBA can't deal with.
+ */
+ while (scan_info->lunindex[target_id].lun < nluns) {
+ if (scan_info->cpi->hba_misc & PIM_EXTLUNS) {
+ CAM_GET_LUN(target->luns,
+ scan_info->lunindex[target_id].lun,
+ lun_id);
+ break;
+ }
+
+ if (CAM_CAN_GET_SIMPLE_LUN(target->luns,
+ scan_info->lunindex[target_id].lun)) {
+ CAM_GET_SIMPLE_LUN(target->luns,
+ scan_info->lunindex[target_id].lun,
+ lun_id);
+ break;
+ }
+
+ scan_info->lunindex[target_id].lun++;
+ }
+
+ if (scan_info->lunindex[target_id].lun < nluns) {
+ mtx_unlock(&target->luns_mtx);
next_target = 0;
- /* -- this LUN is disconnected, its SCSI version
- * allows more LUNs and we guess they may be. */
- } else if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) {
- if (lun_id < (CAM_SCSI2_MAXLUN-1) ||
- CAN_SRCH_HI_SPARSE(device))
+ CAM_DEBUG(request_ccb->ccb_h.path,
+ CAM_DEBUG_PROBE,
+ ("next lun to try at index %u is %jx\n",
+ scan_info->lunindex[target_id].lun,
+ (uintmax_t)lun_id));
+ scan_info->lunindex[target_id].lun++;
+ } else {
+ mtx_unlock(&target->luns_mtx);
+ /* We're done with scanning all luns. */
+ }
+ } else {
+ mtx_unlock(&target->luns_mtx);
+ device = request_ccb->ccb_h.path->device;
+ /* Continue sequential LUN scan if: */
+ /* -- we have more LUNs that need recheck */
+ mtx_lock(&target->bus->eb_mtx);
+ nextdev = device;
+ while ((nextdev = TAILQ_NEXT(nextdev, links)) != NULL)
+ if ((nextdev->flags & CAM_DEV_UNCONFIGURED) == 0)
+ break;
+ mtx_unlock(&target->bus->eb_mtx);
+ if (nextdev != NULL) {
next_target = 0;
- }
- if (next_target == 0) {
- lun_id++;
- if (lun_id > scan_info->cpi->max_lun)
+ /* -- stop if CAM_QUIRK_NOLUNS is set. */
+ } else if (SCSI_QUIRK(device)->quirks & CAM_QUIRK_NOLUNS) {
next_target = 1;
+ /* -- this LUN is connected and its SCSI version
+ * allows more LUNs. */
+ } else if ((device->flags & CAM_DEV_UNCONFIGURED) == 0) {
+ if (lun_id < (CAM_SCSI2_MAXLUN-1) ||
+ CAN_SRCH_HI_DENSE(device))
+ next_target = 0;
+ /* -- this LUN is disconnected, its SCSI version
+ * allows more LUNs and we guess they may be. */
+ } else if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) {
+ if (lun_id < (CAM_SCSI2_MAXLUN-1) ||
+ CAN_SRCH_HI_SPARSE(device))
+ next_target = 0;
+ }
+ if (next_target == 0) {
+ lun_id++;
+ if (lun_id > scan_info->cpi->max_lun)
+ next_target = 1;
+ }
}
}
diff --git a/sys/dev/mpr/mpr_sas_lsi.c b/sys/dev/mpr/mpr_sas_lsi.c
--- a/sys/dev/mpr/mpr_sas_lsi.c
+++ b/sys/dev/mpr/mpr_sas_lsi.c
@@ -1517,6 +1517,7 @@
/*start*/FALSE,
/*load/eject*/0,
/*immediate*/FALSE,
+ /*power_condition*/SSS_PC_START_VALID,
MPR_SENSE_LEN,
/*timeout*/10000);
xpt_action(ccb);
diff --git a/sys/dev/mps/mps_sas_lsi.c b/sys/dev/mps/mps_sas_lsi.c
--- a/sys/dev/mps/mps_sas_lsi.c
+++ b/sys/dev/mps/mps_sas_lsi.c
@@ -1153,6 +1153,7 @@
/*start*/FALSE,
/*load/eject*/0,
/*immediate*/FALSE,
+ /*power_condition*/SSS_PC_START_VALID,
MPS_SENSE_LEN,
/*timeout*/10000);
xpt_action(ccb);
diff --git a/sys/dev/ufshci/ufshci.h b/sys/dev/ufshci/ufshci.h
--- a/sys/dev/ufshci/ufshci.h
+++ b/sys/dev/ufshci/ufshci.h
@@ -335,6 +335,8 @@
uint8_t flags;
};
uint8_t lun;
+#define UFSHCI_UPIU_UNIT_NUMBER_ID_MASK 0x7f
+#define UFSHCI_UPIU_WLUN_ID_MASK 0x80
uint8_t task_tag;
/* dword 1 */
@@ -642,6 +644,14 @@
typedef void (*ufshci_cb_fn_t)(void *, const struct ufshci_completion *, bool);
+/* UFS 4.1, section 10.8.5 "Well Known Logical Unit Defined in UFS" */
+enum ufshci_well_known_luns {
+ UFSHCI_WLUN_REPORT_LUNS = 0x81,
+ UFSHCI_WLUN_BOOT = 0xb0,
+ UFSHCI_WLUN_RPMB = 0xc4,
+ UFSHCI_WLUN_UFS_DEVICE = 0xd0,
+};
+
/*
* UFS Spec 4.1, section 14.1 "UFS Descriptors"
* All descriptors use big-endian byte ordering.
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_pci.c b/sys/dev/ufshci/ufshci_pci.c
--- a/sys/dev/ufshci/ufshci_pci.c
+++ b/sys/dev/ufshci/ufshci_pci.c
@@ -50,7 +50,8 @@
uint32_t quirks;
} pci_ids[] = { { 0x131b36, "QEMU UFS Host Controller", UFSHCI_REF_CLK_19_2MHz,
UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE |
- UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK },
+ UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK |
+ UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS },
{ 0x98fa8086, "Intel Lakefield UFS Host Controller",
UFSHCI_REF_CLK_19_2MHz,
UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE |
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;
};
/*
@@ -266,12 +271,17 @@
8 /* Need to change the number of lanes before changing HS-GEAR. */
#define UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK \
16 /* QEMU does not support Task Management Request */
+#define UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS \
+ 32 /* QEMU does not support Well known logical units*/
uint32_t ref_clk;
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];
@@ -369,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"
@@ -72,6 +74,41 @@
xpt_done(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.
+ */
+uint8_t
+ufshci_sim_translate_scsi_to_ufs_lun(lun_id_t scsi_lun)
+{
+ const int address_format_offset = 8;
+ uint8_t address_format = scsi_lun >> address_format_offset;
+
+ /* Well known logical unit */
+ if (((address_format & RPL_LUNDATA_ATYP_MASK) ==
+ RPL_LUNDATA_ATYP_EXTLUN) &&
+ ((address_format & RPL_LUNDATA_EXT_EAM_MASK) ==
+ RPL_LUNDATA_EXT_EAM_WK))
+ return ((scsi_lun & UFSHCI_UPIU_UNIT_NUMBER_ID_MASK) |
+ UFSHCI_UPIU_WLUN_ID_MASK);
+
+ /* Logical unit */
+ 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)
{
@@ -129,7 +166,8 @@
upiu->header.trans_type = UFSHCI_UPIU_TRANSACTION_CODE_COMMAND;
upiu->header.operational_flags = is_write ? UFSHCI_OPERATIONAL_FLAG_W :
UFSHCI_OPERATIONAL_FLAG_R;
- upiu->header.lun = csio->ccb_h.target_lun;
+ upiu->header.lun = ufshci_sim_translate_scsi_to_ufs_lun(
+ csio->ccb_h.target_lun);
upiu->header.cmd_set_type = UFSHCI_COMMAND_SET_TYPE_SCSI;
upiu->expected_data_transfer_length = htobe32(payload_len);
@@ -208,11 +246,15 @@
return;
case XPT_PATH_INQ: {
struct ccb_pathinq *cpi = &ccb->cpi;
+ uint32_t need_scan_wluns = 0;
+
+ if (!(ctrlr->quirks & UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS))
+ need_scan_wluns = PIM_WLUNS;
cpi->version_num = 1;
cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
cpi->target_sprt = 0;
- cpi->hba_misc = PIM_UNMAPPED | PIM_NO_6_BYTE;
+ cpi->hba_misc = need_scan_wluns | PIM_UNMAPPED | PIM_NO_6_BYTE;
cpi->hba_eng_cnt = 0;
cpi->max_target = 0;
cpi->max_lun = ctrlr->max_lun_count;
@@ -369,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
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 11, 1:55 PM (15 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28325274
Default Alt Text
D53375.1775915715.diff (25 KB)
Attached To
Mode
D53375: cam/scsi, ufshci: Add Well-known LUN Probing
Attached
Detach File
Event Timeline
Log In to Comment