All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH scsi 0/1] libiscsi : T10 DIF support
@ 2014-08-06 22:37 Anish Bhatt
  2014-08-06 22:37 ` [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support Anish Bhatt
  0 siblings, 1 reply; 9+ messages in thread
From: Anish Bhatt @ 2014-08-06 22:37 UTC (permalink / raw)
  To: linux-scsi; +Cc: hch, jbottomley, michaelc, kxie, manojmalviya, Anish Bhatt

The following patch adds T10 DIF support to libiscsi. I didn't see any merge
window messages on linux-scsi, I hope I'm not sending this out of sync.
-Anish

Anish Bhatt (1):
  libiscsi : Add T10 Data Integrity Feature support

 drivers/scsi/libiscsi.c     |  61 +++++++--
 drivers/scsi/libiscsi_tcp.c | 296 ++++++++++++++++++++++++++++++++++++++++----
 include/scsi/libiscsi.h     |   6 +
 include/scsi/libiscsi_tcp.h |  22 ++++
 4 files changed, 349 insertions(+), 36 deletions(-)

-- 
2.0.3


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-06 22:37 [PATCH scsi 0/1] libiscsi : T10 DIF support Anish Bhatt
@ 2014-08-06 22:37 ` Anish Bhatt
  2014-08-07  2:25   ` Mike Christie
                     ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Anish Bhatt @ 2014-08-06 22:37 UTC (permalink / raw)
  To: linux-scsi; +Cc: hch, jbottomley, michaelc, kxie, manojmalviya, Anish Bhatt

Signed-off-by: Anish Bhatt <anish@chelsio.com>
Signed-off by: Manoj Malvia <manojmalviya@chelsio.com>
Signed-off by: Karen Xie <kxie@chelsio.com>
---
 drivers/scsi/libiscsi.c     |  61 +++++++--
 drivers/scsi/libiscsi_tcp.c | 296 ++++++++++++++++++++++++++++++++++++++++----
 include/scsi/libiscsi.h     |   6 +
 include/scsi/libiscsi_tcp.h |  22 ++++
 4 files changed, 349 insertions(+), 36 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 26dc005b..8cfecec 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -233,7 +233,7 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
 						  sizeof(rlen_ahdr->reserved));
 	rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
 	rlen_ahdr->reserved = 0;
-	rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length);
+	rlen_ahdr->read_length = cpu_to_be32(iscsi_scsi_in_total_length(sc));
 
 	ISCSI_DBG_SESSION(task->conn->session,
 			  "bidi-in rlen_ahdr->read_length(%d) "
@@ -325,6 +325,32 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
 	return 0;
 }
 
+inline int iscsi_scsi_out_total_length(struct scsi_cmnd *sc)
+{
+	int sector_size = sc->device->sector_size;
+	int len = scsi_out(sc)->length;
+
+	if ((scsi_get_prot_op(sc) == SCSI_PROT_WRITE_INSERT) ||
+	    (scsi_get_prot_op(sc) == SCSI_PROT_WRITE_PASS))
+		len += (len / sector_size) << ISCSI_PI_LEN_PER_SECTOR_SHIFT;
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_scsi_out_total_length);
+
+inline int iscsi_scsi_in_total_length(struct scsi_cmnd *sc)
+{
+	int sector_size = sc->device->sector_size;
+	int len = scsi_in(sc)->length;
+
+	if ((scsi_get_prot_op(sc) == SCSI_PROT_READ_STRIP) ||
+	    (scsi_get_prot_op(sc) == SCSI_PROT_READ_PASS))
+		len += (len / sector_size) << ISCSI_PI_LEN_PER_SECTOR_SHIFT;
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_scsi_in_total_length);
+
 /**
  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
  * @task: iscsi task
@@ -392,8 +418,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 		task->protected = true;
 
 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
-		unsigned out_len = scsi_out(sc)->length;
+		unsigned out_len = iscsi_scsi_out_total_length(sc);
 		struct iscsi_r2t_info *r2t = &task->unsol_r2t;
+		unsigned int pi_sector_size = sc->device->sector_size +
+			((scsi_get_prot_op(sc) == SCSI_PROT_WRITE_STRIP) ?
+			0 : ISCSI_PI_LEN_PER_SECTOR);
 
 		hdr->data_length = cpu_to_be32(out_len);
 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
@@ -420,6 +449,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 			else
 				task->imm_count = min(out_len,
 							conn->max_xmit_dlength);
+			if (scsi_get_prot_op(sc))
+				task->imm_count =
+					(task->imm_count/pi_sector_size) *
+					pi_sector_size;
 			hton24(hdr->dlength, task->imm_count);
 		} else
 			zero_data(hdr->dlength);
@@ -428,6 +461,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 			r2t->data_length = min(session->first_burst, out_len) -
 					       task->imm_count;
 			r2t->data_offset = task->imm_count;
+			if (scsi_get_prot_op(sc))
+				r2t->data_length =
+					(r2t->data_length/pi_sector_size) *
+					pi_sector_size;
 			r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
 			r2t->exp_statsn = cpu_to_be32(conn->exp_statsn);
 		}
@@ -436,12 +473,12 @@ 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 = iscsi_scsi_in_total_length(sc);
 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
 		zero_data(hdr->dlength);
-		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
-
 		if (sc->sc_data_direction == DMA_FROM_DEVICE)
 			hdr->flags |= ISCSI_FLAG_CMD_READ;
+		hdr->data_length = cpu_to_be32(in_len);
 	}
 
 	/* calculate size of additional header segments (AHSs) */
@@ -467,8 +504,8 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 			  sc->sc_data_direction == DMA_TO_DEVICE ?
 			  "write" : "read", conn->id, sc, sc->cmnd[0],
 			  task->itt, scsi_bufflen(sc),
-			  scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
-			  session->cmdsn,
+			  scsi_bidi_cmnd(sc) ? iscsi_scsi_in_total_length(sc)
+			  : 0, session->cmdsn,
 			  session->max_cmdsn - session->exp_cmdsn + 1);
 	return 0;
 }
@@ -635,8 +672,8 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
 	if (!scsi_bidi_cmnd(sc))
 		scsi_set_resid(sc, scsi_bufflen(sc));
 	else {
-		scsi_out(sc)->resid = scsi_out(sc)->length;
-		scsi_in(sc)->resid = scsi_in(sc)->length;
+		scsi_out(sc)->resid = iscsi_scsi_out_total_length(sc);
+		scsi_in(sc)->resid = iscsi_scsi_in_total_length(sc);
 	}
 
 	/* regular RX path uses back_lock */
@@ -887,7 +924,7 @@ invalid_datalen:
 
 		if (scsi_bidi_cmnd(sc) && res_count > 0 &&
 				(rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW ||
-				 res_count <= scsi_in(sc)->length))
+				 res_count <= iscsi_scsi_in_total_length(sc)))
 			scsi_in(sc)->resid = res_count;
 		else
 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
@@ -937,7 +974,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
 		if (res_count > 0 &&
 		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
-		     res_count <= scsi_in(sc)->length))
+		     res_count <= iscsi_scsi_in_total_length(sc)))
 			scsi_in(sc)->resid = res_count;
 		else
 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
@@ -1753,8 +1790,8 @@ fault:
 	if (!scsi_bidi_cmnd(sc))
 		scsi_set_resid(sc, scsi_bufflen(sc));
 	else {
-		scsi_out(sc)->resid = scsi_out(sc)->length;
-		scsi_in(sc)->resid = scsi_in(sc)->length;
+		scsi_out(sc)->resid = iscsi_scsi_out_total_length(sc);
+		scsi_in(sc)->resid = iscsi_scsi_in_total_length(sc);
 	}
 	sc->scsi_done(sc);
 	return 0;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 60cb6dc..aba3319 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -24,6 +24,7 @@
  *	FUJITA Tomonori
  *	Arne Redlich
  *	Zhenyu Wang
+ *	Manoj Malviya
  */
 
 #include <linux/types.h>
@@ -259,7 +260,7 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
 	 * Set us up for transferring the data digest. hdr digest
 	 * is completely handled in hdr done function.
 	 */
-	if (segment->hash) {
+	if (segment->hash && !tcp_conn->in.pi_ctx.pi_pending) {
 		crypto_hash_final(segment->hash, segment->digest);
 		iscsi_tcp_segment_splice_digest(segment,
 				 recv ? segment->recv_digest : segment->digest);
@@ -270,6 +271,73 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_segment_done);
 
+static int
+iscsi_tcp_segment_interleve_data_pi_recv(struct iscsi_tcp_conn *tcp_conn,
+					 struct iscsi_segment *data_segment,
+					 const void *ptr, unsigned int len)
+{
+	struct iscsi_segment *pi_segment = &tcp_conn->in.pi_ctx.pi_segment;
+	struct iscsi_segment *segment;
+	unsigned int copy = 0, copied = 0;
+	unsigned int copy_state = tcp_conn->in.pi_ctx.copy_state;
+
+restart:
+	copy = 0;
+	if (copy_state == COPY_DATA)
+		segment = data_segment;
+	else /* if (copy_state == COPY_PI) */
+		segment = pi_segment;
+
+	if (copy_state == COPY_PI &&
+	    tcp_conn->in.pi_ctx.prot_op == SCSI_PROT_READ_STRIP) {
+		/* We need to drop pi */
+		copy = min(len - copied, segment->remaining_bytes_in_block);
+		segment->remaining_bytes_in_block -= copy;
+		copied += copy;
+		goto next_state;
+	}
+
+	while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) {
+		if (!segment->remaining_bytes_in_block) {
+			/* change the state */
+			copy_state = ~copy_state;
+			/* reset remianing block size */
+			segment->remaining_bytes_in_block =
+					((segment == data_segment) ?
+					 data_segment->segment_size :
+					 ISCSI_PI_LEN_PER_SECTOR);
+			break;
+		}
+		if (copied == len) {
+			ISCSI_DBG_TCP(tcp_conn->iscsi_conn,
+				      "copied %d bytes\n", len);
+			break;
+		}
+
+		copy = min(len - copied, segment->size - segment->copied);
+		copy = min(copy, segment->remaining_bytes_in_block);
+		segment->remaining_bytes_in_block -= copy;
+		memcpy(segment->data + segment->copied, ptr + copied, copy);
+		copied += copy;
+	}
+
+next_state:
+	if (!segment->remaining_bytes_in_block) {
+		/* change the state */
+		copy_state = ~copy_state;
+		/* reset remianing block size */
+		segment->remaining_bytes_in_block = ((segment == data_segment) ?
+						     data_segment->segment_size
+						     : ISCSI_PI_LEN_PER_SECTOR);
+	}
+	if (copied != len)
+		goto restart;
+
+	tcp_conn->in.pi_ctx.copy_state = copy_state;
+	return copied;
+}
+
+
 /**
  * iscsi_tcp_segment_recv - copy data to segment
  * @tcp_conn: the iSCSI TCP connection
@@ -402,6 +470,9 @@ void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
 	iscsi_segment_init_linear(&tcp_conn->in.segment,
 				tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
 				iscsi_tcp_hdr_recv_done, NULL);
+
+	tcp_conn->in.pi_inline = 0;
+	memset(&tcp_conn->in.pi_ctx, 0, sizeof(tcp_conn->in.pi_ctx));
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_recv_prep);
 
@@ -442,6 +513,71 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
 				iscsi_tcp_data_recv_done, rx_hash);
 }
 
+static int
+iscsi_tcp_process_pi(struct iscsi_tcp_conn *tcp_conn,
+		     struct iscsi_segment *segment)
+{
+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+	struct iscsi_hdr *hdr = tcp_conn->in.hdr;
+	int rc;
+
+	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+		return ISCSI_ERR_DATA_DGST;
+
+	/* check for non-exceptional status */
+	if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
+		if (rc)
+			return rc;
+	}
+
+	iscsi_tcp_hdr_recv_prep(tcp_conn);
+	return 0;
+}
+
+static int
+iscsi_tcp_pi_recv_prep(struct iscsi_tcp_conn *tcp_conn)
+{
+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+	struct iscsi_hdr *hdr = (struct iscsi_hdr *)tcp_conn->in.hdr_buf;
+	struct iscsi_segment *segment = &tcp_conn->in.segment;
+	struct hash_desc *hash = segment->hash;
+	struct scsi_data_buffer *prot_sdb = NULL;
+	struct iscsi_task *task;
+	int rc = 0;
+
+	if (tcp_conn->in.pi_inline) {
+		/* all done. need to calculate the final hash and complete */
+		if (segment->hash) {
+			crypto_hash_final(segment->hash, segment->digest);
+			iscsi_tcp_segment_splice_digest(segment,
+							segment->recv_digest);
+		}
+		iscsi_tcp_process_pi(tcp_conn, segment);
+		return rc;
+	}
+
+	spin_lock(&conn->session->back_lock);
+	task = iscsi_itt_to_ctask(conn, hdr->itt);
+	if (task) {
+		prot_sdb = scsi_prot(task->sc);
+		rc = iscsi_segment_seek_sg(segment, prot_sdb->table.sgl,
+					   prot_sdb->table.nents,
+					   tcp_conn->in.pi_ctx.pi_offset,
+					   tcp_conn->in.pi_ctx.pi_len,
+					   iscsi_tcp_process_pi,
+				/* We don't want to initialize hash again */
+					    NULL);
+	} else {
+		/* TODO : better error handling */
+		rc = ISCSI_ERR_BAD_ITT;
+	}
+	spin_unlock(&conn->session->back_lock);
+	segment->hash = hash;
+	tcp_conn->in.pi_ctx.pi_pending = 0;
+	return rc;
+}
+
 /**
  * iscsi_tcp_cleanup_task - free tcp_task resources
  * @task: iscsi task
@@ -486,7 +622,11 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
 	struct iscsi_tcp_task *tcp_task = task->dd_data;
 	struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
 	int datasn = be32_to_cpu(rhdr->datasn);
-	unsigned total_in_length = scsi_in(task->sc)->length;
+	/* unsigned total_in_length = scsi_in(task->sc)->length; */
+	unsigned total_in_length = iscsi_scsi_in_total_length(task->sc);
+
+	/* tcp_task->data_offset and tcp_conn->in.datalen will always have the
+	 * values received from target */
 
 	/*
 	 * lib iscsi will update this in the completion handling if there
@@ -571,11 +711,12 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
 			      data_length, session->max_burst);
 
 	data_offset = be32_to_cpu(rhdr->data_offset);
-	if (data_offset + data_length > scsi_out(task->sc)->length) {
+	if (data_offset + data_length > iscsi_scsi_out_total_length(task->sc)) {
 		iscsi_conn_printk(KERN_ERR, conn,
 				  "invalid R2T with data len %u at offset %u "
 				  "and total length %d\n", data_length,
-				  data_offset, scsi_out(task->sc)->length);
+				  data_offset,
+				  iscsi_scsi_out_total_length(task->sc));
 		return ISCSI_ERR_DATALEN;
 	}
 
@@ -617,6 +758,11 @@ iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
 	struct iscsi_hdr *hdr = tcp_conn->in.hdr;
 	int rc;
 
+	if (tcp_conn->in.pi_ctx.pi_pending) {
+		rc = iscsi_tcp_pi_recv_prep(tcp_conn);
+		return rc;
+	}
+
 	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
 		return ISCSI_ERR_DATA_DGST;
 
@@ -631,6 +777,18 @@ iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
 	return 0;
 }
 
+static int pi_len_in_data(int prot_op, int total_len,
+			  unsigned int sector_size)
+{
+	int num_sector = total_len/(sector_size + ISCSI_PI_LEN_PER_SECTOR);
+	int pi_len = 0;
+
+	if (prot_op == SCSI_PROT_READ_PASS || prot_op == SCSI_PROT_READ_STRIP)
+		pi_len = num_sector << ISCSI_PI_LEN_PER_SECTOR_SHIFT;
+
+	return pi_len;
+}
+
 /**
  * iscsi_tcp_hdr_dissect - process PDU header
  * @conn: iSCSI connection
@@ -645,6 +803,7 @@ static int
 iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 {
 	int rc = 0, opcode, ahslen;
+	int prot_op;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct iscsi_task *task;
 
@@ -688,6 +847,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 			struct iscsi_tcp_task *tcp_task = task->dd_data;
 			struct hash_desc *rx_hash = NULL;
 			struct scsi_data_buffer *sdb = scsi_in(task->sc);
+			struct scsi_data_buffer *prot_sdb = scsi_prot(task->sc);
+			unsigned int data_offset = tcp_task->data_offset;
+			unsigned int datalen = tcp_conn->in.datalen;
+			unsigned int sector_size = task->sc->device->sector_size;
+			unsigned int pi_len, pi_offset;
 
 			/*
 			 * Setup copy of Data-In into the Scsi_Cmnd
@@ -701,18 +865,74 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 			    !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
 				rx_hash = tcp_conn->rx_hash;
 
-			ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( "
-				     "offset=%d, datalen=%d)\n",
-				      tcp_task->data_offset,
-				      tcp_conn->in.datalen);
+			prot_op = scsi_get_prot_op(task->sc);
+			tcp_conn->in.pi_ctx.prot_op = prot_op;
+
+			if (prot_op) {
+				/* Expecting pi, pi bytes in datalen bytes */
+				pi_len = pi_len_in_data(prot_op,
+							tcp_conn->in.datalen,
+							sector_size);
+				pi_offset = pi_len_in_data(prot_op,
+							   tcp_task->data_offset,
+							   sector_size);
+
+				ISCSI_DBG_TCP(conn,
+					      "iscsi_tcp_hdr_dissect: pi_len %u, pi_offset %u, tcp_conn->in.datalen %u, tcp_task->data_offset %u\n",
+					      pi_len, pi_offset,
+					      tcp_conn->in.datalen,
+					      tcp_task->data_offset);
+
+				datalen = tcp_conn->in.datalen - pi_len;
+				data_offset =  tcp_task->data_offset - pi_offset;
+
+				if (prot_op == SCSI_PROT_READ_INSERT) {
+					pi_len = (datalen/sector_size) <<
+						 ISCSI_PI_LEN_PER_SECTOR_SHIFT;
+					pi_offset = (data_offset/sector_size) <<
+						 ISCSI_PI_LEN_PER_SECTOR_SHIFT;
+				}
+				tcp_conn->in.pi_ctx.pi_len = pi_len;
+				tcp_conn->in.pi_ctx.pi_offset = pi_offset;
+
+				if (prot_op == SCSI_PROT_READ_STRIP)
+					tcp_conn->in.pi_ctx.pi_pending = 0;
+				else
+					tcp_conn->in.pi_ctx.pi_pending = 1;
+			}
+
+			ISCSI_DBG_TCP(conn,
+				      "iscsi_tcp_begin_data_in( offset=%d, datalen=%d)\n",
+				      data_offset, datalen);
 			task->last_xfer = jiffies;
 			rc = iscsi_segment_seek_sg(&tcp_conn->in.segment,
 						   sdb->table.sgl,
 						   sdb->table.nents,
-						   tcp_task->data_offset,
-						   tcp_conn->in.datalen,
+						   data_offset, datalen,
 						   iscsi_tcp_process_data_in,
 						   rx_hash);
+
+			if (tcp_conn->in.pi_ctx.prot_op &&
+			    tcp_conn->in.pi_inline) {
+				if (tcp_conn->in.pi_ctx.pi_pending) {
+					rc = iscsi_segment_seek_sg(
+						   &tcp_conn->in.pi_ctx.pi_segment,
+						   prot_sdb->table.sgl,
+						   prot_sdb->table.nents,
+						   tcp_conn->in.pi_ctx.pi_offset,
+						   tcp_conn->in.pi_ctx.pi_len,
+						   NULL,
+						   NULL);
+				}
+				tcp_conn->in.segment.segment_size = sector_size;
+				tcp_conn->in.segment.remaining_bytes_in_block =
+					sector_size;
+				tcp_conn->in.pi_ctx.copy_state = COPY_DATA;
+				tcp_conn->in.pi_ctx.pi_segment.remaining_bytes_in_block
+					= ISCSI_PI_LEN_PER_SECTOR;
+				tcp_conn->in.pi_ctx.pi_segment.hash = rx_hash;
+			}
+
 			spin_unlock(&conn->session->back_lock);
 			return rc;
 		}
@@ -866,21 +1086,13 @@ inline int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn)
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_recv_segment_is_hdr);
 
-/**
- * iscsi_tcp_recv_skb - Process skb
- * @conn: iscsi connection
- * @skb: network buffer with header and/or data segment
- * @offset: offset in skb
- * @offload: bool indicating if transfer was offloaded
- *
- * Will return status of transfer in status. And will return
- * number of bytes copied.
- */
-int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
-		       unsigned int offset, bool offloaded, int *status)
+int __iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
+			 unsigned int offset, bool offloaded,
+			 bool pi_inline, int *status)
 {
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct iscsi_segment *segment = &tcp_conn->in.segment;
+	struct iscsi_segment *pi_segment = &tcp_conn->in.pi_ctx.pi_segment;
 	struct skb_seq_state seq;
 	unsigned int consumed = 0;
 	int rc = 0;
@@ -916,15 +1128,34 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
 			*status = ISCSI_TCP_SKB_DONE;
 			goto skb_done;
 		}
-		BUG_ON(segment->copied >= segment->size);
 
 		ISCSI_DBG_TCP(conn, "skb %p ptr=%p avail=%u\n", skb, ptr,
 			      avail);
-		rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
+
+		if (tcp_conn->in.pi_ctx.prot_op && pi_inline)
+			rc = iscsi_tcp_segment_interleve_data_pi_recv(tcp_conn,
+								      segment,
+								      ptr,
+								      avail);
+		else {
+			BUG_ON(segment->copied >= segment->size);
+			rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr,
+						    avail);
+		}
+		tcp_conn->in.pi_inline = pi_inline;
+
 		BUG_ON(rc == 0);
 		consumed += rc;
 
 		if (segment->total_copied >= segment->total_size) {
+			/* if pi_inline then segment done can be declared only
+			 * if pi segment is also complete
+			 */
+			if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn) &&
+			    tcp_conn->in.pi_ctx.prot_op && pi_inline &&
+			    (pi_segment->total_copied <
+			     pi_segment->total_size))
+				continue;
 			skb_abort_seq_read(&seq);
 			goto segment_done;
 		}
@@ -946,6 +1177,23 @@ skb_done:
 	conn->rxdata_octets += consumed;
 	return consumed;
 }
+EXPORT_SYMBOL_GPL(__iscsi_tcp_recv_skb);
+
+/**
+ * iscsi_tcp_recv_skb - Process skb
+ * @conn: iscsi connection
+ * @skb: network buffer with header and/or data segment
+ * @offset: offset in skb
+ * @offload: bool indicating if transfer was offloaded
+ *
+ * Will return status of transfer in status. And will return
+ * number of bytes copied.
+ */
+int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
+		       unsigned int offset, bool offloaded, int *status)
+{
+	return __iscsi_tcp_recv_skb(conn, skb, offset, offloaded, 1, status);
+}
 EXPORT_SYMBOL_GPL(iscsi_tcp_recv_skb);
 
 /**
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 728c9ad..1af7bbd 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -76,6 +76,9 @@ enum {
 
 #define ISCSI_ADDRESS_BUF_LEN		64
 
+#define ISCSI_PI_LEN_PER_SECTOR_SHIFT	3
+#define ISCSI_PI_LEN_PER_SECTOR		8
+
 enum {
 	/* this is the maximum possible storage for AHSs */
 	ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +
@@ -421,6 +424,9 @@ extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
 #define iscsi_session_printk(prefix, _sess, fmt, a...)	\
 	iscsi_cls_session_printk(prefix, _sess->cls_session, fmt, ##a)
 
+extern int iscsi_scsi_out_total_length(struct scsi_cmnd *);
+extern int iscsi_scsi_in_total_length(struct scsi_cmnd *);
+
 /*
  * connection management
  */
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 2a7aa75..1a1d87c 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -37,6 +37,7 @@ struct iscsi_segment {
 	unsigned int		copied;
 	unsigned int		total_size;
 	unsigned int		total_copied;
+	unsigned int		segment_size;
 
 	struct hash_desc	*hash;
 	unsigned char		padbuf[ISCSI_PAD_LEN];
@@ -50,6 +51,20 @@ struct iscsi_segment {
 	bool			atomic_mapped;
 
 	iscsi_segment_done_fn_t	*done;
+	/* Used if pi is inline to data */
+	unsigned int		remaining_bytes_in_block;
+};
+
+#define COPY_DATA	0
+#define COPY_PI		~COPY_DATA
+struct protection_info_ctx {
+	unsigned char			prot_op;
+	unsigned int			pi_pending;
+	unsigned int			pi_len;
+	unsigned int			pi_offset;
+	/* Following used only pi is inline to data */
+	unsigned int			copy_state;
+	struct iscsi_segment	pi_segment;
 };
 
 /* Socket connection receive helper */
@@ -62,6 +77,10 @@ struct iscsi_tcp_recv {
 
 	/* copied and flipped values */
 	int			datalen;
+	/* LLD should set if the current pdu has inline pi */
+	int			pi_inline;
+	/* To handle protection bytes */
+	struct protection_info_ctx	pi_ctx;
 };
 
 struct iscsi_tcp_conn {
@@ -97,6 +116,9 @@ enum {
 extern void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn);
 extern int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
 			      unsigned int offset, bool offloaded, int *status);
+extern int __iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
+				unsigned int offset, bool offloaded,
+				bool pi_inline, int *status);
 extern void iscsi_tcp_cleanup_task(struct iscsi_task *task);
 extern int iscsi_tcp_task_init(struct iscsi_task *task);
 extern int iscsi_tcp_task_xmit(struct iscsi_task *task);
-- 
2.0.3


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-06 22:37 ` [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support Anish Bhatt
@ 2014-08-07  2:25   ` Mike Christie
  2014-08-07  2:35     ` Anish Bhatt
  2014-08-14  9:25   ` Sagi Grimberg
  2014-08-21 21:47   ` Martin K. Petersen
  2 siblings, 1 reply; 9+ messages in thread
From: Mike Christie @ 2014-08-07  2:25 UTC (permalink / raw)
  To: Anish Bhatt; +Cc: linux-scsi, hch, jbottomley, kxie, manojmalviya

 On 08/06/2014 05:37 PM, Anish Bhatt wrote
> @@ -436,12 +473,12 @@ 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 = iscsi_scsi_in_total_length(sc);
>  		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
>  		zero_data(hdr->dlength);
> -		hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
> -
>  		if (sc->sc_data_direction == DMA_FROM_DEVICE)
>  			hdr->flags |= ISCSI_FLAG_CMD_READ;
> +		hdr->data_length = cpu_to_be32(in_len);
>  	}
>  

