RDMA/nes: Allocate work item for disconnect event handling

The code currently has a work structure in the QP.  This requires a
lock and a pending flag to ensure there is never more than one request
active.  When two events happen quickly (such as FIN and LLP CLOSE),
it causes unnecessary timeouts since the second one is dropped.

This fix allocates memory for the work request so the second one can
be queued.  A lock is removed since it is no longer needed.

Signed-off-by: Don Wood <donald.e.wood@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index fe08eb5..d89bdee 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -2450,20 +2450,16 @@
  */
 int nes_cm_disconn(struct nes_qp *nesqp)
 {
-	unsigned long flags;
+	struct disconn_work *work;
 
-	spin_lock_irqsave(&nesqp->lock, flags);
-	if (nesqp->disconn_pending == 0) {
-		nesqp->disconn_pending++;
-		spin_unlock_irqrestore(&nesqp->lock, flags);
-		nes_add_ref(&nesqp->ibqp);
-		/* init our disconnect work element, to */
-		INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker);
+	work = kzalloc(sizeof *work, GFP_ATOMIC);
+	if (!work)
+		return -ENOMEM; /* Timer will clean up */
 
-		queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work);
-	} else
-		spin_unlock_irqrestore(&nesqp->lock, flags);
-
+	nes_add_ref(&nesqp->ibqp);
+	work->nesqp = nesqp;
+	INIT_WORK(&work->work, nes_disconnect_worker);
+	queue_work(g_cm_core->disconn_wq, &work->work);
 	return 0;
 }
 
@@ -2473,8 +2469,10 @@
  */
 static void nes_disconnect_worker(struct work_struct *work)
 {
-	struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work);
+	struct disconn_work *dwork = container_of(work, struct disconn_work, work);
+	struct nes_qp *nesqp = dwork->nesqp;
 
+	kfree(dwork);
 	nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",
 			nesqp->last_aeq, nesqp->hwqp.qp_id);
 	nes_cm_disconn_true(nesqp);
@@ -2557,7 +2555,6 @@
 			spin_lock_irqsave(&nesqp->lock, flags);
 		}
 
-		nesqp->disconn_pending = 0;
 		/* There might have been another AE while the lock was released */
 		original_hw_tcp_state = nesqp->hw_tcp_state;
 		original_ibqp_state   = nesqp->ibqp_state;
@@ -2610,7 +2607,6 @@
 			}
 		}
 	} else {
-		nesqp->disconn_pending = 0;
 		spin_unlock_irqrestore(&nesqp->lock, flags);
 	}