All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bart Van Assche <bvanassche-HInyCGIudOg@public.gmane.org>
To: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: dillowda-1Heg1YXhbW8@public.gmane.org,
	roland-BHEL68pLQRGGvPXPguhicg@public.gmane.org
Subject: [PATCH 08/15] ib_srp: Make srp_disconnect_target() wait for IB completions
Date: Sun, 25 Mar 2012 14:56:27 +0000	[thread overview]
Message-ID: <2957171.T8m7GAua3j@asus> (raw)
In-Reply-To: <5207288.nSt5MkVMpO@asus>

Modify srp_disconnect_target() such that it waits until it is
sure that no new IB completions will be received.

Signed-off-by: Bart Van Assche <bvanassche-HInyCGIudOg@public.gmane.org>
Cc: David Dillow <dillowda-1Heg1YXhbW8@public.gmane.org>
Cc: Roland Dreier <roland-BHEL68pLQRGGvPXPguhicg@public.gmane.org>
---
 drivers/infiniband/ulp/srp/ib_srp.c |   99 ++++++++++++++++++++++++++++++-----
 drivers/infiniband/ulp/srp/ib_srp.h |    3 +
 2 files changed, 89 insertions(+), 13 deletions(-)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 9125a9c..564ff08 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -40,7 +40,7 @@
 #include <linux/parser.h>
 #include <linux/random.h>
 #include <linux/jiffies.h>
-
+#include <linux/delay.h>
 #include <linux/atomic.h>
 
 #include <scsi/scsi.h>
@@ -91,6 +91,7 @@ static void srp_remove_one(struct ib_device *device);
 static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
 static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
 static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
+static void srp_reset_req(struct srp_target_port *target, struct srp_request *req);
 
 static struct scsi_transport_template *ib_srp_transport_template;
 
@@ -229,14 +230,16 @@ static int srp_create_target_ib(struct srp_target_port *target)
 		return -ENOMEM;
 
 	target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev,
-				       srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0);
+				       srp_recv_completion, NULL, target,
+				       SRP_RQ_SIZE + 1, 0);
 	if (IS_ERR(target->recv_cq)) {
 		ret = PTR_ERR(target->recv_cq);
 		goto err;
 	}
 
 	target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev,
-				       srp_send_completion, NULL, target, SRP_SQ_SIZE, 0);
+				       srp_send_completion, NULL, target,
+				       SRP_SQ_SIZE + 1, 0);
 	if (IS_ERR(target->send_cq)) {
 		ret = PTR_ERR(target->send_cq);
 		goto err_recv_cq;
@@ -464,11 +467,67 @@ static bool srp_change_conn_state(struct srp_target_port *target,
 	return changed;
 }
 
+static void srp_wait_last_recv_wqe(struct srp_target_port *target)
+{
+	static struct ib_recv_wr wr = {
+	};
+	struct ib_recv_wr *bad_wr;
+	int ret;
+
+	if (target->last_recv_wqe)
+		return;
+
+	ret = ib_post_recv(target->qp, &wr, &bad_wr);
+	if (ret < 0) {
+		shost_printk(KERN_ERR, target->scsi_host,
+			     "ib_post_recv() failed (%d)\n", ret);
+		return;
+	}
+
+	ret = wait_event_timeout(target->qp_wq, target->last_recv_wqe,
+				 target->rq_tmo_jiffies);
+	WARN(ret <= 0, "Timeout while waiting for last recv WQE (ret = %d)\n",
+	     ret);
+}
+
+static void srp_wait_last_send_wqe(struct srp_target_port *target)
+{
+	static struct ib_send_wr wr = {
+	};
+	struct ib_send_wr *bad_wr;
+	unsigned long deadline = jiffies + target->rq_tmo_jiffies;
+	int ret;
+
+	if (target->last_send_wqe)
+		return;
+
+	ret = ib_post_send(target->qp, &wr, &bad_wr);
+	if (ret < 0) {
+		shost_printk(KERN_ERR, target->scsi_host,
+			     "ib_post_send() failed (%d)\n", ret);
+		return;
+	}
+
+	while (!target->last_send_wqe && time_before(jiffies, deadline)) {
+		srp_send_completion(target->send_cq, target);
+		msleep(20);
+	}
+
+	WARN_ON(!target->last_send_wqe);
+}
+
 static void srp_disconnect_target(struct srp_target_port *target)
 {
+	static struct ib_qp_attr qp_attr = {
+		.qp_state = IB_QPS_ERR
+	};
+	int ret;
+
 	if (srp_change_conn_state(target, false)) {
 		/* XXX should send SRP_I_LOGOUT request */
 
+		BUG_ON(!target->cm_id);
+
 		init_completion(&target->done);
 		if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
 			shost_printk(KERN_DEBUG, target->scsi_host,
@@ -477,6 +536,20 @@ static void srp_disconnect_target(struct srp_target_port *target)
 			wait_for_completion(&target->done);
 		}
 	}
+
+	if (target->cm_id) {
+		ib_destroy_cm_id(target->cm_id);
+		target->cm_id = NULL;
+	}
+
+	if (target->qp) {
+		ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE);
+		WARN(ret != 0, "ib_modify_qp() failed: %d\n", ret);
+
+		srp_wait_last_recv_wqe(target);
+
+		srp_wait_last_send_wqe(target);
+	}
 }
 
 static void srp_free_req_data(struct srp_target_port *target)
