xref: /illumos-gate/usr/src/uts/common/io/ib/clients/of/sol_ucma/sol_ucma.c (revision fffafeb2cc01732fd6a28ed530e4424094685ece)
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  * The sol_ucma driver provides the API for librdmacm library for RDMACM
28  * functionality.
29  *
30  * sol_uverbs will create a minor node with prefix ":ucma",
31  * which can be opened only by the kernel (cred == kcred).
32  *
33  * sol_cma driver will open and close the sol_uverb minor
34  * device using the Layered Driver Interfaces (See PSARC
35  * 2001/769).
36  */
37 
38 /* Standard driver includes */
39 #include <sys/types.h>
40 #include <sys/modctl.h>
41 #include <sys/ddi.h>
42 #include <sys/sunddi.h>
43 #include <sys/file.h>
44 #include <sys/errno.h>
45 #include <sys/open.h>
46 #include <sys/cred.h>
47 #include <sys/stat.h>
48 #include <sys/ddi.h>
49 #include <sys/sunddi.h>
50 #include <sys/conf.h>
51 #include <sys/uio.h>
52 #include <sys/sunldi.h>
53 #include <sys/modctl.h>
54 
55 /* Common header files */
56 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
57 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs2ucma.h>
58 #include <sys/ib/clients/of/ofed_kernel.h>
59 
60 /* Kernel Headers for User rdma_cm API */
61 #include <sys/ib/clients/of/rdma/ib_addr.h>
62 #include <sys/ib/clients/of/rdma/rdma_user_cm.h>
63 
64 /* Kernel rdma_cm API */
65 #include <sys/ib/clients/of/rdma/rdma_cm.h>
66 
67 /* sol_ucma internal Header files */
68 #include <sys/ib/clients/of/sol_ucma/sol_ucma.h>
69 
70 /* entry point function prototype declarations */
71 static int sol_ucma_attach(dev_info_t *, ddi_attach_cmd_t);
72 static int sol_ucma_detach(dev_info_t *, ddi_detach_cmd_t);
73 static int sol_ucma_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
74 static int sol_ucma_open(dev_t *, int, int, cred_t *);
75 static int sol_ucma_close(dev_t, int, int, cred_t *);
76 static int sol_ucma_write(dev_t, struct uio *,  cred_t *);
77 static int sol_ucma_poll(dev_t, short, int, short *, struct pollhead **);
78 
79 /* Driver entry points */
80 static struct cb_ops	sol_ucma_cb_ops = {
81 	sol_ucma_open,		/* open */
82 	sol_ucma_close,		/* close */
83 	nodev,			/* strategy (block) */
84 	nodev,			/* print (block) */
85 	nodev,			/* dump (block) */
86 	nodev,			/* read */
87 	sol_ucma_write,		/* write */
88 	nodev,			/* ioctl */
89 	nodev,			/* devmap */
90 	nodev,			/* mmap */
91 	nodev,			/* segmap */
92 	sol_ucma_poll,		/* chpoll */
93 	ddi_prop_op,		/* prop_op */
94 	NULL,			/* streams */
95 	D_NEW | D_MP | D_64BIT,	/* flags */
96 	CB_REV			/* rev */
97 };
98 
99 /* Driver operations */
100 static struct dev_ops	sol_ucma_dev_ops = {
101 	DEVO_REV,		/* struct rev */
102 	0,			/* refcnt */
103 	sol_ucma_getinfo,	/* getinfo */
104 	nulldev,		/* identify */
105 	nulldev,		/* probe */
106 	sol_ucma_attach,	/* attach */
107 	sol_ucma_detach,	/* detach */
108 	nodev,			/* reset */
109 	&sol_ucma_cb_ops,	/* cb_ops */
110 	NULL,			/* bus_ops */
111 	nodev,			/* power */
112 	ddi_quiesce_not_needed	/* quiesce */
113 };
114 
115 /* Module Driver Info */
116 static struct modldrv sol_ucma_modldrv = {
117 	&mod_driverops,
118 	"Solaris User RDMACM driver",
119 	&sol_ucma_dev_ops
120 };
121 
122 /* Module Linkage */
123 static struct modlinkage sol_ucma_modlinkage = {
124 	MODREV_1,
125 	&sol_ucma_modldrv,
126 	NULL,
127 };
128 
129 static char	*sol_ucma_dbg_str = "sol_ucma";
130 sol_ofs_uobj_table_t	ucma_file_uo_tbl;
131 sol_ofs_uobj_table_t	ucma_ctx_uo_tbl;
132 sol_ofs_uobj_table_t	ucma_mcast_uo_tbl;
133 
134 /* Function pointers for uverbs functions */
135 static uverbs_get_clnt_hdl_t		uverbs_get_hdl_fp = NULL;
136 static uverbs_qpnum2qphdl_t		uverbs_qpnum2qphdl_fp = NULL;
137 static uverbs_disable_uqpn_mod_t	uverbs_disable_uqpn_modify_fp = NULL;
138 static uverbs_uqpn_cq_ctrl_t		uverbs_uqpn_cq_ctrl_fp = NULL;
139 static uverbs_set_qp_free_state_t	uverbs_set_qp_free_state_fp = NULL;
140 static uverbs_flush_qp_t		uverbs_flush_qp_fp = NULL;
141 
142 /* Global Variables */
143 sol_ucma_t	sol_ucma;
144 
145 /* RDMACM Functions  */
146 static int	sol_ucma_create_id(dev_t, void *, struct uio *);
147 static int	sol_ucma_destroy_id(dev_t, void *, struct uio *);
148 static int	sol_ucma_bind_addr(dev_t, void *, struct uio *);
149 static int	sol_ucma_resolve_addr(dev_t, void *, struct uio *);
150 static int	sol_ucma_resolve_route(dev_t, void *, struct uio *);
151 static int	sol_ucma_query_route(dev_t, void *, struct uio *);
152 static int	sol_ucma_connect(dev_t, void *, struct uio *);
153 static int	sol_ucma_listen(dev_t, void *, struct uio *);
154 static int	sol_ucma_accept(dev_t, void *, struct uio *);
155 static int	sol_ucma_reject(dev_t, void *, struct uio *);
156 static int	sol_ucma_disconnect(dev_t, void *, struct uio *);
157 static int	sol_ucma_init_qp_attr(dev_t, void *, struct uio *);
158 static int	sol_ucma_get_event(dev_t, void *, struct uio *);
159 static int	sol_ucma_set_option(dev_t, void *, struct uio *);
160 static int	sol_ucma_notify(dev_t, void *, struct uio *);
161 static int	sol_ucma_join_mcast(dev_t, void *, struct uio *);
162 static int	sol_ucma_leave_mcast(dev_t, void *, struct uio *);
163 
164 /*
165  * Event callback from sol_cma
166  */
167 int sol_ucma_evt_hdlr(struct rdma_cm_id *, struct rdma_cm_event *);
168 
169 /*
170  * Internal functions.
171  */
172 static sol_ucma_file_t	*
173 ucma_alloc_file(minor_t *);
174 
175 static sol_ucma_chan_t *
176 ucma_alloc_chan(sol_ucma_file_t *, sol_ucma_create_id_t *);
177 
178 static void
179 ucma_free_chan(sol_ucma_chan_t *, int);
180 
181 static int
182 get_file_chan(uint32_t, sol_ucma_file_t **, sol_ucma_chan_t **, char *, int);
183 
184 static void
185 rdma2usr_route(struct rdma_cm_id *, sol_ucma_query_route_resp_t *);
186 
187 static void
188 usr2rdma_conn_param(struct rdma_ucm_conn_param *, struct rdma_conn_param *);
189 
190 static void
191 rdma2usr_conn_param(struct rdma_conn_param *, struct rdma_ucm_conn_param *);
192 
193 static void
194 rdma2usr_ud_param(struct rdma_ud_param *, sol_ucma_ud_param_t *);
195 
196 static void	sol_ucma_user_objs_init();
197 static void	sol_ucma_user_objs_fini();
198 
199 int
200 _init(void)
201 {
202 	int error;
203 
204 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "_init()");
205 	sol_ucma_user_objs_init();
206 	mutex_init(&sol_ucma.ucma_mutex, NULL, MUTEX_DRIVER, NULL);
207 	cv_init(&sol_ucma.ucma_open_cv, NULL, CV_DRIVER, NULL);
208 
209 	if ((error = ldi_ident_from_mod(&sol_ucma_modlinkage,
210 	    &sol_ucma.ucma_ldi_ident)) != 0) {
211 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
212 		    "ldi_ident_from_mod() failed");
213 		mutex_destroy(&sol_ucma.ucma_mutex);
214 		cv_destroy(&sol_ucma.ucma_open_cv);
215 		sol_ucma_user_objs_fini();
216 		return (error);
217 	}
218 	sol_ucma.ucma_clnt_hdl_flag = SOL_UCMA_CLNT_HDL_UNINITIALIZED;
219 	error = mod_install(&sol_ucma_modlinkage);
220 	if (error) {
221 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "mod_install() failed");
222 		ldi_ident_release(sol_ucma.ucma_ldi_ident);
223 		mutex_destroy(&sol_ucma.ucma_mutex);
224 		cv_destroy(&sol_ucma.ucma_open_cv);
225 		sol_ucma_user_objs_fini();
226 		return (error);
227 	}
228 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "_init(): ret");
229 	return (error);
230 }
231 
232 int
233 _info(struct modinfo *modinfop)
234 {
235 	return (mod_info(&sol_ucma_modlinkage, modinfop));
236 }
237 
238 int
239 _fini(void)
240 {
241 	int ret;
242 
243 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "_fini()");
244 	if ((ret = mod_remove(&sol_ucma_modlinkage)) != 0) {
245 		SOL_OFS_DPRINTF_L3(sol_ucma_dbg_str,
246 		    "sol_ucma, _fini : mod_remove failed");
247 		return (ret);
248 	}
249 	ldi_ident_release(sol_ucma.ucma_ldi_ident);
250 	mutex_destroy(&sol_ucma.ucma_mutex);
251 	cv_destroy(&sol_ucma.ucma_open_cv);
252 	sol_ucma_user_objs_fini();
253 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "_fini(): ret");
254 	return (DDI_SUCCESS);
255 }
256 
257 static int
258 sol_ucma_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
259 {
260 	int	rval;
261 
262 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "attach(%p, %x)", dip, cmd);
263 
264 	switch (cmd) {
265 	case DDI_ATTACH:
266 		mutex_enter(&sol_ucma.ucma_mutex);
267 		if (sol_ucma.ucma_dip != NULL) {
268 			mutex_exit(&sol_ucma.ucma_mutex);
269 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
270 			    "attach: failed, > 1 instance");
271 			return (DDI_FAILURE);
272 		}
273 		sol_ucma.ucma_dip = dip;
274 		mutex_exit(&sol_ucma.ucma_mutex);
275 
276 		rval = ddi_create_minor_node(dip, "sol_ucma", S_IFCHR,
277 		    0, DDI_PSEUDO, 0);
278 		if (rval != DDI_SUCCESS) {
279 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
280 			    "attach: ddi_create_minor_node failed");
281 			mutex_enter(&sol_ucma.ucma_mutex);
282 			sol_ucma.ucma_dip = NULL;
283 			mutex_exit(&sol_ucma.ucma_mutex);
284 			return (DDI_FAILURE);
285 		}
286 
287 		SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str,
288 		    "attach : DDI_ATTACH success");
289 		return (DDI_SUCCESS);
290 	case DDI_RESUME:
291 		return (DDI_SUCCESS);
292 	default:
293 		return (DDI_FAILURE);
294 	}
295 }
296 
297 static int
298 sol_ucma_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
299 {
300 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "detach(%p, %x)", dip, cmd);
301 
302 	switch (cmd) {
303 	case DDI_DETACH:
304 		mutex_enter(&sol_ucma.ucma_mutex);
305 		if (sol_ucma.ucma_num_file) {
306 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
307 			    "detach : %x files not closed",
308 			    sol_ucma.ucma_num_file);
309 			mutex_exit(&sol_ucma.ucma_mutex);
310 			return (DDI_FAILURE);
311 		}
312 		sol_ucma.ucma_dip = NULL;
313 		mutex_exit(&sol_ucma.ucma_mutex);
314 
315 		ddi_remove_minor_node(dip, "sol_ucma");
316 
317 		SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str,
318 		    "detach : DDI_DETACH success");
319 		return (DDI_SUCCESS);
320 	case DDI_SUSPEND:
321 		return (DDI_SUCCESS);
322 	default:
323 		return (DDI_FAILURE);
324 	}
325 }
326 
327 /*ARGSUSED*/
328 static int
329 sol_ucma_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
330     void **resultp)
331 {
332 	switch (cmd) {
333 	case DDI_INFO_DEVT2DEVINFO:
334 		*resultp = (void *)sol_ucma.ucma_dip;
335 		return (DDI_SUCCESS);
336 	case DDI_INFO_DEVT2INSTANCE:
337 		*resultp = (void *)0;
338 		return (DDI_SUCCESS);
339 	default :
340 		return (DDI_FAILURE);
341 	}
342 }
343 
344 static int
345 sol_ucma_open(dev_t *devp, int flag, int otype, cred_t *credp)
346 {
347 	sol_ucma_file_t	*new_filep;
348 	minor_t		new_minor;
349 
350 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "open(%p, %x, %x, %p)",
351 	    devp, flag, otype, credp);
352 
353 	new_filep = ucma_alloc_file(&new_minor);
354 	if (new_filep == NULL)
355 		return (EAGAIN);
356 	SOL_OFS_DPRINTF_L4(sol_ucma_dbg_str, "sol_ucma new minor %x",
357 	    new_minor);
358 
359 	/*
360 	 * For the first open, ensure that the sol_uverbs driver is attached.
361 	 * Also get the function pointers for uverbs API functions using
362 	 * ddi_modopen() and ddi_modsym() for the sol_uverbs driver.
363 	 *
364 	 * ldi_open() is done to ensure that sol_uverbs driver is attached,
365 	 * even though ddi_modopen is sufficient to get the function pointers
366 	 * for the uverbs APIs
367 	 */
368 	mutex_enter(&sol_ucma.ucma_mutex);
369 	if (sol_ucma.ucma_clnt_hdl_flag == SOL_UCMA_CLNT_HDL_UNINITIALIZED) {
370 		int	rval, ret_errno;
371 
372 		sol_ucma.ucma_clnt_hdl_flag =
373 		    SOL_UCMA_CLNT_HDL_INITIALIZING;
374 		if ((rval = ldi_open_by_name(SOL_UCMA_UVERBS_PATH,
375 		    FREAD | FWRITE, kcred, &sol_ucma.ucma_ldi_hdl,
376 		    sol_ucma.ucma_ldi_ident)) != 0) {
377 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
378 			    "ldi_open_by_name(%s, ...) failed with rval %x",
379 			    SOL_UCMA_UVERBS_PATH, rval);
380 			sol_ofs_uobj_free(&new_filep->file_uobj);
381 			sol_ucma.ucma_clnt_hdl_flag =
382 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
383 			mutex_exit(&sol_ucma.ucma_mutex);
384 			return (ENODEV);
385 		}
386 		if ((sol_ucma.ucma_mod_hdl = ddi_modopen("drv/sol_uverbs",
387 		    KRTLD_MODE_FIRST, &ret_errno)) == NULL) {
388 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
389 			    "ddi_modopen(%s, ...) failed", "drv/sol_uverbs");
390 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
391 			    FREAD | FWRITE, kcred);
392 			sol_ofs_uobj_free(&new_filep->file_uobj);
393 			sol_ucma.ucma_clnt_hdl_flag =
394 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
395 			mutex_exit(&sol_ucma.ucma_mutex);
396 			return (ret_errno);
397 		}
398 		if ((uverbs_get_hdl_fp = (uverbs_get_clnt_hdl_t)ddi_modsym(
399 		    sol_ucma.ucma_mod_hdl, SOL_UVERBS_GET_CLNT_HDL, &ret_errno))
400 		    == NULL) {
401 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
402 			    "ddi_modsym(%s, ...) failed",
403 			    SOL_UVERBS_GET_CLNT_HDL);
404 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
405 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
406 			    FREAD | FWRITE, kcred);
407 			sol_ofs_uobj_free(&new_filep->file_uobj);
408 			sol_ucma.ucma_clnt_hdl_flag =
409 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
410 			mutex_exit(&sol_ucma.ucma_mutex);
411 			return (ret_errno);
412 		}
413 		if ((uverbs_qpnum2qphdl_fp = (uverbs_qpnum2qphdl_t)ddi_modsym(
414 		    sol_ucma.ucma_mod_hdl, SOL_UVERBS_QPNUM2QPHDL, &ret_errno))
415 		    == NULL) {
416 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
417 			    "ddi_modsym(%s, ...) failed",
418 			    SOL_UVERBS_QPNUM2QPHDL);
419 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
420 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
421 			    FREAD | FWRITE, kcred);
422 			sol_ofs_uobj_free(&new_filep->file_uobj);
423 			sol_ucma.ucma_clnt_hdl_flag =
424 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
425 			mutex_exit(&sol_ucma.ucma_mutex);
426 			return (ret_errno);
427 		}
428 		if ((uverbs_disable_uqpn_modify_fp =
429 		    (uverbs_disable_uqpn_mod_t)ddi_modsym(
430 		    sol_ucma.ucma_mod_hdl, SOL_UVERBS_DISABLE_UQPN_MODIFY,
431 		    &ret_errno)) == NULL) {
432 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
433 			    "ddi_modsym(%s, ...) failed",
434 			    SOL_UVERBS_DISABLE_UQPN_MODIFY);
435 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
436 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
437 			    FREAD | FWRITE, kcred);
438 			sol_ofs_uobj_free(&new_filep->file_uobj);
439 			sol_ucma.ucma_clnt_hdl_flag =
440 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
441 			mutex_exit(&sol_ucma.ucma_mutex);
442 			return (ret_errno);
443 		}
444 		if ((uverbs_uqpn_cq_ctrl_fp =
445 		    (uverbs_uqpn_cq_ctrl_t)ddi_modsym(
446 		    sol_ucma.ucma_mod_hdl, SOL_UVERBS_UQPN_CQ_CTRL,
447 		    &ret_errno)) == NULL) {
448 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
449 			    "ddi_modsym(%s, ...) failed",
450 			    SOL_UVERBS_UQPN_CQ_CTRL);
451 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
452 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
453 			    FREAD | FWRITE, kcred);
454 			sol_ofs_uobj_free(&new_filep->file_uobj);
455 			sol_ucma.ucma_clnt_hdl_flag =
456 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
457 			mutex_exit(&sol_ucma.ucma_mutex);
458 			return (ret_errno);
459 		}
460 		if ((uverbs_set_qp_free_state_fp =
461 		    (uverbs_set_qp_free_state_t)ddi_modsym(
462 		    sol_ucma.ucma_mod_hdl, SOL_UVERBS_SET_QPFREE_STATE,
463 		    &ret_errno)) == NULL) {
464 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
465 			    "ddi_modsym(%s, ...) failed",
466 			    SOL_UVERBS_SET_QPFREE_STATE);
467 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
468 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
469 			    FREAD | FWRITE, kcred);
470 			sol_ofs_uobj_free(&new_filep->file_uobj);
471 			sol_ucma.ucma_clnt_hdl_flag =
472 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
473 			mutex_exit(&sol_ucma.ucma_mutex);
474 			return (ret_errno);
475 		}
476 		if ((uverbs_flush_qp_fp =
477 		    (uverbs_flush_qp_t)ddi_modsym(
478 		    sol_ucma.ucma_mod_hdl, SOL_UVERBS_FLUSH_QP,
479 		    &ret_errno)) == NULL) {
480 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
481 			    "ddi_modsym(%s, ...) failed",
482 			    SOL_UVERBS_FLUSH_QP);
483 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
484 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
485 			    FREAD | FWRITE, kcred);
486 			sol_ofs_uobj_free(&new_filep->file_uobj);
487 			sol_ucma.ucma_clnt_hdl_flag =
488 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
489 			mutex_exit(&sol_ucma.ucma_mutex);
490 			return (ret_errno);
491 		}
492 
493 		(*uverbs_get_hdl_fp) (&sol_ucma.ucma_ib_clnt_hdl,
494 		    &sol_ucma.ucma_iw_clnt_hdl);
495 		if (sol_ucma.ucma_ib_clnt_hdl == NULL &&
496 		    sol_ucma.ucma_iw_clnt_hdl == NULL) {
497 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
498 			    "uverbs_get_clnt_hdl failed");
499 			(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
500 			(void) ldi_close(sol_ucma.ucma_ldi_hdl,
501 			    FREAD | FWRITE, kcred);
502 			sol_ofs_uobj_free(&new_filep->file_uobj);
503 			sol_ucma.ucma_clnt_hdl_flag =
504 			    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
505 			mutex_exit(&sol_ucma.ucma_mutex);
506 			return (ENODEV);
507 		}
508 		sol_ucma.ucma_clnt_hdl_flag =
509 		    SOL_UCMA_CLNT_HDL_INITIALIZED;
510 		cv_broadcast(&sol_ucma.ucma_open_cv);
511 	} else if (sol_ucma.ucma_clnt_hdl_flag ==
512 	    SOL_UCMA_CLNT_HDL_INITIALIZING) {
513 		cv_wait(&sol_ucma.ucma_open_cv, &sol_ucma.ucma_mutex);
514 	}
515 	mutex_exit(&sol_ucma.ucma_mutex);
516 	*devp = makedevice(getmajor(*devp), new_minor);
517 
518 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "open Success");
519 	return (0);
520 }
521 
522 static int
523 sol_ucma_close(dev_t dev, int flag, int otype, cred_t *credp)
524 {
525 	minor_t		minor;
526 	sol_ucma_file_t	*filep;
527 	genlist_entry_t	*entry;
528 
529 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "close(%x, %x, %x, %p)",
530 	    dev, flag, otype, credp);
531 
532 	minor = getminor(dev);
533 	filep =  (sol_ucma_file_t *)sol_ofs_uobj_get_read(
534 	    &ucma_file_uo_tbl, minor);
535 	if (!filep) {
536 		SOL_OFS_DPRINTF_L4(sol_ucma_dbg_str, "close, no dev_t %x",
537 		    dev);
538 		return (0);
539 	}
540 
541 	/* Disable further event handling for this CM event channel */
542 	mutex_enter(&filep->file_mutex);
543 	if (filep->file_evt_close_flag == SOL_UCMA_EVT_PROGRESS) {
544 		cv_wait(&filep->file_evt_close_cv, &filep->file_mutex);
545 	}
546 	filep->file_evt_close_flag = SOL_UCMA_EVT_DISABLED;
547 	mutex_exit(&filep->file_mutex);
548 
549 	/*
550 	 * Destroy CM IDs which have not been destroyed.
551 	 * For CMIDs which have been connected, call
552 	 * uverbs_set_qp_free_state(SOL_UVERBS2UCMA_ENABLE_QP_FREE)
553 	 * so that QP free will be done when appropriate,
554 	 */
555 	entry = remove_genlist_head(&filep->file_id_list);
556 	while (entry) {
557 		sol_ucma_chan_t	*chanp;
558 		void		*qphdl;
559 
560 		chanp = (sol_ucma_chan_t *)entry->data;
561 		mutex_enter(&chanp->chan_mutex);
562 		if (chanp->chan_rdma_id)
563 			(chanp->chan_rdma_id)->context = NULL;
564 		mutex_exit(&chanp->chan_mutex);
565 		rdma_destroy_id(chanp->chan_rdma_id);
566 
567 		mutex_enter(&chanp->chan_mutex);
568 		qphdl = chanp->chan_qp_hdl;
569 		chanp->chan_qp_hdl = NULL;
570 		mutex_exit(&chanp->chan_mutex);
571 		if (qphdl)
572 			(*uverbs_set_qp_free_state_fp) (
573 			    SOL_UVERBS2UCMA_ENABLE_QP_FREE, 0, qphdl);
574 		ucma_free_chan(chanp, 1);
575 
576 		entry = remove_genlist_head(&filep->file_id_list);
577 	}
578 
579 	/* Flush out any events that have not been acknowledged. */
580 	mutex_enter(&filep->file_mutex);
581 	if (filep->file_pending_evt_cnt) {
582 		sol_ucma_event_t	*evtp;
583 
584 		SOL_OFS_DPRINTF_L3(sol_ucma_dbg_str,
585 		    "close : %d Events not reported to userland",
586 		    filep->file_pending_evt_cnt);
587 		entry = remove_genlist_head(&filep->file_evt_list);
588 		while (entry) {
589 			evtp = (sol_ucma_event_t *)entry->data;
590 			kmem_free(evtp, sizeof (sol_ucma_event_t));
591 			kmem_free(entry, sizeof (genlist_entry_t));
592 			entry = remove_genlist_head(&filep->file_evt_list);
593 		};
594 		mutex_exit(&filep->file_mutex);
595 	}
596 
597 	/*
598 	 * Module close for sol_uverbs when the last file is closed.
599 	 * Set the function pointers to sol_uverbs API to NULL
600 	 * ddi_modclose() and ldi_close() - sol_uverbs driver
601 	 */
602 	mutex_enter(&sol_ucma.ucma_mutex);
603 	if (sol_ucma.ucma_num_file == 1) {
604 		sol_ucma.ucma_clnt_hdl_flag =
605 		    SOL_UCMA_CLNT_HDL_UNINITIALIZED;
606 		uverbs_get_hdl_fp = NULL;
607 		uverbs_qpnum2qphdl_fp = NULL;
608 		uverbs_disable_uqpn_modify_fp = NULL;
609 		uverbs_uqpn_cq_ctrl_fp = NULL;
610 		uverbs_uqpn_cq_ctrl_fp  = NULL;
611 		uverbs_set_qp_free_state_fp = NULL;
612 		uverbs_flush_qp_fp = NULL;
613 		sol_ucma.ucma_ib_clnt_hdl = NULL;
614 		sol_ucma.ucma_iw_clnt_hdl = NULL;
615 		(void) ddi_modclose(sol_ucma.ucma_mod_hdl);
616 		(void) ldi_close(sol_ucma.ucma_ldi_hdl,
617 		    FREAD | FWRITE, kcred);
618 	}
619 	sol_ucma.ucma_num_file--;
620 	mutex_exit(&sol_ucma.ucma_mutex);
621 
622 	kmem_free(filep->file_pollhead, sizeof (struct pollhead));
623 	sol_ofs_uobj_put(&filep->file_uobj);
624 	mutex_destroy(&filep->file_mutex);
625 	cv_destroy(&filep->file_evt_cv);
626 	cv_destroy(&filep->file_evt_close_cv);
627 	rw_enter(&(filep->file_uobj.uo_lock), RW_WRITER);
628 	(void) sol_ofs_uobj_remove(&ucma_file_uo_tbl, &(filep->file_uobj));
629 	rw_exit(&(filep->file_uobj.uo_lock));
630 	sol_ofs_uobj_free(&(filep->file_uobj));
631 	return (0);
632 }
633 
634 typedef struct sol_ucma_cmd_table_s {
635 	int	(*sol_ucma_cmd_fnc)	(dev_t, void *, struct uio *);
636 	uint16_t	sol_ucma_in_len;
637 	uint16_t	sol_ucma_out_len;
638 } sol_ucma_cmd_table_t;
639 
640 static  sol_ucma_cmd_table_t	sol_ucma_cmd_table[] = {
641 	[RDMA_USER_CM_CMD_CREATE_ID]	= sol_ucma_create_id,
642 	    sizeof (sol_ucma_create_id_t),
643 	    sizeof (sol_ucma_create_id_resp_t),
644 	[RDMA_USER_CM_CMD_DESTROY_ID]	= sol_ucma_destroy_id,
645 	    sizeof (sol_ucma_destroy_id_t),
646 	    sizeof (sol_ucma_destroy_id_resp_t),
647 	[RDMA_USER_CM_CMD_BIND_ADDR]	= sol_ucma_bind_addr,
648 	    sizeof (sol_ucma_bind_addr_t),
649 	    0,
650 	[RDMA_USER_CM_CMD_RESOLVE_ADDR]	= sol_ucma_resolve_addr,
651 	    sizeof (sol_ucma_resolve_addr_t),
652 	    0,
653 	[RDMA_USER_CM_CMD_RESOLVE_ROUTE] = sol_ucma_resolve_route,
654 	    sizeof (sol_ucma_resolve_route_t),
655 	    0,
656 	[RDMA_USER_CM_CMD_QUERY_ROUTE]	= sol_ucma_query_route,
657 	    sizeof (sol_ucma_query_route_t),
658 	    sizeof (sol_ucma_query_route_resp_t),
659 	[RDMA_USER_CM_CMD_CONNECT]	= sol_ucma_connect,
660 	    sizeof (sol_ucma_connect_t),
661 	    0,
662 	[RDMA_USER_CM_CMD_LISTEN]	= sol_ucma_listen,
663 	    sizeof (sol_ucma_listen_t),
664 	    0,
665 	[RDMA_USER_CM_CMD_ACCEPT]	= sol_ucma_accept,
666 	    sizeof (sol_ucma_accept_t),
667 	    0,
668 	[RDMA_USER_CM_CMD_REJECT]	= sol_ucma_reject,
669 	    sizeof (sol_ucma_reject_t),
670 	    0,
671 	[RDMA_USER_CM_CMD_DISCONNECT]	= sol_ucma_disconnect,
672 	    sizeof (sol_ucma_disconnect_t),
673 	    0,
674 	[RDMA_USER_CM_CMD_INIT_QP_ATTR]	= sol_ucma_init_qp_attr,
675 	    sizeof (sol_ucma_init_qp_attr_t),
676 	    sizeof (struct ib_uverbs_qp_attr),
677 	[RDMA_USER_CM_CMD_GET_EVENT]	= sol_ucma_get_event,
678 	    sizeof (sol_ucma_get_event_t),
679 	    sizeof (sol_ucma_event_resp_t),
680 	[RDMA_USER_CM_CMD_GET_OPTION]	= NULL,
681 	    0,
682 	    0,
683 	[RDMA_USER_CM_CMD_SET_OPTION]	= sol_ucma_set_option,
684 	    sizeof (sol_ucma_set_option_t),
685 	    0,
686 	[RDMA_USER_CM_CMD_NOTIFY]	= sol_ucma_notify,
687 	    sizeof (sol_ucma_notify_t),
688 	    0,
689 	[RDMA_USER_CM_CMD_JOIN_MCAST]	= sol_ucma_join_mcast,
690 	    sizeof (sol_ucma_join_mcast_t),
691 	    sizeof (sol_ucma_create_id_resp_t),
692 	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= sol_ucma_leave_mcast,
693 	    sizeof (sol_ucma_destroy_id_t),
694 	    sizeof (sol_ucma_destroy_id_resp_t)
695 };
696 
697 #define	SOL_UCMA_MAX_CMD_DATA    512
698 static int
699 sol_ucma_write(dev_t dev, struct uio *uio,  cred_t *credp)
700 {
701 	sol_ucma_cmd_hdr_t	*user_hdrp;
702 	int			ret;
703 	void			*data_buf = NULL;
704 	char			uio_data[SOL_UCMA_MAX_CMD_DATA];
705 	size_t			uio_data_len = uio->uio_resid;
706 
707 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "write(%x, %p, %p)",
708 	    dev, uio, credp);
709 
710 	ret = uiomove((caddr_t)&uio_data, uio_data_len, UIO_WRITE, uio);
711 	user_hdrp = (sol_ucma_cmd_hdr_t *)uio_data;
712 
713 	if (ret != 0) {
714 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "write: uiomove failed");
715 		return (ret);
716 	}
717 
718 	if (user_hdrp->cmd >=
719 	    sizeof (sol_ucma_cmd_table) / sizeof (sol_ucma_cmd_table_t)) {
720 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
721 		    "open : cmd out of bound 0x%x", user_hdrp->cmd);
722 		return (EINVAL);
723 	}
724 	if (!(sol_ucma_cmd_table[user_hdrp->cmd].sol_ucma_cmd_fnc)) {
725 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
726 		    "open : Unsupported cmd 0x%x", user_hdrp->cmd);
727 		return (EINVAL);
728 	}
729 
730 	/*
731 	 * Check the user passed IN-OUT buffer length, with expected lengths
732 	 */
733 	if (sol_ucma_cmd_table[user_hdrp->cmd].sol_ucma_in_len !=
734 	    (user_hdrp->in)) {
735 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
736 		    "write : Invalid Input length cmd %x, in %x expected %x",
737 		    user_hdrp->cmd, user_hdrp->in,
738 		    sol_ucma_cmd_table[user_hdrp->cmd].sol_ucma_in_len);
739 		return (EINVAL);
740 	}
741 
742 	if (sol_ucma_cmd_table[user_hdrp->cmd].sol_ucma_out_len !=
743 	    (user_hdrp->out)) {
744 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
745 		    "write : Invalid Output length cmd %x, in %x expected %x",
746 		    user_hdrp->cmd, user_hdrp->out,
747 		    sol_ucma_cmd_table[user_hdrp->cmd].sol_ucma_out_len);
748 		return (EINVAL);
749 	}
750 
751 
752 	if (user_hdrp->in) {
753 		data_buf = (void *)((char *)uio_data +
754 		    sizeof (sol_ucma_cmd_hdr_t));
755 	}
756 
757 	ret = (sol_ucma_cmd_table[user_hdrp->cmd].sol_ucma_cmd_fnc)
758 	    (dev, data_buf, uio);
759 
760 	/* If the command fails, set back the uio_resid */
761 	if (ret)
762 		uio->uio_resid += uio_data_len;
763 
764 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "write : ret %x", ret);
765 	return (ret);
766 }
767 
768 static int
769 sol_ucma_poll(dev_t dev, short events, int anyyet,
770     short *reventsp, struct pollhead **phpp)
771 {
772 	minor_t		minor = getminor(dev);
773 	sol_ucma_file_t	*filep;
774 
775 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "poll(%x, %x)",
776 	    dev, events);
777 	if (!(events & (POLLIN | POLLRDNORM)))
778 		return (EINVAL);
779 
780 	filep =  (sol_ucma_file_t *)sol_ofs_uobj_get_read(
781 	    &ucma_file_uo_tbl, minor);
782 	ASSERT(filep);
783 
784 	if (filep->file_pending_evt_cnt) {
785 		*reventsp = POLLIN | POLLRDNORM;
786 	} else {
787 		*reventsp = 0;
788 		if (!anyyet)
789 			*phpp = filep->file_pollhead;
790 	}
791 	sol_ofs_uobj_put(&filep->file_uobj);
792 
793 	return (0);
794 }
795 
796 /*
797  * RDMACM functions.
798  */
799 /*ARGSUSED*/
800 static int
801 sol_ucma_create_id(dev_t dev, void *io_buf, struct uio *uio)
802 {
803 	minor_t		minor = getminor(dev);
804 	sol_ucma_file_t	*filep;
805 	sol_ucma_chan_t *chanp;
806 	sol_ucma_create_id_t		*ucma_id_inp;
807 	sol_ucma_create_id_resp_t	ucma_id_resp;
808 
809 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "create_id(%x, %p), minor %x",
810 	    dev, io_buf, minor);
811 
812 	ucma_id_inp = (sol_ucma_create_id_t *)io_buf;
813 	ASSERT(ucma_id_inp);
814 	ASSERT(ucma_id_inp->response.r_laddr);
815 
816 	filep =  (sol_ucma_file_t *)sol_ofs_uobj_get_read(&ucma_file_uo_tbl,
817 	    minor);
818 	ASSERT(filep);
819 
820 	chanp = ucma_alloc_chan(filep, ucma_id_inp);
821 	if (chanp == NULL)  {
822 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
823 		    "create_id: No free Channel");
824 		sol_ofs_uobj_put(&filep->file_uobj);
825 		return (ENODEV);
826 	}
827 	ucma_id_resp.id = chanp->chan_id;
828 
829 #ifdef	_LP64
830 	if (copyout(&ucma_id_resp, (void *)(ucma_id_inp->response.r_laddr),
831 	    sizeof (sol_ucma_create_id_resp_t))) {
832 #else
833 	if (copyout(&ucma_id_resp, (void *)(ucma_id_inp->response.r_addr),
834 	    sizeof (sol_ucma_create_id_resp_t))) {
835 #endif
836 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
837 		    "create_id: copyout fault");
838 		ucma_free_chan(chanp, 1);
839 		sol_ofs_uobj_put(&filep->file_uobj);
840 		return (EFAULT);
841 	}
842 /* */
843 
844 	chanp->chan_rdma_id = rdma_create_id(sol_ucma_evt_hdlr,
845 	    chanp, ucma_id_inp->ps);
846 	if (chanp->chan_rdma_id == NULL) {
847 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
848 		    "create_id: rdma_create_id failed");
849 		ucma_free_chan(chanp, 1);
850 		sol_ofs_uobj_put(&filep->file_uobj);
851 		return (EINVAL);
852 	}
853 	mutex_enter(&chanp->chan_mutex);
854 	(chanp->chan_rdma_id)->context = chanp;
855 	mutex_exit(&chanp->chan_mutex);
856 	rdma_map_id2clnthdl(chanp->chan_rdma_id, sol_ucma.ucma_ib_clnt_hdl,
857 	    sol_ucma.ucma_iw_clnt_hdl);
858 
859 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "create_id: Return SUCCESS");
860 	sol_ofs_uobj_put(&filep->file_uobj);
861 	return (0);
862 }
863 
864 /*ARGSUSED*/
865 static int
866 sol_ucma_destroy_id(dev_t dev, void *io_buf, struct uio *uio)
867 {
868 	sol_ucma_chan_t 	*chanp;
869 	uint32_t		ucma_id;
870 	sol_ucma_file_t		*filep;
871 	sol_ucma_destroy_id_t	*id_inp;
872 	minor_t			minor;
873 	genlist_entry_t		*entry;
874 	sol_ucma_destroy_id_resp_t	id_resp;
875 
876 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "destroy_id(%x, %p)",
877 	    dev, io_buf);
878 
879 	id_inp = (sol_ucma_destroy_id_t *)io_buf;
880 	ucma_id = id_inp->id;
881 	if (!get_file_chan(ucma_id, &filep, &chanp, "destroy_id", 0)) {
882 		minor = getminor(dev);
883 		filep =  (sol_ucma_file_t *)sol_ofs_uobj_get_read(
884 		    &ucma_file_uo_tbl, minor);
885 		if (!filep) {
886 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
887 			    "destroy_id : filep NULL");
888 			return (EINVAL);
889 		}
890 	} else {
891 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "destroy_id : "
892 		    "ucma_id %x invalid", ucma_id);
893 		return (0);
894 	}
895 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "destroy_id: chanp %p", chanp);
896 
897 	/*
898 	 * Event handling, Flush out events pending
899 	 * return the number of events that were acked. Free events not acked.
900 	 */
901 	ASSERT(filep);
902 	mutex_enter(&filep->file_mutex);
903 	if (filep->file_pending_evt_cnt != 0) {
904 		SOL_OFS_DPRINTF_L4(sol_ucma_dbg_str,
905 		    "destroy_id: pending events");
906 		entry = remove_genlist_head(&filep->file_evt_list);
907 		while (entry) {
908 			kmem_free((void *) (entry->data),
909 			    sizeof (sol_ucma_event_t));
910 			kmem_free(entry, sizeof (genlist_entry_t));
911 			entry = remove_genlist_head(&filep->file_evt_list);
912 		};
913 		filep->file_pending_evt_cnt = 0;
914 	}
915 	if (chanp) {
916 		mutex_enter(&chanp->chan_mutex);
917 		id_resp.events_reported = chanp->chan_evt_cnt;
918 		mutex_exit(&chanp->chan_mutex);
919 	} else {
920 		id_resp.events_reported = 0;
921 	}
922 	mutex_exit(&filep->file_mutex);
923 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "destroy_id : chanp %p, "
924 	    "evts %x", chanp, id_resp.events_reported);
925 
926 #ifdef	_LP64
927 	if (copyout(&id_resp, (void *) (id_inp->response.r_laddr),
928 	    sizeof (sol_ucma_destroy_id_resp_t))) {
929 #else
930 	if (copyout(&id_resp, (void *) (id_inp->response.r_addr),
931 	    sizeof (sol_ucma_destroy_id_resp_t))) {
932 #endif
933 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
934 		    "destroy_id: copyout fault");
935 		sol_ofs_uobj_put(&filep->file_uobj);
936 		return (EFAULT);
937 	}
938 /* */
939 
940 	if (chanp) {
941 		mutex_enter(&chanp->chan_mutex);
942 		if (chanp->chan_rdma_id)
943 			(chanp->chan_rdma_id)->context = NULL;
944 		mutex_exit(&chanp->chan_mutex);
945 		rdma_destroy_id(chanp->chan_rdma_id);
946 		ucma_free_chan(chanp, 1);
947 	}
948 
949 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "destroy_id: Success");
950 	sol_ofs_uobj_put(&filep->file_uobj);
951 	return (0);
952 }
953 
954 /*ARGSUSED*/
955 static int
956 sol_ucma_bind_addr(dev_t dev, void *io_buf, struct uio *uio)
957 {
958 	int		ret;
959 	sol_ucma_chan_t	*chanp;
960 	uint32_t	ucma_id;
961 	sol_ucma_bind_addr_t	*bind_addrp;
962 
963 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "bind_addr(%x, %p)",
964 	    dev, io_buf);
965 
966 	bind_addrp = (sol_ucma_bind_addr_t *)io_buf;
967 	ucma_id = bind_addrp->id;
968 	if (get_file_chan(ucma_id, NULL, &chanp, "bind_addr", 1))
969 		return (EINVAL);
970 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "bind_addr - chanp %p", chanp);
971 
972 	ret = rdma_bind_addr(chanp->chan_rdma_id,
973 	    (struct sockaddr *)&bind_addrp->addr);
974 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "bind_addr: ret %x", ret);
975 	return (ret);
976 }
977 
978 /*ARGSUSED*/
979 static int
980 sol_ucma_resolve_addr(dev_t dev, void *io_buf, struct uio *uio)
981 {
982 	sol_ucma_chan_t	*chanp;
983 	uint32_t	ucma_id;
984 	int		ret;
985 	sol_ucma_resolve_addr_t	*resolve_addrp;
986 
987 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "resolve_addr(%x, %p)",
988 	    dev, io_buf);
989 
990 	resolve_addrp = (sol_ucma_resolve_addr_t *)io_buf;
991 	ucma_id  = resolve_addrp->id;
992 	if (get_file_chan(ucma_id, NULL, &chanp, "resolve_addr", 1)) {
993 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
994 		    "resolve_addr: ucma_id %x invalid", ucma_id);
995 		return (EINVAL);
996 	}
997 	ASSERT(chanp);
998 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "resolve_addr - chanp %p", chanp);
999 
1000 	ret = rdma_resolve_addr(chanp->chan_rdma_id,
1001 	    (struct sockaddr *)&resolve_addrp->src_addr,
1002 	    (struct sockaddr *)&resolve_addrp->dst_addr,
1003 	    resolve_addrp->timeout_ms);
1004 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "resolve_addr: ret %x", ret);
1005 	return (ret);
1006 }
1007 
1008 /*ARGSUSED*/
1009 static int
1010 sol_ucma_resolve_route(dev_t dev, void *io_buf, struct uio *uio)
1011 {
1012 	sol_ucma_chan_t	*chanp;
1013 	uint32_t	ucma_id;
1014 	int		ret;
1015 	sol_ucma_resolve_route_t	*resolve_routep;
1016 
1017 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str,
1018 	    "resolve_route(%x, %p)", dev, io_buf);
1019 
1020 	resolve_routep = (sol_ucma_resolve_route_t *)io_buf;
1021 	ucma_id  = resolve_routep->id;
1022 	if (get_file_chan(ucma_id, NULL, &chanp, "resolve_route", 1))
1023 		return (EINVAL);
1024 	ASSERT(chanp);
1025 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "resolve_route - chanp %p",
1026 	    chanp);
1027 
1028 	ret = rdma_resolve_route(chanp->chan_rdma_id,
1029 	    resolve_routep->timeout_ms);
1030 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "resolve_route: ret %x", ret);
1031 	return (ret);
1032 }
1033 
1034 /*ARGSUSED*/
1035 static int
1036 sol_ucma_query_route(dev_t dev, void *io_buf, struct uio *uio)
1037 {
1038 	sol_ucma_chan_t			*chanp;
1039 	uint32_t			ucma_id;
1040 	struct rdma_cm_id		*idp;
1041 	sol_ucma_query_route_t		*query_routep;
1042 	sol_ucma_query_route_resp_t	route_info;
1043 
1044 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "query_route(%x, %p)",
1045 	    dev, io_buf);
1046 
1047 	query_routep = (sol_ucma_query_route_t *)io_buf;
1048 	ucma_id  = query_routep->id;
1049 	if (get_file_chan(ucma_id, NULL, &chanp, "query_route", 1))
1050 		return (EINVAL);
1051 	ASSERT(chanp);
1052 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "query_route - chanp %p", chanp);
1053 	idp = chanp->chan_rdma_id;
1054 
1055 	bzero(&route_info, sizeof (route_info));
1056 	rdma2usr_route(idp, &route_info);
1057 
1058 #ifdef	_LP64
1059 	if (copyout(&route_info, (void *) (query_routep->response.r_laddr),
1060 	    sizeof (sol_ucma_query_route_resp_t))) {
1061 #else
1062 	if (copyout(&route_info, (void *) (query_routep->response.r_addr),
1063 	    sizeof (sol_ucma_query_route_resp_t))) {
1064 #endif
1065 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
1066 		    "query_route: copyout fault");
1067 		return (EFAULT);
1068 	}
1069 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "query_route: Succcess");
1070 	return (0);
1071 }
1072 
1073 /*ARGSUSED*/
1074 static int
1075 sol_ucma_connect(dev_t dev, void *io_buf, struct uio *uio)
1076 {
1077 	sol_ucma_chan_t		*chanp;
1078 	uint32_t		ucma_id;
1079 	int			ret;
1080 	void			*qphdl;
1081 	sol_ucma_connect_t	*connectp;
1082 	struct rdma_conn_param	conn_param;
1083 	struct rdma_cm_id	*idp;
1084 
1085 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "connect(%x, %p)",
1086 	    dev, io_buf);
1087 
1088 	connectp = (sol_ucma_connect_t *)io_buf;
1089 	ucma_id  = connectp->id;
1090 	if (get_file_chan(ucma_id, NULL, &chanp, "connect", 1))
1091 		return (EINVAL);
1092 	ASSERT(chanp);
1093 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "connect - chanp %p", chanp);
1094 
1095 	usr2rdma_conn_param(&(connectp->conn_param), &conn_param);
1096 	ASSERT(uverbs_qpnum2qphdl_fp);
1097 	ASSERT(uverbs_disable_uqpn_modify_fp);
1098 	ASSERT(uverbs_uqpn_cq_ctrl_fp);
1099 	qphdl = (*uverbs_qpnum2qphdl_fp) (conn_param.qp_num);
1100 	if (qphdl == NULL) {
1101 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "connect: "
1102 		    "invalid QPNum %x", conn_param.qp_num);
1103 		return (EINVAL);
1104 	}
1105 	(*uverbs_disable_uqpn_modify_fp) (conn_param.qp_num);
1106 	rdma_map_id2qphdl(chanp->chan_rdma_id, qphdl);
1107 	idp = chanp->chan_rdma_id;
1108 	if (idp->ps == RDMA_PS_TCP)
1109 		(void) (*uverbs_uqpn_cq_ctrl_fp) (conn_param.qp_num,
1110 		    SOL_UVERBS2UCMA_CQ_NOTIFY_DISABLE);
1111 	chanp->chan_qp_num = conn_param.qp_num;
1112 	ret = rdma_connect(chanp->chan_rdma_id, &conn_param);
1113 
1114 	/*
1115 	 * rdma_connect() initiated for this CMID, disable sol_uverbs to
1116 	 * free the QP assosiated with this CM ID.
1117 	 */
1118 	if (ret == 0 && idp->ps == RDMA_PS_TCP) {
1119 		mutex_enter(&chanp->chan_mutex);
1120 		chanp->chan_qp_hdl = qphdl;
1121 		chanp->chan_flags |= SOL_UCMA_CHAN_CONNECT_FLAG;
1122 		mutex_exit(&chanp->chan_mutex);
1123 		(*uverbs_set_qp_free_state_fp) (
1124 		    SOL_UVERBS2UCMA_DISABLE_QP_FREE, conn_param.qp_num,
1125 		    NULL);
1126 	}
1127 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "connect: ret %x", ret);
1128 	return (ret);
1129 }
1130 
1131 /*ARGSUSED*/
1132 static int
1133 sol_ucma_listen(dev_t dev, void *io_buf, struct uio *uio)
1134 {
1135 	sol_ucma_chan_t		*chanp;
1136 	uint32_t		ucma_id;
1137 	int			ret;
1138 	sol_ucma_listen_t	*listenp;
1139 
1140 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "listen(%x, %p)",
1141 	    dev, io_buf);
1142 
1143 	listenp = (sol_ucma_listen_t *)io_buf;
1144 	ucma_id  = listenp->id;
1145 	if (get_file_chan(ucma_id, NULL, &chanp, "listen", 1))
1146 		return (EINVAL);
1147 	ASSERT(chanp);
1148 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "listen - chanp %p", chanp);
1149 
1150 	listenp->backlog = (listenp->backlog == 0 ||
1151 	    listenp->backlog > SOL_UCMA_MAX_LISTEN) ?
1152 	    SOL_UCMA_MAX_LISTEN : listenp->backlog;
1153 	chanp->chan_backlog = listenp->backlog;
1154 
1155 	ret = rdma_listen(chanp->chan_rdma_id, listenp->backlog);
1156 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "listen: ret %x", ret);
1157 	return (ret);
1158 }
1159 
1160 /*ARGSUSED*/
1161 static int
1162 sol_ucma_accept(dev_t dev, void *io_buf, struct uio *uio)
1163 {
1164 	int				ret;
1165 	uint32_t		ucma_id;
1166 	sol_ucma_chan_t	*chanp;
1167 	void			*qphdl;
1168 	sol_ucma_accept_t		*acpt;
1169 	struct rdma_conn_param	conn_param;
1170 
1171 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "accept(%x, %p)",
1172 	    dev, io_buf);
1173 
1174 	acpt = (sol_ucma_accept_t *)io_buf;
1175 	ucma_id = acpt->id;
1176 	if (get_file_chan(ucma_id, NULL, &chanp, "accept", 1))
1177 		return (EINVAL);
1178 	ASSERT(chanp);
1179 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "accept - chanp %p", chanp);
1180 
1181 	if ((acpt->conn_param).valid) {
1182 		struct rdma_cm_id	*idp;
1183 
1184 		chanp->chan_user_id = acpt->uid;
1185 		usr2rdma_conn_param(&acpt->conn_param, &conn_param);
1186 
1187 		ASSERT(uverbs_qpnum2qphdl_fp);
1188 		qphdl = (*uverbs_qpnum2qphdl_fp) (conn_param.qp_num);
1189 		if (qphdl == NULL) {
1190 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "accept: "
1191 			    "invalid QPNum %x", conn_param.qp_num);
1192 			return (EINVAL);
1193 		}
1194 		(*uverbs_disable_uqpn_modify_fp) (conn_param.qp_num);
1195 		rdma_map_id2qphdl(chanp->chan_rdma_id, qphdl);
1196 		idp = chanp->chan_rdma_id;
1197 		if (idp->ps == RDMA_PS_TCP)
1198 			(void) (*uverbs_uqpn_cq_ctrl_fp) (conn_param.qp_num,
1199 			    SOL_UVERBS2UCMA_CQ_NOTIFY_DISABLE);
1200 		chanp->chan_qp_num = conn_param.qp_num;
1201 		ret = rdma_accept(chanp->chan_rdma_id, &conn_param);
1202 	} else
1203 		ret = rdma_accept(chanp->chan_rdma_id, NULL);
1204 
1205 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "accept: ret %x", ret);
1206 	return (ret);
1207 }
1208 
1209 /*ARGSUSED*/
1210 static int
1211 sol_ucma_reject(dev_t dev, void *io_buf, struct uio *uio)
1212 {
1213 	int		ret;
1214 	uint32_t	ucma_id;
1215 	sol_ucma_chan_t	*chanp;
1216 	sol_ucma_reject_t	*rjct;
1217 
1218 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "reject(%x, %p)", dev, io_buf);
1219 
1220 	rjct = (sol_ucma_reject_t *)io_buf;
1221 	ucma_id = rjct->id;
1222 	if (get_file_chan(ucma_id, NULL, &chanp, "reject", 1))
1223 		return (EINVAL);
1224 	ASSERT(chanp);
1225 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "reject - chanp %p", chanp);
1226 
1227 	ret = rdma_reject(chanp->chan_rdma_id, rjct->private_data,
1228 	    rjct->private_data_len);
1229 
1230 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "reject: ret %x", ret);
1231 	return (ret);
1232 }
1233 
1234 /*ARGSUSED*/
1235 static int
1236 sol_ucma_init_qp_attr(dev_t dev, void *io_buf, struct uio *uio)
1237 {
1238 	int				ret;
1239 	uint32_t			ucma_id;
1240 	uint32_t			qp_attr_mask;
1241 	sol_ucma_chan_t			*chanp;
1242 	sol_ucma_init_qp_attr_t		*qp_attr_inp;
1243 	struct ib_uverbs_qp_attr	uverbs_qp_attr;
1244 	struct ib_qp_attr		qp_attr;
1245 
1246 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "init_qp_attr(%x, %p)",
1247 	    dev, io_buf);
1248 
1249 	qp_attr_inp = (sol_ucma_init_qp_attr_t *)io_buf;
1250 	ucma_id = qp_attr_inp->id;
1251 	if (get_file_chan(ucma_id, NULL, &chanp, "init_qp_attr", 1))
1252 		return (EINVAL);
1253 	ASSERT(chanp);
1254 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "init_qp_attr - chanp %p", chanp);
1255 
1256 	qp_attr.qp_state = qp_attr_inp->qp_state;
1257 	if ((ret = rdma_init_qp_attr(chanp->chan_rdma_id, &qp_attr,
1258 	    (int *)&qp_attr_mask)) != 0) {
1259 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "init_qp_attr: ret %x, "
1260 		    "mask %x", ret, qp_attr_mask);
1261 		return (EINVAL);
1262 	}
1263 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "init_qp_attr: ret %x, mask %x",
1264 	    ret, qp_attr_mask);
1265 
1266 	bzero(&uverbs_qp_attr, sizeof (uverbs_qp_attr));
1267 	uverbs_qp_attr.qp_attr_mask = qp_attr_mask;
1268 	uverbs_qp_attr.qp_state = qp_attr.qp_state;
1269 	uverbs_qp_attr.pkey_index = qp_attr.pkey_index;
1270 	uverbs_qp_attr.port_num = qp_attr.port_num;
1271 	uverbs_qp_attr.qp_access_flags = qp_attr.qp_access_flags;
1272 	uverbs_qp_attr.qkey = qp_attr.qkey;
1273 	uverbs_qp_attr.path_mtu = qp_attr.path_mtu;
1274 	uverbs_qp_attr.dest_qp_num = qp_attr.dest_qp_num;
1275 	uverbs_qp_attr.rq_psn = qp_attr.rq_psn;
1276 	uverbs_qp_attr.max_dest_rd_atomic = qp_attr.max_dest_rd_atomic;
1277 	uverbs_qp_attr.min_rnr_timer = qp_attr.min_rnr_timer;
1278 	uverbs_qp_attr.ah_attr.dlid = qp_attr.ah_attr.dlid;
1279 	if (qp_attr.ah_attr.ah_flags) {
1280 		uverbs_qp_attr.ah_attr.is_global = 1;
1281 		bcopy(&(qp_attr.ah_attr.grh.dgid),
1282 		    &(uverbs_qp_attr.ah_attr.grh.dgid), 16);
1283 		uverbs_qp_attr.ah_attr.grh.flow_label =
1284 		    qp_attr.ah_attr.grh.flow_label;
1285 		uverbs_qp_attr.ah_attr.grh.sgid_index =
1286 		    qp_attr.ah_attr.grh.sgid_index;
1287 		uverbs_qp_attr.ah_attr.grh.hop_limit =
1288 		    qp_attr.ah_attr.grh.hop_limit;
1289 		uverbs_qp_attr.ah_attr.grh.traffic_class =
1290 		    qp_attr.ah_attr.grh.traffic_class;
1291 	}
1292 	uverbs_qp_attr.ah_attr.sl = qp_attr.ah_attr.sl;
1293 	uverbs_qp_attr.ah_attr.src_path_bits = qp_attr.ah_attr.src_path_bits;
1294 	uverbs_qp_attr.ah_attr.static_rate = qp_attr.ah_attr.static_rate;
1295 	uverbs_qp_attr.ah_attr.port_num = qp_attr.ah_attr.port_num;
1296 
1297 #ifdef	_LP64
1298 	if (copyout(&uverbs_qp_attr, (void *) (qp_attr_inp->response.r_laddr),
1299 	    sizeof (uverbs_qp_attr))) {
1300 #else
1301 	if (copyout(&uverbs_qp_attr, (void *) (qp_attr_inp->response.r_addr),
1302 	    sizeof (uverbs_qp_attr))) {
1303 #endif
1304 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "init_qp_attr : copyout "
1305 		    "failed");
1306 		return (EFAULT);
1307 	}
1308 	return (0);
1309 }
1310 
1311 static int
1312 sol_ucma_get_event(dev_t dev, void *io_buf, struct uio *uio)
1313 {
1314 	minor_t			minor;
1315 	sol_ucma_file_t		*filep;
1316 	sol_ucma_chan_t		*evt_chanp;
1317 	genlist_entry_t		*entry;
1318 	struct rdma_ucm_get_event	*user_evt_inp;
1319 	sol_ucma_event_t		*queued_evt;
1320 	struct rdma_ucm_event_resp	*user_evt_resp;
1321 
1322 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "get_event(%x, %p)", dev, io_buf);
1323 	user_evt_inp = (struct rdma_ucm_get_event *)io_buf;
1324 
1325 	minor = getminor(dev);
1326 	filep =  (sol_ucma_file_t *)sol_ofs_uobj_get_read(&ucma_file_uo_tbl,
1327 	    minor);
1328 	ASSERT(filep);
1329 
1330 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "get_event fmode %x",
1331 	    uio->uio_fmode);
1332 
1333 	mutex_enter(&filep->file_mutex);
1334 	while (filep->file_pending_evt_cnt == 0) {
1335 		SOL_OFS_DPRINTF_L4(sol_ucma_dbg_str, "get_event: No events");
1336 		if (uio->uio_fmode & (FNONBLOCK | FNDELAY)) {
1337 			mutex_exit(&filep->file_mutex);
1338 			sol_ofs_uobj_put(&filep->file_uobj);
1339 			SOL_OFS_DPRINTF_L4(sol_ucma_dbg_str,
1340 			    "get_event: No events, nonblocking");
1341 			return (EAGAIN);
1342 		}
1343 		if (!cv_wait_sig(&filep->file_evt_cv, &filep->file_mutex)) {
1344 			mutex_exit(&filep->file_mutex);
1345 			sol_ofs_uobj_put(&filep->file_uobj);
1346 			SOL_OFS_DPRINTF_L3(sol_ucma_dbg_str,
1347 			    "get_event: Got Sig");
1348 			return (EINTR);
1349 		}
1350 	}
1351 
1352 	entry = remove_genlist_head(&filep->file_evt_list);
1353 	mutex_exit(&filep->file_mutex);
1354 	ASSERT(entry);
1355 	queued_evt = (sol_ucma_event_t *)entry->data;
1356 	ASSERT(queued_evt);
1357 	user_evt_resp = &queued_evt->event_resp;
1358 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "event2usr "
1359 	    "uid %llx, id %x, event %x, status %x", user_evt_resp->uid,
1360 	    user_evt_resp->id, user_evt_resp->event, user_evt_resp->status);
1361 #ifdef	_LP64
1362 	if (copyout((void *)user_evt_resp,
1363 	    (void *)(user_evt_inp->response.r_laddr),
1364 	    sizeof (sol_ucma_event_resp_t))) {
1365 #else
1366 	if (copyout((void *)user_evt_resp,
1367 	    (void *)(user_evt_inp->response.r_addr),
1368 	    sizeof (sol_ucma_event_resp_t))) {
1369 #endif
1370 		SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "get_event: copyout "
1371 		    "failed");
1372 		sol_ofs_uobj_put(&filep->file_uobj);
1373 		kmem_free(entry, sizeof (genlist_entry_t));
1374 		return (EFAULT);
1375 	}
1376 	mutex_enter(&filep->file_mutex);
1377 	filep->file_pending_evt_cnt--;
1378 	if (queued_evt->event_mcast)
1379 		(queued_evt->event_mcast)->mcast_events++;
1380 	evt_chanp = queued_evt->event_chan;
1381 	if (evt_chanp) {
1382 		/*
1383 		 * If the event is RDMA_CM_EVENT_CONNECT_RESPONSE or
1384 		 * RDMA_CM_EVENT_ESTABLISHED and the CM ID is for RC,
1385 		 * enable completion notifications for the QP.
1386 		 */
1387 		if (user_evt_resp->event == RDMA_CM_EVENT_CONNECT_RESPONSE ||
1388 		    user_evt_resp->event == RDMA_CM_EVENT_ESTABLISHED) {
1389 			struct rdma_cm_id	*idp;
1390 			int	rc;
1391 
1392 			idp = evt_chanp->chan_rdma_id;
1393 			if (idp->ps == RDMA_PS_TCP) {
1394 				ASSERT(uverbs_uqpn_cq_ctrl_fp);
1395 				rc = (*uverbs_uqpn_cq_ctrl_fp)(
1396 				    evt_chanp->chan_qp_num,
1397 				    SOL_UVERBS2UCMA_CQ_NOTIFY_ENABLE);
1398 				if (rc) {
1399 					SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
1400 					    "uverbs_uqpn_cq_ctrl_fp(%X) "
1401 					    "failed!!",
1402 					    evt_chanp->chan_qp_num);
1403 					mutex_exit(&filep->file_mutex);
1404 					filep->file_pending_evt_cnt++;
1405 					return (EIO);
1406 				}
1407 			}
1408 		}
1409 
1410 		/* Bump up backlog for CONNECT_REQUEST events */
1411 		mutex_enter(&evt_chanp->chan_mutex);
1412 		if (user_evt_resp->event == RDMA_CM_EVENT_CONNECT_REQUEST)
1413 			evt_chanp->chan_backlog++;
1414 
1415 		evt_chanp->chan_evt_cnt++;
1416 		mutex_exit(&evt_chanp->chan_mutex);
1417 		SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "get_event : "
1418 		    "chan %p, cnt %x", evt_chanp, evt_chanp->chan_evt_cnt);
1419 	}
1420 	mutex_exit(&filep->file_mutex);
1421 	kmem_free(entry, sizeof (genlist_entry_t));
1422 	kmem_free(queued_evt, sizeof (sol_ucma_event_t));
1423 
1424 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "get_event: Success");
1425 	sol_ofs_uobj_put(&filep->file_uobj);
1426 	return (0);
1427 }
1428 
1429 /*
1430  * This is used when ULP wants to set the QOS option. This is *not*
1431  * supported by Solaris IB stack, return failure.
1432  */
1433 /*ARGSUSED*/
1434 static int
1435 sol_ucma_set_option(dev_t dev, void *io_buf, struct uio *uio)
1436 {
1437 		return (EINVAL);
1438 }
1439 
1440 /*
1441  * This is used when ULP uses librdmacm but uses out of band connection for CM.
1442  */
1443 /*ARGSUSED*/
1444 static int
1445 sol_ucma_notify(dev_t dev, void *io_buf, struct uio *uio)
1446 {
1447 	sol_ucma_notify_t	*notifyp;
1448 	uint32_t			ucma_id;
1449 	sol_ucma_chan_t		*chan;
1450 	int					ret;
1451 
1452 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "notify(%x, %p)", dev, io_buf);
1453 	notifyp = (sol_ucma_notify_t *)io_buf;
1454 	ucma_id = notifyp->id;
1455 	if (get_file_chan(ucma_id, NULL, &chan, "notify", 1))
1456 		return (EINVAL);
1457 	ASSERT(chan);
1458 
1459 	ret = rdma_notify(chan->chan_rdma_id, notifyp->event);
1460 	if (ret)
1461 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "notify failed %x", ret);
1462 	else
1463 		SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "notify Success");
1464 	return (ret);
1465 }
1466 
1467 /*ARGSUSED*/
1468 static int
1469 sol_ucma_join_mcast(dev_t dev, void *io_buf, struct uio *uio)
1470 {
1471 	sol_ucma_join_mcast_t		*join_buf;
1472 	sol_ucma_create_id_resp_t	join_resp;
1473 	sol_ucma_chan_t			*chanp;
1474 	sol_ucma_mcast_t		*mcastp;
1475 	int		rc;
1476 	uint32_t	ucma_id;
1477 
1478 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "join_mcast(%x, %p)",
1479 	    dev, io_buf);
1480 	join_buf = (sol_ucma_join_mcast_t *)io_buf;
1481 	ucma_id = join_buf->id;
1482 	if (get_file_chan(ucma_id, NULL, &chanp, "join_mcast", 1))
1483 		return (EINVAL);
1484 
1485 	mcastp = kmem_zalloc(sizeof (sol_ucma_mcast_t), KM_SLEEP);
1486 	bcopy((void *)(&(join_buf->addr)), (void *)(&(mcastp->mcast_addr)),
1487 	    sizeof (struct sockaddr));
1488 	mcastp->mcast_chan = chanp;
1489 	sol_ofs_uobj_init(&mcastp->mcast_uobj, NULL, SOL_UCMA_MCAST_TYPE);
1490 	if (sol_ofs_uobj_add(&ucma_mcast_uo_tbl, &mcastp->mcast_uobj) != 0) {
1491 		sol_ofs_uobj_free(&mcastp->mcast_uobj);
1492 		return (ENOMEM);
1493 	}
1494 	mcastp->mcast_uobj.uo_live = 1;
1495 	mcastp->mcast_id = join_resp.id = mcastp->mcast_uobj.uo_id;
1496 	mcastp->mcast_uid = join_buf->uid;
1497 
1498 	rc = rdma_join_multicast(chanp->chan_rdma_id,
1499 	    (struct sockaddr *)(&(join_buf->addr)), mcastp);
1500 	if (rc) {
1501 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
1502 		    "join_mcast: rdma_join_multicast ret %x", rc);
1503 		rw_enter(&(mcastp->mcast_uobj.uo_lock), RW_WRITER);
1504 		(void) sol_ofs_uobj_remove(&ucma_mcast_uo_tbl,
1505 		    &mcastp->mcast_uobj);
1506 		rw_exit(&(mcastp->mcast_uobj.uo_lock));
1507 		sol_ofs_uobj_free(&mcastp->mcast_uobj);
1508 		return (rc);
1509 	}
1510 
1511 #ifdef	_LP64
1512 	if (copyout(&join_resp, (void *) (join_buf->response.r_laddr),
1513 	    sizeof (sol_ucma_create_id_resp_t))) {
1514 #else
1515 	if (copyout(&join_resp, (void *) (join_buf->response.r_addr),
1516 	    sizeof (sol_ucma_create_id_resp_t))) {
1517 #endif
1518 		SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "join_mcast: copyout "
1519 		    "failed");
1520 		rdma_leave_multicast(chanp->chan_rdma_id,
1521 		    (struct sockaddr *)(&(join_buf->addr)));
1522 		rw_enter(&(mcastp->mcast_uobj.uo_lock), RW_WRITER);
1523 		(void) sol_ofs_uobj_remove(&ucma_mcast_uo_tbl,
1524 		    &mcastp->mcast_uobj);
1525 		rw_exit(&(mcastp->mcast_uobj.uo_lock));
1526 		sol_ofs_uobj_free(&mcastp->mcast_uobj);
1527 		return (EFAULT);
1528 	}
1529 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "join_mcast: Return Success");
1530 	return (0);
1531 }
1532 
1533 /*ARGSUSED*/
1534 static int
1535 sol_ucma_leave_mcast(dev_t dev, void *io_buf, struct uio *uio)
1536 {
1537 	sol_ucma_destroy_id_t		*id_inp;
1538 	sol_ucma_destroy_id_resp_t	id_resp;
1539 	sol_ucma_mcast_t		*mcastp;
1540 	sol_ucma_chan_t			*chanp;
1541 	uint32_t			ucma_id;
1542 
1543 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "leave_mcast(%x, %p)",
1544 	    dev, io_buf);
1545 	id_inp = (sol_ucma_destroy_id_t *)io_buf;
1546 	ucma_id = id_inp->id;
1547 	mcastp = (sol_ucma_mcast_t *)sol_ofs_uobj_get_read(&ucma_mcast_uo_tbl,
1548 	    ucma_id);
1549 	if (mcastp == NULL) {
1550 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "leave_mcast: invalid "
1551 		    "ID %x", ucma_id);
1552 		return (EINVAL);
1553 	}
1554 	chanp = mcastp->mcast_chan;
1555 
1556 	rdma_leave_multicast(chanp->chan_rdma_id, &mcastp->mcast_addr);
1557 	id_resp.events_reported = mcastp->mcast_events;
1558 
1559 #ifdef	_LP64
1560 	if (copyout(&id_resp, (void *) (id_inp->response.r_laddr),
1561 	    sizeof (sol_ucma_destroy_id_resp_t))) {
1562 #else
1563 	if (copyout(&id_resp, (void *) (id_inp->response.r_addr),
1564 	    sizeof (sol_ucma_destroy_id_resp_t))) {
1565 #endif
1566 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "leave_mcast: copyout "
1567 		    "fault");
1568 		sol_ofs_uobj_put(&mcastp->mcast_uobj);
1569 		return (EFAULT);
1570 	}
1571 	sol_ofs_uobj_put(&mcastp->mcast_uobj);
1572 	rw_enter(&(mcastp->mcast_uobj.uo_lock), RW_WRITER);
1573 	(void) sol_ofs_uobj_remove(&ucma_mcast_uo_tbl, &mcastp->mcast_uobj);
1574 	rw_exit(&(mcastp->mcast_uobj.uo_lock));
1575 	sol_ofs_uobj_free(&mcastp->mcast_uobj);
1576 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "leave_mcast: ret 0");
1577 	return (0);
1578 }
1579 
1580 /*ARGSUSED*/
1581 static int
1582 sol_ucma_disconnect(dev_t dev, void *io_buf, struct uio *uio)
1583 {
1584 	sol_ucma_disconnect_t	*disconnectp;
1585 	uint32_t	ucma_id;
1586 	sol_ucma_chan_t	*chan;
1587 	int		ret;
1588 
1589 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "disconnect(%x, %p)",
1590 	    dev, io_buf);
1591 	disconnectp = (sol_ucma_disconnect_t *)io_buf;
1592 	ucma_id = disconnectp->id;
1593 	if (get_file_chan(ucma_id, NULL, &chan, "disconnect", 1))
1594 		return (EINVAL);
1595 	ASSERT(chan);
1596 
1597 	/*
1598 	 * For a TCP CMID, which has got the DISCONNECT event, call
1599 	 * ibt_flush_qp(), to transition QP to error state.
1600 	 */
1601 	mutex_enter(&chan->chan_mutex);
1602 	if (chan->chan_flush_qp_flag == SOL_UCMA_FLUSH_QP_PENDING) {
1603 		chan->chan_flush_qp_flag = SOL_UCMA_FLUSH_QP_DONE;
1604 		mutex_exit(&chan->chan_mutex);
1605 		(*uverbs_flush_qp_fp)(chan->chan_qp_num);
1606 	} else
1607 		mutex_exit(&chan->chan_mutex);
1608 
1609 	ret = rdma_disconnect(chan->chan_rdma_id);
1610 	mutex_enter(&chan->chan_mutex);
1611 	chan->chan_flush_qp_flag = SOL_UCMA_FLUSH_QP_DONE;
1612 	mutex_exit(&chan->chan_mutex);
1613 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "disconnect: ret %x", ret);
1614 	return (ret);
1615 }
1616 
1617 /*
1618  * RDMA ID Event handler
1619  */
1620 int
1621 sol_ucma_evt_hdlr(struct rdma_cm_id *idp, struct rdma_cm_event *eventp)
1622 {
1623 	sol_ucma_chan_t		*chan, *req_chan;
1624 	sol_ucma_file_t		*file;
1625 	sol_ucma_event_t	*ucma_evt;
1626 	sol_ucma_create_id_t	ucma_create_id;
1627 
1628 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "ucma_evt_hdlr(%p, %p), "
1629 	    "event %x, status %x", idp, eventp, eventp->event,
1630 	    eventp->status);
1631 	chan = (sol_ucma_chan_t *)idp->context;
1632 	if (!chan) {
1633 		SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str, "ucma_evt_hdlr() - "
1634 		    "after destroy - %p", idp);
1635 		return (0);
1636 	}
1637 	mutex_enter(&chan->chan_mutex);
1638 	file = chan->chan_file;
1639 	if (!file) {
1640 		SOL_OFS_DPRINTF_L3(sol_ucma_dbg_str, "ucma_evt_hdlr() - "
1641 		    "after file destroy - idp %p", idp);
1642 		mutex_exit(&chan->chan_mutex);
1643 		return (0);
1644 	}
1645 	mutex_exit(&chan->chan_mutex);
1646 
1647 	mutex_enter(&file->file_mutex);
1648 	if (file->file_evt_close_flag == SOL_UCMA_EVT_DISABLED) {
1649 		SOL_OFS_DPRINTF_L3(sol_ucma_dbg_str, "ucma_evt_hdlr() - "
1650 		    "after file close - idp %p", idp);
1651 		mutex_exit(&file->file_mutex);
1652 		return (0);
1653 	}
1654 	file->file_evt_close_flag = SOL_UCMA_EVT_PROGRESS;
1655 	mutex_exit(&file->file_mutex);
1656 
1657 	/*
1658 	 * If the event is RDMA_CM_EVENT_CONNECT_REQUEST, allocate a
1659 	 * new chan. The rdma_cm_id for this chan has already been
1660 	 * allocated by sol_ofs.
1661 	 */
1662 	ucma_evt = kmem_zalloc(sizeof (sol_ucma_event_t), KM_SLEEP);
1663 	ucma_evt->event_chan = chan;
1664 	if (eventp->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
1665 		mutex_enter(&chan->chan_mutex);
1666 		if (!chan->chan_backlog) {
1667 			SOL_OFS_DPRINTF_L3(sol_ucma_dbg_str,
1668 			    "backlog exceeded");
1669 			mutex_exit(&chan->chan_mutex);
1670 			mutex_enter(&file->file_mutex);
1671 			file->file_evt_close_flag = SOL_UCMA_EVT_NONE;
1672 			cv_broadcast(&file->file_evt_close_cv);
1673 			mutex_exit(&file->file_mutex);
1674 			kmem_free(ucma_evt, sizeof (sol_ucma_event_t));
1675 			return (-1);
1676 		}
1677 		chan->chan_backlog--;
1678 		mutex_exit(&chan->chan_mutex);
1679 		ucma_create_id.uid = chan->chan_user_id;
1680 		req_chan = ucma_alloc_chan(file, &ucma_create_id);
1681 		if (req_chan == NULL)  {
1682 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
1683 			    "evt hdlr: No free Channel");
1684 			sol_ofs_uobj_put(&file->file_uobj);
1685 			mutex_enter(&file->file_mutex);
1686 			file->file_evt_close_flag = SOL_UCMA_EVT_NONE;
1687 			cv_broadcast(&file->file_evt_close_cv);
1688 			mutex_exit(&file->file_mutex);
1689 			return (-1);
1690 		}
1691 		req_chan->chan_rdma_id = idp;
1692 		mutex_enter(&req_chan->chan_mutex);
1693 		idp->context = req_chan;
1694 		mutex_exit(&req_chan->chan_mutex);
1695 		chan = req_chan;
1696 	} else if (eventp->event == RDMA_CM_EVENT_DISCONNECTED ||
1697 	    eventp->event == RDMA_CM_EVENT_REJECTED) {
1698 		void	*qphdl;
1699 
1700 		/*
1701 		 * Connection has been rejected or disconnected,
1702 		 * Enable uverbs to free QP, if it had been disabled
1703 		 * before. sol_uverbs will free the QP appropriately.
1704 		 */
1705 		mutex_enter(&chan->chan_mutex);
1706 		qphdl = chan->chan_qp_hdl;
1707 		chan->chan_qp_hdl = NULL;
1708 		if (idp->ps == RDMA_PS_TCP &&
1709 		    chan->chan_flush_qp_flag != SOL_UCMA_FLUSH_QP_DONE &&
1710 		    eventp->event == RDMA_CM_EVENT_DISCONNECTED) {
1711 			chan->chan_flush_qp_flag =
1712 			    SOL_UCMA_FLUSH_QP_PENDING;
1713 		}
1714 		mutex_exit(&chan->chan_mutex);
1715 
1716 		if (idp->ps == RDMA_PS_TCP && qphdl)
1717 			(*uverbs_set_qp_free_state_fp) (
1718 			    SOL_UVERBS2UCMA_ENABLE_QP_FREE, 0, qphdl);
1719 	} else if (eventp->event == RDMA_CM_EVENT_ESTABLISHED &&
1720 	    chan->chan_flags & SOL_UCMA_CHAN_CONNECT_FLAG)
1721 		eventp->event = RDMA_CM_EVENT_CONNECT_RESPONSE;
1722 
1723 	ucma_evt->event_resp.event = eventp->event;
1724 	ucma_evt->event_resp.status = eventp->status;
1725 	if (idp->ps == RDMA_PS_UDP || idp->ps == RDMA_PS_IPOIB)
1726 		rdma2usr_ud_param(&(eventp->param.ud),
1727 		    &(ucma_evt->event_resp.param.ud));
1728 	else
1729 		rdma2usr_conn_param(&(eventp->param.conn),
1730 		    &(ucma_evt->event_resp.param.conn));
1731 
1732 	if (eventp->event == RDMA_CM_EVENT_MULTICAST_JOIN || eventp->event ==
1733 	    RDMA_CM_EVENT_MULTICAST_ERROR) {
1734 		ucma_evt->event_mcast = (sol_ucma_mcast_t *)
1735 		    eventp->param.ud.private_data;
1736 		ucma_evt->event_resp.uid = (ucma_evt->event_mcast)->mcast_uid;
1737 		ucma_evt->event_resp.id = (ucma_evt->event_mcast)->mcast_id;
1738 	} else {
1739 		ucma_evt->event_resp.uid = chan->chan_user_id;
1740 		ucma_evt->event_resp.id = chan->chan_id;
1741 	}
1742 
1743 	mutex_enter(&file->file_mutex);
1744 	(void) add_genlist(&file->file_evt_list, (uintptr_t)ucma_evt, NULL);
1745 	file->file_pending_evt_cnt++;
1746 	mutex_exit(&file->file_mutex);
1747 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "ucma_evt_hdlr-pollwakeup");
1748 	pollwakeup(file->file_pollhead, POLLIN | POLLRDNORM);
1749 	mutex_enter(&file->file_mutex);
1750 	cv_broadcast(&file->file_evt_cv);
1751 	mutex_exit(&file->file_mutex);
1752 
1753 	mutex_enter(&file->file_mutex);
1754 	file->file_evt_close_flag = SOL_UCMA_EVT_NONE;
1755 	cv_broadcast(&file->file_evt_close_cv);
1756 	mutex_exit(&file->file_mutex);
1757 	return (0);
1758 }
1759 
1760 /*
1761  * Local Functions
1762  */
1763 static sol_ucma_file_t *
1764 ucma_alloc_file(minor_t *new_minorp)
1765 {
1766 	sol_ucma_file_t	*new_file;
1767 
1768 	new_file = kmem_zalloc(sizeof (sol_ucma_file_t), KM_SLEEP);
1769 	sol_ofs_uobj_init(&new_file->file_uobj, NULL, SOL_UCMA_EVT_FILE_TYPE);
1770 	if (sol_ofs_uobj_add(&ucma_file_uo_tbl, &new_file->file_uobj) != 0) {
1771 		sol_ofs_uobj_free(&new_file->file_uobj);
1772 		return (NULL);
1773 	}
1774 	new_file->file_uobj.uo_live = 1;
1775 	init_genlist(&new_file->file_id_list);
1776 	init_genlist(&new_file->file_evt_list);
1777 
1778 	mutex_enter(&sol_ucma.ucma_mutex);
1779 	sol_ucma.ucma_num_file++;
1780 	mutex_exit(&sol_ucma.ucma_mutex);
1781 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "new file num %x, %p",
1782 	    (new_file->file_uobj).uo_id, new_file);
1783 
1784 	mutex_init(&new_file->file_mutex, NULL,
1785 	    MUTEX_DRIVER, NULL);
1786 	cv_init(&new_file->file_evt_cv, NULL, CV_DRIVER,
1787 	    NULL);
1788 	cv_init(&new_file->file_evt_close_cv, NULL, CV_DRIVER,
1789 	    NULL);
1790 	new_file->file_pollhead = kmem_zalloc(sizeof (struct pollhead),
1791 	    KM_SLEEP);
1792 
1793 	*new_minorp = (minor_t)((new_file->file_uobj).uo_id);
1794 	return (new_file);
1795 }
1796 
1797 static sol_ucma_chan_t *
1798 ucma_alloc_chan(sol_ucma_file_t *filep, sol_ucma_create_id_t *create_id_inp)
1799 {
1800 	sol_ucma_chan_t		*new_chanp;
1801 
1802 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "_alloc_chan(%p, %p)",
1803 	    filep, create_id_inp);
1804 
1805 	new_chanp = kmem_zalloc(sizeof (sol_ucma_chan_t), KM_SLEEP);
1806 	sol_ofs_uobj_init(&new_chanp->chan_uobj, NULL, SOL_UCMA_CM_ID_TYPE);
1807 	if (sol_ofs_uobj_add(&ucma_ctx_uo_tbl, &new_chanp->chan_uobj) != 0) {
1808 		sol_ofs_uobj_free(&new_chanp->chan_uobj);
1809 		return (NULL);
1810 	}
1811 	mutex_init(&new_chanp->chan_mutex, NULL, MUTEX_DRIVER, NULL);
1812 
1813 	new_chanp->chan_uobj.uo_live = 1;
1814 	mutex_enter(&filep->file_mutex);
1815 	new_chanp->chan_list_ent = add_genlist(&filep->file_id_list,
1816 	    (uintptr_t)new_chanp, NULL);
1817 	mutex_exit(&filep->file_mutex);
1818 
1819 	SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str, "_alloc_chan - filep %p, "
1820 	    "chan_num %x, new_chan %p", filep, (new_chanp->chan_uobj).uo_id,
1821 	    new_chanp);
1822 
1823 	new_chanp->chan_file = filep;
1824 	new_chanp->chan_user_id = create_id_inp->uid;
1825 	new_chanp->chan_id = (new_chanp->chan_uobj).uo_id;
1826 
1827 	return (new_chanp);
1828 }
1829 
1830 static void
1831 ucma_free_chan(sol_ucma_chan_t *chanp, int delete_list)
1832 {
1833 	sol_ucma_file_t	*filep;
1834 
1835 	ASSERT(chanp);
1836 	if (delete_list) {
1837 		filep = chanp->chan_file;
1838 		ASSERT(filep);
1839 		mutex_enter(&filep->file_mutex);
1840 		delete_genlist(&filep->file_id_list, chanp->chan_list_ent);
1841 		mutex_exit(&filep->file_mutex);
1842 	}
1843 
1844 	mutex_destroy(&chanp->chan_mutex);
1845 	rw_enter(&(chanp->chan_uobj.uo_lock), RW_WRITER);
1846 	(void) sol_ofs_uobj_remove(&ucma_ctx_uo_tbl, &(chanp->chan_uobj));
1847 	rw_exit(&(chanp->chan_uobj.uo_lock));
1848 	sol_ofs_uobj_free(&(chanp->chan_uobj));
1849 }
1850 
1851 static int
1852 get_file_chan(uint32_t ucma_id, sol_ucma_file_t **filep,
1853     sol_ucma_chan_t **chanp, char *caller, int flag_err)
1854 {
1855 	sol_ucma_chan_t	*chan;
1856 
1857 	if (filep)
1858 		*filep = NULL;
1859 	if (chanp)
1860 		*chanp = NULL;
1861 
1862 	chan = (sol_ucma_chan_t *)sol_ofs_uobj_get_read(&ucma_ctx_uo_tbl,
1863 	    ucma_id);
1864 	if (chan == NULL) {
1865 		if (flag_err)
1866 			SOL_OFS_DPRINTF_L2(sol_ucma_dbg_str,
1867 			    "%s, ucma_id %x invalid", caller, ucma_id);
1868 		else
1869 			SOL_OFS_DPRINTF_L5(sol_ucma_dbg_str,
1870 			    "%s, ucma_id %x invalid", caller, ucma_id);
1871 		return (-1);
1872 	}
1873 
1874 	if (filep)
1875 		*filep = chan->chan_file;
1876 	if (chanp)
1877 		*chanp = chan;
1878 
1879 	sol_ofs_uobj_put(&chan->chan_uobj);
1880 	return (0);
1881 }
1882 
1883 static void
1884 rdma2usr_pathrec(struct ib_sa_path_rec *kern_path,
1885     struct ib_user_path_rec *usr_path)
1886 {
1887 	bcopy(&kern_path->dgid, &usr_path->dgid, 16);
1888 	bcopy(&kern_path->sgid, &usr_path->sgid, 16);
1889 	usr_path->dlid = kern_path->dlid;
1890 	usr_path->slid = kern_path->slid;
1891 	usr_path->raw_traffic = kern_path->raw_traffic;
1892 	usr_path->flow_label = kern_path->flow_label;
1893 	usr_path->reversible = kern_path->reversible;
1894 	usr_path->mtu = kern_path->mtu;
1895 	usr_path->pkey = kern_path->pkey;
1896 	usr_path->hop_limit = kern_path->hop_limit;
1897 	usr_path->traffic_class = kern_path->traffic_class;
1898 	usr_path->sl = kern_path->sl;
1899 	usr_path->mtu_selector = kern_path->mtu_selector;
1900 	usr_path->rate_selector = kern_path->rate_selector;
1901 	usr_path->rate = kern_path->rate;
1902 	usr_path->packet_life_time_selector =
1903 	    kern_path->packet_life_time_selector;
1904 	usr_path->packet_life_time = kern_path->packet_life_time;
1905 	usr_path->preference = kern_path->preference;
1906 	usr_path->numb_path = kern_path->numb_path;
1907 }
1908 
1909 static void
1910 rdma2usr_route(struct rdma_cm_id *idp, sol_ucma_query_route_resp_t *resp)
1911 {
1912 	struct rdma_route	*routep;
1913 	int	i;
1914 
1915 	routep = &(idp->route);
1916 	if (idp->device) {
1917 		resp->node_guid = idp->device->node_guid;
1918 		resp->port_num = idp->port_num;
1919 	}
1920 	bcopy(&(routep->addr.src_addr), &resp->src_addr,
1921 	    sizeof (struct sockaddr_in6));
1922 	bcopy(&(routep->addr.dst_addr), &resp->dst_addr,
1923 	    sizeof (struct sockaddr_in6));
1924 	resp->num_paths = routep->num_paths;
1925 	for (i = 0; i < resp->num_paths; i++) {
1926 		rdma2usr_pathrec(&(routep->path_rec[i]),
1927 		    &(resp->ib_route[i]));
1928 	}
1929 }
1930 
1931 static void
1932 usr2rdma_conn_param(struct rdma_ucm_conn_param *usr_conn_paramp,
1933     struct rdma_conn_param *conn_paramp)
1934 {
1935 	conn_paramp->private_data = usr_conn_paramp->private_data;
1936 	conn_paramp->private_data_len = usr_conn_paramp->private_data_len;
1937 	conn_paramp->responder_resources = usr_conn_paramp->responder_resources;
1938 	conn_paramp->initiator_depth = usr_conn_paramp->initiator_depth;
1939 	conn_paramp->flow_control = usr_conn_paramp->flow_control;
1940 	conn_paramp->retry_count = usr_conn_paramp->retry_count;
1941 	conn_paramp->rnr_retry_count = usr_conn_paramp->rnr_retry_count;
1942 	conn_paramp->srq = usr_conn_paramp->srq;
1943 	conn_paramp->qp_num = usr_conn_paramp->qp_num;
1944 }
1945 
1946 static void
1947 rdma2usr_conn_param(struct rdma_conn_param *conn_paramp,
1948     struct rdma_ucm_conn_param *usr_conn_paramp)
1949 {
1950 	usr_conn_paramp->private_data_len = conn_paramp->private_data_len;
1951 
1952 	bzero(usr_conn_paramp->private_data, RDMA_MAX_PRIVATE_DATA);
1953 	if (conn_paramp->private_data)
1954 		bcopy(conn_paramp->private_data,
1955 		    usr_conn_paramp->private_data,
1956 		    usr_conn_paramp->private_data_len);
1957 	usr_conn_paramp->responder_resources = conn_paramp->responder_resources;
1958 	usr_conn_paramp->initiator_depth = conn_paramp->initiator_depth;
1959 	usr_conn_paramp->flow_control = conn_paramp->flow_control;
1960 	usr_conn_paramp->retry_count = conn_paramp->retry_count;
1961 	usr_conn_paramp->rnr_retry_count = conn_paramp->rnr_retry_count;
1962 	usr_conn_paramp->srq = conn_paramp->srq;
1963 	usr_conn_paramp->qp_num = conn_paramp->qp_num;
1964 }
1965 
1966 static void
1967 rdma2usr_ud_param(struct rdma_ud_param *ud_paramp,
1968     sol_ucma_ud_param_t *usr_ud_paramp)
1969 {
1970 	struct ib_ah_attr		*ah_attrp;
1971 	struct ib_uverbs_ah_attr	*usr_ah_attrp;
1972 
1973 	usr_ud_paramp->private_data_len = ud_paramp->private_data_len;
1974 
1975 	bzero(usr_ud_paramp->private_data, RDMA_MAX_PRIVATE_DATA);
1976 	if (ud_paramp->private_data)
1977 		bcopy(ud_paramp->private_data,
1978 		    usr_ud_paramp->private_data,
1979 		    usr_ud_paramp->private_data_len);
1980 	usr_ud_paramp->qp_num = ud_paramp->qp_num;
1981 	usr_ud_paramp->qkey = ud_paramp->qkey;
1982 
1983 	ah_attrp = &(ud_paramp->ah_attr);
1984 	usr_ah_attrp = &(usr_ud_paramp->ah_attr);
1985 	bcopy(&(ah_attrp->grh.dgid), &(usr_ah_attrp->grh.dgid[0]), 16);
1986 	usr_ah_attrp->grh.flow_label = ah_attrp->grh.flow_label;
1987 	usr_ah_attrp->grh.sgid_index = ah_attrp->grh.sgid_index;
1988 	usr_ah_attrp->grh.hop_limit = ah_attrp->grh.hop_limit;
1989 	usr_ah_attrp->grh.traffic_class = ah_attrp->grh.traffic_class;
1990 	usr_ah_attrp->dlid = ah_attrp->dlid;
1991 	usr_ah_attrp->sl = ah_attrp->sl;
1992 	usr_ah_attrp->src_path_bits = ah_attrp->src_path_bits;
1993 	usr_ah_attrp->static_rate = ah_attrp->static_rate;
1994 	usr_ah_attrp->is_global = ah_attrp->ah_flags;
1995 	usr_ah_attrp->port_num = ah_attrp->port_num;
1996 }
1997 
1998 static void
1999 sol_ucma_user_objs_init()
2000 {
2001 	sol_ofs_uobj_tbl_init(&ucma_file_uo_tbl, sizeof (sol_ucma_file_t));
2002 	sol_ofs_uobj_tbl_init(&ucma_ctx_uo_tbl, sizeof (sol_ucma_chan_t));
2003 	sol_ofs_uobj_tbl_init(&ucma_mcast_uo_tbl, sizeof (sol_ucma_mcast_t));
2004 }
2005 
2006 static void
2007 sol_ucma_user_objs_fini()
2008 {
2009 	sol_ofs_uobj_tbl_fini(&ucma_file_uo_tbl);
2010 	sol_ofs_uobj_tbl_fini(&ucma_ctx_uo_tbl);
2011 	sol_ofs_uobj_tbl_fini(&ucma_mcast_uo_tbl);
2012 }
2013