[openib-general] [PATCH] [SRP] support for it_iu length negotiation

John Kingman kingman at storagegear.com
Mon Oct 31 15:45:36 PST 2005


At SRP login, the client indicates to the target a requested maximum
initiator to target IU (it_iu) length.  If the target cannot handle
this length, it rejects the login.  If the target can handle the
requested length, on the other hand, it will accept the login and
respond with its own maximum it_iu length.  Currently, ib_srp does not
utilize the maximum it_iu length suggested by the target, and if the
target rejects the value used by ib_srp, no connection will be made. 

This patch adds the ability for ib_srp to retry a login if the target
rejects the login because the maximum it_iu value used by ib_srp is
too large.  The ib_srp client will reduce its requested maximum it_iu
length to a minimum value and retry the login.  

On a successful login, the ib_srp client will set the maximum it_iu
length it will use to the maximum it_iu length requested by the
target, within the bounds of the minimum and maximum it_iu lengths it
can support.

The size of the indirect memory descriptor table built by ib_srp is
established at build time, based on an internal maximum iu size.  In
order to accomodate the changes described above, this patch modifies
ib_srp so that if the maximum it_iu length established with the target
is less than the internal maximum iu size specified when ib_srp was
built, only those indirect memory descriptors that will fit in the
established maximum it_iu length (the partial descriptor list) will be
sent to the target.  Any indirect memory descriptors beyond that must
be retrieved by the target via rdma read, as described in the SRP 
documentation.

The patch has been tested with our target.

Signed-off-by: John Kingman <kingman at storagegear.com>