What tree and branch did you make these over? Have you seen the patches
from Sagi for iser and libiscsi support?

Could you rebuild this over Christoph's tree which has his patches:

git://git.infradead.org/users/hch/scsi-queue.git

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-07  2:25   ` Mike Christie
@ 2014-08-07  2:35     ` Anish Bhatt
  2014-08-08 22:01       ` Anish Bhatt
  0 siblings, 1 reply; 9+ messages in thread
From: Anish Bhatt @ 2014-08-07  2:35 UTC (permalink / raw)
  To: Mike Christie; +Cc: linux-scsi, hch, jbottomley, Karen Xie, Manoj Malviya

This patch was made over scsi-devel/master, I'll rebase it to Christoph's tree
-Anish
________________________________________
From: Mike Christie [michaelc@cs.wisc.edu]
Sent: Wednesday, August 06, 2014 7:25 PM
To: Anish Bhatt
Cc: linux-scsi@vger.kernel.org; hch@infradead.org; jbottomley@parallels.com; Karen Xie; Manoj Malviya
Subject: Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support

 On 08/06/2014 05:37 PM, Anish Bhatt wrote
> @@ -436,12 +473,12 @@ 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 = iscsi_scsi_in_total_length(sc);
>               hdr->flags |= ISCSI_FLAG_CMD_FINAL;
>               zero_data(hdr->dlength);
> -             hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
> -
>               if (sc->sc_data_direction == DMA_FROM_DEVICE)
>                       hdr->flags |= ISCSI_FLAG_CMD_READ;
> +             hdr->data_length = cpu_to_be32(in_len);
>       }
>

What tree and branch did you make these over? Have you seen the patches
from Sagi for iser and libiscsi support?

Could you rebuild this over Christoph's tree which has his patches:

git://git.infradead.org/users/hch/scsi-queue.git

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-07  2:35     ` Anish Bhatt
@ 2014-08-08 22:01       ` Anish Bhatt
  0 siblings, 0 replies; 9+ messages in thread
From: Anish Bhatt @ 2014-08-08 22:01 UTC (permalink / raw)
  To: Mike Christie; +Cc: linux-scsi, hch, jbottomley, Karen Xie, Manoj Malviya

Mike, I presume you meant the
8846bab
    scsi_cmnd: Introduce scsi_transfer_length helper
d77e653
libiscsi, iser: Adjust data_length to include protection information

 & Martin's fix after that 
5616b0
use the scsi data buffer length to extract transfer size

I see the commits in the branches, but not in master. Do the patches need to be
 rebased onto drivers-for-3.17 then ?
-Anish
________________________________________
From: Anish Bhatt
Sent: Wednesday, August 06, 2014 7:35 PM
To: Mike Christie
Cc: linux-scsi@vger.kernel.org; hch@infradead.org; jbottomley@parallels.com; Karen Xie; Manoj Malviya
Subject: RE: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support

This patch was made over scsi-devel/master, I'll rebase it to Christoph's tree
-Anish
________________________________________
From: Mike Christie [michaelc@cs.wisc.edu]
Sent: Wednesday, August 06, 2014 7:25 PM
To: Anish Bhatt
Cc: linux-scsi@vger.kernel.org; hch@infradead.org; jbottomley@parallels.com; Karen Xie; Manoj Malviya
Subject: Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support

 On 08/06/2014 05:37 PM, Anish Bhatt wrote
> @@ -436,12 +473,12 @@ 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 = iscsi_scsi_in_total_length(sc);
>               hdr->flags |= ISCSI_FLAG_CMD_FINAL;
>               zero_data(hdr->dlength);
> -             hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
> -
>               if (sc->sc_data_direction == DMA_FROM_DEVICE)
>                       hdr->flags |= ISCSI_FLAG_CMD_READ;
> +             hdr->data_length = cpu_to_be32(in_len);
>       }
>

What tree and branch did you make these over? Have you seen the patches
from Sagi for iser and libiscsi support?

Could you rebuild this over Christoph's tree which has his patches:

git://git.infradead.org/users/hch/scsi-queue.git

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-06 22:37 ` [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support Anish Bhatt
  2014-08-07  2:25   ` Mike Christie
@ 2014-08-14  9:25   ` Sagi Grimberg
  2014-08-14  9:28     ` Anish Bhatt
  2014-08-21 21:47   ` Martin K. Petersen
  2 siblings, 1 reply; 9+ messages in thread
From: Sagi Grimberg @ 2014-08-14  9:25 UTC (permalink / raw)
  To: Anish Bhatt; +Cc: linux-scsi, hch, jbottomley, michaelc, kxie, manojmalviya

On 8/7/2014 1:37 AM, Anish Bhatt wrote:
> Signed-off-by: Anish Bhatt <anish@chelsio.com>
> Signed-off by: Manoj Malvia <manojmalviya@chelsio.com>
> Signed-off by: Karen Xie <kxie@chelsio.com>
> ---
>   drivers/scsi/libiscsi.c     |  61 +++++++--
>   drivers/scsi/libiscsi_tcp.c | 296 ++++++++++++++++++++++++++++++++++++++++----
>   include/scsi/libiscsi.h     |   6 +
>   include/scsi/libiscsi_tcp.h |  22 ++++
>   4 files changed, 349 insertions(+), 36 deletions(-)
>

Hey Anish,

Against what target did you guys test this stuff?

Sagi.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-14  9:25   ` Sagi Grimberg
@ 2014-08-14  9:28     ` Anish Bhatt
  0 siblings, 0 replies; 9+ messages in thread
From: Anish Bhatt @ 2014-08-14  9:28 UTC (permalink / raw)
  To: Sagi Grimberg
  Cc: linux-scsi, hch, jbottomley, michaelc, Karen Xie, Manoj Malviya

We tested against a Sanblaze target. 
-Anish
________________________________________
From: Sagi Grimberg [sagig@dev.mellanox.co.il]
Sent: Thursday, August 14, 2014 2:25 AM
To: Anish Bhatt
Cc: linux-scsi@vger.kernel.org; hch@infradead.org; jbottomley@parallels.com; michaelc@cs.wisc.edu; Karen Xie; Manoj Malviya
Subject: Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support

On 8/7/2014 1:37 AM, Anish Bhatt wrote:
> Signed-off-by: Anish Bhatt <anish@chelsio.com>
> Signed-off by: Manoj Malvia <manojmalviya@chelsio.com>
> Signed-off by: Karen Xie <kxie@chelsio.com>
> ---
>   drivers/scsi/libiscsi.c     |  61 +++++++--
>   drivers/scsi/libiscsi_tcp.c | 296 ++++++++++++++++++++++++++++++++++++++++----
>   include/scsi/libiscsi.h     |   6 +
>   include/scsi/libiscsi_tcp.h |  22 ++++
>   4 files changed, 349 insertions(+), 36 deletions(-)
>

Hey Anish,

Against what target did you guys test this stuff?

Sagi.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-06 22:37 ` [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support Anish Bhatt
  2014-08-07  2:25   ` Mike Christie
  2014-08-14  9:25   ` Sagi Grimberg
@ 2014-08-21 21:47   ` Martin K. Petersen
  2014-08-21 21:49     ` Anish Bhatt
  2 siblings, 1 reply; 9+ messages in thread
From: Martin K. Petersen @ 2014-08-21 21:47 UTC (permalink / raw)
  To: Anish Bhatt; +Cc: linux-scsi, hch, jbottomley, michaelc, kxie, manojmalviya

>>>>> "Anish" == Anish Bhatt <anish@chelsio.com> writes:

Anish,

Just a heads up that we've got some changes due to land shortly that'll
provide interfaces for you to get the correct transfer lengths, size of
the protection interval, etc. Your patch should be rebased on top of
those changes.

-- 
Martin K. Petersen	Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support
  2014-08-21 21:47   ` Martin K. Petersen
@ 2014-08-21 21:49     ` Anish Bhatt
  0 siblings, 0 replies; 9+ messages in thread
From: Anish Bhatt @ 2014-08-21 21:49 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: linux-scsi, hch, jbottomley, michaelc, Karen Xie, Manoj Malviya

Thanks for the heads up, will wait for those. Please cc me/Manoj on the patches
-Anish
________________________________________
From: Martin K. Petersen [martin.petersen@oracle.com]
Sent: Thursday, August 21, 2014 2:47 PM
To: Anish Bhatt
Cc: linux-scsi@vger.kernel.org; hch@infradead.org; jbottomley@parallels.com; michaelc@cs.wisc.edu; Karen Xie; Manoj Malviya
Subject: Re: [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support

>>>>> "Anish" == Anish Bhatt <anish@chelsio.com> writes:

Anish,

Just a heads up that we've got some changes due to land shortly that'll
provide interfaces for you to get the correct transfer lengths, size of
the protection interval, etc. Your patch should be rebased on top of
those changes.

--
Martin K. Petersen      Oracle Linux Engineering

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-08-21 21:51 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-06 22:37 [PATCH scsi 0/1] libiscsi : T10 DIF support Anish Bhatt
2014-08-06 22:37 ` [PATCH scsi 1/1] libiscsi : Add T10 Data Integrity Feature support Anish Bhatt
2014-08-07  2:25   ` Mike Christie
2014-08-07  2:35     ` Anish Bhatt
2014-08-08 22:01       ` Anish Bhatt
2014-08-14  9:25   ` Sagi Grimberg
2014-08-14  9:28     ` Anish Bhatt
2014-08-21 21:47   ` Martin K. Petersen
2014-08-21 21:49     ` Anish Bhatt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.