[openib-general] SRP [PATCH 1/4] split srp_reconnect_target

Ishai Rabinovitz ishai at mellanox.co.il
Mon Jun 5 08:33:32 PDT 2006


Split the srp_reconnect_target to two functions _srp_remove_target and
_srp_restore_target. These functions will be used later in patch series also
to allow removal and restoration of a target from the sysfs.

I made some changes in order to support this:
1) There are two new states:
SRP_TARGET_DISCONNECTED - The state after _srp_remove_target was successfully 
                          executed and before _srp_restore_target is executed.
SRP_TARGET_DISCONNECTING - The state while _srp_remove_target is executed.
SRP_TARGET_CONNECTING is now the state while _srp_restore_target is executed.

2) The value of target->cm_id can be NULL. This happens after _srp_remove_target
   destroyed the old cm_id and before _srp_restore_target created the new cm_id.

Signed-off-by: Ishai Rabinovitz <ishai at mellanox.co.il>

Index: last_stable/drivers/infiniband/ulp/srp/ib_srp.c
===================================================================
--- last_stable.orig/drivers/infiniband/ulp/srp/ib_srp.c	2006-06-04 10:03:25.000000000 +0300
+++ last_stable/drivers/infiniband/ulp/srp/ib_srp.c	2006-06-04 10:54:26.000000000 +0300
@@ -40,6 +40,7 @@
 #include <linux/parser.h>
 #include <linux/random.h>
 #include <linux/jiffies.h>
+#include <linux/delay.h>
 
 #include <asm/atomic.h>
 
@@ -373,7 +374,8 @@ static void srp_remove_work(void *target
 	spin_unlock(&target->srp_host->target_lock);
 
 	scsi_remove_host(target->scsi_host);
-	ib_destroy_cm_id(target->cm_id);
+	if (target->cm_id)
+		ib_destroy_cm_id(target->cm_id);
 	srp_free_target_ib(target);
 	scsi_host_put(target->scsi_host);
 }
@@ -464,20 +466,57 @@ static void srp_reset_req(struct srp_tar
 	srp_remove_req(target, req);
 }
 
-static int srp_reconnect_target(struct srp_target_port *target)
+static void srp_remove_target_port(struct srp_target_port *target)
+{
+	/*
+	 * Kill our target port off.
+	 * However, we have to defer the real removal because we might
+	 * be in the context of the SCSI error handler now, which
+	 * would deadlock if we call scsi_remove_host().
+	 */
+	spin_lock_irq(target->scsi_host->host_lock);
+	if (target->state != SRP_TARGET_REMOVED) {
+		target->state = SRP_TARGET_DEAD;
+		INIT_WORK(&target->work, srp_remove_work, target);
+		schedule_work(&target->work);
+	}
+	spin_unlock_irq(target->scsi_host->host_lock);
+}
+
+static int _srp_remove_target(struct srp_target_port *target)
 {
-	struct ib_cm_id *new_cm_id;
 	struct ib_qp_attr qp_attr;
 	struct srp_request *req, *tmp;
 	struct ib_wc wc;
-	int ret;
+	int ret = 0;
 
 	spin_lock_irq(target->scsi_host->host_lock);
-	if (target->state != SRP_TARGET_LIVE) {
+	switch (target->state) {
+	case SRP_TARGET_REMOVED:
+	case SRP_TARGET_DEAD:
+		ret = -ENOENT;
+		break;
+
+	case SRP_TARGET_DISCONNECTING:
+	case SRP_TARGET_CONNECTING:
+		ret = -EAGAIN; /* So that the caller will try again later -
+				  after the connection ends one way or another */
+		break;
+
+	case SRP_TARGET_DISCONNECTED:
+		ret = -ENOTCONN;
+		break;
+
+	case SRP_TARGET_LIVE:
+		break;
+	}
+
+	if (ret) {
 		spin_unlock_irq(target->scsi_host->host_lock);
-		return -EAGAIN;
+		return ret;
 	}
-	target->state = SRP_TARGET_CONNECTING;
+
+	target->state = SRP_TARGET_DISCONNECTING;
 	spin_unlock_irq(target->scsi_host->host_lock);
 
 	srp_disconnect_target(target);
@@ -485,24 +525,14 @@ static int srp_reconnect_target(struct s
 	 * Now get a new local CM ID so that we avoid confusing the
 	 * target in case things are really fouled up.
 	 */
-	new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
-				    srp_cm_handler, target);
-	if (IS_ERR(new_cm_id)) {
-		ret = PTR_ERR(new_cm_id);
-		goto err;
-	}
 	ib_destroy_cm_id(target->cm_id);
-	target->cm_id = new_cm_id;
+	target->cm_id = NULL;
 
 	qp_attr.qp_state = IB_QPS_RESET;
 	ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE);
 	if (ret)
 		goto err;
 
-	ret = srp_init_qp(target, target->qp);
-	if (ret)
-		goto err;
-
 	while (ib_poll_cq(target->cq, 1, &wc) > 0)
 		; /* nothing */
 
@@ -513,6 +543,49 @@ static int srp_reconnect_target(struct s
 	target->tx_head	 = 0;
 	target->tx_tail  = 0;
 
+	spin_lock_irq(target->scsi_host->host_lock);
+	if (target->state == SRP_TARGET_DISCONNECTING) {
+		ret = 0;
+		target->state = SRP_TARGET_DISCONNECTED;
+	} else
+		ret = -EAGAIN;
+	spin_unlock_irq(target->scsi_host->host_lock);
+
+	return ret;
+
+err:
+	printk(KERN_ERR PFX "remove failed (%d), removing target port.\n", ret);
+
+	srp_remove_target_port(target);
+
+	return ret;
+}
+
+static int _srp_restore_target(struct srp_target_port *target)
+{
+	struct ib_cm_id *new_cm_id;
+	int ret;
+
+	spin_lock_irq(target->scsi_host->host_lock);
+	if (target->state != SRP_TARGET_DISCONNECTED) {
+		spin_unlock_irq(target->scsi_host->host_lock);
+		return -EAGAIN;
+	}
+	target->state = SRP_TARGET_CONNECTING;
+	spin_unlock_irq(target->scsi_host->host_lock);
+
+	new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
+				    srp_cm_handler, target);
+	if (IS_ERR(new_cm_id)) {
+		ret = PTR_ERR(new_cm_id);
+		goto err;
+	}
+	target->cm_id = new_cm_id;
+
+	ret = srp_init_qp(target, target->qp);
+	if (ret)
+		goto err;
+
 	ret = srp_connect_target(target);
 	if (ret)
 		goto err;
@@ -528,25 +601,22 @@ static int srp_reconnect_target(struct s
 	return ret;
 
 err:
-	printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret);
+	printk(KERN_ERR PFX "restore failed (%d), removing target port.\n", ret);
 
-	/*
-	 * We couldn't reconnect, so kill our target port off.
-	 * However, we have to defer the real removal because we might
-	 * be in the context of the SCSI error handler now, which
-	 * would deadlock if we call scsi_remove_host().
-	 */
-	spin_lock_irq(target->scsi_host->host_lock);
-	if (target->state == SRP_TARGET_CONNECTING) {
-		target->state = SRP_TARGET_DEAD;
-		INIT_WORK(&target->work, srp_remove_work, target);
-		schedule_work(&target->work);
-	}
-	spin_unlock_irq(target->scsi_host->host_lock);
+	srp_remove_target_port(target);
 
 	return ret;
 }
 