@@ -520,7 +593,6 @@ static void srp_remove_target(struct srp_target_port *target)
 	srp_remove_host(target->scsi_host);
 	scsi_remove_host(target->scsi_host);
 	srp_disconnect_target(target);
-	ib_destroy_cm_id(target->cm_id);
 	srp_free_target_ib(target);
 	srp_free_req_data(target);
 	scsi_host_put(target->scsi_host);
@@ -548,6 +620,8 @@ static int srp_connect_target(struct srp_target_port *target)
 	WARN_ON(target->connected);
 
 	target->qp_in_error = false;
+	target->last_recv_wqe = false;
+	target->last_send_wqe = false;
 
 	ret = srp_lookup_path(target);
 	if (ret)
@@ -645,7 +719,6 @@ static int srp_reconnect_target(struct srp_target_port *target)
 {
 	struct Scsi_Host *shost = target->scsi_host;
 	struct ib_qp_attr qp_attr;
-	struct ib_wc wc;
 	int i, ret;
 
 	if (target->state != SRP_TARGET_LIVE)
@@ -671,11 +744,6 @@ static int srp_reconnect_target(struct srp_target_port *target)
 	if (ret)
 		goto err;
 
-	while (ib_poll_cq(target->recv_cq, 1, &wc) > 0)
-		; /* nothing */
-	while (ib_poll_cq(target->send_cq, 1, &wc) > 0)
-		; /* nothing */
-
 	for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
 		struct srp_request *req = &target->req_ring[i];
 		if (req->scmnd)
@@ -1249,7 +1317,7 @@ static void srp_handle_qp_err(enum ib_wc_status wc_status,
 			      enum ib_wc_opcode wc_opcode,
 			      struct srp_target_port *target)
 {
-	if (target->connected)
+	if (target->connected && !target->qp_in_error)
 		shost_printk(KERN_ERR, target->scsi_host,
 			     PFX "failed %s status %d\n",
 			     wc_opcode & IB_WC_RECV ? "receive" : "send",
@@ -1267,8 +1335,11 @@ static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
 		if (likely(wc.status == IB_WC_SUCCESS)) {
 			srp_handle_recv(target, &wc);
 		} else {
+			if (wc.wr_id == 0) {
+				target->last_recv_wqe = true;
+				wake_up(&target->qp_wq);
+			}
 			srp_handle_qp_err(wc.status, wc.opcode, target);
-			break;
 		}
 	}
 }
@@ -1284,8 +1355,9 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
 			iu = (struct srp_iu *) (uintptr_t) wc.wr_id;
 			list_add(&iu->list, &target->free_tx);
 		} else {
+			if (wc.wr_id == 0)
+				target->last_send_wqe = true;
 			srp_handle_qp_err(wc.status, wc.opcode, target);
-			break;
 		}
 	}
 }
