bk://linux-scsi.bkbits.net/scsi-misc-2.6
jejb@mulgrave.(none)|ChangeSet|20041024214801|61319 jejb

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/11/14 21:35:57-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi
# 
# drivers/scsi/qla1280.c
#   2004/11/14 21:35:54-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/11 15:07:32-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi
# 
# drivers/scsi/qla1280.c
#   2004/11/11 15:07:28-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/24 22:09:45-07:00 akpm@bix.(none) 
#   Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6
#   into bix.(none):/usr/src/bk-scsi
# 
# drivers/scsi/megaraid/megaraid_mbox.c
#   2004/10/24 22:09:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/24 16:48:01-05:00 jejb@mulgrave.(none) 
#   scsi_debug v 1.75
#   
#   From: 	Douglas Gilbert <dougg@torque.net>
#   
#       - fix highmem data transfers
#            - fix kunmap_atomic() argument
#            - disable clustering
#       - allow every_nth < 0 for error continuously once
#         count is reached
#       - minor sense buffer handling cleanup
#   
#   Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
# 
# drivers/scsi/scsi_debug.c
#   2004/10/24 16:47:49-05:00 jejb@mulgrave.(none) +265 -214
#   scsi_debug v 1.75
# 
# ChangeSet
#   2004/10/21 00:22:42-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi
# 
# drivers/scsi/megaraid/megaraid_mbox.h
#   2004/10/21 00:22:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/scsi/megaraid/megaraid_mbox.c
#   2004/10/21 00:22:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/19 22:12:26-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi
# 
# drivers/scsi/megaraid/megaraid_mbox.c
#   2004/10/19 22:12:23-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/15 22:40:42-07:00 akpm@bix.(none) 
#   Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6
#   into bix.(none):/usr/src/bk-scsi
# 
# drivers/scsi/megaraid/megaraid_mbox.h
#   2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/scsi/megaraid/megaraid_mbox.c
#   2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# Documentation/scsi/ChangeLog.megaraid
#   2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/13 13:38:51-07:00 akpm@bix.(none) 
#   foo
# 
# Documentation/scsi/ChangeLog.megaraid
#   2004/10/13 13:38:44-07:00 akpm@bix.(none) +0 -8
#   foo
# 
# drivers/scsi/megaraid/megaraid_mbox.h
#   2004/10/13 13:32:32-07:00 akpm@bix.(none) +0 -2
#   Auto merged
# 
# drivers/scsi/megaraid/megaraid_mbox.c
#   2004/10/13 13:32:32-07:00 akpm@bix.(none) +0 -3
#   Auto merged
# 
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	2004-11-15 21:14:47 -08:00
+++ b/drivers/scsi/scsi_debug.c	2004-11-15 21:14:47 -08:00
@@ -55,8 +55,8 @@
 #include "scsi_logging.h"
 #include "scsi_debug.h"
 
-#define SCSI_DEBUG_VERSION "1.74"
-static const char * scsi_debug_version_date = "20040829";
+#define SCSI_DEBUG_VERSION "1.75"
+static const char * scsi_debug_version_date = "20041023";
 
 /* Additional Sense Code (ASC) used */
 #define NO_ADDED_SENSE 0x0
@@ -82,7 +82,7 @@
 #define DEF_EVERY_NTH   0
 #define DEF_NUM_PARTS   0
 #define DEF_OPTS   0
-#define DEF_SCSI_LEVEL   4    /* SPC-2 */
+#define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
 #define DEF_PTYPE   0
 #define DEF_D_SENSE   0
 
@@ -95,6 +95,13 @@
  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
  *   - a RECOVERED_ERROR is simulated on successful read and write
  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ *
+ * When "every_nth" < 0 then after "- every_nth" commands:
+ *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
+ *   - a RECOVERED_ERROR is simulated on successful read and write
+ *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ * This will continue until some other action occurs (e.g. the user
+ * writing a new value (other than -1 or 1) to every_nth via sysfs).
  */
 
 /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
@@ -195,14 +202,12 @@
 	.cmd_per_lun =		3,
 	.max_sectors =		4096,
 	.unchecked_isa_dma = 	0,
-	.use_clustering = 	ENABLE_CLUSTERING,
+	.use_clustering = 	DISABLE_CLUSTERING,
 	.module =		THIS_MODULE,
 };
 
 static unsigned char * fake_storep;	/* ramdisk storage */
 
