aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c42
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h5
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c14
-rw-r--r--drivers/scsi/libiscsi.c3
4 files changed, 59 insertions, 5 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)
305{ 305{
306 struct iscsi_conn *conn = cls_conn->dd_data; 306 struct iscsi_conn *conn = cls_conn->dd_data;
307 struct iscsi_iser_conn *iser_conn = conn->dd_data; 307 struct iscsi_iser_conn *iser_conn = conn->dd_data;
308 struct iser_conn *ib_conn = iser_conn->ib_conn;
308 309
309 if (iser_conn->ib_conn)
310 iser_conn->ib_conn->iser_conn = NULL;
311 iscsi_conn_teardown(cls_conn); 310 iscsi_conn_teardown(cls_conn);
311 /*
312 * Userspace will normally call the stop callback and
313 * already have freed the ib_conn, but if it goofed up then
314 * we free it here.
315 */
316 if (ib_conn) {
317 ib_conn->iser_conn = NULL;
318 iser_conn_put(ib_conn);
319 }
312} 320}
313 321
314static int 322static int
@@ -340,12 +348,29 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
340 iser_conn = conn->dd_data; 348 iser_conn = conn->dd_data;
341 ib_conn->iser_conn = iser_conn; 349 ib_conn->iser_conn = iser_conn;
342 iser_conn->ib_conn = ib_conn; 350 iser_conn->ib_conn = ib_conn;
351 iser_conn_get(ib_conn);
343 352
344 conn->recv_lock = &iser_conn->lock; 353 conn->recv_lock = &iser_conn->lock;
345 354
346 return 0; 355 return 0;
347} 356}
348 357
358static void
359iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
360{
361 struct iscsi_conn *conn = cls_conn->dd_data;
362 struct iscsi_iser_conn *iser_conn = conn->dd_data;
363 struct iser_conn *ib_conn = iser_conn->ib_conn;
364
365 iscsi_conn_stop(cls_conn, flag);
366 /*
367 * There is no unbind event so the stop callback
368 * must release the ref from the bind.
369 */
370 iser_conn_put(ib_conn);
371 iser_conn->ib_conn = NULL;
372}
373
349static int 374static int
350iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) 375iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
351{ 376{
@@ -564,6 +589,17 @@ iscsi_iser_ep_disconnect(__u64 ep_handle)
564 if (!ib_conn) 589 if (!ib_conn)
565 return; 590 return;
566 591
592 if (ib_conn->iser_conn)
593 /*
594 * Must suspend xmit path if the ep is bound to the
595 * iscsi_conn, so we know we are not accessing the ib_conn
596 * when we free it.
597 *
598 * This may not be bound if the ep poll failed.
599 */
600 iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
601
602
567 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state); 603 iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
568 iser_conn_terminate(ib_conn); 604 iser_conn_terminate(ib_conn);
569} 605}
@@ -622,7 +658,7 @@ static struct iscsi_transport iscsi_iser_transport = {
622 .get_conn_param = iscsi_conn_get_param, 658 .get_conn_param = iscsi_conn_get_param,
623 .get_session_param = iscsi_session_get_param, 659 .get_session_param = iscsi_session_get_param,
624 .start_conn = iscsi_iser_conn_start, 660 .start_conn = iscsi_iser_conn_start,
625 .stop_conn = iscsi_conn_stop, 661 .stop_conn = iscsi_iser_conn_stop,
626 /* iscsi host params */ 662 /* iscsi host params */
627 .get_host_param = iscsi_host_get_param, 663 .get_host_param = iscsi_host_get_param,
628 .set_host_param = iscsi_host_set_param, 664 .set_host_param = iscsi_host_set_param,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 66a2f30ada01..bd5c1a554ea6 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -242,6 +242,7 @@ struct iser_device {
242struct iser_conn { 242struct iser_conn {
243 struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */ 243 struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */
244 enum iser_ib_conn_state state; /* rdma connection state */ 244 enum iser_ib_conn_state state; /* rdma connection state */
245 atomic_t refcount;
245 spinlock_t lock; /* used for state changes */ 246 spinlock_t lock; /* used for state changes */
246 struct iser_device *device; /* device context */ 247 struct iser_device *device; /* device context */
247 struct rdma_cm_id *cma_id; /* CMA ID */ 248 struct rdma_cm_id *cma_id; /* CMA ID */
@@ -314,6 +315,10 @@ void iscsi_iser_recv(struct iscsi_conn *conn,
314 315
315int iser_conn_init(struct iser_conn **ib_conn); 316int iser_conn_init(struct iser_conn **ib_conn);
316 317
318void iser_conn_get(struct iser_conn *ib_conn);
319
320void iser_conn_put(struct iser_conn *ib_conn);
321
317void iser_conn_terminate(struct iser_conn *ib_conn); 322void iser_conn_terminate(struct iser_conn *ib_conn);
318 323
319void iser_rcv_completion(struct iser_desc *desc, 324void iser_rcv_completion(struct iser_desc *desc,
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index d19cfe605ebb..5daed2bd710e 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -328,6 +328,17 @@ static void iser_conn_release(struct iser_conn *ib_conn)
328 kfree(ib_conn); 328 kfree(ib_conn);
329} 329}
330 330
331void iser_conn_get(struct iser_conn *ib_conn)
332{
333 atomic_inc(&ib_conn->refcount);
334}
335
336void iser_conn_put(struct iser_conn *ib_conn)
337{
338 if (atomic_dec_and_test(&ib_conn->refcount))
339 iser_conn_release(ib_conn);
340}
341
331/** 342/**
332 * triggers start of the disconnect procedures and wait for them to be done 343 * triggers start of the disconnect procedures and wait for them to be done
333 */ 344 */
@@ -349,7 +360,7 @@ void iser_conn_terminate(struct iser_conn *ib_conn)
349 wait_event_interruptible(ib_conn->wait, 360 wait_event_interruptible(ib_conn->wait,
350 ib_conn->state == ISER_CONN_DOWN); 361 ib_conn->state == ISER_CONN_DOWN);
351 362
352 iser_conn_release(ib_conn); 363 iser_conn_put(ib_conn);
353} 364}
354 365
355static void iser_connect_error(struct rdma_cm_id *cma_id) 366static void iser_connect_error(struct rdma_cm_id *cma_id)
@@ -496,6 +507,7 @@ int iser_conn_init(struct iser_conn **ibconn)
496 init_waitqueue_head(&ib_conn->wait); 507 init_waitqueue_head(&ib_conn->wait);
497 atomic_set(&ib_conn->post_recv_buf_count, 0); 508 atomic_set(&ib_conn->post_recv_buf_count, 0);
498 atomic_set(&ib_conn->post_send_buf_count, 0); 509 atomic_set(&ib_conn->post_send_buf_count, 0);
510 atomic_set(&ib_conn->refcount, 1);
499 INIT_LIST_HEAD(&ib_conn->conn_list); 511 INIT_LIST_HEAD(&ib_conn->conn_list);
500 spin_lock_init(&ib_conn->lock); 512 spin_lock_init(&ib_conn->lock);
501 513
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 784a935fad4a..79bc49fd7f12 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1383,11 +1383,12 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
1383 } 1383 }
1384} 1384}
1385 1385
1386static void iscsi_suspend_tx(struct iscsi_conn *conn) 1386void iscsi_suspend_tx(struct iscsi_conn *conn)
1387{ 1387{
1388 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 1388 set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
1389 scsi_flush_work(conn->session->host); 1389 scsi_flush_work(conn->session->host);
1390} 1390}
1391EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
1391 1392
1392static void iscsi_start_tx(struct iscsi_conn *conn) 1393static void iscsi_start_tx(struct iscsi_conn *conn)
1393{ 1394{