xref: /illumos-gate/usr/src/uts/common/io/ib/clients/of/sol_ofs/sol_cma.c (revision c0dd49bdd68c0d758a67d56f07826f3b45cfc664)
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  * sol_cma is a part of sol_ofs misc module. This file
28  * provides interfaces for supporting the communication
29  * management API defined in "rdma_cm.h". In-Kernel
30  * consumers of the "rdma_cm.h" API should link sol_ofs
31  * misc module using :
32  *	-N misc/sol_ofs
33  * Solaris uCMA (sol_ucma) driver is the current consumer for
34  * sol_cma.
35  */
36 
37 /* Standard driver includes */
38 #include <sys/types.h>
39 #include <sys/modctl.h>
40 #include <sys/errno.h>
41 #include <sys/stat.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/modctl.h>
45 
46 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
47 #include <sys/ib/clients/of/ofed_kernel.h>
48 #include <sys/ib/clients/of/rdma/ib_addr.h>
49 #include <sys/ib/clients/of/rdma/rdma_cm.h>
50 
51 #include <sys/ib/clients/of/sol_ofs/sol_cma.h>
52 #include <sys/ib/clients/of/sol_ofs/sol_kverb_impl.h>
53 
54 /* Modload support */
55 static struct modlmisc sol_ofs_modmisc	= {
56 	&mod_miscops,
57 	"Solaris OFS Misc module"
58 };
59 
60 struct modlinkage sol_ofs_modlinkage = {
61 	MODREV_1,
62 	(void *)&sol_ofs_modmisc,
63 	NULL
64 };
65 
66 static ib_client_t	*sol_cma_ib_client;
67 sol_cma_glbl_listen_t	sol_cma_glbl_listen;
68 avl_tree_t		sol_cma_glbl_listen_tree;
69 
70 static void		sol_cma_add_dev(struct ib_device *);
71 static void		sol_cma_rem_dev(struct ib_device *);
72 
73 static llist_head_t	sol_cma_dev_list = LLIST_HEAD_INIT(sol_cma_dev_list);
74 kmutex_t		sol_cma_dev_mutex;
75 kmutex_t		sol_cma_glob_mutex;
76 
77 char	*sol_rdmacm_dbg_str = "sol_rdmacm";
78 char	*sol_ofs_dbg_str = "sol_ofs_mod";
79 
80 /*
81  * Local functions defines.
82  */
83 int sol_cma_req_cmid_cmp(const void *p1, const void *p2);
84 int sol_cma_cmid_cmp(const void *p1, const void *p2);
85 int sol_cma_svc_cmp(const void *, const void *);
86 
87 static struct rdma_cm_id *cma_alloc_chan(rdma_cm_event_handler,
88     void *, enum rdma_port_space);
89 static void cma_set_chan_state(sol_cma_chan_t *, cma_chan_state_t);
90 static int cma_cas_chan_state(sol_cma_chan_t *, cma_chan_state_t,
91     cma_chan_state_t);
92 static void cma_free_listen_list(struct rdma_cm_id *);
93 static void cma_destroy_id(struct rdma_cm_id *);
94 static void cma_handle_nomore_events(sol_cma_chan_t *);
95 
96 extern void sol_ofs_dprintf_init();
97 extern void sol_ofs_dprintf_fini();
98 
99 cma_chan_state_t cma_get_chan_state(sol_cma_chan_t *);
100 extern int ibcma_init_root_chan(sol_cma_chan_t *, sol_cma_glbl_listen_t *);
101 extern int ibcma_fini_root_chan(sol_cma_chan_t *);
102 extern void ibcma_copy_srv_hdl(sol_cma_chan_t *, sol_cma_glbl_listen_t *);
103 extern int ibcma_fini_ep_chan(sol_cma_chan_t *);
104 extern uint64_t ibcma_init_root_sid(sol_cma_chan_t *);
105 extern void rdma_ib_destroy_id(struct rdma_cm_id *);
106 extern int rdma_ib_bind_addr(struct rdma_cm_id *, struct sockaddr *);
107 extern int rdma_ib_resolve_addr(struct rdma_cm_id *, struct sockaddr *,
108     struct sockaddr *, int);
109 extern int rdma_ib_resolve_route(struct rdma_cm_id *, int);
110 extern int rdma_ib_init_qp_attr(struct rdma_cm_id *, struct ib_qp_attr *,
111     int *);
112 extern int rdma_ib_connect(struct rdma_cm_id *, struct rdma_conn_param *);
113 extern int rdma_ib_listen(struct rdma_cm_id *, int);
114 extern int rdma_ib_accept(struct rdma_cm_id *, struct rdma_conn_param *);
115 extern int rdma_ib_reject(struct rdma_cm_id *, const void *, uint8_t);
116 extern int rdma_ib_disconnect(struct rdma_cm_id *);
117 extern int rdma_ib_join_multicast(struct rdma_cm_id *, struct sockaddr *,
118     void *);
119 extern void rdma_ib_leave_multicast(struct rdma_cm_id *, struct sockaddr *);
120 
121 int
122 _init(void)
123 {
124 	int		err;
125 
126 	sol_ofs_dprintf_init();
127 	SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_init()");
128 
129 	mutex_init(&sol_cma_glob_mutex, NULL, MUTEX_DRIVER, NULL);
130 	mutex_init(&sol_cma_dev_mutex, NULL, MUTEX_DRIVER, NULL);
131 	avl_create(&sol_cma_glbl_listen_tree,
132 	    sol_cma_svc_cmp, sizeof (sol_cma_glbl_listen_t),
133 	    offsetof(sol_cma_glbl_listen_t, cma_listen_node));
134 
135 	sol_cma_ib_client = kmem_zalloc(sizeof (ib_client_t), KM_NOSLEEP);
136 	if (!sol_cma_ib_client) {
137 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
138 		    "_init() - mem alloc failed");
139 		avl_destroy(&sol_cma_glbl_listen_tree);
140 		mutex_destroy(&sol_cma_dev_mutex);
141 		mutex_destroy(&sol_cma_glob_mutex);
142 		sol_ofs_dprintf_fini();
143 		return (ENOMEM);
144 	}
145 
146 	sol_cma_ib_client->name = "sol_ofs";
147 	sol_cma_ib_client->add = sol_cma_add_dev;
148 	sol_cma_ib_client->remove = sol_cma_rem_dev;
149 	sol_cma_ib_client->dip = NULL;
150 
151 	if ((err = ib_register_client(sol_cma_ib_client)) != 0) {
152 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
153 		    "_init() ib_register_client() failed with err %d",
154 		    err);
155 		kmem_free(sol_cma_ib_client, sizeof (ib_client_t));
156 		avl_destroy(&sol_cma_glbl_listen_tree);
157 		mutex_destroy(&sol_cma_dev_mutex);
158 		mutex_destroy(&sol_cma_glob_mutex);
159 		sol_ofs_dprintf_fini();
160 		return (err);
161 	}
162 
163 	if ((err = mod_install(&sol_ofs_modlinkage)) != 0) {
164 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
165 		    "_init() - mod_install() failed");
166 		ib_unregister_client(sol_cma_ib_client);
167 		kmem_free(sol_cma_ib_client, sizeof (ib_client_t));
168 		avl_destroy(&sol_cma_glbl_listen_tree);
169 		mutex_destroy(&sol_cma_dev_mutex);
170 		mutex_destroy(&sol_cma_glob_mutex);
171 		sol_ofs_dprintf_fini();
172 		return (err);
173 	}
174 
175 	SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_init() - ret");
176 	return (err);
177 }
178 
179 int
180 _fini(void)
181 {
182 	int		err;
183 
184 	SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_fini()");
185 
186 	if (avl_numnodes(&sol_cma_glbl_listen_tree)) {
187 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "_fini - "
188 		    "listen CMIDs still active");
189 		return (EBUSY);
190 	}
191 	if ((err = mod_remove(&sol_ofs_modlinkage)) != 0) {
192 		SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str,
193 		    "_fini: mod_remove failed");
194 		return (err);
195 	}
196 
197 	ib_unregister_client(sol_cma_ib_client);
198 	kmem_free(sol_cma_ib_client, sizeof (ib_client_t));
199 	avl_destroy(&sol_cma_glbl_listen_tree);
200 	mutex_destroy(&sol_cma_dev_mutex);
201 	mutex_destroy(&sol_cma_glob_mutex);
202 	SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_fini() - ret");
203 	sol_ofs_dprintf_fini();
204 	return (err);
205 }
206 
207 int
208 _info(struct modinfo *modinfop)
209 {
210 	return (mod_info(&sol_ofs_modlinkage, modinfop));
211 }
212 
213 typedef struct cma_device {
214 	kmutex_t		cma_mutex;
215 	llist_head_t		cma_list;
216 	genlist_t		cma_epchan_list;
217 	struct ib_device	*cma_device;
218 	uint_t			cma_ref_count;
219 	enum {
220 		SOL_CMA_DEV_ADDED,
221 		SOL_CMA_DEV_REM_IN_PROGRESS
222 	} cma_dev_state;
223 } cma_device_t;
224 
225 static void
226 sol_cma_add_dev(struct ib_device *dev)
227 {
228 	cma_device_t	*new_device;
229 
230 	new_device = kmem_zalloc(sizeof (cma_device_t), KM_NOSLEEP);
231 	if (!new_device) {
232 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "sol_cma_add_dev() "
233 		    "alloc failed!!");
234 		return;
235 	}
236 	mutex_init(&new_device->cma_mutex, NULL, MUTEX_DRIVER, NULL);
237 	llist_head_init(&new_device->cma_list, new_device);
238 	init_genlist(&new_device->cma_epchan_list);
239 	new_device->cma_device = dev;
240 
241 	ib_set_client_data(dev, sol_cma_ib_client, new_device);
242 
243 	mutex_enter(&sol_cma_dev_mutex);
244 	llist_add_tail(&new_device->cma_list, &sol_cma_dev_list);
245 	mutex_exit(&sol_cma_dev_mutex);
246 }
247 
248 static void
249 sol_cma_rem_dev(struct ib_device *dev)
250 {
251 	cma_device_t	*rem_device;
252 	genlist_entry_t	*entry;
253 
254 	SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "sol_rem_dev(%p)", dev);
255 
256 	rem_device = (cma_device_t *)ib_get_client_data(dev, sol_cma_ib_client);
257 	if (!rem_device) {
258 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "sol_cma_rem_dev() "
259 		    "NULL cma_dev!!");
260 		return;
261 	}
262 
263 	mutex_enter(&rem_device->cma_mutex);
264 	rem_device->cma_dev_state = SOL_CMA_DEV_REM_IN_PROGRESS;
265 	if (rem_device->cma_ref_count) {
266 		mutex_exit(&rem_device->cma_mutex);
267 		SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str, "sol_cma_rem_dev() "
268 		    "BUSY cma_dev!!");
269 		return;
270 	}
271 	entry = remove_genlist_head(&rem_device->cma_epchan_list);
272 	while (entry) {
273 		sol_cma_chan_t	*ep_chanp;
274 
275 		ep_chanp = (sol_cma_chan_t *)entry->data;
276 		if (ibcma_fini_ep_chan(ep_chanp) == 0) {
277 			genlist_entry_t	*entry1;
278 			sol_cma_chan_t	*root_chanp;
279 
280 			ASSERT(ep_chanp->chan_listenp);
281 			entry1 = ep_chanp->chan_listenp->listen_ep_root_entry;
282 			root_chanp = (sol_cma_chan_t *)ep_chanp->listen_root;
283 			root_chanp->chan_listenp->listen_eps--;
284 			delete_genlist(&root_chanp->chan_listenp->listen_list,
285 			    entry1);
286 
287 			kmem_free(ep_chanp, sizeof (sol_cma_chan_t));
288 			kmem_free(entry, sizeof (genlist_entry_t));
289 		}
290 
291 		entry = remove_genlist_head(&rem_device->cma_epchan_list);
292 	}
293 	mutex_exit(&rem_device->cma_mutex);
294 
295 	mutex_enter(&sol_cma_dev_mutex);
296 	llist_del(&rem_device->cma_list);
297 	mutex_exit(&sol_cma_dev_mutex);
298 
299 	kmem_free(rem_device, sizeof (cma_device_t));
300 }
301 
302 struct ib_device *
303 sol_cma_acquire_device(ib_guid_t hca_guid)
304 {
305 	llist_head_t	*entry;
306 	cma_device_t	*cma_devp;
307 
308 	mutex_enter(&sol_cma_dev_mutex);
309 	list_for_each(entry, &sol_cma_dev_list) {
310 		cma_devp = (cma_device_t *)entry->ptr;
311 
312 		if (cma_devp->cma_device->node_guid != hca_guid)
313 			continue;
314 
315 		mutex_enter(&cma_devp->cma_mutex);
316 		if (cma_devp->cma_dev_state == SOL_CMA_DEV_REM_IN_PROGRESS) {
317 			SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str,
318 			    "sol_cma_acquire_dev() - Device getting removed!!");
319 			mutex_exit(&cma_devp->cma_mutex);
320 			mutex_exit(&sol_cma_dev_mutex);
321 			return (NULL);
322 		}
323 		cma_devp->cma_ref_count++;
324 		mutex_exit(&cma_devp->cma_mutex);
325 		mutex_exit(&sol_cma_dev_mutex);
326 		return (cma_devp->cma_device);
327 
328 	}
329 	mutex_exit(&sol_cma_dev_mutex);
330 	return (NULL);
331 }
332 
333 static void
334 sol_cma_release_device(struct rdma_cm_id *id)
335 {
336 	ib_device_t	*device = id->device;
337 	llist_head_t	*entry;
338 	cma_device_t	*cma_devp;
339 
340 	mutex_enter(&sol_cma_dev_mutex);
341 	list_for_each(entry, &sol_cma_dev_list) {
342 		cma_devp = (cma_device_t *)entry->ptr;
343 
344 		if (cma_devp->cma_device != device)
345 			continue;
346 
347 		mutex_enter(&cma_devp->cma_mutex);
348 		cma_devp->cma_ref_count--;
349 		if (cma_devp->cma_dev_state == SOL_CMA_DEV_REM_IN_PROGRESS &&
350 		    cma_devp->cma_ref_count == 0) {
351 			SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str,
352 			    "sol_cma_release_dev() - Device free removed!!");
353 			mutex_exit(&cma_devp->cma_mutex);
354 			llist_del(&cma_devp->cma_list);
355 			kmem_free(cma_devp, sizeof (cma_device_t));
356 			mutex_exit(&sol_cma_dev_mutex);
357 			return;
358 		}
359 		mutex_exit(&cma_devp->cma_mutex);
360 	}
361 	mutex_exit(&sol_cma_dev_mutex);
362 }
363 
364 void
365 sol_cma_add_hca_list(sol_cma_chan_t *ep_chanp, ib_guid_t hca_guid)
366 {
367 	llist_head_t	*entry;
368 	cma_device_t	*cma_devp;
369 
370 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "add_hca_list(%p, %llx)",
371 	    ep_chanp, hca_guid);
372 	mutex_enter(&sol_cma_dev_mutex);
373 	list_for_each(entry, &sol_cma_dev_list) {
374 		cma_devp = (cma_device_t *)entry->ptr;
375 
376 		if ((cma_devp->cma_device)->node_guid != hca_guid)
377 			continue;
378 
379 		mutex_enter(&cma_devp->cma_mutex);
380 		ep_chanp->chan_listenp->listen_ep_dev_entry =
381 		    add_genlist(&cma_devp->cma_epchan_list,
382 		    (uintptr_t)ep_chanp, NULL);
383 		ep_chanp->chan_listenp->listen_ep_device = cma_devp->cma_device;
384 		mutex_exit(&cma_devp->cma_mutex);
385 		mutex_exit(&sol_cma_dev_mutex);
386 		return;
387 	}
388 	mutex_exit(&sol_cma_dev_mutex);
389 	SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "add_hca_list(%p, %llx): "
390 	    "No matching HCA in list!!", ep_chanp, hca_guid);
391 }
392 
393 /*
394  * rdma_cm.h API functions.
395  */
396 struct rdma_cm_id *
397 rdma_create_id(rdma_cm_event_handler evt_hdlr, void *context,
398     enum rdma_port_space ps)
399 {
400 	struct rdma_cm_id 	*rdma_idp;
401 
402 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_create_id(%p, %p, %x)",
403 	    evt_hdlr, context, ps);
404 
405 	if (ps != RDMA_PS_TCP && ps != RDMA_PS_UDP && ps != RDMA_PS_IPOIB) {
406 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
407 		    "rdma_create_id: unsupported protocol %x", ps);
408 		return (NULL);
409 	}
410 
411 	rdma_idp = cma_alloc_chan(evt_hdlr, context, ps);
412 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
413 	    "rdma_create_id : ret %p", rdma_idp);
414 
415 	return (rdma_idp);
416 }
417 
418 void
419 rdma_map_id2clnthdl(struct rdma_cm_id *rdma_idp, void *ib_client_hdl,
420     void *iw_client_hdl)
421 {
422 	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)rdma_idp;
423 
424 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
425 	    "rdma_map_id2clnthdl(%p, %p, %p)",
426 	    rdma_idp, ib_client_hdl, iw_client_hdl);
427 	ASSERT(ib_client_hdl != NULL || iw_client_hdl != NULL);
428 	chanp->chan_ib_client_hdl = ib_client_hdl;
429 	chanp->chan_iw_client_hdl = iw_client_hdl;
430 }
431 
432 void
433 rdma_map_id2qphdl(struct rdma_cm_id *rdma_idp, void *qp_hdl)
434 {
435 	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)rdma_idp;
436 
437 	ASSERT(rdma_idp);
438 	ASSERT(qp_hdl);
439 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_mapid2qphdl(%p, %p)",
440 	    rdma_idp, qp_hdl);
441 	chanp->chan_qp_hdl = qp_hdl;
442 }
443 
444 
445 void
446 rdma_destroy_id(struct rdma_cm_id *rdma_idp)
447 {
448 	sol_cma_chan_t		*chanp, *root_chanp;
449 	cma_chan_state_t	state;
450 	int			rc, is_root_cmid, do_wait, is_passive;
451 
452 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id(%p)", rdma_idp);
453 
454 	if (!rdma_idp)
455 		return;
456 
457 	is_root_cmid = do_wait = is_passive = 0;
458 
459 	chanp = (sol_cma_chan_t *)rdma_idp;
460 	root_chanp = (sol_cma_chan_t *)chanp->listen_root;
461 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id(%p), %p",
462 	    rdma_idp, root_chanp);
463 
464 	mutex_enter(&chanp->chan_mutex);
465 	chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_CMID_DESTROYED;
466 
467 	/*
468 	 * Wait in destroy of CMID when rdma_resolve_addr() / rdma_listen()
469 	 * rdma_resolve_route() API is in progress.
470 	 */
471 	while (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_API_PROGRESS)
472 		cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex);
473 
474 	/* Wait if Event is been notified to consumer */
475 	while (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_EVENT_PROGRESS)
476 		cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex);
477 
478 	if (rdma_idp->device)
479 		sol_cma_release_device(rdma_idp);
480 
481 	if (chanp->chan_listenp && chanp->chan_listenp->listen_is_root)
482 		is_root_cmid = 1;
483 	if (root_chanp == NULL && is_root_cmid == 0)
484 		is_passive = 1;
485 
486 	/*
487 	 * Skip Active side handling for passive CMIDs and listen CMID
488 	 * for which REQ CMIDs have not been created.
489 	 */
490 	if (is_passive || (is_root_cmid && chanp->chan_req_state !=
491 	    REQ_CMID_CREATED)) {
492 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
493 		    "Skipping passive %p, %x, %x", chanp->chan_listenp,
494 		    is_root_cmid, chanp->chan_req_state);
495 		goto skip_passive_handling;
496 	}
497 
498 	/*
499 	 * destroy_id() called for listening CMID and there are REQ
500 	 * CMIDs not yet notified. Reject such CMIDs and decrement
501 	 * the count.
502 	 */
503 	if (is_root_cmid && chanp->chan_req_cnt) {
504 		sol_cma_chan_t	*req_cmid_chan, *next_chan;
505 
506 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
507 		    "not notified handling");
508 		for (req_cmid_chan = (sol_cma_chan_t *)avl_first(
509 		    &chanp->chan_req_avl_tree); req_cmid_chan &&
510 		    chanp->chan_req_cnt; req_cmid_chan = next_chan) {
511 			next_chan = AVL_NEXT(
512 			    &chanp->chan_req_avl_tree, req_cmid_chan);
513 			if (req_cmid_chan->chan_req_state ==
514 			    REQ_CMID_CREATED) {
515 				avl_remove(&chanp->chan_req_avl_tree,
516 				    req_cmid_chan);
517 				chanp->chan_req_cnt--;
518 				chanp->chan_req_total_cnt--;
519 				mutex_exit(&chanp->chan_mutex);
520 				mutex_enter(&req_cmid_chan->chan_mutex);
521 				req_cmid_chan->chan_req_state =
522 				    REQ_CMID_NONE;
523 				mutex_exit(&req_cmid_chan->chan_mutex);
524 				(void) rdma_disconnect(
525 				    (struct rdma_cm_id *)req_cmid_chan);
526 				mutex_enter(&chanp->chan_mutex);
527 				if (rdma_idp->ps == RDMA_PS_TCP) {
528 					mutex_enter(
529 					    &req_cmid_chan->chan_mutex);
530 					req_cmid_chan->listen_root =
531 					    rdma_idp;
532 					cma_set_chan_state(req_cmid_chan,
533 					    SOL_CMA_CHAN_DESTROY_PENDING);
534 					mutex_exit(
535 					    &req_cmid_chan->chan_mutex);
536 				} else {
537 					mutex_destroy(
538 					    &req_cmid_chan->chan_mutex);
539 					cv_destroy(
540 					    &req_cmid_chan->chan_destroy_cv);
541 					kmem_free(req_cmid_chan,
542 					    sizeof (sol_cma_chan_t));
543 				}
544 			}
545 		}
546 	}
547 
548 	/*
549 	 * destroy_id() called for :
550 	 * 	listening CMID and all REQ CMIDs destroy_id() called
551 	 *	REQ CMID and 1 more REQ CMID not yet destroyed.
552 	 * wait till the CMID is completly destroyed.
553 	 */
554 	if (is_root_cmid && chanp->chan_req_total_cnt == 0) {
555 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
556 		    "root idp waiting");
557 		cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_WAIT);
558 		cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex);
559 	}
560 
561 	if (root_chanp)
562 		mutex_enter(&root_chanp->chan_mutex);
563 #ifdef	DEBUG
564 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
565 	    "root_idp %p, cnt %x, state %x", root_chanp,
566 	    root_chanp ? root_chanp->chan_req_total_cnt : 0,
567 	    root_chanp ? cma_get_chan_state(root_chanp) : 0);
568 #endif
569 
570 	if (root_chanp && root_chanp->chan_req_total_cnt == 1 &&
571 	    cma_get_chan_state(root_chanp) == SOL_CMA_CHAN_DESTROY_PENDING)
572 		do_wait = 1;
573 	if (root_chanp)
574 		mutex_exit(&root_chanp->chan_mutex);
575 
576 skip_passive_handling :
577 	state = cma_get_chan_state(chanp);
578 	if (is_root_cmid == 0 && state != SOL_CMA_CHAN_DISCONNECT &&
579 	    SOL_CMA_DISCONNECT_OK(chanp)) {
580 		/*
581 		 * A connected CM ID has not been disconnected.
582 		 * Call rdma_disconnect() to disconnect it.
583 		 */
584 		mutex_exit(&chanp->chan_mutex);
585 		rc = rdma_disconnect(rdma_idp);
586 		if (rc) {
587 			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
588 			    "rdma_destroy_id(%p)- disconnect failed!!",
589 			    rdma_idp);
590 			return;
591 		}
592 		mutex_enter(&chanp->chan_mutex);
593 		if (root_chanp && chanp->listen_root == NULL)
594 			chanp->listen_root = (struct rdma_cm_id *)root_chanp;
595 		mutex_exit(&chanp->chan_mutex);
596 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
597 		    "rdma_destroy_id(chanp %p, connect %x, ps %x)",
598 		    chanp, chanp->chan_connect_flag, rdma_idp->ps);
599 		if ((SOL_CMAID_IS_CONNECTED(chanp) &&
600 		    rdma_idp->ps == RDMA_PS_TCP) ||
601 		    (IS_UDP_CMID(rdma_idp) &&
602 		    chanp->chan_connect_flag == SOL_CMA_CONNECT_INITIATED)) {
603 			if (do_wait) {
604 				mutex_enter(&chanp->chan_mutex);
605 				cma_set_chan_state(chanp,
606 				    SOL_CMA_CHAN_DESTROY_WAIT);
607 				cv_wait(&chanp->chan_destroy_cv,
608 				    &chanp->chan_mutex);
609 				mutex_exit(&chanp->chan_mutex);
610 				cma_destroy_id(rdma_idp);
611 			} else {
612 				mutex_enter(&chanp->chan_mutex);
613 				cma_set_chan_state(chanp,
614 				    SOL_CMA_CHAN_DESTROY_PENDING);
615 				mutex_exit(&chanp->chan_mutex);
616 			}
617 		} else {
618 			/*
619 			 * Disconnected a CMID for which CONNECT has been
620 			 * Initiated but not complete.
621 			 * No more callbacks are expected for this CMID.
622 			 * Free this CMID.
623 			 */
624 			cma_destroy_id(rdma_idp);
625 		}
626 	} else if (is_root_cmid == 0 && state ==
627 	    SOL_CMA_CHAN_DISCONNECT && SOL_CMAID_IS_CONNECTED(chanp)) {
628 		/*
629 		 * CM ID was connected and disconnect is process.
630 		 * Free of this CM ID is done for the DISCONNECT
631 		 * notification for this CMID.
632 		 */
633 		cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_PENDING);
634 		mutex_exit(&chanp->chan_mutex);
635 	} else if (state != SOL_CMA_CHAN_DESTROY_PENDING) {
636 		/* CM ID, not connected, just free it. */
637 		mutex_exit(&chanp->chan_mutex);
638 		cma_destroy_id(rdma_idp);
639 	} else
640 		mutex_exit(&chanp->chan_mutex);
641 
642 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: ret");
643 }
644 
645 /*
646  * State transitions for Address resolution :
647  *	Active Side (Client) :
648  *	1. CREATE_ID-->BIND_ADDR-->RESOLVE_ADDR-->RESOLVE_ROUTE
649  *
650  *	Passive Side (Server) :
651  *	2. CREATE_ID-->RESOLVE_ADDR-->RESOLVE_ROUTE
652  *	IF_ADDR_ANY can be passed as local address in RESOLVE_ADDR
653  */
654 int
655 rdma_bind_addr(struct rdma_cm_id *idp, struct sockaddr *addr)
656 {
657 	sol_cma_chan_t		*chanp;
658 	struct rdma_addr	*addrp;
659 	int			ret;
660 
661 	ASSERT(idp);
662 	ASSERT(addr);
663 	chanp = (sol_cma_chan_t *)idp;
664 	addrp = &(idp->route.addr);
665 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_bind_addr(%p, %p)",
666 	    idp, addr);
667 
668 	mutex_enter(&chanp->chan_mutex);
669 	ret = cma_cas_chan_state(chanp, SOL_CMA_CHAN_IDLE, SOL_CMA_CHAN_BOUND);
670 	if (ret) {
671 		mutex_exit(&chanp->chan_mutex);
672 		return (ret);
673 	}
674 	/* Copy the local address to rdma_id structure */
675 	bcopy((void *)addr, (void *)&(addrp->src_addr),
676 	    sizeof (struct sockaddr));
677 	mutex_exit(&chanp->chan_mutex);
678 
679 	/*
680 	 * First call rdma_ib_bind_addr() to bind this address.
681 	 * Next call rdma_iw_bind_addr() to bind this address.
682 	 * For IF_ADDR_ANY, IB address is given priority over
683 	 * iWARP.
684 	 */
685 	if (chanp->chan_ib_client_hdl == NULL) {
686 		ofs_client_t	*ofs_clnt;
687 
688 		ofs_clnt = (ofs_client_t *)sol_cma_ib_client->clnt_hdl;
689 		chanp->chan_ib_client_hdl = ofs_clnt->ibt_hdl;
690 	}
691 	if (chanp->chan_ib_client_hdl && rdma_ib_bind_addr(idp, addr) == 0) {
692 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
693 		    "rdma_bind_addr: ret IB @");
694 		return (0);
695 #ifdef	IWARP_SUPPORT
696 	} else if (chanp->chan_iw_client_hdl && rdma_iw_bind_addr(idp, addr)
697 	    == 0) {
698 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
699 		    "rdma_bind_addr: ret iWARP @");
700 		return (0);
701 #endif	/* IWARP_SUPPORT */
702 	}
703 
704 	mutex_enter(&chanp->chan_mutex);
705 	cma_set_chan_state(chanp, SOL_CMA_CHAN_IDLE);
706 	mutex_exit(&chanp->chan_mutex);
707 	SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, "rdma_bind_addr: ret failure!");
708 	return (EINVAL);
709 }
710 
711 int
712 rdma_resolve_addr(struct rdma_cm_id *idp, struct sockaddr *src_addr,
713     struct sockaddr *dst_addr, int timeout_ms)
714 {
715 	sol_cma_chan_t		*chanp;
716 	struct rdma_addr	*addrp;
717 	cma_chan_state_t	state;
718 
719 	ASSERT(idp);
720 	chanp = (sol_cma_chan_t *)idp;
721 	addrp = &(idp->route.addr);
722 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_resolve_addr(%p, %p, "
723 	    "%p, %x)", idp, src_addr, dst_addr, timeout_ms);
724 
725 	mutex_enter(&chanp->chan_mutex);
726 	state = cma_get_chan_state(chanp);
727 	if (state != SOL_CMA_CHAN_IDLE && state != SOL_CMA_CHAN_BOUND) {
728 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
729 		    "rdma_resolve_addr : invalid chan state %x", state);
730 		mutex_exit(&chanp->chan_mutex);
731 		return (EINVAL);
732 	}
733 	if (chanp->chan_cmid_destroy_state &
734 	    SOL_CMA_CALLER_CMID_DESTROYED) {
735 		SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
736 		    "rdma_resolve_addr : CMID %p, destroy called", chanp);
737 		mutex_exit(&chanp->chan_mutex);
738 		return (EINVAL);
739 	}
740 	chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS;
741 
742 	if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) {
743 		bcopy((void *)src_addr, (void *)&(addrp->src_addr),
744 		    sizeof (struct sockaddr));
745 	}
746 	bcopy((void *)dst_addr, (void *)&(addrp->dst_addr),
747 	    sizeof (struct sockaddr));
748 	mutex_exit(&chanp->chan_mutex);
749 
750 	/*
751 	 * First resolve this as an @ corresponding to IB fabric
752 	 * if this fails, resolve this as an @ corresponding to iWARP
753 	 */
754 	if (chanp->chan_ib_client_hdl == NULL) {
755 		ofs_client_t	*ofs_clnt;
756 
757 		ofs_clnt = (ofs_client_t *)sol_cma_ib_client->clnt_hdl;
758 		chanp->chan_ib_client_hdl = ofs_clnt->ibt_hdl;
759 	}
760 	if (chanp->chan_ib_client_hdl && rdma_ib_resolve_addr(idp, src_addr,
761 	    dst_addr, timeout_ms) == 0) {
762 		SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str,
763 		    "rdma_resolve_addr: ret IB @");
764 #ifdef IWARP_SUPPORT
765 	} else if (chanp->chan_iw_client_hdl && rdma_iw_resolve_addr(idp,
766 	    src_addr, dst_addr, timeout_ms) == 0) {
767 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
768 		    "rdma_resolve_addr: ret iWARP @");
769 #endif	/* IWARP_SUPPORT */
770 	} else {
771 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
772 		    "rdma_resolve_addr: Invalid @");
773 		return (EINVAL);
774 	}
775 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_resolve_addr: ret 0");
776 	return (0);
777 }
778 
779 static void cma_generate_event_sync(struct rdma_cm_id *,
780     enum rdma_cm_event_type, int, struct rdma_conn_param *,
781     struct rdma_ud_param *);
782 
783 void
784 cma_resolve_addr_callback(sol_cma_chan_t *chanp, int rc)
785 {
786 	enum rdma_cm_event_type	event;
787 
788 	mutex_enter(&chanp->chan_mutex);
789 	if (chanp->chan_cmid_destroy_state &
790 	    SOL_CMA_CALLER_CMID_DESTROYED) {
791 		SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
792 		    "cma_resolve_addr : CMID %p, destroy called", chanp);
793 		chanp->chan_cmid_destroy_state &=
794 		    ~SOL_CMA_CALLER_API_PROGRESS;
795 		cv_broadcast(&chanp->chan_destroy_cv);
796 		mutex_exit(&chanp->chan_mutex);
797 		return;
798 	}
799 	if (rc == 0) {
800 		cma_set_chan_state(chanp, SOL_CMA_CHAN_ADDR_RESLVD);
801 		event = RDMA_CM_EVENT_ADDR_RESOLVED;
802 	} else
803 		event = RDMA_CM_EVENT_ADDR_ERROR;
804 
805 	/*
806 	 * Generate RDMA_CM_EVENT_ADDR_RESOLVED event
807 	 * This will result in RDMA_USER_CM_CMD_RESOLVE_ROUTE in
808 	 * userland.
809 	 */
810 	chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS;
811 	mutex_exit(&chanp->chan_mutex);
812 	cma_generate_event_sync((struct rdma_cm_id *)chanp, event, 0,
813 	    NULL, NULL);
814 
815 	mutex_enter(&chanp->chan_mutex);
816 	chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS;
817 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
818 		cv_broadcast(&chanp->chan_destroy_cv);
819 	mutex_exit(&chanp->chan_mutex);
820 }
821 
822 int
823 rdma_resolve_route(struct rdma_cm_id *idp, int timeout_ms)
824 {
825 	sol_cma_chan_t		*chanp;
826 
827 	ASSERT(idp);
828 	chanp = (sol_cma_chan_t *)idp;
829 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_route(%p, %x)", idp,
830 	    timeout_ms);
831 
832 	mutex_enter(&chanp->chan_mutex);
833 	if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ADDR_RESLVD,
834 	    SOL_CMA_CHAN_ROUTE_RESLVD) != 0) {
835 		mutex_exit(&chanp->chan_mutex);
836 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
837 		    "resolve_route: Invalid state");
838 		return (EINVAL);
839 	}
840 	if (chanp->chan_cmid_destroy_state &
841 	    SOL_CMA_CALLER_CMID_DESTROYED) {
842 		SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
843 		    "rdma_resolve_route : CMID %p, destroy called", chanp);
844 		mutex_exit(&chanp->chan_mutex);
845 		return (EINVAL);
846 	}
847 	chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS;
848 	mutex_exit(&chanp->chan_mutex);
849 
850 	/*
851 	 * Generate RDMA_CM_EVENT_ROUTE_RESOLVED event
852 	 * This will result in RDMA_USER_CM_CMD_RESOLVE_ROUTE in
853 	 * userland
854 	 */
855 	cma_generate_event(idp, RDMA_CM_EVENT_ROUTE_RESOLVED, 0,
856 	    NULL, NULL);
857 
858 	mutex_enter(&chanp->chan_mutex);
859 	chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS;
860 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
861 		cv_broadcast(&chanp->chan_destroy_cv);
862 	mutex_exit(&chanp->chan_mutex);
863 
864 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_route: ret 0");
865 	return (0);
866 }
867 
868 /*
869  * Connect or Listen request should be send after Route is resolved
870  *
871  *	Active Side (Client) :
872  *	1. (State ROUTE_RESOLVED)-->CONNECT-->ACCEPT/REJECT-->DISCONNECT
873  *	       -->DESTROY_ID-->close(9E)
874  *	2. Same as (1), DESTROY_ID without DISCONNECT
875  *	3. Same as (1), close(9e) without DESTROY_ID.
876  *
877  *	Passive Side (Server) :
878  *	4. (State ROUTE_RESOLVED)-->LISTEN->DISCONNECT
879  *		-->DESTROY_ID-->close(9E)
880  *	5. Same as (4), DESTROY_ID without DISCONNECT
881  *	6. Same as (4), close(9e) without DESTROY_ID.
882  */
883 int
884 rdma_connect(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param)
885 {
886 	sol_cma_chan_t		*chanp;
887 	int			ret = EINVAL;
888 
889 	ASSERT(idp);
890 	chanp = (sol_cma_chan_t *)idp;
891 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_connect(%p, %p)", idp,
892 	    conn_param);
893 
894 	mutex_enter(&chanp->chan_mutex);
895 	if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) {
896 		mutex_exit(&chanp->chan_mutex);
897 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
898 		    "rdma_connect, Invalid Xport");
899 		return (EINVAL);
900 	}
901 	if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ROUTE_RESLVD,
902 	    SOL_CMA_CHAN_CONNECT)) {
903 		mutex_exit(&chanp->chan_mutex);
904 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
905 		    "rdma_connect, Invalid state");
906 		return (EINVAL);
907 	}
908 
909 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
910 		ret = rdma_ib_connect(idp, conn_param);
911 #ifdef	IWARP_SUPPORT
912 	} else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) {
913 		ret = rdma_iw_connect(idp, conn_param);
914 #endif	/* IWARP_SUPPORT */
915 	}
916 	mutex_exit(&chanp->chan_mutex);
917 
918 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_connect: ret %x", ret);
919 	return (ret);
920 }
921 
922 static int cma_init_listen_root(sol_cma_chan_t *);
923 static void cma_fini_listen_root(sol_cma_chan_t *);
924 
925 int
926 rdma_listen(struct rdma_cm_id *idp, int bklog)
927 {
928 	sol_cma_chan_t		*chanp;
929 	int			ret;
930 	genlist_entry_t		*entry;
931 	cma_chan_state_t	state;
932 
933 	ASSERT(idp);
934 	chanp = (sol_cma_chan_t *)idp;
935 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_listen(%p, %x)",
936 	    idp, bklog);
937 
938 	mutex_enter(&chanp->chan_mutex);
939 	state = cma_get_chan_state(chanp);
940 	if (state == SOL_CMA_CHAN_IDLE) {
941 		mutex_exit(&chanp->chan_mutex);
942 		return (EINVAL);
943 	}
944 	cma_set_chan_state(chanp, SOL_CMA_CHAN_LISTEN);
945 
946 	if (chanp->chan_cmid_destroy_state &
947 	    SOL_CMA_CALLER_CMID_DESTROYED) {
948 		SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
949 		    "rdma_listen : CMID %p, destroy called", chanp);
950 		mutex_exit(&chanp->chan_mutex);
951 		return (EINVAL);
952 	}
953 	chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS;
954 
955 	ASSERT(chanp->chan_listenp == NULL);
956 
957 	chanp->chan_listenp = kmem_zalloc(sizeof (sol_cma_listen_info_t),
958 	    KM_SLEEP);
959 	init_genlist(&(CHAN_LISTEN_LIST(chanp)));
960 	(chanp->chan_listenp)->listen_is_root = 1;
961 	ret = cma_init_listen_root(chanp);
962 	if (ret) {
963 		chanp->chan_listenp = NULL;
964 		mutex_exit(&chanp->chan_mutex);
965 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen: "
966 		    "cma_init_listen_root: failed");
967 		kmem_free(chanp->chan_listenp,
968 		    sizeof (sol_cma_listen_info_t));
969 		return (EINVAL);
970 	}
971 
972 	if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) {
973 		ibcma_append_listen_list(idp);
974 #ifdef IWARP_SUPPORT
975 		iwcma_append_listen_list(idp);
976 #endif
977 	} else if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
978 		ibcma_append_listen_list(idp);
979 #ifdef	IWARP_SUPPORT
980 	} else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) {
981 		iwcma_append_listen_list(idp);
982 #endif	/* IWARP_SUPPORT */
983 	}
984 
985 	if (genlist_empty(&(CHAN_LISTEN_LIST(chanp)))) {
986 		cma_fini_listen_root(chanp);
987 		kmem_free((void *)chanp->chan_listenp,
988 		    sizeof (sol_cma_listen_info_t));
989 		chanp->chan_listenp = NULL;
990 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen: "
991 		    "No listeners");
992 		mutex_exit(&chanp->chan_mutex);
993 		return (0);
994 	}
995 
996 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) {
997 		chanp->chan_cmid_destroy_state &=
998 		    ~SOL_CMA_CALLER_API_PROGRESS;
999 		cv_broadcast(&chanp->chan_destroy_cv);
1000 	}
1001 
1002 	genlist_for_each(entry, &(CHAN_LISTEN_LIST(chanp))) {
1003 		struct rdma_cm_id	*ep_idp;
1004 		sol_cma_chan_t		*ep_chanp;
1005 
1006 		ep_idp = (struct rdma_cm_id *)entry->data;
1007 		ep_chanp = (sol_cma_chan_t *)ep_idp;
1008 		if (ep_chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1009 			ret = rdma_ib_listen(ep_idp, bklog);
1010 #ifdef IWARP_SUPPORT
1011 		if (ep_chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1012 			ret = rdma_iw_listen(ep_idp, bklog);
1013 #endif
1014 		if (ret)
1015 			break;
1016 	}
1017 
1018 	chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS;
1019 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
1020 		cv_broadcast(&chanp->chan_destroy_cv);
1021 	mutex_exit(&chanp->chan_mutex);
1022 
1023 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_listen: ret %x", ret);
1024 	return (ret);
1025 }
1026 
1027 int
1028 rdma_accept(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param)
1029 {
1030 	struct rdma_cm_id	*root_idp;
1031 	sol_cma_chan_t		*root_chanp, *chanp;
1032 	int			ret = EINVAL;
1033 
1034 	ASSERT(idp);
1035 	chanp = (sol_cma_chan_t *)idp;
1036 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_accept(%p, %p)",
1037 	    idp, conn_param);
1038 
1039 	mutex_enter(&chanp->chan_mutex);
1040 	if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_LISTEN,
1041 	    SOL_CMA_CHAN_ACCEPT) && cma_cas_chan_state(chanp,
1042 	    SOL_CMA_CHAN_CONNECT, SOL_CMA_CHAN_ACCEPT)) {
1043 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1044 		    "rdma_accept, Invalid state");
1045 		mutex_exit(&chanp->chan_mutex);
1046 		return (EINVAL);
1047 	}
1048 	mutex_exit(&chanp->chan_mutex);
1049 
1050 	root_idp = CHAN_LISTEN_ROOT(chanp);
1051 	root_chanp = (sol_cma_chan_t *)root_idp;
1052 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: root_idp %p",
1053 	    root_idp);
1054 
1055 	/* Delete from REQ_AVL_TREE on passive side */
1056 	if (root_idp) {
1057 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: root_idp %p"
1058 		    "REQ AVL remove %p", root_chanp, idp);
1059 		mutex_enter(&root_chanp->chan_mutex);
1060 		avl_remove(&root_chanp->chan_req_avl_tree, idp);
1061 
1062 		/* For TCP, insert into ACPT_AVL_TREE */
1063 		if (idp->ps == RDMA_PS_TCP) {
1064 			void		*find_ret;
1065 			avl_index_t	where;
1066 
1067 			SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1068 			    "Add to ACPT AVL of %p IDP, idp %p, qp_hdl %p",
1069 			    root_idp, idp, chanp->chan_qp_hdl);
1070 			find_ret = avl_find(&root_chanp->chan_acpt_avl_tree,
1071 			    (void *)chanp->chan_qp_hdl, &where);
1072 			if (find_ret) {
1073 				mutex_exit(&root_chanp->chan_mutex);
1074 				SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1075 				    "DUPLICATE ENTRY in ACPT AVL : root %p, "
1076 				    "idp %p, qp_hdl %p",
1077 				    root_idp, idp, chanp->chan_qp_hdl);
1078 				return (EINVAL);
1079 			}
1080 			avl_insert(&root_chanp->chan_acpt_avl_tree,
1081 			    (void *)idp, where);
1082 		}
1083 		mutex_exit(&root_chanp->chan_mutex);
1084 
1085 		mutex_enter(&chanp->chan_mutex);
1086 		/* Update chan_req_state to ACCEPTED */
1087 		chanp->chan_req_state = REQ_CMID_ACCEPTED;
1088 		mutex_exit(&chanp->chan_mutex);
1089 	}
1090 
1091 	if (root_idp && IS_UDP_CMID(root_idp)) {
1092 		cma_chan_state_t	chan_state;
1093 
1094 		/*
1095 		 * Accepting the connect request, no more events for this
1096 		 * connection.
1097 		 */
1098 		mutex_enter(&chanp->chan_mutex);
1099 		cma_handle_nomore_events(chanp);
1100 		chan_state = cma_get_chan_state(chanp);
1101 		mutex_exit(&chanp->chan_mutex);
1102 		/* If rdma_destroy_id() was called, destroy CMID */
1103 		if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING)
1104 			cma_destroy_id((struct rdma_cm_id *)chanp);
1105 	}
1106 
1107 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1108 		ret = rdma_ib_accept(idp, conn_param);
1109 #ifdef	IWARP_SUPPORT
1110 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1111 		ret = rdma_iw_accept(idp, conn_param);
1112 #endif	/* IWARP_SUPPORT */
1113 
1114 	if (ret && root_idp && idp->ps == RDMA_PS_TCP) {
1115 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1116 		    "Delete from REQ AVL of %p IDP, idp %p",
1117 		    root_idp, idp);
1118 		mutex_enter(&root_chanp->chan_mutex);
1119 		avl_remove(&root_chanp->chan_acpt_avl_tree, idp);
1120 		mutex_exit(&root_chanp->chan_mutex);
1121 		mutex_enter(&chanp->chan_mutex);
1122 		chanp->chan_req_state = REQ_CMID_NONE;
1123 		mutex_exit(&chanp->chan_mutex);
1124 	}
1125 
1126 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_accept: ret %x", ret);
1127 	return (ret);
1128 }
1129 
1130 int
1131 rdma_notify(struct rdma_cm_id *idp, enum ib_event_type evt)
1132 {
1133 	sol_cma_chan_t		*chanp;
1134 
1135 	ASSERT(idp);
1136 	chanp = (sol_cma_chan_t *)idp;
1137 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_notify(%p, %x)", idp, evt);
1138 
1139 	mutex_enter(&chanp->chan_mutex);
1140 	if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ROUTE_RESLVD,
1141 	    SOL_CMA_CHAN_EVENT_NOTIFIED)) {
1142 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1143 		    "rdma_notify, Invalid state");
1144 		mutex_exit(&chanp->chan_mutex);
1145 		return (EINVAL);
1146 	}
1147 	mutex_exit(&chanp->chan_mutex);
1148 
1149 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_notify: ret 0");
1150 	return (0);
1151 }
1152 
1153 int
1154 rdma_reject(struct rdma_cm_id *idp, const void *priv_data,
1155     uint8_t priv_data_len)
1156 {
1157 	struct rdma_cm_id	*root_idp;
1158 	sol_cma_chan_t		*root_chanp, *chanp;
1159 	int			ret = EINVAL;
1160 
1161 	ASSERT(idp);
1162 	chanp = (sol_cma_chan_t *)idp;
1163 	root_idp = CHAN_LISTEN_ROOT(chanp);
1164 	root_chanp = (sol_cma_chan_t *)root_idp;
1165 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_reject(%p, %p)", idp,
1166 	    priv_data, priv_data_len);
1167 
1168 	mutex_enter(&chanp->chan_mutex);
1169 	if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_LISTEN,
1170 	    SOL_CMA_CHAN_REJECT)) {
1171 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1172 		    "rdma_accept, Invalid state");
1173 		mutex_exit(&chanp->chan_mutex);
1174 		return (EINVAL);
1175 	}
1176 	mutex_exit(&chanp->chan_mutex);
1177 
1178 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1179 		ret = rdma_ib_reject(idp, priv_data, priv_data_len);
1180 #ifdef	IWARP_SUPPORT
1181 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1182 		ret = rdma_iw_reject(idp, priv_data, priv_data_len);
1183 #endif	/* IWARP_SUPPORT */
1184 
1185 
1186 	if (!ret && root_idp) {
1187 		cma_chan_state_t	chan_state;
1188 
1189 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "reject: root_idp %p"
1190 		    "REQ AVL remove %p", root_chanp, idp);
1191 		/* Remove from Req AVL tree */
1192 		mutex_enter(&root_chanp->chan_mutex);
1193 		avl_remove(&root_chanp->chan_req_avl_tree, idp);
1194 		mutex_exit(&root_chanp->chan_mutex);
1195 
1196 		/* Update chan_req_state to REJECTED */
1197 		mutex_enter(&chanp->chan_mutex);
1198 		chanp->chan_req_state = REQ_CMID_REJECTED;
1199 
1200 		/*
1201 		 * Rejecting connect request, no more events for this
1202 		 * connection.
1203 		 */
1204 		cma_handle_nomore_events(chanp);
1205 		chan_state = cma_get_chan_state(chanp);
1206 		mutex_exit(&chanp->chan_mutex);
1207 		/* If rdma_destroy_id() was called, destroy CMID */
1208 		if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING)
1209 			cma_destroy_id((struct rdma_cm_id *)chanp);
1210 	}
1211 
1212 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_reject: ret %x", ret);
1213 	return (ret);
1214 }
1215 
1216 int
1217 rdma_disconnect(struct rdma_cm_id *idp)
1218 {
1219 	sol_cma_chan_t		*chanp;
1220 	int			ret = EINVAL;
1221 	cma_chan_state_t	state;
1222 
1223 	chanp = (sol_cma_chan_t *)idp;
1224 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_disconnect(%p)", idp);
1225 
1226 	if (!idp)
1227 		return (0);
1228 
1229 	mutex_enter(&chanp->chan_mutex);
1230 	if (!(SOL_CMA_DISCONNECT_OK(chanp))) {
1231 		SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
1232 		    "rdma_disconnect(%p) - Not connected!!", idp);
1233 		mutex_exit(&chanp->chan_mutex);
1234 		return (EINVAL);
1235 	}
1236 	state = cma_get_chan_state(chanp);
1237 	cma_set_chan_state(chanp, SOL_CMA_CHAN_DISCONNECT);
1238 	mutex_exit(&chanp->chan_mutex);
1239 
1240 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
1241 		ret = rdma_ib_disconnect(idp);
1242 #ifdef	IWARP_SUPPORT
1243 	} else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) {
1244 		ret = rdma_iw_disconnect(idp);
1245 #endif	/* IWARP_SUPPORT */
1246 	}
1247 
1248 	if (ret) {
1249 		mutex_enter(&chanp->chan_mutex);
1250 		cma_set_chan_state(chanp, state);
1251 		mutex_exit(&chanp->chan_mutex);
1252 		return (ret);
1253 	}
1254 
1255 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_disconnect: ret %x", ret);
1256 	return (ret);
1257 }
1258 
1259 int
1260 rdma_init_qp_attr(struct rdma_cm_id *idp, struct ib_qp_attr *qpattr,
1261     int *qp_attr_mask)
1262 {
1263 	sol_cma_chan_t		*chanp;
1264 	int			ret = EINVAL;
1265 
1266 	ASSERT(idp);
1267 	chanp = (sol_cma_chan_t *)idp;
1268 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_init_qp_attr(%p, %p, %p)",
1269 	    idp, qpattr, qp_attr_mask);
1270 
1271 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
1272 		ret = rdma_ib_init_qp_attr(idp, qpattr, qp_attr_mask);
1273 #ifdef	IWARP_SUPPORT
1274 	} else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1275 		ret = rdma_iw_init_qp_attr(idp, qpattr, qp_attr_mask);
1276 #endif	/* IWARP_SUPPORT */
1277 	} else {
1278 		ret = EINVAL;
1279 	}
1280 
1281 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1282 	    "rdma_init_qp_attr: ret %x", ret);
1283 
1284 	return (ret);
1285 }
1286 
1287 int
1288 rdma_join_multicast(struct rdma_cm_id *idp, struct sockaddr *addr,
1289     void *context)
1290 {
1291 	sol_cma_chan_t		*chanp;
1292 	int			ret = ENODEV;
1293 	cma_chan_state_t	state;
1294 
1295 	ASSERT(idp);
1296 	chanp = (sol_cma_chan_t *)idp;
1297 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1298 	    "rdma_join_multicast(%p, %p, %p)",
1299 	    idp, addr, context);
1300 
1301 	mutex_enter(&chanp->chan_mutex);
1302 	state = cma_get_chan_state(chanp);
1303 	if (state != SOL_CMA_CHAN_BOUND &&
1304 	    state != SOL_CMA_CHAN_ROUTE_RESLVD &&
1305 	    state != SOL_CMA_CHAN_ADDR_RESLVD) {
1306 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1307 		    "rdma_join_multicast, Invalid state");
1308 		mutex_exit(&chanp->chan_mutex);
1309 		return (EINVAL);
1310 	}
1311 
1312 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1313 		ret = rdma_ib_join_multicast(idp, addr, context);
1314 #ifdef	IWARP_SUPPORT
1315 	/* No support for Multicast on iWARP */
1316 	else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1317 		ret = ENOTSUP;
1318 #endif	/* IWARP_SUPPORT */
1319 	mutex_exit(&chanp->chan_mutex);
1320 
1321 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1322 	    "rdma_join_multicast: ret %x", ret);
1323 	return (ret);
1324 }
1325 
1326 void
1327 rdma_leave_multicast(struct rdma_cm_id *idp, struct sockaddr *addr)
1328 {
1329 	sol_cma_chan_t		*chanp;
1330 	cma_chan_state_t	state;
1331 
1332 	ASSERT(idp);
1333 	chanp = (sol_cma_chan_t *)idp;
1334 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_leave_multicast(%p, %p)",
1335 	    idp, addr);
1336 
1337 	mutex_enter(&chanp->chan_mutex);
1338 	state = cma_get_chan_state(chanp);
1339 	if (state != SOL_CMA_CHAN_BOUND &&
1340 	    state != SOL_CMA_CHAN_ROUTE_RESLVD &&
1341 	    state != SOL_CMA_CHAN_ADDR_RESLVD) {
1342 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1343 		    "rdma_leave_multicast, Invalid state");
1344 		mutex_exit(&chanp->chan_mutex);
1345 		return;
1346 	}
1347 
1348 	if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1349 		rdma_ib_leave_multicast(idp, addr);
1350 #ifdef	IWARP_SUPPORT
1351 	/* No support for Multicast on iWARP */
1352 	else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1353 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1354 		    "rdma_leave_multicast, iWARP");
1355 #endif	/* IWARP_SUPPORT */
1356 	mutex_exit(&chanp->chan_mutex);
1357 
1358 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_join_multicast: ret");
1359 }
1360 
1361 /*
1362  * Functions to compare to rdma_cm_id *, used by AVL tree
1363  * routines.
1364  */
1365 int
1366 sol_cma_req_cmid_cmp(const void *p1, const void *p2)
1367 {
1368 	sol_cma_chan_t		*chanp;
1369 
1370 	chanp = (sol_cma_chan_t *)p2;
1371 	if (chanp->chan_session_id > p1)
1372 		return (+1);
1373 	else if (chanp->chan_session_id < p1)
1374 		return (-1);
1375 	else
1376 		return (0);
1377 }
1378 
1379 int
1380 sol_cma_cmid_cmp(const void *p1, const void *p2)
1381 {
1382 	sol_cma_chan_t		*chanp;
1383 
1384 	chanp = (sol_cma_chan_t *)p2;
1385 	if (chanp->chan_qp_hdl > p1)
1386 		return (+1);
1387 	else if (chanp->chan_qp_hdl < p1)
1388 		return (-1);
1389 	else
1390 		return (0);
1391 }
1392 
1393 /*
1394  * Function to compare two sol_cma_glbl_listen_t *, used by
1395  * AVL tree routines.
1396  */
1397 int
1398 sol_cma_svc_cmp(const void *p1, const void *p2)
1399 {
1400 	sol_cma_glbl_listen_t	*listenp;
1401 	uint64_t		sid;
1402 
1403 	sid = *(uint64_t *)p1;
1404 	listenp = (sol_cma_glbl_listen_t *)p2;
1405 	if (listenp->cma_listen_chan_sid > sid)
1406 		return (+1);
1407 	else if (listenp->cma_listen_chan_sid < sid)
1408 		return (-1);
1409 	else
1410 		return (0);
1411 }
1412 
1413 static int
1414 cma_init_listen_root(sol_cma_chan_t *chanp)
1415 {
1416 	sol_cma_glbl_listen_t	*cma_listenp;
1417 	sol_cma_listen_info_t	*chan_listenp;
1418 	int			rc = 0;
1419 	avl_index_t		where = 0;
1420 	uint64_t		listen_sid;
1421 
1422 	ASSERT(chanp);
1423 	ASSERT(chanp->chan_listenp);
1424 	chan_listenp = chanp->chan_listenp;
1425 
1426 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1427 	    "cma_init_listen_root(%p)", chanp);
1428 
1429 	/*
1430 	 * First search for matching global listen_info for this SID.
1431 	 * If found with the same client handle, reuse the service
1432 	 * handle, if matching SID is found with different client
1433 	 * handle, return EINVAL.
1434 	 */
1435 	listen_sid = ibcma_init_root_sid(chanp);
1436 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1437 	    "cma_init_listen_root: search SID 0x%llx",
1438 	    listen_sid);
1439 
1440 	mutex_enter(&sol_cma_glob_mutex);
1441 	cma_listenp = avl_find(&sol_cma_glbl_listen_tree,
1442 	    (void *) &listen_sid, &where);
1443 	if (cma_listenp && cma_listenp->cma_listen_clnt_hdl ==
1444 	    chanp->chan_ib_client_hdl) {
1445 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1446 		    "cma_init_listen_root: matching listenp %p SID 0x%llx",
1447 		    cma_listenp, listen_sid);
1448 		chan_listenp->listen_entry = add_genlist(
1449 		    &cma_listenp->cma_listen_chan_list,
1450 		    (uintptr_t)chanp, NULL);
1451 		chan_listenp->chan_glbl_listen_info = cma_listenp;
1452 		ibcma_copy_srv_hdl(chanp, cma_listenp);
1453 		mutex_exit(&sol_cma_glob_mutex);
1454 		return (0);
1455 	} else if (cma_listenp) {
1456 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1457 		    "cma_init_listen_root: listenp %p, SID 0x%llx match, "
1458 		    "client hdl prev %p, new %p mismatch",
1459 		    cma_listenp, listen_sid,
1460 		    cma_listenp->cma_listen_clnt_hdl,
1461 		    chanp->chan_ib_client_hdl);
1462 		mutex_exit(&sol_cma_glob_mutex);
1463 		return (EINVAL);
1464 	}
1465 
1466 	cma_listenp = kmem_zalloc(sizeof (sol_cma_glbl_listen_t), KM_SLEEP);
1467 	init_genlist(&cma_listenp->cma_listen_chan_list);
1468 	chan_listenp->listen_entry = add_genlist(
1469 	    &cma_listenp->cma_listen_chan_list, (uintptr_t)chanp, NULL);
1470 	chan_listenp->chan_glbl_listen_info = cma_listenp;
1471 	cma_listenp->cma_listen_clnt_hdl = chanp->chan_ib_client_hdl;
1472 	cma_listenp->cma_listen_chan_sid = listen_sid;
1473 
1474 	rc = ibcma_init_root_chan(chanp, cma_listenp);
1475 	if (rc) {
1476 		mutex_exit(&sol_cma_glob_mutex);
1477 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1478 		    "cma_init_listen_root: ibcma_init_root_chan failed!!");
1479 		delete_genlist(&cma_listenp->cma_listen_chan_list,
1480 		    chan_listenp->listen_entry);
1481 		kmem_free(cma_listenp, sizeof (sol_cma_glbl_listen_t));
1482 		return (rc);
1483 	}
1484 	avl_insert(&sol_cma_glbl_listen_tree, cma_listenp, where);
1485 	mutex_exit(&sol_cma_glob_mutex);
1486 	return (0);
1487 }
1488 
1489 static void
1490 cma_fini_listen_root(sol_cma_chan_t *chanp)
1491 {
1492 	sol_cma_glbl_listen_t	*cma_listenp;
1493 	sol_cma_listen_info_t	*chan_listenp;
1494 
1495 	ASSERT(chanp);
1496 	ASSERT(chanp->chan_listenp);
1497 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_fini_listen_root(%p)",
1498 	    chanp);
1499 	chan_listenp = chanp->chan_listenp;
1500 	cma_listenp = chan_listenp->chan_glbl_listen_info;
1501 	ASSERT(cma_listenp);
1502 	mutex_enter(&sol_cma_glob_mutex);
1503 	delete_genlist(&cma_listenp->cma_listen_chan_list,
1504 	    chan_listenp->listen_entry);
1505 	if (genlist_empty(&cma_listenp->cma_listen_chan_list)) {
1506 		if (ibcma_fini_root_chan(chanp) == 0) {
1507 			avl_remove(&sol_cma_glbl_listen_tree,
1508 			    cma_listenp);
1509 			kmem_free(cma_listenp,
1510 			    sizeof (sol_cma_glbl_listen_t));
1511 		} else
1512 			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1513 			    "cma_fini_listen_root: "
1514 			    "ibcma_fini_root_chan failed");
1515 	}
1516 
1517 	mutex_exit(&sol_cma_glob_mutex);
1518 }
1519 
1520 typedef struct cma_event_async_arg {
1521 	struct rdma_cm_id	*idp;
1522 	enum rdma_cm_event_type	event;
1523 	int			status;
1524 	union {
1525 		struct rdma_conn_param	conn;
1526 		struct rdma_ud_param	param;
1527 	} un;
1528 	struct rdma_conn_param	*conn_param;
1529 	struct rdma_ud_param	*ud_paramp;
1530 } cma_event_async_arg_t;
1531 
1532 static void cma_generate_event_sync(struct rdma_cm_id *,
1533     enum rdma_cm_event_type, int, struct rdma_conn_param *,
1534     struct rdma_ud_param *);
1535 
1536 void
1537 cma_generate_event_thr(void *arg)
1538 {
1539 	cma_event_async_arg_t	*event_arg = (cma_event_async_arg_t *)arg;
1540 
1541 	cma_generate_event_sync(event_arg->idp, event_arg->event,
1542 	    event_arg->status, event_arg->conn_param,
1543 	    event_arg->ud_paramp);
1544 
1545 	if (event_arg->conn_param && event_arg->conn_param->private_data_len)
1546 		kmem_free((void *)event_arg->conn_param->private_data,
1547 		    event_arg->conn_param->private_data_len);
1548 	if (event_arg->ud_paramp && event_arg->ud_paramp->private_data_len)
1549 		kmem_free((void *)event_arg->ud_paramp->private_data,
1550 		    event_arg->ud_paramp->private_data_len);
1551 	kmem_free(arg, sizeof (cma_event_async_arg_t));
1552 }
1553 
1554 void
1555 cma_generate_event(struct rdma_cm_id *idp, enum rdma_cm_event_type event,
1556     int status, struct rdma_conn_param *conn_param,
1557     struct rdma_ud_param *ud_paramp)
1558 {
1559 	cma_event_async_arg_t	*event_arg;
1560 	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)idp;
1561 
1562 	/*
1563 	 * Set SOL_CMA_CALLER_EVENT_PROGRESS to indicate event
1564 	 * notification is in progress, so that races between
1565 	 * rdma_destroy_id() and event notification is taken care.
1566 	 *
1567 	 * If rdma_destroy_id() has been called for this CMID, call
1568 	 * cma_generate_event_sync() which skips notification to the
1569 	 * consumer and handles the event.
1570 	 */
1571 	mutex_enter(&chanp->chan_mutex);
1572 	chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS;
1573 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) {
1574 		mutex_exit(&chanp->chan_mutex);
1575 		cma_generate_event_sync(idp, event, status, conn_param,
1576 		    ud_paramp);
1577 		return;
1578 	}
1579 	mutex_exit(&chanp->chan_mutex);
1580 
1581 	event_arg = kmem_zalloc(sizeof (cma_event_async_arg_t), KM_SLEEP);
1582 	event_arg->idp = idp;
1583 	event_arg->event = event;
1584 	event_arg->status = status;
1585 	event_arg->conn_param = NULL;
1586 	event_arg->ud_paramp = NULL;
1587 	if (conn_param && conn_param->private_data_len) {
1588 		bcopy(conn_param, &(event_arg->un.conn),
1589 		    sizeof (struct rdma_conn_param));
1590 		event_arg->conn_param = &(event_arg->un.conn);
1591 		event_arg->conn_param->private_data = kmem_zalloc(
1592 		    conn_param->private_data_len, KM_SLEEP);
1593 		bcopy(conn_param->private_data,
1594 		    (void *)event_arg->conn_param->private_data,
1595 		    conn_param->private_data_len);
1596 	} else if (conn_param && conn_param->private_data_len == 0) {
1597 		bcopy(conn_param, &(event_arg->un.conn),
1598 		    sizeof (struct rdma_conn_param));
1599 	} else if (ud_paramp) {
1600 		bcopy(ud_paramp, &(event_arg->un.param),
1601 		    sizeof (struct rdma_ud_param));
1602 		event_arg->ud_paramp = &(event_arg->un.param);
1603 		if (ud_paramp->private_data_len) {
1604 			event_arg->ud_paramp->private_data = kmem_zalloc(
1605 			    ud_paramp->private_data_len, KM_SLEEP);
1606 			bcopy(ud_paramp->private_data,
1607 			    (void *)event_arg->ud_paramp->private_data,
1608 			    ud_paramp->private_data_len);
1609 		} else if (ud_paramp->private_data) {
1610 			event_arg->ud_paramp->private_data =
1611 			    ud_paramp->private_data;
1612 		}
1613 	}
1614 
1615 	if (taskq_dispatch(system_taskq, cma_generate_event_thr,
1616 	    (void *)event_arg, TQ_SLEEP) == 0) {
1617 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1618 		    "generate_event_async: taskq_dispatch() failed!!");
1619 		mutex_enter(&chanp->chan_mutex);
1620 		chanp->chan_cmid_destroy_state &=
1621 		    ~SOL_CMA_CALLER_EVENT_PROGRESS;
1622 		if (chanp->chan_cmid_destroy_state &
1623 		    SOL_CMA_CALLER_CMID_DESTROYED)
1624 			cv_broadcast(&chanp->chan_destroy_cv);
1625 		mutex_exit(&chanp->chan_mutex);
1626 	}
1627 }
1628 
1629 static void
1630 cma_generate_event_sync(struct rdma_cm_id *idp, enum rdma_cm_event_type event,
1631     int status, struct rdma_conn_param *conn_param,
1632     struct rdma_ud_param *ud_paramp)
1633 {
1634 	struct rdma_cm_event	cm_event;
1635 	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)idp;
1636 	struct rdma_cm_id	*root_idp = NULL;
1637 	sol_cma_chan_t		*root_chanp;
1638 	int			ret;
1639 	cma_chan_state_t	chan_state;
1640 
1641 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "generate_event_sync(%p, %x, "
1642 	    "%x, %p, %p", idp, event, status, conn_param, ud_paramp);
1643 
1644 	bzero(&cm_event, sizeof (cm_event));
1645 	cm_event.event = event;
1646 	cm_event.status = status;
1647 	if (conn_param)
1648 		bcopy((void *)conn_param, (void *)(&(cm_event.param.conn)),
1649 		    sizeof (struct rdma_conn_param));
1650 	else if (ud_paramp)
1651 		bcopy((void *)ud_paramp, (void *)(&(cm_event.param.ud)),
1652 		    sizeof (struct rdma_ud_param));
1653 
1654 	/*
1655 	 * If the consumer has destroyed the context for this CMID -
1656 	 * do not notify, skip to handling the sol_ofs specific
1657 	 * handling of the event.
1658 	 */
1659 	mutex_enter(&chanp->chan_mutex);
1660 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) {
1661 		mutex_exit(&chanp->chan_mutex);
1662 		goto ofs_consume_event;
1663 	}
1664 	mutex_exit(&chanp->chan_mutex);
1665 
1666 	root_idp = CHAN_LISTEN_ROOT(chanp);
1667 	root_chanp = (sol_cma_chan_t *)root_idp;
1668 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "gen_event: root_idp %p",
1669 	    root_idp);
1670 
1671 	if (event == RDMA_CM_EVENT_CONNECT_REQUEST) {
1672 		/*
1673 		 * Update chan_req_state for the REQ CMID. Decrement
1674 		 * count of REQ CMIDs not notifed to consumer.
1675 		 */
1676 		ASSERT(root_idp);
1677 		mutex_enter(&root_chanp->chan_mutex);
1678 		root_chanp->chan_req_cnt--;
1679 #ifdef	DEBUG
1680 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1681 		    "Dec req_cnt of %p IDP, idp %p, req_cnt %x",
1682 		    root_idp, idp, root_chanp->chan_req_cnt);
1683 #endif
1684 		mutex_exit(&root_chanp->chan_mutex);
1685 	}
1686 
1687 	/* Pass the event to the client */
1688 	ret = (idp->event_handler) (idp, &cm_event);
1689 
1690 	if (ret) {
1691 		if (event == RDMA_CM_EVENT_CONNECT_REQUEST) {
1692 			SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str,
1693 			    "cma_generate_event_async: consumer failed %d "
1694 			    "event", event);
1695 			/*
1696 			 * Disconnect if the consumer returned non zero.
1697 			 * rdma_disconnect will send a REJ to the active
1698 			 * side / client.
1699 			 */
1700 			if (rdma_disconnect(idp))
1701 				SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1702 				    "generate_event_async: rdma_disconnect "
1703 				    "failed");
1704 		} else
1705 			SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1706 			    "generate_event_async: consumer failed %d event",
1707 			    event);
1708 
1709 		mutex_enter(&chanp->chan_mutex);
1710 		chanp->chan_req_state = REQ_CMID_NONE;
1711 		chanp->chan_connect_flag = SOL_CMA_CONNECT_NONE;
1712 		chanp->chan_cmid_destroy_state &=
1713 		    ~SOL_CMA_CALLER_EVENT_PROGRESS;
1714 		if (chanp->chan_cmid_destroy_state &
1715 		    SOL_CMA_CALLER_CMID_DESTROYED) {
1716 			cv_broadcast(&chanp->chan_destroy_cv);
1717 			mutex_exit(&chanp->chan_mutex);
1718 		} else {
1719 			mutex_exit(&chanp->chan_mutex);
1720 			rdma_destroy_id(idp);
1721 		}
1722 		return;
1723 	}
1724 ofs_consume_event:
1725 	if (event == RDMA_CM_EVENT_DISCONNECTED || event ==
1726 	    RDMA_CM_EVENT_REJECTED) {
1727 		mutex_enter(&chanp->chan_mutex);
1728 		chanp->chan_connect_flag = SOL_CMA_CONNECT_NONE;
1729 		chanp->chan_qp_hdl = NULL;
1730 		mutex_exit(&chanp->chan_mutex);
1731 	}
1732 	if (event == RDMA_CM_EVENT_DISCONNECTED && root_idp) {
1733 		cma_chan_state_t	chan_state;
1734 
1735 		mutex_enter(&chanp->chan_mutex);
1736 		cma_handle_nomore_events(chanp);
1737 		chan_state = cma_get_chan_state(chanp);
1738 		chanp->chan_cmid_destroy_state &=
1739 		    ~SOL_CMA_CALLER_EVENT_PROGRESS;
1740 		if (chanp->chan_cmid_destroy_state &
1741 		    SOL_CMA_CALLER_CMID_DESTROYED) {
1742 			cv_broadcast(&chanp->chan_destroy_cv);
1743 			mutex_exit(&chanp->chan_mutex);
1744 		} else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1745 			/* If rdma_destroy_id() was called, destroy CMID */
1746 			mutex_exit(&chanp->chan_mutex);
1747 			cma_destroy_id((struct rdma_cm_id *)chanp);
1748 		} else
1749 			mutex_exit(&chanp->chan_mutex);
1750 		return;
1751 	} else if (event == RDMA_CM_EVENT_DISCONNECTED && !root_idp) {
1752 		/*
1753 		 * Client side TCP CMID :
1754 		 *	If rdma_destroy_id() was called, destroy CMID.
1755 		 *
1756 		 *	If not chan_connect_flag is set to CONNECT_NONE
1757 		 *	so it can be deleted when rdma_destroy_id is
1758 		 *	called.
1759 		 */
1760 		mutex_enter(&chanp->chan_mutex);
1761 		chan_state = cma_get_chan_state(chanp);
1762 		chanp->chan_cmid_destroy_state &=
1763 		    ~SOL_CMA_CALLER_EVENT_PROGRESS;
1764 		if (chanp->chan_cmid_destroy_state &
1765 		    SOL_CMA_CALLER_CMID_DESTROYED) {
1766 			cv_broadcast(&chanp->chan_destroy_cv);
1767 			mutex_exit(&chanp->chan_mutex);
1768 		} else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1769 			mutex_exit(&chanp->chan_mutex);
1770 			cma_destroy_id(idp);
1771 		} else
1772 			mutex_exit(&chanp->chan_mutex);
1773 		return;
1774 	} else if (IS_UDP_CMID(idp) && event == RDMA_CM_EVENT_UNREACHABLE) {
1775 		/*
1776 		 * If rdma_destroy_id() was called, destroy CMID
1777 		 * If not chan_connect_flag is set to CONNECT_NONE
1778 		 * so it can be deleted when rdma_destroy_id is
1779 		 * called.
1780 		 */
1781 		mutex_enter(&chanp->chan_mutex);
1782 		chan_state = cma_get_chan_state(chanp);
1783 		chanp->chan_cmid_destroy_state &=
1784 		    ~SOL_CMA_CALLER_EVENT_PROGRESS;
1785 		if (chanp->chan_cmid_destroy_state &
1786 		    SOL_CMA_CALLER_CMID_DESTROYED) {
1787 			cv_broadcast(&chanp->chan_destroy_cv);
1788 			mutex_exit(&chanp->chan_mutex);
1789 		} else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1790 			mutex_exit(&chanp->chan_mutex);
1791 			cma_destroy_id(idp);
1792 		} else
1793 			mutex_exit(&chanp->chan_mutex);
1794 		return;
1795 	}
1796 
1797 	mutex_enter(&chanp->chan_mutex);
1798 	chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_EVENT_PROGRESS;
1799 	if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
1800 		cv_broadcast(&chanp->chan_destroy_cv);
1801 	mutex_exit(&chanp->chan_mutex);
1802 }
1803 
1804 /* Local Static functions */
1805 static struct rdma_cm_id *
1806 cma_alloc_chan(rdma_cm_event_handler evt_hdlr, void *context,
1807     enum rdma_port_space ps)
1808 {
1809 	struct rdma_cm_id	*rdma_idp;
1810 	sol_cma_chan_t		*chanp;
1811 
1812 	chanp = kmem_zalloc(sizeof (sol_cma_chan_t), KM_SLEEP);
1813 	mutex_init(&chanp->chan_mutex, NULL, MUTEX_DRIVER, NULL);
1814 	cv_init(&chanp->chan_destroy_cv, NULL, CV_DRIVER, NULL);
1815 	rdma_idp = &(chanp->chan_rdma_cm);
1816 	rdma_idp->context = context;
1817 	rdma_idp->ps = ps;
1818 	rdma_idp->event_handler = evt_hdlr;
1819 	mutex_enter(&chanp->chan_mutex);
1820 	cma_set_chan_state(chanp, SOL_CMA_CHAN_IDLE);
1821 	avl_create(&chanp->chan_req_avl_tree, sol_cma_req_cmid_cmp,
1822 	    sizeof (sol_cma_chan_t),
1823 	    offsetof(sol_cma_chan_t, chan_req_avl_node));
1824 	avl_create(&chanp->chan_acpt_avl_tree, sol_cma_cmid_cmp,
1825 	    sizeof (sol_cma_chan_t),
1826 	    offsetof(sol_cma_chan_t, chan_acpt_avl_node));
1827 	mutex_exit(&chanp->chan_mutex);
1828 
1829 	return (rdma_idp);
1830 }
1831 
1832 /* Change the state of sol_cma_chan_t */
1833 static void
1834 cma_set_chan_state(sol_cma_chan_t *chanp, cma_chan_state_t newstate)
1835 {
1836 	ASSERT(MUTEX_HELD(&chanp->chan_mutex));
1837 	chanp->chan_state = newstate;
1838 }
1839 
1840 cma_chan_state_t
1841 cma_get_chan_state(sol_cma_chan_t *chanp)
1842 {
1843 	ASSERT(MUTEX_HELD(&chanp->chan_mutex));
1844 	return (chanp->chan_state);
1845 }
1846 
1847 /* Check & Swap the state of sol_ucma_chan_t */
1848 static int
1849 cma_cas_chan_state(sol_cma_chan_t *chanp, cma_chan_state_t prevstate,
1850     cma_chan_state_t newstate)
1851 {
1852 	int	ret = 0;
1853 
1854 	ASSERT(MUTEX_HELD(&chanp->chan_mutex));
1855 	if (chanp->chan_state != prevstate)
1856 		ret = -1;
1857 	else
1858 		chanp->chan_state = newstate;
1859 
1860 	return (ret);
1861 }
1862 
1863 static void
1864 cma_free_listen_list(struct rdma_cm_id *idp)
1865 {
1866 	genlist_entry_t	*entry;
1867 	sol_cma_chan_t	*chanp = (sol_cma_chan_t *)idp;
1868 
1869 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_free_listen_list(%p)", idp);
1870 	mutex_enter(&chanp->chan_mutex);
1871 	entry = remove_genlist_head(&(CHAN_LISTEN_LIST(chanp)));
1872 	mutex_exit(&chanp->chan_mutex);
1873 	while (entry) {
1874 		sol_cma_chan_t	*ep_chanp;
1875 
1876 		ep_chanp = (sol_cma_chan_t *)entry->data;
1877 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "fini_ep_chan: %p",
1878 		    ep_chanp);
1879 		if (ibcma_fini_ep_chan(ep_chanp) == 0) {
1880 			genlist_entry_t		*entry1;
1881 			struct ib_device	*device;
1882 			cma_device_t		*cma_device;
1883 
1884 			ASSERT(ep_chanp->chan_listenp);
1885 			mutex_enter(&ep_chanp->chan_mutex);
1886 			entry1 = ep_chanp->chan_listenp->listen_ep_dev_entry;
1887 			device = ep_chanp->chan_listenp->listen_ep_device;
1888 			ASSERT(device);
1889 			cma_device = device->data;
1890 			delete_genlist(&cma_device->cma_epchan_list,
1891 			    entry1);
1892 			sol_cma_release_device(
1893 			    (struct rdma_cm_id *)ep_chanp);
1894 			mutex_exit(&ep_chanp->chan_mutex);
1895 			if (ep_chanp->chan_listenp)
1896 				kmem_free(ep_chanp->chan_listenp,
1897 				    sizeof (sol_cma_listen_info_t));
1898 
1899 			mutex_destroy(&ep_chanp->chan_mutex);
1900 			cv_destroy(&ep_chanp->chan_destroy_cv);
1901 			kmem_free(ep_chanp, sizeof (sol_cma_chan_t));
1902 			kmem_free(entry, sizeof (genlist_entry_t));
1903 		}
1904 
1905 		mutex_enter(&chanp->chan_mutex);
1906 		entry = remove_genlist_head(&(CHAN_LISTEN_LIST(chanp)));
1907 		mutex_exit(&chanp->chan_mutex);
1908 	}
1909 }
1910 
1911 /*
1912  * Destroy a listening CMID when :
1913  *	a. All CONNECTION REQUEST recieved have been rejected
1914  *	   or closed.
1915  *	b. No CONNECTION REQUEST recieved.
1916  * Do not destroy a listening CMID when :
1917  *	a. CONNECTION REQUEST has been recieved and not been
1918  *	   accepted from the passive / server side.
1919  *	b. CONNECTION REQUEST has been recieved and has been
1920  *	   accepted from the passive server side.
1921  *	Mark the listening CMID as destroy pending.
1922  *
1923  * For CMIDs created for rdma_connect() or created for a
1924  * CONNECT request, destroy the CMID only when :
1925  *       CONNECTION has been closed or rejected.
1926  *
1927  *       Mark the CMID as destroy pending.
1928  *
1929  * When a connection is rejected or closed :
1930  *	Check if flag indicates - destroy pending,
1931  *	cma_destroy_id() is called, this also does
1932  *
1933  *	If there is a listening CMID assosiated with it,
1934  *	   call cma_destroy_if(listen_cmid);
1935  */
1936 void
1937 cma_destroy_id(struct rdma_cm_id *idp)
1938 {
1939 	sol_cma_chan_t		*chanp = (sol_cma_chan_t *)idp;
1940 	cma_chan_state_t	state;
1941 	ulong_t			acpt_nodes, req_nodes;
1942 
1943 	mutex_enter(&chanp->chan_mutex);
1944 	acpt_nodes = avl_numnodes(&chanp->chan_acpt_avl_tree);
1945 	req_nodes = avl_numnodes(&chanp->chan_req_avl_tree);
1946 	state = cma_get_chan_state(chanp);
1947 	SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_destroy_id(%p)- "
1948 	    "est CMIDs %ld, req CMID %ld, listen_root %p, state %x, %x",
1949 	    idp, acpt_nodes, req_nodes, chanp->listen_root,
1950 	    state, chanp->chan_req_state);
1951 
1952 	/*
1953 	 * If there are either REQ recieved or Established CMIDs just return.
1954 	 * rdma_destroy() for these CMIDs can be called by client later.
1955 	 */
1956 	if (acpt_nodes || req_nodes) {
1957 		cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_PENDING);
1958 		mutex_exit(&chanp->chan_mutex);
1959 		return;
1960 	}
1961 	cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROYING);
1962 	avl_destroy(&chanp->chan_req_avl_tree);
1963 	avl_destroy(&chanp->chan_acpt_avl_tree);
1964 
1965 	mutex_exit(&chanp->chan_mutex);
1966 	if (idp->route.path_rec) {
1967 		kmem_free(idp->route.path_rec,
1968 		    sizeof (struct ib_sa_path_rec) * idp->route.num_paths);
1969 		idp->route.path_rec = NULL;
1970 	}
1971 
1972 	switch (chanp->chan_xport_type) {
1973 	case SOL_CMA_XPORT_NONE :
1974 		break;
1975 	case SOL_CMA_XPORT_IB :
1976 		rdma_ib_destroy_id(idp);
1977 		break;
1978 #ifdef	IWARP_SUPPORT
1979 	case SOL_CMA_XPORT_IWARP :
1980 		rdma_iw_destroy_id(idp);
1981 		break;
1982 #endif	/* IWARP_SUPPORT */
1983 	default :
1984 		SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1985 		    "cma_destroy_id: Unsupported xport type %x",
1986 		    chanp->chan_xport_type);
1987 		break;
1988 	}
1989 
1990 	/*
1991 	 * Flush out & Free all listeners wrt to this ID
1992 	 * No locking is required as this code is executed
1993 	 * all REQ CMIDs have been destroyed. listen_list
1994 	 * will therefore not be modified during this loop.
1995 	 */
1996 	if (chanp->chan_listenp) {
1997 		cma_free_listen_list(idp);
1998 		cma_fini_listen_root(chanp);
1999 		kmem_free((void *)chanp->chan_listenp,
2000 		    sizeof (sol_cma_listen_info_t));
2001 		chanp->chan_listenp = NULL;
2002 	}
2003 
2004 	if (chanp->listen_root) {
2005 		struct rdma_cm_id	*root_idp;
2006 		sol_cma_chan_t		*root_chanp;
2007 
2008 		root_idp = chanp->listen_root;
2009 		root_chanp = (sol_cma_chan_t *)root_idp;
2010 		mutex_enter(&root_chanp->chan_mutex);
2011 		state = cma_get_chan_state(root_chanp);
2012 		acpt_nodes = avl_numnodes(&root_chanp->chan_acpt_avl_tree);
2013 		req_nodes = avl_numnodes(&root_chanp->chan_req_avl_tree);
2014 		mutex_exit(&root_chanp->chan_mutex);
2015 		SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_destroy_id(%p)-"
2016 		    " root idp %p, state %x, acpt_nodes %ld, req_nodes %ld",
2017 		    idp, root_idp, state, acpt_nodes, req_nodes);
2018 
2019 		if (state == SOL_CMA_CHAN_DESTROY_PENDING &&
2020 		    req_nodes == 0UL && acpt_nodes == 0UL) {
2021 			mutex_enter(&root_chanp->chan_mutex);
2022 			root_chanp->chan_req_state = REQ_CMID_NONE;
2023 			mutex_exit(&root_chanp->chan_mutex);
2024 			cma_destroy_id(root_idp);
2025 		} else if (state == SOL_CMA_CHAN_DESTROY_WAIT &&
2026 		    req_nodes == 0UL && acpt_nodes == 0UL) {
2027 			mutex_enter(&root_chanp->chan_mutex);
2028 			cma_set_chan_state(root_chanp,
2029 			    SOL_CMA_CHAN_DESTROY_PENDING);
2030 			root_chanp->chan_req_state = REQ_CMID_NONE;
2031 			cv_broadcast(&root_chanp->chan_destroy_cv);
2032 			mutex_exit(&root_chanp->chan_mutex);
2033 		}
2034 	}
2035 
2036 	mutex_destroy(&chanp->chan_mutex);
2037 	cv_destroy(&chanp->chan_destroy_cv);
2038 	kmem_free(chanp, sizeof (sol_cma_chan_t));
2039 }
2040 
2041 /*
2042  * Server TCP disconnect for an established channel.
2043  *	Remove from EST AVL tree.
2044  *
2045  *	If destroy_id() has been called for the listening
2046  *	CMID and there are no more CMIDs with pending
2047  *	events corresponding to the listening CMID, free
2048  *	the listening CMID.
2049  *
2050  *
2051  *	If not chan_connect_flag is set to CONNECT_NONE
2052  *	so it can be deleted when rdma_destroy_id is
2053  *	called.
2054  */
2055 static void
2056 cma_handle_nomore_events(sol_cma_chan_t *chanp)
2057 {
2058 	struct rdma_cm_id	*idp, *root_idp;
2059 	sol_cma_chan_t		*root_chanp;
2060 	cma_chan_state_t	state;
2061 	ulong_t			req_nodes, acpt_nodes;
2062 
2063 	idp = (struct rdma_cm_id *)chanp;
2064 	root_idp = CHAN_LISTEN_ROOT(chanp);
2065 	root_chanp = (sol_cma_chan_t *)root_idp;
2066 	if (!root_chanp)
2067 		return;
2068 
2069 	CHAN_LISTEN_ROOT(chanp) = NULL;
2070 	mutex_enter(&root_chanp->chan_mutex);
2071 	root_chanp->chan_req_total_cnt--;
2072 	if (!root_chanp->chan_req_total_cnt)
2073 		root_chanp->chan_req_state = REQ_CMID_NONE;
2074 	if (root_idp->ps == RDMA_PS_TCP && chanp->chan_req_state ==
2075 	    REQ_CMID_ACCEPTED) {
2076 		avl_remove(&root_chanp->chan_acpt_avl_tree, idp);
2077 		chanp->chan_req_state = REQ_CMID_NONE;
2078 	}
2079 	if (chanp->chan_req_state == REQ_CMID_CREATED ||
2080 	    chanp->chan_req_state == REQ_CMID_NOTIFIED) {
2081 		avl_remove(&root_chanp->chan_req_avl_tree, idp);
2082 		chanp->chan_req_state = REQ_CMID_NONE;
2083 	}
2084 	state = cma_get_chan_state(root_chanp);
2085 	req_nodes = avl_numnodes(&root_chanp->chan_req_avl_tree);
2086 	acpt_nodes = avl_numnodes(&root_chanp->chan_acpt_avl_tree);
2087 	mutex_exit(&root_chanp->chan_mutex);
2088 	if (state == SOL_CMA_CHAN_DESTROY_PENDING && req_nodes == 0UL &&
2089 	    acpt_nodes == 0UL)
2090 		cma_destroy_id(root_idp);
2091 }
2092 
2093 extern int ib_modify_qp(struct ib_qp *, struct ib_qp_attr *, int);
2094 extern int rdma_init_qp_attr(struct rdma_cm_id *, struct ib_qp_attr *,
2095     int *);
2096 
2097 static int
2098 cma_init_ud_qp(sol_cma_chan_t *chanp, struct ib_qp *qp)
2099 {
2100 	struct ib_qp_attr qp_attr;
2101 	int qp_attr_mask, ret;
2102 
2103 	qp_attr.qp_state = IB_QPS_INIT;
2104 	ret = rdma_init_qp_attr(&chanp->chan_rdma_cm, &qp_attr, &qp_attr_mask);
2105 	if (ret)
2106 		return (ret);
2107 
2108 	ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
2109 	if (ret)
2110 		return (ret);
2111 
2112 	qp_attr.qp_state = IB_QPS_RTR;
2113 	ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
2114 	if (ret)
2115 		return (ret);
2116 
2117 	qp_attr.qp_state = IB_QPS_RTS;
2118 	qp_attr.sq_psn = 0;
2119 	ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN);
2120 
2121 	return (ret);
2122 }
2123 
2124 static int
2125 cma_init_conn_qp(sol_cma_chan_t *chanp, struct ib_qp *qp)
2126 {
2127 	struct ib_qp_attr qp_attr;
2128 	int qp_attr_mask, ret;
2129 
2130 	qp_attr.qp_state = IB_QPS_INIT;
2131 	ret = rdma_init_qp_attr(&chanp->chan_rdma_cm, &qp_attr, &qp_attr_mask);
2132 	if (ret)
2133 		return (ret);
2134 
2135 	return (ib_modify_qp(qp, &qp_attr, qp_attr_mask));
2136 }
2137 
2138 static inline int
2139 cma_is_ud_ps(enum rdma_port_space ps)
2140 {
2141 	return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
2142 }
2143 
2144 int
2145 rdma_create_qp(struct rdma_cm_id *idp, struct ib_pd *pd,
2146     struct ib_qp_init_attr *qp_init_attr)
2147 {
2148 	sol_cma_chan_t	*chanp;
2149 	struct ib_qp	*qp;
2150 	int		ret;
2151 	ofs_client_t	*dev_ofs_client;
2152 
2153 	ASSERT(idp);
2154 	chanp = (sol_cma_chan_t *)idp;
2155 	if (idp->device->node_guid != pd->device->node_guid)
2156 		return (-EINVAL);
2157 
2158 	dev_ofs_client = (ofs_client_t *)pd->device->clnt_hdl;
2159 	rdma_map_id2clnthdl(idp, dev_ofs_client->ibt_hdl, NULL);
2160 
2161 	qp = ib_create_qp(pd, qp_init_attr);
2162 	if ((uintptr_t)qp >= (uintptr_t)-0xFFF) {
2163 		return ((intptr_t)qp);
2164 	}
2165 	rdma_map_id2qphdl(idp, (void *)qp->ibt_qp);
2166 
2167 	if (cma_is_ud_ps(idp->ps)) {
2168 		ret = cma_init_ud_qp(chanp, qp);
2169 	} else {
2170 		ret = cma_init_conn_qp(chanp, qp);
2171 	}
2172 
2173 	if (ret) {
2174 		goto err;
2175 	}
2176 
2177 	idp->qp = qp;
2178 	chanp->chan_qp_num = qp->qp_num;
2179 	chanp->chan_is_srq = (qp->srq != NULL);
2180 	return (0);
2181 err:
2182 	(void) ib_destroy_qp(qp);
2183 	return (ret);
2184 }
2185 
2186 void
2187 rdma_destroy_qp(struct rdma_cm_id *idp)
2188 {
2189 	ASSERT(idp);
2190 	(void) ib_destroy_qp(idp->qp);
2191 	idp->qp = NULL;
2192 }
2193