1*9e39c5baSBill Taylor /*
2*9e39c5baSBill Taylor  * CDDL HEADER START
3*9e39c5baSBill Taylor  *
4*9e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
5*9e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
6*9e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
7*9e39c5baSBill Taylor  *
8*9e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
10*9e39c5baSBill Taylor  * See the License for the specific language governing permissions
11*9e39c5baSBill Taylor  * and limitations under the License.
12*9e39c5baSBill Taylor  *
13*9e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
14*9e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
16*9e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
17*9e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9e39c5baSBill Taylor  *
19*9e39c5baSBill Taylor  * CDDL HEADER END
20*9e39c5baSBill Taylor  */
21*9e39c5baSBill Taylor 
22*9e39c5baSBill Taylor /*
23*9e39c5baSBill Taylor  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24*9e39c5baSBill Taylor  */
25*9e39c5baSBill Taylor 
26*9e39c5baSBill Taylor /*
27*9e39c5baSBill Taylor  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28*9e39c5baSBill Taylor  * Use is subject to license terms.
29*9e39c5baSBill Taylor  */
30*9e39c5baSBill Taylor 
31*9e39c5baSBill Taylor /*
32*9e39c5baSBill Taylor  *
33*9e39c5baSBill Taylor  * MODULE: dapls_cr_callback.c
34*9e39c5baSBill Taylor  *
35*9e39c5baSBill Taylor  * PURPOSE: implements passive side connection callbacks
36*9e39c5baSBill Taylor  *
37*9e39c5baSBill Taylor  * Description: Accepts asynchronous callbacks from the Communications Manager
38*9e39c5baSBill Taylor  *              for EVDs that have been specified as the connection_evd.
39*9e39c5baSBill Taylor  *
40*9e39c5baSBill Taylor  * $Id: dapl_cr_callback.c,v 1.58 2003/08/20 14:55:39 sjs2 Exp $
41*9e39c5baSBill Taylor  */
42*9e39c5baSBill Taylor 
43*9e39c5baSBill Taylor #include "dapl.h"
44*9e39c5baSBill Taylor #include "dapl_evd_util.h"
45*9e39c5baSBill Taylor #include "dapl_cr_util.h"
46*9e39c5baSBill Taylor #include "dapl_ia_util.h"
47*9e39c5baSBill Taylor #include "dapl_sp_util.h"
48*9e39c5baSBill Taylor #include "dapl_ep_util.h"
49*9e39c5baSBill Taylor #include "dapl_adapter_util.h"
50*9e39c5baSBill Taylor 
51*9e39c5baSBill Taylor 
52*9e39c5baSBill Taylor /*
53*9e39c5baSBill Taylor  * Prototypes
54*9e39c5baSBill Taylor  */
55*9e39c5baSBill Taylor DAT_RETURN dapli_connection_request(
56*9e39c5baSBill Taylor 	IN ib_cm_handle_t ib_cm_handle,
57*9e39c5baSBill Taylor 	IN DAPL_SP *sp_ptr,
58*9e39c5baSBill Taylor 	IN DAPL_PRIVATE	*prd_ptr,
59*9e39c5baSBill Taylor 	IN DAPL_EVD *evd_ptr);
60*9e39c5baSBill Taylor 
61*9e39c5baSBill Taylor DAPL_EP * dapli_get_sp_ep(
62*9e39c5baSBill Taylor 	IN ib_cm_handle_t ib_cm_handle,
63*9e39c5baSBill Taylor 	IN DAPL_SP *sp_ptr,
64*9e39c5baSBill Taylor 	IN const ib_cm_events_t ib_cm_event);
65*9e39c5baSBill Taylor 
66*9e39c5baSBill Taylor /*
67*9e39c5baSBill Taylor  * dapls_cr_callback
68*9e39c5baSBill Taylor  *
69*9e39c5baSBill Taylor  * The callback function registered with verbs for passive side of
70*9e39c5baSBill Taylor  * connection requests. The interface is specified by cm_api.h
71*9e39c5baSBill Taylor  *
72*9e39c5baSBill Taylor  *
73*9e39c5baSBill Taylor  * Input:
74*9e39c5baSBill Taylor  * 	ib_cm_handle,		Handle to CM
75*9e39c5baSBill Taylor  * 	ib_cm_event		Specific CM event
76*9e39c5baSBill Taylor  *	instant_data		Private data with DAT ADDRESS header
77*9e39c5baSBill Taylor  * 	context			SP pointer
78*9e39c5baSBill Taylor  *
79*9e39c5baSBill Taylor  * Output:
80*9e39c5baSBill Taylor  * 	None
81*9e39c5baSBill Taylor  *
82*9e39c5baSBill Taylor  */
83*9e39c5baSBill Taylor void
dapls_cr_callback(IN ib_cm_handle_t ib_cm_handle,IN const ib_cm_events_t ib_cm_event,IN const void * private_data_ptr,IN const void * context)84*9e39c5baSBill Taylor dapls_cr_callback(
85*9e39c5baSBill Taylor 	IN ib_cm_handle_t ib_cm_handle,
86*9e39c5baSBill Taylor 	IN const ib_cm_events_t ib_cm_event,
87*9e39c5baSBill Taylor 	IN const void *private_data_ptr, /* event data */
88*9e39c5baSBill Taylor 	IN const void *context)
89*9e39c5baSBill Taylor {
90*9e39c5baSBill Taylor 	DAPL_EP		*ep_ptr;
91*9e39c5baSBill Taylor 	DAPL_EVD	*evd_ptr;
92*9e39c5baSBill Taylor 	DAPL_SP		*sp_ptr;
93*9e39c5baSBill Taylor 	DAPL_PRIVATE	*prd_ptr;
94*9e39c5baSBill Taylor 	DAT_EVENT_NUMBER	event_type;
95*9e39c5baSBill Taylor 	DAT_RETURN		dat_status;
96*9e39c5baSBill Taylor 
97*9e39c5baSBill Taylor 	dapl_dbg_log(DAPL_DBG_TYPE_CM,
98*9e39c5baSBill Taylor 	    "--> dapls_cr_callback! context: 0x%p "
99*9e39c5baSBill Taylor 	    "event: %d cm_handle 0x%llx magic 0x%x\n",
100*9e39c5baSBill Taylor 	    context, ib_cm_event, ib_cm_handle,
101*9e39c5baSBill Taylor 	    ((DAPL_HEADER *)context)->magic);
102*9e39c5baSBill Taylor 
103*9e39c5baSBill Taylor 	if (((DAPL_HEADER *)context)->magic == DAPL_MAGIC_INVALID) {
104*9e39c5baSBill Taylor 		return;
105*9e39c5baSBill Taylor 	}
106*9e39c5baSBill Taylor 	/*
107*9e39c5baSBill Taylor 	 * Passive side of the connection, context is a SP and
108*9e39c5baSBill Taylor 	 * we need to look up the EP.
109*9e39c5baSBill Taylor 	 */
110*9e39c5baSBill Taylor 	dapl_os_assert(((DAPL_HEADER *)context)->magic == DAPL_MAGIC_PSP ||
111*9e39c5baSBill Taylor 	    ((DAPL_HEADER *)context)->magic == DAPL_MAGIC_RSP);
112*9e39c5baSBill Taylor 	sp_ptr = (DAPL_SP *) context;
113*9e39c5baSBill Taylor 
114*9e39c5baSBill Taylor 	/*
115*9e39c5baSBill Taylor 	 * CONNECT_REQUEST events create an event on the PSP
116*9e39c5baSBill Taylor 	 * EVD, which will trigger connection processing. The
117*9e39c5baSBill Taylor 	 * sequence is:
118*9e39c5baSBill Taylor 	 * CONNECT_REQUEST Event to SP
119*9e39c5baSBill Taylor 	 * CONNECTED Event to EP
120*9e39c5baSBill Taylor 	 * DISCONNECT Event to EP
121*9e39c5baSBill Taylor 	 *
122*9e39c5baSBill Taylor 	 * Obtain the EP if required and set an event up on the correct EVD.
123*9e39c5baSBill Taylor 	 */
124*9e39c5baSBill Taylor 	if (ib_cm_event == IB_CME_CONNECTION_REQUEST_PENDING ||
125*9e39c5baSBill Taylor 	    ib_cm_event == IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA) {
126*9e39c5baSBill Taylor 		ep_ptr = NULL;
127*9e39c5baSBill Taylor 		evd_ptr = sp_ptr->evd_handle;
128*9e39c5baSBill Taylor 	} else {
129*9e39c5baSBill Taylor 		ep_ptr = dapli_get_sp_ep(ib_cm_handle, sp_ptr, ib_cm_event);
130*9e39c5baSBill Taylor 		dapl_os_assert(ep_ptr != NULL);
131*9e39c5baSBill Taylor 		evd_ptr = (DAPL_EVD *) ep_ptr->param.connect_evd_handle;
132*9e39c5baSBill Taylor 		dapl_dbg_log(DAPL_DBG_TYPE_CM,
133*9e39c5baSBill Taylor 		    "    dapls_cr_callback cont: ep 0x%p evd 0x%p\n",
134*9e39c5baSBill Taylor 		    ep_ptr, evd_ptr);
135*9e39c5baSBill Taylor 	}
136*9e39c5baSBill Taylor 
137*9e39c5baSBill Taylor 	prd_ptr = (DAPL_PRIVATE *)private_data_ptr;
138*9e39c5baSBill Taylor 	dat_status = DAT_INTERNAL_ERROR;	/* init to ERR */
139*9e39c5baSBill Taylor 
140*9e39c5baSBill Taylor 	switch (ib_cm_event) {
141*9e39c5baSBill Taylor 	case IB_CME_CONNECTION_REQUEST_PENDING:
142*9e39c5baSBill Taylor 	case IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA: {
143*9e39c5baSBill Taylor 		/*
144*9e39c5baSBill Taylor 		 * Requests arriving on a disabled SP are immediatly rejected
145*9e39c5baSBill Taylor 		 */
146*9e39c5baSBill Taylor 
147*9e39c5baSBill Taylor 		dapl_os_lock(&sp_ptr->header.lock);
148*9e39c5baSBill Taylor 		if (sp_ptr->listening == DAT_FALSE) {
149*9e39c5baSBill Taylor 			dapl_os_unlock(&sp_ptr->header.lock);
150*9e39c5baSBill Taylor 			dapl_dbg_log(DAPL_DBG_TYPE_CM,
151*9e39c5baSBill Taylor 			"---> dapls_cr_callback: conn event on down SP\n");
152*9e39c5baSBill Taylor 			return;
153*9e39c5baSBill Taylor 		}
154*9e39c5baSBill Taylor 
155*9e39c5baSBill Taylor 		if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_RSP) {
156*9e39c5baSBill Taylor 		/*
157*9e39c5baSBill Taylor 		 * RSP connections only allow a single connection. Close
158*9e39c5baSBill Taylor 		 * it down NOW so we reject any further connections.
159*9e39c5baSBill Taylor 		 */
160*9e39c5baSBill Taylor 			sp_ptr->listening = DAT_FALSE;
161*9e39c5baSBill Taylor 		}
162*9e39c5baSBill Taylor 		dapl_os_unlock(&sp_ptr->header.lock);
163*9e39c5baSBill Taylor 
164*9e39c5baSBill Taylor 		/*
165*9e39c5baSBill Taylor 		 * Only occurs on the passive side of a connection
166*9e39c5baSBill Taylor 		 * dapli_connection_request will post the connection
167*9e39c5baSBill Taylor 		 * event if appropriate.
168*9e39c5baSBill Taylor 		 */
169*9e39c5baSBill Taylor 		dat_status = dapli_connection_request(ib_cm_handle,
170*9e39c5baSBill Taylor 		    sp_ptr, prd_ptr, evd_ptr);
171*9e39c5baSBill Taylor 		break;
172*9e39c5baSBill Taylor 	}
173*9e39c5baSBill Taylor 	case IB_CME_CONNECTED: {
174*9e39c5baSBill Taylor 		/*
175*9e39c5baSBill Taylor 		 * This is just a notification the connection is now
176*9e39c5baSBill Taylor 		 * established, there isn't any private data to deal with.
177*9e39c5baSBill Taylor 		 *
178*9e39c5baSBill Taylor 		 * Update the EP state and cache a copy of the cm handle,
179*9e39c5baSBill Taylor 		 * then let the user know we are ready to go.
180*9e39c5baSBill Taylor 		 */
181*9e39c5baSBill Taylor 		dapl_os_lock(&ep_ptr->header.lock);
182*9e39c5baSBill Taylor 		if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING) {
183*9e39c5baSBill Taylor 		/*
184*9e39c5baSBill Taylor 		 * If someone pulled the plug on the connection, just
185*9e39c5baSBill Taylor 		 * exit
186*9e39c5baSBill Taylor 		 */
187*9e39c5baSBill Taylor 			dapl_os_unlock(&ep_ptr->header.lock);
188*9e39c5baSBill Taylor 			dat_status = DAT_SUCCESS;
189*9e39c5baSBill Taylor 			break;
190*9e39c5baSBill Taylor 		}
191*9e39c5baSBill Taylor 		dapls_ib_connected(ep_ptr);
192*9e39c5baSBill Taylor 		ep_ptr->param.ep_state = DAT_EP_STATE_CONNECTED;
193*9e39c5baSBill Taylor 		ep_ptr->cm_handle = ib_cm_handle;
194*9e39c5baSBill Taylor 		dapl_os_unlock(&ep_ptr->header.lock);
195*9e39c5baSBill Taylor 
196*9e39c5baSBill Taylor 		dat_status = dapls_evd_post_connection_event(
197*9e39c5baSBill Taylor 		    evd_ptr,
198*9e39c5baSBill Taylor 		    DAT_CONNECTION_EVENT_ESTABLISHED,
199*9e39c5baSBill Taylor 		    (DAT_HANDLE) ep_ptr,
200*9e39c5baSBill Taylor 		    ((DAPL_CR *)ep_ptr->cr_ptr)->param.private_data_size,
201*9e39c5baSBill Taylor 		    ((DAPL_CR *)ep_ptr->cr_ptr)->param.private_data);
202*9e39c5baSBill Taylor 		/*
203*9e39c5baSBill Taylor 		 * post them to the recv evd now.
204*9e39c5baSBill Taylor 		 * there is a race here - if events arrive after we change
205*9e39c5baSBill Taylor 		 * the ep state to connected and before we process premature
206*9e39c5baSBill Taylor 		 * events
207*9e39c5baSBill Taylor 		 */
208*9e39c5baSBill Taylor 		dapls_evd_post_premature_events(ep_ptr);
209*9e39c5baSBill Taylor 		break;
210*9e39c5baSBill Taylor 	}
211*9e39c5baSBill Taylor 	case IB_CME_DISCONNECTED:
212*9e39c5baSBill Taylor 	case IB_CME_DISCONNECTED_ON_LINK_DOWN: {
213*9e39c5baSBill Taylor 		/*
214*9e39c5baSBill Taylor 		 * EP is now fully disconnected; initiate any post processing
215*9e39c5baSBill Taylor 		 * to reset the underlying QP and get the EP ready for
216*9e39c5baSBill Taylor 		 * another connection
217*9e39c5baSBill Taylor 		 */
218*9e39c5baSBill Taylor 		dapl_os_lock(&ep_ptr->header.lock);
219*9e39c5baSBill Taylor 		if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECTED) {
220*9e39c5baSBill Taylor 			/* DTO error caused this */
221*9e39c5baSBill Taylor 			event_type = DAT_CONNECTION_EVENT_BROKEN;
222*9e39c5baSBill Taylor 		} else {
223*9e39c5baSBill Taylor 			ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
224*9e39c5baSBill Taylor 			dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE,
225*9e39c5baSBill Taylor 			    ib_cm_event);
226*9e39c5baSBill Taylor 			event_type = DAT_CONNECTION_EVENT_DISCONNECTED;
227*9e39c5baSBill Taylor 		}
228*9e39c5baSBill Taylor 		dapls_evd_post_premature_events(ep_ptr);
229*9e39c5baSBill Taylor 
230*9e39c5baSBill Taylor 		ep_ptr->cr_ptr = NULL;
231*9e39c5baSBill Taylor 		dapl_os_unlock(&ep_ptr->header.lock);
232*9e39c5baSBill Taylor 
233*9e39c5baSBill Taylor 		/*
234*9e39c5baSBill Taylor 		 * If the user has done an ep_free of the EP, we have been
235*9e39c5baSBill Taylor 		 * waiting for the disconnect event; just clean it up now.
236*9e39c5baSBill Taylor 		 */
237*9e39c5baSBill Taylor 		if (ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT) {
238*9e39c5baSBill Taylor 			(void) dapl_ep_free(ep_ptr);
239*9e39c5baSBill Taylor 		}
240*9e39c5baSBill Taylor 
241*9e39c5baSBill Taylor 		/* If the EP has been freed, the evd_ptr will be NULL */
242*9e39c5baSBill Taylor 		if (evd_ptr != NULL) {
243*9e39c5baSBill Taylor 			dat_status = dapls_evd_post_connection_event(
244*9e39c5baSBill Taylor 			    evd_ptr, event_type, (DAT_HANDLE) ep_ptr, 0, 0);
245*9e39c5baSBill Taylor 		}
246*9e39c5baSBill Taylor 
247*9e39c5baSBill Taylor 		break;
248*9e39c5baSBill Taylor 	}
249*9e39c5baSBill Taylor 	case IB_CME_DESTINATION_REJECT:
250*9e39c5baSBill Taylor 	case IB_CME_DESTINATION_REJECT_PRIVATE_DATA:
251*9e39c5baSBill Taylor 	case IB_CME_DESTINATION_UNREACHABLE: {
252*9e39c5baSBill Taylor 		/*
253*9e39c5baSBill Taylor 		 * After posting an accept the requesting node has
254*9e39c5baSBill Taylor 		 * stopped talking.
255*9e39c5baSBill Taylor 		 */
256*9e39c5baSBill Taylor 		dapl_os_lock(&ep_ptr->header.lock);
257*9e39c5baSBill Taylor 		ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
258*9e39c5baSBill Taylor 		ep_ptr->cm_handle = IB_INVALID_HANDLE;
259*9e39c5baSBill Taylor 		dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, ib_cm_event);
260*9e39c5baSBill Taylor 		dapl_os_unlock(&ep_ptr->header.lock);
261*9e39c5baSBill Taylor 		dat_status = dapls_evd_post_connection_event(
262*9e39c5baSBill Taylor 		    evd_ptr,
263*9e39c5baSBill Taylor 		    DAT_CONNECTION_EVENT_ACCEPT_COMPLETION_ERROR,
264*9e39c5baSBill Taylor 		    (DAT_HANDLE) ep_ptr, 0, 0);
265*9e39c5baSBill Taylor 
266*9e39c5baSBill Taylor 		break;
267*9e39c5baSBill Taylor 	}
268*9e39c5baSBill Taylor 	case IB_CME_TOO_MANY_CONNECTION_REQUESTS: {
269*9e39c5baSBill Taylor 		/*
270*9e39c5baSBill Taylor 		 * DAPL does not deal with this IB error. There is a
271*9e39c5baSBill Taylor 		 * separate OVERFLOW event error if we try to post too many
272*9e39c5baSBill Taylor 		 * events, but we don't propagate this provider error.  Not
273*9e39c5baSBill Taylor 		 * all providers generate this error.
274*9e39c5baSBill Taylor 		 */
275*9e39c5baSBill Taylor 		break;
276*9e39c5baSBill Taylor 	}
277*9e39c5baSBill Taylor 	case IB_CME_LOCAL_FAILURE: {
278*9e39c5baSBill Taylor 		ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
279*9e39c5baSBill Taylor 		dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, ib_cm_event);
280*9e39c5baSBill Taylor 		dat_status = dapls_evd_post_connection_event(
281*9e39c5baSBill Taylor 		    evd_ptr,
282*9e39c5baSBill Taylor 		    DAT_CONNECTION_EVENT_BROKEN,
283*9e39c5baSBill Taylor 		    (DAT_HANDLE) ep_ptr, 0, 0);
284*9e39c5baSBill Taylor 
285*9e39c5baSBill Taylor 		break;
286*9e39c5baSBill Taylor 	}
287*9e39c5baSBill Taylor 	case IB_CME_TIMED_OUT: {
288*9e39c5baSBill Taylor 		ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
289*9e39c5baSBill Taylor 		dapls_ib_disconnect_clean(ep_ptr, DAT_FALSE, ib_cm_event);
290*9e39c5baSBill Taylor 		dat_status = dapls_evd_post_connection_event(
291*9e39c5baSBill Taylor 		    evd_ptr,
292*9e39c5baSBill Taylor 		    DAT_CONNECTION_EVENT_TIMED_OUT,
293*9e39c5baSBill Taylor 		    (DAT_HANDLE) ep_ptr, 0, 0);
294*9e39c5baSBill Taylor 
295*9e39c5baSBill Taylor 		break;
296*9e39c5baSBill Taylor 	}
297*9e39c5baSBill Taylor 	default:
298*9e39c5baSBill Taylor 		dapl_os_assert(0);		/* shouldn't happen */
299*9e39c5baSBill Taylor 		break;
300*9e39c5baSBill Taylor 	}
301*9e39c5baSBill Taylor 
302*9e39c5baSBill Taylor 	if (dat_status != DAT_SUCCESS) {
303*9e39c5baSBill Taylor 		/* The event post failed; take appropriate action.  */
304*9e39c5baSBill Taylor 		(void) dapls_ib_reject_connection(ib_cm_handle,
305*9e39c5baSBill Taylor 		    IB_CME_LOCAL_FAILURE, sp_ptr);
306*9e39c5baSBill Taylor 		return;
307*9e39c5baSBill Taylor 	}
308*9e39c5baSBill Taylor }
309*9e39c5baSBill Taylor 
310*9e39c5baSBill Taylor 
311*9e39c5baSBill Taylor /*
312*9e39c5baSBill Taylor  * dapli_connection_request
313*9e39c5baSBill Taylor  *
314*9e39c5baSBill Taylor  * Process a connection request on the Passive side of a connection.
315*9e39c5baSBill Taylor  * Create a CR record and link it on to the SP so we can update it
316*9e39c5baSBill Taylor  * and free it later. Create an EP if specified by the PSP flags.
317*9e39c5baSBill Taylor  *
318*9e39c5baSBill Taylor  * Input:
319*9e39c5baSBill Taylor  * 	ib_cm_handle,
320*9e39c5baSBill Taylor  * 	sp_ptr
321*9e39c5baSBill Taylor  * 	event_ptr
322*9e39c5baSBill Taylor  *	prd_ptr
323*9e39c5baSBill Taylor  *
324*9e39c5baSBill Taylor  * Output:
325*9e39c5baSBill Taylor  * 	None
326*9e39c5baSBill Taylor  *
327*9e39c5baSBill Taylor  * Returns
328*9e39c5baSBill Taylor  *	DAT_INSUFFICIENT_RESOURCES
329*9e39c5baSBill Taylor  *	DAT_SUCCESS
330*9e39c5baSBill Taylor  *
331*9e39c5baSBill Taylor  */
332*9e39c5baSBill Taylor DAT_RETURN
dapli_connection_request(IN ib_cm_handle_t ib_cm_handle,IN DAPL_SP * sp_ptr,IN DAPL_PRIVATE * prd_ptr,IN DAPL_EVD * evd_ptr)333*9e39c5baSBill Taylor dapli_connection_request(
334*9e39c5baSBill Taylor 	IN  ib_cm_handle_t ib_cm_handle,
335*9e39c5baSBill Taylor 	IN  DAPL_SP *sp_ptr,
336*9e39c5baSBill Taylor 	IN  DAPL_PRIVATE *prd_ptr,
337*9e39c5baSBill Taylor 	IN  DAPL_EVD *evd_ptr)
338*9e39c5baSBill Taylor {
339*9e39c5baSBill Taylor 	DAT_RETURN	dat_status;
340*9e39c5baSBill Taylor 	DAPL_CR		*cr_ptr;
341*9e39c5baSBill Taylor 	DAPL_EP		*ep_ptr;
342*9e39c5baSBill Taylor 	DAPL_IA		*ia_ptr;
343*9e39c5baSBill Taylor 	DAT_SP_HANDLE	sp_handle;
344*9e39c5baSBill Taylor 	struct sockaddr_in *sv4;
345*9e39c5baSBill Taylor 	struct sockaddr_in6 *sv6;
346*9e39c5baSBill Taylor 	uint8_t		*sadata;
347*9e39c5baSBill Taylor 	DAT_COUNT	length;
348*9e39c5baSBill Taylor 
349*9e39c5baSBill Taylor 	cr_ptr = dapls_cr_alloc(sp_ptr->header.owner_ia);
350*9e39c5baSBill Taylor 	if (cr_ptr == NULL) {
351*9e39c5baSBill Taylor 		/* Invoking function will call dapls_ib_cm_reject() */
352*9e39c5baSBill Taylor 		return (DAT_INSUFFICIENT_RESOURCES);
353*9e39c5baSBill Taylor 	}
354*9e39c5baSBill Taylor 
355*9e39c5baSBill Taylor 	/*
356*9e39c5baSBill Taylor 	 * Set up the CR
357*9e39c5baSBill Taylor 	 */
358*9e39c5baSBill Taylor 	cr_ptr->sp_ptr = sp_ptr; /* maintain sp_ptr in case of reject */
359*9e39c5baSBill Taylor 	cr_ptr->ib_cm_handle = ib_cm_handle;
360*9e39c5baSBill Taylor 	/*
361*9e39c5baSBill Taylor 	 * Copy the remote address and private data out of the private_data
362*9e39c5baSBill Taylor 	 * payload and put them in a local structure
363*9e39c5baSBill Taylor 	 */
364*9e39c5baSBill Taylor 	cr_ptr->param.private_data = cr_ptr->private_data;
365*9e39c5baSBill Taylor 	cr_ptr->param.remote_ia_address_ptr =
366*9e39c5baSBill Taylor 	    (DAT_IA_ADDRESS_PTR)&cr_ptr->remote_ia_address;
367*9e39c5baSBill Taylor 	cr_ptr->param.remote_port_qual =
368*9e39c5baSBill Taylor 	    (DAT_PORT_QUAL) prd_ptr->hello_msg.hi_port;
369*9e39c5baSBill Taylor 	length = (DAT_COUNT) prd_ptr->hello_msg.hi_clen;
370*9e39c5baSBill Taylor 	cr_ptr->param.private_data_size = length;
371*9e39c5baSBill Taylor 	(void) dapl_os_memcpy(cr_ptr->private_data,
372*9e39c5baSBill Taylor 	    prd_ptr->private_data, length);
373*9e39c5baSBill Taylor 	switch (prd_ptr->hello_msg.hi_ipv) {
374*9e39c5baSBill Taylor 	case AF_INET:
375*9e39c5baSBill Taylor 		sv4 = (struct sockaddr_in *)&cr_ptr->remote_ia_address;
376*9e39c5baSBill Taylor 		sv4->sin_family = AF_INET;
377*9e39c5baSBill Taylor 		sv4->sin_port = prd_ptr->hello_msg.hi_port;
378*9e39c5baSBill Taylor 		sv4->sin_addr = prd_ptr->hello_msg.hi_v4ipaddr;
379*9e39c5baSBill Taylor 		break;
380*9e39c5baSBill Taylor 	case AF_INET6:
381*9e39c5baSBill Taylor 		sv6 = (struct sockaddr_in6 *)&cr_ptr->remote_ia_address;
382*9e39c5baSBill Taylor 		sv6->sin6_family = AF_INET6;
383*9e39c5baSBill Taylor 		sv6->sin6_port = prd_ptr->hello_msg.hi_port;
384*9e39c5baSBill Taylor 		sv6->sin6_addr = prd_ptr->hello_msg.hi_v6ipaddr;
385*9e39c5baSBill Taylor 		break;
386*9e39c5baSBill Taylor 	default:
387*9e39c5baSBill Taylor 		sadata = (uint8_t *)&cr_ptr->remote_ia_address;
388*9e39c5baSBill Taylor 		(void) dapl_os_memcpy(sadata, prd_ptr->hello_msg.hi_saaddr,
389*9e39c5baSBill Taylor 		    DAPL_ATS_NBYTES);
390*9e39c5baSBill Taylor 		break;
391*9e39c5baSBill Taylor 	}
392*9e39c5baSBill Taylor 
393*9e39c5baSBill Taylor 	/* EP will be NULL unless RSP service point */
394*9e39c5baSBill Taylor 	ep_ptr = (DAPL_EP *) sp_ptr->ep_handle;
395*9e39c5baSBill Taylor 
396*9e39c5baSBill Taylor 	if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) {
397*9e39c5baSBill Taylor 		/*
398*9e39c5baSBill Taylor 		 * Never true for RSP connections
399*9e39c5baSBill Taylor 		 *
400*9e39c5baSBill Taylor 		 * Create an EP for the user. If we can't allocate an
401*9e39c5baSBill Taylor 		 * EP we are out of resources and need to tell the
402*9e39c5baSBill Taylor 		 * requestor that we cant help them.
403*9e39c5baSBill Taylor 		 */
404*9e39c5baSBill Taylor 		ia_ptr = sp_ptr->header.owner_ia;
405*9e39c5baSBill Taylor 		ep_ptr = dapl_ep_alloc(ia_ptr, NULL, DAT_FALSE);
406*9e39c5baSBill Taylor 		if (ep_ptr == NULL) {
407*9e39c5baSBill Taylor 			dapls_cr_free(cr_ptr);
408*9e39c5baSBill Taylor 			/* Invoking function will call dapls_ib_cm_reject() */
409*9e39c5baSBill Taylor 			return (DAT_INSUFFICIENT_RESOURCES);
410*9e39c5baSBill Taylor 		}
411*9e39c5baSBill Taylor 		/* Link the EP onto the IA */
412*9e39c5baSBill Taylor 		dapl_ia_link_ep(ia_ptr, ep_ptr);
413*9e39c5baSBill Taylor 	}
414*9e39c5baSBill Taylor 
415*9e39c5baSBill Taylor 	cr_ptr->param.local_ep_handle = ep_ptr;
416*9e39c5baSBill Taylor 
417*9e39c5baSBill Taylor 	if (ep_ptr != NULL) {
418*9e39c5baSBill Taylor 		/* Assign valid EP fields: RSP and PSP_PROVIDER_FLAG only */
419*9e39c5baSBill Taylor 		if (sp_ptr->psp_flags == DAT_PSP_PROVIDER_FLAG) {
420*9e39c5baSBill Taylor 			ep_ptr->param.ep_state =
421*9e39c5baSBill Taylor 			    DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING;
422*9e39c5baSBill Taylor 		} else { /* RSP */
423*9e39c5baSBill Taylor 			dapl_os_assert(sp_ptr->header.handle_type ==
424*9e39c5baSBill Taylor 			    DAT_HANDLE_TYPE_RSP);
425*9e39c5baSBill Taylor 			ep_ptr->param.ep_state =
426*9e39c5baSBill Taylor 			    DAT_EP_STATE_PASSIVE_CONNECTION_PENDING;
427*9e39c5baSBill Taylor 		}
428*9e39c5baSBill Taylor 		ep_ptr->cm_handle = ib_cm_handle;
429*9e39c5baSBill Taylor 	}
430*9e39c5baSBill Taylor 
431*9e39c5baSBill Taylor 	/* Post the event.  */
432*9e39c5baSBill Taylor 	/* assign sp_ptr to union to avoid typecast errors from compilers */
433*9e39c5baSBill Taylor 	sp_handle.psp_handle = (DAT_PSP_HANDLE)sp_ptr;
434*9e39c5baSBill Taylor 	dat_status = dapls_evd_post_cr_arrival_event(
435*9e39c5baSBill Taylor 	    evd_ptr,
436*9e39c5baSBill Taylor 	    DAT_CONNECTION_REQUEST_EVENT,
437*9e39c5baSBill Taylor 	    sp_handle,
438*9e39c5baSBill Taylor 	    (DAT_IA_ADDRESS_PTR)&sp_ptr->header.owner_ia->hca_ptr->hca_address,
439*9e39c5baSBill Taylor 	    sp_ptr->conn_qual,
440*9e39c5baSBill Taylor 	    (DAT_CR_HANDLE)cr_ptr);
441*9e39c5baSBill Taylor 	if (dat_status != DAT_SUCCESS) {
442*9e39c5baSBill Taylor 		dapls_cr_free(cr_ptr);
443*9e39c5baSBill Taylor 		(void) dapls_ib_reject_connection(ib_cm_handle,
444*9e39c5baSBill Taylor 		    IB_CME_LOCAL_FAILURE, sp_ptr);
445*9e39c5baSBill Taylor 		return (DAT_INSUFFICIENT_RESOURCES);
446*9e39c5baSBill Taylor 	}
447*9e39c5baSBill Taylor 
448*9e39c5baSBill Taylor 	/* link the CR onto the SP so we can pick it up later */
449*9e39c5baSBill Taylor 	dapl_sp_link_cr(sp_ptr, cr_ptr);
450*9e39c5baSBill Taylor 
451*9e39c5baSBill Taylor 	return (DAT_SUCCESS);
452*9e39c5baSBill Taylor }
453*9e39c5baSBill Taylor 
454*9e39c5baSBill Taylor 
455*9e39c5baSBill Taylor /*
456*9e39c5baSBill Taylor  * dapli_get_sp_ep
457*9e39c5baSBill Taylor  *
458*9e39c5baSBill Taylor  * Passive side of a connection is now fully established. Clean
459*9e39c5baSBill Taylor  * up resources and obtain the EP pointer associated with a CR in
460*9e39c5baSBill Taylor  * the SP
461*9e39c5baSBill Taylor  *
462*9e39c5baSBill Taylor  * Input:
463*9e39c5baSBill Taylor  * 	ib_cm_handle,
464*9e39c5baSBill Taylor  * 	sp_ptr
465*9e39c5baSBill Taylor  *
466*9e39c5baSBill Taylor  * Output:
467*9e39c5baSBill Taylor  *	none
468*9e39c5baSBill Taylor  *
469*9e39c5baSBill Taylor  * Returns
470*9e39c5baSBill Taylor  * 	ep_ptr
471*9e39c5baSBill Taylor  *
472*9e39c5baSBill Taylor  */
473*9e39c5baSBill Taylor DAPL_EP *
dapli_get_sp_ep(IN ib_cm_handle_t ib_cm_handle,IN DAPL_SP * sp_ptr,IN const ib_cm_events_t ib_cm_event)474*9e39c5baSBill Taylor dapli_get_sp_ep(
475*9e39c5baSBill Taylor 	IN ib_cm_handle_t ib_cm_handle,
476*9e39c5baSBill Taylor 	IN DAPL_SP *sp_ptr,
477*9e39c5baSBill Taylor 	IN const ib_cm_events_t ib_cm_event)
478*9e39c5baSBill Taylor {
479*9e39c5baSBill Taylor 	DAPL_CR		*cr_ptr;
480*9e39c5baSBill Taylor 	DAPL_EP		*ep_ptr;
481*9e39c5baSBill Taylor 
482*9e39c5baSBill Taylor 	/*
483*9e39c5baSBill Taylor 	 * There are potentially multiple connections in progress. Need to
484*9e39c5baSBill Taylor 	 * go through the list and find the one we are interested
485*9e39c5baSBill Taylor 	 * in. There is no guarantee of order. dapl_sp_search_cr
486*9e39c5baSBill Taylor 	 * leaves the CR on the SP queue.
487*9e39c5baSBill Taylor 	 */
488*9e39c5baSBill Taylor 	cr_ptr = dapl_sp_search_cr(sp_ptr, ib_cm_handle);
489*9e39c5baSBill Taylor 	if (cr_ptr == NULL) {
490*9e39c5baSBill Taylor 		dapl_os_assert(0);
491*9e39c5baSBill Taylor 		return (NULL);
492*9e39c5baSBill Taylor 	}
493*9e39c5baSBill Taylor 
494*9e39c5baSBill Taylor 	ep_ptr = (DAPL_EP *)cr_ptr->param.local_ep_handle;
495*9e39c5baSBill Taylor 
496*9e39c5baSBill Taylor 	dapl_os_assert(!(DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) ||
497*9e39c5baSBill Taylor 	    ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT);
498*9e39c5baSBill Taylor 
499*9e39c5baSBill Taylor 	if (ib_cm_event == IB_CME_DISCONNECTED ||
500*9e39c5baSBill Taylor 	    ib_cm_event == IB_CME_DISCONNECTED_ON_LINK_DOWN) {
501*9e39c5baSBill Taylor 		/* Remove the CR from the queue */
502*9e39c5baSBill Taylor 		dapl_sp_remove_cr(sp_ptr, cr_ptr);
503*9e39c5baSBill Taylor 		/*
504*9e39c5baSBill Taylor 		 * Last event, time to clean up and dispose of the resource
505*9e39c5baSBill Taylor 		 */
506*9e39c5baSBill Taylor 		dapls_cr_free(cr_ptr);
507*9e39c5baSBill Taylor 
508*9e39c5baSBill Taylor 		/*
509*9e39c5baSBill Taylor 		 * If this SP has been removed from service, free it
510*9e39c5baSBill Taylor 		 * up after the last CR is removed
511*9e39c5baSBill Taylor 		 */
512*9e39c5baSBill Taylor 		dapl_os_lock(&sp_ptr->header.lock);
513*9e39c5baSBill Taylor 		if (sp_ptr->listening != DAT_TRUE &&
514*9e39c5baSBill Taylor 		    sp_ptr->cr_list_count == 0 &&
515*9e39c5baSBill Taylor 		    sp_ptr->state != DAPL_SP_STATE_FREE) {
516*9e39c5baSBill Taylor 			dapl_dbg_log(DAPL_DBG_TYPE_CM,
517*9e39c5baSBill Taylor 			    "--> dapli_get_sp_ep! disconnect dump sp: %p \n",
518*9e39c5baSBill Taylor 			    sp_ptr);
519*9e39c5baSBill Taylor 			sp_ptr->state = DAPL_SP_STATE_FREE;
520*9e39c5baSBill Taylor 			dapl_os_unlock(&sp_ptr->header.lock);
521*9e39c5baSBill Taylor 			(void) dapls_ib_remove_conn_listener(sp_ptr->
522*9e39c5baSBill Taylor 			    header.owner_ia, sp_ptr);
523*9e39c5baSBill Taylor 			dapls_ia_unlink_sp((DAPL_IA *)sp_ptr->header.owner_ia,
524*9e39c5baSBill Taylor 			    sp_ptr);
525*9e39c5baSBill Taylor 			dapls_sp_free_sp(sp_ptr);
526*9e39c5baSBill Taylor 		} else {
527*9e39c5baSBill Taylor 			dapl_os_unlock(&sp_ptr->header.lock);
528*9e39c5baSBill Taylor 		}
529*9e39c5baSBill Taylor 	}
530*9e39c5baSBill Taylor 	return (ep_ptr);
531*9e39c5baSBill Taylor }
532