Commit ab628b9f authored by David Disseldorp's avatar David Disseldorp Committed by Martin K. Petersen

scsi: target: Split out COMPARE AND WRITE memcmp into helper

In preparation for finding and returning the miscompare offset.

Link: https://lore.kernel.org/r/20201031233211.5207-4-ddiss@suse.deReviewed-by: default avatarMike Christie <michael.christie@oracle.com>
Signed-off-by: default avatarDavid Disseldorp <ddiss@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 8dd992fb
...@@ -434,20 +434,75 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, ...@@ -434,20 +434,75 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success,
return ret; return ret;
} }
/*
* compare @cmp_len bytes of @read_sgl with @cmp_sgl. On miscompare return
* TCM_MISCOMPARE_VERIFY.
*/
static sense_reason_t
compare_and_write_do_cmp(struct scatterlist *read_sgl, unsigned int read_nents,
struct scatterlist *cmp_sgl, unsigned int cmp_nents,
unsigned int cmp_len)
{
unsigned char *buf = NULL;
struct scatterlist *sg;
sense_reason_t ret;
unsigned int offset;
size_t rc;
int i;
buf = kzalloc(cmp_len, GFP_KERNEL);
if (!buf) {
ret = TCM_OUT_OF_RESOURCES;
goto out;
}
rc = sg_copy_to_buffer(cmp_sgl, cmp_nents, buf, cmp_len);
if (!rc) {
pr_err("sg_copy_to_buffer() failed for compare_and_write\n");
ret = TCM_OUT_OF_RESOURCES;
goto out;
}
/*
* Compare SCSI READ payload against verify payload
*/
offset = 0;
for_each_sg(read_sgl, sg, read_nents, i) {
unsigned int len = min(sg->length, cmp_len);
unsigned char *addr = kmap_atomic(sg_page(sg));
if (memcmp(addr, buf + offset, len)) {
pr_warn("Detected MISCOMPARE for addr: %p buf: %p\n",
addr, buf + offset);
kunmap_atomic(addr);
ret = TCM_MISCOMPARE_VERIFY;
goto out;
}
kunmap_atomic(addr);
offset += len;
cmp_len -= len;
if (!cmp_len)
break;
}
pr_debug("COMPARE AND WRITE read data matches compare data\n");
ret = TCM_NO_SENSE;
out:
kfree(buf);
return ret;
}
static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success, static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
int *post_ret) int *post_ret)
{ {
struct se_device *dev = cmd->se_dev; struct se_device *dev = cmd->se_dev;
struct sg_table write_tbl = { }; struct sg_table write_tbl = { };
struct scatterlist *write_sg, *sg; struct scatterlist *write_sg;
unsigned char *buf = NULL, *addr;
struct sg_mapping_iter m; struct sg_mapping_iter m;
unsigned int offset = 0, len; unsigned int len;
unsigned int nlbas = cmd->t_task_nolb;
unsigned int block_size = dev->dev_attrib.block_size; unsigned int block_size = dev->dev_attrib.block_size;
unsigned int compare_len = (nlbas * block_size); unsigned int compare_len = (cmd->t_task_nolb * block_size);
sense_reason_t ret = TCM_NO_SENSE; sense_reason_t ret = TCM_NO_SENSE;
int rc, i; int i;
/* /*
* Handle early failure in transport_generic_request_failure(), * Handle early failure in transport_generic_request_failure(),
...@@ -473,12 +528,13 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes ...@@ -473,12 +528,13 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
goto out; goto out;
} }
buf = kzalloc(cmd->data_length, GFP_KERNEL); ret = compare_and_write_do_cmp(cmd->t_bidi_data_sg,
if (!buf) { cmd->t_bidi_data_nents,
pr_err("Unable to allocate compare_and_write buf\n"); cmd->t_data_sg,
ret = TCM_OUT_OF_RESOURCES; cmd->t_data_nents,
compare_len);
if (ret)
goto out; goto out;
}
if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) { if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) {
pr_err("Unable to allocate compare_and_write sg\n"); pr_err("Unable to allocate compare_and_write sg\n");
...@@ -486,44 +542,9 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes ...@@ -486,44 +542,9 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
goto out; goto out;
} }
write_sg = write_tbl.sgl; write_sg = write_tbl.sgl;
/*
* Setup verify and write data payloads from total NumberLBAs.
*/
rc = sg_copy_to_buffer(cmd->t_data_sg, cmd->t_data_nents, buf,
cmd->data_length);
if (!rc) {
pr_err("sg_copy_to_buffer() failed for compare_and_write\n");
ret = TCM_OUT_OF_RESOURCES;
goto out;
}
/*
* Compare against SCSI READ payload against verify payload
*/
for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, i) {
addr = (unsigned char *)kmap_atomic(sg_page(sg));
if (!addr) {
ret = TCM_OUT_OF_RESOURCES;
goto out;
}
len = min(sg->length, compare_len);
if (memcmp(addr, buf + offset, len)) {
pr_warn("Detected MISCOMPARE for addr: %p buf: %p\n",
addr, buf + offset);
kunmap_atomic(addr);
goto miscompare;
}
kunmap_atomic(addr);
offset += len;
compare_len -= len;
if (!compare_len)
break;
}
i = 0; i = 0;
len = cmd->t_task_nolb * block_size; len = compare_len;
sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG); sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG);
/* /*
* Currently assumes NoLB=1 and SGLs are PAGE_SIZE.. * Currently assumes NoLB=1 and SGLs are PAGE_SIZE..
...@@ -568,13 +589,8 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes ...@@ -568,13 +589,8 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
__target_execute_cmd(cmd, false); __target_execute_cmd(cmd, false);
kfree(buf);
return ret; return ret;
miscompare:
pr_warn("Target/%s: Send MISCOMPARE check condition and sense\n",
dev->transport->name);
ret = TCM_MISCOMPARE_VERIFY;
out: out:
/* /*
* In the MISCOMPARE or failure case, unlock ->caw_sem obtained in * In the MISCOMPARE or failure case, unlock ->caw_sem obtained in
...@@ -582,7 +598,6 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes ...@@ -582,7 +598,6 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
*/ */
up(&dev->caw_sem); up(&dev->caw_sem);
sg_free_table(&write_tbl); sg_free_table(&write_tbl);
kfree(buf);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment