summaryrefslogtreecommitdiff
path: root/drivers/infiniband/ulp/iser/iscsi_iser.c
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-05-21 15:54:03 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-07-12 08:22:17 -0500
commitb40977d95fb3a1898ace6a7d97e4ed1a33a440a4 (patch)
treedfbe7909a066c974f16403e25f687496dde7fb0a /drivers/infiniband/ulp/iser/iscsi_iser.c
parent5af3e91d232b7e022f258202f72ebb79b8b0c706 (diff)
[SCSI] iser: fix handling of scsi cmnds during recovery.
After the stop_conn callback has returned the LLD should not touch the scsi cmds. iscsi_tcp and libiscsi use the conn->recv_lock and suspend_rx field to halt recv path processing, but iser does not have any protection. This patch modifies iser so that userspace can just call the ep_disconnect callback, which will halt all recv IO, before calling the stop_conn callback so we do not have to worry about the conn->recv_lock and suspend rx field. iser just needs to stop the send side from accessing the ib conn. Fixup to handle when the ep poll fails and ep disconnect is called from Erez. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/infiniband/ulp/iser/iscsi_iser.c')
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 9b34946eb00d..8a1bfb7277c8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -305,10 +305,18 @@ iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
- if (iser_conn->ib_conn)
- iser_conn->ib_conn->iser_conn = NULL;
iscsi_conn_teardown(cls_conn);
+ /*
+ * Userspace will normally call the stop callback and
+ * already have freed the ib_conn, but if it goofed up then
+ * we free it here.
+ */
+ if (ib_conn) {
+ ib_conn->iser_conn = NULL;
+ iser_conn_put(ib_conn);
+ }
}
static int
@@ -340,12 +348,29 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
iser_conn = conn->dd_data;
ib_conn->iser_conn = iser_conn;
iser_conn->ib_conn = ib_conn;
+ iser_conn_get(ib_conn);
conn->recv_lock = &iser_conn->lock;
return 0;
}
+static void
+iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
+
+ iscsi_conn_stop(cls_conn, flag);
+ /*
+ * There is no unbind event so the stop callback
+ * must release the ref from the bind.
+ */
+ iser_conn_put(ib_conn);
+ iser_conn->ib_conn = NULL;
+}
+
static int
iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
{
@@ -564,6 +589,17 @@ iscsi_iser_ep_disconnect(__u64 ep_handle)
if (!ib_conn)
return;
+ if (ib_conn->iser_conn)
+ /*
+ * Must suspend xmit path if the ep is bound to the
+ * iscsi_conn, so we know we are not accessing the ib_conn
+ * when we free it.
+ *
+ * This may not be bound if the ep poll failed.
+ */
+ iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
+
+
iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
iser_conn_terminate(ib_conn);
}
@@ -622,7 +658,7 @@ static struct iscsi_transport iscsi_iser_transport = {
.get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
- .stop_conn = iscsi_conn_stop,
+ .stop_conn = iscsi_iser_conn_stop,
/* iscsi host params */
.get_host_param = iscsi_host_get_param,
.set_host_param = iscsi_host_set_param,