@@ -2229,6 +2301,7 @@ static ssize_t srp_create_target(struct device *dev,
 	spin_lock_init(&target->lock);
 	INIT_LIST_HEAD(&target->free_tx);
 	INIT_LIST_HEAD(&target->free_reqs);
+	init_waitqueue_head(&target->qp_wq);
 	for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) {
 		struct srp_request *req = &target->req_ring[i];
 
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index de2d0b3..84b6a4c 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -180,6 +180,9 @@ struct srp_target_port {
 	struct completion	done;
 	int			status;
 	bool			qp_in_error;
+	bool			last_recv_wqe;
+	bool			last_send_wqe;
+	wait_queue_head_t	qp_wq;
 
 	struct completion	tsk_mgmt_done;
 	u8			tsk_mgmt_status;
-- 
1.7.7


--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2012-03-25 14:56 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-25 14:45 [PATCH 00/15, v3] Make ib_srp better suited for H.A. purposes Bart Van Assche
2012-03-25 14:47 ` [PATCH 01/15] ib_srp: Enlarge block layer timeout Bart Van Assche
2012-03-29 16:59   ` Dave Dillow
     [not found]     ` <20120329165931.GA19700-1Heg1YXhbW8@public.gmane.org>
2012-04-22 16:01       ` Bart Van Assche
     [not found]         ` <4F942B74.4040106-HInyCGIudOg@public.gmane.org>
2012-04-30 15:11           ` David Dillow
     [not found]             ` <1335798691.441.2.camel-zHLflQxYYDO4Hhoo1DtQwJ9G+ZOsUmrO@public.gmane.org>
2012-05-19 10:50               ` Bart Van Assche
     [not found]                 ` <4FB77AEE.7030100-HInyCGIudOg@public.gmane.org>
2012-05-30  4:56                   ` David Dillow
2012-03-25 14:48 ` [PATCH 02/15] ib_srp: Introduce srp_handle_qp_err() Bart Van Assche
2012-03-25 14:50 ` [PATCH 03/15] ib_srp: Micro-optimize srp_queuecommand() Bart Van Assche
2012-03-25 14:52 ` [PATCH 04/15] ib_srp: Suppress superfluous error messages Bart Van Assche
2012-03-25 14:53 ` [PATCH 05/15] ib_srp: Avoid that SCSI error handling triggers a crash Bart Van Assche
2012-03-25 14:54 ` [PATCH 06/15] ib_srp: Introduce the helper function srp_remove_target() Bart Van Assche
2012-03-25 14:55 ` [PATCH 07/15] ib_srp: Eliminate state SRP_TARGET_DEAD Bart Van Assche
2012-03-25 14:56 ` Bart Van Assche [this message]
2012-03-25 14:57 ` [PATCH 09/15] srp_transport: Fix atttribute registration Bart Van Assche
2012-03-25 14:58 ` [PATCH 10/15] srp_transport: Simplify attribute initialization code Bart Van Assche
2012-03-25 14:59 ` [PATCH 11/15] srp_transport: Document sysfs attributes Bart Van Assche
2012-03-25 15:00 ` [PATCH 12/15] ib_srp: " Bart Van Assche
2012-03-25 15:01 ` [PATCH 13/15] ib_srp: Allow SRP disconnect through sysfs Bart Van Assche
2012-07-16 22:20   ` Mike Christie
     [not found]     ` <500493B4.4010303-hcNo3dDEHLuVc3sceRu5cw@public.gmane.org>
2012-07-17 12:55       ` bart-LmZ/31Jx5xYUl6sPKNhdgg
2012-03-25 15:02 ` [PATCH 14/15] ib_srp: Introduce a temporary variable in srp_remove_target() Bart Van Assche
2012-03-25 15:03 ` [PATCH 15/15] ib_srp: Maintain a single connection per I_T nexus Bart Van Assche
2012-03-25 15:18 ` [PATCH 00/15, v3] Make ib_srp better suited for H.A. purposes Bart Van Assche
2012-03-27 16:37   ` Dave Dillow

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2957171.T8m7GAua3j@asus \
    --to=bvanassche-hinycgiudog@public.gmane.org \
    --cc=dillowda-1Heg1YXhbW8@public.gmane.org \
    --cc=linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=roland-BHEL68pLQRGGvPXPguhicg@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.