[PATCH 5/5] lio iblock: add support for REQ_CMP_AND_WRITE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mike Christie <michaelc@xxxxxxxxxxx>

This patch has the iblock backing store use blkdev_issue_cmp_and_write
if the backing store device/queue supports it.

Signed-off-by: Mike Christie <michaelc@xxxxxxxxxxx>
---
 drivers/target/target_core_iblock.c |   85 ++++++++++++++++++++++++++++-------
 1 files changed, 68 insertions(+), 17 deletions(-)

diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 7e6b857..cac928a 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -153,6 +153,11 @@ static int iblock_configure_device(struct se_device *dev)
 	 */
 	dev->dev_attrib.max_write_same_len = 0xFFFF;
 
+	/* convert from linux block layer 512 byte sector to our block size */
+	dev->dev_attrib.max_compare_and_write_len =
+		(q->limits.max_cmp_and_write_sectors << IBLOCK_LBA_SHIFT) /
+						dev->dev_attrib.hw_block_size;
+
 	if (blk_queue_nonrot(q))
 		dev->dev_attrib.is_nonrot = 1;
 
@@ -413,6 +418,67 @@ iblock_execute_sync_cache(struct se_cmd *cmd)
 	return 0;
 }
 
+/*
+ * Convert the blocksize advertised to the initiator to the 512 byte
+ * units unconditionally used by the Linux block layer.
+ */
+static int iblock_get_lba_shift(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+
+	if (dev->dev_attrib.block_size == 4096)
+		return 3;
+	else if (dev->dev_attrib.block_size == 2048)
+		return 2;
+	else if (dev->dev_attrib.block_size == 1024)
+		return 1;
+	else
+		return 0;
+}
+
+static sense_reason_t
+iblock_execute_compare_and_write(struct se_cmd *cmd)
+{
+	struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
+	int ret, i = 0;
+	sector_t block_lba;
+	struct scatterlist *sg;
+	struct bio *bio;
+
+	block_lba = cmd->t_task_lba << iblock_get_lba_shift(cmd);
+
+	/* assumes SGLs are PAGE_SIZE */
+	bio = blkdev_setup_cmp_and_write(bdev, block_lba, GFP_KERNEL,
+					 cmd->t_data_nents);
+	if (!bio) {
+		pr_err("blkdev_setup_cmp_and_write() failed\n");
+		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+	}
+
+	for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) {
+		ret = bio_add_pc_page(bdev_get_queue(bdev), bio, sg_page(sg),
+				      sg->length, sg->offset);
+		if (ret != sg->length) {
+			bio_put(bio);
+			pr_err("bio_add_pc_page() failed\n");
+			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		}
+	}
+
+	ret = blkdev_issue_cmp_and_write(bio);
+	if (ret == -ECANCELED) {
+	        pr_warn("Target/%s: Send MISCOMPARE check condition and sense\n",
+        	        cmd->se_dev->transport->name);
+		return TCM_MISCOMPARE_VERIFY;
+	} else if (ret < 0) {
+		pr_err("blkdev_issue_cmp_and_write() failed: %d\n", ret);
+		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+	}
+
+	target_complete_cmd(cmd, GOOD);
+	return 0;
+}
+
 static sense_reason_t
 iblock_do_unmap(struct se_cmd *cmd, void *priv,
 		sector_t lba, sector_t nolb)
@@ -701,23 +767,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
 		rw = READ;
 	}
 
-	/*
-	 * Convert the blocksize advertised to the initiator to the 512 byte
-	 * units unconditionally used by the Linux block layer.
-	 */
-	if (dev->dev_attrib.block_size == 4096)
-		block_lba = (cmd->t_task_lba << 3);
-	else if (dev->dev_attrib.block_size == 2048)
-		block_lba = (cmd->t_task_lba << 2);
-	else if (dev->dev_attrib.block_size == 1024)
-		block_lba = (cmd->t_task_lba << 1);
-	else if (dev->dev_attrib.block_size == 512)
-		block_lba = cmd->t_task_lba;
-	else {
-		pr_err("Unsupported SCSI -> BLOCK LBA conversion:"
-				" %u\n", dev->dev_attrib.block_size);
-		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-	}
+	block_lba = cmd->t_task_lba << iblock_get_lba_shift(cmd);
 
 	ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
 	if (!ibr)
@@ -841,6 +891,7 @@ static struct sbc_ops iblock_sbc_ops = {
 	.execute_write_same	= iblock_execute_write_same,
 	.execute_write_same_unmap = iblock_execute_write_same_unmap,
 	.execute_unmap		= iblock_execute_unmap,
+	.execute_compare_and_write = iblock_execute_compare_and_write,
 };
 
 static sense_reason_t
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux