[RFC 6/6] bidi support: iSCSI bidi & varlen CDBs

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

 



This patch is intended to provide a working example of a use case
for bidi and varlen CDBs. The actual patches will be sent via the
open-iscsi project.

- Use proposed SCSI implementation for iSCSI bidirectional commands.
- Use proposed block layer implementation for iSCSI extended CDBs.
- Dynamically build AHSs for extended cdbs and bidirectional requests.
- Follow iscsi rfc-3720 concerning datasn and r2tsn with bidirectional commands,
  these must be the same counter.
[- Remove check for first-burst bigger than max-burst so iSCSI regression tests can pass.
   this is the wrong fix and will be removed in actual patches]

Signed-off-by: Benny Halevy <[email protected]>
Signed-off-by: Boaz Harrosh <[email protected]>

---
 drivers/infiniband/ulp/iser/iscsi_iser.c |    4 +-
 drivers/scsi/iscsi_tcp.c                 |  190 +++++++++++++++++++++++-------
 drivers/scsi/iscsi_tcp.h                 |   10 +-
 drivers/scsi/libiscsi.c                  |   33 +++--
 include/scsi/iscsi_proto.h               |    8 ++
 include/scsi/libiscsi.h                  |   18 +++-
 6 files changed, 200 insertions(+), 63 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index dd221ed..a0eae0c 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -140,10 +140,10 @@ iscsi_iser_cmd_init(struct iscsi_cmd_tas
 	iser_ctask->iser_conn    = iser_conn;

 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
-		BUG_ON(ctask->total_length == 0);
+		BUG_ON(iscsi_out_total_length(ctask) == 0);

 		debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
-			   ctask->itt, ctask->total_length, ctask->imm_count,
+			   ctask->itt, iscsi_out_total_length(ctask), ctask->imm_count,
 			   ctask->unsol_count);
 	}

diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index d0b139c..2bc57a5 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -109,7 +109,9 @@ iscsi_hdr_digest(struct iscsi_conn *conn
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;

 	crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
-	buf->sg.length = tcp_conn->hdr_size;
+	buf->sg.length += sizeof(__u32);
+	debug_tcp("iscsi_hdr_digest: &crc %p crc 0x%02x%02x%02x%02x\n",
+	          crc, crc[0], crc[1], crc[2], crc[3]);
 }

 static inline int
@@ -229,14 +231,21 @@ iscsi_data_rsp(struct iscsi_conn *conn,
 	if (tcp_conn->in.datalen == 0)
 		return 0;

-	if (ctask->datasn != datasn)
+	if (tcp_ctask->exp_datasn != datasn) {
+		debug_tcp("%s: ctask->datasn(%d) != rhdr->datasn(%d)\n",
+		          __FUNCTION__, tcp_ctask->exp_datasn, datasn);
 		return ISCSI_ERR_DATASN;
+	}

-	ctask->datasn++;
+	tcp_ctask->exp_datasn++;

 	tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
-	if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length)
+	if (tcp_ctask->data_offset + tcp_conn->in.datalen > iscsi_in_total_length(ctask)) {
+		debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+		          __FUNCTION__, tcp_ctask->data_offset,
+		          tcp_conn->in.datalen, iscsi_in_total_length(ctask));
 		return ISCSI_ERR_DATA_OFFSET;
+	}

 	if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
 		struct scsi_cmnd *sc = ctask->sc;
