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 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <strings.h>
28
29#include <dapl.h>
30#include <dapl_adapter_util.h>
31#include <dapl_evd_util.h>
32#include <dapl_cr_util.h>
33#include <dapl_lmr_util.h>
34#include <dapl_rmr_util.h>
35#include <dapl_cookie.h>
36#include <dapl_name_service.h>
37#include <dapl_tavor_ibtf_impl.h>
38
39/* Function prototypes */
40extern DAT_RETURN dapls_tavor_wrid_init(ib_qp_handle_t);
41extern void dapls_tavor_wrid_cleanup(DAPL_EP *, ib_qp_handle_t);
42
43int g_dapl_loopback_connection = 0;
44
45/*
46 * dapls_ib_connect
47 *
48 * Initiate a connection with the passive listener on another node
49 *
50 * Input:
51 *        ep_handle,
52 *        remote_ia_address,
53 *        remote_conn_qual,
54 *	  prd_size		size of private data and structure
55 *	  prd_prt		pointer to private data structure
56 *
57 * Output:
58 *        none
59 *
60 * Returns:
61 *        DAT_SUCCESS
62 *        DAT_INSUFFICIENT_RESOURCES
63 *        DAT_INVALID_PARAMETER
64 *
65 */
66
67DAT_RETURN
68dapls_ib_connect(IN DAT_EP_HANDLE ep_handle,
69    IN DAT_IA_ADDRESS_PTR remote_ia_address, IN DAT_CONN_QUAL remote_conn_qual,
70    IN DAT_COUNT prd_size, IN DAPL_PRIVATE *prd_ptr, IN DAT_TIMEOUT timeout)
71{
72	dapl_ep_connect_t args;
73	DAPL_EP *ep_p = (DAPL_EP *)ep_handle;
74	struct sockaddr *s;
75	char addr_buf[64];
76	ib_gid_t dgid;
77	int retval;
78	struct sockaddr_in6 *v6addr;
79	struct sockaddr_in *v4addr;
80	dapl_ia_addr_t *sap;
81
82	s = (struct sockaddr *)remote_ia_address;
83	dapl_dbg_log(DAPL_DBG_TYPE_CM,
84	    "dapls_ib_connect: ep 0x%p\n"
85	    "                  addr %s, conn_qual %016llu, ep_hkey %016llx\n"
86	    "                  prd_size %d, timeout 0x%x\n",
87	    ep_p, dapls_inet_ntop(s, addr_buf, 64), remote_conn_qual,
88	    ep_p->qp_handle->ep_hkey, prd_size, timeout);
89	if (ep_p->qp_handle == NULL) {
90		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
91		    "dapls_ib_connect: ep 0x%p, addr %s, conn_qual %016llu, "
92		    "qp_handle == NULL\n", ep_p, dapls_inet_ntop(s,
93		    addr_buf, 64), remote_conn_qual);
94		return (DAT_INVALID_PARAMETER);
95	}
96	if (timeout == DAT_TIMEOUT_INFINITE) {
97		args.epc_timeout = 0;
98	} else {
99		args.epc_timeout = timeout;
100	}
101	/* resolve remote address to dgid */
102	retval = dapls_ns_lookup_address(ep_p->header.owner_ia,
103	    remote_ia_address, timeout, &dgid);
104	if (retval == DAT_SUCCESS) {
105		args.epc_dgid = dgid;
106	} else if ((retval & DAT_SUBTYPE_MASK) ==
107	    DAT_INVALID_ADDRESS_UNREACHABLE) {
108		/* let the kernel driver look up the dgid from ATS */
109		args.epc_dgid.gid_guid = 0ULL;
110		args.epc_dgid.gid_prefix = 0ULL;
111	} else {
112		return (retval);
113	}
114	args.epc_sid = remote_conn_qual;
115	args.epc_hkey = ep_p->qp_handle->ep_hkey;
116	sap = (dapl_ia_addr_t *)&args.epc_raddr_sadata;
117	/*
118	 * filled in the remote_ia_address for consistent though
119	 * not necessary when dapls_ns_lookup_address has resolved the dgid
120	 */
121	switch (s->sa_family) {
122	case AF_INET:
123		/* LINTED: E_BAD_PTR_CAST_ALIGN */
124		v4addr = (struct sockaddr_in *)s;
125		sap->iad_v4pad[0] = 0;
126		sap->iad_v4pad[1] = 0;
127		sap->iad_v4pad[2] = 0;
128		sap->iad_v4 = v4addr->sin_addr;
129		break;
130	case AF_INET6:
131		/* LINTED: E_BAD_PTR_CAST_ALIGN */
132		v6addr = (struct sockaddr_in6 *)s;
133		sap->iad_v6 = v6addr->sin6_addr;
134		break;
135	}
136
137	/* establish the hello message */
138	(void) dapl_os_memzero((void *)&prd_ptr->hello_msg,
139	    sizeof (DAPL_HELLO_MSG));
140	/* on ATS leave the msg blank to avoid confusion to 3rd parties */
141	if ((args.epc_dgid.gid_guid | args.epc_dgid.gid_prefix)) {
142		prd_ptr->hello_msg.hi_checksum = DAPL_CHECKSUM;
143		prd_ptr->hello_msg.hi_clen = prd_size;
144		prd_ptr->hello_msg.hi_mid = 0;
145		prd_ptr->hello_msg.hi_vers = DAPL_HELLO_MSG_VERS;
146
147		/* fill in local address */
148		s = (struct sockaddr *)
149		    &ep_p->header.owner_ia->hca_ptr->hca_address;
150		prd_ptr->hello_msg.hi_ipv = (uint8_t)s->sa_family;
151		switch (s->sa_family) {
152		case AF_INET:
153			/* LINTED: E_BAD_PTR_CAST_ALIGN */
154			v4addr = (struct sockaddr_in *)s;
155			prd_ptr->hello_msg.hi_port = v4addr->sin_port;
156			prd_ptr->hello_msg.hi_v4ipaddr = v4addr->sin_addr;
157			break;
158		case AF_INET6:
159			/* LINTED: E_BAD_PTR_CAST_ALIGN */
160			v6addr = (struct sockaddr_in6 *)s;
161			prd_ptr->hello_msg.hi_port = v6addr->sin6_port;
162			prd_ptr->hello_msg.hi_v6ipaddr = v6addr->sin6_addr;
163			break;
164		default:
165			break; /* fall through */
166		}
167	}
168	if (prd_size > 0) {
169		(void) dapl_os_memcpy((void *)&args.epc_priv[0],
170		    (void *)prd_ptr, sizeof (DAPL_PRIVATE));
171	} else {
172		(void) dapl_os_memcpy((void *)
173		    &args.epc_priv[DAPL_CONSUMER_MAX_PRIVATE_DATA_SIZE],
174		    (void *)&prd_ptr->hello_msg, sizeof (DAPL_HELLO_MSG));
175	}
176	args.epc_priv_sz = sizeof (DAPL_PRIVATE);
177
178	retval = ioctl(ep_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
179	    DAPL_EP_CONNECT, &args);
180	if (retval != 0) {
181		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
182		    "dapls_ib_connect: connect failed %s, retval %d\n\n",
183		    strerror(errno), retval);
184		return (dapls_convert_error(errno, retval));
185	}
186
187	dapl_dbg_log(DAPL_DBG_TYPE_CM,
188	    "dapls_ib_connect: connected to %s\n\n",
189	    dapls_inet_ntop(s, addr_buf, 64));
190	return (DAT_SUCCESS);
191}
192
193/*
194 * dapls_ib_disconnect
195 *
196 * Disconnect an EP
197 *
198 * Input:
199 *        ep_handle,
200 *        disconnect_flags
201 *
202 * Output:
203 *        none
204 *
205 * Returns:
206 *        DAT_SUCCESS
207 *        DAT_INSUFFICIENT_RESOURCES
208 *        DAT_INVALID_PARAMETER
209 *
210 */
211/* ARGSUSED */
212DAT_RETURN
213dapls_ib_disconnect(IN DAPL_EP *ep_ptr,
214    IN DAT_CLOSE_FLAGS close_flags)
215{
216	dapl_ep_disconnect_t args;
217	struct sockaddr *s;
218	char addr_buf[64];
219	int retval;
220
221	if (ep_ptr->qp_handle == NULL) {
222		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
223		    "dapls_ib_disconnect: qp_handle == NULL\n");
224		return (DAT_INVALID_PARAMETER);
225	}
226	args.epd_hkey = ep_ptr->qp_handle->ep_hkey;
227
228	retval = ioctl(ep_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
229	    DAPL_EP_DISCONNECT, &args);
230	/* no reason for disconnect to fail so transition the state */
231	ep_ptr->qp_state = IBT_STATE_ERROR;
232
233	if (retval != 0) {
234		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
235		    "dapls_ib_disconnect: disconnect failed %s\n",
236		    strerror(errno));
237		return (dapls_convert_error(errno, retval));
238	}
239	s = (struct sockaddr *)ep_ptr->param.remote_ia_address_ptr;
240	dapl_dbg_log(DAPL_DBG_TYPE_CM,
241	    "dapls_ib_disconnect: disconnected from %s, conn_qual %016llu\n",
242	    dapls_inet_ntop(s, addr_buf, 64), ep_ptr->param.remote_port_qual);
243	return (DAT_SUCCESS);
244}
245
246
247/*
248 * dapls_ib_connected
249 *
250 * transition qp_state to IBT_STATE_RTS
251 *
252 */
253void
254dapls_ib_connected(IN DAPL_EP *ep_ptr)
255{
256	ep_ptr->qp_state = IBT_STATE_RTS;
257}
258
259
260/*
261 * dapls_ib_disconnect_clean
262 *
263 * transition qp_state to IBT_STATE_ERROR.
264 * abort connection if necessary.
265 *
266 * Input:
267 *	ep_ptr		DAPL_EP
268 *
269 * Output:
270 * 	none
271 *
272 * Returns:
273 * 	void
274 *
275 */
276/* ARGSUSED */
277void
278dapls_ib_disconnect_clean(IN DAPL_EP *ep_ptr, IN DAT_BOOLEAN active,
279    IN const ib_cm_events_t ib_cm_event)
280{
281	switch (ib_cm_event) {
282	case IB_CME_CONNECTED:
283	case IB_CME_CONNECTION_REQUEST_PENDING:
284	case IB_CME_CONNECTION_REQUEST_PENDING_PRIVATE_DATA:
285		(void) dapls_ib_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG);
286		/* FALLTHROUGH */
287	case IB_CME_DESTINATION_REJECT:
288	case IB_CME_DESTINATION_REJECT_PRIVATE_DATA:
289	case IB_CME_DESTINATION_UNREACHABLE:
290	case IB_CME_TOO_MANY_CONNECTION_REQUESTS:
291	case IB_CME_LOCAL_FAILURE:
292	case IB_CME_TIMED_OUT:
293	case IB_CME_DISCONNECTED_ON_LINK_DOWN:
294		ep_ptr->qp_state = IBT_STATE_ERROR;
295	}
296}
297
298
299/*
300 * dapls_ib_reinit_ep
301 *
302 * Move the QP to INIT state again.
303 *
304 * Input:
305 *	ep_ptr		DAPL_EP
306 *
307 * Output:
308 * 	none
309 *
310 * Returns:
311 * 	void
312 *
313 */
314void
315dapls_ib_reinit_ep(IN DAPL_EP *ep_ptr)
316{
317	dapl_ep_reinit_t	reinit_args;
318	ib_hca_handle_t		hca_hndl;
319	ib_qp_handle_t		qp_p;
320	char			addr_buf[64];
321	int			retval;
322
323	hca_hndl = ep_ptr->header.owner_ia->hca_ptr->ib_hca_handle;
324	qp_p = ep_ptr->qp_handle;
325
326	if (qp_p == NULL) {
327		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
328		    "dapls_ib_reinit: qp_handle == NULL\n");
329		return;
330	}
331	/*
332	 * Do all the work request cleanup processing right away
333	 * no one should really be doing any operation on this
334	 * qp (we are not threadsafe)...
335	 */
336	dapls_tavor_wrid_cleanup(ep_ptr, qp_p);
337
338	reinit_args.epri_hkey = qp_p->ep_hkey;
339	if (ioctl(hca_hndl->ia_fd, DAPL_EP_REINIT, &reinit_args) != 0) {
340		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
341		    "dapls_ib_reinit: reinit failed %s\n",
342		    strerror(errno));
343		return;
344	}
345
346	qp_p->qp_sq_lastwqeaddr = NULL;
347	qp_p->qp_rq_lastwqeaddr = NULL;
348
349	/*
350	 * Setup data structure for work request processing
351	 */
352	retval = dapls_tavor_wrid_init(qp_p);
353	if (retval != DAT_SUCCESS) {
354		/*
355		 * we failed to create data structures for work request
356		 * processing. Lets unmap and leave, the qp will get
357		 * cleaned when ep gets destroyed - the ep is unusable
358		 * in this state.
359		 */
360		if (munmap((void *)qp_p->qp_addr, qp_p->qp_map_len) < 0) {
361			dapl_dbg_log(DAPL_DBG_TYPE_ERR,
362			    "qp_free: munmap failed(%d)\n", errno);
363		}
364		qp_p->qp_addr = NULL;
365		dapl_dbg_log(DAPL_DBG_TYPE_CM,
366		    "dapls_ib_reinit: wrid_init failed %d\n", retval);
367		return;
368	}
369
370	/* we have a new ep and it is in the init state */
371	ep_ptr->qp_state = IBT_STATE_INIT;
372
373	dapl_dbg_log(DAPL_DBG_TYPE_CM,
374	    "dapls_ib_reinit: successful, ia_address %s, conn_qual %016llu\n",
375	    dapls_inet_ntop((struct sockaddr *)ep_ptr->param.
376	    remote_ia_address_ptr, addr_buf, 64),
377	    ep_ptr->param.remote_port_qual);
378}
379
380
381/*
382 * dapl_ib_setup_conn_listener
383 *
384 * Have the CM set up a connection listener.
385 *
386 * Input:
387 *        ibm_hca_handle           HCA handle
388 *        qp_handle                QP handle
389 *
390 * Output:
391 *        none
392 *
393 * Returns:
394 *        DAT_SUCCESS
395 *        DAT_INSUFFICIENT_RESOURCES
396 *        DAT_INVALID_PARAMETER
397 *
398 */
399DAT_RETURN
400dapls_ib_setup_conn_listener(IN DAPL_IA *ia_ptr,
401    IN DAT_UINT64 ServiceID, IN DAPL_SP *sp_ptr)
402{
403	ib_hca_handle_t hca_hdl = ia_ptr->hca_ptr->ib_hca_handle;
404	struct dapls_ib_cm_srvc_handle *srvc_hdl;
405	dapl_service_register_t args;
406	struct sockaddr *s;
407	char addr_buf[64];
408	DAPL_EVD *evd_p = (DAPL_EVD *)sp_ptr->evd_handle;
409	int retval;
410
411	if (hca_hdl == NULL) {
412		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
413		    "setup_conn_listener: hca_handle == NULL\n");
414		return (DAT_INVALID_PARAMETER);
415	}
416	if (evd_p == NULL) {
417		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
418		    "setup_conn_listener: evd_p == NULL\n");
419		return (DAT_INVALID_PARAMETER);
420	}
421	srvc_hdl = (struct dapls_ib_cm_srvc_handle *)
422	    dapl_os_alloc(sizeof (*srvc_hdl));
423	if (srvc_hdl == NULL) {
424		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
425		    "setup_conn_listener: srvc_handle == NULL\n");
426		return (DAT_INSUFFICIENT_RESOURCES);
427	}
428
429	args.sr_sid = ServiceID;
430	args.sr_evd_hkey = evd_p->ib_cq_handle->evd_hkey;
431	args.sr_sp_cookie = (uintptr_t)sp_ptr;
432
433	retval = ioctl(hca_hdl->ia_fd, DAPL_SERVICE_REGISTER, &args);
434	if (retval != 0) {
435		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
436		    "setup_conn_listener: register failed %s\n",
437		    strerror(errno));
438		dapl_os_free(srvc_hdl, sizeof (*srvc_hdl));
439		return (dapls_convert_error(errno, retval));
440	}
441	srvc_hdl->sv_sp_hkey = args.sr_sp_hkey;
442	sp_ptr->cm_srvc_handle = srvc_hdl;
443	sp_ptr->conn_qual = args.sr_retsid;
444
445	s = (struct sockaddr *)&ia_ptr->hca_ptr->hca_address;
446	dapl_dbg_log(DAPL_DBG_TYPE_CM,
447	    "setup_conn_listener: listening on ia_address %s, "
448	    "conn_qual %016llu\n\n", dapls_inet_ntop(s, addr_buf, 64),
449	    sp_ptr->conn_qual);
450	return (DAT_SUCCESS);
451}
452
453/*
454 * dapl_ib_remove_conn_listener
455 *
456 * Have the CM remove a connection listener.
457 *
458 * Input:
459 *      ia_handle               IA handle
460 *      ServiceID               IB Channel Service ID
461 *
462 * Output:
463 *      none
464 *
465 * Returns:
466 *      DAT_SUCCESS
467 *      DAT_INVALID_PARAMETER
468 *
469 */
470DAT_RETURN
471dapls_ib_remove_conn_listener(IN DAPL_IA *ia_ptr, IN DAPL_SP *sp_ptr)
472{
473	ib_hca_handle_t hca_hdl = ia_ptr->hca_ptr->ib_hca_handle;
474	struct dapls_ib_cm_srvc_handle *srvc_hdl;
475	dapl_service_deregister_t args;
476	struct sockaddr *s;
477	char addr_buf[64];
478	int retval;
479
480	if (hca_hdl == NULL) {
481		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
482		    "remove_conn_listener: hca_handle == NULL\n");
483		return (DAT_INVALID_PARAMETER);
484	}
485	srvc_hdl = (struct dapls_ib_cm_srvc_handle *)sp_ptr->
486	    cm_srvc_handle;
487
488	args.sdr_sp_hkey = srvc_hdl->sv_sp_hkey;
489	retval = ioctl(hca_hdl->ia_fd, DAPL_SERVICE_DEREGISTER, &args);
490	if (retval != 0) {
491		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
492		    "remove_conn_listener: deregister failed %s\n",
493		    strerror(errno));
494		return (dapls_convert_error(errno, retval));
495	}
496	dapl_os_free(srvc_hdl, sizeof (*srvc_hdl));
497	sp_ptr->cm_srvc_handle = NULL;
498
499	s = (struct sockaddr *)&ia_ptr->hca_ptr->hca_address;
500	dapl_dbg_log(DAPL_DBG_TYPE_CM,
501	    "remove_conn_listener: successful, ia_address %s, "
502	    "conn_qual %016llu\n\n", dapls_inet_ntop(s, addr_buf, 64),
503	    sp_ptr->conn_qual);
504	return (DAT_SUCCESS);
505}
506
507/*
508 * dapls_ib_reject_connection
509 *
510 * Perform necessary steps to reject a connection
511 *
512 * Input:
513 *        cr_handle
514 *
515 * Output:
516 *        none
517 *
518 * Returns:
519 *        DAT_SUCCESS
520 *        DAT_INSUFFICIENT_RESOURCES
521 *        DAT_INVALID_PARAMETER
522 *
523 */
524DAT_RETURN
525dapls_ib_reject_connection(IN ib_cm_handle_t cm_handle,
526    IN int reject_reason, IN DAPL_SP *sp_ptr)
527{
528	dapl_cr_reject_t args;
529	int retval;
530
531	args.crr_reason = reject_reason;
532	args.crr_bkl_cookie = (uint64_t)cm_handle;
533	args.crr_sp_hkey = sp_ptr->cm_srvc_handle->sv_sp_hkey;
534
535	dapl_dbg_log(DAPL_DBG_TYPE_CM,
536	    "dapls_ib_reject: fd %d, sp_hkey %016llx, bkl_index 0x%llx\n",
537	    sp_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
538	    args.crr_sp_hkey, args.crr_bkl_cookie);
539
540	retval = ioctl(sp_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
541	    DAPL_CR_REJECT, &args);
542	if (retval != 0) {
543		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
544		    "dapls_ib_reject: reject failed %s\n",
545		    strerror(errno));
546		return (dapls_convert_error(errno, retval));
547	}
548	return (DAT_SUCCESS);
549}
550
551
552/*
553 * dapls_ib_accept_connection
554 *
555 * Perform necessary steps to accept a connection
556 *
557 * Input:
558 *        cr_handle
559 *        ep_handle
560 *        private_data_size
561 *        private_data
562 *
563 * Output:
564 *        none
565 *
566 * Returns:
567 *        DAT_SUCCESS
568 *        DAT_INSUFFICIENT_RESOURCES
569 *        DAT_INVALID_PARAMETER
570 *
571 */
572DAT_RETURN
573dapls_ib_accept_connection(IN DAT_CR_HANDLE cr_handle,
574    IN DAT_EP_HANDLE ep_handle, IN DAPL_PRIVATE *prd_ptr)
575{
576	DAPL_EP		*ep_p = (DAPL_EP *)ep_handle;
577	DAPL_CR		*cr_p = (DAPL_CR *)cr_handle;
578	dapl_cr_accept_t	args;
579	int			retval;
580
581	/* check if ep is valid */
582	if (ep_p->qp_handle == NULL) {
583		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
584		    "dapls_ib_accept: qp_handle == NULL\n");
585		return (DAT_INVALID_PARAMETER);
586	}
587
588	dapl_dbg_log(DAPL_DBG_TYPE_CM,
589	    "dapls_ib_accept: fd %d, sp_hkey %016llx, "
590	    "bkl_index 0x%llx, ep_hkey %016llx\n",
591	    cr_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
592	    cr_p->sp_ptr->cm_srvc_handle->sv_sp_hkey,
593	    (uint64_t)cr_p->ib_cm_handle, ep_p->qp_handle->ep_hkey);
594
595	args.cra_bkl_cookie = (uint64_t)cr_p->ib_cm_handle;
596	args.cra_sp_hkey = cr_p->sp_ptr->cm_srvc_handle->sv_sp_hkey;
597	args.cra_ep_hkey = ep_p->qp_handle->ep_hkey;
598
599	args.cra_priv_sz = IB_MAX_REP_PDATA_SIZE;
600	bcopy(prd_ptr, args.cra_priv, IB_MAX_REP_PDATA_SIZE);
601
602	retval = ioctl(cr_p->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
603	    DAPL_CR_ACCEPT, &args);
604	if (retval != 0) {
605		ep_p->qp_state = IBT_STATE_ERROR;
606		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
607		    "dapls_ib_accept: accept failed %s\n",
608		    strerror(errno));
609		return (dapls_convert_error(errno, retval));
610	}
611	return (DAT_SUCCESS);
612}
613/*
614 * dapls_ib_cm_remote_addr
615 *
616 * Obtain the remote IP address given a connection
617 *
618 * Input:
619 *      cr_handle
620 *      private data structure handle (only for IBHOSTS_NAMING)
621 *
622 * Output:
623 *      remote_ia_address: where to place the remote address
624 *
625 * Returns:
626 *      DAT_SUCCESS
627 *      DAT_INSUFFICIENT_RESOURCES
628 *      DAT_INVALID_PARAMETER
629 *
630 */
631/* ARGSUSED */
632DAT_RETURN
633dapls_ib_cm_remote_addr(
634	IN DAT_HANDLE	dat_handle,
635	IN DAPL_PRIVATE	*prd_ptr,
636	OUT DAT_SOCK_ADDR6 *remote_ia_address)
637{
638	return (DAT_SUCCESS);
639}
640
641
642/*
643 * dapls_ib_handoff_connection
644 *
645 * handoff connection to a different qualifier
646 *
647 * Input:
648 *        cr_ptr
649 *        cr_handoff
650 *
651 * Output:
652 *        none
653 *
654 * Returns:
655 *        DAT_SUCCESS
656 *        DAT_INSUFFICIENT_RESOURCES
657 *        DAT_INVALID_PARAMETER
658 *
659 */
660DAT_RETURN
661dapls_ib_handoff_connection(IN DAPL_CR *cr_ptr, IN DAT_CONN_QUAL cr_handoff)
662{
663	dapl_cr_handoff_t args;
664	int retval;
665
666	dapl_dbg_log(DAPL_DBG_TYPE_CM,
667	    "dapls_ib_handoff: fd %d, sp_hkey %016llx, "
668	    "bkl_index 0x%llx conn_qual %llu\n",
669	    cr_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
670	    cr_ptr->sp_ptr->cm_srvc_handle->sv_sp_hkey,
671	    (uint64_t)cr_ptr->ib_cm_handle, cr_handoff);
672
673	args.crh_bkl_cookie = (uint64_t)cr_ptr->ib_cm_handle;
674	args.crh_sp_hkey = cr_ptr->sp_ptr->cm_srvc_handle->sv_sp_hkey;
675	args.crh_conn_qual = cr_handoff;
676
677	retval = ioctl(cr_ptr->header.owner_ia->hca_ptr->ib_hca_handle->ia_fd,
678	    DAPL_CR_HANDOFF, &args);
679	if (retval != 0) {
680		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
681		    "dapls_ib_handoff: failed %s\n", strerror(errno));
682		return (dapls_convert_error(errno, retval));
683	}
684	return (DAT_SUCCESS);
685}
686