Index: ib_srp.h
===================================================================
--- ib_srp.h	(revision 3914)
+++ ib_srp.h	(working copy)
@@ -53,8 +53,10 @@ enum {
 
 	SRP_PORT_REDIRECT	= 1,
 	SRP_DLID_REDIRECT	= 2,
+	SRP_LOGIN_RETRY		= 3,
 
-	SRP_MAX_IU_LEN		= 256,
+	SRP_MAX_IU_LEN		= 1024,     /* our maximum it_iu size */
+	SRP_REQ_IU_LEN		= 256,      /* it_iu size to request initially */
 
 	SRP_RQ_SHIFT    	= 6,
 	SRP_RQ_SIZE		= 1 << SRP_RQ_SHIFT,
@@ -65,9 +67,11 @@ enum {
 };
 
 #define SRP_OP_RECV		(1 << 31)
-#define SRP_MAX_INDIRECT	((SRP_MAX_IU_LEN -			\
-				  sizeof (struct srp_cmd) -		\
-				  sizeof (struct srp_indirect_buf)) / 16)
+#define SRP_MIN_IU_LEN          (sizeof (struct srp_cmd) +          \
+				 sizeof (struct srp_indirect_buf))
+#define SRP_NUM_PARTIALS(x)                                         \
+	(((x) - SRP_MIN_IU_LEN) / sizeof (struct srp_direct_buf))
+#define SRP_MAX_INDIRECT        SRP_NUM_PARTIALS(SRP_MAX_IU_LEN)
 
 enum srp_target_state {
 	SRP_TARGET_LIVE,
@@ -117,8 +121,10 @@ struct srp_target_port {
 	struct ib_cm_id	       *cm_id;
 	struct ib_cq	       *cq;
 	struct ib_qp	       *qp;
-
 	int			max_ti_iu_len;
+	int			max_it_iu_len;
+	int			req_it_iu_len;
+	int			max_partial_desc;
 	s32			req_lim;
 
 	unsigned		rx_head;

Index: ib_srp.c
===================================================================
--- ib_srp.c	(revision 3914)
+++ ib_srp.c	(working copy)
@@ -295,7 +297,7 @@ static int srp_send_req(struct srp_targe
 
 	req->priv.opcode     	= SRP_LOGIN_REQ;
 	req->priv.tag        	= 0;
-	req->priv.req_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+	req->priv.req_it_iu_len = cpu_to_be32(target->req_it_iu_len);
 	req->priv.req_buf_fmt 	= cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
 					      SRP_BUF_FORMAT_INDIRECT);
 	memcpy(req->priv.initiator_port_id, target->srp_host->initiator_port_id, 16);
@@ -386,6 +388,7 @@ static int srp_connect_target(struct srp
 				return ret;
 			break;
 
+		case SRP_LOGIN_RETRY:
 		case SRP_DLID_REDIRECT:
 			break;
 
@@ -528,11 +531,6 @@ static int srp_map_data(struct scsi_cmnd
 
 			fmt = SRP_DATA_DESC_INDIRECT;
 
-			if (scmnd->sc_data_direction == DMA_TO_DEVICE)
-				cmd->data_out_desc_cnt = n;
-			else
-				cmd->data_in_desc_cnt = n;
-
 			buf->table_desc.va  = cpu_to_be64(req->cmd->dma +
 							  sizeof *cmd +
 							  sizeof *buf);
@@ -552,6 +550,20 @@ static int srp_map_data(struct scsi_cmnd
 
 			buf->len = cpu_to_be32(datalen);
 
+			/*
+			 * buf->len includes the SRP indirect descriptor table.
+			 * We only include in the descriptor count (n) and len 
+			 * the descriptors that fit in partial descriptor list
+			 * of the it_iu. Any beyond that will be rdma read by 
+			 * the target.
+			 */
+			n = min(target->max_partial_desc, n);
+
+			if (scmnd->sc_data_direction == DMA_TO_DEVICE)
+				cmd->data_out_desc_cnt = n;
+			else
+				cmd->data_in_desc_cnt = n;
+
 			len = sizeof (struct srp_cmd) +
 				sizeof (struct srp_indirect_buf) +
 				n * sizeof (struct srp_direct_buf);
@@ -1003,10 +1015,19 @@ static void srp_cm_rej_handler(struct ib
 			struct srp_login_rej *rej = event->private_data;
 			u32 reason = be32_to_cpu(rej->reason);
 
-			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
-				printk(KERN_WARNING PFX
+			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) {
+				printk(KERN_DEBUG PFX
 				       "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
-			else
+				/* 
+				 * Retry with minimum it_iu length and let target 
+				 * suggest max it_iu length. 
+				 */
+				if (target->req_it_iu_len > SRP_MIN_IU_LEN) {
+					target->req_it_iu_len = SRP_MIN_IU_LEN;
+					target->status = SRP_LOGIN_RETRY;
+					break;
+				}
+			} else
 				printk(KERN_WARNING PFX
 				       "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
 		} else
@@ -1045,6 +1066,17 @@ static int srp_cm_handler(struct ib_cm_i
 			struct srp_login_rsp *rsp = event->private_data;
 
 			target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);
+			target->max_it_iu_len = be32_to_cpu(rsp->max_it_iu_len);
+			if (target->max_it_iu_len > SRP_MAX_IU_LEN)
+			    target->max_it_iu_len = SRP_MAX_IU_LEN;
+			else if (target->max_it_iu_len < SRP_MIN_IU_LEN) {
+				printk(KERN_ERR PFX "Invalid rsp->max_it_iu_len: %d\n", 
+					target->max_it_iu_len);
+				target->status = -ECONNRESET;
+				break;
+			}
+			target->max_partial_desc = 
+				SRP_NUM_PARTIALS(target->max_it_iu_len);
 			target->req_lim       = be32_to_cpu(rsp->req_lim_delta);
 
 			target->scsi_host->can_queue = min(target->req_lim,
@@ -1227,7 +1259,8 @@ static struct scsi_host_template srp_tem
 	.eh_host_reset_handler		= srp_reset_host,
 	.can_queue			= SRP_SQ_SIZE,
 	.this_id			= -1,
-	.sg_tablesize			= SRP_MAX_INDIRECT,
+	.sg_tablesize			= (SRP_MAX_INDIRECT < SG_ALL ? 
+					   SRP_MAX_INDIRECT : SG_ALL),
 	.cmd_per_lun			= SRP_SQ_SIZE,
 	.use_clustering			= ENABLE_CLUSTERING
 };
@@ -1434,6 +1467,8 @@ static ssize_t srp_create_target(struct 
 		ret = PTR_ERR(target->cm_id);
 		goto err_free;
 	}
+	target->req_it_iu_len = SRP_REQ_IU_LEN;
+	target->max_partial_desc = SRP_NUM_PARTIALS(SRP_REQ_IU_LEN);
 
 	ret = srp_connect_target(target);
 	if (ret) {



More information about the general mailing list