diff options
-rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.c | 42 | ||||
-rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.h | 5 | ||||
-rw-r--r-- | drivers/infiniband/ulp/iser/iser_verbs.c | 14 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 3 |
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 | ||
314 | static int | 322 | static 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 | ||
358 | static void | ||
359 | iscsi_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 | |||
349 | static int | 374 | static int |
350 | iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) | 375 | iscsi_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 { | |||
242 | struct iser_conn { | 242 | struct 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 | ||
315 | int iser_conn_init(struct iser_conn **ib_conn); | 316 | int iser_conn_init(struct iser_conn **ib_conn); |
316 | 317 | ||
318 | void iser_conn_get(struct iser_conn *ib_conn); | ||
319 | |||
320 | void iser_conn_put(struct iser_conn *ib_conn); | ||
321 | |||
317 | void iser_conn_terminate(struct iser_conn *ib_conn); | 322 | void iser_conn_terminate(struct iser_conn *ib_conn); |
318 | 323 | ||
319 | void iser_rcv_completion(struct iser_desc *desc, | 324 | void 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 | ||
331 | void iser_conn_get(struct iser_conn *ib_conn) | ||
332 | { | ||
333 | atomic_inc(&ib_conn->refcount); | ||
334 | } | ||
335 | |||
336 | void 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 | ||
355 | static void iser_connect_error(struct rdma_cm_id *cma_id) | 366 | static 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 | ||
1386 | static void iscsi_suspend_tx(struct iscsi_conn *conn) | 1386 | void 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 | } |
1391 | EXPORT_SYMBOL_GPL(iscsi_suspend_tx); | ||
1391 | 1392 | ||
1392 | static void iscsi_start_tx(struct iscsi_conn *conn) | 1393 | static void iscsi_start_tx(struct iscsi_conn *conn) |
1393 | { | 1394 | { |