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_cr_accept.c
34 *
35 * PURPOSE: Connection management
36 * Description: Interfaces in this file are completely described in
37 * the DAPL 1.1 API, Chapter 6, section 4
38 *
39 * $Id: dapl_cr_accept.c,v 1.21 2003/08/08 19:20:05 sjs2 Exp $
40 */
41
42 #include "dapl.h"
43 #include "dapl_adapter_util.h"
44
45 /*
46 * dapl_cr_accept
47 *
48 * DAPL Requirements Version xxx, 6.4.2.1
49 *
50 * Establish a connection between active remote side requesting Endpoint
51 * and passic side local Endpoint.
52 *
53 * Input:
54 * cr_handle
55 * ep_handle
56 * private_data_size
57 * private_data
58 *
59 * Output:
60 * none
61 *
62 * Returns:
63 * DAT_SUCCESS
64 * DAT_INVALID_PARAMETER
65 * DAT_INVALID_ATTRIBUTE
66 */
67 DAT_RETURN
dapl_cr_accept(IN DAT_CR_HANDLE cr_handle,IN DAT_EP_HANDLE ep_handle,IN DAT_COUNT private_data_size,IN const DAT_PVOID private_data)68 dapl_cr_accept(
69 IN DAT_CR_HANDLE cr_handle,
70 IN DAT_EP_HANDLE ep_handle,
71 IN DAT_COUNT private_data_size,
72 IN const DAT_PVOID private_data)
73 {
74 DAPL_EP *ep_ptr;
75 DAT_RETURN dat_status;
76 DAPL_PRIVATE prd;
77 DAPL_CR *cr_ptr;
78 DAT_EP_STATE entry_ep_state;
79 DAT_EP_HANDLE entry_ep_handle;
80
81 dapl_dbg_log(DAPL_DBG_TYPE_API,
82 "dapl_cr_accept(%p, %p, %d, %p)\n",
83 cr_handle, ep_handle, private_data_size, private_data);
84
85 if (DAPL_BAD_HANDLE(cr_handle, DAPL_MAGIC_CR)) {
86 dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
87 DAT_INVALID_HANDLE_CR);
88 goto bail;
89 }
90
91 cr_ptr = (DAPL_CR *) cr_handle;
92
93 /*
94 * Return an error if we have an ep_handle and the CR already has an
95 * EP, indicating this is an RSP connection or PSP_PROVIDER_FLAG was
96 * specified.
97 */
98 if (ep_handle != NULL &&
99 (DAPL_BAD_HANDLE(ep_handle, DAPL_MAGIC_EP) ||
100 cr_ptr->param.local_ep_handle != NULL)) {
101 dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
102 DAT_INVALID_HANDLE_EP);
103 goto bail;
104 }
105
106 if ((0 != private_data_size) && (NULL == private_data)) {
107 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
108 goto bail;
109 }
110
111 /*
112 * Verify the private data size doesn't exceed the max
113 */
114 if (private_data_size > DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE) {
115 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
116 goto bail;
117 }
118
119 /*
120 * ep_handle is NULL if the user specified DAT_PSP_PROVIDER_FLAG
121 * OR this is an RSP connection; retrieve it from the cr.
122 */
123 if (ep_handle == NULL) {
124 ep_handle = cr_ptr->param.local_ep_handle;
125 if ((((DAPL_EP *) ep_handle)->param.ep_state !=
126 DAT_EP_STATE_TENTATIVE_CONNECTION_PENDING) &&
127 (((DAPL_EP *)ep_handle)->param.ep_state !=
128 DAT_EP_STATE_PASSIVE_CONNECTION_PENDING)) {
129 return (DAT_INVALID_STATE);
130 }
131 } else {
132 /* ensure this EP isn't connected or in use */
133 if (((DAPL_EP *)ep_handle)->param.ep_state !=
134 DAT_EP_STATE_UNCONNECTED) {
135 return (DAT_INVALID_STATE);
136 }
137 }
138
139 ep_ptr = (DAPL_EP *) ep_handle;
140
141 /*
142 * Verify the attributes of the EP handle before we connect it. Test
143 * all of the handles to make sure they are currently valid.
144 * Specifically:
145 * pz_handle required
146 * recv_evd_handle optional, but must be valid
147 * request_evd_handle optional, but must be valid
148 * connect_evd_handle required
149 * We do all verification and state change under lock, at which
150 * point the EP state should protect us from most races.
151 */
152 dapl_os_lock(&ep_ptr->header.lock);
153 if ((ep_ptr->param.pz_handle == NULL) ||
154 DAPL_BAD_HANDLE(ep_ptr->param.pz_handle, DAPL_MAGIC_PZ) ||
155 (ep_ptr->param.connect_evd_handle == NULL) ||
156 DAPL_BAD_HANDLE(ep_ptr->param.connect_evd_handle, DAPL_MAGIC_EVD) ||
157 !(((DAPL_EVD *)ep_ptr->param.connect_evd_handle)->evd_flags &
158 DAT_EVD_CONNECTION_FLAG) ||
159 (ep_ptr->param.recv_evd_handle != DAT_HANDLE_NULL &&
160 (DAPL_BAD_HANDLE(ep_ptr->param.recv_evd_handle, DAPL_MAGIC_EVD))) ||
161 (ep_ptr->param.request_evd_handle != DAT_HANDLE_NULL &&
162 (DAPL_BAD_HANDLE(ep_ptr->param.request_evd_handle,
163 DAPL_MAGIC_EVD)))) {
164 dapl_os_unlock(&ep_ptr->header.lock);
165 dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
166 DAT_INVALID_HANDLE_EP);
167 goto bail;
168 }
169
170 if (ep_ptr->qp_state == DAPL_QP_STATE_UNATTACHED) {
171 /*
172 * If we are lazy attaching the QP then we may need to
173 * hook it up here. Typically, we run this code only for
174 * DAT_PSP_PROVIDER_FLAG
175 */
176 dat_status = dapls_ib_qp_alloc(cr_ptr->header.owner_ia, ep_ptr,
177 ep_ptr);
178
179 if (dat_status != DAT_SUCCESS) {
180 /* This is not a great error code, but spec allows */
181 dapl_os_unlock(&ep_ptr->header.lock);
182 dat_status = DAT_ERROR(DAT_INVALID_HANDLE,
183 DAT_INVALID_HANDLE_EP);
184 goto bail;
185 }
186 }
187
188 entry_ep_state = ep_ptr->param.ep_state;
189 entry_ep_handle = cr_ptr->param.local_ep_handle;
190 ep_ptr->param.ep_state = DAT_EP_STATE_COMPLETION_PENDING;
191 ep_ptr->cm_handle = cr_ptr->ib_cm_handle;
192 ep_ptr->cr_ptr = cr_ptr;
193 ep_ptr->param.remote_ia_address_ptr = cr_ptr->param.
194 remote_ia_address_ptr;
195 cr_ptr->param.local_ep_handle = ep_handle;
196
197 /*
198 * private data
199 */
200 (void) dapl_os_memcpy(prd.private_data, private_data,
201 private_data_size);
202 (void) dapl_os_memzero(prd.private_data + private_data_size,
203 sizeof (DAPL_PRIVATE) - private_data_size);
204
205 dapl_os_unlock(&ep_ptr->header.lock);
206
207 dat_status = dapls_ib_accept_connection(cr_handle, ep_handle, &prd);
208
209 /*
210 * If the provider failed, unwind the damage so we are back at
211 * the initial state.
212 */
213 if (dat_status != DAT_SUCCESS) {
214 ep_ptr->param.ep_state = entry_ep_state;
215 cr_ptr->param.local_ep_handle = entry_ep_handle;
216 } else {
217 /*
218 * Make this CR invalid. We need to hang on to it until
219 * the connection terminates, but it's destroyed from
220 * the app point of view.
221 */
222 cr_ptr->header.magic = DAPL_MAGIC_CR_DESTROYED;
223 }
224
225 bail:
226 return (dat_status);
227 }
228