From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 1/6] scsi_debug: use pdt constants
Date: Fri,  6 May 2016 00:40:24 -0400
Message-ID: <1462509629-24282-2-git-send-email-dgilbert@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55598 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1750860AbcEFEkj (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:39 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

Use TYPE_* constants for SCSI peripheral device types instead
of numbers. Further cleanups requested by checkpatch.pl .

Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/scsi_debug.c | 86 +++++++++++++++++++++++++----------------------
 1 file changed, 45 insertions(+), 41 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 6b2d006..fc0246c 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -59,8 +59,8 @@
 #include "scsi_logging.h"
 
 /* make sure inq_product_rev string corresponds to this version */
-#define SCSI_DEBUG_VERSION "1.86"
-static const char *sdebug_version_date = "20160422";
+#define SDEBUG_VERSION "1.86"
+static const char *sdebug_version_date = "20160430";
 
 #define MY_NAME "scsi_debug"
 
@@ -123,7 +123,7 @@ static const char *sdebug_version_date = "20160422";
 #define DEF_OPTS   0
 #define DEF_OPT_BLKS 1024
 #define DEF_PHYSBLK_EXP 0
-#define DEF_PTYPE   0
+#define DEF_PTYPE   TYPE_DISK
 #define DEF_REMOVABLE false
 #define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
 #define DEF_SECTOR_SIZE 512
@@ -137,6 +137,8 @@ static const char *sdebug_version_date = "20160422";
 #define DEF_STRICT 0
 #define JDELAY_OVERRIDDEN -9999
 
+#define SDEBUG_LUN_0_VAL 0
+
 /* bit mask values for sdebug_opts */
 #define SDEBUG_OPT_NOISE		1
 #define SDEBUG_OPT_MEDIUM_ERR		2
@@ -232,7 +234,7 @@ static const char *sdebug_version_date = "20160422";
 
 #define SDEBUG_MAX_PARTS 4
 
-#define SCSI_DEBUG_MAX_CMD_LEN 32
+#define SDEBUG_MAX_CMD_LEN 32
 
 
 struct sdebug_dev_info {
@@ -278,8 +280,8 @@ struct sdebug_scmd_extra_t {
 };
 
 struct opcode_info_t {
-	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff
-				 * for terminating element */
+	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
+				/* for terminating element */
 	u8 opcode;		/* if num_attached > 0, preferred */
 	u16 sa;			/* service action */
 	u32 flags;		/* OR-ed set of SDEB_F_* */
@@ -571,7 +573,7 @@ static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
 static int sdebug_opt_blks = DEF_OPT_BLKS;
 static int sdebug_opts = DEF_OPTS;
 static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
-static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
+static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
 static int sdebug_scsi_level = DEF_SCSI_LEVEL;
 static int sdebug_sector_size = DEF_SECTOR_SIZE;
 static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
@@ -649,7 +651,7 @@ static const int device_qfull_result =
 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
 
 
-static unsigned int scsi_debug_lbp(void)
+static inline unsigned int scsi_debug_lbp(void)
 {
 	return 0 == sdebug_fake_rw &&
 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
@@ -825,7 +827,8 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 			break;
 		case SDEBUG_UA_MICROCODE_CHANGED:
 			mk_sense_buffer(scp, UNIT_ATTENTION,
-				TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
+					TARGET_CHANGED_ASC,
+					MICROCODE_CHANGED_ASCQ);
 			if (sdebug_verbose)
 				cp = "microcode has been changed";
 			break;
@@ -1225,11 +1228,11 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
 	if (! arr)
 		return DID_REQUEUE << 16;
-	have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
+	have_wlun = scsi_is_wlun(scp->device->lun);
 	if (have_wlun)
-		pq_pdt = 0x1e;	/* present, wlun */
-	else if (sdebug_no_lun_0 && (0 == devip->lun))
-		pq_pdt = 0x7f;	/* not present, no device type */
+		pq_pdt = TYPE_WLUN;	/* present, wlun */
+	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
+		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
 	else
 		pq_pdt = (sdebug_ptype & 0x1f);
 	arr[0] = pq_pdt;
@@ -1244,7 +1247,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 		
 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
 		    (devip->channel & 0x7f);
-		if (0 == sdebug_vpd_use_hostno)
+		if (sdebug_vpd_use_hostno == 0)
 			host_no = 0;
 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
 			    (devip->target * 1000) + devip->lun);
@@ -1333,7 +1336,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	arr[3] = 2;    /* response_data_format==2 */
 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
-	if (0 == sdebug_vpd_use_hostno)
+	if (sdebug_vpd_use_hostno == 0)
 		arr[5] = 0x10; /* claim: implicit TGPS */
 	arr[6] = 0x10; /* claim: MultiP */
 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
@@ -1345,9 +1348,9 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
 	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
 	n = 62;
-	if (sdebug_ptype == 0) {
+	if (sdebug_ptype == TYPE_DISK) {
 		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
-	} else if (sdebug_ptype == 1) {
+	} else if (sdebug_ptype == TYPE_TAPE) {
 		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
 	}
 	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
@@ -1534,7 +1537,7 @@ static int resp_report_tgtpgs(struct scsi_cmnd * scp,
 	 * The asymmetric access state is cycled according to the host_id.
 	 */
 	n = 4;
-	if (0 == sdebug_vpd_use_hostno) {
+	if (sdebug_vpd_use_hostno == 0) {
 		arr[n++] = host_no % 3; /* Asymm access state */
 		arr[n++] = 0x0F; /* claim: all states are supported */
 	} else {
@@ -1938,7 +1941,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	subpcode = cmd[3];
 	msense_6 = (MODE_SENSE == cmd[0]);
 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
-	if ((0 == sdebug_ptype) && (0 == dbd))
+	if ((sdebug_ptype == TYPE_DISK) && (dbd == 0))
 		bd_len = llbaa ? 16 : 8;
 	else
 		bd_len = 0;
@@ -1950,9 +1953,9 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	}
 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
 			(devip->target * 1000) - 3;
-	/* set DPOFUA bit for disks */
-	if (0 == sdebug_ptype)
-		dev_spec = 0x10;	/* would be 0x90 if read-only */
+	/* for disks set DPOFUA bit and clear write protect (WP) bit */
+	if (sdebug_ptype == TYPE_DISK)
+		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
 	else
 		dev_spec = 0x0;
 	if (msense_6) {
@@ -3345,7 +3348,7 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
 	spin_lock_irqsave(&queued_arr_lock, iflags);
 	sqcp = &queued_arr[qa_indx];
 	scp = sqcp->a_cmnd;
-	if (unlikely(NULL == scp)) {
+	if (unlikely(scp == NULL)) {
 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
 		pr_err("scp is NULL\n");
 		return;
@@ -3470,11 +3473,11 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
 	if (sdebug_verbose)
 		pr_info("slave_configure <%u %u %u %llu>\n",
 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
-	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
-		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
-	if (NULL == devip) {
+	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
+		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
+	if (devip == NULL) {
 		devip = find_build_dev_info(sdp);
-		if (NULL == devip)
+		if (devip == NULL)
 			return 1;  /* no resources, will be marked offline */
 	}
 	sdp->hostdata = devip;
@@ -3528,7 +3531,7 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
 			sd_dp = sqcp->sd_dp;
 			spin_unlock_irqrestore(&queued_arr_lock,
 					       iflags);
-			if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
+			if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
 				if (sd_dp)
 					hrtimer_cancel(&sd_dp->hrt);
 			} else if (sdebug_jdelay < 0) {
@@ -3565,7 +3568,7 @@ static void stop_all_queued(void)
 			sqcp->a_cmnd = NULL;
 			sd_dp = sqcp->sd_dp;
 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
-			if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
+			if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
 				if (sd_dp)
 					hrtimer_cancel(&sd_dp->hrt);
 			} else if (sdebug_jdelay < 0) {
@@ -3779,8 +3782,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 	if (unlikely(WARN_ON(!cmnd)))
 		return SCSI_MLQUEUE_HOST_BUSY;
 
-	if (unlikely(NULL == devip)) {
-		if (0 == scsi_result)
+	if (unlikely(devip == NULL)) {
+		if (scsi_result == 0)
 			scsi_result = DID_NO_CONNECT << 16;
 		goto respond_in_thread;
 	}
@@ -3841,7 +3844,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 	cmnd->result = scsi_result;
 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 	sd_dp = sqcp->sd_dp;
-	if ((delta_jiff > 0) || (sdebug_ndelay > 0)) {
+	if (delta_jiff > 0 || sdebug_ndelay > 0) {
 		ktime_t kt;
 
 		if (delta_jiff > 0) {
@@ -3938,7 +3941,7 @@ module_param_named(write_same_length, sdebug_write_same_length, int,
 MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI debug adapter driver");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(SCSI_DEBUG_VERSION);
+MODULE_VERSION(SDEBUG_VERSION);
 
 MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
 MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
@@ -3984,9 +3987,10 @@ static char sdebug_info[256];
 
 static const char * scsi_debug_info(struct Scsi_Host * shp)
 {
-	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
-		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
-		sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
+	sprintf(sdebug_info,
+		"scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x",
+		SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb,
+		sdebug_opts);
 	return sdebug_info;
 }
 
@@ -4036,7 +4040,7 @@ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
 		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
 		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
 		"usec_in_jiffy=%lu\n",
-		SCSI_DEBUG_VERSION, sdebug_version_date,
+		SDEBUG_VERSION, sdebug_version_date,
 		sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
 		sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
 		sdebug_max_luns, atomic_read(&sdebug_completions),
@@ -4064,7 +4068,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf,
 {
 	int jdelay, res;
 
-	if ((count > 0) && (1 == sscanf(buf, "%d", &jdelay))) {
+	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
 		res = count;
 		if (sdebug_jdelay != jdelay) {
 			unsigned long iflags;
@@ -4672,7 +4676,7 @@ static int __init scsi_debug_init(void)
 			       (sdebug_sectors_per * sdebug_heads);
 	}
 
-	if (0 == sdebug_fake_rw) {
+	if (sdebug_fake_rw == 0) {
 		fake_storep = vmalloc(sz);
 		if (NULL == fake_storep) {
 			pr_err("out of memory, 1\n");
@@ -5044,8 +5048,8 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 		}
 	}
 	if (unlikely(!(F_SKIP_UA & flags) &&
-		     SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm,
-						      SDEBUG_NUM_UAS))) {
+		     find_first_bit(devip->uas_bm,
+				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
 		errsts = make_ua(scp, devip);
 		if (errsts)
 			goto check_cond;
-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 0/6] scsi_debug: multiple queue support and cleanup
Date: Fri,  6 May 2016 00:40:23 -0400
Message-ID: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55615 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1751036AbcEFEkk (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:40 -0400
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

Changes since v2.5
  - rework the 'add multiple queue support' patch based on
    reviewers' comments to more closely follow the scsi/block mq
    template

Changes since original version:
  - reduce resp_report_luns to reporting 256 LUNs (0 to 255)
    using address_method=0 which is single level peripheral
    device addressing method. Reviewer would like further
    address_methods support which will be presented as a
    separate patch

Primary reason for this patch series is to add multi queue support
modelled on the null_blk driver. Incorporate REPORT LUNS patch from
Tomas Winkler sent in Febrary 2015; trim to a maximum of 256 LUNs
(0 to 255) per target. Add parameter that permits LU names to use
UUIDs (spc5r08.pdf).

The original patch set was made up of 12 patches, the first 7 of
which have already been accepted with minor edits. This patch set
(and "v2.5" before it) represent the second half of the original patch
set. So this patch set is based on the current SCSI maintainers'
repositories. For those who want to try this patch set on lk 4.5
or the linux-stable tree, this patch should be applied before
this series:
   http://sg.danny.cz/sg/p/sdebug_mq_1st_half.patch

Douglas Gilbert (6):
  scsi_debug: use pdt constants
  scsi_debug: rework resp_report_luns
  scsi_debug: add multiple queue support
  scsi_debug: vpd and mode page work
  scsi_debug: uuid for lu name
  scsi_debug: use locally assigned naa

 drivers/scsi/scsi_debug.c | 1156 ++++++++++++++++++++++++++++-----------------
 1 file changed, 730 insertions(+), 426 deletions(-)

-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 2/6] scsi_debug: rework resp_report_luns
Date: Fri,  6 May 2016 00:40:25 -0400
Message-ID: <1462509629-24282-3-git-send-email-dgilbert@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55609 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1750813AbcEFEkk (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:40 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

Based on "[PATH V2] scsi_debug: rework resp_report_luns" patch
sent by Tomas Winkler on Thursday, 26 Feb 2015. His notes:
  1. Remove duplicated boundary checks which simplify the fill-in
     loop
  2. Use more of scsi generic API
Replace fixed length response array a with heap allocation
allowing up to 256 normal LUNs per target.

Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/scsi_debug.c | 135 +++++++++++++++++++++++++++++-----------------
 1 file changed, 87 insertions(+), 48 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index fc0246c..e97ddf0 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -3208,63 +3208,94 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
 }
 
-#define SDEBUG_RLUN_ARR_SZ 256
-
-static int resp_report_luns(struct scsi_cmnd * scp,
-			    struct sdebug_dev_info * devip)
+/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
+ * (W-LUN), the normal Linux scanning logic does not associate it with a
+ * device (e.g. /dev/sg7). The following magic will make that association:
+ *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
+ * where <n> is a host number. If there are multiple targets in a host then
+ * the above will associate a W-LUN to each target. To only get a W-LUN
+ * for target 2, then use "echo '- 2 49409' > scan" .
+ */
+static int resp_report_luns(struct scsi_cmnd *scp,
+			    struct sdebug_dev_info *devip)
 {
+	unsigned char *cmd = scp->cmnd;
 	unsigned int alloc_len;
-	int lun_cnt, i, upper, num, n, want_wlun, shortish;
+	unsigned char select_report;
 	u64 lun;
-	unsigned char *cmd = scp->cmnd;
-	int select_report = (int)cmd[2];
-	struct scsi_lun *one_lun;
-	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
-	unsigned char * max_addr;
+	struct scsi_lun *lun_p;
+	u8 *arr;
+	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
+	unsigned int wlun_cnt;	/* report luns W-LUN count */
+	unsigned int tlun_cnt;	/* total LUN count */
+	unsigned int rlen;	/* response length (in bytes) */
+	int i, res;
 
 	clear_luns_changed_on_target(devip);
-	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
-	shortish = (alloc_len < 4);
-	if (shortish || (select_report > 2)) {
-		mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
+
+	select_report = cmd[2];
+	alloc_len = get_unaligned_be32(cmd + 6);
+
+	if (alloc_len < 4) {
+		pr_err("alloc len too small %d\n", alloc_len);
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
 		return check_condition_result;
 	}
-	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
-	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
-	lun_cnt = sdebug_max_luns;
-	if (1 == select_report)
+
+	switch (select_report) {
+	case 0:		/* all LUNs apart from W-LUNs */
+		lun_cnt = sdebug_max_luns;
+		wlun_cnt = 0;
+		break;
+	case 1:		/* only W-LUNs */
 		lun_cnt = 0;
-	else if (sdebug_no_lun_0 && (lun_cnt > 0))
+		wlun_cnt = 1;
+		break;
+	case 2:		/* all LUNs */
+		lun_cnt = sdebug_max_luns;
+		wlun_cnt = 1;
+		break;
+	case 0x10:	/* only administrative LUs */
+	case 0x11:	/* see SPC-5 */
+	case 0x12:	/* only subsiduary LUs owned by referenced LU */
+	default:
+		pr_debug("select report invalid %d\n", select_report);
+		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
+		return check_condition_result;
+	}
+
+	if (sdebug_no_lun_0 && (lun_cnt > 0))
 		--lun_cnt;
-	want_wlun = (select_report > 0) ? 1 : 0;
-	num = lun_cnt + want_wlun;
-	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
-	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
-	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
-			    sizeof(struct scsi_lun)), num);
-	if (n < num) {
-		want_wlun = 0;
-		lun_cnt = n;
-	}
-	one_lun = (struct scsi_lun *) &arr[8];
-	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
-	for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
-             ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
-	     i++, lun++) {
-		upper = (lun >> 8) & 0x3f;
-		if (upper)
-			one_lun[i].scsi_lun[0] =
-			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
-		one_lun[i].scsi_lun[1] = lun & 0xff;
-	}
-	if (want_wlun) {
-		one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
-		one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
-		i++;
-	}
-	alloc_len = (unsigned char *)(one_lun + i) - arr;
-	return fill_from_dev_buffer(scp, arr,
-				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
+
+	tlun_cnt = lun_cnt + wlun_cnt;
+
+	rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8;
+	arr = vmalloc(rlen);
+	if (!arr) {
+		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+				INSUFF_RES_ASCQ);
+		return check_condition_result;
+	}
+	memset(arr, 0, rlen);
+	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
+		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
+
+	/* luns start at byte 8 in response following the header */
+	lun_p = (struct scsi_lun *)&arr[8];
+
+	/* LUNs use single level peripheral device addressing method */
+	lun = sdebug_no_lun_0 ? 1 : 0;
+	for (i = 0; i < lun_cnt; i++)
+		int_to_scsilun(lun++, lun_p++);
+
+	if (wlun_cnt)
+		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
+
+	put_unaligned_be32(rlen - 8, &arr[0]);
+
+	res = fill_from_dev_buffer(scp, arr, rlen);
+	vfree(arr);
+	return res;
 }
 
 static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
@@ -4303,6 +4334,10 @@ static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
 	bool changed;
 
 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+		if (n > 256) {
+			pr_warn("max_luns can be no more than 256\n");
+			return -EINVAL;
+		}
 		changed = (sdebug_max_luns != n);
 		sdebug_max_luns = n;
 		sdebug_max_tgts_luns();
@@ -4647,6 +4682,10 @@ static int __init scsi_debug_init(void)
 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
 		return -EINVAL;
 	}
+	if (sdebug_max_luns > 256) {
+		pr_warn("max_luns can be no more than 256, use default\n");
+		sdebug_max_luns = DEF_MAX_LUNS;
+	}
 
 	if (sdebug_lowest_aligned > 0x3fff) {
 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 3/6] scsi_debug: add multiple queue support
Date: Fri,  6 May 2016 00:40:26 -0400
Message-ID: <1462509629-24282-4-git-send-email-dgilbert@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55630 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1751342AbcEFEkp (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:45 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

Add submit_queue parameter (minimum and default: 1; maximum:
nr_cpu_ids) that controls how many queues are built, each with
their own lock and in_use bit vector. Add statistics parameter
which is default off.

Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/scsi_debug.c | 702 +++++++++++++++++++++++++++++-----------------
 1 file changed, 446 insertions(+), 256 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index e97ddf0..2ee55d5 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -135,6 +135,8 @@ static const char *sdebug_version_date = "20160430";
 #define DEF_VPD_USE_HOSTNO 1
 #define DEF_WRITESAME_LENGTH 0xFFFF
 #define DEF_STRICT 0
+#define DEF_STATISTICS false
+#define DEF_SUBMIT_QUEUES 1
 #define JDELAY_OVERRIDDEN -9999
 
 #define SDEBUG_LUN_0_VAL 0
@@ -201,20 +203,17 @@ static const char *sdebug_version_date = "20160430";
  * or "peripheral device" addressing (value 0) */
 #define SAM2_LUN_ADDRESS_METHOD 0
 
-/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
- * (for response) at one time. Can be reduced by max_queue option. Command
- * responses are not queued when jdelay=0 and ndelay=0. The per-device
- * DEF_CMD_PER_LUN can be changed via sysfs:
- * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
- * SCSI_DEBUG_CANQUEUE. */
-#define SCSI_DEBUG_CANQUEUE_WORDS  9	/* a WORD is bits in a long */
-#define SCSI_DEBUG_CANQUEUE  (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
+/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
+ * (for response) per submit queue at one time. Can be reduced by max_queue
+ * option. Command responses are not queued when jdelay=0 and ndelay=0. The
+ * per-device DEF_CMD_PER_LUN can be changed via sysfs:
+ * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
+ * but cannot exceed SDEBUG_CANQUEUE .
+ */
+#define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
+#define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
 #define DEF_CMD_PER_LUN  255
 
-#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
-#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
-#endif
-
 #define F_D_IN			1
 #define F_D_OUT			2
 #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
@@ -245,7 +244,7 @@ struct sdebug_dev_info {
 	struct sdebug_host_info *sdbg_host;
 	unsigned long uas_bm[1];
 	atomic_t num_in_q;
-	char stopped;		/* TODO: should be atomic */
+	atomic_t stopped;
 	bool used;
 };
 
@@ -262,23 +261,36 @@ struct sdebug_host_info {
 struct sdebug_defer {
 	struct hrtimer hrt;
 	struct execute_work ew;
-	int qa_indx;
+	int sqa_idx;	/* index of sdebug_queue array */
+	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
+	int issuing_cpu;
 };
 
 struct sdebug_queued_cmd {
-	/* in_use flagged by a bit in queued_in_use_bm[] */
+	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
+	 * instance indicates this slot is in use.
+	 */
 	struct sdebug_defer *sd_dp;
 	struct scsi_cmnd *a_cmnd;
+	unsigned int inj_recovered:1;
+	unsigned int inj_transport:1;
+	unsigned int inj_dif:1;
+	unsigned int inj_dix:1;
+	unsigned int inj_short:1;
 };
 
-struct sdebug_scmd_extra_t {
-	bool inj_recovered;
-	bool inj_transport;
-	bool inj_dif;
-	bool inj_dix;
-	bool inj_short;
+struct sdebug_queue {
+	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
+	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
+	spinlock_t qc_lock;
+	atomic_t blocked;	/* to temporarily stop more being queued */
 };
 
+static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
+static atomic_t sdebug_completions;  /* count of deferred completions */
+static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
+static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
+
 struct opcode_info_t {
 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
 				/* for terminating element */
@@ -326,6 +338,7 @@ enum sdeb_opcode_index {
 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
 };
 
+
 static const unsigned char opcode_ind_arr[256] = {
 /* 0x0; 0x0->0x1f: 6 byte cdbs */
 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
@@ -563,7 +576,7 @@ static int sdebug_fake_rw = DEF_FAKE_RW;
 static unsigned int sdebug_guard = DEF_GUARD;
 static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
 static int sdebug_max_luns = DEF_MAX_LUNS;
-static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
+static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
 static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
 static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
 static int sdebug_no_lun_0 = DEF_NO_LUN_0;
@@ -594,10 +607,8 @@ static bool sdebug_strict = DEF_STRICT;
 static bool sdebug_any_injecting_opt;
 static bool sdebug_verbose;
 static bool have_dif_prot;
-
-static atomic_t sdebug_cmnd_count;
-static atomic_t sdebug_completions;
-static atomic_t sdebug_a_tsf;		/* counter of 'almost' TSFs */
+static bool sdebug_statistics = DEF_STATISTICS;
+static bool sdebug_mq_active;
 
 static unsigned int sdebug_store_sectors;
 static sector_t sdebug_capacity;	/* in sectors */
@@ -625,10 +636,9 @@ static int dix_writes;
 static int dix_reads;
 static int dif_errors;
 
-static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
-static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
+static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
+static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
 
-static DEFINE_SPINLOCK(queued_arr_lock);
 static DEFINE_RWLOCK(atomic_rw);
 
 static char sdebug_proc_name[] = MY_NAME;
@@ -1428,16 +1438,15 @@ static int resp_start_stop(struct scsi_cmnd * scp,
 			   struct sdebug_dev_info * devip)
 {
 	unsigned char *cmd = scp->cmnd;
-	int power_cond, start;
+	int power_cond, stop;
 
 	power_cond = (cmd[4] & 0xf0) >> 4;
 	if (power_cond) {
 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
 		return check_condition_result;
 	}
-	start = cmd[4] & 1;
-	if (start == devip->stopped)
-		devip->stopped = !start;
+	stop = !(cmd[4] & 1);
+	atomic_xchg(&devip->stopped, stop);
 	return 0;
 }
 
@@ -2450,6 +2459,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
 static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
 	u8 *cmd = scp->cmnd;
+	struct sdebug_queued_cmd *sqcp;
 	u64 lba;
 	u32 num;
 	u32 ei_lba;
@@ -2509,11 +2519,14 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 				    "to DIF device\n");
 	}
 	if (unlikely(sdebug_any_injecting_opt)) {
-		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
+		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
 
-		if (ep->inj_short)
-			num /= 2;
-	}
+		if (sqcp) {
+			if (sqcp->inj_short)
+				num /= 2;
+		}
+	} else
+		sqcp = NULL;
 
 	/* inline check_device_access_params() */
 	if (unlikely(lba + num > sdebug_capacity)) {
@@ -2563,22 +2576,20 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 
 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
 
-	if (unlikely(sdebug_any_injecting_opt)) {
-		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
-
-		if (ep->inj_recovered) {
+	if (unlikely(sqcp)) {
+		if (sqcp->inj_recovered) {
 			mk_sense_buffer(scp, RECOVERED_ERROR,
 					THRESHOLD_EXCEEDED, 0);
 			return check_condition_result;
-		} else if (ep->inj_transport) {
+		} else if (sqcp->inj_transport) {
 			mk_sense_buffer(scp, ABORTED_COMMAND,
 					TRANSPORT_PROBLEM, ACK_NAK_TO);
 			return check_condition_result;
-		} else if (ep->inj_dif) {
+		} else if (sqcp->inj_dif) {
 			/* Logical block guard check failed */
 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
 			return illegal_condition_result;
-		} else if (ep->inj_dix) {
+		} else if (sqcp->inj_dix) {
 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
 			return illegal_condition_result;
 		}
@@ -2851,25 +2862,29 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	write_unlock_irqrestore(&atomic_rw, iflags);
 	if (unlikely(-1 == ret))
 		return DID_ERROR << 16;
-	else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
+	else if (unlikely(sdebug_verbose &&
+			  (ret < (num * sdebug_sector_size))))
 		sdev_printk(KERN_INFO, scp->device,
 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
 			    my_name, num * sdebug_sector_size, ret);
 
 	if (unlikely(sdebug_any_injecting_opt)) {
-		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
+		struct sdebug_queued_cmd *sqcp =
+				(struct sdebug_queued_cmd *)scp->host_scribble;
 
-		if (ep->inj_recovered) {
-			mk_sense_buffer(scp, RECOVERED_ERROR,
-					THRESHOLD_EXCEEDED, 0);
-			return check_condition_result;
-		} else if (ep->inj_dif) {
-			/* Logical block guard check failed */
-			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
-			return illegal_condition_result;
-		} else if (ep->inj_dix) {
-			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
-			return illegal_condition_result;
+		if (sqcp) {
+			if (sqcp->inj_recovered) {
+				mk_sense_buffer(scp, RECOVERED_ERROR,
+						THRESHOLD_EXCEEDED, 0);
+				return check_condition_result;
+			} else if (sqcp->inj_dif) {
+				/* Logical block guard check failed */
+				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
+				return illegal_condition_result;
+			} else if (sqcp->inj_dix) {
+				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
+				return illegal_condition_result;
+			}
 		}
 	}
 	return 0;
@@ -3360,28 +3375,53 @@ static int resp_xdwriteread_10(struct scsi_cmnd *scp,
 	return resp_xdwriteread(scp, lba, num, devip);
 }
 
-/* Queued command completions converge here. */
+static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
+{
+	struct sdebug_queue *sqp = sdebug_q_arr;
+
+	if (sdebug_mq_active) {
+		u32 tag = blk_mq_unique_tag(cmnd->request);
+		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
+
+		if (unlikely(hwq >= submit_queues)) {
+			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
+			hwq %= submit_queues;
+		}
+		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
+		return sqp + hwq;
+	} else
+		return sqp;
+}
+
+/* Queued (deferred) command completions converge here. */
 static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
 {
-	int qa_indx;
+	int qc_idx;
 	int retiring = 0;
 	unsigned long iflags;
+	struct sdebug_queue *sqp;
 	struct sdebug_queued_cmd *sqcp;
 	struct scsi_cmnd *scp;
 	struct sdebug_dev_info *devip;
 
-	atomic_inc(&sdebug_completions);
-	qa_indx = sd_dp->qa_indx;
-	if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) {
-		pr_err("wild qa_indx=%d\n", qa_indx);
+	qc_idx = sd_dp->qc_idx;
+	sqp = sdebug_q_arr + sd_dp->sqa_idx;
+	if (sdebug_statistics) {
+		atomic_inc(&sdebug_completions);
+		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
+			atomic_inc(&sdebug_miss_cpus);
+	}
+	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
+		pr_err("wild qc_idx=%d\n", qc_idx);
 		return;
 	}
-	spin_lock_irqsave(&queued_arr_lock, iflags);
-	sqcp = &queued_arr[qa_indx];
+	spin_lock_irqsave(&sqp->qc_lock, iflags);
+	sqcp = &sqp->qc_arr[qc_idx];
 	scp = sqcp->a_cmnd;
 	if (unlikely(scp == NULL)) {
-		spin_unlock_irqrestore(&queued_arr_lock, iflags);
-		pr_err("scp is NULL\n");
+		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
+		       sd_dp->sqa_idx, qc_idx);
 		return;
 	}
 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
@@ -3393,8 +3433,8 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
 		retiring = 1;
 
 	sqcp->a_cmnd = NULL;
-	if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) {
-		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
+		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 		pr_err("Unexpected completion\n");
 		return;
 	}
@@ -3403,18 +3443,18 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
 		int k, retval;
 
 		retval = atomic_read(&retired_max_queue);
-		if (qa_indx >= retval) {
-			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		if (qc_idx >= retval) {
+			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 			pr_err("index %d too large\n", retval);
 			return;
 		}
-		k = find_last_bit(queued_in_use_bm, retval);
+		k = find_last_bit(sqp->in_use_bm, retval);
 		if ((k < sdebug_max_queue) || (k == retval))
 			atomic_set(&retired_max_queue, 0);
 		else
 			atomic_set(&retired_max_queue, k + 1);
 	}
-	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 	scp->scsi_done(scp); /* callback to mid level */
 }
 
@@ -3533,47 +3573,53 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp)
 	}
 }
 
+static void stop_qc_helper(struct sdebug_defer *sd_dp)
+{
+	if (!sd_dp)
+		return;
+	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
+		hrtimer_cancel(&sd_dp->hrt);
+	else if (sdebug_jdelay < 0)
+		cancel_work_sync(&sd_dp->ew.work);
+}
+
 /* If @cmnd found deletes its timer or work queue and returns true; else
    returns false */
 static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
 {
 	unsigned long iflags;
-	int k, qmax, r_qmax;
+	int j, k, qmax, r_qmax;
+	struct sdebug_queue *sqp;
 	struct sdebug_queued_cmd *sqcp;
 	struct sdebug_dev_info *devip;
 	struct sdebug_defer *sd_dp;
 
-	spin_lock_irqsave(&queued_arr_lock, iflags);
-	qmax = sdebug_max_queue;
-	r_qmax = atomic_read(&retired_max_queue);
-	if (r_qmax > qmax)
-		qmax = r_qmax;
-	for (k = 0; k < qmax; ++k) {
-		if (test_bit(k, queued_in_use_bm)) {
-			sqcp = &queued_arr[k];
-			if (cmnd != sqcp->a_cmnd)
-				continue;
-			/* found command */
-			devip = (struct sdebug_dev_info *)
-				cmnd->device->hostdata;
-			if (devip)
-				atomic_dec(&devip->num_in_q);
-			sqcp->a_cmnd = NULL;
-			sd_dp = sqcp->sd_dp;
-			spin_unlock_irqrestore(&queued_arr_lock,
-					       iflags);
-			if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
-				if (sd_dp)
-					hrtimer_cancel(&sd_dp->hrt);
-			} else if (sdebug_jdelay < 0) {
-				if (sd_dp)
-					cancel_work_sync(&sd_dp->ew.work);
+	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
+		spin_lock_irqsave(&sqp->qc_lock, iflags);
+		qmax = sdebug_max_queue;
+		r_qmax = atomic_read(&retired_max_queue);
+		if (r_qmax > qmax)
+			qmax = r_qmax;
+		for (k = 0; k < qmax; ++k) {
+			if (test_bit(k, sqp->in_use_bm)) {
+				sqcp = &sqp->qc_arr[k];
+				if (cmnd != sqcp->a_cmnd)
+					continue;
+				/* found */
+				devip = (struct sdebug_dev_info *)
+						cmnd->device->hostdata;
+				if (devip)
+					atomic_dec(&devip->num_in_q);
+				sqcp->a_cmnd = NULL;
+				sd_dp = sqcp->sd_dp;
+				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+				stop_qc_helper(sd_dp);
+				clear_bit(k, sqp->in_use_bm);
+				return true;
 			}
-			clear_bit(k, queued_in_use_bm);
-			return true;
 		}
+		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 	}
-	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 	return false;
 }
 
@@ -3581,48 +3627,48 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
 static void stop_all_queued(void)
 {
 	unsigned long iflags;
-	int k;
+	int j, k;
+	struct sdebug_queue *sqp;
 	struct sdebug_queued_cmd *sqcp;
 	struct sdebug_dev_info *devip;
 	struct sdebug_defer *sd_dp;
 
-	spin_lock_irqsave(&queued_arr_lock, iflags);
-	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
-		if (test_bit(k, queued_in_use_bm)) {
-			sqcp = &queued_arr[k];
-			if (NULL == sqcp->a_cmnd)
-				continue;
-			devip = (struct sdebug_dev_info *)
-				sqcp->a_cmnd->device->hostdata;
-			if (devip)
-				atomic_dec(&devip->num_in_q);
-			sqcp->a_cmnd = NULL;
-			sd_dp = sqcp->sd_dp;
-			spin_unlock_irqrestore(&queued_arr_lock, iflags);
-			if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
-				if (sd_dp)
-					hrtimer_cancel(&sd_dp->hrt);
-			} else if (sdebug_jdelay < 0) {
-				if (sd_dp)
-					cancel_work_sync(&sd_dp->ew.work);
+	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
+		spin_lock_irqsave(&sqp->qc_lock, iflags);
+		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
+			if (test_bit(k, sqp->in_use_bm)) {
+				sqcp = &sqp->qc_arr[k];
+				if (sqcp->a_cmnd == NULL)
+					continue;
+				devip = (struct sdebug_dev_info *)
+					sqcp->a_cmnd->device->hostdata;
+				if (devip)
+					atomic_dec(&devip->num_in_q);
+				sqcp->a_cmnd = NULL;
+				sd_dp = sqcp->sd_dp;
+				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+				stop_qc_helper(sd_dp);
+				clear_bit(k, sqp->in_use_bm);
+				spin_lock_irqsave(&sqp->qc_lock, iflags);
 			}
-			clear_bit(k, queued_in_use_bm);
-			spin_lock_irqsave(&queued_arr_lock, iflags);
 		}
+		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 	}
-	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 }
 
 /* Free queued command memory on heap */
 static void free_all_queued(void)
 {
-	int k;
+	int j, k;
+	struct sdebug_queue *sqp;
 	struct sdebug_queued_cmd *sqcp;
 
-	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
-		sqcp = &queued_arr[k];
-		kfree(sqcp->sd_dp);
-		sqcp->sd_dp = NULL;
+	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
+		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
+			sqcp = &sqp->qc_arr[k];
+			kfree(sqcp->sd_dp);
+			sqcp->sd_dp = NULL;
+		}
 	}
 }
 
@@ -3801,24 +3847,71 @@ static void __init sdebug_build_parts(unsigned char *ramp,
 	}
 }
 
+static void block_unblock_all_queues(bool block)
+{
+	int j;
+	struct sdebug_queue *sqp;
+
+	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
+		atomic_set(&sqp->blocked, (int)block);
+}
+
+/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
+ * commands will be processed normally before triggers occur.
+ */
+static void tweak_cmnd_count(void)
+{
+	int count, modulo;
+
+	modulo = abs(sdebug_every_nth);
+	if (modulo < 2)
+		return;
+	block_unblock_all_queues(true);
+	count = atomic_read(&sdebug_cmnd_count);
+	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
+	block_unblock_all_queues(false);
+}
+
+static void clear_queue_stats(void)
+{
+	atomic_set(&sdebug_cmnd_count, 0);
+	atomic_set(&sdebug_completions, 0);
+	atomic_set(&sdebug_miss_cpus, 0);
+	atomic_set(&sdebug_a_tsf, 0);
+}
+
+static void setup_inject(struct sdebug_queue *sqp,
+			 struct sdebug_queued_cmd *sqcp)
+{
+	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
+		return;
+	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
+	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
+	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
+	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
+	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
+}
+
+/* Complete the processing of the thread that queued a SCSI command to this
+ * driver. It either completes the command by calling cmnd_done() or
+ * schedules a hr timer or work queue then returns 0. Returns
+ * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
+ */
 static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 			 int scsi_result, int delta_jiff)
 {
 	unsigned long iflags;
 	int k, num_in_q, qdepth, inject;
-	struct sdebug_queued_cmd *sqcp = NULL;
+	struct sdebug_queue *sqp;
+	struct sdebug_queued_cmd *sqcp;
 	struct scsi_device *sdp;
 	struct sdebug_defer *sd_dp;
 
-	if (unlikely(WARN_ON(!cmnd)))
-		return SCSI_MLQUEUE_HOST_BUSY;
-
 	if (unlikely(devip == NULL)) {
 		if (scsi_result == 0)
 			scsi_result = DID_NO_CONNECT << 16;
 		goto respond_in_thread;
 	}
-
 	sdp = cmnd->device;
 
 	if (unlikely(sdebug_verbose && scsi_result))
@@ -3828,17 +3921,22 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 		goto respond_in_thread;
 
 	/* schedule the response at a later time if resources permit */
-	spin_lock_irqsave(&queued_arr_lock, iflags);
+	sqp = get_queue(cmnd);
+	spin_lock_irqsave(&sqp->qc_lock, iflags);
+	if (unlikely(atomic_read(&sqp->blocked))) {
+		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
 	num_in_q = atomic_read(&devip->num_in_q);
 	qdepth = cmnd->device->queue_depth;
 	inject = 0;
 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
 		if (scsi_result) {
-			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 			goto respond_in_thread;
 		} else
 			scsi_result = device_qfull_result;
-	} else if (unlikely((sdebug_every_nth != 0) &&
+	} else if (unlikely(sdebug_every_nth &&
 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
 			    (scsi_result == 0))) {
 		if ((num_in_q == (qdepth - 1)) &&
@@ -3850,9 +3948,9 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 		}
 	}
 
-	k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
+	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
 	if (unlikely(k >= sdebug_max_queue)) {
-		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
 		if (scsi_result)
 			goto respond_in_thread;
 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
@@ -3868,13 +3966,16 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 		else
 			return SCSI_MLQUEUE_HOST_BUSY;
 	}
-	__set_bit(k, queued_in_use_bm);
+	__set_bit(k, sqp->in_use_bm);
 	atomic_inc(&devip->num_in_q);
-	sqcp = &queued_arr[k];
+	sqcp = &sqp->qc_arr[k];
 	sqcp->a_cmnd = cmnd;
+	cmnd->host_scribble = (unsigned char *)sqcp;
 	cmnd->result = scsi_result;
-	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 	sd_dp = sqcp->sd_dp;
+	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
+		setup_inject(sqp, sqcp);
 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
 		ktime_t kt;
 
@@ -3891,20 +3992,26 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 				return SCSI_MLQUEUE_HOST_BUSY;
 			sqcp->sd_dp = sd_dp;
 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
-				     HRTIMER_MODE_REL);
+				     HRTIMER_MODE_REL_PINNED);
 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
-			sd_dp->qa_indx = k;
+			sd_dp->sqa_idx = sqp - sdebug_q_arr;
+			sd_dp->qc_idx = k;
 		}
-		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
-	} else {	/* jdelay < 0 */
+		if (sdebug_statistics)
+			sd_dp->issuing_cpu = raw_smp_processor_id();
+		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
+	} else {	/* jdelay < 0, use work queue */
 		if (NULL == sd_dp) {
 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
 			if (NULL == sd_dp)
 				return SCSI_MLQUEUE_HOST_BUSY;
 			sqcp->sd_dp = sd_dp;
-			sd_dp->qa_indx = k;
+			sd_dp->sqa_idx = sqp - sdebug_q_arr;
+			sd_dp->qc_idx = k;
 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
 		}
+		if (sdebug_statistics)
+			sd_dp->issuing_cpu = raw_smp_processor_id();
 		schedule_work(&sd_dp->ew.work);
 	}
 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
@@ -3958,7 +4065,9 @@ module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
 module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
 module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
 module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
+module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
 module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
+module_param_named(submit_queues, submit_queues, int, S_IRUGO);
 module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
 module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
 module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
@@ -4005,7 +4114,9 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
 MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
 MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
 MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
+MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
 MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
+MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
 MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
 MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
 MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
@@ -4018,10 +4129,17 @@ static char sdebug_info[256];
 
 static const char * scsi_debug_info(struct Scsi_Host * shp)
 {
-	sprintf(sdebug_info,
-		"scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x",
-		SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb,
-		sdebug_opts);
+	int k;
+
+	k = scnprintf(sdebug_info, sizeof(sdebug_info),
+		      "%s: version %s [%s], dev_size_mb=%d, opts=0x%x\n",
+		      my_name, SDEBUG_VERSION, sdebug_version_date,
+		      sdebug_dev_size_mb, sdebug_opts);
+	if (k >= (sizeof(sdebug_info) - 1))
+		return sdebug_info;
+	scnprintf(sdebug_info + k, sizeof(sdebug_info) - k,
+		  "%s: submit_queues=%d, statistics=%d\n", my_name,
+		  submit_queues, (int)sdebug_statistics);
 	return sdebug_info;
 }
 
@@ -4043,7 +4161,7 @@ static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
 	if (sdebug_every_nth != 0)
-		atomic_set(&sdebug_cmnd_count, 0);
+		tweak_cmnd_count();
 	return length;
 }
 
@@ -4052,39 +4170,43 @@ static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
  * output are not atomics so might be inaccurate in a busy system. */
 static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
 {
-	int f, l;
-	char b[32];
-
-	if (sdebug_every_nth > 0)
-		snprintf(b, sizeof(b), " (curr:%d)",
-			 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
-				atomic_read(&sdebug_a_tsf) :
-				atomic_read(&sdebug_cmnd_count)));
-	else
-		b[0] = '\0';
-
-	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
-		"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
-		"every_nth=%d%s\n"
-		"delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
-		"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
-		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
-		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
-		"usec_in_jiffy=%lu\n",
-		SDEBUG_VERSION, sdebug_version_date,
-		sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
-		sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
-		sdebug_max_luns, atomic_read(&sdebug_completions),
-		sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
-		sdebug_sectors_per, num_aborts, num_dev_resets,
-		num_target_resets, num_bus_resets, num_host_resets,
-		dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
-
-	f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
-	if (f != sdebug_max_queue) {
-		l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
-		seq_printf(m, "   %s BUSY: first,last bits set: %d,%d\n",
-			   "queued_in_use_bm", f, l);
+	int f, j, l;
+	struct sdebug_queue *sqp;
+
+	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
+		   SDEBUG_VERSION, sdebug_version_date);
+	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
+		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
+		   sdebug_opts, sdebug_every_nth);
+	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
+		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
+		   sdebug_sector_size, "bytes");
+	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
+		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
+		   num_aborts);
+	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
+		   num_dev_resets, num_target_resets, num_bus_resets,
+		   num_host_resets);
+	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
+		   dix_reads, dix_writes, dif_errors);
+	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
+		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
+		   sdebug_mq_active);
+	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
+		   atomic_read(&sdebug_cmnd_count),
+		   atomic_read(&sdebug_completions),
+		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
+		   atomic_read(&sdebug_a_tsf));
+
+	seq_printf(m, "submit_queues=%d\n", submit_queues);
+	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
+		seq_printf(m, "  queue %d:\n", j);
+		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
+		if (f != sdebug_max_queue) {
+			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
+			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
+				   "first,last bits", f, l);
+		}
 	}
 	return 0;
 }
