Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/scsipi Try REPORT LUNS command to enumerate logical ...



details:   https://anonhg.NetBSD.org/src/rev/24ee1129f568
branches:  trunk
changeset: 359853:24ee1129f568
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Thu Jan 27 18:37:02 2022 +0000

description:
Try REPORT LUNS command to enumerate logical units.

diffstat:

 sys/dev/scsipi/scsi_spc.h |   26 +++++++++-
 sys/dev/scsipi/scsiconf.c |  122 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 145 insertions(+), 3 deletions(-)

diffs (209 lines):

diff -r d74046fef7dc -r 24ee1129f568 sys/dev/scsipi/scsi_spc.h
--- a/sys/dev/scsipi/scsi_spc.h Thu Jan 27 18:07:27 2022 +0000
+++ b/sys/dev/scsipi/scsi_spc.h Thu Jan 27 18:37:02 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: scsi_spc.h,v 1.6 2019/03/28 10:44:29 kardel Exp $      */
+/*     $NetBSD: scsi_spc.h,v 1.7 2022/01/27 18:37:02 jakllsch Exp $    */
 
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -404,6 +404,30 @@
 /*
  * REPORT LUNS
  */
+#define SCSI_REPORT_LUNS               0xa0
+
+struct scsi_report_luns {
+       uint8_t opcode;
+       uint8_t reserved1;
+       uint8_t selectreport;
+#define SELECTREPORT_NORMAL            0x00
+#define SELECTREPORT_WELLKNOWN         0x01
+#define SELECTREPORT_ALL               0x02
+       uint8_t reserved3[3];
+       uint8_t alloclen[4];
+       uint8_t reserved10;
+       uint8_t control;
+};
+
+struct scsi_report_luns_header {
+       uint8_t length[4];              /* in bytes, not including header */
+       uint8_t _res4[4];
+                                       /* followed by array of: */
+};
+
+struct scsi_report_luns_lun {
+       uint8_t lun[8];
+};
 
 /*
  * MAINTENANCE_IN[REPORT SUPPORTED OPERATION CODES]
diff -r d74046fef7dc -r 24ee1129f568 sys/dev/scsipi/scsiconf.c
--- a/sys/dev/scsipi/scsiconf.c Thu Jan 27 18:07:27 2022 +0000
+++ b/sys/dev/scsipi/scsiconf.c Thu Jan 27 18:37:02 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: scsiconf.c,v 1.293 2021/12/21 22:53:21 riastradh Exp $ */
+/*     $NetBSD: scsiconf.c,v 1.294 2022/01/27 18:37:02 jakllsch Exp $  */
 
 /*-
  * Copyright (c) 1998, 1999, 2004 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scsiconf.c,v 1.293 2021/12/21 22:53:21 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scsiconf.c,v 1.294 2022/01/27 18:37:02 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -64,6 +64,7 @@
 #include <sys/scsiio.h>
 #include <sys/queue.h>
 #include <sys/atomic.h>
+#include <sys/kmem.h>
 
 #include <dev/scsipi/scsi_all.h>
 #include <dev/scsipi/scsipi_all.h>
@@ -370,6 +371,109 @@
        return 0;
 }
 
+static int
+lun_compar(const void *a, const void *b)
+{
+       const uint16_t * const la = a, * const lb = b;
+
+       if (*la < *lb)
+               return -1;
+       if (*la > *lb)
+               return 1;
+       return 0;
+}
+
+static int
+scsi_report_luns(struct scsibus_softc *sc, int target,
+    uint16_t ** const luns, size_t *nluns)
+{
+       struct scsi_report_luns replun;
+       struct scsi_report_luns_header *rlr;
+       struct scsi_report_luns_lun *lunp;
+
+       struct scsipi_channel *chan = sc->sc_channel;
+       struct scsipi_inquiry_data inqbuf;
+       struct scsipi_periph *periph;
+       uint16_t tmp;
+
+       int error;
+       size_t i, rlrlen;
+
+       periph = scsipi_alloc_periph(M_WAITOK);
+       periph->periph_channel = chan;
+       periph->periph_switch = &scsi_probe_dev;
+
+       periph->periph_target = target;
+       periph->periph_lun = 0;
+       periph->periph_quirks = chan->chan_defquirks;
+
+       if ((error = scsipi_inquire(periph, &inqbuf,
+           XS_CTL_DISCOVERY | XS_CTL_SILENT)))
+               goto end2;
+       periph->periph_version = inqbuf.version & SID_ANSII;
+       if (periph->periph_version < 3) {
+               error = ENOTSUP;
+               goto end2;
+       }
+
+       rlrlen = sizeof(*rlr) + sizeof(*lunp) * 1;
+
+again:
+       rlr = kmem_zalloc(rlrlen, KM_SLEEP);
+
+       replun.opcode = SCSI_REPORT_LUNS;
+       replun.selectreport = SELECTREPORT_NORMAL;
+       _lto4b(rlrlen, replun.alloclen);
+
+       error = scsipi_command(periph, (void *)&replun, sizeof(replun),
+           (void *)rlr, rlrlen, SCSIPIRETRIES, 10000, NULL,
+           XS_CTL_DATA_IN | XS_CTL_DISCOVERY | XS_CTL_SILENT);
+       if (error)
+               goto end;
+
+       if (sizeof(*rlr) + _4btol(rlr->length) > rlrlen &&
+           sizeof(*rlr) + _4btol(rlr->length) <= 32) {
+               const size_t old_rlrlen = rlrlen;
+               rlrlen = sizeof(*rlr) + uimin(_4btol(rlr->length),
+                   16383 * sizeof(*lunp));
+               kmem_free(rlr, old_rlrlen);
+               rlr = NULL;
+               goto again;
+       }
+
+       KASSERT(nluns != NULL);
+       *nluns = (rlrlen - sizeof(*rlr)) / sizeof(*lunp);
+
+       KASSERT(luns != NULL);
+       *luns = kmem_alloc(*nluns * sizeof(**luns), KM_SLEEP);
+
+       for (i = 0; i < *nluns; i++) {
+               lunp = &((struct scsi_report_luns_lun *)&rlr[1])[i];
+               switch (lunp->lun[0] & 0xC0) {
+               default:
+                       scsi_print_addr(periph);
+                       printf("LUN %016"PRIx64" ignored\n", _8btol(lunp->lun));
+                       (*luns)[i] = 0;
+                       break;
+               case 0x40:
+                       (*luns)[i] = _2btol(&lunp->lun[0]) & 0x3FFF;
+                       break;
+               case 0x00:
+                       (*luns)[i] = _2btol(&lunp->lun[0]) & 0x00FF;
+                       break;
+               }
+       }
+
+       kheapsort(*luns, *nluns, sizeof(**luns), lun_compar, &tmp);
+
+end:
+       if (rlr)
+               kmem_free(rlr, rlrlen);
+end2:
+       scsipi_free_periph(periph);
+       return error;
+}
+
 /*
  * Probe the requested scsi bus. It must be already set up.
  * target and lun optionally narrow the search if not -1
@@ -405,11 +509,19 @@
         */
        scsipi_adapter_ioctl(chan, SCBUSIOLLSCAN, NULL, 0, curproc);
 
+       uint16_t *luns;
+       size_t nluns;
+
        if ((error = scsipi_adapter_addref(chan->chan_adapter)) != 0)
                goto ret;
        for (target = mintarget; target <= maxtarget; target++) {
                if (target == chan->chan_id)
                        continue;
+               if (scsi_report_luns(sc, target, &luns, &nluns) == 0) {
+                       for (size_t i = 0; i < nluns; i++)
+                               if (luns[i] >= minlun && luns[i] <= maxlun)
+                                       scsi_probe_device(sc, target, luns[i]);
+               } else
                for (lun = minlun; lun <= maxlun; lun++) {
                        /*
                         * See if there's a device present, and configure it.
@@ -419,6 +531,12 @@
                        /* otherwise something says we should look further */
                }
 
+               if (luns != NULL) {
+                       kmem_free(luns, sizeof(*luns) * nluns);
+                       luns = NULL;
+                       nluns = 0;
+               }
+
                /*
                 * Now that we've discovered all of the LUNs on this
                 * I_T Nexus, update the xfer mode for all of them



Home | Main Index | Thread Index | Old Index