In case protection information exists over the wire
iscsi header data_length field is required to include it.

Also remove iser transfer length checks for each task as
they are not always true and somewhat redundant anyway.

Signed-off-by: Sagi Grimberg <[email protected]>
---
 drivers/infiniband/ulp/iser/iser_initiator.c |   34 +++++++-----------------
 drivers/scsi/libiscsi.c                      |   35 +++++++++++++++++++++++++-
 include/scsi/libiscsi.h                      |   19 ++++++++++++++
 3 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c 
b/drivers/infiniband/ulp/iser/iser_initiator.c
index 2e2d903..1600e35 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -41,11 +41,11 @@
 #include "iscsi_iser.h"
 
 /* Register user buffer memory and initialize passive rdma
- *  dto descriptor. Total data size is stored in
- *  iser_task->data[ISER_DIR_IN].data_len
+ *  dto descriptor. Data size is stored in
+ *  task->data[ISER_DIR_IN].data_len, Protection size
+ *  os stored in task->prot[ISER_DIR_IN].data_len
  */
-static int iser_prepare_read_cmd(struct iscsi_task *task,
-                                unsigned int edtl)
+static int iser_prepare_read_cmd(struct iscsi_task *task)
 
 {
        struct iscsi_iser_task *iser_task = task->dd_data;
@@ -73,14 +73,6 @@ static int iser_prepare_read_cmd(struct iscsi_task *task,
                        return err;
        }
 
-       if (edtl > iser_task->data[ISER_DIR_IN].data_len) {
-               iser_err("Total data length: %ld, less than EDTL: "
-                        "%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
-                        iser_task->data[ISER_DIR_IN].data_len, edtl,
-                        task->itt, iser_task->ib_conn);
-               return -EINVAL;
-       }
-
        err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_IN);
        if (err) {
                iser_err("Failed to set up Data-IN RDMA\n");
@@ -100,8 +92,9 @@ static int iser_prepare_read_cmd(struct iscsi_task *task,
 }
 
 /* Register user buffer memory and initialize passive rdma
- *  dto descriptor. Total data size is stored in
- *  task->data[ISER_DIR_OUT].data_len
+ *  dto descriptor. Data size is stored in
+ *  task->data[ISER_DIR_OUT].data_len, Protection size
+ *  is stored at task->prot[ISER_DIR_OUT].data_len
  */
 static int
 iser_prepare_write_cmd(struct iscsi_task *task,
@@ -135,14 +128,6 @@ iser_prepare_write_cmd(struct iscsi_task *task,
                        return err;
        }
 
-       if (edtl > iser_task->data[ISER_DIR_OUT].data_len) {
-               iser_err("Total data length: %ld, less than EDTL: %d, "
-                        "in WRITE cmd BHS itt: %d, conn: 0x%p\n",
-                        iser_task->data[ISER_DIR_OUT].data_len,
-                        edtl, task->itt, task->conn);
-               return -EINVAL;
-       }
-
        err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_OUT);
        if (err != 0) {
                iser_err("Failed to register write cmd RDMA mem\n");
@@ -417,11 +402,12 @@ int iser_send_command(struct iscsi_conn *conn,
        if (scsi_prot_sg_count(sc)) {
                prot_buf->buf  = scsi_prot_sglist(sc);
                prot_buf->size = scsi_prot_sg_count(sc);
-               prot_buf->data_len = sc->prot_sdb->length;
+               prot_buf->data_len = iscsi_prot_len(data_buf->data_len,
+                                                   sc->device->sector_size);
        }
 
        if (hdr->flags & ISCSI_FLAG_CMD_READ) {
-               err = iser_prepare_read_cmd(task, edtl);
+               err = iser_prepare_read_cmd(task);
                if (err)
                        goto send_command_error;
        }
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 26dc005..b54d1cc 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -326,6 +326,31 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task 
*task, int opcode)
 }
 
 /**
+ * iscsi_adjust_dl - Adjust SCSI data length to include PI
+ * @sc: scsi command.
+ * @data_length: command data length.
+ *
+ * Adjust the data length to account for how much data
+ * is actually on the wire.
+ *
+ * returns the adjusted data length
+ **/
+static unsigned
+iscsi_adjust_dl(struct scsi_cmnd *sc, unsigned data_len)
+{
+       if (sc->sc_data_direction == DMA_FROM_DEVICE) {
+               if (scsi_get_prot_op(sc) ==  SCSI_PROT_READ_INSERT)
+                       return data_len;
+       } else {
+               if (scsi_get_prot_op(sc) ==  SCSI_PROT_WRITE_STRIP)
+                       return data_len;
+       }
+
+       /* Protection information exists on the wire */
+       return data_len + iscsi_prot_len(data_len, sc->device->sector_size);
+}
+
+/**
  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
  * @task: iscsi task
  *
@@ -395,6 +420,9 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
                unsigned out_len = scsi_out(sc)->length;
                struct iscsi_r2t_info *r2t = &task->unsol_r2t;
 
+               if (task->protected)
+                       out_len = iscsi_adjust_dl(sc, out_len);
+
                hdr->data_length = cpu_to_be32(out_len);
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
                /*
@@ -436,9 +464,14 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
                        /* No unsolicit Data-Out's */
                        hdr->flags |= ISCSI_FLAG_CMD_FINAL;
        } else {
+               unsigned in_len = scsi_in(sc)->length;
+
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
                zero_data(hdr->dlength);
-               hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
+               if (task->protected)
+                       in_len = iscsi_adjust_dl(sc, in_len);
+
+               hdr->data_length = cpu_to_be32(in_len);
 
                if (sc->sc_data_direction == DMA_FROM_DEVICE)
                        hdr->flags |= ISCSI_FLAG_CMD_READ;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 728c9ad..534a1dc 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -494,4 +494,23 @@ iscsi_padding(unsigned int len)
        return len;
 }
 
+/*
+ * data integrity helpers
+ */
+static inline unsigned
+iscsi_prot_len(unsigned data_len, unsigned sector_size)
+{
+       switch (sector_size) {
+       case 512:
+               return (data_len >> 9) * 8;
+       case 1024:
+               return (data_len >> 10) * 8;
+       case 2048:
+               return (data_len >> 11) * 8;
+       case 4096:
+               return (data_len >> 12) * 8;
+       default:
+               return (data_len >> ilog2(sector_size)) * 8;
+       }
+}
 #endif
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to