@@ -4093,7 +4215,9 @@ static ssize_t delay_show(struct device_driver *ddp, char *buf)
 {
 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
 }
-/* Returns -EBUSY if jdelay is being changed and commands are queued */
+/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
+ * of delay is jiffies.
+ */
 static ssize_t delay_store(struct device_driver *ddp, const char *buf,
 			   size_t count)
 {
@@ -4102,21 +4226,27 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf,
 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
 		res = count;
 		if (sdebug_jdelay != jdelay) {
-			unsigned long iflags;
-			int k;
-
-			spin_lock_irqsave(&queued_arr_lock, iflags);
-			k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
-			if (k != sdebug_max_queue)
-				res = -EBUSY;	/* have queued commands */
-			else {
+			int j, k;
+			struct sdebug_queue *sqp;
+
+			block_unblock_all_queues(true);
+			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
+			     ++j, ++sqp) {
+				k = find_first_bit(sqp->in_use_bm,
+						   sdebug_max_queue);
+				if (k != sdebug_max_queue) {
+					res = -EBUSY;   /* queued commands */
+					break;
+				}
+			}
+			if (res > 0) {
 				/* make sure sdebug_defer instances get
 				 * re-allocated for new delay variant */
 				free_all_queued();
 				sdebug_jdelay = jdelay;
 				sdebug_ndelay = 0;
 			}
-			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			block_unblock_all_queues(false);
 		}
 		return res;
 	}
