diff --git a/iscsi-scst/kernel/isert-scst/iser.h b/iscsi-scst/kernel/isert-scst/iser.h index 8c1883c39..97f947940 100644 --- a/iscsi-scst/kernel/isert-scst/iser.h +++ b/iscsi-scst/kernel/isert-scst/iser.h @@ -104,6 +104,7 @@ struct isert_cq { }; #define ISERT_CONNECTION_ABORTED 0 +#define ISERT_DRAIN_POSTED 1 struct isert_connection { struct iscsi_conn iscsi ____cacheline_aligned; @@ -159,6 +160,7 @@ struct isert_connection { unsigned long flags; struct work_struct close_work; + struct isert_wr drain_wr; struct kref kref; void *priv_data; /* for connection tracking */ diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index a327e1400..8ead9081e 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -119,9 +119,24 @@ int isert_post_send(struct isert_connection *isert_conn, void isert_conn_disconnect(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)) { + 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); + isert_conn->drain_wr.send_wr.opcode = IB_WR_SEND; + err = ib_post_send(isert_conn->qp, &isert_conn->drain_wr.send_wr, &bad_wr); + if (unlikely(err)) { + pr_err("Failed to post drain wr, err:%d\n", err); + /* We need to decrement iser_conn->kref in order to be able to cleanup + * the connection */ + isert_conn_free(isert_conn); + } + } } static int isert_pdu_handle_hello_req(struct isert_cmnd *pdu) @@ -485,7 +500,10 @@ static void isert_handle_wc_error(struct ib_wc *wc) switch (wr->wr_op) { case ISER_WR_SEND: - isert_pdu_err(&isert_pdu->iscsi); + if (unlikely(wr->send_wr.num_sge == 0)) /* Drain WR */ + isert_conn_free(isert_conn); + else + isert_pdu_err(&isert_pdu->iscsi); break; case ISER_WR_RDMA_READ: isert_pdu_err(&isert_pdu->iscsi); @@ -1016,6 +1034,7 @@ static struct isert_connection *isert_conn_create(struct rdma_cm_id *cm_id, } kref_init(&isert_conn->kref); + kref_get(&isert_conn->kref); TRACE_EXIT(); return isert_conn;