Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / infiniband / ulp / isert / ib_isert.c
index 8a51c3b..b0edb66 100644 (file)
@@ -66,6 +66,7 @@ isert_rdma_accept(struct isert_conn *isert_conn);
 struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np);
 
 static void isert_release_work(struct work_struct *work);
+static void isert_wait4flush(struct isert_conn *isert_conn);
 
 static inline bool
 isert_prot_cmd(struct isert_conn *conn, struct se_cmd *cmd)
@@ -815,12 +816,31 @@ isert_put_conn(struct isert_conn *isert_conn)
        kref_put(&isert_conn->kref, isert_release_kref);
 }
 
+static void
+isert_handle_unbound_conn(struct isert_conn *isert_conn)
+{
+       struct isert_np *isert_np = isert_conn->cm_id->context;
+
+       mutex_lock(&isert_np->mutex);
+       if (!list_empty(&isert_conn->node)) {
+               /*
+                * This means iscsi doesn't know this connection
+                * so schedule a cleanup ourselves
+                */
+               list_del_init(&isert_conn->node);
+               isert_put_conn(isert_conn);
+               complete(&isert_conn->wait);
+               queue_work(isert_release_wq, &isert_conn->release_work);
+       }
+       mutex_unlock(&isert_np->mutex);
+}
+
 /**
  * isert_conn_terminate() - Initiate connection termination
  * @isert_conn: isert connection struct
  *
  * Notes:
- * In case the connection state is FULL_FEATURE, move state
+ * In case the connection state is BOUND, move state
  * to TEMINATING and start teardown sequence (rdma_disconnect).
  * In case the connection state is UP, complete flush as well.
  *
@@ -832,23 +852,19 @@ isert_conn_terminate(struct isert_conn *isert_conn)
 {
        int err;
 
-       switch (isert_conn->state) {
-       case ISER_CONN_TERMINATING:
-               break;
-       case ISER_CONN_UP:
-       case ISER_CONN_FULL_FEATURE: /* FALLTHRU */
-               isert_info("Terminating conn %p state %d\n",
-                          isert_conn, isert_conn->state);
-               isert_conn->state = ISER_CONN_TERMINATING;
-               err = rdma_disconnect(isert_conn->cm_id);
-               if (err)
-                       isert_warn("Failed rdma_disconnect isert_conn %p\n",
-                                  isert_conn);
-               break;
-       default:
-               isert_warn("conn %p teminating in state %d\n",
-                          isert_conn, isert_conn->state);
-       }
+       if (isert_conn->state >= ISER_CONN_TERMINATING)
+               return;
+
+       isert_info("Terminating conn %p state %d\n",
+                  isert_conn, isert_conn->state);
+       isert_conn->state = ISER_CONN_TERMINATING;
+       err = rdma_disconnect(isert_conn->cm_id);
+       if (err)
+               isert_warn("Failed rdma_disconnect isert_conn %p\n",
+                          isert_conn);
+
+       isert_info("conn %p completing wait\n", isert_conn);
+       complete(&isert_conn->wait);
 }
 
 static int
