[PATCH RFC] Target/loopback: Conform to protection operation in scsi command

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

 



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




[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux