The branch main has been updated by jaeyoon:

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

commit ba963776199f84775388a03d072121bf93707020
Author:     Jaeyoon Choi <[email protected]>
AuthorDate: 2025-12-01 04:38:52 +0000
Commit:     Jaeyoon Choi <[email protected]>
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;
+                               }
                        }
                }
 

Reply via email to