-static unsigned char spare_buff[SDEBUG_SENSE_LEN];
-
 static int num_aborts = 0;
 static int num_dev_resets = 0;
 static int num_bus_resets = 0;
@@ -228,21 +233,28 @@
 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
 
 /* function declarations */
-static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
-			int bufflen, struct sdebug_dev_info * devip);
-static int resp_mode_sense(unsigned char * cmd, int target,
-			   unsigned char * buff, int bufflen,
+static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
+			struct sdebug_dev_info * devip);
+static int resp_requests(struct scsi_cmnd * SCpnt,
+			 struct sdebug_dev_info * devip);
+static int resp_readcap(struct scsi_cmnd * SCpnt,
+			struct sdebug_dev_info * devip);
+static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target,
 			   struct sdebug_dev_info * devip);
 static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
 		     int num, struct sdebug_dev_info * devip);
 static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
 		      int num, struct sdebug_dev_info * devip);
-static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
-			    int bufflen, struct sdebug_dev_info * devip);
+static int resp_report_luns(struct scsi_cmnd * SCpnt,
+			    struct sdebug_dev_info * devip);
+static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+                                int arr_len);
+static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+                               int max_arr_len);
 static void timer_intr_handler(unsigned long);
 static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
 static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
-			    int asc, int asq, int inbandLen);
+			    int asc, int asq);
 static int check_reset(struct scsi_cmnd * SCpnt,
 		       struct sdebug_dev_info * devip);
 static int schedule_resp(struct scsi_cmnd * cmnd,
@@ -264,49 +276,20 @@
 static struct device pseudo_primary;
 static struct bus_type pseudo_lld_bus;
 
-static unsigned char * scatg2virt(const struct scatterlist * sclp)
-{
-	if (NULL == sclp)
-		return NULL;
-	else if (sclp->page)
-		return (unsigned char *)page_address(sclp->page) +
-		       sclp->offset;
-	else
-		return NULL;
-}
 
 static
 int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 {
 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
 	int block, upper_blk, num, k;
-	unsigned char *buff;
 	int errsts = 0;
 	int target = SCpnt->device->id;
-	int bufflen = SCpnt->request_bufflen;
-	unsigned long capac;
 	struct sdebug_dev_info * devip = NULL;
-	unsigned char * sbuff;
 	int inj_recovered = 0;
 
 	if (done == NULL)
 		return 0;	/* assume mid level reprocessing command */
 
-	if (SCpnt->use_sg) { /* just use first element */
-		struct scatterlist *sgpnt = (struct scatterlist *)
-						SCpnt->request_buffer;
-
-		buff = scatg2virt(&sgpnt[0]);
-		bufflen = sgpnt[0].length;
-		/* READ and WRITE process scatterlist themselves */
-	}
-	else
-		buff = (unsigned char *) SCpnt->request_buffer;
-	if (NULL == buff) {
-		buff = spare_buff;	/* assume cmd moves no data */
-		bufflen = SDEBUG_SENSE_LEN;
-	}
-
 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
 		printk(KERN_INFO "scsi_debug: cmd ");
 		for (k = 0, num = SCpnt->cmd_len; k < num; ++k)
@@ -328,9 +311,11 @@
 		return schedule_resp(SCpnt, NULL, done,
 				     DID_NO_CONNECT << 16, 0);
 
-        if ((scsi_debug_every_nth > 0) &&
-            (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) {
-                scsi_debug_cmnd_count =0;
+        if ((scsi_debug_every_nth != 0) &&
+            (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
+                scsi_debug_cmnd_count = 0;
+		if (scsi_debug_every_nth < -1)
+			scsi_debug_every_nth = -1;
 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
 			return 0; /* ignore command causing timeout */
 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
@@ -339,23 +324,14 @@
 
 	switch (*cmd) {
 	case INQUIRY:     /* mandatory, ignore unit attention */
-		errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
+		errsts = resp_inquiry(SCpnt, target, devip);
 		break;
 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
-		if (devip) {
-			sbuff = devip->sense_buff;
-			memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ?
-					     bufflen : SDEBUG_SENSE_LEN);
-			mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0, 7);
-		} else {
-			memset(buff, 0, bufflen);
-			buff[0] = 0x70;
-		}
+		errsts = resp_requests(SCpnt, devip);
 		break;
 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
 	case START_STOP:
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
 		if ((errsts = check_reset(SCpnt, devip)))
@@ -366,40 +342,24 @@
 		break;
 	case SEND_DIAGNOSTIC:     /* mandatory */
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
 		break;
 	case TEST_UNIT_READY:     /* mandatory */
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
 		break;
         case RESERVE:
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
                 break;
         case RESERVE_10:
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
                 break;
         case RELEASE:
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
                 break;
         case RELEASE_10:
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
                 break;
 	case READ_CAPACITY:
-		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
-		if (bufflen > 7) {
-			capac = (unsigned long)sdebug_capacity - 1;
-			buff[0] = (capac >> 24);
-			buff[1] = (capac >> 16) & 0xff;
-			buff[2] = (capac >> 8) & 0xff;
-			buff[3] = capac & 0xff;
-			buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
-			buff[7] = SECT_SIZE_PER(target) & 0xff;
-		}
+		errsts = resp_readcap(SCpnt, devip);
 		break;
 	case READ_16:
 	case READ_12:
@@ -432,12 +392,15 @@
 		errsts = resp_read(SCpnt, upper_blk, block, num, devip);
 		if (inj_recovered && (0 == errsts)) {
 			mk_sense_buffer(devip, RECOVERED_ERROR,
-					THRESHHOLD_EXCEEDED, 0, 18);
+					THRESHHOLD_EXCEEDED, 0);
 			errsts = check_condition_result;
 		}
 		break;
 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
-		errsts = resp_report_luns(cmd, buff, bufflen, devip);
+		errsts = resp_report_luns(SCpnt, devip);
+		break;
+	case VERIFY:		/* 10 byte SBC-2 command */
+		errsts = check_reset(SCpnt, devip);
 		break;
 	case WRITE_16:
 	case WRITE_12:
@@ -470,19 +433,16 @@
 		errsts = resp_write(SCpnt, upper_blk, block, num, devip);
 		if (inj_recovered && (0 == errsts)) {
 			mk_sense_buffer(devip, RECOVERED_ERROR,
-					THRESHHOLD_EXCEEDED, 0, 18);
+					THRESHHOLD_EXCEEDED, 0);
 			errsts = check_condition_result;
 		}
 		break;
 	case MODE_SENSE:
 	case MODE_SENSE_10:
-		if ((errsts = check_reset(SCpnt, devip)))
-			break;
-		errsts = resp_mode_sense(cmd, target, buff, bufflen, devip);
+		errsts = resp_mode_sense(SCpnt, target, devip);
 		break;
 	case SYNCHRONIZE_CACHE:
 		errsts = check_reset(SCpnt, devip);
-		memset(buff, 0, bufflen);
 		break;
 	default:
 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
@@ -490,7 +450,7 @@
 			       "supported\n", *cmd);
 		if ((errsts = check_reset(SCpnt, devip)))
 			break;	/* Unit attention takes precedence */
-		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0, 18);
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
 		errsts = check_condition_result;
 		break;
 	}
