diff --git a/iscsi-scst/kernel/isert-scst/iser.h b/iscsi-scst/kernel/isert-scst/iser.h index a2b4a00af..3f8113908 100644 --- a/iscsi-scst/kernel/isert-scst/iser.h +++ b/iscsi-scst/kernel/isert-scst/iser.h @@ -155,6 +155,7 @@ struct isert_cq { #define ISERT_CONNECTION_ABORTED 0 #define ISERT_DRAIN_POSTED 1 #define ISERT_DRAIN_FAILED 2 +#define ISERT_DISCON_CALLED 3 struct isert_connection { struct iscsi_conn iscsi ____cacheline_aligned; @@ -210,6 +211,7 @@ struct isert_connection { unsigned long flags; struct work_struct close_work; struct work_struct drain_work; + struct work_struct discon_work; struct isert_wr drain_wr; struct kref kref; @@ -280,6 +282,7 @@ int isert_alloc_conn_resources(struct isert_connection *isert_conn); void isert_free_conn_resources(struct isert_connection *isert_conn); void isert_conn_free(struct isert_connection *isert_conn); void isert_conn_disconnect(struct isert_connection *isert_conn); +void isert_post_drain(struct isert_connection *isert_conn); static inline struct isert_connection *isert_conn_alloc(void) { diff --git a/iscsi-scst/kernel/isert-scst/iser_datamover.c b/iscsi-scst/kernel/isert-scst/iser_datamover.c index 7d175241b..15c40713a 100644 --- a/iscsi-scst/kernel/isert-scst/iser_datamover.c +++ b/iscsi-scst/kernel/isert-scst/iser_datamover.c @@ -107,6 +107,7 @@ int isert_portal_remove(void *portal_h) void isert_free_connection(struct iscsi_conn *iscsi_conn) { struct isert_connection *isert_conn = (struct isert_connection *)iscsi_conn; + isert_post_drain(isert_conn); isert_conn_free(isert_conn); } diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index f56ef3286..2bfc53cd4 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -123,14 +123,12 @@ int isert_post_send(struct isert_connection *isert_conn, return err; } -void isert_conn_disconnect(struct isert_connection *isert_conn) +void isert_post_drain(struct isert_connection *isert_conn) { - struct ib_send_wr *bad_wr; - int err = rdma_disconnect(isert_conn->cm_id); - if (unlikely(err)) - pr_err("Failed to rdma disconnect, err:%d\n", err); - if (!test_and_set_bit(ISERT_DRAIN_POSTED, &isert_conn->flags)) { + struct ib_send_wr *bad_wr; + int err; + isert_wr_set_fields(&isert_conn->drain_wr, isert_conn, NULL); isert_conn->drain_wr.wr_op = ISER_WR_SEND; isert_conn->drain_wr.send_wr.wr_id = _ptr_to_u64(&isert_conn->drain_wr); @@ -146,6 +144,14 @@ void isert_conn_disconnect(struct isert_connection *isert_conn) } } +void isert_conn_disconnect(struct isert_connection *isert_conn) +{ + int err = rdma_disconnect(isert_conn->cm_id); + + if (unlikely(err)) + pr_err("Failed to rdma disconnect, err:%d\n", err); +} + static int isert_pdu_handle_hello_req(struct isert_cmnd *pdu) { pr_info("iSER Hello not supported\n"); @@ -498,6 +504,33 @@ static const char *wr_status_str(enum ib_wc_status status) } } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void isert_discon_do_work(void *ctx) +#else +static void isert_discon_do_work(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + struct isert_connection *isert_conn = ctx; +#else + struct isert_connection *isert_conn = + container_of(work, struct isert_connection, discon_work); +#endif + + /* notify upper layer */ + isert_connection_closed(&isert_conn->iscsi); +} + +static void isert_sched_discon(struct isert_connection *isert_conn) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&isert_conn->discon_work, isert_discon_do_work, isert_conn); +#else + INIT_WORK(&isert_conn->discon_work, isert_discon_do_work); +#endif + isert_conn_queue_work(&isert_conn->discon_work); +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void isert_conn_drained_do_work(void *ctx) #else @@ -511,10 +544,6 @@ static void isert_conn_drained_do_work(struct work_struct *work) container_of(work, struct isert_connection, drain_work); #endif - /* notify upper layer */ - if (!test_bit(ISERT_CONNECTION_ABORTED, &isert_conn->flags)) - isert_connection_closed(&isert_conn->iscsi); - isert_conn_free(isert_conn); } @@ -528,6 +557,38 @@ static void isert_sched_conn_drained(struct isert_connection *isert_conn) isert_conn_queue_work(&isert_conn->drain_work); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void isert_conn_closed_do_work(void *ctx) +#else +static void isert_conn_closed_do_work(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + struct isert_connection *isert_conn = ctx; +#else + struct isert_connection *isert_conn = + container_of(work, struct isert_connection, close_work); +#endif + + if (!test_bit(ISERT_CONNECTION_ABORTED, &isert_conn->flags)) + if (!test_and_set_bit(ISERT_DISCON_CALLED, &isert_conn->flags)) + isert_connection_closed(&isert_conn->iscsi); + + isert_conn_free(isert_conn); +} + +static void isert_sched_conn_closed(struct isert_connection *isert_conn) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&isert_conn->close_work, isert_conn_closed_do_work, + isert_conn); +#else + INIT_WORK(&isert_conn->close_work, isert_conn_closed_do_work); +#endif + isert_conn_queue_work(&isert_conn->close_work); +} + + static void isert_handle_wc_error(struct ib_wc *wc) { struct isert_wr *wr = _u64_to_ptr(wc->wr_id); @@ -544,6 +605,10 @@ static void isert_handle_wc_error(struct ib_wc *wc) isert_conn, wr, wr_status_str(wc->status), wc->vendor_err); + if (!test_bit(ISERT_CONNECTION_ABORTED, &isert_conn->flags)) + if (!test_and_set_bit(ISERT_DISCON_CALLED, &isert_conn->flags)) + isert_sched_discon(isert_conn); + switch (wr->wr_op) { case ISER_WR_SEND: if (unlikely(wr->send_wr.num_sge == 0)) /* Drain WR */ @@ -1204,36 +1269,6 @@ void isert_conn_free(struct isert_connection *isert_conn) kref_put(&isert_conn->kref, isert_kref_free); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -static void isert_conn_closed_do_work(void *ctx) -#else -static void isert_conn_closed_do_work(struct work_struct *work) -#endif -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) - struct isert_connection *isert_conn = ctx; -#else - struct isert_connection *isert_conn = - container_of(work, struct isert_connection, close_work); -#endif - - /* notify upper layer */ - if (test_bit(ISERT_DRAIN_FAILED, &isert_conn->flags)) - isert_connection_closed(&isert_conn->iscsi); - - isert_conn_free(isert_conn); -} - -static void isert_sched_conn_closed(struct isert_connection *isert_conn) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) - INIT_WORK(&isert_conn->close_work, isert_conn_closed_do_work, isert_conn); -#else - INIT_WORK(&isert_conn->close_work, isert_conn_closed_do_work); -#endif - isert_conn_queue_work(&isert_conn->close_work); -} - static int isert_cm_timewait_exit_handler(struct rdma_cm_id *cm_id, struct rdma_cm_event *event) { @@ -1395,6 +1430,7 @@ static int isert_cm_connect_handler(struct rdma_cm_id *cm_id, isert_conn->peer_addrsz); if (unlikely(ret)) { set_bit(ISERT_CONNECTION_ABORTED, &isert_conn->flags); + isert_post_drain(isert_conn); isert_conn_free(isert_conn); goto out; }