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