@@ -513,18 +473,105 @@
 			printk(KERN_INFO "scsi_debug: Reporting Unit "
 			       "attention: power on reset\n");
 		devip->reset = 0;
-		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0, 18);
+		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
 		return check_condition_result;
 	}
 	return 0;
 }
 
-#define SDEBUG_LONG_INQ_SZ 96
-#define SDEBUG_MAX_INQ_ARR_SZ 128
+/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
+static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+				int arr_len)
+{
+	int k, req_len, act_len, len, active;
+	void * kaddr;
+	void * kaddr_off;
+	struct scatterlist * sgpnt;
+
+	if (0 == scp->request_bufflen)
+		return 0;
+	if (NULL == scp->request_buffer)
+		return (DID_ERROR << 16);
+	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+	      (scp->sc_data_direction == DMA_FROM_DEVICE)))
+		return (DID_ERROR << 16);
+	if (0 == scp->use_sg) {
+		req_len = scp->request_bufflen;
+		act_len = (req_len < arr_len) ? req_len : arr_len;
+		memcpy(scp->request_buffer, arr, act_len);
+		scp->resid = req_len - act_len;
+		return 0;
+	}
+	sgpnt = (struct scatterlist *)scp->request_buffer;
+	active = 1;
+	for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
+		if (active) {
+			kaddr = (unsigned char *)
+				kmap_atomic(sgpnt->page, KM_USER0);
+			if (NULL == kaddr)
+				return (DID_ERROR << 16);
+			kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
+			len = sgpnt->length;
+			if ((req_len + len) > arr_len) {
+				active = 0;
+				len = arr_len - req_len;
+			}
+			memcpy(kaddr_off, arr + req_len, len);
+			kunmap_atomic(kaddr, KM_USER0);
+			act_len += len;
+		}
+		req_len += sgpnt->length;
+	}
+	scp->resid = req_len - act_len;
+	return 0;
+}
 
