[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