@@ -4133,18 +4263,26 @@ static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
 static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
 			    size_t count)
 {
-	unsigned long iflags;
-	int ndelay, res, k;
+	int ndelay, res;
 
 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
-	    (ndelay >= 0) && (ndelay < 1000000000)) {
+	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
 		res = count;
 		if (sdebug_ndelay != ndelay) {
-			spin_lock_irqsave(&queued_arr_lock, iflags);
-			k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
-			if (k != sdebug_max_queue)
-				res = -EBUSY;	/* have queued commands */
-			else {
+			int j, k;
+			struct sdebug_queue *sqp;
+
+			block_unblock_all_queues(true);
+			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
+			     ++j, ++sqp) {
+				k = find_first_bit(sqp->in_use_bm,
+						   sdebug_max_queue);
+				if (k != sdebug_max_queue) {
+					res = -EBUSY;   /* queued commands */
+					break;
+				}
+			}
+			if (res > 0) {
 				/* make sure sdebug_defer instances get
 				 * re-allocated for new delay variant */
 				free_all_queued();
@@ -4152,7 +4290,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
 							: DEF_JDELAY;
 			}
-			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			block_unblock_all_queues(false);
 		}
 		return res;
 	}
@@ -4185,8 +4323,7 @@ opts_done:
 	sdebug_opts = opts;
 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
