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 
43 extern 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 	*/
52 static ibt_cm_status_t ibcma_rc_hdlr(void *, ibt_cm_event_t *,
53     ibt_cm_return_args_t *, void *, ibt_priv_data_len_t);
54 static 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);
56 static void ibcma_multicast_hdlr(void *, ibt_status_t, ibt_mcg_info_t *);
57 
58 /*	Local functions 	*/
59 static int ibcma_tcp_connect(struct rdma_cm_id *, ibcma_chan_t *,
60     struct rdma_conn_param *);
61 static int ibcma_udp_connect(struct rdma_cm_id *, ibcma_chan_t *,
62     struct rdma_conn_param *);
63 static struct rdma_cm_id *ibcma_create_new_id(struct rdma_cm_id *);
64 static int ibcma_query_local_ip(struct rdma_cm_id *, sol_cma_chan_t *,
65     ibcma_chan_t *);
66 static int ibcma_get_paths(struct rdma_cm_id *, sol_cma_chan_t *,
67     ibcma_chan_t *);
68 static void ibcma_get_devlist(sol_cma_chan_t *, ib_guid_t *, int,
69     genlist_t *, boolean_t);
70 static int ibcma_any_addr(ibt_ip_addr_t *);
71 static int ibcma_get_first_ib_ipaddr(struct rdma_cm_id *);
72 
73 /* Utility Conversion Routines */
74 static void 	ipaddr2mgid(struct sockaddr *, ib_gid_t *, ib_pkey_t);
75 static void 	ibt_path2ah(ibt_path_info_t *, struct ib_ah_attr *);
76 static void	ibt_addsvect2ah(ibt_adds_vect_t *, struct ib_ah_attr *);
77 static void	ibt_addsvect2sa_path(ibt_adds_vect_t *,
78     struct ib_sa_path_rec *, ib_lid_t);
79 static void	ibt_path2sa_path(ibt_path_info_t *, struct ib_sa_path_rec *,
80     ib_lid_t);
81 static void 	mcginfo2ah(ibt_mcg_info_t *, struct ib_ah_attr *);
82 static void	sockaddr2ibtaddr_port(struct rdma_cm_id *, struct sockaddr *,
83     ibt_ip_addr_t *, in_port_t *);
84 static void ipaddr2sockaddr(ibt_ip_addr_t *, struct sockaddr *,
85     in_port_t *);
86 
87 #ifdef	QP_DEBUG
88 static void 	dump_qp_info(ibt_qp_hdl_t);
89 #endif
90 static void	dump_priv_data(void *, ibt_priv_data_len_t,
91     ibt_priv_data_len_t, char *);
92 
93 extern cma_chan_state_t cma_get_chan_state(sol_cma_chan_t *);
94 
95 /*
96  * RDMA CM API - Transport specific functions
97  */
98 void
rdma_ib_destroy_id(struct rdma_cm_id * idp)99 rdma_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 
144 int
rdma_ib_bind_addr(struct rdma_cm_id * idp,struct sockaddr * addr)145 rdma_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 
185 extern void cma_resolve_addr_callback(sol_cma_chan_t *, int);
186 int
rdma_ib_resolve_addr(struct rdma_cm_id * idp,struct sockaddr * src_addr,struct sockaddr * dst_addr,int timeout_ms)187 rdma_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  */
287 int
rdma_ib_init_qp_attr(struct rdma_cm_id * idp,struct ib_qp_attr * qpattr,int * qp_attr_mask)288 rdma_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 
357 int
rdma_ib_connect(struct rdma_cm_id * idp,struct rdma_conn_param * conn_param)358 rdma_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 
387 extern void sol_cma_add_hca_list(sol_cma_chan_t *, ib_guid_t);
388 void
ibcma_append_listen_list(struct rdma_cm_id * root_idp)389 ibcma_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 
470 int
ibcma_init_root_chan(sol_cma_chan_t * root_chanp,sol_cma_glbl_listen_t * listenp)471 ibcma_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 
506 int
ibcma_fini_root_chan(sol_cma_chan_t * rchanp)507 ibcma_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 
522 void
ibcma_copy_srv_hdl(sol_cma_chan_t * root_chanp,sol_cma_glbl_listen_t * listenp)523 ibcma_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 
529 int
ibcma_fini_ep_chan(sol_cma_chan_t * ep_chanp)530 ibcma_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 
566 uint64_t
ibcma_init_root_sid(sol_cma_chan_t * root_chanp)567 ibcma_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*/
587 int
rdma_ib_listen(struct rdma_cm_id * ep_idp,int bklog)588 rdma_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
618 int
rdma_ib_accept(struct rdma_cm_id * idp,struct rdma_conn_param * conn_param)619 rdma_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 
713 int
rdma_ib_reject(struct rdma_cm_id * idp,const void * private_data,uint8_t private_data_len)714 rdma_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 
778 int
rdma_ib_disconnect(struct rdma_cm_id * idp)779 rdma_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 
836 handle_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 
870 int
rdma_ib_join_multicast(struct rdma_cm_id * idp,struct sockaddr * addr,void * context)871 rdma_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 
954 void
rdma_ib_leave_multicast(struct rdma_cm_id * idp,struct sockaddr * addr)955 rdma_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
992 static int
ibcma_tcp_connect(struct rdma_cm_id * idp,ibcma_chan_t * ibchanp,struct rdma_conn_param * conn_paramp)993 ibcma_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 
1088 static int
ibcma_udp_connect(struct rdma_cm_id * idp,ibcma_chan_t * ibchanp,struct rdma_conn_param * conn_paramp)1089 ibcma_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 
1154 static int
ibcma_init_devinfo(struct rdma_cm_id * idp,ibcma_chan_t * ibchanp,ibt_path_info_t * pathp)1155 ibcma_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 
1197 static int
ibcma_query_local_ip(struct rdma_cm_id * idp,sol_cma_chan_t * chanp,ibcma_chan_t * ibchanp)1198 ibcma_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 
1242 static void
ibcma_path_hdlr(void * arg,ibt_status_t retval,ibt_path_info_t * pathp,uint8_t num_paths,ibt_path_ip_src_t * src_ip_p)1243 ibcma_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 
1300 static int
ibcma_get_paths(struct rdma_cm_id * idp,sol_cma_chan_t * chanp,ibcma_chan_t * ibchanp)1301 ibcma_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*/
1343 static ibt_cm_status_t
ibcma_ud_hdlr(void * inp,ibt_cm_ud_event_t * eventp,ibt_cm_ud_return_args_t * ret_args,void * priv_data,ibt_priv_data_len_t priv_datalen)1344 ibcma_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 
1507 ud_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 
1520 static ibt_cm_status_t
ibcma_handle_req(struct rdma_cm_id * idp,struct rdma_cm_id ** event_id_ptr,ibt_cm_event_t * eventp,struct rdma_conn_param * paramp,enum rdma_cm_event_type * event,int * evt_status)1521 ibcma_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 
1713 static void
ibcma_handle_rep(struct rdma_cm_id * idp,ibt_cm_event_t * eventp)1714 ibcma_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 
1743 static ibt_cm_status_t
ibcma_handle_est(struct rdma_cm_id * idp,struct rdma_cm_id ** event_id_ptr,ibt_cm_event_t * eventp,struct rdma_conn_param * paramp,enum rdma_cm_event_type * event,int * evt_status)1744 ibcma_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 
1797 est_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 
1813 static ibt_cm_status_t
ibcma_handle_closed(struct rdma_cm_id * idp,struct rdma_cm_id ** event_id_ptr,ibt_cm_event_t * eventp,enum rdma_cm_event_type * event,int * evt_status)1814 ibcma_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 
1862 static ibt_cm_status_t
ibcma_handle_failed(struct rdma_cm_id * idp,struct rdma_cm_id ** event_id_ptr,ibt_cm_event_t * eventp,struct rdma_conn_param * paramp,enum rdma_cm_event_type * event,int * evt_status)1863 ibcma_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 
2006 static ibt_cm_status_t
ibcma_rc_hdlr(void * inp,ibt_cm_event_t * eventp,ibt_cm_return_args_t * ret_args,void * priv_data,ibt_priv_data_len_t priv_datalen)2007 ibcma_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 
2122 static void
ibcma_multicast_hdlr(void * arg,ibt_status_t status,ibt_mcg_info_t * mcg_infop)2123 ibcma_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 
2157 static int
ibcma_get_first_ib_ipaddr(struct rdma_cm_id * idp)2158 ibcma_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 */
2198 static void
ipaddr2sockaddr(ibt_ip_addr_t * ibt_addrp,struct sockaddr * sock_addrp,in_port_t * portp)2199 ipaddr2sockaddr(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 
2221 static void
sockaddr2ibtaddr_port(struct rdma_cm_id * idp,struct sockaddr * sock_addrp,ibt_ip_addr_t * ibt_addrp,in_port_t * portp)2222 sockaddr2ibtaddr_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 
2255 static void
mcginfo2ah(ibt_mcg_info_t * mcgp,struct ib_ah_attr * ah_attr)2256 mcginfo2ah(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 
2286 static void
ibt_path2ah(ibt_path_info_t * pathp,struct ib_ah_attr * ah_attr)2287 ibt_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 
2293 static void
ibt_addsvect2ah(ibt_adds_vect_t * adds_vectp,struct ib_ah_attr * ah_attr)2294 ibt_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 
2320 static void
ibt_path2sa_path(ibt_path_info_t * pathp,struct ib_sa_path_rec * sa_pathp,ib_lid_t base_lid)2321 ibt_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 
2332 static void
ibt_addsvect2sa_path(ibt_adds_vect_t * adds_vectp,struct ib_sa_path_rec * sa_pathp,ib_lid_t base_lid)2333 ibt_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  */
2355 static void
ip_ib_mc_map(uint32_t addr,char * buf)2356 ip_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 
2384 static void
ipaddr2mgid(struct sockaddr * addrp,ib_gid_t * mgidp,ib_pkey_t pkey)2385 ipaddr2mgid(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 
2404 static int
ibcma_any_addr(ibt_ip_addr_t * addr)2405 ibcma_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 
2415 static struct rdma_cm_id *
ibcma_create_new_id(struct rdma_cm_id * idp)2416 ibcma_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 
2457 static void
ibcma_get_devlist(sol_cma_chan_t * root_chanp,ib_guid_t * hca_guidp,int num_hcas,genlist_t * ret_devlist,boolean_t with_ipaddr_only)2458 ibcma_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
2549 static void
dump_qp_info(ibt_qp_hdl_t qphdl)2550 dump_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 
2612 static void
dump_priv_data(void * priv_data,ibt_priv_data_len_t arr_len,ibt_priv_data_len_t priv_len,char * caller)2613 dump_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