1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*
32  *
33  * MODULE: dapl_evd_connection_callback.c
34  *
35  * PURPOSE: implements connection callbacks
36  *
37  * Description: Accepts asynchronous callbacks from the Communications Manager
38  *              for EVDs that have been specified as the connection_evd.
39  *
40  * $Id: dapl_evd_connection_callb.c,v 1.33 2003/07/30 18:13:38 hobie16 Exp $
41  */
42 
43 #include "dapl.h"
44 #include "dapl_evd_util.h"
45 #include "dapl_ep_util.h"
46 
47 
48 /*
49  * dapl_evd_connection_callback
50  *
51  * Connection callback function for ACTIVE connection requests; callbacks
52  * generated by the Connection Manager in response to issuing a
53  * connect call.
54  *
55  * Input:
56  * 	ib_cm_handle,
57  * 	ib_cm_event
58  *	private_data_ptr
59  * 	context (evd)
60  *	cr_pp
61  *
62  * Output:
63  * 	None
64  *
65  */
66 
67 void
dapl_evd_connection_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)68 dapl_evd_connection_callback(
69     IN    ib_cm_handle_t	ib_cm_handle,
70     IN    const ib_cm_events_t  ib_cm_event,
71     IN	  const void 		*private_data_ptr,
72     IN    const void		*context)
73 {
74 	DAPL_EP		*ep_ptr;
75 	DAPL_EVD	*evd_ptr;
76 	DAPL_PRIVATE	*prd_ptr;
77 	DAT_EVENT_NUMBER event_type;
78 
79 	dapl_dbg_log(
80 	    DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,
81 	    "--> dapl_evd_connection_callback: ctxt: %p event: %x"
82 	    " cm_handle %p\n",
83 	    context,
84 	    ib_cm_event,
85 	    ib_cm_handle);
86 
87 	/*
88 	 * Determine the type of handle passed back to us in the context
89 	 * and sort out key parameters.
90 	 */
91 	dapl_os_assert(((DAPL_HEADER *)context)->magic == DAPL_MAGIC_EP ||
92 	    ((DAPL_HEADER *)context)->magic == DAPL_MAGIC_EP_EXIT);
93 	/*
94 	 * Active side of the connection, context is an EP and
95 	 * PSP is irrelevant.
96 	 */
97 	ep_ptr  = (DAPL_EP *)context;
98 	evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle;
99 
100 	prd_ptr = (DAPL_PRIVATE *)private_data_ptr;
101 
102 	switch (ib_cm_event) {
103 	case IB_CME_CONNECTED:
104 	{
105 		/*
106 		 * If we don't have an EP at this point we are very screwed
107 		 * up
108 		 */
109 		DAT_RETURN dat_status;
110 
111 		if (ep_ptr->param.ep_state == DAT_EP_STATE_DISCONNECT_PENDING) {
112 			/*
113 			 * If someone pulled the plug on the connection, just
114 			 * exit
115 			 */
116 			break;
117 		}
118 		dapls_ib_connected(ep_ptr);
119 		ep_ptr->param.ep_state	= DAT_EP_STATE_CONNECTED;
120 		ep_ptr->cm_handle	= ib_cm_handle;
121 		/* copy in the private data */
122 		(void) dapl_os_memcpy(ep_ptr->private_data,
123 		    prd_ptr->private_data,
124 		    IB_MAX_REQ_PDATA_SIZE);
125 
126 		dat_status = dapls_evd_post_connection_event(
127 		    evd_ptr,
128 		    DAT_CONNECTION_EVENT_ESTABLISHED,
129 		    (DAT_HANDLE) ep_ptr,
130 		    IB_MAX_REQ_PDATA_SIZE,
131 		    ep_ptr->private_data);
132 
133 		if (dat_status != DAT_SUCCESS) {
134 			(void) dapls_ib_disconnect(ep_ptr,
135 			    DAT_CLOSE_ABRUPT_FLAG);
136 			ep_ptr->param.ep_state =
137 			    DAT_EP_STATE_DISCONNECT_PENDING;
138 		}
139 
140 		/*
141 		 * If we received any premature DTO completions and
142 		 * post them to the recv evd now.
143 		 * there is a race here - if events arrive after we change
144 		 * the ep state to connected and before we process premature
145 		 * events
146 		 */
147 		dapls_evd_post_premature_events(ep_ptr);
148 
149 		break;
150 	}
151 	case IB_CME_DISCONNECTED:
152 	case IB_CME_DISCONNECTED_ON_LINK_DOWN:
153 	{
154 		/*
155 		 * EP is now fully disconnected; initiate any post processing
156 		 * to reset the underlying QP and get the EP ready for
157 		 * another connection
158 		 */
159 		if (ep_ptr->param.ep_state  == DAT_EP_STATE_DISCONNECTED) {
160 			/* DTO error caused this */
161 			event_type = DAT_CONNECTION_EVENT_BROKEN;
162 		} else {
163 			ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
164 			dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE,
165 			    ib_cm_event);
166 			event_type = DAT_CONNECTION_EVENT_DISCONNECTED;
167 		}
168 
169 		/* If the EP has been freed, the evd_ptr will be NULL */
170 		if (evd_ptr != NULL) {
171 			(void) dapls_evd_post_connection_event(
172 			    evd_ptr, event_type, (DAT_HANDLE) ep_ptr, 0, 0);
173 		}
174 
175 		/*
176 		 * If the user has done an ep_free of the EP, we have been
177 		 * waiting for the disconnect event; just clean it up now.
178 		 */
179 		if (ep_ptr->header.magic == DAPL_MAGIC_EP_EXIT) {
180 			(void) dapl_ep_free(ep_ptr);
181 		}
182 		break;
183 	}
184 	case IB_CME_DESTINATION_REJECT_PRIVATE_DATA:
185 	{
186 		ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
187 		dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event);
188 		(void) dapls_evd_post_connection_event(
189 		    evd_ptr,
190 		    DAT_CONNECTION_EVENT_PEER_REJECTED,
191 		    (DAT_HANDLE) ep_ptr,
192 		    0,
193 		    0);
194 		break;
195 	}
196 	case IB_CME_DESTINATION_UNREACHABLE:
197 	{
198 		ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
199 		dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event);
200 		(void) dapls_evd_post_connection_event(
201 		    evd_ptr,
202 		    DAT_CONNECTION_EVENT_UNREACHABLE,
203 		    (DAT_HANDLE) ep_ptr,
204 		    0,
205 		    0);
206 		break;
207 	}
208 	case IB_CME_DESTINATION_REJECT:
209 	case IB_CME_TOO_MANY_CONNECTION_REQUESTS:
210 	case IB_CME_LOCAL_FAILURE:
211 	{
212 		ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
213 		dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event);
214 		(void) dapls_evd_post_connection_event(
215 		    evd_ptr,
216 		    DAT_CONNECTION_EVENT_NON_PEER_REJECTED,
217 		    (DAT_HANDLE) ep_ptr,
218 		    0,
219 		    0);
220 		break;
221 	}
222 	case IB_CME_TIMED_OUT:
223 	{
224 		ep_ptr->param.ep_state  = DAT_EP_STATE_DISCONNECTED;
225 		dapls_ib_disconnect_clean(ep_ptr, DAT_TRUE, ib_cm_event);
226 		(void) dapls_evd_post_connection_event(
227 		    evd_ptr,
228 		    DAT_CONNECTION_EVENT_TIMED_OUT,
229 		    (DAT_HANDLE) ep_ptr,
230 		    0,
231 		    0);
232 		break;
233 	}
234 	case IB_CME_CONNECTION_REQUEST_PENDING:
235 	case IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA:
236 	default:
237 	{
238 		dapl_os_assert(0);		/* shouldn't happen */
239 		break;
240 	}
241 	}
242 
243 	dapl_dbg_log(DAPL_DBG_TYPE_CM | DAPL_DBG_TYPE_CALLBACK,
244 	    "dapl_evd_connection_callback () returns\n");
245 
246 }
247 
248 
249 /*
250  * Local variables:
251  *  c-indent-level: 4
252  *  c-basic-offset: 4
253  *  tab-width: 8
254  * End:
255  */
256