-	atomic_set(&sdebug_cmnd_count, 0);
-	atomic_set(&sdebug_a_tsf, 0);
+	tweak_cmnd_count();
 	return count;
 }
 static DRIVER_ATTR_RW(opts);
@@ -4316,7 +4453,11 @@ static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
 
 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
 		sdebug_every_nth = nth;
-		atomic_set(&sdebug_cmnd_count, 0);
+		if (nth && !sdebug_statistics) {
+			pr_info("every_nth needs statistics=1, set it\n");
+			sdebug_statistics = true;
+		}
+		tweak_cmnd_count();
 		return count;
 	}
 	return -EINVAL;
@@ -4371,21 +4512,27 @@ static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
 static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
 			       size_t count)
 {
-	unsigned long iflags;
-	int n, k;
+	int j, n, k, a;
+	struct sdebug_queue *sqp;
 
 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
-	    (n <= SCSI_DEBUG_CANQUEUE)) {
-		spin_lock_irqsave(&queued_arr_lock, iflags);
-		k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
+	    (n <= SDEBUG_CANQUEUE)) {
+		block_unblock_all_queues(true);
+		k = 0;
+		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
+		     ++j, ++sqp) {
+			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
+			if (a > k)
+				k = a;
+		}
 		sdebug_max_queue = n;
-		if (SCSI_DEBUG_CANQUEUE == k)
+		if (k == SDEBUG_CANQUEUE)
 			atomic_set(&retired_max_queue, 0);
 		else if (k >= n)
 			atomic_set(&retired_max_queue, k + 1);
 		else
 			atomic_set(&retired_max_queue, 0);
-		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		block_unblock_all_queues(false);
 		return count;
 	}
 	return -EINVAL;
@@ -4484,12 +4631,40 @@ static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
 }
 static DRIVER_ATTR_RW(vpd_use_hostno);
 