@@ -882,35 +898,27 @@ static int
 isert_disconnected_handler(struct rdma_cm_id *cma_id,
                           enum rdma_cm_event_type event)
 {
-       struct isert_np *isert_np = cma_id->context;
-       struct isert_conn *isert_conn;
-       bool terminating = false;
-
-       if (isert_np->cm_id == cma_id)
-               return isert_np_cma_handler(cma_id->context, event);
-
-       isert_conn = cma_id->qp->qp_context;
+       struct isert_conn *isert_conn = cma_id->qp->qp_context;
 
        mutex_lock(&isert_conn->mutex);
-       terminating = (isert_conn->state == ISER_CONN_TERMINATING);
-       isert_conn_terminate(isert_conn);
-       mutex_unlock(&isert_conn->mutex);
-
-       isert_info("conn %p completing wait\n", isert_conn);
-       complete(&isert_conn->wait);
-
-       if (terminating)
-               goto out;
-
-       mutex_lock(&isert_np->mutex);
-       if (!list_empty(&isert_conn->node)) {
-               list_del_init(&isert_conn->node);
-               isert_put_conn(isert_conn);
-               queue_work(isert_release_wq, &isert_conn->release_work);
+       switch (isert_conn->state) {
+       case ISER_CONN_TERMINATING:
+               break;
+       case ISER_CONN_UP:
+               isert_conn_terminate(isert_conn);
+               isert_wait4flush(isert_conn);
+               isert_handle_unbound_conn(isert_conn);
+               break;
+       case ISER_CONN_BOUND:
+       case ISER_CONN_FULL_FEATURE: /* FALLTHRU */
+               iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+               break;
+       default:
+               isert_warn("conn %p teminating in state %d\n",
+                          isert_conn, isert_conn->state);
        }
-       mutex_unlock(&isert_np->mutex);
+       mutex_unlock(&isert_conn->mutex);
 
-out:
        return 0;
 }
 
@@ -929,12 +937,16 @@ isert_connect_error(struct rdma_cm_id *cma_id)
 static int
 isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 {
+       struct isert_np *isert_np = cma_id->context;
        int ret = 0;
 
        isert_info("%s (%d): status %d id %p np %p\n",
                   rdma_event_msg(event->event), event->event,
                   event->status, cma_id, cma_id->context);
 
+       if (isert_np->cm_id == cma_id)
+               return isert_np_cma_handler(cma_id->context, event->event);
+
        switch (event->event) {
        case RDMA_CM_EVENT_CONNECT_REQUEST:
                ret = isert_connect_request(cma_id, event);
@@ -980,13 +992,10 @@ isert_post_recvm(struct isert_conn *isert_conn, u32 count)
        rx_wr--;
        rx_wr->next = NULL; /* mark end of work requests list */
 
-       isert_conn->post_recv_buf_count += count;
        ret = ib_post_recv(isert_conn->qp, isert_conn->rx_wr,
                           &rx_wr_failed);
-       if (ret) {
+       if (ret)
                isert_err("ib_post_recv() failed with ret: %d\n", ret);
-               isert_conn->post_recv_buf_count -= count;
-       }
 
        return ret;
 }
@@ -1002,12 +1011,9 @@ isert_post_recv(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc)
        rx_wr.num_sge = 1;
        rx_wr.next = NULL;
 
-       isert_conn->post_recv_buf_count++;
        ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_failed);
-       if (ret) {
+       if (ret)
                isert_err("ib_post_recv() failed with ret: %d\n", ret);
-               isert_conn->post_recv_buf_count--;
-       }
 
        return ret;
 }
@@ -1120,12 +1126,9 @@ isert_rdma_post_recvl(struct isert_conn *isert_conn)
        rx_wr.sg_list = &sge;
        rx_wr.num_sge = 1;
 
-       isert_conn->post_recv_buf_count++;
        ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_fail);
-       if (ret) {
+       if (ret)
                isert_err("ib_post_recv() failed: %d\n", ret);
-               isert_conn->post_recv_buf_count--;
-       }
 
        return ret;
 }
@@ -1620,7 +1623,6 @@ isert_rcv_completion(struct iser_rx_desc *desc,
        ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen,
                                      DMA_FROM_DEVICE);
 
-       isert_conn->post_recv_buf_count--;
 }
 
 static int
@@ -2035,7 +2037,8 @@ is_isert_tx_desc(struct isert_conn *isert_conn, void *wr_id)
        void *start = isert_conn->rx_descs;
        int len = ISERT_QP_MAX_RECV_DTOS * sizeof(*isert_conn->rx_descs);
 
-       if (wr_id >= start && wr_id < start + len)
+       if ((wr_id >= start && wr_id < start + len) ||
+           (wr_id == isert_conn->login_req_buf))
                return false;
 
        return true;
@@ -2059,10 +2062,6 @@ isert_cq_comp_err(struct isert_conn *isert_conn, struct ib_wc *wc)
                        isert_unmap_tx_desc(desc, ib_dev);
                else
                        isert_completion_put(desc, isert_cmd, ib_dev, true);
-       } else {
-               isert_conn->post_recv_buf_count--;
-               if (!isert_conn->post_recv_buf_count)
-                       iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
        }
 }
 
@@ -3193,6 +3192,7 @@ accept_wait:
 
        conn->context = isert_conn;
        isert_conn->conn = conn;
+       isert_conn->state = ISER_CONN_BOUND;
 
        isert_set_conn_info(np, conn, isert_conn);