-static const char * vendor_id = "Linux   ";
-static const char * product_id = "scsi_debug      ";
-static const char * product_rev = "0004";
+/* Returns number of bytes fetched into 'arr' or -1 if error. */
+static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+			       int max_arr_len)
+{
+	int k, req_len, len, fin;
+	void * kaddr;
+	void * kaddr_off;
+	struct scatterlist * sgpnt;
+
+	if (0 == scp->request_bufflen)
+		return 0;
+	if (NULL == scp->request_buffer)
+		return -1;
+	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+	      (scp->sc_data_direction == DMA_TO_DEVICE)))
+		return -1;
+	if (0 == scp->use_sg) {
+		req_len = scp->request_bufflen;
+		len = (req_len < max_arr_len) ? req_len : max_arr_len;
+		memcpy(arr, scp->request_buffer, len);
+		return len;
+	}
+	sgpnt = (struct scatterlist *)scp->request_buffer;
+	for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
+		kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
+		if (NULL == kaddr)
+			return -1;
+		kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
+		len = sgpnt->length;
+		if ((req_len + len) > max_arr_len) {
+			len = max_arr_len - req_len;
+			fin = 1;
+		}
+		memcpy(arr + req_len, kaddr_off, len);
+		kunmap_atomic(kaddr, KM_USER0);
+		if (fin)
+			return req_len + len;
+		req_len += sgpnt->length;
+	}
+	return req_len;
+}
+
+
+static const char * inq_vendor_id = "Linux   ";
+static const char * inq_product_id = "scsi_debug      ";
+static const char * inq_product_rev = "0004";
 
 static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
 			   const char * dev_id_str, int dev_id_str_len)
@@ -536,8 +583,8 @@
 	arr[0] = 0x2;	/* ASCII */
 	arr[1] = 0x1;
 	arr[2] = 0x0;
-	memcpy(&arr[4], vendor_id, 8);
-	memcpy(&arr[12], product_id, 16);
+	memcpy(&arr[4], inq_vendor_id, 8);
+	memcpy(&arr[12], inq_product_id, 16);
 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
 	num = 8 + 16 + dev_id_str_len;
 	arr[3] = num;
@@ -558,24 +605,25 @@
 	return num + 12;
 }
 
-static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
-			int bufflen, struct sdebug_dev_info * devip)
+
+#define SDEBUG_LONG_INQ_SZ 96
+#define SDEBUG_MAX_INQ_ARR_SZ 128
+
+static int resp_inquiry(struct scsi_cmnd * scp, int target,
+			struct sdebug_dev_info * devip)
 {
 	unsigned char pq_pdt;
 	unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
-	int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ?
-			SDEBUG_MAX_INQ_ARR_SZ : bufflen;
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
+	int alloc_len;
 
-	if (bufflen < cmd[4])
-		printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d "
-		       "< alloc_length=%d\n", bufflen, (int)cmd[4]);
-	memset(buff, 0, bufflen);
+	alloc_len = (cmd[3] << 8) + cmd[4];
 	memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
 	pq_pdt = (scsi_debug_ptype & 0x1f);
 	arr[0] = pq_pdt;
 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
-			       	0, 18);
+			       	0);
 		return check_condition_result;
 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
 		int dev_id_num, len;
@@ -600,11 +648,11 @@
 		} else {
 			/* Illegal request, invalid field in cdb */
 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
-					INVALID_FIELD_IN_CDB, 0, 18);
+					INVALID_FIELD_IN_CDB, 0);
 			return check_condition_result;
 		}