+static ssize_t statistics_show(struct device_driver *ddp, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
+}
+static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
+				size_t count)
+{
+	int n;
+
+	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
+		if (n > 0)
+			sdebug_statistics = true;
+		else {
+			clear_queue_stats();
+			sdebug_statistics = false;
+		}
+		return count;
+	}
+	return -EINVAL;
+}
+static DRIVER_ATTR_RW(statistics);
+
 static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
 {
 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
 }
 static DRIVER_ATTR_RO(sector_size);
 
+static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
+}
+static DRIVER_ATTR_RO(submit_queues);
+
 static ssize_t dix_show(struct device_driver *ddp, char *buf)
 {
 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
@@ -4610,6 +4785,8 @@ static struct attribute *sdebug_drv_attrs[] = {
 	&driver_attr_add_host.attr,
 	&driver_attr_vpd_use_hostno.attr,
 	&driver_attr_sector_size.attr,
+	&driver_attr_statistics.attr,
+	&driver_attr_submit_queues.attr,
 	&driver_attr_dix.attr,
 	&driver_attr_dif.attr,
 	&driver_attr_guard.attr,
@@ -4632,8 +4809,6 @@ static int __init scsi_debug_init(void)
 	int k;
 	int ret;
 
-	atomic_set(&sdebug_cmnd_count, 0);
-	atomic_set(&sdebug_completions, 0);
 	atomic_set(&retired_max_queue, 0);
 
 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
@@ -4692,6 +4867,17 @@ static int __init scsi_debug_init(void)
 		return -EINVAL;
 	}
 
+	if (submit_queues < 1) {
+		pr_err("submit_queues must be 1 or more\n");
+		return -EINVAL;
+	}
+	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
+			       GFP_KERNEL);
+	if (sdebug_q_arr == NULL)
+		return -ENOMEM;
+	for (k = 0; k < submit_queues; ++k)
+		spin_lock_init(&sdebug_q_arr[k].qc_lock);
+
 	if (sdebug_dev_size_mb < 1)
 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
@@ -4719,7 +4905,8 @@ static int __init scsi_debug_init(void)
 		fake_storep = vmalloc(sz);
 		if (NULL == fake_storep) {
 			pr_err("out of memory, 1\n");
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto free_q_arr;
 		}
 		memset(fake_storep, 0, sz);
 		if (sdebug_num_parts > 0)
@@ -4758,7 +4945,8 @@ static int __init scsi_debug_init(void)
 		    sdebug_unmap_granularity <=
 		    sdebug_unmap_alignment) {
 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto free_vm;
 		}
 
 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
@@ -4819,7 +5007,8 @@ free_vm:
 	vfree(map_storep);
 	vfree(dif_storep);
 	vfree(fake_storep);
-
+free_q_arr:
+	kfree(sdebug_q_arr);
 	return ret;
 }
 
@@ -4837,6 +5026,7 @@ static void __exit scsi_debug_exit(void)
 
 	vfree(dif_storep);
 	vfree(fake_storep);
+	kfree(sdebug_q_arr);
 }
 
 device_initcall(scsi_debug_init);
@@ -4925,62 +5115,43 @@ static void sdebug_remove_adapter(void)
 static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
 {
 	int num_in_q = 0;
-	unsigned long iflags;
 	struct sdebug_dev_info *devip;
 
-	spin_lock_irqsave(&queued_arr_lock, iflags);
+	block_unblock_all_queues(true);
 	devip = (struct sdebug_dev_info *)sdev->hostdata;
 	if (NULL == devip) {
-		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		block_unblock_all_queues(false);
 		return	-ENODEV;
 	}
 	num_in_q = atomic_read(&devip->num_in_q);
-	spin_unlock_irqrestore(&queued_arr_lock, iflags);
 
 	if (qdepth < 1)
 		qdepth = 1;
-	/* allow to exceed max host queued_arr elements for testing */
-	if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
-		qdepth = SCSI_DEBUG_CANQUEUE + 10;
+	/* allow to exceed max host qc_arr elements for testing */
+	if (qdepth > SDEBUG_CANQUEUE + 10)
+		qdepth = SDEBUG_CANQUEUE + 10;
 	scsi_change_queue_depth(sdev, qdepth);
 
 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
-		sdev_printk(KERN_INFO, sdev,
-			    "%s: qdepth=%d, num_in_q=%d\n",
+		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
 			    __func__, qdepth, num_in_q);
 	}
+	block_unblock_all_queues(false);
 	return sdev->queue_depth;
 }
 
-static int check_inject(struct scsi_cmnd *scp)
+static bool fake_timeout(struct scsi_cmnd *scp)
 {
-	struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
-
-	memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
-
-	if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
-		atomic_set(&sdebug_cmnd_count, 0);
+	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
 		if (sdebug_every_nth < -1)
 			sdebug_every_nth = -1;
 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
-			return 1; /* ignore command causing timeout */
+			return true; /* ignore command causing timeout */
 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
 			 scsi_medium_access_command(scp))
-			return 1; /* time out reads and writes */
-		if (sdebug_any_injecting_opt) {
-			if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
-				ep->inj_recovered = true;
-			if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
-				ep->inj_transport = true;
-			if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
-				ep->inj_dif = true;
-			if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
-				ep->inj_dix = true;
-			if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
-				ep->inj_short = true;
-		}
+			return true; /* time out reads and writes */
 	}
-	return 0;
+	return false;
 }
 
 static int scsi_debug_queuecommand(struct Scsi_Host *shost,
@@ -5001,6 +5172,8 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 	bool has_wlun_rl;
 
 	scsi_set_resid(scp, 0);
+	if (sdebug_statistics)
+		atomic_inc(&sdebug_cmnd_count);
 	if (unlikely(sdebug_verbose &&
 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
 		char b[120];
@@ -5015,7 +5188,13 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 				n += scnprintf(b + n, sb - n, "%02x ",
 					       (u32)cmd[k]);
 		}
-		sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
+		if (sdebug_mq_active)
+			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
+				    my_name, blk_mq_unique_tag(scp->request),
+				    b);
+		else
+			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
+				    b);
 	}
 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
@@ -5093,7 +5272,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 		if (errsts)
 			goto check_cond;
 	}
-	if (unlikely((F_M_ACCESS & flags) && devip->stopped)) {
+	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
 		if (sdebug_verbose)
 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
@@ -5105,7 +5284,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
 		goto fini;
 	if (unlikely(sdebug_every_nth)) {
-		if (check_inject(scp))
+		if (fake_timeout(scp))
 			return 0;	/* ignore command: make trouble */
 	}
 	if (likely(oip->pfp))
@@ -5139,7 +5318,7 @@ static struct scsi_host_template sdebug_driver_template = {
 	.eh_target_reset_handler = scsi_debug_target_reset,
 	.eh_bus_reset_handler = scsi_debug_bus_reset,
 	.eh_host_reset_handler = scsi_debug_host_reset,
-	.can_queue =		SCSI_DEBUG_CANQUEUE,
+	.can_queue =		SDEBUG_CANQUEUE,
 	.this_id =		7,
 	.sg_tablesize =		SG_MAX_SEGMENTS,
 	.cmd_per_lun =		DEF_CMD_PER_LUN,
@@ -5147,7 +5326,6 @@ static struct scsi_host_template sdebug_driver_template = {
 	.use_clustering = 	DISABLE_CLUSTERING,
 	.module =		THIS_MODULE,
 	.track_queue_depth =	1,
-	.cmd_size =		sizeof(struct sdebug_scmd_extra_t),
 };
 
 static int sdebug_driver_probe(struct device * dev)
@@ -5168,6 +5346,16 @@ static int sdebug_driver_probe(struct device * dev)
 		error = -ENODEV;
 		return error;
 	}
+	if (submit_queues > nr_cpu_ids) {
+		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n",
+			my_name, submit_queues, nr_cpu_ids);
+		submit_queues = nr_cpu_ids;
+	}
+	/* Decide whether to tell scsi subsystem that we want mq */
+	/* Following should give the same answer for each host */
+	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
+	if (sdebug_mq_active)
+		hpnt->nr_hw_queues = submit_queues;
 
         sdbg_host->shost = hpnt;
 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
@@ -5225,6 +5413,8 @@ static int sdebug_driver_probe(struct device * dev)
 
 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
