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) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 * IB specific routines for RDMA CM functionality
28 */
29/* Standard driver includes */
30#include <sys/types.h>
31#include <sys/modctl.h>
32#include <sys/errno.h>
33#include <sys/stat.h>
34
35#include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
36#include <sys/ib/clients/of/ofed_kernel.h>
37#include <sys/ib/clients/of/rdma/ib_addr.h>
38#include <sys/ib/clients/of/rdma/rdma_cm.h>
39
40#include <sys/ib/clients/of/sol_ofs/sol_cma.h>
41#include <sys/ib/clients/of/sol_ofs/sol_ib_cma.h>
42
43extern char 	*sol_rdmacm_dbg_str;
44
45/* Delay of 5 secs */
46#define	SOL_OFS_REQ_DELAY	5000000
47
48/* Default Qkey used for IPoIB. */
49#define	SOL_IPOIB_DEFAULT_QKEY	0xB1B
50
51/*	Solaris CM Event Callbacks 	*/
52static ibt_cm_status_t ibcma_rc_hdlr(void *, ibt_cm_event_t *,
53    ibt_cm_return_args_t *, void *, ibt_priv_data_len_t);
54static ibt_cm_status_t ibcma_ud_hdlr(void *, ibt_cm_ud_event_t *,
55    ibt_cm_ud_return_args_t *, void *, ibt_priv_data_len_t);
56static void ibcma_multicast_hdlr(void *, ibt_status_t, ibt_mcg_info_t *);
57
58/*	Local functions 	*/
59static int ibcma_tcp_connect(struct rdma_cm_id *, ibcma_chan_t *,
60    struct rdma_conn_param *);
61static int ibcma_udp_connect(struct rdma_cm_id *, ibcma_chan_t *,
62    struct rdma_conn_param *);
63static struct rdma_cm_id *ibcma_create_new_id(struct rdma_cm_id *);
64static int ibcma_query_local_ip(struct rdma_cm_id *, sol_cma_chan_t *,
65    ibcma_chan_t *);
66static int ibcma_get_paths(struct rdma_cm_id *, sol_cma_chan_t *,
67    ibcma_chan_t *);
68static void ibcma_get_devlist(sol_cma_chan_t *, ib_guid_t *, int,
69    genlist_t *, boolean_t);
70static int ibcma_any_addr(ibt_ip_addr_t *);
71static int ibcma_get_first_ib_ipaddr(struct rdma_cm_id *);
72
73/* Utility Conversion Routines */
74static void 	ipaddr2mgid(struct sockaddr *, ib_gid_t *, ib_pkey_t);
75static void 	ibt_path2ah(ibt_path_info_t *, struct ib_ah_attr *);
76static void	ibt_addsvect2ah(ibt_adds_vect_t *, struct ib_ah_attr *);
77static void	ibt_addsvect2sa_path(ibt_adds_vect_t *,
78    struct ib_sa_path_rec *, ib_lid_t);
79static void	ibt_path2sa_path(ibt_path_info_t *, struct ib_sa_path_rec *,
80    ib_lid_t);
81static void 	mcginfo2ah(ibt_mcg_info_t *, struct ib_ah_attr *);
82static void	sockaddr2ibtaddr_port(struct rdma_cm_id *, struct sockaddr *,
83    ibt_ip_addr_t *, in_port_t *);
84static void ipaddr2sockaddr(ibt_ip_addr_t *, struct sockaddr *,
85    in_port_t *);
86
87#ifdef	QP_DEBUG
88static void 	dump_qp_info(ibt_qp_hdl_t);
89#endif
90static void	dump_priv_data(void *, ibt_priv_data_len_t,
91    ibt_priv_data_len_t, char *);
92
93extern cma_chan_state_t cma_get_chan_state(sol_cma_chan_t *);
94
95/*
96 * RDMA CM API - Transport specific functions
97 */
98void
99rdma_ib_destroy_id(struct rdma_cm_id *idp)
100{
101	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)idp;
102	ibcma_chan_t		*ibchanp;
103	ibt_status_t		status;
104
105	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_destroy_id(%p)", idp);
106	ASSERT(chanp);
107	ibchanp = &(chanp->chan_ib);
108
109	if (ibchanp->chan_mcast_cnt) {
110		genlist_entry_t	*entry;
111		ibcma_mcast_t	*ibmcastp;
112		ib_gid_t	zero_gid;
113
114		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
115		    "rdma_ib_destroy_id: pending mcast!!");
116		entry = remove_genlist_head(&ibchanp->chan_mcast_list);
117		while (entry) {
118			ibmcastp = (ibcma_mcast_t *)entry->data;
119
120			bzero(&zero_gid, sizeof (ib_gid_t));
121			status = ibt_leave_mcg(ibchanp->chan_devp->dev_sgid,
122			    ibmcastp->mcast_gid, zero_gid, IB_MC_JSTATE_FULL);
123			if (status != IBT_SUCCESS)
124				SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
125				    "destroy_id: ibt_leave_mcg failed %d",
126				    status);
127			kmem_free(ibmcastp, sizeof (ibcma_mcast_t));
128
129			entry = remove_genlist_head(&ibchanp->chan_mcast_list);
130		}
131	}
132	if (ibchanp->chan_devp) {
133		kmem_free(ibchanp->chan_devp, sizeof (ibcma_dev_t));
134		ibchanp->chan_devp = NULL;
135	}
136	if (ibchanp->chan_pathp) {
137		kmem_free(ibchanp->chan_pathp, ibchanp->chan_path_size);
138		ibchanp->chan_pathp = NULL;
139	}
140
141	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_destroy_id: return");
142}
143
144int
145rdma_ib_bind_addr(struct rdma_cm_id *idp, struct sockaddr *addr)
146{
147	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)idp;
148	ibcma_chan_t	*ibchanp;
149	int		ret;
150	in_port_t	port;
151
152	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_bind_addr(%p, %p)",
153	    idp, addr);
154	ASSERT(chanp);
155	ibchanp = &(chanp->chan_ib);
156
157	sockaddr2ibtaddr_port(idp, addr, &ibchanp->chan_local_addr, &port);
158	ibchanp->chan_addr_flag = IBCMA_LOCAL_ADDR_SET_FLAG;
159
160	/*
161	 * If this is IF_ADDR_ANY, get info of IB port with IP @.
162	 * Return Failure, if there are no IB ports with IP @.
163	 */
164	if (sol_cma_any_addr(addr)) {
165		ibchanp->chan_port = port;
166		ibchanp->chan_addr_flag |= IBCMA_LOCAL_ADDR_IFADDRANY;
167		return (0);
168	}
169
170	ret = ibcma_query_local_ip(idp, chanp, ibchanp);
171	if (ret == 0) {
172		init_genlist(&ibchanp->chan_mcast_list);
173		ibchanp->chan_sid = ibt_get_ip_sid(idp->ps, port);
174		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
175		    "chan SID %llx , ps %x, port %x",
176		    ibchanp->chan_sid, idp->ps, port);
177		ibchanp->chan_port = port;
178		chanp->chan_xport_type = SOL_CMA_XPORT_IB;
179	}
180	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_bind_addr: return %x",
181	    ret);
182	return (ret);
183}
184
185extern void cma_resolve_addr_callback(sol_cma_chan_t *, int);
186int
187rdma_ib_resolve_addr(struct rdma_cm_id *idp, struct sockaddr *src_addr,
188    struct sockaddr *dst_addr, int timeout_ms)
189{
190	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)idp;
191	ibcma_chan_t	*ibchanp;
192	int		ret;
193	in_port_t	port;
194	in_addr_t	remote_addr;
195
196	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_resolve_addr("
197	    "%p, %p, %p, %x)", idp, src_addr, dst_addr, timeout_ms);
198	ASSERT(chanp);
199	ibchanp = &(chanp->chan_ib);
200
201	/*
202	 * Copy src_addr if the passed src @ is valid IP address and
203	 * the local @ has not been set for this CMID.
204	 */
205	if ((ibchanp->chan_addr_flag & IBCMA_LOCAL_ADDR_SET_FLAG) == 0 &&
206	    IS_VALID_SOCKADDR(src_addr)) {
207		sockaddr2ibtaddr_port(idp, src_addr, &ibchanp->chan_local_addr,
208		    &port);
209		ibchanp->chan_addr_flag |= IBCMA_LOCAL_ADDR_SET_FLAG;
210		if (port) {
211			ibchanp->chan_sid = ibt_get_ip_sid(idp->ps, port);
212			SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_addr, "
213			    "local @ SID %llx, ps %x, port %x",
214			    ibchanp->chan_sid, idp->ps, port);
215			ibchanp->chan_port = port;
216		}
217	}
218
219	sockaddr2ibtaddr_port(idp, dst_addr, &ibchanp->chan_remote_addr,
220	    &port);
221	ibchanp->chan_addr_flag |= IBCMA_REMOTE_ADDR_SET_FLAG;
222	if (ibchanp->chan_sid == 0) {
223		ASSERT(!sol_cma_any_addr(dst_addr));
224		ibchanp->chan_sid = ibt_get_ip_sid(idp->ps, port);
225		ibchanp->chan_port = port;
226		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_addr, remote @ "
227		    "SID %llx , ps %x, port %x", ibchanp->chan_sid,
228		    idp->ps, port);
229		init_genlist(&ibchanp->chan_mcast_list);
230	}
231
232	/*
233	 * Return SUCCESS if remote address is a MCAST address
234	 * and local address is not IF_ADDR_ANY. If local_addr
235	 * is IF_ADDR_ANY and remote is MCAST, return FAILURE.
236	 */
237	remote_addr = htonl((ibchanp->chan_remote_addr).un.ip4addr);
238	if ((ibchanp->chan_remote_addr).family == AF_INET &&
239	    (remote_addr >= 0xE0000000 && remote_addr <= 0xEFFFFFFF)) {
240		if (ibchanp->chan_devp) {
241			SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
242			    "ib_resolve_addr - mcast dest @, local IP");
243			(idp->route).num_paths = 0;
244			ret = 0;
245		} else {
246			ret = ibcma_get_first_ib_ipaddr(idp);
247		}
248
249		if (ret == 0 && idp->device == NULL)
250			idp->device = sol_cma_acquire_device(ntohll(
251			    ibchanp->chan_devp->dev_node_guid));
252
253		cma_resolve_addr_callback(chanp, 0);
254		return (0);
255	}
256
257	if ((ret = ibcma_get_paths(idp, chanp, ibchanp)) == 0)
258		chanp->chan_xport_type = SOL_CMA_XPORT_IB;
259
260	return (ret);
261}
262
263/*
264 * Linux OFED implementation is as below :
265 *	1. librdmacm sends INIT_QP_ATTR command to get QP attributes
266 *	   which the kernel CM expects QP attribute to be in. Kernel
267 *	   CM sets the QP attribute to be set and passes it back to
268 *	   user library.
269 *	2. librdmacm calls ibv_modify_qp() to modify the QP attribute.
270 *         The QP attribute used is the same as the that passed by
271 *		   kernel sol_ucma.
272 *
273 * For RC connections, Solaris ibcm manages the QP state after :
274 *	CM Event Handler is called	- Passive side
275 *	ibv_open_rc_channel(9f)  	- Active Side
276 * The client will *not* have to do an explcit modify_qp(). To fit this
277 * INIT_QP_ATTR commands *marks* the QP to fake it's attributes and
278 * ignore ibv_modify_qp() for this QP. Solaris ibcm manages QP state.
279 *
280 * Before the above calls, the client will have to maintain the QP state.
281 * The sol_ucma driver will pass the appropriate QP atrributes, for the
282 * clients to pass to ibv_modify_qp().
283 *
284 * For UD, OFED model is adhered to till the QP is transitioned to RTS.
285 * Any transitions after the QP has transitioned to RTS are ignored.
286 */
287int
288rdma_ib_init_qp_attr(struct rdma_cm_id *idp, struct ib_qp_attr *qpattr,
289    int *qp_attr_mask)
290{
291	sol_cma_chan_t	*chanp;
292	ibcma_chan_t	*ibchanp;
293	ibcma_dev_t	*devp;
294	uint32_t	qpstate;
295
296	ASSERT(idp);
297	chanp = (sol_cma_chan_t *)idp;
298	ibchanp = &chanp->chan_ib;
299	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_init_qp_attr("
300	    "%p, %p, %p)", idp, qpattr, qp_attr_mask);
301
302	if (ibchanp->chan_qpmodifyflag == 1) {
303		SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str,
304		    "Ignoring Init QP Attr");
305		return (0);
306	}
307
308	qpstate = qpattr->qp_state;
309	bzero(qpattr, sizeof (struct ib_qp_attr));
310	qpattr->qp_state = qpstate;
311
312	devp = ibchanp->chan_devp;
313	if (devp == NULL) {
314		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
315		    "init_qp_attr, devp NULL");
316		return (EINVAL);
317	}
318	qpattr->pkey_index = devp->dev_pkey_ix;
319	qpattr->port_num = devp->dev_port_num;
320
321	if (idp->ps == RDMA_PS_TCP && qpstate == IB_QPS_INIT) {
322		qpattr->qp_access_flags = IB_ACCESS_REMOTE_WRITE |
323		    IB_ACCESS_REMOTE_READ;
324		*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT |
325		    IB_QP_ACCESS_FLAGS;
326		return (0);
327	} else if (idp->ps == RDMA_PS_TCP &&
328	    qpstate == IB_QPS_RTR) {
329		*qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU  |
330		    IB_QP_DEST_QPN | IB_QP_RQ_PSN |
331		    IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER;
332		/*
333		 * Fill in valid values for address vector & Remote QPN.
334		 * Fill in MTU from REQ data.
335		 */
336		ibt_addsvect2ah(&ibchanp->chan_rcreq_addr, &qpattr->ah_attr);
337		qpattr->path_mtu = (uint32_t)
338		    ((ibchanp->chan_rtr_data).req_path_mtu);
339		qpattr->dest_qp_num = ibchanp->chan_rcreq_qpn;
340		qpattr->rq_psn = (ibchanp->chan_rtr_data).req_rq_psn;
341		qpattr->max_dest_rd_atomic = ibchanp->chan_rcreq_ra_in;
342		qpattr->min_rnr_timer =
343		    (ibchanp->chan_rtr_data).req_rnr_nak_time;
344		return (0);
345	} else if (IS_UDP_CMID(idp)) {
346		if (idp->ps == RDMA_PS_UDP)
347			qpattr->qkey = RDMA_UDP_QKEY;
348		else
349			qpattr->qkey = SOL_IPOIB_DEFAULT_QKEY;
350		*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX |
351		    IB_QP_PORT | IB_QP_QKEY;
352		return (0);
353	} else
354		return (EINVAL);
355}
356
357int
358rdma_ib_connect(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param)
359{
360	sol_cma_chan_t	*chanp;
361	ibcma_chan_t	*ibchanp;
362	int		ret;
363
364	ASSERT(idp);
365	chanp = (sol_cma_chan_t *)idp;
366	ibchanp = &chanp->chan_ib;
367	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_connect(%p, %p)", idp,
368	    conn_param);
369
370	ASSERT(chanp->chan_xport_type == SOL_CMA_XPORT_IB);
371	if (ibchanp->chan_devp == NULL || ibchanp->chan_pathp == NULL) {
372		SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, "rdma_ib_connect : "
373		    "invalid IP @");
374		return (EINVAL);
375	}
376	ASSERT(ibchanp->chan_devp);
377
378	ibchanp->chan_qpmodifyflag  = 1;
379	if (idp->ps == RDMA_PS_TCP)
380		ret = ibcma_tcp_connect(idp, ibchanp, conn_param);
381	else
382		ret = ibcma_udp_connect(idp, ibchanp, conn_param);
383
384	return (ret);
385}
386
387extern void sol_cma_add_hca_list(sol_cma_chan_t *, ib_guid_t);
388void
389ibcma_append_listen_list(struct rdma_cm_id  *root_idp)
390{
391	int			num_hcas;
392	ib_guid_t		*hca_guidp;
393	struct rdma_cm_id	*ep_idp;
394	sol_cma_chan_t		*root_chanp, *ep_chanp;
395	ibcma_chan_t		*root_ibchanp, *ep_ibchanp;
396	genlist_t		dev_genlist;
397	genlist_entry_t		*entry;
398
399	sol_cma_listen_info_t	*listenp;
400	ibcma_dev_t		*devp;
401
402	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "append_listen(%p)", root_idp);
403	root_chanp = (sol_cma_chan_t *)root_idp;
404	root_ibchanp = &root_chanp->chan_ib;
405
406	/*
407	 * Address other than IF_ADDR_ANY bound to this channel. Listen on
408	 * this IP address alone.
409	 */
410	if (root_ibchanp->chan_devp &&
411	    (root_ibchanp->chan_addr_flag & IBCMA_LOCAL_ADDR_IFADDRANY) == 0) {
412		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "Create listen chan");
413		ep_idp = ibcma_create_new_id(root_idp);
414		ASSERT(ep_idp);
415
416		ep_chanp = (sol_cma_chan_t *)ep_idp;
417		listenp = kmem_zalloc(sizeof (sol_cma_listen_info_t),
418		    KM_SLEEP);
419		ep_chanp->chan_listenp = listenp;
420
421		ep_ibchanp = &ep_chanp->chan_ib;
422		ep_ibchanp->chan_port = root_ibchanp->chan_port;
423		listenp->listen_ep_root_entry = add_genlist(
424		    &(CHAN_LISTEN_LIST(root_chanp)),
425		    (uintptr_t)ep_idp, root_idp);
426		devp = ep_ibchanp->chan_devp;
427		sol_cma_add_hca_list(ep_chanp, ntohll(devp->dev_node_guid));
428		return;
429	}
430
431	/*
432	 * Get the list of IB devs with valid IP addresses
433	 * Append to the list of listeners for root_idp
434	 */
435	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "Search IP @");
436	num_hcas = ibt_get_hca_list(&hca_guidp);
437	ibcma_get_devlist(root_chanp, hca_guidp, num_hcas,
438	    &dev_genlist, B_FALSE);
439	entry = remove_genlist_head(&dev_genlist);
440	while (entry) {
441		devp = (ibcma_dev_t *)(entry->data);
442		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
443		    "Create listen chan- ALL");
444		ep_idp = ibcma_create_new_id(root_idp);
445		ASSERT(ep_idp);
446
447		ep_chanp = (sol_cma_chan_t *)ep_idp;
448		ep_chanp->chan_xport_type = SOL_CMA_XPORT_IB;
449		ipaddr2sockaddr(&devp->dev_ipaddr,
450		    &(ep_idp->route.addr.src_addr), NULL);
451		listenp = kmem_zalloc(sizeof (sol_cma_listen_info_t),
452		    KM_SLEEP);
453		ep_chanp->chan_listenp = listenp;
454
455		ep_ibchanp = &ep_chanp->chan_ib;
456		ASSERT(ep_ibchanp->chan_devp == NULL);
457		ep_ibchanp->chan_devp = devp;
458		ep_ibchanp->chan_port = root_ibchanp->chan_port;
459
460		listenp->listen_ep_root_entry = add_genlist(
461		    &(CHAN_LISTEN_LIST(root_chanp)),
462		    (uintptr_t)ep_idp, root_idp);
463		sol_cma_add_hca_list(ep_chanp, ntohll(devp->dev_node_guid));
464		kmem_free(entry, sizeof (genlist_entry_t));
465		entry = remove_genlist_head(&dev_genlist);
466	}
467	ibt_free_hca_list(hca_guidp, num_hcas);
468}
469
470int
471ibcma_init_root_chan(sol_cma_chan_t *root_chanp, sol_cma_glbl_listen_t *listenp)
472{
473	ibcma_chan_t		*root_ibchanp;
474	ibt_srv_desc_t		service;
475	ibt_status_t		status;
476	struct rdma_cm_id	*root_idp;
477
478	root_idp = &(root_chanp->chan_rdma_cm);
479	root_ibchanp = &root_chanp->chan_ib;
480
481	if (root_idp->ps == RDMA_PS_TCP)
482		service.sd_handler = ibcma_rc_hdlr;
483	else
484		service.sd_ud_handler = ibcma_ud_hdlr;
485	service.sd_flags = IBT_SRV_NO_FLAGS;
486	status = ibt_register_service(root_chanp->chan_ib_client_hdl,
487	    &service, root_ibchanp->chan_sid,
488	    root_ibchanp->chan_port ? 1 : 0xffff,
489	    &((root_chanp->chan_listenp)->listen_ib_srv_hdl),
490	    NULL);
491	if (status != IBT_SUCCESS) {
492		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
493		    "init_root_chan: ibt_register_service ret %x"
494		    "SID %x, port %x", status, root_ibchanp->chan_sid,
495		    root_ibchanp->chan_port);
496		return (EINVAL);
497	}
498	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "init_root_chan: "
499	    "ibt_register_service: SID %x, port %x: done",
500	    root_ibchanp->chan_sid, root_ibchanp->chan_port);
501	listenp->cma_listen_svc_hdl =
502	    (void *)(root_chanp->chan_listenp)->listen_ib_srv_hdl;
503	return (0);
504}
505
506int
507ibcma_fini_root_chan(sol_cma_chan_t *rchanp)
508{
509	ibt_status_t	status;
510
511	status = ibt_deregister_service(rchanp->chan_ib_client_hdl,
512	    (rchanp->chan_listenp)->listen_ib_srv_hdl);
513	if (status != IBT_SUCCESS) {
514		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
515		    "fini_root_chan: ibt_deregister_service ret %x",
516		    status);
517		return (EINVAL);
518	}
519	return (0);
520}
521
522void
523ibcma_copy_srv_hdl(sol_cma_chan_t *root_chanp, sol_cma_glbl_listen_t *listenp)
524{
525	(root_chanp->chan_listenp)->listen_ib_srv_hdl =
526	    (ibt_srv_hdl_t)listenp->cma_listen_svc_hdl;
527}
528
529int
530ibcma_fini_ep_chan(sol_cma_chan_t *ep_chanp)
531{
532	struct rdma_cm_id	*root_idp;
533	sol_cma_chan_t		*root_chanp;
534	sol_cma_listen_info_t	*root_listenp, *ep_listenp;
535	ibt_status_t		status;
536	ibcma_chan_t		*ep_ibchanp = &ep_chanp->chan_ib;
537
538	ASSERT(ep_chanp);
539	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
540	    "fini_ep_chan(%p)", ep_chanp);
541	root_idp  = CHAN_LISTEN_ROOT(ep_chanp);
542	root_chanp = (sol_cma_chan_t *)root_idp;
543	root_listenp = root_chanp->chan_listenp;
544	ep_listenp = ep_chanp->chan_listenp;
545
546	if (ep_ibchanp->chan_devp)
547		kmem_free(ep_ibchanp->chan_devp, sizeof (ibcma_dev_t));
548	if (ep_ibchanp->chan_pathp)
549		kmem_free(ep_ibchanp->chan_pathp,
550		    ep_ibchanp->chan_path_size);
551
552	if (!ep_listenp->listen_ib_sbind_hdl)
553		return (0);
554	status = ibt_unbind_service(root_listenp->listen_ib_srv_hdl,
555	    ep_listenp->listen_ib_sbind_hdl);
556	if (status != IBT_SUCCESS) {
557		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
558		    "fini_ep_chan(%p) : ibt_unbind_service() ret %d",
559		    status);
560		return (-1);
561	}
562
563	return (0);
564}
565
566uint64_t
567ibcma_init_root_sid(sol_cma_chan_t *root_chanp)
568{
569	ibcma_chan_t		*root_ibchanp;
570	struct rdma_cm_id	*root_idp;
571
572	root_ibchanp = &root_chanp->chan_ib;
573	root_idp = (struct rdma_cm_id *)root_chanp;
574	if (root_ibchanp->chan_sid == 0) {
575		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "listen No SID : ps %x",
576		    root_idp->ps);
577		root_ibchanp->chan_sid = ibt_get_ip_sid(root_idp->ps,
578		    root_ibchanp->chan_port);
579		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "chan SID %llx , ps %x, "
580		    "port %x", root_ibchanp->chan_sid, root_idp->ps,
581		    root_ibchanp->chan_port);
582	}
583	return ((uint64_t)root_ibchanp->chan_sid);
584}
585
586/*ARGSUSED*/
587int
588rdma_ib_listen(struct rdma_cm_id *ep_idp, int bklog)
589{
590	struct rdma_cm_id	*root_idp;
591	ibcma_chan_t		*ep_ibchanp;
592	sol_cma_chan_t		*root_chanp, *ep_chanp;
593	ibcma_dev_t		*ep_devp;
594	ibt_status_t		status;
595
596	ASSERT(ep_idp);
597	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "ib_listen(%p)", ep_idp);
598	ep_chanp = (sol_cma_chan_t *)ep_idp;
599	root_idp  = CHAN_LISTEN_ROOT(ep_chanp);
600	root_chanp = (sol_cma_chan_t *)root_idp;
601	ep_ibchanp = &ep_chanp->chan_ib;
602
603	ep_devp = ep_ibchanp->chan_devp;
604	ASSERT(ep_devp);
605	status = ibt_bind_service(
606	    (root_chanp->chan_listenp)->listen_ib_srv_hdl,
607	    ep_devp->dev_sgid, NULL, ep_idp,
608	    &((ep_chanp->chan_listenp)->listen_ib_sbind_hdl));
609	if (status != IBT_SUCCESS) {
610		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen_ep: "
611		    "ibt_bind_service failed with %x", status);
612		return (EINVAL);
613	}
614	return (0);
615}
616
617#define	SOL_REP_PRIV_DATA_SZ 208
618int
619rdma_ib_accept(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param)
620{
621	sol_cma_chan_t	*chanp;
622	ibcma_chan_t	*ibchanp;
623	ibt_status_t	status;
624	void		*privp = NULL;
625	uint8_t		priv_len;
626
627	ASSERT(idp);
628	chanp = (sol_cma_chan_t *)idp;
629	ibchanp = &chanp->chan_ib;
630
631	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_accept(%p, %p)",
632	    idp, conn_param);
633	if (chanp->chan_session_id == NULL) {
634		SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str,
635		    "Active side, cm_proceed not needed");
636		return (0);
637	}
638
639	if (!conn_param) {
640		SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, "conn_param NULL");
641		return (0);
642	}
643
644	ibchanp->chan_qpmodifyflag  = 1;
645	if (idp->ps == RDMA_PS_TCP)  {
646		ibt_cm_proceed_reply_t	cm_reply;
647
648		/* Fill cm_reply */
649		cm_reply.rep.cm_channel =
650		    (ibt_channel_hdl_t)chanp->chan_qp_hdl;
651		cm_reply.rep.cm_rdma_ra_out = conn_param->initiator_depth;
652		cm_reply.rep.cm_rdma_ra_in = conn_param->responder_resources;
653		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: "
654		    "init_dept %x, resp_res %x", conn_param->initiator_depth,
655		    conn_param->responder_resources);
656		cm_reply.rep.cm_rnr_retry_cnt = conn_param->rnr_retry_count;
657		priv_len = conn_param->private_data_len;
658		if (priv_len) {
659			privp = (void *)kmem_zalloc(
660			    SOL_REP_PRIV_DATA_SZ, KM_SLEEP);
661			bcopy((void *)conn_param->private_data,
662			    privp, priv_len);
663#ifdef	DEBUG
664			dump_priv_data(privp, SOL_REP_PRIV_DATA_SZ,
665			    conn_param->private_data_len, "ib_accept");
666#endif
667		}
668
669		status = ibt_ofuvcm_proceed(IBT_CM_EVENT_REQ_RCV,
670		    chanp->chan_session_id, IBT_CM_ACCEPT, &cm_reply,
671		    privp, priv_len);
672		if (status != IBT_SUCCESS) {
673			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "ib_accept: "
674			    "ibt_ofuvcm_proceed failed %x", status);
675			if (privp)
676				kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
677			return (EINVAL);
678		}
679		if (privp)
680			kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
681		chanp->chan_session_id = NULL;
682	} else  {
683		ibt_qp_hdl_t	qphdl = chanp->chan_qp_hdl;
684
685		priv_len = conn_param->private_data_len;
686		if (priv_len) {
687			privp = (void *)kmem_zalloc(
688			    SOL_REP_PRIV_DATA_SZ, KM_SLEEP);
689			bcopy((void *)conn_param->private_data,
690			    privp, priv_len);
691#ifdef DEBUG
692			dump_priv_data(privp, SOL_REP_PRIV_DATA_SZ,
693			    conn_param->private_data_len, "ib_accept");
694#endif
695		}
696
697		status = ibt_cm_ud_proceed(chanp->chan_session_id, qphdl,
698		    IBT_CM_ACCEPT, NULL, privp, priv_len);
699		if (status != IBT_SUCCESS) {
700			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "ib_accept: "
701			    "ibt_cm_ud_proceed failed %x", status);
702			if (privp)
703				kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
704			return (EINVAL);
705		}
706
707		if (privp)
708			kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
709	}
710	return (0);
711}
712
713int
714rdma_ib_reject(struct rdma_cm_id *idp, const void *private_data,
715    uint8_t private_data_len)
716{
717	sol_cma_chan_t	*chanp;
718	ibt_status_t	status;
719	void		*privp = NULL;
720
721	ASSERT(idp);
722	chanp = (sol_cma_chan_t *)idp;
723	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
724	    "rdma_ib_reject(%p, %p, %x)", idp,
725	    private_data, private_data_len);
726
727	if (chanp->chan_session_id == NULL) {
728		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_ib_reject :"
729		    "chan_session_id NULL");
730		return (EINVAL);
731	}
732
733	if (private_data_len) {
734		privp = (void *)kmem_zalloc(SOL_REP_PRIV_DATA_SZ,
735		    KM_SLEEP);
736		bcopy((void *)private_data, privp,
737		    private_data_len);
738#ifdef	DEBUG
739		dump_priv_data(privp, SOL_REP_PRIV_DATA_SZ,
740		    private_data_len, "ib_reject");
741#endif
742	}
743
744	if (idp->ps == RDMA_PS_TCP)  {
745		ibt_cm_proceed_reply_t cm_reply;
746
747		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_reject :"
748		    "calling ibt_cm_proceed");
749		status = ibt_cm_proceed(IBT_CM_EVENT_REQ_RCV,
750		    chanp->chan_session_id, IBT_CM_REJECT, &cm_reply,
751		    privp, private_data_len);
752		if (status != IBT_SUCCESS) {
753			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "ib_reject: "
754			    "ibt_cm_proceed failed %x", status);
755			if (privp)
756				kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
757			return (EINVAL);
758		}
759	} else  {
760		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_ib_reject :"
761		    "calling ibt_cm_ud_proceed");
762		status = ibt_cm_ud_proceed(chanp->chan_session_id, NULL,
763		    IBT_CM_REJECT, NULL, privp, private_data_len);
764		if (status != IBT_SUCCESS) {
765			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "ib_reject: "
766			    "ibt_cm_ud_proceed failed %x", status);
767			if (privp)
768				kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
769			return (EINVAL);
770		}
771	}
772
773	if (privp)
774		kmem_free(privp, SOL_REP_PRIV_DATA_SZ);
775	return (0);
776}
777
778int
779rdma_ib_disconnect(struct rdma_cm_id *idp)
780{
781	sol_cma_chan_t		*root_chanp, *chanp;
782	ibt_status_t		status;
783	struct rdma_cm_id	*root_idp;
784
785	ASSERT(idp);
786	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "ib_disconnect(%p)", idp);
787	chanp = (sol_cma_chan_t *)idp;
788
789	root_idp = CHAN_LISTEN_ROOT(chanp);
790	root_chanp = (sol_cma_chan_t *)root_idp;
791	if (!root_chanp)
792		goto handle_close_chan;
793
794	mutex_enter(&chanp->chan_mutex);
795	if (chanp->chan_req_state == REQ_CMID_NOTIFIED ||
796	    chanp->chan_req_state == REQ_CMID_CREATED) {
797		CHAN_LISTEN_ROOT(chanp) = NULL;
798		mutex_exit(&chanp->chan_mutex);
799
800		if (IS_UDP_CMID(idp)) {
801			status = ibt_cm_ud_proceed(chanp->chan_session_id,
802			    NULL, IBT_CM_NO_CHANNEL, NULL, NULL, 0);
803			if (status != IBT_SUCCESS) {
804				SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
805				    "ib_disconnect(%p) Reject for incoming REQ "
806				    "failed, status %d", status);
807				return (EINVAL);
808			}
809		} else {
810			ibt_cm_proceed_reply_t	cm_reply;
811
812			bzero(&cm_reply, sizeof (cm_reply));
813			status = ibt_cm_proceed(IBT_CM_EVENT_REQ_RCV,
814			    chanp->chan_session_id, IBT_CM_REJECT, &cm_reply,
815			    NULL, 0);
816			if (status != IBT_SUCCESS) {
817				SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
818				    "ib_disconnect(%p) Reject for incoming REQ "
819				    "failed, status %d", status);
820				return (EINVAL);
821			}
822		}
823		mutex_enter(&root_chanp->chan_mutex);
824		mutex_enter(&chanp->chan_mutex);
825		if (REQ_CMID_IN_REQ_AVL_TREE(chanp)) {
826			ASSERT(cma_get_req_idp(root_idp,
827			    chanp->chan_session_id));
828			avl_remove(&root_chanp->chan_req_avl_tree, idp);
829			chanp->chan_req_state = REQ_CMID_SERVER_NONE;
830		}
831		mutex_exit(&chanp->chan_mutex);
832		mutex_exit(&root_chanp->chan_mutex);
833	} else
834		mutex_exit(&chanp->chan_mutex);
835
836handle_close_chan :
837	/*
838	 * Close RC channel for RC.
839	 * No explicit Disconnect required for UD
840	 */
841	mutex_enter(&chanp->chan_mutex);
842	if (idp->ps == RDMA_PS_TCP && chanp->chan_qp_hdl &&
843	    SOL_CMID_CLOSE_REQUIRED(chanp)) {
844		ibt_execution_mode_t	mode;
845		void			*qp_hdl = chanp->chan_qp_hdl;
846
847
848		/*
849		 * No callbacks for CMIDs for which destroy_id() has
850		 * been called.
851		 */
852		mode = (chanp->chan_cmid_destroy_state &
853		    SOL_CMA_CALLER_CMID_DESTROYED) ? IBT_NOCALLBACKS :
854		    IBT_BLOCKING;
855		mutex_exit(&chanp->chan_mutex);
856		status = ibt_close_rc_channel(qp_hdl,
857		    mode, NULL, 0, NULL, NULL, NULL);
858		if (status != IBT_SUCCESS) {
859			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
860			    "disconnect: close_rc_channel failed %x",
861			    status);
862			return (EINVAL);
863		}
864	} else
865		mutex_exit(&chanp->chan_mutex);
866
867	return (0);
868}
869
870int
871rdma_ib_join_multicast(struct rdma_cm_id *idp, struct sockaddr *addr,
872    void *context)
873{
874	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)idp;
875	ibcma_chan_t	*ibchanp;
876	ibt_mcg_attr_t	mcg_attr;
877	ibt_ip_addr_t	mcast_addr;
878	ibt_mcg_info_t	*mcg_infop;
879	ibt_status_t	status;
880	ib_gid_t	mcast_gid, mcast_gid_horder;
881	ibcma_dev_t	*devp;
882	ibcma_mcast_t	*ibmcastp = NULL;
883
884	ibchanp = &chanp->chan_ib;
885	devp = ibchanp->chan_devp;
886	if (devp == NULL) {
887		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "join_mcast: devp NULL");
888		return (EINVAL);
889	}
890
891	ibmcastp = kmem_zalloc(sizeof (ibcma_mcast_t), KM_SLEEP);
892	ibmcastp->mcast_idp = idp;
893	ibmcastp->mcast_ctx = context;
894	bcopy(addr, &ibmcastp->mcast_addr, sizeof (struct sockaddr));
895	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "join_mcast: ibmcastp %p",
896	    ibmcastp);
897
898	sockaddr2ibtaddr_port(idp, addr, &mcast_addr, NULL);
899
900	/* Check if input @ to rdma_join_mcast is multicast IP @ */
901	if (!(mcast_addr.family == AF_INET &&
902	    ((htonl(mcast_addr.un.ip4addr) & 0xE0000000) ==
903	    0xE0000000))) {
904		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
905		    "Invalid IP addr specified");
906		kmem_free(ibmcastp, sizeof (ibcma_mcast_t));
907		return (EINVAL);
908	}
909
910	bzero(&mcg_attr, sizeof (mcg_attr));
911	if (sol_cma_any_addr(addr)) {
912		bzero(&mcast_gid, sizeof (mcast_gid));
913		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "ANY mcast addr input");
914	} else {
915		ipaddr2mgid(addr, &mcast_gid_horder, devp->dev_pkey);
916
917		mcast_gid.gid_prefix = htonll(
918		    mcast_gid_horder.gid_prefix);
919		mcast_gid.gid_guid = htonll(
920		    mcast_gid_horder.gid_guid);
921	}
922	bcopy(&mcast_gid, &(mcg_attr.mc_mgid), sizeof (ib_gid_t));
923	mcg_attr.mc_mtu_req.r_selector = IBT_BEST;
924	mcg_attr.mc_flow = 0;
925	mcg_attr.mc_hop = 0xFF;
926	mcg_attr.mc_tclass = 0;
927	mcg_attr.mc_sl = 0;
928	mcg_attr.mc_pkt_lt_req.p_selector = IBT_BEST;
929	mcg_attr.mc_pkey = devp->dev_pkey;
930	mcg_attr.mc_rate_req.r_selector = IBT_BEST;
931	mcg_attr.mc_join_state = IB_MC_JSTATE_FULL;
932	if (idp->ps == RDMA_PS_UDP)
933		mcg_attr.mc_qkey = RDMA_UDP_QKEY;
934	else
935		mcg_attr.mc_qkey = SOL_IPOIB_DEFAULT_QKEY;
936	mcg_infop = kmem_zalloc(sizeof (ibt_mcg_info_t), KM_SLEEP);
937
938	status = ibt_join_mcg(ibchanp->chan_devp->dev_sgid,
939	    &mcg_attr, mcg_infop, ibcma_multicast_hdlr, ibmcastp);
940	if (status != IBT_SUCCESS) {
941		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "\t join_mcast : "
942		    "ibt_join_mcg failed with status %d", status);
943		kmem_free(ibmcastp, sizeof (ibcma_mcast_t));
944		return (EINVAL);
945	}
946
947	(void) add_genlist(&ibchanp->chan_mcast_list, (uintptr_t)ibmcastp,
948	    NULL);
949	ibchanp->chan_mcast_cnt++;
950
951	return (0);
952}
953
954void
955rdma_ib_leave_multicast(struct rdma_cm_id *idp, struct sockaddr *addr)
956{
957	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)idp;
958	ibcma_chan_t	*ibchanp;
959	ibcma_mcast_t	*ibmcastp = NULL;
960	genlist_entry_t	*entry;
961	ib_gid_t	zero_gid;
962	ibt_status_t	status;
963
964	ibchanp = &chanp->chan_ib;
965	genlist_for_each(entry, &ibchanp->chan_mcast_list) {
966		ibmcastp = (ibcma_mcast_t *)entry->data;
967		ASSERT(ibmcastp);
968		if (bcmp(&ibmcastp->mcast_addr, addr,
969		    sizeof (struct sockaddr)) == 0) {
970			delete_genlist(&ibchanp->chan_mcast_list, entry);
971			break;
972		}
973		ibmcastp = NULL;
974	}
975	if (ibmcastp == NULL) {
976		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
977		    "leave_mcast: No matching @");
978		return;
979	}
980	ibchanp->chan_mcast_cnt--;
981	bzero(&zero_gid, sizeof (ib_gid_t));
982	status = ibt_leave_mcg(ibchanp->chan_devp->dev_sgid,
983	    ibmcastp->mcast_gid, zero_gid, IB_MC_JSTATE_FULL);
984	if (status != IBT_SUCCESS)
985		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "leave_mcast: "
986		    "ibt_leave_mcg failed %d", status);
987	kmem_free(ibmcastp, sizeof (ibcma_mcast_t));
988}
989
990/* Local Functions */
991#define	SOL_REQ_PRIV_DATA_SZ	96
992static int
993ibcma_tcp_connect(struct rdma_cm_id *idp, ibcma_chan_t *ibchanp,
994    struct rdma_conn_param *conn_paramp)
995{
996	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)idp;
997	ibt_chan_open_flags_t	flags;
998	ibt_chan_open_args_t	args;
999	ibt_status_t		status;
1000	ibt_ip_cm_info_t	ipcm_info;
1001
1002	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "tcp_connect(%p, %p, %p)", idp,
1003	    ibchanp, conn_paramp);
1004	bzero(&args, sizeof (args));
1005	args.oc_path_retry_cnt = conn_paramp->retry_count;
1006	args.oc_path_rnr_retry_cnt = conn_paramp->rnr_retry_count;
1007	flags = IBT_OCHAN_OFUV;
1008	args.oc_path = ibchanp->chan_pathp;
1009	(args.oc_path)->pi_sid = ibchanp->chan_sid;
1010	args.oc_cm_handler =  ibcma_rc_hdlr;
1011	args.oc_cm_clnt_private = idp;
1012	args.oc_rdma_ra_out = conn_paramp->initiator_depth;
1013	args.oc_rdma_ra_in = conn_paramp->responder_resources;
1014	args.oc_priv_data_len = IBT_IP_HDR_PRIV_DATA_SZ +
1015	    conn_paramp->private_data_len;
1016	args.oc_priv_data = kmem_zalloc(SOL_REQ_PRIV_DATA_SZ, KM_SLEEP);
1017
1018	bcopy(&ibchanp->chan_local_addr, &ipcm_info.src_addr,
1019	    sizeof (ibt_ip_addr_t));
1020	bcopy(&ibchanp->chan_remote_addr, &ipcm_info.dst_addr,
1021	    sizeof (ibt_ip_addr_t));
1022	ipcm_info.src_port = ibchanp->chan_port;
1023	status = ibt_format_ip_private_data(&ipcm_info, args.oc_priv_data_len,
1024	    args.oc_priv_data);
1025	if (status != IBT_SUCCESS) {
1026		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1027		    "ibt_format_ip_private_data failed!!");
1028		kmem_free(args.oc_priv_data, SOL_REQ_PRIV_DATA_SZ);
1029		return (EINVAL);
1030	}
1031
1032	if (conn_paramp->private_data_len) {
1033		void	*dest;
1034
1035		dest = (void *)((uint8_t *)args.oc_priv_data +
1036		    IBT_IP_HDR_PRIV_DATA_SZ);
1037		bcopy(conn_paramp->private_data, dest,
1038		    conn_paramp->private_data_len);
1039	}
1040
1041	/*
1042	 * Set the RDMA related flags for this QP, if required.
1043	 */
1044	if (conn_paramp->initiator_depth || conn_paramp->responder_resources) {
1045		ibt_cep_modify_flags_t	cep_flags = IBT_CEP_SET_NOTHING;
1046		ibt_cep_flags_t		flags = IBT_CEP_NO_FLAGS;
1047
1048		if (conn_paramp->initiator_depth) {
1049			cep_flags |= IBT_CEP_SET_RDMA_R;
1050			flags |= IBT_CEP_RDMA_RD;
1051		}
1052		if (conn_paramp->responder_resources) {
1053			cep_flags |= IBT_CEP_SET_RDMA_W;
1054			flags |= IBT_CEP_RDMA_WR;
1055		}
1056
1057		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1058		    "tcp_connect: Calling  ibt_modify_rdma(%p, %x)",
1059		    chanp->chan_qp_hdl, cep_flags);
1060		status = ibt_modify_rdma(chanp->chan_qp_hdl,
1061		    cep_flags, flags);
1062		if (status != IBT_SUCCESS) {
1063			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "tcp_connect: "
1064			    "ibt_open_rdma failed %x", status);
1065			kmem_free(args.oc_priv_data, SOL_REQ_PRIV_DATA_SZ);
1066			return (EINVAL);
1067		}
1068	}
1069
1070	dump_priv_data(args.oc_priv_data, SOL_REQ_PRIV_DATA_SZ,
1071	    args.oc_priv_data_len, "tcp_connect");
1072	chanp->chan_connect_flag = SOL_CMA_CONNECT_INITIATED;
1073	status = ibt_open_rc_channel(chanp->chan_qp_hdl, flags,
1074	    IBT_NONBLOCKING, &args, NULL);
1075	if (status != IBT_SUCCESS) {
1076		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1077		    "tcp_connect: ibv_open_rc_channel failed %x",
1078		    status);
1079		kmem_free(args.oc_priv_data, SOL_REQ_PRIV_DATA_SZ);
1080		chanp->chan_connect_flag = SOL_CMA_CONNECT_CLIENT_NONE;
1081		return (EINVAL);
1082	}
1083	kmem_free(args.oc_priv_data, SOL_REQ_PRIV_DATA_SZ);
1084
1085	return (0);
1086}
1087
1088static int
1089ibcma_udp_connect(struct rdma_cm_id *idp, ibcma_chan_t *ibchanp,
1090    struct rdma_conn_param *conn_paramp)
1091{
1092	ibt_status_t		status;
1093	ibt_ud_dest_attr_t	attr;
1094	ibt_path_info_t		*pathp;
1095	ibt_adds_vect_t		*addr_vect;
1096	ibcma_dev_t		*devp;
1097	ibt_ip_cm_info_t	ipcm_info;
1098	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)idp;
1099
1100	devp = ibchanp->chan_devp;
1101	ASSERT(devp);
1102
1103	/* We always select the first path */
1104	pathp = ibchanp->chan_pathp;
1105	addr_vect = &((pathp->pi_prim_cep_path).cep_adds_vect);
1106
1107	bzero(&attr, sizeof (attr));
1108	attr.ud_pkey_ix = devp->dev_pkey_ix;
1109	attr.ud_cm_handler = ibcma_ud_hdlr;
1110	attr.ud_cm_private = idp;
1111	attr.ud_priv_data_len = IBT_IP_HDR_PRIV_DATA_SZ +
1112	    conn_paramp->private_data_len;
1113	attr.ud_priv_data = kmem_zalloc(attr.ud_priv_data_len, KM_SLEEP);
1114	if (conn_paramp->private_data_len) {
1115		bcopy(conn_paramp->private_data,
1116		    (void *)(((char *)attr.ud_priv_data) +
1117		    IBT_IP_HDR_PRIV_DATA_SZ),
1118		    conn_paramp->private_data_len);
1119	}
1120
1121	bcopy((void *)&ibchanp->chan_local_addr, &ipcm_info.src_addr,
1122	    sizeof (ibt_ip_addr_t));
1123	bcopy((void *)&ibchanp->chan_remote_addr, &ipcm_info.dst_addr,
1124	    sizeof (ibt_ip_addr_t));
1125	ipcm_info.src_port = ibchanp->chan_port;
1126	status = ibt_format_ip_private_data(&ipcm_info, attr.ud_priv_data_len,
1127	    attr.ud_priv_data);
1128	if (status != IBT_SUCCESS) {
1129		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "\tibudp_connect: "
1130		    "ibt_format_ip_private_data() failed with status %d",
1131		    status);
1132		kmem_free(attr.ud_priv_data, attr.ud_priv_data_len);
1133		return (EINVAL);
1134	}
1135	attr.ud_sid = ibchanp->chan_sid;
1136	attr.ud_addr = addr_vect;
1137
1138	chanp->chan_connect_flag = SOL_CMA_CONNECT_INITIATED;
1139	status = ibt_ud_get_dqpn(&attr, IBT_NONBLOCKING, NULL);
1140
1141	if (status != IBT_SUCCESS) {
1142		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "\tibudp_connect: "
1143		    "ibt_ud_get_dqpn failed with status %x", status);
1144		kmem_free(attr.ud_priv_data, attr.ud_priv_data_len);
1145		chanp->chan_connect_flag = SOL_CMA_CONNECT_CLIENT_NONE;
1146		return (EINVAL);
1147	}
1148
1149	kmem_free(attr.ud_priv_data, attr.ud_priv_data_len);
1150
1151	return (0);
1152}
1153
1154static int
1155ibcma_init_devinfo(struct rdma_cm_id *idp, ibcma_chan_t	*ibchanp,
1156    ibt_path_info_t *pathp)
1157{
1158	ibcma_dev_t		*devp;
1159	ibt_status_t		status;
1160	uint_t			nports, psize;
1161	ib_pkey_t		pkey;
1162	ibt_hca_portinfo_t	*pinfop;
1163
1164	if (ibchanp->chan_devp)
1165		return (-1);
1166
1167	/* Get the port_info and the pkey */
1168	status = ibt_query_hca_ports_byguid(pathp->pi_hca_guid,
1169	    pathp->pi_prim_cep_path.cep_hca_port_num,
1170	    &pinfop, &nports, &psize);
1171	if (status != IBT_SUCCESS) {
1172		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "init_devinfo - "
1173		    "query_hca_port failed rc %d", status);
1174		return (-1);
1175	} else {
1176		int	index;
1177
1178		index = pathp->pi_prim_cep_path.cep_pkey_ix;
1179		pkey = (pinfop->p_pkey_tbl)[index];
1180		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "init_devinfo - pkey %x",
1181		    pkey);
1182		ibt_free_portinfo(pinfop, psize);
1183	}
1184	devp = kmem_zalloc(sizeof (ibcma_dev_t), KM_SLEEP);
1185	ibchanp->chan_devp = devp;
1186	devp->dev_node_guid = pathp->pi_hca_guid;
1187	devp->dev_port_num = pathp->pi_prim_cep_path.cep_hca_port_num;
1188	devp->dev_pkey_ix = pathp->pi_prim_cep_path.cep_pkey_ix;
1189	devp->dev_pkey = pkey;
1190	devp->dev_sgid = pathp->pi_prim_cep_path.cep_adds_vect.av_sgid;
1191
1192	idp->device = sol_cma_acquire_device(ntohll(devp->dev_node_guid));
1193	idp->port_num = devp->dev_port_num;
1194	return (0);
1195}
1196
1197static int
1198ibcma_query_local_ip(struct rdma_cm_id *idp, sol_cma_chan_t *chanp,
1199    ibcma_chan_t *ibchanp)
1200{
1201	ibt_status_t		status;
1202	ibt_ip_addr_t		*local_addrp;
1203	ibt_ip_path_attr_t	path_attr;
1204	ibt_path_info_t		local_path;
1205
1206	if (ibchanp->chan_pathp != NULL) {
1207		return (0);
1208	}
1209	local_addrp = &ibchanp->chan_local_addr;
1210	bzero(&path_attr, sizeof (path_attr));
1211	path_attr.ipa_dst_ip = local_addrp;
1212	bcopy(local_addrp, &path_attr.ipa_src_ip, sizeof (ibt_ip_addr_t));
1213	path_attr.ipa_ndst = 1;
1214	path_attr.ipa_max_paths = 1;
1215	path_attr.ipa_zoneid = 0;
1216
1217	if ((status = ibt_get_ip_paths(chanp->chan_ib_client_hdl,
1218	    IBT_PATH_NO_FLAGS, &path_attr, &local_path, NULL, NULL)) !=
1219	    IBT_SUCCESS) {
1220		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1221		    "ib_cma_get_devinfo:status %d,  %p not IB IP @",
1222		    status, local_addrp);
1223		return (EINVAL);
1224	}
1225	if (ibcma_init_devinfo(idp, ibchanp, &local_path)) {
1226		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1227		    "ib_cma_get_devinfo:init_devinfo failed");
1228		return (EINVAL);
1229	}
1230
1231	return (0);
1232}
1233
1234#define	IBCMA_FREE_IN_IPPATH_HDLR()				\
1235	if (pathp)						\
1236		kmem_free(pathp, sizeof (ibt_path_info_t) * 	\
1237		    num_paths);					\
1238	if (src_ip_p)						\
1239		kmem_free(src_ip_p, sizeof (ibt_path_ip_src_t) 	\
1240		    * num_paths);
1241
1242static void
1243ibcma_path_hdlr(void *arg, ibt_status_t retval, ibt_path_info_t *pathp,
1244    uint8_t num_paths, ibt_path_ip_src_t *src_ip_p)
1245{
1246	struct rdma_cm_id	*idp = (struct rdma_cm_id *)arg;
1247	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)arg;
1248	ibcma_chan_t		*ibchanp = &(chanp->chan_ib);
1249	int			i;
1250	ibcma_dev_t		*devp;
1251	ib_lid_t		base_lid;
1252
1253	if (retval != IBT_SUCCESS && retval != IBT_INSUFF_DATA) {
1254		cma_resolve_addr_callback(chanp, 1);
1255		IBCMA_FREE_IN_IPPATH_HDLR();
1256		return;
1257	}
1258
1259	ibchanp->chan_path_size = 2 * sizeof (ibt_path_info_t);
1260	ibchanp->chan_pathp = kmem_zalloc(ibchanp->chan_path_size, KM_SLEEP);
1261	bcopy(pathp, ibchanp->chan_pathp, num_paths *
1262	    sizeof (ibt_path_info_t));
1263	ibchanp->chan_numpaths = num_paths;
1264
1265	if (ibchanp->chan_devp == NULL && src_ip_p) {
1266		ipaddr2sockaddr(&(src_ip_p[0].ip_primary),
1267		    &(idp->route.addr.src_addr), NULL);
1268		bcopy(&(src_ip_p[0].ip_primary), &ibchanp->chan_local_addr,
1269		    sizeof (ibt_ip_addr_t));
1270		if (ibcma_init_devinfo((struct rdma_cm_id *)chanp,
1271		    ibchanp, pathp)) {
1272			kmem_free(ibchanp->chan_pathp,
1273			    ibchanp->chan_path_size);
1274			cma_resolve_addr_callback(chanp, 1);
1275			IBCMA_FREE_IN_IPPATH_HDLR();
1276			return;
1277		}
1278	}
1279
1280	if (ibchanp->chan_devp == NULL) {
1281		cma_resolve_addr_callback(chanp, 1);
1282		IBCMA_FREE_IN_IPPATH_HDLR();
1283		return;
1284	}
1285
1286	devp = ibchanp->chan_devp;
1287	(idp->route).num_paths = ibchanp->chan_numpaths;
1288	idp->route.path_rec = kmem_zalloc(sizeof (struct ib_sa_path_rec) *
1289	    ibchanp->chan_numpaths, KM_SLEEP);
1290	base_lid = ibt_get_port_state_byguid(devp->dev_node_guid,
1291	    devp->dev_port_num, NULL, &base_lid);
1292	for (i = 0; i < ibchanp->chan_numpaths; i++)
1293		ibt_path2sa_path(&((ibchanp->chan_pathp)[i]),
1294		    &((idp->route.path_rec)[i]), base_lid);
1295
1296	cma_resolve_addr_callback(chanp, 0);
1297	IBCMA_FREE_IN_IPPATH_HDLR();
1298}
1299
1300static int
1301ibcma_get_paths(struct rdma_cm_id *idp, sol_cma_chan_t *chanp,
1302    ibcma_chan_t *ibchanp)
1303{
1304	ibt_ip_path_attr_t	path_attr;
1305	ibt_status_t		status;
1306	ibt_ip_addr_t		*dst_addrp;
1307
1308	ASSERT(ibchanp);
1309
1310	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "ibcma_get_paths(%p, %p)", idp,
1311	    ibchanp);
1312	bzero(&path_attr, sizeof (ibt_ip_path_attr_t));
1313	dst_addrp = kmem_zalloc(sizeof (ibt_ip_addr_t), KM_SLEEP);
1314	bcopy(&ibchanp->chan_remote_addr, dst_addrp, sizeof (ibt_ip_addr_t));
1315	path_attr.ipa_dst_ip = dst_addrp;
1316	bcopy(&ibchanp->chan_local_addr, &path_attr.ipa_src_ip,
1317	    sizeof (ibt_ip_addr_t));
1318	path_attr.ipa_ndst = 1;
1319	path_attr.ipa_max_paths = 2;
1320	path_attr.ipa_zoneid = 0;
1321	if (ibcma_any_addr(&path_attr.ipa_src_ip))
1322		path_attr.ipa_src_ip.family = AF_UNSPEC;
1323
1324	status = ibt_aget_ip_paths(chanp->chan_ib_client_hdl, IBT_PATH_NO_FLAGS,
1325	    &path_attr, ibcma_path_hdlr, idp);
1326	if (status != IBT_SUCCESS) {
1327		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1328		    "cma_get_paths : ibt_aget_paths() failed %d", status);
1329		kmem_free(dst_addrp, sizeof (ibt_ip_addr_t));
1330		return (EINVAL);
1331	}
1332
1333	kmem_free(dst_addrp, sizeof (ibt_ip_addr_t));
1334	return (0);
1335}
1336
1337/*
1338 * Solaris Event Handlers
1339 */
1340
1341/* UD Event Handler */
1342/*ARGSUSED*/
1343static ibt_cm_status_t
1344ibcma_ud_hdlr(void *inp, ibt_cm_ud_event_t *eventp,
1345    ibt_cm_ud_return_args_t *ret_args, void *priv_data,
1346    ibt_priv_data_len_t priv_datalen)
1347{
1348	struct rdma_cm_id	*root_idp, *event_idp, *idp;
1349	sol_cma_chan_t		*root_chanp, *chanp, *event_chanp;
1350	ibcma_chan_t		*ibchanp, *event_ibchanp;
1351	struct rdma_ud_param	ud_param, *ud_paramp = &ud_param;
1352	enum rdma_cm_event_type event;
1353	int			evt_status = -1;
1354	ibt_priv_data_len_t	cm_privlen;
1355	void			*cm_priv;
1356	ibt_status_t		ibt_status;
1357	ibt_ip_cm_info_t	info;
1358	cma_chan_state_t	chan_state;
1359
1360	event_idp = idp = (struct rdma_cm_id *)inp;
1361	chanp = (sol_cma_chan_t *)idp;
1362	ibchanp = &chanp->chan_ib;
1363	root_idp = CHAN_LISTEN_ROOT(chanp);
1364	root_chanp = (sol_cma_chan_t *)root_idp;
1365	SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str, "cma_ud_hdlr(%p, %p)",
1366	    inp, eventp);
1367
1368	bzero(&ud_param, sizeof (struct rdma_ud_param));
1369	cm_privlen = eventp->cm_priv_data_len;
1370	cm_priv = eventp->cm_priv_data;
1371	if (eventp->cm_type == IBT_CM_UD_EVENT_SIDR_REQ) {
1372		ibt_cm_sidr_req_t	*sidr_req;
1373		void			*find_ret;
1374		avl_index_t		where;
1375
1376		ASSERT(root_chanp);
1377
1378		/*
1379		 * Reject further REQs if destroy of listen CMID
1380		 * has been called.
1381		 */
1382		mutex_enter(&root_chanp->chan_mutex);
1383		chan_state = cma_get_chan_state(root_chanp);
1384		mutex_exit(&root_chanp->chan_mutex);
1385		if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING ||
1386		    chan_state == SOL_CMA_CHAN_DESTROY_WAIT) {
1387			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "UD Req Hdlr, "
1388			    "listen CMID destroy called");
1389			return (IBT_CM_REJECT);
1390		}
1391
1392		sidr_req = &((eventp->cm_event).sidr_req);
1393		SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, "SIDR REQ");
1394
1395		if (cm_privlen < IBT_IP_HDR_PRIV_DATA_SZ) {
1396			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "UD Req Hdlr, "
1397			    "Priv data len %x < %x", cm_privlen,
1398			    IBT_IP_HDR_PRIV_DATA_SZ);
1399			return (IBT_CM_REJECT);
1400		}
1401		ibt_status = ibt_get_ip_data(cm_privlen, cm_priv, &info);
1402		if (ibt_status != IBT_SUCCESS) {
1403			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "UD Req Hdlr, "
1404			    "ibt_get_ip_data failed, %x", ibt_status);
1405			return (IBT_CM_REJECT);
1406		}
1407		cm_privlen -= IBT_IP_HDR_PRIV_DATA_SZ;
1408		cm_priv = (void *)(((uchar_t *)cm_priv) +
1409		    IBT_IP_HDR_PRIV_DATA_SZ);
1410
1411		event_idp = ibcma_create_new_id(idp);
1412		if (event_idp == NULL) {
1413			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1414			    "create_new_id failed!!");
1415			return (IBT_CM_REJECT);
1416		}
1417		event_idp->device = sol_cma_acquire_device(ntohll(
1418		    sidr_req->sreq_hca_guid));
1419		event_idp->port_num = sidr_req->sreq_hca_port;
1420		(event_idp->route).num_paths = 0;
1421
1422		event_chanp = (sol_cma_chan_t *)event_idp;
1423		event_chanp->chan_req_state = REQ_CMID_NOTIFIED;
1424		event_ibchanp = &event_chanp->chan_ib;
1425		event_chanp->chan_session_id = eventp->cm_session_id;
1426		bcopy(&info.src_addr, &event_ibchanp->chan_remote_addr,
1427		    sizeof (ibt_ip_addr_t));
1428		ipaddr2sockaddr(&info.src_addr,
1429		    &(event_idp->route.addr.dst_addr), &info.src_port);
1430		bcopy(&info.dst_addr, &event_ibchanp->chan_local_addr,
1431		    sizeof (ibt_ip_addr_t));
1432		ipaddr2sockaddr(&info.dst_addr,
1433		    &(event_idp->route.addr.src_addr), &info.src_port);
1434
1435		/*
1436		 * Increment number of Reqs for listening CMID,
1437		 * so that listening CMID is not deleted, till this
1438		 * connection expects no more events.
1439		 * chan_req_cnt is decremented connection is
1440		 * notified to the consumer.
1441		 *
1442		 * Insert the CMID into the REQ_AVL_TREE. This is
1443		 * deleted when the connection is accepted or rejected.
1444		 */
1445		mutex_enter(&root_chanp->chan_mutex);
1446		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1447		    "Add to REQ AVL of %p IDP, idp %p, session_id %p",
1448		    root_idp, event_idp, event_chanp->chan_session_id);
1449		find_ret = avl_find(&root_chanp->chan_req_avl_tree,
1450		    (void *)event_chanp->chan_session_id, &where);
1451		if (find_ret) {
1452			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1453			    "DUPLICATE ENTRY in REQ AVL : root %p, "
1454			    "idp %p, session_id %p",
1455			    root_idp, event_idp,
1456			    event_chanp->chan_session_id);
1457			mutex_exit(&root_chanp->chan_mutex);
1458			event_chanp->chan_req_state = REQ_CMID_CREATED;
1459			rdma_destroy_id(event_idp);
1460			return (IBT_CM_REJECT);
1461		}
1462		root_chanp->chan_req_cnt++;
1463		root_chanp->chan_req_state = REQ_CMID_CREATED;
1464		root_chanp->chan_req_total_cnt++;
1465		avl_insert(&root_chanp->chan_req_avl_tree,
1466		    (void *)event_idp, where);
1467		mutex_exit(&root_chanp->chan_mutex);
1468
1469		event = RDMA_CM_EVENT_CONNECT_REQUEST;
1470		evt_status = 0;
1471	} else if (eventp->cm_type == IBT_CM_UD_EVENT_SIDR_REP) {
1472		ibt_cm_sidr_rep_t	*sidr_rep;
1473
1474		ASSERT(chanp->chan_connect_flag == SOL_CMA_CONNECT_INITIATED);
1475		mutex_enter(&chanp->chan_mutex);
1476		chanp->chan_connect_flag = SOL_CMA_CONNECT_CLIENT_NONE;
1477		chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS;
1478		mutex_exit(&chanp->chan_mutex);
1479		sidr_rep = &((eventp->cm_event).sidr_rep);
1480		if (sidr_rep->srep_status == IBT_CM_SREP_CHAN_VALID) {
1481			evt_status = 0;
1482			event = RDMA_CM_EVENT_ESTABLISHED;
1483			ud_paramp->qp_num = sidr_rep->srep_remote_qpn;
1484			ud_paramp->qkey = sidr_rep->srep_remote_qkey;
1485			ibt_path2ah(ibchanp->chan_pathp, &ud_paramp->ah_attr);
1486		} else {
1487			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1488			    "SIDR Response err with status %x",
1489			    sidr_rep->srep_status);
1490			event = RDMA_CM_EVENT_UNREACHABLE;
1491			evt_status = sidr_rep->srep_status;
1492			goto ud_gen_event;
1493		}
1494	}
1495
1496	ud_paramp->private_data_len = cm_privlen;
1497	if (evt_status == 0 && cm_privlen) {
1498		ud_paramp->private_data = kmem_zalloc(cm_privlen, KM_SLEEP);
1499		bcopy(cm_priv, (void *)ud_paramp->private_data,
1500		    cm_privlen);
1501#ifdef DEBUG
1502		dump_priv_data((void *)ud_paramp->private_data,
1503		    SOL_REP_PRIV_DATA_SZ, cm_privlen, "ibcma_ud_hdlr");
1504#endif
1505	}
1506
1507ud_gen_event:
1508	/* Pass back the event to sol_cma consumer */
1509	cma_generate_event(event_idp, event, evt_status, NULL, ud_paramp);
1510
1511	if (ud_paramp->private_data)
1512		kmem_free((void *)ud_paramp->private_data, cm_privlen);
1513
1514	if (eventp->cm_type == IBT_CM_UD_EVENT_SIDR_REQ)
1515		return (IBT_CM_DEFER);
1516	else
1517		return (IBT_CM_DEFAULT);
1518}
1519
1520static ibt_cm_status_t
1521ibcma_handle_req(struct rdma_cm_id *idp, struct rdma_cm_id **event_id_ptr,
1522    ibt_cm_event_t *eventp, struct rdma_conn_param *paramp,
1523    enum rdma_cm_event_type *event, int *evt_status)
1524{
1525	struct rdma_cm_id	*root_idp, *event_idp;
1526	sol_cma_chan_t		*root_chanp, *event_chanp, *chanp;
1527	ibcma_chan_t		*event_ibchanp, *ibchanp;
1528	ibt_status_t		ibt_status;
1529	ibt_cm_req_rcv_t	*reqp;
1530	ibt_priv_data_len_t	cm_privlen;
1531	ibt_ofuvcm_req_data_t	rtr_data;
1532	ibt_ip_cm_info_t	info;
1533	void			*cm_priv, *priv_data;
1534	ib_lid_t		base_lid;
1535	void			*find_ret;
1536	avl_index_t		where;
1537	cma_chan_state_t	chan_state;
1538#ifdef  DEBUG
1539	void			*dump_priv;
1540#endif
1541
1542	chanp = (sol_cma_chan_t *)idp;
1543	ibchanp = &chanp->chan_ib;
1544	root_idp = CHAN_LISTEN_ROOT(chanp);
1545	root_chanp = (sol_cma_chan_t *)root_idp;
1546	ASSERT(chanp->chan_listenp);
1547	ASSERT(root_idp);
1548
1549	/*
1550	 * Reject further REQs if destroy of listen CMID
1551	 * has been called.
1552	 */
1553	mutex_enter(&root_chanp->chan_mutex);
1554	chan_state = cma_get_chan_state(root_chanp);
1555	mutex_exit(&root_chanp->chan_mutex);
1556	if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING ||
1557	    chan_state == SOL_CMA_CHAN_DESTROY_WAIT) {
1558		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "RC Req Hdlr, "
1559		    "listen CMID destroy called");
1560		return (IBT_CM_REJECT);
1561	}
1562
1563	*event = RDMA_CM_EVENT_CONNECT_REQUEST;
1564	*evt_status = 0;
1565	reqp = &(eventp->cm_event.req);
1566	paramp->qp_num = reqp->req_remote_qpn;
1567	paramp->srq = (reqp->req_flags & IBT_CM_SRQ_EXISTS) ? 1 : 0;
1568	paramp->responder_resources = reqp->req_rdma_ra_in;
1569	paramp->initiator_depth = reqp->req_rdma_ra_out;
1570	paramp->flow_control = (reqp->req_flags & IBT_CM_FLOW_CONTROL)
1571	    ? 1 : 0;
1572	paramp->retry_count = reqp->req_retry_cnt;
1573	paramp->rnr_retry_count = reqp->req_rnr_retry_cnt;
1574
1575#ifdef	DEBUG
1576	dump_priv = kmem_zalloc(SOL_REQ_PRIV_DATA_SZ, KM_SLEEP);
1577	bcopy(eventp->cm_priv_data, dump_priv, eventp->cm_priv_data_len);
1578	dump_priv_data(dump_priv, SOL_REQ_PRIV_DATA_SZ,
1579	    eventp->cm_priv_data_len, "handle_req");
1580	kmem_free(dump_priv, SOL_REQ_PRIV_DATA_SZ);
1581#endif	/* DEBUG */
1582
1583	cm_privlen = eventp->cm_priv_data_len;
1584	cm_priv = eventp->cm_priv_data;
1585	if (cm_privlen < IBT_IP_HDR_PRIV_DATA_SZ) {
1586		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "RC Req Hdlr, "
1587		    "Priv data len %x < %x", cm_privlen,
1588		    IBT_IP_HDR_PRIV_DATA_SZ);
1589		return (IBT_CM_REJECT);
1590	}
1591	ibt_status = ibt_get_ip_data(cm_privlen, cm_priv, &info);
1592	if (ibt_status != IBT_SUCCESS) {
1593		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "RC Req Hdlr, "
1594		    "ibt_get_ip_data failed, %x", ibt_status);
1595		return (IBT_CM_REJECT);
1596	}
1597	bcopy(&info.dst_addr, &ibchanp->chan_remote_addr,
1598	    sizeof (ibt_ip_addr_t));
1599
1600	ibt_status = ibt_ofuvcm_get_req_data(eventp->cm_session_id, &rtr_data);
1601	if (ibt_status != IBT_SUCCESS) {
1602		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "RC Req Hdlr, "
1603		    "ibt_ofuvcm_get_req_data failed, %x", ibt_status);
1604		return (IBT_CM_REJECT);
1605	}
1606
1607	paramp->private_data_len = cm_privlen - IBT_IP_HDR_PRIV_DATA_SZ;
1608	if (paramp->private_data_len) {
1609		priv_data = (void *)((uint8_t *)cm_priv +
1610		    IBT_IP_HDR_PRIV_DATA_SZ);
1611		paramp->private_data = kmem_zalloc(paramp->private_data_len,
1612		    KM_SLEEP);
1613		bcopy(priv_data, (void *)paramp->private_data,
1614		    paramp->private_data_len);
1615	}
1616	event_idp = ibcma_create_new_id(idp);
1617	if (event_idp == NULL) {
1618		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1619		    "create_new_id failed!!");
1620		if (paramp->private_data)
1621			kmem_free((void *)paramp->private_data,
1622			    paramp->private_data_len);
1623		return (IBT_CM_REJECT);
1624	}
1625
1626	/*
1627	 * Fill the route, device and port_num.
1628	 * TBD - Fill up packet_life_time
1629	 */
1630	event_idp->device = sol_cma_acquire_device(ntohll(
1631	    reqp->req_hca_guid));
1632	event_idp->port_num = reqp->req_prim_hca_port;
1633	(event_idp->route).num_paths = reqp->req_alt_hca_port ? 2 : 1;
1634	event_idp->route.path_rec = kmem_zalloc(
1635	    sizeof (struct ib_sa_path_rec) * ((event_idp->route).num_paths),
1636	    KM_SLEEP);
1637	base_lid = ibt_get_port_state_byguid(reqp->req_hca_guid,
1638	    reqp->req_prim_hca_port, NULL, &base_lid);
1639	ibt_addsvect2sa_path(&reqp->req_prim_addr,
1640	    &(event_idp->route.path_rec[0]), base_lid);
1641	(event_idp->route.path_rec[0]).mtu = (uint8_t)rtr_data.req_path_mtu;
1642	if (reqp->req_alt_hca_port) {
1643		base_lid = ibt_get_port_state_byguid(
1644		    reqp->req_hca_guid, reqp->req_alt_hca_port,
1645		    NULL, &base_lid);
1646		ibt_addsvect2sa_path(&reqp->req_alt_addr,
1647		    &(event_idp->route.path_rec[1]), base_lid);
1648		(event_idp->route.path_rec[1]).mtu =
1649		    (uint8_t)rtr_data.req_path_mtu;
1650	}
1651
1652	*event_id_ptr = event_idp;
1653
1654	event_chanp = (sol_cma_chan_t *)event_idp;
1655	event_chanp->chan_req_state = REQ_CMID_NOTIFIED;
1656	event_ibchanp = &event_chanp->chan_ib;
1657	event_chanp->chan_session_id = eventp->cm_session_id;
1658	bcopy((void *)(&reqp->req_prim_addr),
1659	    (void *)(&event_ibchanp->chan_rcreq_addr),
1660	    sizeof (ibt_adds_vect_t));
1661	bcopy(&rtr_data, &(event_ibchanp->chan_rtr_data),
1662	    sizeof (ibt_ofuvcm_req_data_t));
1663	event_ibchanp->chan_rcreq_qpn = reqp->req_remote_qpn;
1664	event_ibchanp->chan_rcreq_ra_in = reqp->req_rdma_ra_in;
1665	bcopy(&info.src_addr, &event_ibchanp->chan_remote_addr,
1666	    sizeof (ibt_ip_addr_t));
1667	ipaddr2sockaddr(&info.src_addr,
1668	    &(event_idp->route.addr.dst_addr), &info.src_port);
1669	bcopy(&info.dst_addr, &event_ibchanp->chan_local_addr,
1670	    sizeof (ibt_ip_addr_t));
1671	ipaddr2sockaddr(&info.dst_addr,
1672	    &(event_idp->route.addr.src_addr), &info.src_port);
1673
1674	/*
1675	 * Increment number of Reqs for listening CMID, so that
1676	 * listening CMID is not deleted, till this connection
1677	 * expects no more events. chan_req_cnt is decremented
1678	 * when connection is notified to the consumer.
1679	 *
1680	 * Insert the CMID into the REQ_AVL_TREE. This is
1681	 * deleted when the connection is accepted or rejected.
1682	 */
1683	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1684	    "Add to REQ AVL of %p IDP, idp %p, session_id %p",
1685	    root_idp, event_idp, event_chanp->chan_session_id);
1686	mutex_enter(&root_chanp->chan_mutex);
1687	find_ret = avl_find(&root_chanp->chan_req_avl_tree,
1688	    (void *)event_chanp->chan_session_id, &where);
1689	if (find_ret) {
1690		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1691		    "DUPLICATE ENTRY in REQ AVL : root %p, "
1692		    "idp %p, session_id %p",
1693		    root_idp, event_idp,
1694		    event_chanp->chan_session_id);
1695		mutex_exit(&root_chanp->chan_mutex);
1696		event_chanp->chan_req_state = REQ_CMID_CREATED;
1697		if (paramp->private_data)
1698			kmem_free((void *)paramp->private_data,
1699			    paramp->private_data_len);
1700		rdma_destroy_id(event_idp);
1701		return (IBT_CM_REJECT);
1702	}
1703	root_chanp->chan_req_cnt++;
1704	root_chanp->chan_req_state = REQ_CMID_CREATED;
1705	root_chanp->chan_req_total_cnt++;
1706
1707	avl_insert(&root_chanp->chan_req_avl_tree, (void *)event_idp, where);
1708	mutex_exit(&root_chanp->chan_mutex);
1709
1710	return (IBT_CM_DEFER);
1711}
1712
1713static void
1714ibcma_handle_rep(struct rdma_cm_id *idp, ibt_cm_event_t *eventp)
1715{
1716	sol_cma_chan_t		*chanp;
1717	ibt_cm_rep_rcv_t	*repp;
1718	struct rdma_conn_param	*paramp;
1719
1720	chanp = (sol_cma_chan_t *)idp;
1721
1722	paramp = &chanp->chan_param;
1723	bzero(paramp, sizeof (chanp->chan_param));
1724	repp = &((eventp->cm_event).rep);
1725	paramp->srq = (repp->rep_flags & IBT_CM_SRQ_EXISTS) ? 1 : 0;
1726	paramp->responder_resources = repp->rep_rdma_ra_in;
1727	paramp->initiator_depth = repp->rep_rdma_ra_out;
1728	paramp->flow_control = (repp->rep_flags & IBT_CM_FLOW_CONTROL) ? 1 : 0;
1729
1730#ifdef DEBUG
1731	dump_priv_data(eventp->cm_priv_data, SOL_REP_PRIV_DATA_SZ,
1732	    eventp->cm_priv_data_len, "handle_rep");
1733#endif
1734	paramp->private_data_len =  eventp->cm_priv_data_len;
1735	if (paramp->private_data_len) {
1736		paramp->private_data = kmem_zalloc(paramp->private_data_len,
1737		    KM_SLEEP);
1738		bcopy((void *)eventp->cm_priv_data,
1739		    (void *)paramp->private_data, paramp->private_data_len);
1740	}
1741}
1742
1743static ibt_cm_status_t
1744ibcma_handle_est(struct rdma_cm_id *idp, struct rdma_cm_id **event_id_ptr,
1745    ibt_cm_event_t *eventp, struct rdma_conn_param *paramp,
1746    enum rdma_cm_event_type *event, int *evt_status)
1747{
1748	struct rdma_cm_id	*event_idp, *root_idp;
1749	sol_cma_chan_t		*event_chanp, *chanp, *root_chanp;
1750	ibcma_chan_t		*event_ibchanp;
1751
1752	/* Established event on active / client side */
1753	chanp = (sol_cma_chan_t *)idp;
1754	if (chanp->chan_listenp == NULL) {
1755		ASSERT(chanp->chan_connect_flag == SOL_CMA_CONNECT_INITIATED);
1756		chanp->chan_connect_flag = SOL_CMA_CONNECT_ESTABLISHED;
1757		*event_id_ptr = idp;
1758		bcopy(&chanp->chan_param, paramp,
1759		    sizeof (struct rdma_conn_param));
1760		if (paramp->private_data_len) {
1761			paramp->private_data = kmem_zalloc(
1762			    paramp->private_data_len, KM_SLEEP);
1763			bcopy((void *)((chanp->chan_param).private_data),
1764			    (void *)paramp->private_data,
1765			    paramp->private_data_len);
1766			kmem_free((void *)((chanp->chan_param).private_data),
1767			    paramp->private_data_len);
1768		}
1769		event_chanp = chanp;
1770		mutex_enter(&chanp->chan_mutex);
1771		chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS;
1772		mutex_exit(&chanp->chan_mutex);
1773		goto est_common;
1774	}
1775
1776	root_idp = CHAN_LISTEN_ROOT((chanp));
1777	ASSERT(root_idp);
1778	root_chanp = (sol_cma_chan_t *)root_idp;
1779	event_chanp = NULL;
1780
1781	mutex_enter(&root_chanp->chan_mutex);
1782	event_idp = cma_get_acpt_idp(root_idp, eventp->cm_channel);
1783	mutex_exit(&root_chanp->chan_mutex);
1784	if (event_idp == NULL) {
1785		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "ibcma_handle_est: "
1786		    "No matching CMID for qp_hdl %p in ACPT AVL of CMID %p",
1787		    eventp->cm_channel, root_chanp);
1788		return (IBT_CM_REJECT);
1789	}
1790	*event_id_ptr = event_idp;
1791	event_chanp = (sol_cma_chan_t *)event_idp;
1792	mutex_enter(&event_chanp->chan_mutex);
1793	event_chanp->chan_cmid_destroy_state |=
1794	    SOL_CMA_CALLER_EVENT_PROGRESS;
1795	mutex_exit(&event_chanp->chan_mutex);
1796
1797est_common:
1798#ifdef QP_DEBUG
1799	dump_qp_info(event_chanp->chan_qp_hdl);
1800#endif
1801
1802	/*
1803	 * Pass back CONNECT_ESTABLISHED event to consumer.
1804	 */
1805	*event = RDMA_CM_EVENT_ESTABLISHED;
1806	event_ibchanp = &event_chanp->chan_ib;
1807	event_ibchanp->chan_qpmodifyflag  = 1;
1808
1809	*evt_status = 0;
1810	return (IBT_CM_DEFAULT);
1811}
1812
1813static ibt_cm_status_t
1814ibcma_handle_closed(struct rdma_cm_id *idp, struct rdma_cm_id **event_id_ptr,
1815    ibt_cm_event_t *eventp, enum rdma_cm_event_type *event, int *evt_status)
1816{
1817	struct rdma_cm_id	*root_idp, *event_idp;
1818	sol_cma_chan_t		*chanp, *root_chanp, *event_chanp;
1819
1820	*event = RDMA_CM_EVENT_DISCONNECTED;
1821	*evt_status = 0;
1822	chanp = (sol_cma_chan_t *)idp;
1823	mutex_enter(&chanp->chan_mutex);
1824	root_idp = CHAN_LISTEN_ROOT((chanp));
1825	root_chanp = (sol_cma_chan_t *)root_idp;
1826	chanp->chan_qp_hdl = NULL;
1827	if (!root_idp) {
1828		chanp->chan_cmid_destroy_state |=
1829		    SOL_CMA_CALLER_EVENT_PROGRESS;
1830		chanp->chan_qp_hdl = NULL;
1831		chanp->chan_connect_flag = SOL_CMA_CONNECT_CLIENT_NONE;
1832		mutex_exit(&chanp->chan_mutex);
1833		*event_id_ptr = idp;
1834		return (IBT_CM_DEFAULT);
1835	}
1836	mutex_exit(&chanp->chan_mutex);
1837
1838	/* On the passive side, search ACPT AVL Tree */
1839	mutex_enter(&root_chanp->chan_mutex);
1840	event_idp = cma_get_acpt_idp(root_idp, eventp->cm_channel);
1841	event_chanp = (sol_cma_chan_t *)event_idp;
1842	if (event_idp == NULL) {
1843		mutex_exit(&root_chanp->chan_mutex);
1844		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1845		    "ibcma_handle_closed: "
1846		    "No matching CMID for qp hdl %p in EST AVL of CMID %p",
1847		    eventp->cm_channel, root_idp);
1848		return (IBT_CM_DEFAULT);
1849	}
1850	avl_remove(&root_chanp->chan_acpt_avl_tree, event_idp);
1851	mutex_exit(&root_chanp->chan_mutex);
1852	mutex_enter(&event_chanp->chan_mutex);
1853	event_chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1854	event_chanp->chan_cmid_destroy_state |=
1855	    SOL_CMA_CALLER_EVENT_PROGRESS;
1856	mutex_exit(&event_chanp->chan_mutex);
1857
1858	*event_id_ptr = event_idp;
1859	return (IBT_CM_DEFAULT);
1860}
1861
1862static ibt_cm_status_t
1863ibcma_handle_failed(struct rdma_cm_id *idp, struct rdma_cm_id **event_id_ptr,
1864    ibt_cm_event_t *eventp, struct rdma_conn_param *paramp,
1865    enum rdma_cm_event_type *event, int *evt_status)
1866{
1867	struct rdma_cm_id	*root_idp, *event_idp;
1868	sol_cma_chan_t		*event_chanp, *chanp, *root_chanp;
1869	ibt_cm_conn_failed_t	*failedp;
1870
1871	failedp = &(eventp->cm_event.failed);
1872	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "ibcma_handle_failed - idp %p, "
1873	    "cf_code %x, cf_msg %x, cf_arej_info_valid %x, cf_reason %x",
1874	    idp, failedp->cf_code, failedp->cf_msg,
1875	    failedp->cf_arej_info_valid, failedp->cf_reason);
1876	chanp = (sol_cma_chan_t *)idp;
1877	root_idp = CHAN_LISTEN_ROOT((chanp));
1878	root_chanp = (sol_cma_chan_t *)root_idp;
1879
1880	*evt_status = 0;
1881	switch (failedp->cf_code) {
1882	case IBT_CM_FAILURE_REJ_SENT :
1883		/*  Reject sent. No event to userland. */
1884		break;
1885
1886	case IBT_CM_FAILURE_REJ_RCV :
1887		/*
1888		 * Reject recieved. If this is a consumer reject, copy the
1889		 * private * data. Send RDMA_CM_EVENT_REJECTED to user land.
1890		 */
1891		if (failedp->cf_reason == IBT_CM_CONSUMER &&
1892		    eventp->cm_priv_data_len) {
1893			paramp->private_data_len = eventp->cm_priv_data_len;
1894			paramp->private_data = kmem_zalloc(
1895			    paramp->private_data_len, KM_SLEEP);
1896			bcopy(eventp->cm_priv_data,
1897			    (void *)paramp->private_data,
1898			    paramp->private_data_len);
1899		}
1900
1901		/*
1902		 * If this an REJECT for an accepted CMID, pass the
1903		 * event to accepted CMID.
1904		 */
1905		if (root_idp) {
1906			sol_cma_chan_t	*root_chanp;
1907			ASSERT(eventp->cm_channel);
1908
1909			root_chanp = (sol_cma_chan_t *)root_idp;
1910			mutex_enter(&root_chanp->chan_mutex);
1911			event_idp = cma_get_acpt_idp(root_idp,
1912			    eventp->cm_channel);
1913			if (event_idp == NULL) {
1914				SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
1915				    "ibcma_handle_failed: No matching CMID "
1916				    "for qp_hdl %p in ACPT AVL of CMID %p",
1917				    eventp->cm_channel, idp);
1918				mutex_exit(&root_chanp->chan_mutex);
1919				break;
1920			}
1921
1922			event_chanp = (sol_cma_chan_t *)event_idp;
1923			*event_id_ptr = event_idp;
1924			mutex_enter(&event_chanp->chan_mutex);
1925			avl_remove(&root_chanp->chan_acpt_avl_tree,
1926			    event_idp);
1927			event_chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1928			event_chanp->chan_cmid_destroy_state |=
1929			    SOL_CMA_CALLER_EVENT_PROGRESS;
1930			event_chanp->chan_qp_hdl = NULL;
1931			mutex_exit(&event_chanp->chan_mutex);
1932			mutex_exit(&root_chanp->chan_mutex);
1933		} else {
1934			mutex_enter(&chanp->chan_mutex);
1935			chanp->chan_cmid_destroy_state |=
1936			    SOL_CMA_CALLER_EVENT_PROGRESS;
1937			chanp->chan_qp_hdl = NULL;
1938			chanp->chan_connect_flag =
1939			    SOL_CMA_CONNECT_CLIENT_NONE;
1940			mutex_exit(&chanp->chan_mutex);
1941			*event_id_ptr  = idp;
1942		}
1943		*evt_status = failedp->cf_reason;
1944		*event = RDMA_CM_EVENT_REJECTED;
1945		break;
1946
1947	case IBT_CM_FAILURE_TIMEOUT :
1948		/*
1949		 * Connection Timeout, Send RDMA_CM_EVENT_REJECTED event and
1950		 * status as IBT_CM_TIMEOUT.
1951		 */
1952		if (eventp->cm_session_id && root_idp) {
1953			mutex_enter(&root_chanp->chan_mutex);
1954			event_idp = cma_get_req_idp(root_idp,
1955			    eventp->cm_session_id);
1956			if (event_idp == NULL) {
1957				mutex_exit(&root_chanp->chan_mutex);
1958				SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
1959				    "ibcma_handle_failed: No matching CMID "
1960				    "for qp_hdl %p in REQ AVL of CMID %p",
1961				    eventp->cm_session_id, idp);
1962				break;
1963			}
1964
1965			event_chanp = (sol_cma_chan_t *)event_idp;
1966			mutex_enter(&event_chanp->chan_mutex);
1967			*event_id_ptr = event_idp;
1968			avl_remove(&root_chanp->chan_req_avl_tree,
1969			    event_idp);
1970			root_chanp->chan_req_cnt--;
1971			event_chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1972			event_chanp->chan_qp_hdl = NULL;
1973			mutex_exit(&event_chanp->chan_mutex);
1974			mutex_exit(&root_chanp->chan_mutex);
1975
1976
1977			*evt_status = IBT_CM_TIMEOUT;
1978			*event = RDMA_CM_EVENT_REJECTED;
1979		}
1980		if (!eventp->cm_session_id && root_idp) {
1981			SOL_OFS_DPRINTF_L0(sol_rdmacm_dbg_str,
1982			    "ibcma_handle_failed: timeout "
1983			    "session_id NULL");
1984		}
1985		if (!root_idp) {
1986			*event_id_ptr  = idp;
1987			mutex_enter(&chanp->chan_mutex);
1988			chanp->chan_cmid_destroy_state |=
1989			    SOL_CMA_CALLER_EVENT_PROGRESS;
1990			chanp->chan_qp_hdl = NULL;
1991			chanp->chan_connect_flag =
1992			    SOL_CMA_CONNECT_CLIENT_NONE;
1993			mutex_exit(&chanp->chan_mutex);
1994			*evt_status = IBT_CM_TIMEOUT;
1995			*event = RDMA_CM_EVENT_REJECTED;
1996		}
1997		break;
1998
1999	case IBT_CM_FAILURE_STALE :
2000		/* Stale connection, ignore */
2001		break;
2002	}
2003	return (IBT_CM_DEFAULT);
2004}
2005
2006static ibt_cm_status_t
2007ibcma_rc_hdlr(void *inp, ibt_cm_event_t *eventp,
2008    ibt_cm_return_args_t *ret_args, void *priv_data,
2009    ibt_priv_data_len_t priv_datalen)
2010{
2011	struct rdma_cm_id	*idp, *event_idp;
2012	sol_cma_chan_t		*chanp;
2013	ibt_cm_status_t		status;
2014	ibt_status_t		ibt_status;
2015	enum rdma_cm_event_type event;
2016	struct rdma_conn_param	conn_param, *paramp = &conn_param;
2017	int	event_status;
2018
2019	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "ib_cma_rc_hdlr(%p, %p, %p, "
2020	    "%p, %x)", inp, eventp, ret_args, priv_data, priv_datalen);
2021	idp = event_idp = (struct rdma_cm_id *)inp;
2022	chanp = (sol_cma_chan_t *)idp;
2023	chanp->chan_session_id = NULL;
2024
2025	bzero(paramp, sizeof (struct rdma_conn_param));
2026	switch (eventp->cm_type) {
2027
2028	case IBT_CM_EVENT_REQ_RCV :
2029		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2030		    "ibcma_rc_hdlr : REQ Event");
2031
2032		/*
2033		 * We need to do a round trip to userland. Send a MRA
2034		 * so that the client does not send multiple REQs. Then
2035		 * continue the processing of REQs.
2036		 */
2037		ibt_status =  ibt_cm_delay(IBT_CM_DELAY_REQ,
2038		    eventp->cm_session_id, SOL_OFS_REQ_DELAY, NULL, 0);
2039		if (ibt_status != IBT_SUCCESS) {
2040			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
2041			    "ibcma_rc_hdlr : ibt_cma_delay failed %x",
2042			    ibt_status);
2043			return (IBT_CM_REJECT);
2044		}
2045		status = ibcma_handle_req(idp, &event_idp, eventp, paramp,
2046		    &event, &event_status);
2047		if (status == IBT_CM_REJECT)
2048			return (status);
2049		break;
2050	case IBT_CM_EVENT_REP_RCV :
2051		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2052		    "ibcma_rc_hdlr : REP Event");
2053
2054		ibcma_handle_rep(idp, eventp);
2055		return (IBT_CM_DEFAULT);
2056		/* NOTREACHED */
2057		/* break; */
2058	case IBT_CM_EVENT_LAP_RCV :
2059	case IBT_CM_EVENT_APR_RCV :
2060		/*
2061		 * Alternate Paths not supported from userland. Return
2062		 * IBT_CM_REJECT.
2063		 */
2064		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2065		    "ibcma_rc_hdlr : AP Event");
2066		return (IBT_CM_REJECT);
2067		/* NOTREACHED */
2068		/* break; */
2069	case IBT_CM_EVENT_MRA_RCV :
2070		/* Let Solaris ibcm take default action for MRA */
2071		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2072		    "ibcma_rc_hdlr : MRA Event");
2073		return (IBT_CM_DEFAULT);
2074		/* NOTREACHED */
2075		/* break; */
2076	case IBT_CM_EVENT_CONN_EST :
2077		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2078		    "ibcma_rc_hdlr : EST Event");
2079		status = ibcma_handle_est(idp, &event_idp, eventp, paramp,
2080		    &event, &event_status);
2081		break;
2082	case IBT_CM_EVENT_CONN_CLOSED :
2083		/*
2084		 * Pass on RDMA_CM_EVENT_DISCONNECTED to consumer
2085		 */
2086		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2087		    "ibcma_rc_hdlr : CLOSED Event");
2088		status = ibcma_handle_closed(idp, &event_idp, eventp,
2089		    &event, &event_status);
2090		break;
2091
2092	case IBT_CM_EVENT_FAILURE :
2093		/* Handle Failure Event */
2094		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2095		    "ibcma_rc_hdlr : FAIL Event");
2096		status = ibcma_handle_failed(idp, &event_idp, eventp, paramp,
2097		    &event, &event_status);
2098
2099		/*
2100		 * Check if there is an event to be send to the userland.
2101		 * Return if there are none.
2102		 */
2103		if (event_status == 0)
2104			return (status);
2105		break;
2106	}
2107
2108	/* Pass back the event to sol_cma consumer */
2109	if (event_idp) {
2110		cma_generate_event(event_idp, event, event_status,
2111		    paramp, NULL);
2112	} else
2113		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
2114		    "No Event to userland!!");
2115	if (paramp->private_data)
2116		kmem_free((void *)paramp->private_data,
2117		    paramp->private_data_len);
2118
2119	return (status);
2120}
2121
2122static void
2123ibcma_multicast_hdlr(void *arg, ibt_status_t status, ibt_mcg_info_t *mcg_infop)
2124{
2125	struct rdma_cm_id	*idp;
2126	ibcma_mcast_t		*ib_mcastp = (ibcma_mcast_t *)arg;
2127	int			evt_status;
2128	struct rdma_ud_param	uddata, *ud_param = &uddata;
2129	enum rdma_cm_event_type event;
2130
2131	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "multicast_hdlr(%p, %x, %p)",
2132	    arg, status, mcg_infop);
2133	idp = ib_mcastp->mcast_idp;
2134
2135	bzero(ud_param, sizeof (struct rdma_ud_param));
2136	bcopy(&(mcg_infop->mc_adds_vect.av_dgid),
2137	    &(ib_mcastp->mcast_gid), sizeof (ib_gid_t));
2138	ud_param->private_data = ib_mcastp->mcast_ctx;
2139
2140	event = (status == IBT_SUCCESS) ?
2141	    RDMA_CM_EVENT_MULTICAST_JOIN : RDMA_CM_EVENT_MULTICAST_ERROR;
2142	evt_status = (status == IBT_SUCCESS) ? 0 : -1;
2143	if (status == IBT_SUCCESS) {
2144		mcginfo2ah(mcg_infop, &ud_param->ah_attr);
2145		ud_param->qp_num = IB_MC_QPN;
2146		if (idp->ps == RDMA_PS_UDP)
2147			ud_param->qkey = RDMA_UDP_QKEY;
2148		else
2149			ud_param->qkey = SOL_IPOIB_DEFAULT_QKEY;
2150	}
2151
2152	/* Send the event to consumer of sol_cma.  */
2153	cma_generate_event(idp, event, evt_status, NULL, ud_param);
2154	kmem_free(mcg_infop, sizeof (ibt_mcg_info_t));
2155}
2156
2157static int
2158ibcma_get_first_ib_ipaddr(struct rdma_cm_id *idp)
2159{
2160	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)idp;
2161	ibcma_chan_t	*ibchanp;
2162	int		num_hcas, info_inited = 0;
2163	ib_guid_t	*hca_guidp;
2164	genlist_t	devlist;
2165	genlist_entry_t	*entry;
2166	ibcma_dev_t	*devp;
2167
2168	ASSERT(idp);
2169	ibchanp = &(chanp->chan_ib);
2170	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "get_first_ib_ipaddr(%p)", idp);
2171
2172	num_hcas = ibt_get_hca_list(&hca_guidp);
2173	ibcma_get_devlist(chanp, hca_guidp, num_hcas, &devlist, B_TRUE);
2174	entry = remove_genlist_head(&devlist);
2175	while (entry) {
2176		devp = (ibcma_dev_t *)entry->data;
2177		if (info_inited == 0) {
2178			(idp->route).num_paths = 0;
2179			idp->port_num = devp->dev_port_num;
2180			chanp->chan_xport_type = SOL_CMA_XPORT_IB;
2181			ibchanp->chan_devp = devp;
2182			info_inited = 1;
2183		} else {
2184			kmem_free(devp, sizeof (ibcma_dev_t));
2185		}
2186		kmem_free(entry, sizeof (genlist_entry_t));
2187		entry = remove_genlist_head(&devlist);
2188	}
2189	ibt_free_hca_list(hca_guidp, num_hcas);
2190
2191	if (info_inited)
2192		return (0);
2193	else
2194		return (ENODEV);
2195}
2196
2197/* Utility Conversion functions */
2198static void
2199ipaddr2sockaddr(ibt_ip_addr_t *ibt_addrp, struct sockaddr *sock_addrp,
2200    in_port_t *portp)
2201{
2202		sock_addrp->sa_family = ibt_addrp->family;
2203		if (ibt_addrp->family == AF_INET) {
2204			struct sockaddr_in	*sock_in4p;
2205			sock_in4p = (struct sockaddr_in *)sock_addrp;
2206
2207			sock_in4p->sin_addr.s_addr = ibt_addrp->un.ip4addr;
2208			if (portp)
2209				sock_in4p->sin_port = ntohs(*portp);
2210		} else {
2211			struct sockaddr_in6 *in6_addr;
2212			in6_addr = (struct sockaddr_in6 *)sock_addrp;
2213
2214			bcopy(&(ibt_addrp->un.ip6addr), &(in6_addr->sin6_addr),
2215			    sizeof (in6_addr_t));
2216			if (portp)
2217				in6_addr->sin6_port = *portp;
2218		}
2219}
2220
2221static void
2222sockaddr2ibtaddr_port(struct rdma_cm_id *idp, struct sockaddr *sock_addrp,
2223    ibt_ip_addr_t *ibt_addrp, in_port_t *portp)
2224{
2225	in_port_t	ip_port;
2226
2227	ibt_addrp->family = sock_addrp->sa_family;
2228	if (sock_addrp->sa_family == AF_INET) {
2229		struct sockaddr_in	*sock_in4p;
2230		sock_in4p = (struct sockaddr_in *)sock_addrp;
2231
2232		ibt_addrp->un.ip4addr = sock_in4p->sin_addr.s_addr;
2233		if (IS_UDP_CMID(idp))
2234			ip_port = ddi_swap16(sock_in4p->sin_port);
2235		else
2236			ip_port = htons(sock_in4p->sin_port);
2237
2238		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "sockaddr2ibtaddr : "
2239		    "AF_INET addr %x, port %x, %x", ibt_addrp->un.ip4addr,
2240		    sock_in4p->sin_port, ip_port);
2241
2242		if (portp)
2243			*portp = ip_port;
2244
2245	} else {
2246		struct sockaddr_in6	*in6_addr;
2247		in6_addr = (struct sockaddr_in6 *)sock_addrp;
2248		bcopy(&(in6_addr->sin6_addr), &(ibt_addrp->un.ip6addr),
2249		    sizeof (in6_addr_t));
2250		if (portp)
2251			*portp = in6_addr->sin6_port;
2252	}
2253}
2254
2255static void
2256mcginfo2ah(ibt_mcg_info_t *mcgp, struct ib_ah_attr *ah_attr)
2257{
2258	ibt_adds_vect_t	*adds_vectp;
2259	ib_gid_t	dgid_nworder;
2260
2261	adds_vectp = &(mcgp->mc_adds_vect);
2262
2263	/*
2264	 * Libraries expect the GID to be in network order. Convert
2265	 * to network order before passing it to the library.
2266	 */
2267	dgid_nworder.gid_prefix = htonll(
2268	    (adds_vectp->av_dgid).gid_prefix);
2269	dgid_nworder.gid_guid = htonll(
2270	    (adds_vectp->av_dgid).gid_guid);
2271	bcopy(&dgid_nworder, &((ah_attr->grh).dgid), sizeof (ib_gid_t));
2272
2273	(ah_attr->grh).flow_label =  adds_vectp->av_flow;
2274	(ah_attr->grh).sgid_index = adds_vectp->av_sgid_ix;
2275	(ah_attr->grh).hop_limit = adds_vectp->av_hop;
2276	(ah_attr->grh).traffic_class = adds_vectp->av_tclass;
2277
2278	ah_attr->dlid = adds_vectp->av_dlid;
2279	ah_attr->sl = adds_vectp->av_srvl;
2280	ah_attr->src_path_bits = adds_vectp->av_src_path;
2281	ah_attr->static_rate = adds_vectp->av_srate;
2282	ah_attr->ah_flags = (adds_vectp->av_send_grh) ? 1 : 0;
2283	ah_attr->port_num = adds_vectp->av_port_num;
2284}
2285
2286static void
2287ibt_path2ah(ibt_path_info_t *pathp, struct ib_ah_attr *ah_attr)
2288{
2289
2290	ibt_addsvect2ah(&((pathp->pi_prim_cep_path).cep_adds_vect), ah_attr);
2291}
2292
2293static void
2294ibt_addsvect2ah(ibt_adds_vect_t *adds_vectp, struct ib_ah_attr *ah_attr)
2295{
2296	ib_gid_t	dgid_nworder;
2297
2298	/*
2299	 * Libraries expect the GID to be in network order. Convert
2300	 * to network order before passing it to the library.
2301	 */
2302	dgid_nworder.gid_prefix = htonll(
2303	    (adds_vectp->av_dgid).gid_prefix);
2304	dgid_nworder.gid_guid = htonll(
2305	    (adds_vectp->av_dgid).gid_guid);
2306	bcopy(&dgid_nworder, &((ah_attr->grh).dgid), sizeof (ib_gid_t));
2307	(ah_attr->grh).flow_label =  adds_vectp->av_flow;
2308	(ah_attr->grh).sgid_index = adds_vectp->av_sgid_ix;
2309	(ah_attr->grh).hop_limit = adds_vectp->av_hop;
2310	(ah_attr->grh).traffic_class = adds_vectp->av_tclass;
2311
2312	ah_attr->dlid = adds_vectp->av_dlid;
2313	ah_attr->sl = adds_vectp->av_srvl;
2314	ah_attr->src_path_bits = adds_vectp->av_src_path;
2315	ah_attr->static_rate = adds_vectp->av_srate;
2316	ah_attr->ah_flags = (adds_vectp->av_send_grh) ? 1 : 0;
2317	ah_attr->port_num = adds_vectp->av_port_num;
2318}
2319
2320static void
2321ibt_path2sa_path(ibt_path_info_t *pathp, struct ib_sa_path_rec *sa_pathp,
2322    ib_lid_t base_lid)
2323{
2324	ibt_adds_vect_t	*adds_vectp;
2325
2326	adds_vectp = &((pathp->pi_prim_cep_path).cep_adds_vect);
2327	ibt_addsvect2sa_path(adds_vectp, sa_pathp, base_lid);
2328	sa_pathp->mtu = pathp->pi_path_mtu;
2329	sa_pathp->packet_life_time = pathp->pi_prim_pkt_lt;
2330}
2331
2332static void
2333ibt_addsvect2sa_path(ibt_adds_vect_t *adds_vectp,
2334    struct ib_sa_path_rec *sa_pathp, ib_lid_t base_lid)
2335{
2336	bcopy(&(adds_vectp->av_dgid), &(sa_pathp->dgid), 16);
2337	bcopy(&(adds_vectp->av_sgid), &(sa_pathp->sgid), 16);
2338	sa_pathp->dlid = adds_vectp->av_dlid;
2339	sa_pathp->slid = base_lid + adds_vectp->av_src_path;
2340	sa_pathp->flow_label =  adds_vectp->av_flow;
2341	sa_pathp->reversible = 1;
2342	sa_pathp->hop_limit = adds_vectp->av_hop;
2343	sa_pathp->traffic_class  = adds_vectp->av_tclass;
2344	sa_pathp->sl = adds_vectp->av_srvl;
2345	sa_pathp->rate = adds_vectp->av_srate;
2346	sa_pathp->mtu_selector = IBT_EQU;
2347	sa_pathp->rate_selector = IBT_EQU;
2348	sa_pathp->packet_life_time_selector = IBT_EQU;
2349}
2350
2351/*
2352 * Map a multicast IP onto multicast MAC for type IP-over-InfiniBand.
2353 * Leave P_Key as 0 to be filled in by caller
2354 */
2355static void
2356ip_ib_mc_map(uint32_t addr, char *buf)
2357{
2358	buf[0]  = 0;		/* Reserved */
2359	buf[1]  = 0xff;		/* Multicast QPN */
2360	buf[2]  = 0xff;
2361	buf[3]  = 0xff;
2362	addr    = ntohl(addr);
2363	buf[4]  = 0xff;
2364	buf[5]  = 0x12;		/* link local scope */
2365	buf[6]  = 0x40;		/* IPv4 signature */
2366	buf[7]  = 0x1b;
2367	buf[8]  = 0;		/* P_Key */
2368	buf[9]  = 0;
2369	buf[10] = 0;
2370	buf[11] = 0;
2371	buf[12] = 0;
2372	buf[13] = 0;
2373	buf[14] = 0;
2374	buf[15] = 0;
2375	buf[19] = addr & 0xff;
2376	addr  >>= 8;
2377	buf[18] = addr & 0xff;
2378	addr  >>= 8;
2379	buf[17] = addr & 0xff;
2380	addr  >>= 8;
2381	buf[16] = addr & 0x0f;
2382}
2383
2384static void
2385ipaddr2mgid(struct sockaddr *addrp, ib_gid_t *mgidp, ib_pkey_t pkey)
2386{
2387	char			mc_map[32];	/* Max H/W addr len */
2388	struct sockaddr_in	*sin = (struct sockaddr_in *)addrp;
2389	struct sockaddr_in6	*sin6 = (struct sockaddr_in6 *)addrp;
2390
2391	if ((addrp->sa_family ==  AF_INET6) &&
2392	    b2h32((sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) ==
2393	    0xFF10A01B) {
2394		bcopy(&sin6->sin6_addr, mgidp, sizeof (ib_gid_t));
2395	} else {
2396		ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
2397		mc_map[7] = 0x01;   /* Use RDMA CM signature */
2398		mc_map[8] = (char)(pkey >> 8);
2399		mc_map[9] = (char)(pkey);
2400		bcopy(mc_map+4, mgidp, sizeof (ib_gid_t));
2401	}
2402}
2403
2404static int
2405ibcma_any_addr(ibt_ip_addr_t *addr)
2406{
2407	ASSERT(addr);
2408	if (addr->family == AF_INET)
2409		return (addr->un.ip4addr == INADDR_ANY);
2410	else if (addr->family == AF_INET6)
2411		return (IN6_IS_ADDR_UNSPECIFIED(&(addr->un.ip6addr)));
2412	return (0);
2413}
2414
2415static struct rdma_cm_id *
2416ibcma_create_new_id(struct rdma_cm_id *idp)
2417{
2418	struct rdma_cm_id	*new_idp;
2419	sol_cma_chan_t		*chanp, *new_chanp;
2420	ibcma_chan_t		*ibchanp, *new_ibchanp;
2421
2422	new_idp = cma_create_new_id(idp);
2423	if (new_idp == NULL)
2424		return (new_idp);
2425	new_chanp = (sol_cma_chan_t *)new_idp;
2426	new_ibchanp = &new_chanp->chan_ib;
2427	chanp = (sol_cma_chan_t *)idp;
2428	ibchanp = &chanp->chan_ib;
2429	if (ibchanp->chan_devp) {
2430		ibcma_dev_t	*devp;
2431
2432		devp = (ibcma_dev_t *)kmem_zalloc(sizeof (ibcma_dev_t),
2433		    KM_SLEEP);
2434		new_ibchanp->chan_devp = devp;
2435		bcopy(ibchanp->chan_devp, devp, sizeof (ibcma_dev_t));
2436	}
2437
2438	if (ibchanp->chan_pathp && ibchanp->chan_numpaths &&
2439	    ibchanp->chan_path_size) {
2440		new_ibchanp->chan_pathp = (ibt_path_info_t *)kmem_zalloc(
2441		    ibchanp->chan_path_size, KM_SLEEP);
2442		bcopy(ibchanp->chan_pathp, new_ibchanp->chan_pathp,
2443		    ibchanp->chan_path_size);
2444		new_ibchanp->chan_path_size = ibchanp->chan_path_size;
2445		new_ibchanp->chan_numpaths = ibchanp->chan_numpaths;
2446	}
2447	bcopy(&ibchanp->chan_local_addr, &new_ibchanp->chan_local_addr,
2448	    sizeof (ibt_ip_addr_t));
2449	bcopy(&ibchanp->chan_remote_addr, &new_ibchanp->chan_remote_addr,
2450	    sizeof (ibt_ip_addr_t));
2451	new_ibchanp->chan_port = ibchanp->chan_port;
2452	new_ibchanp->chan_sid = ibchanp->chan_sid;
2453
2454	return (new_idp);
2455}
2456
2457static void
2458ibcma_get_devlist(sol_cma_chan_t *root_chanp, ib_guid_t *hca_guidp,
2459    int num_hcas, genlist_t *ret_devlist, boolean_t with_ipaddr_only)
2460{
2461	int			i;
2462	ibt_status_t		status;
2463	ibcma_dev_t		*devp;
2464	uint_t			num_ports, p;
2465	uint_t			port_size;
2466	ibt_hca_portinfo_t	*port_info, *tmp;
2467	ibt_srcip_info_t	*src_info;
2468	ibt_srcip_attr_t	attr;
2469	uint_t			entries;
2470
2471	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2472	    "get_devlist(%p, %p, %x, %p, %x)", root_chanp, hca_guidp,
2473	    num_hcas, ret_devlist, with_ipaddr_only);
2474
2475	init_genlist(ret_devlist);
2476	for (i = 0; i < num_hcas; i++) {
2477		status = ibt_query_hca_ports_byguid(hca_guidp[i], 0, &port_info,
2478		    &num_ports, &port_size);
2479		if (status !=  IBT_SUCCESS) {
2480			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
2481			    "ibt_query_hca_ports_byguid failed %d", status);
2482			continue;
2483		}
2484
2485		for (p = 0, tmp = port_info; p < num_ports; p++, tmp++) {
2486			uint_t		s, num_sgids;
2487			uint16_t	pk;
2488			uint_t		num_pkeys;
2489
2490			if (tmp->p_linkstate != IBT_PORT_ACTIVE)
2491				continue;
2492
2493			num_sgids = tmp->p_sgid_tbl_sz / sizeof (ib_gid_t);
2494			num_pkeys = tmp->p_pkey_tbl_sz / sizeof (ib_pkey_t);
2495
2496			for (s = 0; s < num_sgids; s++) {
2497				/* Skip holes in sgid table */
2498				if (tmp->p_sgid_tbl[s].gid_guid == 0x0LL)
2499					continue;
2500				for (pk = 0; pk < num_pkeys; pk++) {
2501					/* Skip holes in pkey table */
2502					if (tmp->p_pkey_tbl[pk] == 0)
2503						continue;
2504					if (with_ipaddr_only == B_TRUE) {
2505						bcopy(&tmp->p_sgid_tbl[s],
2506						    &attr.sip_gid,
2507						    sizeof (ib_gid_t));
2508						attr.sip_pkey =
2509						    tmp->p_pkey_tbl[pk];
2510						attr.sip_family = AF_INET;
2511						attr.sip_zoneid = 0;
2512
2513						status = ibt_get_src_ip(&attr,
2514						    &src_info, &entries);
2515						if (status != IBT_SUCCESS)
2516							continue;
2517					}
2518
2519					/* allocate devinfo & fill in info */
2520					devp = kmem_zalloc(
2521					    sizeof (ibcma_dev_t), KM_SLEEP);
2522					devp->dev_node_guid = hca_guidp[i];
2523					devp->dev_port_num = p + 1;
2524					devp->dev_pkey_ix = pk;
2525					devp->dev_pkey = tmp->p_pkey_tbl[pk];
2526					devp->dev_sgid = tmp->p_sgid_tbl[s];
2527					if (with_ipaddr_only == B_TRUE) {
2528						bcopy(&src_info[0].ip_addr,
2529						    &devp->dev_ipaddr,
2530						    sizeof (ibt_ip_addr_t));
2531						ibt_free_srcip_info(src_info,
2532						    entries);
2533					}
2534
2535					SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2536					    "get_devlist: add2devlist "
2537					    "node_guid %llx", hca_guidp[i]);
2538					(void) add_genlist(ret_devlist,
2539					    (uintptr_t)devp, NULL);
2540				}
2541			}
2542		}
2543		ibt_free_portinfo(port_info, port_size);
2544	}
2545}
2546
2547
2548#ifdef	QP_DEBUG
2549static void
2550dump_qp_info(ibt_qp_hdl_t qphdl)
2551{
2552	ibt_qp_query_attr_t	qp_query;
2553	ibt_qp_info_t		*qp_info;
2554	ibt_status_t		status;
2555	ibt_qp_rc_attr_t	*rcp;
2556
2557	bzero(&qp_query, sizeof (qp_query));
2558	status = ibt_query_qp(qphdl, &qp_query);
2559	if (status != IBT_SUCCESS) {
2560		cmn_err(CE_WARN, "query_qp failed!!");
2561		return;
2562	}
2563	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2564	    "QP HDL : %p, qp_sq_cq %p, qp_rq_cq %p, "
2565	    "qp_rdd_hdl %p, qp_qpn %x, qp_sq_sgl %x, qp_rq_sgl %x, "
2566	    "qp_srq %p, quer_attr.qp_flags %x",
2567	    qphdl, qp_query.qp_sq_cq, qp_query.qp_rq_cq,
2568	    qp_query.qp_rdd_hdl, qp_query.qp_qpn,
2569	    qp_query.qp_sq_sgl, qp_query.qp_rq_sgl,
2570	    qp_query.qp_srq, qp_query.qp_flags);
2571	qp_info = &(qp_query.qp_info);
2572	rcp = &((qp_info->qp_transport).rc);
2573	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2574	    "qp_sq_sz %x, qp_rq_sz %x, qp_state %x, "
2575	    "qp_current_state %x, qp_info.qp_flags %x, qp_trans %x",
2576	    qp_info->qp_sq_sz, qp_info->qp_rq_sz, qp_info->qp_state,
2577	    qp_info->qp_current_state, qp_info->qp_flags,
2578	    qp_info->qp_trans);
2579	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2580	    "rc_sq_psn %x, rc_rq_psn %x, rc_dst_qpn %x, "
2581	    "rc_mig_state %x, rc_rnr_retry_cnt %x, rc_retry_cnt %x, "
2582	    "rc_rdma_ra_out %x, rc_rdma_ra_in %x, rc_min_rnr_nak %x, "
2583	    "rc_path_mtu %x", rcp->rc_sq_psn, rcp->rc_rq_psn,
2584	    rcp->rc_dst_qpn, rcp->rc_mig_state, rcp->rc_rnr_retry_cnt,
2585	    rcp->rc_retry_cnt, rcp->rc_rdma_ra_out, rcp->rc_rdma_ra_in,
2586	    rcp->rc_min_rnr_nak, rcp->rc_path_mtu);
2587	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2588	    "av_dgid %llx: %llx, av_sgid: %llx, "
2589	    "srate %x, srvl %x, flow %x, tclass %x, hop %x, "
2590	    "av_port_num %x, av_send_grh %x, av_dlid %x, "
2591	    "av_src_path %x, av_sgid_ix %x, pkey_index %x, "
2592	    "port_num %x",
2593	    (rcp->rc_path).cep_adds_vect.av_sgid.gid_prefix,
2594	    (rcp->rc_path).cep_adds_vect.av_sgid.gid_guid,
2595	    (rcp->rc_path).cep_adds_vect.av_dgid.gid_prefix,
2596	    (rcp->rc_path).cep_adds_vect.av_dgid.gid_guid,
2597	    (rcp->rc_path).cep_adds_vect.av_srate,
2598	    (rcp->rc_path).cep_adds_vect.av_srvl,
2599	    (rcp->rc_path).cep_adds_vect.av_flow,
2600	    (rcp->rc_path).cep_adds_vect.av_tclass,
2601	    (rcp->rc_path).cep_adds_vect.av_hop,
2602	    (rcp->rc_path).cep_adds_vect.av_port_num,
2603	    (rcp->rc_path).cep_adds_vect.av_opaque1,
2604	    (rcp->rc_path).cep_adds_vect.av_opaque2,
2605	    (rcp->rc_path).cep_adds_vect.av_opaque3,
2606	    (rcp->rc_path).cep_adds_vect.av_opaque4,
2607	    (rcp->rc_path).cep_pkey_ix,
2608	    (rcp->rc_path).cep_hca_port_num);
2609}
2610#endif
2611
2612static void
2613dump_priv_data(void *priv_data, ibt_priv_data_len_t arr_len,
2614    ibt_priv_data_len_t priv_len, char *caller)
2615{
2616	uint8_t	i;
2617	uchar_t *c = (uchar_t *)priv_data;
2618
2619	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "priv_data to %s: %p, len %d",
2620	    caller, priv_data, priv_len);
2621	if (!priv_len || !priv_data)
2622		return;
2623
2624	/* Display in rows of 16 uchar_t */
2625	for (i = 0; i < arr_len; i += 16)
2626		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
2627		    "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
2628		    c[i], c[i + 1], c[i + 2], c[i + 3], c[i + 4], c[i + 5],
2629		    c[i + 6], c[i + 7], c[i + 8], c[i + 9], c[i + 10],
2630		    c[i + 11], c[i + 12], c[i + 13], c[i + 14], c[i + 15]);
2631
2632}
2633