-		memcpy(buff, arr, min_len);
-		return 0;
+		return fill_from_dev_buffer(scp, arr,
+			    min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ));
 	}
 	/* drops through here for a standard inquiry */
 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
@@ -612,20 +660,67 @@
 	arr[3] = 2;    /* response_data_format==2 */
 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
 	arr[6] = 0x1; /* claim: ADDR16 */
+	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
 	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
-	memcpy(&arr[8], vendor_id, 8);
-	memcpy(&arr[16], product_id, 16);
-	memcpy(&arr[32], product_rev, 4);
+	memcpy(&arr[8], inq_vendor_id, 8);
+	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] = 0x40; /* SAM-2 */
-	arr[60] = 0x2; arr[61] = 0x60; /* SPC-2 */
+	arr[60] = 0x3; arr[61] = 0x0;  /* SPC-3 */
 	if (scsi_debug_ptype == 0) {
-	    arr[62] = 0x1; arr[63] = 0x80; /* SBC */
+		arr[62] = 0x1; arr[63] = 0x80; /* SBC */
 	} else if (scsi_debug_ptype == 1) {
-	    arr[62] = 0x2; arr[63] = 0x00; /* SSC */
+		arr[62] = 0x2; arr[63] = 0x00; /* SSC */
 	}
-	memcpy(buff, arr, min_len);
-	return 0;
+	return fill_from_dev_buffer(scp, arr,
+			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
+}
+
+static int resp_requests(struct scsi_cmnd * scp,
+			 struct sdebug_dev_info * devip)
+{
+	unsigned char * sbuff;
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
+	unsigned char arr[SDEBUG_SENSE_LEN];
+	int len = 18;
+
+	memset(arr, 0, SDEBUG_SENSE_LEN);
+	if (devip->reset == 1)
+		mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+	sbuff = devip->sense_buff;
+	if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
+		/* DESC bit set and sense_buff in fixed format */
+		arr[0] = 0x72;
+		arr[1] = sbuff[2];     /* sense key */
+		arr[2] = sbuff[12];    /* asc */
+		arr[3] = sbuff[13];    /* ascq */
+		len = 8;
+	} else
+		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
+	mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+	return fill_from_dev_buffer(scp, arr, len);
+}
+
+#define SDEBUG_READCAP_ARR_SZ 8
+static int resp_readcap(struct scsi_cmnd * scp,
+			struct sdebug_dev_info * devip)
+{
+	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
+	unsigned long capac;
+	int errsts;
+
+	if ((errsts = check_reset(scp, devip)))
+		return errsts;
+	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
+	capac = (unsigned long)sdebug_capacity - 1;
+	arr[0] = (capac >> 24);
+	arr[1] = (capac >> 16) & 0xff;
+	arr[2] = (capac >> 8) & 0xff;
+	arr[3] = capac & 0xff;
+	arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+	arr[7] = SECT_SIZE_PER(target) & 0xff;
+	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
 }
 
 /* <<Following mode page info copied from ST318451LW>> */
@@ -706,34 +801,29 @@
 
 #define SDEBUG_MAX_MSENSE_SZ 256
 
-static int resp_mode_sense(unsigned char * cmd, int target,
-			   unsigned char * buff, int bufflen,
+static int resp_mode_sense(struct scsi_cmnd * scp, int target,
 			   struct sdebug_dev_info * devip)
 {
 	unsigned char dbd;
 	int pcontrol, pcode, subpcode;
 	unsigned char dev_spec;
-	int alloc_len, msense_6, offset, len;
+	int alloc_len, msense_6, offset, len, errsts;
 	unsigned char * ap;
 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
-	int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ?
-			SDEBUG_MAX_MSENSE_SZ : bufflen;
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
 
-	SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen));
+	if ((errsts = check_reset(scp, devip)))
+		return errsts;
 	dbd = cmd[1] & 0x8;
 	pcontrol = (cmd[2] & 0xc0) >> 6;
 	pcode = cmd[2] & 0x3f;
 	subpcode = cmd[3];
 	msense_6 = (MODE_SENSE == cmd[0]);
 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