+	if (sdebug_every_nth)	/* need stats counters for every_nth */
+		sdebug_statistics = true;
         error = scsi_add_host(hpnt, &sdbg_host->dev);
         if (error) {
 		pr_err("scsi_add_host failed\n");
-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 4/6] scsi_debug: vpd and mode page work
Date: Fri,  6 May 2016 00:40:27 -0400
Message-ID: <1462509629-24282-5-git-send-email-dgilbert@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55624 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1751314AbcEFEkp (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:45 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

Cleanup some mode and vpd pages. Stop reporting SBC (disk) pages
when peripheral type is something else (e.g. tape). Update
version descriptors. Expand LBPRZ flag handling.

Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/scsi_debug.c | 187 ++++++++++++++++++++++++++--------------------
 1 file changed, 108 insertions(+), 79 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 2ee55d5..afbbfaa 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -125,7 +125,7 @@ static const char *sdebug_version_date = "20160430";
 #define DEF_PHYSBLK_EXP 0
 #define DEF_PTYPE   TYPE_DISK
 #define DEF_REMOVABLE false
-#define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
+#define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
 #define DEF_SECTOR_SIZE 512
 #define DEF_UNMAP_ALIGNMENT 0
 #define DEF_UNMAP_GRANULARITY 1
@@ -661,7 +661,11 @@ static const int device_qfull_result =
 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
 
 
-static inline unsigned int scsi_debug_lbp(void)
+/* Only do the extra work involved in logical block provisioning if one or
+ * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
+ * real reads and writes (i.e. not skipping them for speed).
+ */
+static inline bool scsi_debug_lbp(void)
 {
 	return 0 == sdebug_fake_rw &&
 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
@@ -922,10 +926,10 @@ static const u64 naa5_comp_b = 0x5333333000000000ULL;
 static const u64 naa5_comp_c = 0x5111111000000000ULL;
 
 /* Device identification VPD page. Returns number of bytes placed in arr */
-static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
-			   int target_dev_id, int dev_id_num,
-			   const char * dev_id_str,
-			   int dev_id_str_len)
+static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
+			  int target_dev_id, int dev_id_num,
+			  const char *dev_id_str,
+			  int dev_id_str_len)
 {
 	int num, port_a;
 	char b[32];
@@ -1004,14 +1008,14 @@ static unsigned char vpd84_data[] = {
 };
 
 /*  Software interface identification VPD page */
-static int inquiry_evpd_84(unsigned char * arr)
+static int inquiry_vpd_84(unsigned char *arr)
 {
 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
 	return sizeof(vpd84_data);
 }
 
 /* Management network addresses VPD page */
-static int inquiry_evpd_85(unsigned char * arr)
+static int inquiry_vpd_85(unsigned char *arr)
 {
 	int num = 0;
 	const char * na1 = "https://www.kernel.org/config";
@@ -1046,7 +1050,7 @@ static int inquiry_evpd_85(unsigned char * arr)
 }
 
 /* SCSI ports VPD page */
-static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
+static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
 {
 	int num = 0;
 	int port_a, port_b;
@@ -1133,7 +1137,7 @@ static unsigned char vpd89_data[] = {
 };
 
 /* ATA Information VPD page */
-static int inquiry_evpd_89(unsigned char * arr)
+static int inquiry_vpd_89(unsigned char *arr)
 {
 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
 	return sizeof(vpd89_data);
@@ -1148,7 +1152,7 @@ static unsigned char vpdb0_data[] = {
 };
 
 /* Block limits VPD page (SBC-3) */
-static int inquiry_evpd_b0(unsigned char * arr)
+static int inquiry_vpd_b0(unsigned char *arr)
 {
 	unsigned int gran;
 
@@ -1191,7 +1195,7 @@ static int inquiry_evpd_b0(unsigned char * arr)
 }
 
 /* Block device characteristics VPD page (SBC-3) */
-static int inquiry_evpd_b1(unsigned char *arr)
+static int inquiry_vpd_b1(unsigned char *arr)
 {
 	memset(arr, 0, 0x3c);
 	arr[0] = 0;
@@ -1202,24 +1206,22 @@ static int inquiry_evpd_b1(unsigned char *arr)
 	return 0x3c;
 }
 
-/* Logical block provisioning VPD page (SBC-3) */
-static int inquiry_evpd_b2(unsigned char *arr)
+/* Logical block provisioning VPD page (SBC-4) */
+static int inquiry_vpd_b2(unsigned char *arr)
 {
 	memset(arr, 0, 0x4);
 	arr[0] = 0;			/* threshold exponent */
-
 	if (sdebug_lbpu)
 		arr[1] = 1 << 7;
-
 	if (sdebug_lbpws)
 		arr[1] |= 1 << 6;
-
 	if (sdebug_lbpws10)
 		arr[1] |= 1 << 5;
-
-	if (sdebug_lbprz)
-		arr[1] |= 1 << 2;
-
+	if (sdebug_lbprz && scsi_debug_lbp())
+		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
+	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
+	/* minimum_percentage=0; provisioning_type=0 (unknown) */
+	/* threshold_percentage=0 */
 	return 0x4;
 }
 
@@ -1232,12 +1234,13 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	unsigned char * arr;
 	unsigned char *cmd = scp->cmnd;
 	int alloc_len, n, ret;
-	bool have_wlun;
+	bool have_wlun, is_disk;
 
 	alloc_len = get_unaligned_be16(cmd + 3);
 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
 	if (! arr)
 		return DID_REQUEUE << 16;
+	is_disk = (sdebug_ptype == TYPE_DISK);
 	have_wlun = scsi_is_wlun(scp->device->lun);
 	if (have_wlun)
 		pq_pdt = TYPE_WLUN;	/* present, wlun */
@@ -1275,11 +1278,12 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 			arr[n++] = 0x86;  /* extended inquiry */
 			arr[n++] = 0x87;  /* mode page policy */
 			arr[n++] = 0x88;  /* SCSI ports */
-			arr[n++] = 0x89;  /* ATA information */
-			arr[n++] = 0xb0;  /* Block limits (SBC) */
-			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
-			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
-				arr[n++] = 0xb2;
+			if (is_disk) {	  /* SBC only */
+				arr[n++] = 0x89;  /* ATA information */
+				arr[n++] = 0xb0;  /* Block limits */
+				arr[n++] = 0xb1;  /* Block characteristics */
+				arr[n++] = 0xb2;  /* Logical Block Prov */
+			}
 			arr[3] = n - 4;	  /* number of supported VPD pages */
 		} else if (0x80 == cmd[2]) { /* unit serial number */
 			arr[1] = cmd[2];	/*sanity */
@@ -1287,21 +1291,21 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 			memcpy(&arr[4], lu_id_str, len);
 		} else if (0x83 == cmd[2]) { /* device identification */
 			arr[1] = cmd[2];	/*sanity */
-			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
-						 target_dev_id, lu_id_num,
-						 lu_id_str, len);
+			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
+						target_dev_id, lu_id_num,
+						lu_id_str, len);
 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
 			arr[1] = cmd[2];	/*sanity */
-			arr[3] = inquiry_evpd_84(&arr[4]);
+			arr[3] = inquiry_vpd_84(&arr[4]);
 		} else if (0x85 == cmd[2]) { /* Management network addresses */
 			arr[1] = cmd[2];	/*sanity */
-			arr[3] = inquiry_evpd_85(&arr[4]);
+			arr[3] = inquiry_vpd_85(&arr[4]);
 		} else if (0x86 == cmd[2]) { /* extended inquiry */
 			arr[1] = cmd[2];	/*sanity */
 			arr[3] = 0x3c;	/* number of following entries */
 			if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
-			else if (sdebug_dif)
+			else if (have_dif_prot)
 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
 			else
 				arr[4] = 0x0;   /* no protection stuff */
@@ -1315,20 +1319,20 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 			arr[10] = 0x82;	 /* mlus, per initiator port */
 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
 			arr[1] = cmd[2];	/*sanity */
-			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
-		} else if (0x89 == cmd[2]) { /* ATA information */
+			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
+		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
 			arr[1] = cmd[2];        /*sanity */
-			n = inquiry_evpd_89(&arr[4]);
+			n = inquiry_vpd_89(&arr[4]);
 			put_unaligned_be16(n, arr + 2);
-		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
+		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
 			arr[1] = cmd[2];        /*sanity */
-			arr[3] = inquiry_evpd_b0(&arr[4]);
-		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
+			arr[3] = inquiry_vpd_b0(&arr[4]);
+		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
 			arr[1] = cmd[2];        /*sanity */
-			arr[3] = inquiry_evpd_b1(&arr[4]);
-		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
+			arr[3] = inquiry_vpd_b1(&arr[4]);
+		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
 			arr[1] = cmd[2];        /*sanity */
-			arr[3] = inquiry_evpd_b2(&arr[4]);
+			arr[3] = inquiry_vpd_b2(&arr[4]);
 		} else {
 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
 			kfree(arr);
@@ -1355,15 +1359,17 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 	memcpy(&arr[16], inq_product_id, 16);
 	memcpy(&arr[32], inq_product_rev, 4);
 	/* version descriptors (2 bytes each) follow */
-	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
-	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
+	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
+	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
 	n = 62;
-	if (sdebug_ptype == TYPE_DISK) {
-		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
-	} else if (sdebug_ptype == TYPE_TAPE) {
-		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
-	}
-	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
+	if (is_disk) {		/* SBC-4 no version claimed */
+		put_unaligned_be16(0x600, arr + n);
+		n += 2;
+	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
+		put_unaligned_be16(0x525, arr + n);
+		n += 2;
+	}
+	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
 	ret = fill_from_dev_buffer(scp, arr,
 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
 	kfree(arr);
@@ -1499,13 +1505,17 @@ static int resp_readcap16(struct scsi_cmnd * scp,
 
 	if (scsi_debug_lbp()) {
 		arr[14] |= 0x80; /* LBPME */
-		if (sdebug_lbprz)
-			arr[14] |= 0x40; /* LBPRZ */
+		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
+		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
+		 * in the wider field maps to 0 in this field.
+		 */
+		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
+			arr[14] |= 0x40;
 	}
 
 	arr[15] = sdebug_lowest_aligned & 0xff;
 
-	if (sdebug_dif) {
+	if (have_dif_prot) {
 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
 		arr[12] |= 1; /* PROT_EN */
 	}
@@ -1935,22 +1945,23 @@ static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
 static int resp_mode_sense(struct scsi_cmnd *scp,
 			   struct sdebug_dev_info *devip)
 {
-	unsigned char dbd, llbaa;
 	int pcontrol, pcode, subpcode, bd_len;
 	unsigned char dev_spec;
-	int alloc_len, msense_6, offset, len, target_dev_id;
+	int alloc_len, offset, len, target_dev_id;
 	int target = scp->device->id;
 	unsigned char * ap;
 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
 	unsigned char *cmd = scp->cmnd;
+	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
 
-	dbd = !!(cmd[1] & 0x8);
+	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
 	pcontrol = (cmd[2] & 0xc0) >> 6;
 	pcode = cmd[2] & 0x3f;
 	subpcode = cmd[3];
 	msense_6 = (MODE_SENSE == cmd[0]);
-	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
-	if ((sdebug_ptype == TYPE_DISK) && (dbd == 0))
+	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
+	is_disk = (sdebug_ptype == TYPE_DISK);
+	if (is_disk && !dbd)
 		bd_len = llbaa ? 16 : 8;
 	else
 		bd_len = 0;
@@ -1963,7 +1974,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
 			(devip->target * 1000) - 3;
 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
-	if (sdebug_ptype == TYPE_DISK)
+	if (is_disk)
 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
 	else
 		dev_spec = 0x0;
@@ -2002,6 +2013,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
 		return check_condition_result;
 	}
+	bad_pcode = false;
+
 	switch (pcode) {
 	case 0x1:	/* Read-Write error recovery page, direct access */
 		len = resp_err_recov_pg(ap, pcontrol, target);
@@ -2012,12 +2025,18 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 		offset += len;
 		break;
         case 0x3:       /* Format device page, direct access */
-                len = resp_format_pg(ap, pcontrol, target);
-                offset += len;
+		if (is_disk) {
+			len = resp_format_pg(ap, pcontrol, target);
+			offset += len;
+		} else
+			bad_pcode = true;
                 break;
 	case 0x8:	/* Caching page, direct access */
-		len = resp_caching_pg(ap, pcontrol, target);
-		offset += len;
+		if (is_disk) {
+			len = resp_caching_pg(ap, pcontrol, target);
+			offset += len;
+		} else
+			bad_pcode = true;
 		break;
 	case 0xa:	/* Control Mode page, all devices */
 		len = resp_ctrl_m_pg(ap, pcontrol, target);
@@ -2046,8 +2065,12 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 		if ((0 == subpcode) || (0xff == subpcode)) {
 			len = resp_err_recov_pg(ap, pcontrol, target);
 			len += resp_disconnect_pg(ap + len, pcontrol, target);
-			len += resp_format_pg(ap + len, pcontrol, target);
-			len += resp_caching_pg(ap + len, pcontrol, target);
+			if (is_disk) {
+				len += resp_format_pg(ap + len, pcontrol,
+						      target);
+				len += resp_caching_pg(ap + len, pcontrol,
+						       target);
+			}
 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
 			if (0xff == subpcode) {
@@ -2056,13 +2079,17 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
 			}
 			len += resp_iec_m_pg(ap + len, pcontrol, target);
+			offset += len;
 		} else {
 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
 			return check_condition_result;
                 }
-		offset += len;
 		break;
 	default:
+		bad_pcode = true;
+		break;
+	}
+	if (bad_pcode) {
 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
 		return check_condition_result;
 	}
@@ -2753,9 +2780,10 @@ static void unmap_region(sector_t lba, unsigned int len)
 		    lba + sdebug_unmap_granularity <= end &&
 		    index < map_size) {
 			clear_bit(index, map_storep);
-			if (sdebug_lbprz) {
+			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
 				memset(fake_storep +
-				       lba * sdebug_sector_size, 0,
+				       lba * sdebug_sector_size,
+				       (sdebug_lbprz & 1) ? 0 : 0xff,
 				       sdebug_sector_size *
 				       sdebug_unmap_granularity);
 			}
@@ -4098,7 +4126,8 @@ MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
 MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
 MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
 MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
-MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
+MODULE_PARM_DESC(lbprz,
+	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
 MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
 MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
 MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
@@ -4112,7 +4141,7 @@ MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err...
 MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
 MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
 MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
-MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
+MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
 MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
 MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
 MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
@@ -4125,21 +4154,21 @@ MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size
 MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
 MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
 
-static char sdebug_info[256];
+#define SDEBUG_INFO_LEN 256
+static char sdebug_info[SDEBUG_INFO_LEN];
 
 static const char * scsi_debug_info(struct Scsi_Host * shp)
 {
 	int k;
 
-	k = scnprintf(sdebug_info, sizeof(sdebug_info),
-		      "%s: version %s [%s], dev_size_mb=%d, opts=0x%x\n",
-		      my_name, SDEBUG_VERSION, sdebug_version_date,
-		      sdebug_dev_size_mb, sdebug_opts);
-	if (k >= (sizeof(sdebug_info) - 1))
+	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
+		      my_name, SDEBUG_VERSION, sdebug_version_date);
+	if (k >= (SDEBUG_INFO_LEN - 1))
 		return sdebug_info;
-	scnprintf(sdebug_info + k, sizeof(sdebug_info) - k,
-		  "%s: submit_queues=%d, statistics=%d\n", my_name,
-		  submit_queues, (int)sdebug_statistics);
+	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
+		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
+		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
+		  "statistics", (int)sdebug_statistics);
 	return sdebug_info;
 }
 
-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 5/6] scsi_debug: uuid for lu name
Date: Fri,  6 May 2016 00:40:28 -0400
Message-ID: <1462509629-24282-6-git-send-email-dgilbert@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55638 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1751343AbcEFEkr (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:47 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

Permit changing of a LU name from a (fake) IEEE registered NAA (5)
to a locally assigned UUID. Using a UUID (RFC 4122) for a SCSI
designation descriptor (e.g. a LU name) was added in spc5r08.pdf
(a draft INCITS standard) on 25 January 2016. Add parameter
uuid_ctl to use a separate UUID for each LU (storage device) name.
Additional option for all LU names to have the same UUID (since
their storage is shared). Previous action of using NAA identifier
for LU name remains the default.

Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/scsi_debug.c | 61 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index afbbfaa..efb4549 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/atomic.h>
 #include <linux/hrtimer.h>
+#include <linux/uuid.h>
 
 #include <net/checksum.h>
 
@@ -137,6 +138,7 @@ static const char *sdebug_version_date = "20160430";
 #define DEF_STRICT 0
 #define DEF_STATISTICS false
 #define DEF_SUBMIT_QUEUES 1
+#define DEF_UUID_CTL 0
 #define JDELAY_OVERRIDDEN -9999
 
 #define SDEBUG_LUN_0_VAL 0
@@ -241,6 +243,7 @@ struct sdebug_dev_info {
 	unsigned int channel;
 	unsigned int target;
 	u64 lun;
+	uuid_be lu_name;
 	struct sdebug_host_info *sdbg_host;
 	unsigned long uas_bm[1];
 	atomic_t num_in_q;
@@ -600,6 +603,7 @@ static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
 static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
 static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
 static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
+static int sdebug_uuid_ctl = DEF_UUID_CTL;
 static bool sdebug_removable = DEF_REMOVABLE;
 static bool sdebug_clustering;
 static bool sdebug_host_lock = DEF_HOST_LOCK;
@@ -928,8 +932,8 @@ static const u64 naa5_comp_c = 0x5111111000000000ULL;
 /* Device identification VPD page. Returns number of bytes placed in arr */
 static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
 			  int target_dev_id, int dev_id_num,
-			  const char *dev_id_str,
-			  int dev_id_str_len)
+			  const char *dev_id_str, int dev_id_str_len,
+			  const uuid_be *lu_name)
 {
 	int num, port_a;
 	char b[32];
@@ -946,13 +950,25 @@ static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
 	arr[3] = num;
 	num += 4;
 	if (dev_id_num >= 0) {
-		/* NAA-5, Logical unit identifier (binary) */
-		arr[num++] = 0x1;	/* binary (not necessarily sas) */
-		arr[num++] = 0x3;	/* PIV=0, lu, naa */
-		arr[num++] = 0x0;
-		arr[num++] = 0x8;
-		put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
-		num += 8;
+		if (sdebug_uuid_ctl) {
+			/* Locally assigned UUID */
+			arr[num++] = 0x1;  /* binary (not necessarily sas) */
+			arr[num++] = 0xa;  /* PIV=0, lu, naa */
+			arr[num++] = 0x0;
+			arr[num++] = 0x12;
+			arr[num++] = 0x10; /* uuid type=1, locally assigned */
+			arr[num++] = 0x0;
+			memcpy(arr + num, lu_name, 16);
+			num += 16;
+		} else {
+			/* NAA-5, Logical unit identifier (binary) */
+			arr[num++] = 0x1;  /* binary (not necessarily sas) */
+			arr[num++] = 0x3;  /* PIV=0, lu, naa */
+			arr[num++] = 0x0;
+			arr[num++] = 0x8;
+			put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
+			num += 8;
+		}
 		/* Target relative port number */
 		arr[num++] = 0x61;	/* proto=sas, binary */
 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
@@ -1293,7 +1309,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 			arr[1] = cmd[2];	/*sanity */
 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
 						target_dev_id, lu_id_num,
-						lu_id_str, len);
+						lu_id_str, len,
+						&devip->lu_name);
 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
 			arr[1] = cmd[2];	/*sanity */
 			arr[3] = inquiry_vpd_84(&arr[4]);
@@ -3503,6 +3520,9 @@ static void sdebug_q_cmd_wq_complete(struct work_struct *work)
 	sdebug_q_cmd_complete(sd_dp);
 }
 
+static bool got_shared_uuid;
+static uuid_be shared_uuid;
+
 static struct sdebug_dev_info *sdebug_device_create(
 			struct sdebug_host_info *sdbg_host, gfp_t flags)
 {
@@ -3510,6 +3530,17 @@ static struct sdebug_dev_info *sdebug_device_create(
 
 	devip = kzalloc(sizeof(*devip), flags);
 	if (devip) {
+		if (sdebug_uuid_ctl == 1)
+			uuid_be_gen(&devip->lu_name);
+		else if (sdebug_uuid_ctl == 2) {
+			if (got_shared_uuid)
+				devip->lu_name = shared_uuid;
+			else {
+				uuid_be_gen(&shared_uuid);
+				got_shared_uuid = true;
+				devip->lu_name = shared_uuid;
+			}
+		}
 		devip->sdbg_host = sdbg_host;
 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
 	}
@@ -4101,6 +4132,7 @@ module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
 module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
 module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
 module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
+module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
 module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
 		   S_IRUGO | S_IWUSR);
 module_param_named(write_same_length, sdebug_write_same_length, int,
@@ -4150,6 +4182,8 @@ MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"
 MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
 MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
 MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
+MODULE_PARM_DESC(uuid_ctl,
+		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
 MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
 MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
 MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
@@ -4787,6 +4821,12 @@ static ssize_t strict_store(struct device_driver *ddp, const char *buf,
 }
 static DRIVER_ATTR_RW(strict);
 
+static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
+}
+static DRIVER_ATTR_RO(uuid_ctl);
+
 
 /* Note: The following array creates attribute files in the
    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
@@ -4825,6 +4865,7 @@ static struct attribute *sdebug_drv_attrs[] = {
 	&driver_attr_host_lock.attr,
 	&driver_attr_ndelay.attr,
 	&driver_attr_strict.attr,
+	&driver_attr_uuid_ctl.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(sdebug_drv);
-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: [PATCH v3 6/6] scsi_debug: use locally assigned naa
Date: Fri,  6 May 2016 00:40:29 -0400
Message-ID: <1462509629-24282-7-git-send-email-dgilbert@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:55646 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1751314AbcEFEkr (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Fri, 6 May 2016 00:40:47 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

For reported SAS addresses replace fake IEEE registered NAAs (5)
with locally assigned NAAs (3).

Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
 drivers/scsi/scsi_debug.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index efb4549..0f9ba41 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -925,9 +925,10 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
 static const char * inq_vendor_id = "Linux   ";
 static const char * inq_product_id = "scsi_debug      ";
 static const char *inq_product_rev = "0186";	/* version less '.' */
-static const u64 naa5_comp_a = 0x5222222000000000ULL;
-static const u64 naa5_comp_b = 0x5333333000000000ULL;
-static const u64 naa5_comp_c = 0x5111111000000000ULL;
+/* Use some locally assigned NAAs for SAS addresses. */
+static const u64 naa3_comp_a = 0x3222222000000000ULL;
+static const u64 naa3_comp_b = 0x3333333000000000ULL;
+static const u64 naa3_comp_c = 0x3111111000000000ULL;
 
 /* Device identification VPD page. Returns number of bytes placed in arr */
 static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
@@ -961,12 +962,12 @@ static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
 			memcpy(arr + num, lu_name, 16);
 			num += 16;
 		} else {
-			/* NAA-5, Logical unit identifier (binary) */
+			/* NAA-3, Logical unit identifier (binary) */
 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
 			arr[num++] = 0x0;
 			arr[num++] = 0x8;
-			put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
+			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
 			num += 8;
 		}
 		/* Target relative port number */
@@ -979,14 +980,14 @@ static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
 		arr[num++] = 0x0;
 		arr[num++] = 0x1;	/* relative port A */
 	}
-	/* NAA-5, Target port identifier */
+	/* NAA-3, Target port identifier */
 	arr[num++] = 0x61;	/* proto=sas, binary */
 	arr[num++] = 0x93;	/* piv=1, target port, naa */
 	arr[num++] = 0x0;
 	arr[num++] = 0x8;
-	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
+	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
 	num += 8;
-	/* NAA-5, Target port group identifier */
+	/* NAA-3, Target port group identifier */
 	arr[num++] = 0x61;	/* proto=sas, binary */
 	arr[num++] = 0x95;	/* piv=1, target port group id */
 	arr[num++] = 0x0;
@@ -995,19 +996,19 @@ static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
 	arr[num++] = 0;
 	put_unaligned_be16(port_group_id, arr + num);
 	num += 2;
-	/* NAA-5, Target device identifier */
+	/* NAA-3, Target device identifier */
 	arr[num++] = 0x61;	/* proto=sas, binary */
 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
 	arr[num++] = 0x0;
 	arr[num++] = 0x8;
-	put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
+	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
 	num += 8;
 	/* SCSI name string: Target device identifier */
 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
 	arr[num++] = 0x0;
 	arr[num++] = 24;
-	memcpy(arr + num, "naa.52222220", 12);
+	memcpy(arr + num, "naa.32222220", 12);
 	num += 12;
 	snprintf(b, sizeof(b), "%08X", target_dev_id);
 	memcpy(arr + num, b, 8);
@@ -1086,7 +1087,7 @@ static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
 	arr[num++] = 0x0;	/* reserved */
 	arr[num++] = 0x8;	/* length */
-	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
+	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
 	num += 8;
 	arr[num++] = 0x0;	/* reserved */
 	arr[num++] = 0x0;	/* reserved */
@@ -1101,7 +1102,7 @@ static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
 	arr[num++] = 0x0;	/* reserved */
 	arr[num++] = 0x8;	/* length */
-	put_unaligned_be64(naa5_comp_a + port_b, arr + num);
+	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
 	num += 8;
 
 	return num;
@@ -1931,10 +1932,10 @@ static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
 		};
 	int port_a, port_b;
 
