summaryrefslogtreecommitdiff
path: root/sys/scsi
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2006-07-23 14:34:56 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2006-07-23 14:34:56 +0000
commit9d1d459f5a3798c7c060e7d6e2f3c5503f15be3a (patch)
treef306e603cb9567e0dd67eb9759c3aee4aa9b29d2 /sys/scsi
parentc533cbd1d5bbf4ffa0c3b15ace88015a9c0a10cf (diff)
Use REPORT LUNS to get the list of LUNs to probe. If such a list is
obtained probe the LUNs given without checking for duplicate INQUIRY data. For non-USB, non-ATAPI, devices claiming to be SCSI-3 compliant. And the target must have something attached at LUN 0. If REPORT LUNS can't be used or isn't supported, the old scan process is used. Fixes Fibre Channel and SCSI enclosure devices that provide identical INQUIRY data for all LUNs and were thus being misprobed as having only LUN 0. Tested by Bob Kitella, dlg@, beck@. Suggestions from deraadt@. ok dlg@ beck@
Diffstat (limited to 'sys/scsi')
-rw-r--r--sys/scsi/scsi_all.h29
-rw-r--r--sys/scsi/scsi_base.c26
-rw-r--r--sys/scsi/scsiconf.c52
-rw-r--r--sys/scsi/scsiconf.h4
4 files changed, 102 insertions, 9 deletions
diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h
index 7b2bde2bfba..cbb02a0bd0c 100644
--- a/sys/scsi/scsi_all.h
+++ b/sys/scsi/scsi_all.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_all.h,v 1.35 2006/05/11 00:45:59 krw Exp $ */
+/* $OpenBSD: scsi_all.h,v 1.36 2006/07/23 14:34:55 krw Exp $ */
/* $NetBSD: scsi_all.h,v 1.10 1996/09/12 01:57:17 thorpej Exp $ */
/*
@@ -156,6 +156,19 @@ struct scsi_prevent {
#define PR_PREVENT 0x01
#define PR_ALLOW 0x00
+struct scsi_report_luns {
+ u_int8_t opcode;
+ u_int8_t unused;
+ u_int8_t selectreport;
+#define REPORT_NORMAL 0x00
+#define REPORT_WELLKNOWN 0x01
+#define REPORT_ALL 0x02
+ u_int8_t unused2[3];
+ u_int8_t length[4];
+ u_int8_t unused4;
+ u_int8_t control;
+};
+
/*
* Opcodes
*/
@@ -176,6 +189,7 @@ struct scsi_prevent {
#define CHANGE_DEFINITION 0x40
#define MODE_SELECT_BIG 0x55
#define MODE_SENSE_BIG 0x5a
+#define REPORT_LUNS 0xa0
/*
* Sort of an extra one, for SCSI_RESET.
@@ -344,6 +358,19 @@ union scsi_mode_sense_buf {
u_char buf[255]; /* 256 bytes breaks some devices. */
} __packed; /* Ensure sizeof() is 255! */
+struct scsi_report_luns_data {
+ u_int8_t length[4]; /* length of LUN inventory, in bytes */
+ u_int8_t reserved[4]; /* unused */
+ /*
+ * LUN inventory- we only support the type zero form for now.
+ */
+#define RPL_LUNDATA_SIZE 8 /* Bytes per lun */
+ struct {
+ u_int8_t lundata[RPL_LUNDATA_SIZE];
+ } luns[256]; /* scsi_link->luns is u_int8_t. */
+};
+#define RPL_LUNDATA_T0LUN 1 /* Type 0 LUN is in lundata[1] */
+
/*
* SPI status information unit. See section 14.3.5 of SPI-3.
*/
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index 12deb79a5e5..677af8c7aa9 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_base.c,v 1.109 2006/07/22 18:44:28 krw Exp $ */
+/* $OpenBSD: scsi_base.c,v 1.110 2006/07/23 14:34:55 krw Exp $ */
/* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */
/*
@@ -604,6 +604,30 @@ scsi_mode_select_big(struct scsi_link *sc_link, int byte2,
return (error);
}
+int
+scsi_report_luns(struct scsi_link *sc_link, int selectreport,
+ struct scsi_report_luns_data *data, u_int32_t datalen, int flags,
+ int timeout)
+{
+ struct scsi_report_luns scsi_cmd;
+ int error;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(data, datalen);
+
+ scsi_cmd.opcode = REPORT_LUNS;
+ scsi_cmd.selectreport = selectreport;
+ _lto4b(datalen, scsi_cmd.length);
+
+ error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
+ sizeof(scsi_cmd), (u_char *)data, datalen, 4, timeout, NULL,
+ flags | SCSI_DATA_IN);
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_report_luns: error = %d\n", error));
+
+ return (error);
+}
+
/*
* This routine is called by the scsi interrupt when the transfer is complete.
*/
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
index 8e602244f8d..3f55b00f4c7 100644
--- a/sys/scsi/scsiconf.c
+++ b/sys/scsi/scsiconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.c,v 1.109 2006/07/22 18:25:42 krw Exp $ */
+/* $OpenBSD: scsiconf.c,v 1.110 2006/07/23 14:34:55 krw Exp $ */
/* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */
/*
@@ -217,9 +217,11 @@ scsi_probe_busses(int bus, int target, int lun)
int
scsi_probe_bus(int bus, int target, int lun)
{
+ struct scsi_report_luns_data *data = NULL;
struct scsibus_softc *scsi;
+ struct scsi_link *sc_link;
u_int16_t scsi_addr;
- int maxtarget, mintarget, maxlun, minlun;
+ int i, luncount, maxtarget, mintarget, maxlun, minlun;
if (bus < 0 || bus >= scsibus_cd.cd_ndevs)
return (ENXIO);
@@ -252,17 +254,55 @@ scsi_probe_bus(int bus, int target, int lun)
else
minlun = lun;
}
-
+
+ data = malloc(sizeof *data, M_TEMP, M_NOWAIT);
+
for (target = mintarget; target <= maxtarget; target++) {
if (target == scsi_addr)
continue;
-
- for (lun = minlun; lun <= maxlun; lun++) {
+ if (scsi_probedev(scsi, target, 0) == EINVAL)
+ continue;
+
+ sc_link = scsi->sc_link[target][0];
+ if (sc_link != NULL && data != NULL &&
+ (sc_link->flags & (SDEV_UMASS | SDEV_ATAPI)) == 0 &&
+ (sc_link->inqdata.version & SID_ANSII) > 2) {
+ scsi_report_luns(sc_link, REPORT_NORMAL, data,
+ sizeof *data, scsi_autoconf | SCSI_SILENT |
+ SCSI_IGNORE_ILLEGAL_REQUEST |
+ SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE,
+ 10000);
+ /*
+ * XXX In theory we should check if data is full, which
+ * would indicate it needs to be enlarged and REPORT
+ * LUNS tried again. Solaris tries up to 3 times with
+ * larger sizes for data.
+ */
+ luncount = _4btol(data->length) / RPL_LUNDATA_SIZE;
+ for (i = 0; i < luncount; i++) {
+ if (data->luns[i].lundata[0] != 0)
+ continue;
+ lun = data->luns[i].lundata[RPL_LUNDATA_T0LUN];
+ if (lun == 0 || lun < minlun || lun > maxlun)
+ continue;
+ /* Probe the provided LUN. Don't check LUN 0. */
+ scsi->sc_link[target][0] = NULL;
+ scsi_probedev(scsi, target, lun);
+ scsi->sc_link[target][0] = sc_link;
+ }
+ if (luncount > 0)
+ continue; /* Next target. */
+ }
+
+ /* No LUN list available. Scan entire range. */
+ for (lun = max(minlun, 1); lun <= maxlun; lun++)
if (scsi_probedev(scsi, target, lun) == EINVAL)
break;
- }
}
+ if (data != NULL)
+ free(data, M_TEMP);
+
return (0);
}
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
index 57a320107d0..4d2ef28954c 100644
--- a/sys/scsi/scsiconf.h
+++ b/sys/scsi/scsiconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsiconf.h,v 1.70 2006/07/22 18:03:07 krw Exp $ */
+/* $OpenBSD: scsiconf.h,v 1.71 2006/07/23 14:34:55 krw Exp $ */
/* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */
/*
@@ -338,6 +338,8 @@ int scsi_scsi_cmd(struct scsi_link *, struct scsi_generic *,
int scsi_do_ioctl(struct scsi_link *, dev_t, u_long, caddr_t,
int, struct proc *);
void sc_print_addr(struct scsi_link *);
+int scsi_report_luns(struct scsi_link *, int,
+ struct scsi_report_luns_data *, u_int32_t, int, int);
void show_scsi_xs(struct scsi_xfer *);
void scsi_print_sense(struct scsi_xfer *);