aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOr Gerlitz <ogerlitz@mellanox.com>2012-03-05 11:21:44 -0500
committerRoland Dreier <roland@purestorage.com>2012-03-05 11:53:05 -0500
commit89e984e2c2cd14f77ccb26c47726ac7f13b70ae8 (patch)
treee628854190ad60fc8890318236a3ec395b8b94bb
parentd474186f19d7ac1c7fbb293fdcfa46103e45e2ca (diff)
IB/iser: Post initial receive buffers before sending the final login request
An iser target may send iscsi NO-OP PDUs as soon as it marks the iSER iSCSI session as fully operative. This means that there is window where there are no posted receive buffers on the initiator side, so it's possible for the iSER RC connection to break because of RNR NAK / retry errors. To fix this, rely on the flags bits in the login request to have FFP (0x3) in the lower nibble as a marker for the final login request, and post an initial chunk of receive buffers before sending that login request instead of after getting the login response. Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Cc: <stable@vger.kernel.org> Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c18
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h1
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c30
3 files changed, 22 insertions, 27 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 9a43cb07f294..db43b3117168 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -364,6 +364,9 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
364 } 364 }
365 ib_conn = ep->dd_data; 365 ib_conn = ep->dd_data;
366 366
367 if (iser_alloc_rx_descriptors(ib_conn))
368 return -ENOMEM;
369
367 /* binds the iSER connection retrieved from the previously 370 /* binds the iSER connection retrieved from the previously
368 * connected ep_handle to the iSCSI layer connection. exchanges 371 * connected ep_handle to the iSCSI layer connection. exchanges
369 * connection pointers */ 372 * connection pointers */
@@ -398,19 +401,6 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
398 iser_conn->ib_conn = NULL; 401 iser_conn->ib_conn = NULL;
399} 402}
400 403
401static int
402iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
403{
404 struct iscsi_conn *conn = cls_conn->dd_data;
405 int err;
406
407 err = iser_conn_set_full_featured_mode(conn);
408 if (err)
409 return err;
410
411 return iscsi_conn_start(cls_conn);
412}
413
414static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) 404static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
415{ 405{
416 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 406 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
@@ -724,7 +714,7 @@ static struct iscsi_transport iscsi_iser_transport = {
724 .get_conn_param = iscsi_conn_get_param, 714 .get_conn_param = iscsi_conn_get_param,
725 .get_ep_param = iscsi_iser_get_ep_param, 715 .get_ep_param = iscsi_iser_get_ep_param,
726 .get_session_param = iscsi_session_get_param, 716 .get_session_param = iscsi_session_get_param,
727 .start_conn = iscsi_iser_conn_start, 717 .start_conn = iscsi_conn_start,
728 .stop_conn = iscsi_iser_conn_stop, 718 .stop_conn = iscsi_iser_conn_stop,
729 /* iscsi host params */ 719 /* iscsi host params */
730 .get_host_param = iscsi_host_get_param, 720 .get_host_param = iscsi_host_get_param,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index db7ea3704da7..296be431a0e9 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -366,4 +366,5 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
366void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); 366void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
367int iser_initialize_task_headers(struct iscsi_task *task, 367int iser_initialize_task_headers(struct iscsi_task *task,
368 struct iser_tx_desc *tx_desc); 368 struct iser_tx_desc *tx_desc);
369int iser_alloc_rx_descriptors(struct iser_conn *ib_conn);
369#endif 370#endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 622e9857c869..a00ccd1ca333 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -170,7 +170,7 @@ static void iser_create_send_desc(struct iser_conn *ib_conn,
170} 170}
171 171
172 172
173static int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) 173int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)
174{ 174{
175 int i, j; 175 int i, j;
176 u64 dma_addr; 176 u64 dma_addr;
@@ -230,23 +230,24 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn)
230 kfree(ib_conn->rx_descs); 230 kfree(ib_conn->rx_descs);
231} 231}
232 232
233/** 233static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
234 * iser_conn_set_full_featured_mode - (iSER API)
235 */
236int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
237{ 234{
238 struct iscsi_iser_conn *iser_conn = conn->dd_data; 235 struct iscsi_iser_conn *iser_conn = conn->dd_data;
239 236
240 iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX); 237 iser_dbg("req op %x flags %x\n", req->opcode, req->flags);
241 238 /* check if this is the last login - going to full feature phase */
242 /* Check that there is no posted recv or send buffers left - */ 239 if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE)
243 /* they must be consumed during the login phase */ 240 return 0;
244 BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0);
245 BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
246 241
247 if (iser_alloc_rx_descriptors(iser_conn->ib_conn)) 242 /*
248 return -ENOMEM; 243 * Check that there is one posted recv buffer (for the last login
244 * response) and no posted send buffers left - they must have been
245 * consumed during previous login phases.
246 */
247 WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1);
248 WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
249 249
250 iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
250 /* Initial post receive buffers */ 251 /* Initial post receive buffers */
251 if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX)) 252 if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
252 return -ENOMEM; 253 return -ENOMEM;
@@ -426,6 +427,9 @@ int iser_send_control(struct iscsi_conn *conn,
426 err = iser_post_recvl(iser_conn->ib_conn); 427 err = iser_post_recvl(iser_conn->ib_conn);
427 if (err) 428 if (err)
428 goto send_control_error; 429 goto send_control_error;
430 err = iser_post_rx_bufs(conn, task->hdr);
431 if (err)
432 goto send_control_error;
429 } 433 }
430 434
431 err = iser_post_send(iser_conn->ib_conn, mdesc); 435 err = iser_post_send(iser_conn->ib_conn, mdesc);