-	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
-	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
-	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
-	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
+	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
+	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
+	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
+	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
 	port_a = target_dev_id + 1;
 	port_b = port_a + 1;
 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
-- 
2.7.4


From mboxrd@z Thu Jan  1 00:00:00 1970
From: Bart Van Assche <bart.vanassche@sandisk.com>
Subject: Re: [PATCH v3 3/6] scsi_debug: add multiple queue support
Date: Mon, 9 May 2016 09:12:28 -0700
Message-ID: <5730B6EC.90001@sandisk.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
 <1462509629-24282-4-git-send-email-dgilbert@interlog.com>
Mime-Version: 1.0
Content-Type: text/plain; charset="windows-1252"; format=flowed
Content-Transfer-Encoding: 7bit
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from mail-bl2on0075.outbound.protection.outlook.com ([65.55.169.75]:48066
	"EHLO na01-bl2-obe.outbound.protection.outlook.com"
	rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP
	id S1752098AbcEIQMd (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Mon, 9 May 2016 12:12:33 -0400
In-Reply-To: <1462509629-24282-4-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: Douglas Gilbert <dgilbert@interlog.com>, linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

On 05/05/2016 09:40 PM, Douglas Gilbert wrote:
>   static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
>   {
>   	unsigned long iflags;
> -	int k, qmax, r_qmax;
> +	int j, k, qmax, r_qmax;
> +	struct sdebug_queue *sqp;
>   	struct sdebug_queued_cmd *sqcp;
>   	struct sdebug_dev_info *devip;
>   	struct sdebug_defer *sd_dp;
>
> -	[ ... ]
> +	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
> +		spin_lock_irqsave(&sqp->qc_lock, iflags);
> +		qmax = sdebug_max_queue;
> +		r_qmax = atomic_read(&retired_max_queue);
> +		if (r_qmax > qmax)
> +			qmax = r_qmax;
> +		for (k = 0; k < qmax; ++k) {
> +			if (test_bit(k, sqp->in_use_bm)) {
> +				sqcp = &sqp->qc_arr[k];
> +				if (cmnd != sqcp->a_cmnd)
> +					continue;
> +				/* found */
> +				[ ... ]

It is not clear to me why a for-loop is used in this function to look up 
the sqp pointer instead of calling get_queue() or using sqa_idx?

>   static const char * scsi_debug_info(struct Scsi_Host * shp)
>   {
> -	sprintf(sdebug_info,
> -		"scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x",
> -		SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb,
> -		sdebug_opts);
> +	int k;
> +
> +	k = scnprintf(sdebug_info, sizeof(sdebug_info),
> +		      "%s: version %s [%s], dev_size_mb=%d, opts=0x%x\n",
> +		      my_name, SDEBUG_VERSION, sdebug_version_date,
> +		      sdebug_dev_size_mb, sdebug_opts);
> +	if (k >= (sizeof(sdebug_info) - 1))
> +		return sdebug_info;
> +	scnprintf(sdebug_info + k, sizeof(sdebug_info) - k,
> +		  "%s: submit_queues=%d, statistics=%d\n", my_name,
> +		  submit_queues, (int)sdebug_statistics);
>   	return sdebug_info;
>   }

 From the comment above the definition of scnprintf(): "The return value 
is the number of characters written into @buf not including the trailing 
'\0'". Maybe you need snprintf() instead of scnprintf()?

Bart.

From mboxrd@z Thu Jan  1 00:00:00 1970
From: Douglas Gilbert <dgilbert@interlog.com>
Subject: Re: [PATCH v3 3/6] scsi_debug: add multiple queue support
Date: Tue, 10 May 2016 00:30:43 +0200
Message-ID: <57310F93.2000709@interlog.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
 <1462509629-24282-4-git-send-email-dgilbert@interlog.com>
 <5730B6EC.90001@sandisk.com>
Reply-To: dgilbert@interlog.com
Mime-Version: 1.0
Content-Type: text/plain; charset=windows-1252; format=flowed
Content-Transfer-Encoding: 7bit
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from smtp.infotech.no ([82.134.31.41]:43310 "EHLO smtp.infotech.no"
	rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
	id S1752446AbcEIWau (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Mon, 9 May 2016 18:30:50 -0400
In-Reply-To: <5730B6EC.90001@sandisk.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: Bart Van Assche <bart.vanassche@sandisk.com>, linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com

On 2016-05-09 06:12 PM, Bart Van Assche wrote:
> On 05/05/2016 09:40 PM, Douglas Gilbert wrote:
>>   static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
>>   {
>>       unsigned long iflags;
>> -    int k, qmax, r_qmax;
>> +    int j, k, qmax, r_qmax;
>> +    struct sdebug_queue *sqp;
>>       struct sdebug_queued_cmd *sqcp;
>>       struct sdebug_dev_info *devip;
>>       struct sdebug_defer *sd_dp;
>>
>> -    [ ... ]
>> +    for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
>> +        spin_lock_irqsave(&sqp->qc_lock, iflags);
>> +        qmax = sdebug_max_queue;
>> +        r_qmax = atomic_read(&retired_max_queue);
>> +        if (r_qmax > qmax)
>> +            qmax = r_qmax;
>> +        for (k = 0; k < qmax; ++k) {
>> +            if (test_bit(k, sqp->in_use_bm)) {
>> +                sqcp = &sqp->qc_arr[k];
>> +                if (cmnd != sqcp->a_cmnd)
>> +                    continue;
>> +                /* found */
>> +                [ ... ]
>
> It is not clear to me why a for-loop is used in this function to look up the sqp
> pointer instead of calling get_queue() or using sqa_idx?

Yes get_queue() could be used to remove the outer loop.

sqa_idx is found in the sdebug_defer structure and instances of it
exist only for scsi commands that are currently deferred (on or work
item or a hr timer). There is a pointer from scsi_defer to the
corresponding scsi_cmnd but not vice versa.

Using the every_nth parameter, scsi commands can be ignored, meaning
they are neither deferred (queued) nor completed (by calling scsi_done()).
In this case the driver just returns on the command delivery thread
(without error) and forgets about that scsi command instance. It is
simulating an unreported transport or LLD failure. So there is an
extremely high chance the mid-level will attempt to abort that command.
In that case there is no related sqa_idx and that scsi command will not
be found by stop_queued_cmnd(). That is fine since there are no related
resources to free up.

So IMO the code is correct as it stands but its efficiency could be
improved by using get_queue() to replace the outer loop.

>>   static const char * scsi_debug_info(struct Scsi_Host * shp)
>>   {
>> -    sprintf(sdebug_info,
>> -        "scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x",
>> -        SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb,
>> -        sdebug_opts);
>> +    int k;
>> +
>> +    k = scnprintf(sdebug_info, sizeof(sdebug_info),
>> +              "%s: version %s [%s], dev_size_mb=%d, opts=0x%x\n",
>> +              my_name, SDEBUG_VERSION, sdebug_version_date,
>> +              sdebug_dev_size_mb, sdebug_opts);
>> +    if (k >= (sizeof(sdebug_info) - 1))
>> +        return sdebug_info;
>> +    scnprintf(sdebug_info + k, sizeof(sdebug_info) - k,
>> +          "%s: submit_queues=%d, statistics=%d\n", my_name,
>> +          submit_queues, (int)sdebug_statistics);
>>       return sdebug_info;
>>   }
>
>  From the comment above the definition of scnprintf(): "The return value is the
> number of characters written into @buf not including the trailing '\0'". Maybe
> you need snprintf() instead of scnprintf()?

The maximum return value from the first scnprintf(sdebug_info ...)
is (sizeof(sdebug_info) - 1)). So strictly speaking the early return
comparison should be "==" for scnprintf and ">=" for snprintf. Given
that snprintf is more dangerous then scnprintf (e.g. with repeated
"k += snprintf(buff + k, buff_len - k, ...)" statements) then I would
prefer to keep scnprintf and yes, ">=" is overkill but will work.

Doug Gilbert

From mboxrd@z Thu Jan  1 00:00:00 1970
From: Bart Van Assche <bart.vanassche@sandisk.com>
Subject: Re: [PATCH v3 3/6] scsi_debug: add multiple queue support
Date: Mon, 9 May 2016 15:36:33 -0700
Message-ID: <573110F1.2030305@sandisk.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
 <1462509629-24282-4-git-send-email-dgilbert@interlog.com>
 <5730B6EC.90001@sandisk.com> <57310F93.2000709@interlog.com>
Mime-Version: 1.0
Content-Type: text/plain; charset="windows-1252"; format=flowed
Content-Transfer-Encoding: 7bit
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from mail-bn1on0076.outbound.protection.outlook.com ([157.56.110.76]:19648
	"EHLO na01-bn1-obe.outbound.protection.outlook.com"
	rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP
	id S1751450AbcEIWgi (ORCPT <rfc822;linux-scsi@vger.kernel.org>);
	Mon, 9 May 2016 18:36:38 -0400
In-Reply-To: <57310F93.2000709@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: dgilbert@interlog.com, linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com

On 05/09/2016 03:30 PM, Douglas Gilbert wrote:> The maximum return value 
from the first scnprintf(sdebug_info ...)
> is (sizeof(sdebug_info) - 1)). So strictly speaking the early return
> comparison should be "==" for scnprintf and ">=" for snprintf. Given
> that snprintf is more dangerous then scnprintf (e.g. with repeated
> "k += snprintf(buff + k, buff_len - k, ...)" statements) then I would
> prefer to keep scnprintf and yes, ">=" is overkill but will work.

Thanks for the feedback. I'm fine with the other changes in this patch, 
hence:

Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>

From mboxrd@z Thu Jan  1 00:00:00 1970
From: "Martin K. Petersen" <martin.petersen@oracle.com>
Subject: Re: [PATCH v3 0/6] scsi_debug: multiple queue support and cleanup
Date: Tue, 10 May 2016 21:27:06 -0400
Message-ID: <yq1h9e5peol.fsf@sermon.lab.mkp.net>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
Mime-Version: 1.0
Content-Type: text/plain
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from aserp1040.oracle.com ([141.146.126.69]:25536 "EHLO
	aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
	with ESMTP id S1751069AbcEKB1W (ORCPT
	<rfc822;linux-scsi@vger.kernel.org>); Tue, 10 May 2016 21:27:22 -0400
In-Reply-To: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
	(Douglas Gilbert's message of "Fri, 6 May 2016 00:40:23 -0400")
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: Douglas Gilbert <dgilbert@interlog.com>
Cc: linux-scsi@vger.kernel.org, martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com, bart.vanassche@sandisk.com

>>>>> "Douglas" == Douglas Gilbert <dgilbert@interlog.com> writes:

Douglas> Changes since v2.5 - rework the 'add multiple queue support'
Douglas> patch based on reviewers' comments to more closely follow the
Douglas> scsi/block mq template

Applied the remaining patches in your series to 4.7/scsi-queue.

Thanks!

-- 
Martin K. Petersen	Oracle Linux Engineering

From mboxrd@z Thu Jan  1 00:00:00 1970
From: Andy Shevchenko <andy.shevchenko@gmail.com>
Subject: Re: [PATCH v3 5/6] scsi_debug: uuid for lu name
Date: Tue, 31 May 2016 15:57:40 +0300
Message-ID: <CAHp75VfEbLdGhL851RZdM5+UHNKFNqu31VNH=2a5SWc3LjrMsA@mail.gmail.com>
References: <1462509629-24282-1-git-send-email-dgilbert@interlog.com>
	<1462509629-24282-6-git-send-email-dgilbert@interlog.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Return-path: <linux-scsi-owner@vger.kernel.org>
Received: from mail-oi0-f67.google.com ([209.85.218.67]:34656 "EHLO
	mail-oi0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
	with ESMTP id S1753872AbcEaM5l (ORCPT
	<rfc822;linux-scsi@vger.kernel.org>); Tue, 31 May 2016 08:57:41 -0400
Received: by mail-oi0-f67.google.com with SMTP id r64so30330876oie.1
        for <linux-scsi@vger.kernel.org>; Tue, 31 May 2016 05:57:41 -0700 (PDT)
In-Reply-To: <1462509629-24282-6-git-send-email-dgilbert@interlog.com>
Sender: linux-scsi-owner@vger.kernel.org
List-Id: linux-scsi@vger.kernel.org
To: Douglas Gilbert <dgilbert@interlog.com>
Cc: linux-scsi <linux-scsi@vger.kernel.org>, "Martin K. Petersen" <martin.petersen@oracle.com>, Tomas Winkler <tomas.winkler@intel.com>, emilne@redhat.com, bart.vanassche@sandisk.com

On Fri, May 6, 2016 at 7:40 AM, Douglas Gilbert <dgilbert@interlog.com> wrote:
> Permit changing of a LU name from a (fake) IEEE registered NAA (5)
> to a locally assigned UUID. Using a UUID (RFC 4122) for a SCSI
> designation descriptor (e.g. a LU name) was added in spc5r08.pdf
> (a draft INCITS standard) on 25 January 2016. Add parameter
> uuid_ctl to use a separate UUID for each LU (storage device) name.
> Additional option for all LU names to have the same UUID (since
> their storage is shared). Previous action of using NAA identifier
> for LU name remains the default.

> @@ -3503,6 +3520,9 @@ static void sdebug_q_cmd_wq_complete(struct work_struct *work)
>         sdebug_q_cmd_complete(sd_dp);
>  }
>
> +static bool got_shared_uuid;
> +static uuid_be shared_uuid;

So, the assignment to them is non-atomic, is it a problem here?

> @@ -3510,6 +3530,17 @@ static struct sdebug_dev_info *sdebug_device_create(
>
>         devip = kzalloc(sizeof(*devip), flags);
>         if (devip) {
> +               if (sdebug_uuid_ctl == 1)
> +                       uuid_be_gen(&devip->lu_name);
> +               else if (sdebug_uuid_ctl == 2) {
> +                       if (got_shared_uuid)
> +                               devip->lu_name = shared_uuid;
> +                       else {
> +                               uuid_be_gen(&shared_uuid);
> +                               got_shared_uuid = true;
> +                               devip->lu_name = shared_uuid;
> +                       }
> +               }

Perhaps
                       if (got_shared_uuid == false)
                               uuid_be_gen(&shared_uuid);
                               got_shared_uuid = true;
                       }
                       devip->lu_name = shared_uuid;

>                 devip->sdbg_host = sdbg_host;
>                 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
>         }

> @@ -4150,6 +4182,8 @@ MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"
>  MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
>  MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
>  MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
> +MODULE_PARM_DESC(uuid_ctl,
> +                "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");

Why not on one line?

>  MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
>  MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
>  MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
> @@ -4787,6 +4821,12 @@ static ssize_t strict_store(struct device_driver *ddp, const char *buf,
>  }
>  static DRIVER_ATTR_RW(strict);
>
> +static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
> +{
> +       return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);

It will never show the difference between 1 and 2. Was it on purpose?

> +}
> +static DRIVER_ATTR_RO(uuid_ctl);

-- 
With Best Regards,
Andy Shevchenko

