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