Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 01 Dec 2025 06:23:22 +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: ba963776199f - main - cam/scsi: Support well known logical unit
Message-ID:  <692d345a.fdf1.6bbf87e1@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=ba963776199f84775388a03d072121bf93707020

commit ba963776199f84775388a03d072121bf93707020
Author:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2025-12-01 04:38:52 +0000
Commit:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2025-12-01 04:40:31 +0000

    cam/scsi: Support well known logical unit
    
    This patch adds an additional state to probe well-known logical units
    before probing normal logical units.
    
    Reviewed by:            imp (mentor)
    Sponsored by:           Samsung Electronics
    Differential Revision:  https://reviews.freebsd.org/D53920
---
 sys/cam/cam_ccb.h          |   1 +
 sys/cam/cam_xpt.c          |   1 +
 sys/cam/cam_xpt_internal.h |   1 +
 sys/cam/scsi/scsi_all.h    |   2 +-
 sys/cam/scsi/scsi_xpt.c    | 239 +++++++++++++++++++++++++++++----------------
 5 files changed, 161 insertions(+), 83 deletions(-)

diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 1f110686a658..19f18f36b8c9 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -614,6 +614,7 @@ typedef enum {
 } 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_xpt.c b/sys/cam/cam_xpt.c
index a11b688c4456..ecf06045ed90 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -4682,6 +4682,7 @@ xpt_alloc_target(struct cam_eb *bus, target_id_t target_id)
 	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
index 5a812e6e7d20..73f50895ee74 100644
--- a/sys/cam/cam_xpt_internal.h
+++ b/sys/cam/cam_xpt_internal.h
@@ -169,6 +169,7 @@ struct cam_et {
 	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
index b6fb66beefcd..e50974edac86 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -3057,7 +3057,7 @@ struct scsi_report_luns_data {
 	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];
 };
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index bef35243af98..d0c170867b97 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -130,6 +130,7 @@ typedef enum {
 	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 @@ static char *probe_action_text[] = {
 	"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 int       proberequestbackoff(struct cam_periph *periph,
 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 @@ again:
 			     /*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 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
 	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 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
 	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 @@ out:
 				    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 @@ out:
 			    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 @@ out:
 		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 @@ out:
 			 * 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 @@ out:
 		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 @@ probe_device_check:
 
 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 @@ scsi_find_quirk(struct cam_ed *device)
 	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 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
 
 		/* 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 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
 		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 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
 
 		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;
+				}
 			}
 		}
 


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?692d345a.fdf1.6bbf87e1>