diff options
Diffstat (limited to 'drivers/infiniband/hw/nes/nes_cm.c')
| -rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.c | 128 | 
1 files changed, 64 insertions, 64 deletions
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 114b802771a..73473db1986 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2450,19 +2450,16 @@ static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_nod   */  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); -		/* init our disconnect work element, to */ -		INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); - -		queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); -	} else -		spin_unlock_irqrestore(&nesqp->lock, flags); +	work = kzalloc(sizeof *work, GFP_ATOMIC); +	if (!work) +		return -ENOMEM; /* Timer will clean up */ +	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;  } @@ -2472,11 +2469,14 @@ int nes_cm_disconn(struct nes_qp *nesqp)   */  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); +	nes_rem_ref(&nesqp->ibqp);  } @@ -2493,7 +2493,12 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  	u16 last_ae;  	u8 original_hw_tcp_state;  	u8 original_ibqp_state; -	u8 issued_disconnect_reset = 0; +	enum iw_cm_event_type disconn_status = IW_CM_EVENT_STATUS_OK; +	int issue_disconn = 0; +	int issue_close = 0; +	int issue_flush = 0; +	u32 flush_q = NES_CQP_FLUSH_RQ; +	struct ib_event ibevent;  	if (!nesqp) {  		nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n"); @@ -2517,24 +2522,55 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  	original_ibqp_state   = nesqp->ibqp_state;  	last_ae = nesqp->last_aeq; +	if (nesqp->term_flags) { +		issue_disconn = 1; +		issue_close = 1; +		nesqp->cm_id = NULL; +		if (nesqp->flush_issued == 0) { +			nesqp->flush_issued = 1; +			issue_flush = 1; +		} +	} else if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || +			((original_ibqp_state == IB_QPS_RTS) && +			(last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { +		issue_disconn = 1; +		if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) +			disconn_status = IW_CM_EVENT_STATUS_RESET; +	} + +	if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || +		 (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) || +		 (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) || +		 (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { +		issue_close = 1; +		nesqp->cm_id = NULL; +		if (nesqp->flush_issued == 0) { +			nesqp->flush_issued = 1; +			issue_flush = 1; +		} +	} + +	spin_unlock_irqrestore(&nesqp->lock, flags); -	nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state); +	if ((issue_flush) && (nesqp->destroyed == 0)) { +		/* Flush the queue(s) */ +		if (nesqp->hw_iwarp_state >= NES_AEQE_IWARP_STATE_TERMINATE) +			flush_q |= NES_CQP_FLUSH_SQ; +		flush_wqes(nesvnic->nesdev, nesqp, flush_q, 1); -	if ((nesqp->cm_id) && (cm_id->event_handler)) { -		if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || -				((original_ibqp_state == IB_QPS_RTS) && -				(last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { +		if (nesqp->term_flags) { +			ibevent.device = nesqp->ibqp.device; +			ibevent.event = nesqp->terminate_eventtype; +			ibevent.element.qp = &nesqp->ibqp; +			nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); +		} +	} + +	if ((cm_id) && (cm_id->event_handler)) { +		if (issue_disconn) {  			atomic_inc(&cm_disconnects);  			cm_event.event = IW_CM_EVENT_DISCONNECT; -			if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { -				cm_event.status = IW_CM_EVENT_STATUS_RESET; -				nes_debug(NES_DBG_CM, "Generating a CM " -					"Disconnect Event (status reset) for " -					"QP%u, cm_id = %p. \n", -					nesqp->hwqp.qp_id, cm_id); -			} else -				cm_event.status = IW_CM_EVENT_STATUS_OK; - +			cm_event.status = disconn_status;  			cm_event.local_addr = cm_id->local_addr;  			cm_event.remote_addr = cm_id->remote_addr;  			cm_event.private_data = NULL; @@ -2547,29 +2583,14 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  				nesqp->hwqp.sq_tail, cm_id,  				atomic_read(&nesqp->refcount)); -			spin_unlock_irqrestore(&nesqp->lock, flags);  			ret = cm_id->event_handler(cm_id, &cm_event);  			if (ret)  				nes_debug(NES_DBG_CM, "OFA CM event_handler "  					"returned, ret=%d\n", ret); -			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; -		last_ae = nesqp->last_aeq; - -		if ((issued_disconnect_reset == 0) && (nesqp->cm_id) && -				((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) || -				 (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) || -				 (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) || -				 (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { +		if (issue_close) {  			atomic_inc(&cm_closes); -			nesqp->cm_id = NULL; -			nesqp->in_disconnect = 0; -			spin_unlock_irqrestore(&nesqp->lock, flags);  			nes_disconnect(nesqp, 1);  			cm_id->provider_data = nesqp; @@ -2588,28 +2609,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)  			}  			cm_id->rem_ref(cm_id); - -			spin_lock_irqsave(&nesqp->lock, flags); -			if (nesqp->flush_issued == 0) { -				nesqp->flush_issued = 1; -				spin_unlock_irqrestore(&nesqp->lock, flags); -				flush_wqes(nesvnic->nesdev, nesqp, -					NES_CQP_FLUSH_RQ, 1); -			} else -				spin_unlock_irqrestore(&nesqp->lock, flags); -		} else { -			cm_id = nesqp->cm_id; -			spin_unlock_irqrestore(&nesqp->lock, flags); -			/* check to see if the inbound reset beat the outbound reset */ -			if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) { -				nes_debug(NES_DBG_CM, "QP%u: Decing refcount " -					"due to inbound reset beating the " -					"outbound reset.\n", nesqp->hwqp.qp_id); -			}  		} -	} else { -		nesqp->disconn_pending = 0; -		spin_unlock_irqrestore(&nesqp->lock, flags);  	}  	return 0;  |