-	if (bufflen < alloc_len)
-		printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d "
-		       "< alloc_length=%d\n", bufflen, alloc_len);
-	memset(buff, 0, bufflen);
 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
 	if (0x3 == pcontrol) {  /* Saving values not supported */
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
-			       	0, 18);
+			       	0);
 		return check_condition_result;
 	}
 	dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
@@ -748,7 +838,7 @@
 
 	if (0 != subpcode) { /* TODO: Control Extension page */
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
-			       	0, 18);
+			       	0);
 		return check_condition_result;
 	}
 	switch (pcode) {
@@ -787,146 +877,104 @@
 		break;
 	default:
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
-			       	0, 18);
+			       	0);
 		return check_condition_result;
 	}
 	if (msense_6)
 		arr[0] = offset - 1;
 	else {
-		offset -= 2;
-		arr[0] = (offset >> 8) & 0xff;
-		arr[1] = offset & 0xff;
+		arr[0] = ((offset - 2) >> 8) & 0xff;
+		arr[1] = (offset - 2) & 0xff;
 	}
-	memcpy(buff, arr, min_len);
-	return 0;
+	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
 }
 
 static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
 		     int num, struct sdebug_dev_info * devip)
 {
-        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
-        int nbytes, sgcount;
-        struct scatterlist *sgpnt = NULL;
-        int bufflen = SCpnt->request_bufflen;
 	unsigned long iflags;
+	int ret;
 
 	if (upper_blk || (block + num > sdebug_capacity)) {
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
-				0, 18);
+				0);
 		return check_condition_result;
 	}
 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
 	    (block <= OPT_MEDIUM_ERR_ADDR) &&
 	    ((block + num) > OPT_MEDIUM_ERR_ADDR)) {
 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
-				0, 18);
+				0);
 		/* claim unrecoverable read error */
 		return check_condition_result;
 	}
 	read_lock_irqsave(&atomic_rw, iflags);
-        sgcount = 0;
-	nbytes = bufflen;
-	/* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n",
-	       block, bufflen); */
-	if (SCpnt->use_sg) {
-		sgcount = 0;
-		sgpnt = (struct scatterlist *) buff;
-		buff = scatg2virt(&sgpnt[sgcount]);
-		bufflen = sgpnt[sgcount].length;
-	}
-	do {
-		memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen);
-		nbytes -= bufflen;
-		if (SCpnt->use_sg) {
-			block += bufflen >> POW2_SECT_SIZE;
-			sgcount++;
-			if (nbytes) {
-				buff = scatg2virt(&sgpnt[sgcount]);
-				bufflen = sgpnt[sgcount].length;
-			}
-		} else if (nbytes > 0)
-			printk(KERN_WARNING "scsi_debug:resp_read: unexpected "
-			       "nbytes=%d\n", nbytes);
-	} while (nbytes);
+	ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
+			   	   num * SECT_SIZE);
 	read_unlock_irqrestore(&atomic_rw, iflags);
-	return 0;
+	return ret;
 }
 
 static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
 		      int num, struct sdebug_dev_info * devip)
 {
-        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
-        int nbytes, sgcount;
-        struct scatterlist *sgpnt = NULL;
-        int bufflen = SCpnt->request_bufflen;
 	unsigned long iflags;
+	int res;
 
 	if (upper_blk || (block + num > sdebug_capacity)) {
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
-			       	0, 18);
+			       	0);
 		return check_condition_result;
 	}
 
 	write_lock_irqsave(&atomic_rw, iflags);
-        sgcount = 0;
-	nbytes = bufflen;
-	if (SCpnt->use_sg) {
-		sgcount = 0;
-		sgpnt = (struct scatterlist *) buff;
-		buff = scatg2virt(&sgpnt[sgcount]);
-		bufflen = sgpnt[sgcount].length;
-	}
-	do {
-		memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen);
-
-		nbytes -= bufflen;
-		if (SCpnt->use_sg) {
-			block += bufflen >> POW2_SECT_SIZE;
-			sgcount++;
-			if (nbytes) {
-				buff = scatg2virt(&sgpnt[sgcount]);
-				bufflen = sgpnt[sgcount].length;
-			}
-		} else if (nbytes > 0)
-			printk(KERN_WARNING "scsi_debug:resp_write: "
-			       "unexpected nbytes=%d\n", nbytes);
-	} while (nbytes);
+	res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
+			   	  num * SECT_SIZE);
 	write_unlock_irqrestore(&atomic_rw, iflags);
