diff options
Diffstat (limited to 'drivers/infiniband/ulp/iser/iscsi_iser.c')
-rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.c | 105 |
1 files changed, 61 insertions, 44 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 25f195ef44b0..eb7973957a6e 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c | |||
@@ -99,6 +99,7 @@ MODULE_PARM_DESC(pi_enable, "Enable T10-PI offload support (default:disabled)"); | |||
99 | module_param_named(pi_guard, iser_pi_guard, int, 0644); | 99 | module_param_named(pi_guard, iser_pi_guard, int, 0644); |
100 | MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)"); | 100 | MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)"); |
101 | 101 | ||
102 | static struct workqueue_struct *release_wq; | ||
102 | struct iser_global ig; | 103 | struct iser_global ig; |
103 | 104 | ||
104 | void | 105 | void |
@@ -337,24 +338,6 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
337 | return cls_conn; | 338 | return cls_conn; |
338 | } | 339 | } |
339 | 340 | ||
340 | static void | ||
341 | iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn) | ||
342 | { | ||
343 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
344 | struct iser_conn *ib_conn = conn->dd_data; | ||
345 | |||
346 | iscsi_conn_teardown(cls_conn); | ||
347 | /* | ||
348 | * Userspace will normally call the stop callback and | ||
349 | * already have freed the ib_conn, but if it goofed up then | ||
350 | * we free it here. | ||
351 | */ | ||
352 | if (ib_conn) { | ||
353 | ib_conn->iscsi_conn = NULL; | ||
354 | iser_conn_put(ib_conn, 1); /* deref iscsi/ib conn unbinding */ | ||
355 | } | ||
356 | } | ||
357 | |||
358 | static int | 341 | static int |
359 | iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, | 342 | iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, |
360 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, | 343 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, |
@@ -392,29 +375,39 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, | |||
392 | conn->dd_data = ib_conn; | 375 | conn->dd_data = ib_conn; |
393 | ib_conn->iscsi_conn = conn; | 376 | ib_conn->iscsi_conn = conn; |
394 | 377 | ||
395 | iser_conn_get(ib_conn); /* ref iscsi/ib conn binding */ | ||
396 | return 0; | 378 | return 0; |
397 | } | 379 | } |
398 | 380 | ||
381 | static int | ||
382 | iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) | ||
383 | { | ||
384 | struct iscsi_conn *iscsi_conn; | ||
385 | struct iser_conn *ib_conn; | ||
386 | |||
387 | iscsi_conn = cls_conn->dd_data; | ||
388 | ib_conn = iscsi_conn->dd_data; | ||
389 | reinit_completion(&ib_conn->stop_completion); | ||
390 | |||
391 | return iscsi_conn_start(cls_conn); | ||
392 | } | ||
393 | |||
399 | static void | 394 | static void |
400 | iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 395 | iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
401 | { | 396 | { |
402 | struct iscsi_conn *conn = cls_conn->dd_data; | 397 | struct iscsi_conn *conn = cls_conn->dd_data; |
403 | struct iser_conn *ib_conn = conn->dd_data; | 398 | struct iser_conn *ib_conn = conn->dd_data; |
404 | 399 | ||
400 | iser_dbg("stopping iscsi_conn: %p, ib_conn: %p\n", conn, ib_conn); | ||
401 | iscsi_conn_stop(cls_conn, flag); | ||
402 | |||
405 | /* | 403 | /* |
406 | * Userspace may have goofed up and not bound the connection or | 404 | * Userspace may have goofed up and not bound the connection or |
407 | * might have only partially setup the connection. | 405 | * might have only partially setup the connection. |
408 | */ | 406 | */ |
409 | if (ib_conn) { | 407 | if (ib_conn) { |
410 | iscsi_conn_stop(cls_conn, flag); | 408 | conn->dd_data = NULL; |
411 | /* | 409 | complete(&ib_conn->stop_completion); |
412 | * There is no unbind event so the stop callback | ||
413 | * must release the ref from the bind. | ||
414 | */ | ||
415 | iser_conn_put(ib_conn, 1); /* deref iscsi/ib conn unbinding */ | ||
416 | } | 410 | } |
417 | conn->dd_data = NULL; | ||
418 | } | 411 | } |
419 | 412 | ||
420 | static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) | 413 | static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) |
@@ -515,28 +508,28 @@ iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn, | |||
515 | case ISCSI_PARAM_HDRDGST_EN: | 508 | case ISCSI_PARAM_HDRDGST_EN: |
516 | sscanf(buf, "%d", &value); | 509 | sscanf(buf, "%d", &value); |
517 | if (value) { | 510 | if (value) { |
518 | iser_err("DataDigest wasn't negotiated to None"); | 511 | iser_err("DataDigest wasn't negotiated to None\n"); |
519 | return -EPROTO; | 512 | return -EPROTO; |
520 | } | 513 | } |
521 | break; | 514 | break; |
522 | case ISCSI_PARAM_DATADGST_EN: | 515 | case ISCSI_PARAM_DATADGST_EN: |
523 | sscanf(buf, "%d", &value); | 516 | sscanf(buf, "%d", &value); |
524 | if (value) { | 517 | if (value) { |
525 | iser_err("DataDigest wasn't negotiated to None"); | 518 | iser_err("DataDigest wasn't negotiated to None\n"); |
526 | return -EPROTO; | 519 | return -EPROTO; |
527 | } | 520 | } |
528 | break; | 521 | break; |
529 | case ISCSI_PARAM_IFMARKER_EN: | 522 | case ISCSI_PARAM_IFMARKER_EN: |
530 | sscanf(buf, "%d", &value); | 523 | sscanf(buf, "%d", &value); |
531 | if (value) { | 524 | if (value) { |
532 | iser_err("IFMarker wasn't negotiated to No"); | 525 | iser_err("IFMarker wasn't negotiated to No\n"); |
533 | return -EPROTO; | 526 | return -EPROTO; |
534 | } | 527 | } |
535 | break; | 528 | break; |
536 | case ISCSI_PARAM_OFMARKER_EN: | 529 | case ISCSI_PARAM_OFMARKER_EN: |
537 | sscanf(buf, "%d", &value); | 530 | sscanf(buf, "%d", &value); |
538 | if (value) { | 531 | if (value) { |
539 | iser_err("OFMarker wasn't negotiated to No"); | 532 | iser_err("OFMarker wasn't negotiated to No\n"); |
540 | return -EPROTO; | 533 | return -EPROTO; |
541 | } | 534 | } |
542 | break; | 535 | break; |
@@ -652,19 +645,20 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) | |||
652 | struct iser_conn *ib_conn; | 645 | struct iser_conn *ib_conn; |
653 | 646 | ||
654 | ib_conn = ep->dd_data; | 647 | ib_conn = ep->dd_data; |
655 | if (ib_conn->iscsi_conn) | 648 | iser_info("ep %p ib conn %p state %d\n", ep, ib_conn, ib_conn->state); |
656 | /* | ||
657 | * Must suspend xmit path if the ep is bound to the | ||
658 | * iscsi_conn, so we know we are not accessing the ib_conn | ||
659 | * when we free it. | ||
660 | * | ||
661 | * This may not be bound if the ep poll failed. | ||
662 | */ | ||
663 | iscsi_suspend_tx(ib_conn->iscsi_conn); | ||
664 | |||
665 | |||
666 | iser_info("ib conn %p state %d\n", ib_conn, ib_conn->state); | ||
667 | iser_conn_terminate(ib_conn); | 649 | iser_conn_terminate(ib_conn); |
650 | |||
651 | /* | ||
652 | * if iser_conn and iscsi_conn are bound, we must wait iscsi_conn_stop | ||
653 | * call and ISER_CONN_DOWN state before freeing the iser resources. | ||
654 | * otherwise we are safe to free resources immediately. | ||
655 | */ | ||
656 | if (ib_conn->iscsi_conn) { | ||
657 | INIT_WORK(&ib_conn->release_work, iser_release_work); | ||
658 | queue_work(release_wq, &ib_conn->release_work); | ||
659 | } else { | ||
660 | iser_conn_release(ib_conn); | ||
661 | } | ||
668 | } | 662 | } |
669 | 663 | ||
670 | static umode_t iser_attr_is_visible(int param_type, int param) | 664 | static umode_t iser_attr_is_visible(int param_type, int param) |
@@ -748,13 +742,13 @@ static struct iscsi_transport iscsi_iser_transport = { | |||
748 | /* connection management */ | 742 | /* connection management */ |
749 | .create_conn = iscsi_iser_conn_create, | 743 | .create_conn = iscsi_iser_conn_create, |
750 | .bind_conn = iscsi_iser_conn_bind, | 744 | .bind_conn = iscsi_iser_conn_bind, |
751 | .destroy_conn = iscsi_iser_conn_destroy, | 745 | .destroy_conn = iscsi_conn_teardown, |
752 | .attr_is_visible = iser_attr_is_visible, | 746 | .attr_is_visible = iser_attr_is_visible, |
753 | .set_param = iscsi_iser_set_param, | 747 | .set_param = iscsi_iser_set_param, |
754 | .get_conn_param = iscsi_conn_get_param, | 748 | .get_conn_param = iscsi_conn_get_param, |
755 | .get_ep_param = iscsi_iser_get_ep_param, | 749 | .get_ep_param = iscsi_iser_get_ep_param, |
756 | .get_session_param = iscsi_session_get_param, | 750 | .get_session_param = iscsi_session_get_param, |
757 | .start_conn = iscsi_conn_start, | 751 | .start_conn = iscsi_iser_conn_start, |
758 | .stop_conn = iscsi_iser_conn_stop, | 752 | .stop_conn = iscsi_iser_conn_stop, |
759 | /* iscsi host params */ | 753 | /* iscsi host params */ |
760 | .get_host_param = iscsi_host_get_param, | 754 | .get_host_param = iscsi_host_get_param, |
@@ -801,6 +795,12 @@ static int __init iser_init(void) | |||
801 | mutex_init(&ig.connlist_mutex); | 795 | mutex_init(&ig.connlist_mutex); |
802 | INIT_LIST_HEAD(&ig.connlist); | 796 | INIT_LIST_HEAD(&ig.connlist); |
803 | 797 | ||
798 | release_wq = alloc_workqueue("release workqueue", 0, 0); | ||
799 | if (!release_wq) { | ||
800 | iser_err("failed to allocate release workqueue\n"); | ||
801 | return -ENOMEM; | ||
802 | } | ||
803 | |||
804 | iscsi_iser_scsi_transport = iscsi_register_transport( | 804 | iscsi_iser_scsi_transport = iscsi_register_transport( |
805 | &iscsi_iser_transport); | 805 | &iscsi_iser_transport); |
806 | if (!iscsi_iser_scsi_transport) { | 806 | if (!iscsi_iser_scsi_transport) { |
@@ -819,7 +819,24 @@ register_transport_failure: | |||
819 | 819 | ||
820 | static void __exit iser_exit(void) | 820 | static void __exit iser_exit(void) |
821 | { | 821 | { |
822 | struct iser_conn *ib_conn, *n; | ||
823 | int connlist_empty; | ||
824 | |||
822 | iser_dbg("Removing iSER datamover...\n"); | 825 | iser_dbg("Removing iSER datamover...\n"); |
826 | destroy_workqueue(release_wq); | ||
827 | |||
828 | mutex_lock(&ig.connlist_mutex); | ||
829 | connlist_empty = list_empty(&ig.connlist); | ||
830 | mutex_unlock(&ig.connlist_mutex); | ||
831 | |||
832 | if (!connlist_empty) { | ||
833 | iser_err("Error cleanup stage completed but we still have iser " | ||
834 | "connections, destroying them anyway.\n"); | ||
835 | list_for_each_entry_safe(ib_conn, n, &ig.connlist, conn_list) { | ||
836 | iser_conn_release(ib_conn); | ||
837 | } | ||
838 | } | ||
839 | |||
823 | iscsi_unregister_transport(&iscsi_iser_transport); | 840 | iscsi_unregister_transport(&iscsi_iser_transport); |
824 | kmem_cache_destroy(ig.desc_cache); | 841 | kmem_cache_destroy(ig.desc_cache); |
825 | } | 842 | } |