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