+	if (-1 == res)
+		return (DID_ERROR << 16);
+	else if ((res < (num * SECT_SIZE)) &&
+		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
+		printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, "
+		       " IO sent=%d bytes\n", num * SECT_SIZE, res);
 	return 0;
 }
 
-static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
-			    int bufflen, struct sdebug_dev_info * devip)
+#define SDEBUG_RLUN_ARR_SZ 128
+
+static int resp_report_luns(struct scsi_cmnd * scp,
+			    struct sdebug_dev_info * devip)
 {
 	unsigned int alloc_len;
 	int lun_cnt, i, upper;
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
 	int select_report = (int)cmd[2];
 	struct scsi_lun *one_lun;
+	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
 
 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
 	if ((alloc_len < 16) || (select_report > 2)) {
 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
-			       	0, 18);
+			       	0);
 		return check_condition_result;
 	}
-	if (bufflen > 8) { /* can produce response with up to 16k luns
-			      (lun 0 to lun 16383) */
-		memset(buff, 0, bufflen);
-		lun_cnt = scsi_debug_max_luns;
-		buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
-		buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
-		lun_cnt = min((int)((bufflen - 8) / sizeof(struct scsi_lun)),
-			      lun_cnt);
-		one_lun = (struct scsi_lun *) &buff[8];
-		for (i = 0; i < lun_cnt; i++) {
-			upper = (i >> 8) & 0x3f;
-			if (upper)
-				one_lun[i].scsi_lun[0] =
-				    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
-			one_lun[i].scsi_lun[1] = i & 0xff;
-		}
+	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
+	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
+	lun_cnt = scsi_debug_max_luns;
+	arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
+	arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
+	lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
+			    sizeof(struct scsi_lun)), lun_cnt);
+	one_lun = (struct scsi_lun *) &arr[8];
+	for (i = 0; i < lun_cnt; i++) {
+		upper = (i >> 8) & 0x3f;
+		if (upper)
+			one_lun[i].scsi_lun[0] =
+			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
+		one_lun[i].scsi_lun[1] = i & 0xff;
 	}
-	return 0;
+	return fill_from_dev_buffer(scp, arr,
+				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
 }
 
 /* When timer goes off this function is called. */
@@ -1041,14 +1089,19 @@
 		open_devip->reset = 1;
 		open_devip->used = 1;
 		memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
-		open_devip->sense_buff[0] = 0x70;
+		if (scsi_debug_dsense)
+			open_devip->sense_buff[0] = 0x72;
+		else {
+			open_devip->sense_buff[0] = 0x70;
+			open_devip->sense_buff[7] = 0xa;
+		}
 		return open_devip;
         }
         return NULL;
 }
 
 static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
-			    int asc, int asq, int inbandLen)
+			    int asc, int asq)
 {
 	unsigned char * sbuff;
 
@@ -1060,11 +1113,9 @@
 		sbuff[2] = asc;
 		sbuff[3] = asq;
 	} else {
-		if (inbandLen > SDEBUG_SENSE_LEN)
-			inbandLen = SDEBUG_SENSE_LEN;
 		sbuff[0] = 0x70;  /* fixed, current */
 		sbuff[2] = key;
-		sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+		sbuff[7] = 0xa;	  /* implies 18 byte sense buffer */
 		sbuff[12] = asc;
 		sbuff[13] = asq;
 	}
@@ -1355,7 +1406,7 @@
 MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");
 MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->...");
 MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
-MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=4[SPC-2])");
+MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
 
 
 static char sdebug_info[256];
@@ -1391,7 +1442,7 @@
 		if (1 != sscanf(arr, "%d", &pos))
 			return -EINVAL;
 		scsi_debug_opts = pos;
-		if (scsi_debug_every_nth > 0)
+		if (scsi_debug_every_nth != 0)
                         scsi_debug_cmnd_count = 0;
 		return length;
 	}
@@ -1547,7 +1598,7 @@
 {
         int nth;
 
-	if ((count > 0) && (1 == sscanf(buf, "%d", &nth)) && (nth >= 0)) {
+	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
 		scsi_debug_every_nth = nth;
 		scsi_debug_cmnd_count = 0;
 		return count;