+static int srp_reconnect_target(struct srp_target_port *target)
+{
+	int ret = _srp_remove_target(target);
+	if (ret && ret != -ENOTCONN)
+		return ret;
+
+	return _srp_restore_target(target);
+}
+
 static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
 		       int sg_cnt, struct srp_request *req,
 		       struct srp_direct_buf *buf)
@@ -933,6 +1003,13 @@ static int __srp_post_send(struct srp_ta
 	return ret;
 }
 
+static int srp_target_is_not_connected(struct srp_target_port *target)
+{
+	return (1 << target->state) &
+	       ((1 << SRP_TARGET_CONNECTING) | (1 << SRP_TARGET_DISCONNECTING) |
+		(1 << SRP_TARGET_DISCONNECTED));
+}
+
 static int srp_queuecommand(struct scsi_cmnd *scmnd,
 			    void (*done)(struct scsi_cmnd *))
 {
@@ -942,7 +1019,7 @@ static int srp_queuecommand(struct scsi_
 	struct srp_cmd *cmd;
 	int len;
 
-	if (target->state == SRP_TARGET_CONNECTING)
+	if (unlikely(srp_target_is_not_connected(target)))
 		goto err;
 
 	if (target->state == SRP_TARGET_DEAD ||
@@ -1292,6 +1369,9 @@ static int srp_abort(struct scsi_cmnd *s
 
 	printk(KERN_ERR "SRP abort called\n");
 
+	if (srp_target_is_not_connected(target))
+		return FAILED;
+
 	if (srp_find_req(target, scmnd, &req))
 		return FAILED;
 	if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1320,6 +1400,9 @@ static int srp_reset_device(struct scsi_
 
 	printk(KERN_ERR "SRP reset_device called\n");
 
+	if (srp_target_is_not_connected(target))
+		return FAILED;
+
 	if (srp_find_req(target, scmnd, &req))
 		return FAILED;
 	if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1914,8 +2000,10 @@ static void srp_remove_one(struct ib_dev
 		list_for_each_entry_safe(target, tmp_target,
 					 &host->target_list, list) {
 			scsi_remove_host(target->scsi_host);
-			srp_disconnect_target(target);
-			ib_destroy_cm_id(target->cm_id);
+			if (target->cm_id) {
+				srp_disconnect_target(target);
+				ib_destroy_cm_id(target->cm_id);
+			}
 			srp_free_target_ib(target);
 			scsi_host_put(target->scsi_host);
 		}
Index: last_stable/drivers/infiniband/ulp/srp/ib_srp.h
===================================================================
--- last_stable.orig/drivers/infiniband/ulp/srp/ib_srp.h	2006-06-04 10:02:47.000000000 +0300
+++ last_stable/drivers/infiniband/ulp/srp/ib_srp.h	2006-06-04 10:03:25.000000000 +0300
@@ -75,6 +75,8 @@ enum {
 enum srp_target_state {
 	SRP_TARGET_LIVE,
 	SRP_TARGET_CONNECTING,
+	SRP_TARGET_DISCONNECTED,
+	SRP_TARGET_DISCONNECTING,
 	SRP_TARGET_DEAD,
 	SRP_TARGET_REMOVED
 };
-- 
Ishai Rabinovitz



More information about the general mailing list