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_ep_connect.c
34 *
35 * PURPOSE: Endpoint management
36 * Description: Interfaces in this file are completely described in
37 * the DAPL 1.1 API, Chapter 6, section 5
38 *
39 * $Id: dapl_ep_connect.c,v 1.23 2003/07/31 13:55:18 hobie16 Exp $
40 */
41
42 #include "dapl.h"
43 #include "dapl_ep_util.h"
44 #include "dapl_adapter_util.h"
45 #include "dapl_evd_util.h"
46
47 /*
48 * dapl_ep_connect
49 *
50 * DAPL Requirements Version xxx, 6.5.7
51 *
52 * Request a connection be established between the local Endpoint
53 * and a remote Endpoint. This operation is used by the active/client
54 * side of a connection
55 *
56 * Input:
57 * ep_handle
58 * remote_ia_address
59 * remote_conn_qual
60 * timeout
61 * private_data_size
62 * privaet_data
63 * qos
64 * connect_flags
65 *
66 * Output:
67 * None
68 *
69 * Returns:
70 * DAT_SUCCESS
71 * DAT_INSUFFICIENT_RESOUCRES
72 * DAT_INVALID_PARAMETER
73 * DAT_MODLE_NOT_SUPPORTED
74 */
75 DAT_RETURN
dapl_ep_connect(IN DAT_EP_HANDLE ep_handle,IN DAT_IA_ADDRESS_PTR remote_ia_address,IN DAT_CONN_QUAL remote_conn_qual,IN DAT_TIMEOUT timeout,IN DAT_COUNT private_data_size,IN const DAT_PVOID private_data,IN DAT_QOS qos,IN DAT_CONNECT_FLAGS connect_flags)76 dapl_ep_connect(
77 IN DAT_EP_HANDLE ep_handle,
78 IN DAT_IA_ADDRESS_PTR remote_ia_address,
79 IN DAT_CONN_QUAL remote_conn_qual,
80 IN DAT_TIMEOUT timeout,
81 IN DAT_COUNT private_data_size,
82 IN const DAT_PVOID private_data,
83 IN DAT_QOS qos,
84 IN DAT_CONNECT_FLAGS connect_flags)
85 {
86 DAPL_EP *ep_ptr;
87 DAPL_PRIVATE prd;
88 DAPL_EP alloc_ep;
89 DAT_RETURN dat_status;
90
91 dapl_dbg_log(DAPL_DBG_TYPE_API | DAPL_DBG_TYPE_CM,
92 "dapl_ep_connect (%p, {%u.%u.%u.%u}, %X, %d, %d, %p, %x, %x)\n",
93 ep_handle,
94 remote_ia_address->sa_data[2],
95 remote_ia_address->sa_data[3],
96 remote_ia_address->sa_data[4],
97 remote_ia_address->sa_data[5],
98 remote_conn_qual,
99 timeout,
100 private_data_size,
101 private_data,
102 qos,
103 connect_flags);
104
105 dat_status = DAT_SUCCESS;
106 ep_ptr = (DAPL_EP *) ep_handle;
107
108 /*
109 * Verify parameter & state. The connection handle must be good
110 * at this point.
111 */
112 if (DAPL_BAD_HANDLE(ep_ptr, DAPL_MAGIC_EP)) {
113 dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
114 DAT_INVALID_HANDLE_EP);
115 goto bail;
116 }
117
118 if (DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD)) {
119 dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
120 DAT_INVALID_HANDLE_EVD_CONN);
121 goto bail;
122 }
123
124 /*
125 * If the endpoint needs a QP, associated the QP with it.
126 * This needs to be done carefully, in order to:
127 * * Avoid allocating under a lock.
128 * * Not step on data structures being altered by
129 * routines with which we are racing.
130 * So we:
131 * * Confirm that a new QP is needed and is not forbidden by the
132 * current state.
133 * * Allocate it into a separate EP.
134 * * Take the EP lock.
135 * * Reconfirm that the EP is in a state where it needs a QP.
136 * * Assign the QP and release the lock.
137 */
138 if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
139 if (ep_ptr->param.pz_handle == NULL ||
140 DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ)) {
141 dat_status = DAT_ERROR(DAT_INVALID_STATE,
142 DAT_INVALID_STATE_EP_NOTREADY);
143 goto bail;
144 }
145 alloc_ep = *ep_ptr;
146
147 dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,
148 &alloc_ep, ep_ptr);
149 if (dat_status != DAT_SUCCESS) {
150 dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
151 DAT_RESOURCE_MEMORY);
152 goto bail;
153 }
154
155 dapl_os_lock(&ep_ptr->header.lock);
156 /*
157 * PZ shouldn't have changed since we're only racing with
158 * dapl_cr_accept()
159 */
160 if (ep_ptr->qp_state != DAPL_QP_STATE_UNATTACHED) {
161 /* Bail, cleaning up. */
162 dapl_os_unlock(&ep_ptr->header.lock);
163 dat_status = dapls_ib_qp_free(ep_ptr->header.owner_ia,
164 &alloc_ep);
165 if (dat_status != DAT_SUCCESS) {
166 dapl_dbg_log(DAPL_DBG_TYPE_WARN,
167 "ep_connect: ib_qp_free failed with %x\n",
168 dat_status);
169 }
170 dat_status = DAT_ERROR(DAT_INVALID_STATE,
171 dapls_ep_state_subtype(ep_ptr));
172 goto bail;
173 }
174 ep_ptr->qp_handle = alloc_ep.qp_handle;
175 ep_ptr->qpn = alloc_ep.qpn;
176 ep_ptr->qp_state = alloc_ep.qp_state;
177
178 dapl_os_unlock(&ep_ptr->header.lock);
179 }
180
181 /*
182 * We do state checks and transitions under lock.
183 * The only code we're racing against is dapl_cr_accept.
184 */
185 dapl_os_lock(&ep_ptr->header.lock);
186
187 /*
188 * Verify the attributes of the EP handle before we connect it. Test
189 * all of the handles to make sure they are currently valid.
190 * Specifically:
191 * pz_handle required
192 * recv_evd_handle optional, but must be valid
193 * request_evd_handle optional, but must be valid
194 * connect_evd_handle required
195 */
196 if (ep_ptr->param.pz_handle == NULL ||
197 DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) ||
198 ep_ptr->param.connect_evd_handle == NULL ||
199 DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle,
200 DAPL_MAGIC_EVD) ||
201 !(((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags &
202 DAT_EVD_CONNECTION_FLAG) ||
203 (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL &&
204 (DAPL_BAD_HANDLE(ep_ptr->param.recv_evd_handle,
205 DAPL_MAGIC_EVD))) ||
206 (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL &&
207 (DAPL_BAD_HANDLE(ep_ptr->param.request_evd_handle,
208 DAPL_MAGIC_EVD)))) {
209 dapl_os_unlock(&ep_ptr->header.lock);
210 dat_status = DAT_ERROR(DAT_INVALID_STATE,
211 DAT_INVALID_STATE_EP_NOTREADY);
212 goto bail;
213 }
214
215 /*
216 * Check both the EP state and the QP state: if we don't have a QP
217 * we need to attach one now.
218 */
219 if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
220 dat_status = dapls_ib_qp_alloc(ep_ptr->header.owner_ia,
221 ep_ptr, ep_ptr);
222
223 if (dat_status != DAT_SUCCESS) {
224 dapl_os_unlock(&ep_ptr->header.lock);
225 dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
226 DAT_RESOURCE_TEP);
227 goto bail;
228 }
229 }
230
231 if (ep_ptr->param.ep_state != DAT_EP_STATE_UNCONNECTED) {
232 dapl_os_unlock(&ep_ptr->header.lock);
233 dat_status = DAT_ERROR(DAT_INVALID_STATE,
234 dapls_ep_state_subtype(ep_ptr));
235 goto bail;
236 }
237
238 if (qos != DAT_QOS_BEST_EFFORT ||
239 connect_flags != DAT_CONNECT_DEFAULT_FLAG) {
240 /*
241 * At this point we only support one QOS level
242 */
243 dapl_os_unlock(&ep_ptr->header.lock);
244 dat_status = DAT_ERROR(DAT_MODEL_NOT_SUPPORTED, 0);
245 goto bail;
246 }
247
248 /*
249 * Verify the private data size doesn't exceed the max
250 */
251 if (private_data_size > DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE) {
252 dapl_os_unlock(&ep_ptr->header.lock);
253 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5);
254 goto bail;
255 }
256
257 /*
258 * transition the state before requesting a connection to avoid
259 * race conditions
260 */
261 ep_ptr->param.ep_state = DAT_EP_STATE_ACTIVE_CONNECTION_PENDING;
262
263 /*
264 * At this point we're committed, and done with the endpoint
265 * except for the connect, so we can drop the lock.
266 */
267 dapl_os_unlock(&ep_ptr->header.lock);
268
269 /*
270 * fill in the private data
271 */
272 (void) dapl_os_memzero(&prd, sizeof (DAPL_PRIVATE));
273 if (private_data_size > 0)
274 (void) dapl_os_memcpy(prd.private_data, private_data,
275 private_data_size);
276
277 /* Copy the connection qualifiers */
278 (void) dapl_os_memcpy(ep_ptr->param.remote_ia_address_ptr,
279 remote_ia_address, sizeof (DAT_SOCK_ADDR6));
280 ep_ptr->param.remote_port_qual = remote_conn_qual;
281
282 dat_status = dapls_ib_connect(ep_handle,
283 remote_ia_address, remote_conn_qual,
284 private_data_size, &prd, timeout);
285
286 if (dat_status != DAT_SUCCESS) {
287 DAPL_EVD *evd_ptr;
288
289 if (dat_status == DAT_ERROR(DAT_INVALID_ADDRESS,
290 DAT_INVALID_ADDRESS_UNREACHABLE)) {
291 /* Unreachable IP address */
292 evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle;
293 if (evd_ptr != NULL) {
294 (void) dapls_evd_post_connection_event(evd_ptr,
295 DAT_CONNECTION_EVENT_UNREACHABLE,
296 (DAT_HANDLE) ep_ptr, 0, 0);
297 }
298 ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
299 dat_status = DAT_SUCCESS;
300 } else if (dat_status == DAT_ERROR(DAT_INVALID_PARAMETER,
301 DAT_INVALID_ADDRESS_UNREACHABLE)) {
302 /* Non-existant connection qualifier */
303 evd_ptr = (DAPL_EVD *)ep_ptr->param.connect_evd_handle;
304 if (evd_ptr != NULL) {
305 (void) dapls_evd_post_connection_event(evd_ptr,
306 DAT_CONNECTION_EVENT_NON_PEER_REJECTED,
307 (DAT_HANDLE) ep_ptr, 0, 0);
308 }
309 ep_ptr->param.ep_state = DAT_EP_STATE_DISCONNECTED;
310 dat_status = DAT_SUCCESS;
311 } else {
312 ep_ptr->param.ep_state = DAT_EP_STATE_UNCONNECTED;
313 }
314 }
315
316 bail:
317 dapl_dbg_log(DAPL_DBG_TYPE_RTN | DAPL_DBG_TYPE_CM,
318 "dapl_ep_connect () returns 0x%x\n", dat_status);
319
320 return (dat_status);
321 }
322