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
_init(void)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
_info(struct modinfo * modinfop)233 _info(struct modinfo *modinfop)
234 {
235 return (mod_info(&sol_ucma_modlinkage, modinfop));
236 }
237
238 int
_fini(void)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
sol_ucma_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
sol_ucma_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
sol_ucma_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
sol_ucma_open(dev_t * devp,int flag,int otype,cred_t * credp)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
sol_ucma_close(dev_t dev,int flag,int otype,cred_t * credp)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
sol_ucma_write(dev_t dev,struct uio * uio,cred_t * credp)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
sol_ucma_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)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
sol_ucma_create_id(dev_t dev,void * io_buf,struct uio * uio)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