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 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