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 }