xref: /illumos-gate/usr/src/lib/udapl/udapl_tavor/common/dapl_cr_accept.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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