In case SCSI command states SCSI_PROT_READ_STRIP or SCSI_PROT_WRITE_GENERATE loopback should follow it by allocating protection scatterlist and generate protection information if needed. Signed-off-by: Sagi Grimberg <sagig@xxxxxxxxxxxx> --- drivers/target/loopback/tcm_loop.c | 81 ++++++++++++++++++++++++++++++++ drivers/target/target_core_transport.c | 1 + include/target/target_core_backend.h | 1 - include/target/target_core_base.h | 2 + 4 files changed, 84 insertions(+), 1 deletions(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index fadad7c..a581ff3 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -31,6 +31,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> #include <scsi/scsi_cmnd.h> +#include <linux/crc-t10dif.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> @@ -169,6 +170,51 @@ static int tcm_loop_sam_attr(struct scsi_cmnd *sc) return MSG_SIMPLE_TAG; } +static void tcm_loop_calc_dif(void *data, sector_t sector, u32 sector_size, + struct se_dif_v1_tuple *sdt) +{ + sdt->guard_tag = cpu_to_be16(crc_t10dif(data, sector_size)); + sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); + sdt->app_tag = 0; +} + +static void tcm_loop_generate_dif(struct se_cmd *cmd, sector_t sector, + u32 sector_size) +{ + struct se_dif_v1_tuple *sdt; + struct scatterlist *dsg, *psg = cmd->t_prot_sg; + void *daddr, *paddr; + int i, j, offset = 0; + + for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { + + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + paddr = kmap_atomic(sg_page(psg)) + psg->offset; + for (j = 0; j < dsg->length; j += sector_size) { + + if (offset >= psg->length) { + kunmap_atomic(paddr); + psg = sg_next(psg); + paddr = kmap_atomic(sg_page(psg)) + psg->offset; + offset = 0; + } + + sdt = paddr + offset; + tcm_loop_calc_dif(daddr + j, sector, sector_size, sdt); + + pr_debug("DIF sector: %llu guard_tag: 0x%04x" + " app_tag: 0x%04x ref_tag: %u\n", + (unsigned long long)sector, sdt->guard_tag, + sdt->app_tag, be32_to_cpu(sdt->ref_tag)); + + sector++; + offset += sizeof(struct se_dif_v1_tuple); + } + kunmap_atomic(paddr); + kunmap_atomic(daddr); + } +} + static void tcm_loop_submission_work(struct work_struct *work) { struct tcm_loop_cmd *tl_cmd = @@ -181,6 +227,7 @@ static void tcm_loop_submission_work(struct work_struct *work) struct scatterlist *sgl_bidi = NULL; u32 sgl_bidi_count = 0; int rc; + u32 prot_len; tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; @@ -212,6 +259,40 @@ static void tcm_loop_submission_work(struct work_struct *work) se_cmd->se_cmd_flags |= SCF_BIDI; } + + if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) { + prot_len = scsi_bufflen(sc) * sizeof(struct se_dif_v1_tuple); + do_div(prot_len, sc->device->sector_size); + } + + switch (scsi_get_prot_op(sc)) { + case SCSI_PROT_READ_STRIP: + rc = target_alloc_sgl(&se_cmd->t_prot_sg, + &se_cmd->t_prot_nents, + prot_len, true); + if (rc < 0) { + pr_err("Failed to allocate protection, returning...\n"); + return; + } + break; + case SCSI_PROT_WRITE_INSERT: + rc = target_alloc_sgl(&se_cmd->t_prot_sg, + &se_cmd->t_prot_nents, + prot_len, true); + if (rc < 0) { + pr_err("Failed to allocate protection, returning...\n"); + return; + } + tcm_loop_generate_dif(se_cmd, scsi_get_lba(sc) & 0xffffffff, + sc->device->sector_size); + break; + case SCSI_PROT_READ_PASS: + case SCSI_PROT_WRITE_PASS: + case SCSI_PROT_NORMAL: + default: + break; + } + rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, scsi_bufflen(sc), tcm_loop_sam_attr(sc), diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index fb7fac5..ed84783 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2184,6 +2184,7 @@ out: kfree(sg); return -ENOMEM; } +EXPORT_SYMBOL(target_alloc_sgl); /* * Allocate any required resources to execute the command. For writes we diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 7020e33..0eabeab 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -87,7 +87,6 @@ int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); void *transport_kmap_data_sg(struct se_cmd *); void transport_kunmap_data_sg(struct se_cmd *); /* core helpers also used by xcopy during internal command setup */ -int target_alloc_sgl(struct scatterlist **, unsigned int *, u32, bool); sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, struct scatterlist *, u32, struct scatterlist *, u32); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 344fd05..6aa3a17 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -897,4 +897,6 @@ struct se_wwn { struct config_group fabric_stat_group; }; +int target_alloc_sgl(struct scatterlist **, unsigned int *, u32, bool); + #endif /* TARGET_CORE_BASE_H */ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html