target/rd: Add ramdisk bit for NULLIO operation

This patch adds a rd_nullio parameter that allows RAMDISK_MCP backends
to function in NULLIO mode, where all se_cmd I/O is immediately completed
in rd_execute_rw() without actually performing the SGL memory copy.

This is useful for performance testing when the ramdisk SGL memory copy
begins to eat lots of cycles during heavy small block workloads, so allow
this bit to be enabled when necessary on a per rd_dev basis.

Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index e0b3c37..0921a64 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -291,6 +291,11 @@
 	u32 src_len;
 	u64 tmp;
 
+	if (dev->rd_flags & RDF_NULLIO) {
+		target_complete_cmd(cmd, SAM_STAT_GOOD);
+		return 0;
+	}
+
 	tmp = cmd->t_task_lba * se_dev->dev_attrib.block_size;
 	rd_offset = do_div(tmp, PAGE_SIZE);
 	rd_page = tmp;
@@ -373,11 +378,12 @@
 }
 
 enum {
-	Opt_rd_pages, Opt_err
+	Opt_rd_pages, Opt_rd_nullio, Opt_err
 };
 
 static match_table_t tokens = {
 	{Opt_rd_pages, "rd_pages=%d"},
+	{Opt_rd_nullio, "rd_nullio=%d"},
 	{Opt_err, NULL}
 };
 
@@ -408,6 +414,14 @@
 				" Count: %u\n", rd_dev->rd_page_count);
 			rd_dev->rd_flags |= RDF_HAS_PAGE_COUNT;
 			break;
+		case Opt_rd_nullio:
+			match_int(args, &arg);
+			if (arg != 1)
+				break;
+
+			pr_debug("RAMDISK: Setting NULLIO flag: %d\n", arg);
+			rd_dev->rd_flags |= RDF_NULLIO;
+			break;
 		default:
 			break;
 		}
@@ -424,8 +438,9 @@
 	ssize_t bl = sprintf(b, "TCM RamDisk ID: %u  RamDisk Makeup: rd_mcp\n",
 			rd_dev->rd_dev_id);
 	bl += sprintf(b + bl, "        PAGES/PAGE_SIZE: %u*%lu"
-			"  SG_table_count: %u\n", rd_dev->rd_page_count,
-			PAGE_SIZE, rd_dev->sg_table_count);
+			"  SG_table_count: %u  nullio: %d\n", rd_dev->rd_page_count,
+			PAGE_SIZE, rd_dev->sg_table_count,
+			!!(rd_dev->rd_flags & RDF_NULLIO));
 	return bl;
 }