Skip to contentSkip to conversation

bidi support: iSCSI bidi & varlen CDBs

RFC In review Boaz Harrosh 1 participant 1 message Jan 21, 2007

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

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

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]

---
 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(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +2 -2
index dd221ed..a0eae0c 100644
@@ -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);
 	}
 
drivers/scsi/iscsi_tcp.c +149 -41

356 lines not on this page · raw message

drivers/scsi/iscsi_tcp.h +6 -4
index 3273683..24620ee 100644
@@ -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;
drivers/scsi/libiscsi.c +20 -13
index e11b23c..08e4528 100644
@@ -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);
include/scsi/iscsi_proto.h +8 -0
index 02f6e4b..e530734 100644
@@ -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;
include/scsi/libiscsi.h +15 -3
index ea0816d..6701ea6 100644
@@ -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 */