Page MenuHomeFreeBSD

D53375.1775915715.diff
No OneTemporary

Size
25 KB
Referenced Files
None
Subscribers
None

D53375.1775915715.diff

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

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)

Event Timeline