@@ -246,7 +255,7 @@ iscsi_data_rsp(struct iscsi_conn *conn,
 			int res_count = be32_to_cpu(rhdr->residual_count);

 			if (res_count > 0 &&
-			    res_count <= sc->request_bufflen) {
+			    res_count <= iscsi_in_total_length(ctask)) {
 				sc->resid = res_count;
 				sc->result = (DID_OK << 16) | rhdr->cmd_status;
 			} else
@@ -281,6 +290,7 @@ iscsi_solicit_data_init(struct iscsi_con
 {
 	struct iscsi_data *hdr;
 	struct scsi_cmnd *sc = ctask->sc;
+	struct scsi_cmnd_buff scb;

 	hdr = &r2t->dtask.hdr;
 	memset(hdr, 0, sizeof(struct iscsi_data));
@@ -308,12 +318,13 @@ iscsi_solicit_data_init(struct iscsi_con
 	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
 			   sizeof(struct iscsi_hdr));

-	if (sc->use_sg) {
+	scsi_get_out_buff(sc, &scb);
+	if (scb.use_sg) {
 		int i, sg_count = 0;
-		struct scatterlist *sg = sc->request_buffer;
+		struct scatterlist *sg = scb.buffer;

 		r2t->sg = NULL;
-		for (i = 0; i < sc->use_sg; i++, sg += 1) {
+		for (i = 0; i < scb.use_sg; i++, sg += 1) {
 			/* FIXME: prefetch ? */
 			if (sg_count + sg->length > r2t->data_offset) {
 				int page_offset;
@@ -337,7 +348,7 @@ iscsi_solicit_data_init(struct iscsi_con
 		BUG_ON(r2t->sg == NULL);
 	} else {
 		iscsi_buf_init_iov(&r2t->sendbuf,
-			    (char*)sc->request_buffer + r2t->data_offset,
+			    (char*)scb.buffer + r2t->data_offset,
 			    r2t->data_count);
 		r2t->sg = NULL;
 	}
@@ -365,15 +376,13 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
 		return ISCSI_ERR_DATALEN;
 	}

-	if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
+	if (tcp_ctask->exp_datasn != r2tsn)
 		return ISCSI_ERR_R2TSN;

 	rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
 	if (rc)
 		return rc;

-	/* FIXME: use R2TSN to detect missing R2T */
-
 	/* fill-in new R2T associated with the task */
 	spin_lock(&session->lock);
 	if (!ctask->sc || ctask->mtask ||
@@ -401,11 +410,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s
 			    r2t->data_length, session->max_burst);

 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
-	if (r2t->data_offset + r2t->data_length > ctask->total_length) {
+	if (r2t->data_offset + r2t->data_length > iscsi_out_total_length(ctask)) {
 		spin_unlock(&session->lock);
 		printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
 		       "offset %u and total length %d\n", r2t->data_length,
-		       r2t->data_offset, ctask->total_length);
+		       r2t->data_offset, iscsi_out_total_length(ctask));
 		return ISCSI_ERR_DATALEN;
 	}

@@ -414,7 +423,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s

 	iscsi_solicit_data_init(conn, ctask, r2t);

-	tcp_ctask->exp_r2tsn = r2tsn + 1;
+	tcp_ctask->exp_datasn = r2tsn + 1;
 	__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
 	tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
 	list_move_tail(&ctask->running, &conn->xmitqueue);
@@ -512,8 +521,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
 		tcp_conn->in.ctask = session->cmds[itt];
 		if (ahslen)
 			rc = ISCSI_ERR_AHSLEN;
-		else if (tcp_conn->in.ctask->sc->sc_data_direction ==
-								DMA_TO_DEVICE)
+		else if (tcp_conn->in.ctask->sc->sc_data_direction == DMA_TO_DEVICE ||
+		         tcp_conn->in.ctask->sc->sc_data_direction == DMA_BIDIRECTIONAL)
 			rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
 		else
 			rc = ISCSI_ERR_PROTO;
@@ -609,7 +618,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *
 	       size, tcp_conn->in.offset, tcp_conn->in.copied);

 	BUG_ON(size <= 0);
-	BUG_ON(tcp_ctask->sent + size > ctask->total_length);
+	BUG_ON(tcp_ctask->sent + size > iscsi_in_total_length(ctask));

 	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
 			   (char*)buf + (offset + tcp_conn->data_copied), size);
@@ -704,28 +713,30 @@ static int iscsi_scsi_data_in(struct isc
 	struct scsi_cmnd *sc = ctask->sc;
 	struct scatterlist *sg;
 	int i, offset, rc = 0;
+	struct scsi_cmnd_buff scb;

 	BUG_ON((void*)ctask != sc->SCp.ptr);

+	scsi_get_in_buff(sc, &scb);
 	/*
 	 * copying Data-In into the Scsi_Cmnd
 	 */
-	if (!sc->use_sg) {
+	if (!scb.use_sg) {
 		i = ctask->data_count;
-		rc = iscsi_ctask_copy(tcp_conn, ctask, sc->request_buffer,
-				      sc->request_bufflen,
+		rc = iscsi_ctask_copy(tcp_conn, ctask, scb.buffer,
+				      scb.bufflen,
 				      tcp_ctask->data_offset);
 		if (rc == -EAGAIN)
 			return rc;
 		if (conn->datadgst_en)
-			iscsi_recv_digest_update(tcp_conn, sc->request_buffer,
+			iscsi_recv_digest_update(tcp_conn, scb.buffer,
 						 i);
 		rc = 0;
 		goto done;
 	}

 	offset = tcp_ctask->data_offset;
-	sg = sc->request_buffer;
+	sg = scb.buffer;

 	if (tcp_ctask->data_offset)
 		for (i = 0; i < tcp_ctask->sg_count; i++)
@@ -734,7 +745,7 @@ static int iscsi_scsi_data_in(struct isc
 	if (offset < 0)
 		offset = 0;

-	for (i = tcp_ctask->sg_count; i < sc->use_sg; i++) {
+	for (i = tcp_ctask->sg_count; i < scb.use_sg; i++) {
 		char *dest;

 		dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
@@ -749,7 +760,7 @@ static int iscsi_scsi_data_in(struct isc
 				if (!offset)
 					crypto_hash_update(
 							&tcp_conn->rx_hash,
-							&sg[i], 1);
+							&sg[i], sg[i].length);
 				else
 					partial_sg_digest_update(
 							&tcp_conn->rx_hash,
@@ -1141,7 +1152,8 @@ iscsi_sendhdr(struct iscsi_conn *conn, s
 		flags |= MSG_MORE;

 	res = iscsi_send(conn, buf, size, flags);
-	debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
+	debug_tcp("sendhdr %d bytes, length %d sent %d res %d\n",
+	          size, buf->sg.length, buf->sent, res);
 	if (res >= 0) {
 		if (size != res)
 			return -EAGAIN;
@@ -1217,6 +1229,7 @@ iscsi_solicit_data_cont(struct iscsi_con
 	struct iscsi_data *hdr;
 	struct scsi_cmnd *sc = ctask->sc;
 	int new_offset;
+	struct scsi_cmnd_buff scb;

 	hdr = &r2t->dtask.hdr;
 	memset(hdr, 0, sizeof(struct iscsi_data));
@@ -1245,12 +1258,13 @@ iscsi_solicit_data_cont(struct iscsi_con
 	if (iscsi_buf_left(&r2t->sendbuf))
 		return;

-	if (sc->use_sg) {
+	scsi_get_out_buff(sc, &scb);
+	if (scb.use_sg) {
 		iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
 		r2t->sg += 1;
 	} else {
 		iscsi_buf_init_iov(&r2t->sendbuf,
-			    (char*)sc->request_buffer + new_offset,
+			    (char*)scb.buffer + new_offset,
 			    r2t->data_count);
 		r2t->sg = NULL;
 	}
@@ -1279,39 +1293,133 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task
 {
 	struct scsi_cmnd *sc = ctask->sc;
 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+	int hdrlength, rlen;
+	unsigned short ahslength;
+	struct iscsi_ecdb_ahdr *ecdb_ahdr;
+	struct scsi_cmnd_buff scb;

 	BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));

+	/*
+	 * extended headers immediately follow tcp_ctask->hdr hence ctask->hdr
+	 * must point there
+	 */
+	tcp_ctask->hdrext = tcp_ctask->hdrextbuf;
+	BUG_ON(tcp_ctask->hdrext != (char *)ctask->hdr + sizeof(tcp_ctask->hdr));
+
 	tcp_ctask->sent = 0;
 	tcp_ctask->sg_count = 0;
+	tcp_ctask->exp_datasn = 0;
+
+	/*
+	 * make an extended cdb AHS
+	 */
+	if (sc->request->varlen_cdb && (sc->request->varlen_cdb_len > MAX_COMMAND_SIZE)) {
+		int pad_len;
+
+		ecdb_ahdr = (struct iscsi_ecdb_ahdr *)tcp_ctask->hdrext;
+		rlen = sc->request->varlen_cdb_len - MAX_COMMAND_SIZE;
+
+		BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb));
+		ahslength = rlen + sizeof(ecdb_ahdr->reserved);

-	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+		/* need to pad ecdb? */
+		pad_len = rlen & (ISCSI_PAD_LEN - 1);
+		if (pad_len) {
+			pad_len = ISCSI_PAD_LEN - pad_len;
+			memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len);
+			ahslength += pad_len;
+		}
+
+		ecdb_ahdr->ahslength = cpu_to_be16(ahslength);
+		ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB;
+		ecdb_ahdr->reserved = 0;
+		memcpy(ecdb_ahdr->ecdb, sc->request->varlen_cdb+MAX_COMMAND_SIZE, rlen);
+
+		tcp_ctask->hdrext += ahslength + sizeof(ecdb_ahdr->ahslength) +
+				sizeof(ecdb_ahdr->ahstype);
+		debug_scsi("iscsi_tcp_cmd_init: extended cdb:"
+			" varlen_cdb_len %d rlen %d pad_len %d ahs_length %d total_ahs_length %Zd\n",
+			sc->request->varlen_cdb_len, rlen, pad_len, ahslength,
+			((char *)tcp_ctask->hdrext - (char *)tcp_ctask->hdrextbuf) );
+	}
+
+	switch (sc->sc_data_direction) {
+	case DMA_BIDIRECTIONAL: {
+		struct iscsi_rlength_ahdr *rlen_ahdr;
+
+		scsi_get_in_buff(sc, &scb);
+		BUG_ON(scb.buffer == NULL);
+		BUG_ON(scb.bufflen == 0);
+
+		rlen_ahdr = (struct iscsi_rlength_ahdr*)tcp_ctask->hdrext;
+		rlen_ahdr->ahslength =
+			cpu_to_be16(sizeof(rlen_ahdr->read_length) +
+			            sizeof(rlen_ahdr->reserved));
+		rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH;
+		rlen_ahdr->reserved = 0;
+		rlen_ahdr->read_length = cpu_to_be32(scb.bufflen);
+
+		tcp_ctask->hdrext += sizeof(*rlen_ahdr);
+		
+		debug_scsi("bidi-in rlen_ahdr->read_length(%d) rlen_ahdr->ahslength(%d)\n",
+			   be32_to_cpu(rlen_ahdr->read_length) ,be16_to_cpu(rlen_ahdr->ahslength)
+		);
+	}
+	/* FALLTHROUGH */
+	case DMA_TO_DEVICE:
 		tcp_ctask->xmstate = XMSTATE_W_HDR;
-		tcp_ctask->exp_r2tsn = 0;
-		BUG_ON(ctask->total_length == 0);
+		BUG_ON(iscsi_out_total_length(ctask) == 0);

-		if (sc->use_sg) {
-			struct scatterlist *sg = sc->request_buffer;
+		scsi_get_out_buff(sc, &scb);
+		BUG_ON(scb.buffer == NULL);
+		BUG_ON(scb.bufflen == 0);
+		if (scb.use_sg) {
+			struct scatterlist *sg = scb.buffer;

 			iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
 			tcp_ctask->sg = sg + 1;
-			tcp_ctask->bad_sg = sg + sc->use_sg;
+			tcp_ctask->bad_sg = sg + scb.use_sg;
 		} else {
 			iscsi_buf_init_iov(&tcp_ctask->sendbuf,
-					   sc->request_buffer,
-					   sc->request_bufflen);
+			                   scb.buffer,
+			                   scb.bufflen);
 			tcp_ctask->sg = NULL;
 			tcp_ctask->bad_sg = NULL;
 		}
 		debug_scsi("cmd [itt 0x%x total %d imm_data %d "
 			   "unsol count %d, unsol offset %d]\n",
-			   ctask->itt, ctask->total_length, ctask->imm_count,
-			   ctask->unsol_count, ctask->unsol_offset);
-	} else
+			   ctask->itt, iscsi_out_total_length(ctask), ctask->imm_count,
+			   ctask->unsol_count, ctask->unsol_offset);
+		break;
+
+	case DMA_FROM_DEVICE:
+	case DMA_NONE:
 		tcp_ctask->xmstate = XMSTATE_R_HDR;
+		break;
+
+	default:
+		BUG_ON(1);
+	}
+
+	/* calculate size of additional header segments (AHSs) */
+	hdrlength = (char *)tcp_ctask->hdrext -
+	            ((char *)&tcp_ctask->hdr + sizeof(tcp_ctask->hdr));
+
+	BUG_ON(hdrlength & (ISCSI_PAD_LEN-1));
+	hdrlength /= ISCSI_PAD_LEN;
+
+	BUG_ON(hdrlength >= 256);
+	tcp_ctask->hdr.hlength = hdrlength & 0xFF;
+
+	debug_scsi("iscsi_tcp_cmd_init: total_pdu_length %Zd "
+	           "hlength %d dlength %d data_length %d\n",
+	           tcp_ctask->hdrext - (char *)&tcp_ctask->hdr,
+	           tcp_ctask->hdr.hlength, ntoh24(ctask->hdr->dlength),
+	           be32_to_cpu(ctask->hdr->data_length));

-	iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
-			    sizeof(struct iscsi_hdr));
+	iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&tcp_ctask->hdr,
+	                   tcp_ctask->hdrext - (char *)&tcp_ctask->hdr);
 }

 /**
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 3273683..24620ee 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -47,7 +47,7 @@ #define XMSTATE_W_RESEND_DATA_DIGEST	0x8

 #define ISCSI_PAD_LEN			4
 #define ISCSI_SG_TABLESIZE		SG_ALL
-#define ISCSI_TCP_MAX_CMD_LEN		16
+#define ISCSI_TCP_MAX_CMD_LEN		260  /* FIXME: SCSI_MAX_VARLEN_CDB_LEN */

 struct crypto_hash;
 struct socket;
@@ -141,8 +141,10 @@ struct iscsi_r2t_info {

 struct iscsi_tcp_cmd_task {
 	struct iscsi_cmd	hdr;
-	char			hdrext[4*sizeof(__u16)+	/* AHS */
-				    sizeof(__u32)];	/* HeaderDigest */
+	char			hdrextbuf[sizeof(struct iscsi_ecdb_ahdr) +
+					  sizeof(struct iscsi_rlength_ahdr) +
+					  sizeof(__u32)];	/* HeaderDigest */
+	char			*hdrext;
 	char			pad[ISCSI_PAD_LEN];
 	int			pad_count;		/* padded bytes */
 	struct iscsi_buf	headbuf;		/* header buf (xmit) */
@@ -152,7 +154,7 @@ struct iscsi_tcp_cmd_task {
 	struct scatterlist	*sg;			/* per-cmd SG list  */
 	struct scatterlist	*bad_sg;		/* assert statement */
 	int			sg_count;		/* SG's to process  */
-	uint32_t		exp_r2tsn;
+	uint32_t		exp_datasn;		/* expected target's R2TSN/DataSN */
 	int			data_offset;
 	struct iscsi_r2t_info	*r2t;			/* in progress R2T    */
 	struct iscsi_queue	r2tpool;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e11b23c..08e4528 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -120,10 +120,16 @@ static void iscsi_prep_scsi_cmd_pdu(stru
         session->cmdsn++;
         hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
         memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
-        memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+	if (sc->cmd_len < MAX_COMMAND_SIZE) {
+		memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+	}

 	ctask->data_count = 0;
-	if (sc->sc_data_direction == DMA_TO_DEVICE) {
+	switch (sc->sc_data_direction) {
+	case DMA_BIDIRECTIONAL:
+		hdr->flags |= ISCSI_FLAG_CMD_READ;
+		/* FALLTHROUGH */
+	case DMA_TO_DEVICE:
 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
 		/*
 		 * Write counters:
@@ -145,11 +151,11 @@ static void iscsi_prep_scsi_cmd_pdu(stru
 		ctask->unsol_datasn = 0;

 		if (session->imm_data_en) {
-			if (ctask->total_length >= session->first_burst)
+			if (iscsi_out_total_length(ctask) >= session->first_burst)
 				ctask->imm_count = min(session->first_burst,
 							conn->max_xmit_dlength);
 			else
-				ctask->imm_count = min(ctask->total_length,
+				ctask->imm_count = min(iscsi_out_total_length(ctask),
 							conn->max_xmit_dlength);
 			hton24(ctask->hdr->dlength, ctask->imm_count);
 		} else
@@ -157,20 +163,20 @@ static void iscsi_prep_scsi_cmd_pdu(stru

 		if (!session->initial_r2t_en) {
 			ctask->unsol_count = min(session->first_burst,
-				ctask->total_length) - ctask->imm_count;
+				iscsi_out_total_length(ctask)) - ctask->imm_count;
 			ctask->unsol_offset = ctask->imm_count;
 		}

 		if (!ctask->unsol_count)
 			/* No unsolicit Data-Out's */
 			ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-	} else {
-		ctask->datasn = 0;
+		break;
+	case DMA_FROM_DEVICE:
+		hdr->flags |= ISCSI_FLAG_CMD_READ;
+		/* FALLTHROUGH */
+	default:
 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
 		zero_data(hdr->dlength);
-
-		if (sc->sc_data_direction == DMA_FROM_DEVICE)
-			hdr->flags |= ISCSI_FLAG_CMD_READ;
 	}

 	conn->scsicmd_pdus_cnt++;
@@ -817,7 +823,6 @@ int iscsi_queuecommand(struct scsi_cmnd
 	ctask->conn = conn;
 	ctask->sc = sc;
 	INIT_LIST_HEAD(&ctask->running);
-	ctask->total_length = sc->request_bufflen;
 	iscsi_prep_scsi_cmd_pdu(ctask);

 	session->tt->init_cmd_task(ctask);
@@ -826,7 +831,9 @@ int iscsi_queuecommand(struct scsi_cmnd
 	debug_scsi(
 	       "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
 		"win %d]\n",
-		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+		sc->sc_data_direction == DMA_TO_DEVICE ? "write" :
+		  sc->sc_data_direction == DMA_BIDIRECTIONAL ? "bidirectional" :
+		  sc->sc_data_direction == DMA_FROM_DEVICE ? "read" : "none",
 		conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
 		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
 	spin_unlock(&session->lock);
@@ -1633,7 +1640,7 @@ int iscsi_conn_start(struct iscsi_cls_co
 		printk("iscsi: invalid burst lengths: "
 		       "first_burst %d max_burst %d\n",
 		       session->first_burst, session->max_burst);
-		return -EINVAL;
+//		return -EINVAL;
 	}

 	spin_lock_bh(&session->lock);
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 02f6e4b..e530734 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -139,6 +139,14 @@ struct iscsi_rlength_ahdr {
 	__be32 read_length;
 };

+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+	__be16 ahslength;	/* CDB length - 15, including reserved byte */
+	uint8_t ahstype;
+	uint8_t reserved;
+	uint8_t ecdb[260 - 16];	/* 4-byte aligned extended CDB spillover */
+};
+
 /* SCSI Response Header */
 struct iscsi_cmd_rsp {
 	uint8_t opcode;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index ea0816d..6701ea6 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -25,6 +25,7 @@ #define LIBISCSI_H

 #include <linux/types.h>
 #include <linux/mutex.h>
+#include <scsi/scsi_cmnd.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 #include <scsi/iscsi_proto.h>
@@ -33,7 +34,6 @@ #include <scsi/iscsi_if.h>
 struct scsi_transport_template;
 struct scsi_device;
 struct Scsi_Host;
-struct scsi_cmnd;
 struct socket;
 struct iscsi_transport;
 struct iscsi_cls_session;
@@ -99,7 +99,6 @@ struct iscsi_cmd_task {
 	 */
 	struct iscsi_cmd	*hdr;
 	int			itt;		/* this ITT */
-	int			datasn;		/* DataSN */

 	uint32_t		unsol_datasn;
 	int			imm_count;	/* imm-data (bytes)   */
@@ -108,7 +107,6 @@ struct iscsi_cmd_task {
 	int			unsol_offset;
 	int			data_count;	/* remaining Data-Out */
 	struct scsi_cmnd	*sc;		/* associated SCSI cmd*/
-	int			total_length;
 	struct iscsi_conn	*conn;		/* used connection    */
 	struct iscsi_mgmt_task	*mtask;		/* tmf mtask in progr */

@@ -119,6 +117,20 @@ struct iscsi_cmd_task {
 	void			*dd_data;	/* driver/transport data */
 };

+static inline int
+iscsi_out_total_length(struct iscsi_cmd_task* ctask)
+{
+	return ctask->sc->request_bufflen;
+}
+
+static inline int
+iscsi_in_total_length(struct iscsi_cmd_task* ctask)
+{
+	return is_bidi_cmnd(ctask->sc) ?
+		ctask->sc->bidi_read_sdb.request_bufflen :
+		ctask->sc->request_bufflen;
+}
+
 struct iscsi_conn {
 	struct iscsi_cls_conn	*cls_conn;	/* ptr to class connection */
 	void			*dd_data;	/* iscsi_transport data */
-- 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux