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 * sol_uverbs_qp.c 27 * 28 * OFED User Verbs kernel agent QP implementation. 29 * 30 */ 31 #include <sys/vfs.h> 32 #include <sys/vnode.h> 33 #include <sys/errno.h> 34 #include <sys/cred.h> 35 #include <sys/uio.h> 36 #include <sys/semaphore.h> 37 #include <sys/ddi.h> 38 #include <sys/sunddi.h> 39 40 #include <sys/ib/ibtl/ibvti.h> 41 #include <sys/ib/clients/of/ofa_solaris.h> 42 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h> 43 #include <sys/ib/clients/of/ofed_kernel.h> 44 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs.h> 45 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_qp.h> 46 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_event.h> 47 48 49 static uint32_t ibt_cep_flags2ibv(ibt_cep_flags_t); 50 static void uverbs_cq_ctrl(uverbs_ucq_uobj_t *, sol_uverbs_cq_ctrl_t); 51 52 extern char *sol_uverbs_dbg_str; 53 54 /* 55 * Multicast Element 56 */ 57 typedef struct uverbs_mcast_entry { 58 llist_head_t list; 59 ibt_mcg_info_t mcg; 60 } uverbs_mcast_entry_t; 61 62 /* 63 * uverbs_qp_state_table 64 * 65 * Determine if the requested QP modify operation is valid. To maintain/ensure 66 * consistency with the semantics expected by OFED user verbs operaton, this 67 * table is used to verify a QP transition. A valid transition is one that is 68 * a legal state transition and meets the required/optional attributes 69 * associated with that transition for that QP type. 70 * 71 * Note: The OFED kern-abi (See ib_user_verbs.h) does not provide any 72 * mechanism to support queue resize, consequently the IBTA spec defined 73 * valid optional parameter to modify QP size (IB_QP_CAP) is not included 74 * in the state table. 75 */ 76 typedef struct { 77 int valid; 78 enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETY + 1]; 79 enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETY + 1]; 80 } uverbs_qp_state_tbl_t; 81 82 static uverbs_qp_state_tbl_t 83 uverbs_qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = { 84 [IB_QPS_RESET] = { 85 [IB_QPS_RESET] = { .valid = 1 }, 86 [IB_QPS_ERR] = { .valid = 1 }, 87 [IB_QPS_INIT] = { .valid = 1, 88 .req_param = { 89 [IB_QPT_UD] = (IB_QP_PKEY_INDEX | 90 IB_QP_PORT | IB_QP_QKEY), 91 [IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT | 92 IB_QP_ACCESS_FLAGS), 93 [IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT | 94 IB_QP_ACCESS_FLAGS), 95 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 96 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 97 } 98 }, 99 }, 100 [IB_QPS_INIT] = { 101 [IB_QPS_RESET] = { .valid = 1 }, 102 [IB_QPS_ERR] = { .valid = 1 }, 103 [IB_QPS_INIT] = { .valid = 1, 104 .opt_param = { 105 [IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_PORT | 106 IB_QP_QKEY), 107 [IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT | 108 IB_QP_ACCESS_FLAGS), 109 [IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT | 110 IB_QP_ACCESS_FLAGS), 111 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 112 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 113 } 114 }, 115 [IB_QPS_RTR] = { .valid = 1, 116 .req_param = { 117 [IB_QPT_UC] = (IB_QP_AV | IB_QP_PATH_MTU | 118 IB_QP_DEST_QPN | IB_QP_RQ_PSN), 119 [IB_QPT_RC] = (IB_QP_AV | IB_QP_PATH_MTU | 120 IB_QP_DEST_QPN | IB_QP_RQ_PSN | 121 IB_QP_MAX_DEST_RD_ATOMIC | 122 IB_QP_MIN_RNR_TIMER), 123 }, 124 .opt_param = { 125 [IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 126 [IB_QPT_UC] = (IB_QP_ALT_PATH | 127 IB_QP_ACCESS_FLAGS | 128 IB_QP_PKEY_INDEX), 129 [IB_QPT_RC] = (IB_QP_ALT_PATH | 130 IB_QP_ACCESS_FLAGS | 131 IB_QP_PKEY_INDEX), 132 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 133 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 134 } 135 } 136 }, 137 [IB_QPS_RTR] = { 138 [IB_QPS_RESET] = { .valid = 1 }, 139 [IB_QPS_ERR] = { .valid = 1 }, 140 [IB_QPS_RTS] = { .valid = 1, 141 .req_param = { 142 [IB_QPT_UD] = IB_QP_SQ_PSN, 143 [IB_QPT_UC] = IB_QP_SQ_PSN, 144 [IB_QPT_RC] = (IB_QP_TIMEOUT | 145 IB_QP_RETRY_CNT | 146 IB_QP_RNR_RETRY | 147 IB_QP_SQ_PSN | 148 IB_QP_MAX_QP_RD_ATOMIC), 149 [IB_QPT_SMI] = IB_QP_SQ_PSN, 150 [IB_QPT_GSI] = IB_QP_SQ_PSN, 151 }, 152 .opt_param = { 153 [IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), 154 [IB_QPT_UC] = (IB_QP_CUR_STATE | 155 IB_QP_ALT_PATH | 156 IB_QP_ACCESS_FLAGS | 157 IB_QP_PATH_MIG_STATE), 158 [IB_QPT_RC] = (IB_QP_CUR_STATE | 159 IB_QP_ALT_PATH | 160 IB_QP_ACCESS_FLAGS | 161 IB_QP_MIN_RNR_TIMER | 162 IB_QP_PATH_MIG_STATE), 163 [IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 164 [IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 165 } 166 } 167 }, 168 [IB_QPS_RTS] = { 169 [IB_QPS_RESET] = { .valid = 1 }, 170 [IB_QPS_ERR] = { .valid = 1 }, 171 [IB_QPS_RTS] = { .valid = 1, 172 .opt_param = { 173 [IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), 174 [IB_QPT_UC] = (IB_QP_CUR_STATE | 175 IB_QP_ACCESS_FLAGS | 176 IB_QP_ALT_PATH | 177 IB_QP_PATH_MIG_STATE), 178 [IB_QPT_RC] = (IB_QP_CUR_STATE | 179 IB_QP_ACCESS_FLAGS | 180 IB_QP_ALT_PATH | 181 IB_QP_PATH_MIG_STATE | 182 IB_QP_MIN_RNR_TIMER), 183 [IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 184 [IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 185 } 186 }, 187 [IB_QPS_SQD] = { .valid = 1, 188 .opt_param = { 189 [IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY, 190 [IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY, 191 [IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY, 192 [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY, 193 [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY 194 } 195 }, 196 }, 197 [IB_QPS_SQD] = { 198 [IB_QPS_RESET] = { .valid = 1 }, 199 [IB_QPS_ERR] = { .valid = 1 }, 200 [IB_QPS_RTS] = { .valid = 1, 201 .opt_param = { 202 [IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), 203 [IB_QPT_UC] = (IB_QP_CUR_STATE | 204 IB_QP_ALT_PATH | 205 IB_QP_ACCESS_FLAGS | 206 IB_QP_PATH_MIG_STATE), 207 [IB_QPT_RC] = (IB_QP_CUR_STATE | 208 IB_QP_ALT_PATH | 209 IB_QP_ACCESS_FLAGS | 210 IB_QP_MIN_RNR_TIMER | 211 IB_QP_PATH_MIG_STATE), 212 [IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 213 [IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 214 } 215 }, 216 [IB_QPS_SQD] = { .valid = 1, 217 .opt_param = { 218 [IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 219 [IB_QPT_UC] = (IB_QP_AV | IB_QP_ALT_PATH | 220 IB_QP_ACCESS_FLAGS | 221 IB_QP_PKEY_INDEX | 222 IB_QP_PATH_MIG_STATE), 223 [IB_QPT_RC] = (IB_QP_PORT | IB_QP_AV | 224 IB_QP_TIMEOUT | 225 IB_QP_RETRY_CNT | 226 IB_QP_RNR_RETRY | 227 IB_QP_MAX_QP_RD_ATOMIC | 228 IB_QP_MAX_DEST_RD_ATOMIC | 229 IB_QP_ALT_PATH | 230 IB_QP_ACCESS_FLAGS | 231 IB_QP_PKEY_INDEX | 232 IB_QP_MIN_RNR_TIMER | 233 IB_QP_PATH_MIG_STATE), 234 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 235 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY), 236 } 237 } 238 }, 239 [IB_QPS_SQE] = { 240 [IB_QPS_RESET] = { .valid = 1 }, 241 [IB_QPS_ERR] = { .valid = 1 }, 242 [IB_QPS_RTS] = { .valid = 1, 243 .opt_param = { 244 [IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY), 245 [IB_QPT_UC] = (IB_QP_CUR_STATE | 246 IB_QP_ACCESS_FLAGS), 247 [IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 248 [IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY), 249 } 250 } 251 }, 252 [IB_QPS_ERR] = { 253 [IB_QPS_RESET] = { .valid = 1 }, 254 [IB_QPS_ERR] = { .valid = 1 } 255 } 256 }; 257 258 /* 259 * Function: 260 * uverbs_modify_qp_is_ok 261 * Input: 262 * cur_state - The current OFED QP state. 263 * next_state - The OFED QP state to transition to. 264 * type - The OFED QP transport type. 265 * mask - The OFED QP attribute mask for the QP transition. 266 * Output: 267 * None 268 * Returns: 269 * Returns 1 if the operation is valid; otherwise 0 for invalid 270 * operations. 271 * Description: 272 * Indicate whether the desired QP modify operation is a valid operation. 273 * To be valid, the state transition must be legal and the required and 274 * optional parameters must be valid for the transition and QP type. 275 */ 276 static int 277 uverbs_modify_qp_is_ok(enum ib_qp_state cur_state, 278 enum ib_qp_state next_state, enum ib_qp_type type, 279 enum ib_qp_attr_mask *maskp) 280 { 281 enum ib_qp_attr_mask req_param, opt_param; 282 uverbs_qp_state_tbl_t *state_tblp; 283 enum ib_qp_attr_mask mask = *maskp; 284 285 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp_is_ok" 286 "(%x, %x, %x, %x)", cur_state, next_state, type, mask); 287 288 if (cur_state < 0 || cur_state > IB_QPS_ERR || 289 next_state < 0 || next_state > IB_QPS_ERR) { 290 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 291 "modify_qp_is_ok: bad state, cur %d, next %d", 292 cur_state, next_state); 293 return (0); 294 } 295 296 if (mask & IB_QP_CUR_STATE && 297 cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS && 298 cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE) { 299 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 300 "modify_qp_is_ok: cur_state %d is a bad state", 301 cur_state); 302 return (0); 303 } 304 305 state_tblp = &uverbs_qp_state_table[cur_state][next_state]; 306 if (!state_tblp->valid) { 307 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp: " 308 "bad transition, cur = %d, next = %d", cur_state, 309 next_state); 310 return (0); 311 } 312 313 req_param = state_tblp->req_param[type]; 314 opt_param = state_tblp->opt_param[type]; 315 316 if ((mask & req_param) != req_param) { 317 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 318 "modify_qp_is_ok: cur %d, next %d, " 319 "missing required parms, spec = 0x%08X, " 320 "req = 0%08X", cur_state, next_state, 321 mask, req_param); 322 return (0); 323 } 324 325 if (mask & ~(req_param | opt_param | IB_QP_STATE)) { 326 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, 327 "modify_qp_is_ok: cur %d, next %d, " 328 "illegal optional parms, parms = 0x%08X, " 329 "illegal = 0x%08X", cur_state, next_state, 330 mask, mask & ~(req_param | opt_param | IB_QP_STATE)); 331 *maskp = mask & (req_param | opt_param | IB_QP_STATE); 332 return (0); 333 } 334 335 return (1); 336 } 337 338 339 /* 340 * Function: 341 * sol_uverbs_create_qp 342 * Input: 343 * uctxt - Pointer to the callers user context. 344 * buf - Pointer to kernel buffer containing the create command. 345 * in_len - Length in bytes of input command buffer. 346 * out_len - Length in bytes of output response buffer. 347 * Output: 348 * The command output buffer is updated with command results. 349 * Returns: 350 * DDI_SUCCESS on success, else error code. 351 * Description: 352 * User verbs entry point to create a new device QP. 353 */ 354 /* ARGSUSED */ 355 int 356 sol_uverbs_create_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 357 int in_len, int out_len) 358 { 359 struct ib_uverbs_create_qp cmd; 360 struct ib_uverbs_create_qp_resp resp; 361 uverbs_uqp_uobj_t *uqp; 362 ibt_qp_type_t qp_type; 363 ibt_qp_alloc_attr_t qp_attr; 364 ibt_chan_sizes_t qp_sizes; 365 int rc = 0; 366 uverbs_upd_uobj_t *upd; 367 uverbs_ucq_uobj_t *uscq; 368 uverbs_ucq_uobj_t *urcq; 369 uverbs_usrq_uobj_t *usrq = NULL; 370 371 (void) memcpy(&cmd, buf, sizeof (cmd)); 372 (void) memset(&resp, 0, sizeof (resp)); 373 (void) memset(&qp_attr, 0, sizeof (qp_attr)); 374 (void) memset(&qp_sizes, 0, sizeof (qp_sizes)); 375 376 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_qp(): entry"); 377 378 switch (cmd.qp_type) { 379 case IB_QPT_UC: 380 qp_type = IBT_UC_RQP; 381 break; 382 case IB_QPT_UD: 383 qp_type = IBT_UD_RQP; 384 break; 385 case IB_QPT_RC: 386 qp_type = IBT_RC_RQP; 387 break; 388 default: 389 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 390 "create_qp(): Invalid qp type"); 391 rc = EINVAL; 392 goto err_out; 393 } 394 395 qp_attr.qp_alloc_flags = IBT_QP_USER_MAP; 396 397 if (cmd.is_srq) { 398 qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ; 399 } 400 401 qp_attr.qp_flags = IBT_WR_SIGNALED; 402 if (cmd.sq_sig_all) { 403 qp_attr.qp_flags = IBT_ALL_SIGNALED; 404 } 405 406 uqp = kmem_zalloc(sizeof (*uqp), KM_NOSLEEP); 407 if (uqp == NULL) { 408 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 409 "create_qp(): User object allocation failed"); 410 rc = ENOMEM; 411 goto err_out; 412 } 413 sol_ofs_uobj_init(&uqp->uobj, cmd.user_handle, 414 SOL_UVERBS_UQP_UOBJ_TYPE); 415 rw_enter(&uqp->uobj.uo_lock, RW_WRITER); 416 llist_head_init(&uqp->mcast_list, NULL); 417 llist_head_init(&uqp->async_list, NULL); 418 419 uqp->async_events_reported = 0; 420 uqp->uctxt = uctxt; 421 uqp->disable_qp_mod = FALSE; 422 423 if (cmd.is_srq) { 424 usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle); 425 uqp->uqp_rcq_srq_valid |= SOL_UVERBS_UQP_SRQ_VALID; 426 uqp->uqp_srq_hdl = cmd.srq_handle; 427 } 428 upd = uverbs_uobj_get_upd_read(cmd.pd_handle); 429 uqp->uqp_pd_hdl = cmd.pd_handle; 430 uscq = uverbs_uobj_get_ucq_read(cmd.send_cq_handle); 431 uqp->uqp_scq_hdl = cmd.send_cq_handle; 432 uqp->uqp_rcq_hdl = cmd.recv_cq_handle; 433 if (cmd.recv_cq_handle != cmd.send_cq_handle) { 434 urcq = uverbs_uobj_get_ucq_read(cmd.recv_cq_handle); 435 uqp->uqp_rcq_srq_valid |= SOL_UVERBS_UQP_RCQ_VALID; 436 } else 437 urcq = uscq; 438 439 if (!upd || !uscq || !urcq || (cmd.is_srq && !usrq)) { 440 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 441 "create_qp(): Invalid resource handle"); 442 rc = EINVAL; 443 goto err_put; 444 } 445 uqp->uqp_rcq = urcq; 446 uqp->uqp_scq = uscq; 447 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 448 "uqp %p, rcq %p. scq %p", uqp, urcq, uscq); 449 450 qp_attr.qp_pd_hdl = upd->pd; 451 if (usrq) { 452 qp_attr.qp_srq_hdl = usrq->srq; 453 } 454 qp_attr.qp_scq_hdl = uscq->cq; 455 qp_attr.qp_rcq_hdl = urcq->cq; 456 qp_attr.qp_sizes.cs_sq = cmd.max_send_wr; 457 qp_attr.qp_sizes.cs_rq = cmd.max_recv_wr; 458 qp_attr.qp_sizes.cs_sq_sgl = cmd.max_send_sge; 459 qp_attr.qp_sizes.cs_rq_sgl = cmd.max_recv_sge; 460 461 uqp->max_inline_data = cmd.max_inline_data; 462 uqp->ofa_qp_type = cmd.qp_type; 463 464 /* 465 * NOTE: We allocate the QP and leave it in the RESET state to follow 466 * usage semantics consistent with OFA verbs. 467 */ 468 rc = ibt_alloc_qp(uctxt->hca->hdl, qp_type, &qp_attr, &qp_sizes, 469 &uqp->qp_num, &uqp->qp); 470 if (rc != IBT_SUCCESS) { 471 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 472 "create_qp(): Error in ibt_alloc_qp() (rc=%d)", rc); 473 rc = sol_uverbs_ibt_to_kernel_status(rc); 474 uqp->uobj.uo_uobj_sz = sizeof (uverbs_uqp_uobj_t); 475 goto err_put; 476 } 477 478 ibt_set_qp_private(uqp->qp, uqp); 479 480 /* Bump up the active_qp_cnt for CQ, SRQ & PD resources it is using */ 481 upd->active_qp_cnt++; 482 uscq->active_qp_cnt++; 483 if (cmd.recv_cq_handle != cmd.send_cq_handle) 484 urcq->active_qp_cnt++; 485 if (usrq) 486 usrq->active_qp_cnt++; 487 488 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 489 "\treq cs_sq=%d, actual cs_sq=%d", 490 qp_attr.qp_sizes.cs_sq, qp_sizes.cs_sq); 491 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 492 "\treq cs_sq_sgl=%d, actual cs_sg_sgl=%d", 493 qp_attr.qp_sizes.cs_sq_sgl, qp_sizes.cs_sq_sgl); 494 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 495 "\treq cs_rq=%d, actual cs_rq=%d", 496 qp_attr.qp_sizes.cs_rq, qp_sizes.cs_rq); 497 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 498 "\treq cs_rq_sgl=%d, actual cs_rq_sgl=%d", 499 qp_attr.qp_sizes.cs_rq_sgl, qp_sizes.cs_rq_sgl); 500 501 /* 502 * Query underlying hardware for data used in mapping QP work 503 * queues back to user space, we will return this information 504 * in the user verbs command response. 505 */ 506 rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_CHANNEL, 507 (void *)uqp->qp, &resp.drv_out, sizeof (resp.drv_out)); 508 if (rc != IBT_SUCCESS) { 509 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 510 "create_qp(): Error in ibt_ci_data_out() (rc=%d)", rc); 511 rc = EFAULT; 512 uqp->uobj.uo_uobj_sz = sizeof (uverbs_uqp_uobj_t); 513 goto err_qp_destroy; 514 } 515 516 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 517 "create_qp QP: ibt_ci_data_out:0x%016llx 0x%016llx", 518 resp.drv_out[0], resp.drv_out[1]); 519 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 520 " :0x%016llx 0x%016llx", 521 resp.drv_out[2], resp.drv_out[3]); 522 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 523 " :0x%016llx 0x%016llx", 524 resp.drv_out[4], resp.drv_out[5]); 525 526 if (sol_ofs_uobj_add(&uverbs_uqp_uo_tbl, &uqp->uobj) != 0) { 527 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 528 "create_qp(): User object add failed (rc=%d)", rc); 529 rc = ENOMEM; 530 goto err_qp_destroy; 531 } 532 533 resp.qp_handle = uqp->uobj.uo_id; 534 resp.qpn = uqp->qp_num; 535 resp.max_send_wr = qp_sizes.cs_sq; 536 resp.max_send_sge = qp_sizes.cs_sq_sgl; 537 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_qp() : " 538 "resp.qp_handle=0x%08x, resp.qpn=0x%08x", resp.qp_handle, resp.qpn); 539 540 /* 541 * In Solaris the receive work requests and sg entries are cleared 542 * when a SRQ is used since these values are ignored. To maintain 543 * consistency with OFED we return the requested values as is done 544 * in OFED, but these values will be ignored and SRQ valuves are 545 * used. MTHCA lib will extract the zeroed out value from the 546 * driver out data. 547 */ 548 if (usrq) { 549 resp.max_recv_wr = cmd.max_recv_wr; 550 resp.max_recv_sge = cmd.max_recv_sge; 551 } else { 552 resp.max_recv_wr = qp_sizes.cs_rq; 553 resp.max_recv_sge = qp_sizes.cs_rq_sgl; 554 } 555 resp.max_inline_data = cmd.max_inline_data; 556 557 #ifdef _LP64 558 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 559 #else 560 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 561 #endif 562 if (rc != 0) { 563 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 564 "create_qp(): Error writing resp data (rc=%d)", rc); 565 rc = EFAULT; 566 goto err_uo_delete; 567 } 568 569 mutex_enter(&uctxt->lock); 570 uqp->list_entry = add_genlist(&uctxt->qp_list, (uintptr_t)uqp, 571 (void*)uctxt); 572 mutex_exit(&uctxt->lock); 573 574 if (!uqp->list_entry) { 575 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 576 "create_qp(): Error adding uqp to qp_list\n"); 577 rc = ENOMEM; 578 goto err_uo_delete; 579 } 580 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 581 "create_qp() - uqp %p", uqp); 582 583 uqp->uobj.uo_live = 1; 584 585 sol_ofs_uobj_put(&upd->uobj); 586 sol_ofs_uobj_put(&uscq->uobj); 587 588 if (urcq != uscq) { 589 sol_ofs_uobj_put(&urcq->uobj); 590 } 591 if (usrq) { 592 sol_ofs_uobj_put(&usrq->uobj); 593 } 594 rw_exit(&uqp->uobj.uo_lock); 595 596 return (DDI_SUCCESS); 597 598 err_uo_delete: 599 /* 600 * Need to set uo_live, so sol_ofs_uobj_remove() will 601 * remove the object from the object table. 602 */ 603 uqp->uobj.uo_live = 1; 604 (void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj); 605 606 err_qp_destroy: 607 (void) ibt_free_qp(uqp->qp); 608 609 upd->active_qp_cnt--; 610 uscq->active_qp_cnt--; 611 if (cmd.recv_cq_handle != cmd.send_cq_handle) 612 urcq->active_qp_cnt--; 613 if (usrq) 614 usrq->active_qp_cnt--; 615 616 err_put: 617 if (upd) { 618 sol_ofs_uobj_put(&upd->uobj); 619 } 620 if (uscq) { 621 sol_ofs_uobj_put(&uscq->uobj); 622 } 623 if (urcq && urcq != uscq) { 624 sol_ofs_uobj_put(&urcq->uobj); 625 } 626 if (usrq) { 627 sol_ofs_uobj_put(&usrq->uobj); 628 } 629 630 rw_exit(&uqp->uobj.uo_lock); 631 sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free); 632 633 err_out: 634 return (rc); 635 } 636 637 /* 638 * Free the resources used by uqp. Return 0, if the free of all 639 * resources where succesful, return non-zero, if not. 640 * 641 * If other uQPs are holding the resources (PD, CQ, SRQ), do not 642 * free the resource, but return 0, so the free of uqp can be 643 * done. Return failure only if active_cnt cannot be decremented 644 * resource_free() fails. 645 */ 646 static int 647 uverbs_uqp_rsrc_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt) 648 { 649 uverbs_ucq_uobj_t *uscq = NULL, *urcq = NULL; 650 uverbs_usrq_uobj_t *usrq = NULL; 651 uverbs_upd_uobj_t *upd = NULL; 652 int ret, rc = -1; 653 654 /* Get uobj for PD, CQ & SRQ resources used. */ 655 upd = uverbs_uobj_get_upd_write(uqp->uqp_pd_hdl); 656 if (upd == NULL) { 657 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 658 "uqp_rsrc_free: get_upd %d failed", uqp->uqp_pd_hdl); 659 goto err_free; 660 } 661 uscq = uverbs_uobj_get_ucq_write(uqp->uqp_scq_hdl); 662 if (uscq == NULL) { 663 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 664 "uqp_rsrc_free: get_ucq %x failed", uqp->uqp_scq_hdl); 665 goto err_free; 666 } 667 if (uqp->uqp_rcq_srq_valid & SOL_UVERBS_UQP_RCQ_VALID) { 668 urcq = uverbs_uobj_get_ucq_write(uqp->uqp_rcq_hdl); 669 if (urcq == NULL) { 670 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 671 "uqp_rsrc_free: get_ucq %x failed", 672 uqp->uqp_rcq_hdl); 673 goto err_free; 674 } 675 } 676 if (uqp->uqp_rcq_srq_valid & SOL_UVERBS_UQP_SRQ_VALID) { 677 usrq = uverbs_uobj_get_usrq_write(uqp->uqp_srq_hdl); 678 if (usrq == NULL) { 679 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 680 "uqp_rsrc_free: get_srq %x failed", 681 uqp->uqp_srq_hdl); 682 goto err_free; 683 } 684 } 685 rc = 0; 686 687 /* Decrement active_qp_cnt for resources used */ 688 upd->active_qp_cnt--; 689 uscq->active_qp_cnt--; 690 if (urcq) 691 urcq->active_qp_cnt--; 692 if (usrq) 693 usrq->active_qp_cnt--; 694 695 /* 696 * Free the resources, if active_qp_cnt is 0 and userland free 697 * already been pending for the resource. 698 */ 699 if (upd->active_qp_cnt == 0 && upd->free_pending) { 700 ret = uverbs_upd_free(upd, uctxt); 701 if (ret && rc == 0) { 702 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 703 "uqp_rsrc_free: upd_free failed"); 704 rc = ret; 705 } 706 } else if (upd) 707 sol_ofs_uobj_put(&upd->uobj); 708 if (uscq && uscq->active_qp_cnt == 0 && uscq->free_pending) { 709 ret = uverbs_ucq_free(uscq, uctxt); 710 if (ret && rc == 0) { 711 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 712 "uqp_rsrc_free: ucq_free failed"); 713 rc = ret; 714 } 715 } else if (uscq) 716 sol_ofs_uobj_put(&uscq->uobj); 717 if (urcq && urcq->active_qp_cnt == 0 && urcq->free_pending) { 718 rc = uverbs_ucq_free(urcq, uctxt); 719 if (ret && rc == 0) { 720 if (rc) 721 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 722 "uqp_rsrc_free: ucq_free failed"); 723 rc = ret; 724 } 725 } else if (urcq) 726 sol_ofs_uobj_put(&urcq->uobj); 727 if (usrq && usrq->active_qp_cnt == 0 && usrq->free_pending) { 728 rc = uverbs_usrq_free(usrq, uctxt); 729 if (ret && rc == 0) { 730 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 731 "uqp_rsrc_free: usrq_free failed"); 732 rc = ret; 733 } 734 } else if (usrq) 735 sol_ofs_uobj_put(&usrq->uobj); 736 return (rc); 737 738 err_free: 739 if (upd) 740 sol_ofs_uobj_put(&upd->uobj); 741 if (uscq) 742 sol_ofs_uobj_put(&uscq->uobj); 743 if (urcq) 744 sol_ofs_uobj_put(&urcq->uobj); 745 if (usrq) 746 sol_ofs_uobj_put(&usrq->uobj); 747 748 return (rc); 749 } 750 751 /* 752 * Free the resources held by the uqp. 753 * Call ibt_free_qp() to free the IBTF QP. 754 * Free uqp. 755 */ 756 int 757 uverbs_uqp_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt) 758 { 759 int rc; 760 ibt_status_t status; 761 762 /* Detach Mcast entries, if any. */ 763 uverbs_detach_uqp_mcast_entries(uqp); 764 765 if (!uqp->qp) 766 goto skip_ibt_free_qp; 767 768 status = ibt_free_qp(uqp->qp); 769 if (status != IBT_SUCCESS) { 770 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 771 "uqp_free: ibt_free_qp failed %d", status); 772 sol_ofs_uobj_put(&uqp->uobj); 773 return (status); 774 } 775 uqp->qp = NULL; 776 777 skip_ibt_free_qp : 778 rc = uverbs_uqp_rsrc_free(uqp, uctxt); 779 if (rc) { 780 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 781 "uqp_free: uqp_rcrc_free failed %d", rc); 782 sol_ofs_uobj_put(&uqp->uobj); 783 return (rc); 784 } 785 786 (void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj); 787 sol_ofs_uobj_put(&uqp->uobj); 788 789 if (uqp->list_entry) { 790 mutex_enter(&uctxt->lock); 791 delete_genlist(&uctxt->qp_list, uqp->list_entry); 792 uqp->list_entry = NULL; 793 mutex_exit(&uctxt->lock); 794 } 795 796 sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free); 797 798 if (uctxt->uctxt_free_pending && (uctxt->qp_list).count == 0) { 799 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, 800 "uqp_free: freeing uctxt %p", uctxt); 801 sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free); 802 } 803 return (0); 804 } 805 806 /* 807 * Function: 808 * sol_uverbs_destroy_qp 809 * Input: 810 * uctxt - Pointer to the callers user context. 811 * buf - Pointer to kernel buffer containing the destroy command. 812 * in_len - Length in bytes of input command buffer. 813 * out_len - Length in bytes of output response buffer. 814 * Output: 815 * The command output buffer is updated with command results. 816 * Returns: 817 * DDI_SUCCESS on success, else error code. 818 * Description: 819 * User verbs entry point to destroy a device QP. 820 */ 821 /* ARGSUSED */ 822 int 823 sol_uverbs_destroy_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 824 int in_len, int out_len) 825 { 826 struct ib_uverbs_destroy_qp cmd; 827 struct ib_uverbs_destroy_qp_resp resp; 828 uverbs_uqp_uobj_t *uqp; 829 int rc; 830 int uobj_put_req = 1; 831 832 (void) memcpy(&cmd, buf, sizeof (cmd)); 833 (void) memset(&resp, 0, sizeof (resp)); 834 835 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: entry " 836 "(qp_handle=%d)", cmd.qp_handle); 837 838 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 839 if (uqp == NULL) { 840 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 841 "destroy_qp() : List lookup failure"); 842 rc = EINVAL; 843 goto err_out; 844 } 845 846 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: qp_handle=%d, " 847 "uqp %p, qp_ptr %p", cmd.qp_handle, uqp, uqp->qp); 848 849 if (!llist_empty(&uqp->mcast_list)) { 850 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 851 "destroy_qp() called with attached MC group(s)"); 852 rc = EBUSY; 853 goto err_busy; 854 } 855 856 uverbs_release_uqp_uevents(uctxt->async_evfile, uqp); 857 resp.events_reported = uqp->async_events_reported; 858 859 /* 860 * If ucma has disabled QP free for this QP, set FREE_PENDING 861 * flag so that the QP can be freed when UCMA enables QP_FREE. 862 * Call ibt_free_qp() is ucma has not disabled QP free. 863 */ 864 if (uqp->uqp_free_state == SOL_UVERBS2UCMA_DISABLE_QP_FREE) { 865 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 866 "destroy_qp() - UCMA disabled"); 867 uqp->uqp_free_state = SOL_UVERBS2UCMA_FREE_PENDING; 868 sol_ofs_uobj_put(&uqp->uobj); 869 rc = 0; 870 goto report_qp_evts; 871 } else { 872 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 873 "destroy_qp() - freeing QP : %p", uqp); 874 rc = uverbs_uqp_free(uqp, uctxt); 875 uobj_put_req = 0; 876 } 877 878 if (rc) { 879 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 880 "destroy_qp() - ibt_free_qp() fail %d", rc); 881 rc = sol_uverbs_ibt_to_kernel_status(rc); 882 if (uobj_put_req) 883 goto err_busy; 884 else 885 goto err_out; 886 } 887 888 report_qp_evts: 889 #ifdef _LP64 890 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 891 #else 892 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 893 #endif 894 if (rc != 0) { 895 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 896 "destroy_qp() : copyout failure %x", rc); 897 rc = EFAULT; 898 goto err_out; 899 } 900 901 return (DDI_SUCCESS); 902 903 err_busy: 904 sol_ofs_uobj_put(&uqp->uobj); 905 906 err_out: 907 return (rc); 908 } 909 910 /* 911 * Function: 912 * uverbs_copy_path_info_from_ibv 913 * Input: 914 * src_path - IB OFED path. 915 * Output: 916 * dest_path - IBT path. 917 * Returns: 918 * None 919 * Description: 920 * Helper to copy from the OFED path format to IBT path format. 921 */ 922 static void 923 uverbs_copy_path_info_from_ibv(struct ib_uverbs_qp_dest *src_path, 924 ibt_cep_path_t *dest_path) 925 { 926 ASSERT(src_path != NULL); 927 ASSERT(dest_path != NULL); 928 929 (void) memcpy(&dest_path->cep_adds_vect.av_dgid, 930 &src_path->dgid[0], sizeof (src_path->dgid)); 931 932 dest_path->cep_adds_vect.av_flow = src_path->flow_label; 933 dest_path->cep_adds_vect.av_dlid = src_path->dlid; 934 dest_path->cep_adds_vect.av_hop = src_path->hop_limit; 935 dest_path->cep_adds_vect.av_tclass = src_path->traffic_class; 936 dest_path->cep_adds_vect.av_srvl = src_path->sl & 0x0f; 937 dest_path->cep_adds_vect.av_port_num = src_path->port_num; 938 dest_path->cep_adds_vect.av_src_path = src_path->src_path_bits; 939 dest_path->cep_adds_vect.av_send_grh = src_path->is_global; 940 dest_path->cep_adds_vect.av_sgid_ix = src_path->sgid_index; 941 dest_path->cep_adds_vect.av_srate = src_path->static_rate; 942 } 943 944 /* 945 * Function: 946 * uverbs_modify_update 947 * Input: 948 * cmd - The user verbs modify command to be translated. 949 * cur_state - The current QP state 950 * new_state - The new QP state 951 * Output: 952 * qp_query_attr - The IBT QP attributes. 953 * flags - The IBT flags. 954 * Returns: 955 * None 956 * Description: 957 * Helper to convert OFED user verbs QP modify attributes to IBT 958 * QP modify attributes. Note that on required parameters, the 959 * individual IBT modify flags are not set (there is a global 960 * flag for the transition), only optional flags are set. 961 */ 962 static void 963 uverbs_modify_update(struct ib_uverbs_modify_qp *cmd, 964 enum ib_qp_state cur_state, enum ib_qp_state new_state, 965 ibt_qp_query_attr_t *qp_query_attr, ibt_cep_modify_flags_t *flags) 966 { 967 ibt_qp_info_t *qp_infop; 968 ibt_qp_rc_attr_t *rcp; 969 ibt_qp_uc_attr_t *ucp; 970 ibt_qp_ud_attr_t *udp; 971 972 *flags = IBT_CEP_SET_NOTHING; 973 qp_infop = &(qp_query_attr->qp_info); 974 rcp = &(qp_infop->qp_transport.rc); 975 ucp = &(qp_infop->qp_transport.uc); 976 udp = &(qp_infop->qp_transport.ud); 977 978 switch (cur_state) { 979 case IB_QPS_RESET: 980 qp_infop->qp_current_state = IBT_STATE_RESET; 981 break; 982 case IB_QPS_INIT: 983 qp_infop->qp_current_state = IBT_STATE_INIT; 984 break; 985 case IB_QPS_RTR: 986 qp_infop->qp_current_state = IBT_STATE_RTR; 987 break; 988 case IB_QPS_RTS: 989 qp_infop->qp_current_state = IBT_STATE_RTS; 990 break; 991 case IB_QPS_SQD: 992 qp_infop->qp_current_state = IBT_STATE_SQD; 993 break; 994 case IB_QPS_SQE: 995 qp_infop->qp_current_state = IBT_STATE_SQE; 996 break; 997 case IB_QPS_ERR: 998 qp_infop->qp_current_state = IBT_STATE_ERROR; 999 break; 1000 } 1001 1002 if (cmd->attr_mask & IB_QP_STATE) { 1003 switch (new_state) { 1004 case IB_QPS_RESET: 1005 qp_infop->qp_state = IBT_STATE_RESET; 1006 *flags |= IBT_CEP_SET_STATE; 1007 break; 1008 1009 case IB_QPS_INIT: 1010 qp_infop->qp_state = IBT_STATE_INIT; 1011 if (cur_state == IB_QPS_RESET) { 1012 *flags |= IBT_CEP_SET_RESET_INIT; 1013 } else { 1014 *flags |= IBT_CEP_SET_STATE; 1015 } 1016 break; 1017 1018 case IB_QPS_RTR: 1019 qp_infop->qp_state = IBT_STATE_RTR; 1020 if (cur_state == IB_QPS_INIT) { 1021 *flags |= IBT_CEP_SET_INIT_RTR; 1022 } else { 1023 *flags |= IBT_CEP_SET_STATE; 1024 } 1025 break; 1026 1027 case IB_QPS_RTS: 1028 qp_infop->qp_state = IBT_STATE_RTS; 1029 1030 /* 1031 * For RTS transitions other than RTR we must 1032 * specify the assumption for the qp state. 1033 */ 1034 if (cur_state == IB_QPS_RTR) { 1035 *flags |= IBT_CEP_SET_RTR_RTS; 1036 } else { 1037 ibt_cep_state_t *ibt_curr = 1038 &qp_infop->qp_current_state; 1039 1040 switch (cur_state) { 1041 case IB_QPS_RTR: 1042 *ibt_curr = IBT_STATE_RTR; 1043 break; 1044 1045 case IB_QPS_RTS: 1046 *ibt_curr = IBT_STATE_RTS; 1047 break; 1048 1049 case IB_QPS_SQD: 1050 *ibt_curr = IBT_STATE_SQD; 1051 break; 1052 1053 case IB_QPS_SQE: 1054 *ibt_curr = IBT_STATE_SQE; 1055 break; 1056 } 1057 *flags |= IBT_CEP_SET_STATE; 1058 } 1059 break; 1060 1061 case IB_QPS_SQD: 1062 qp_infop->qp_state = IBT_STATE_SQD; 1063 *flags |= IBT_CEP_SET_STATE; 1064 break; 1065 1066 case IB_QPS_SQE: 1067 qp_infop->qp_state = IBT_STATE_SQE; 1068 *flags |= IBT_CEP_SET_STATE; 1069 break; 1070 1071 case IB_QPS_ERR: 1072 qp_infop->qp_state = IBT_STATE_ERROR; 1073 *flags |= IBT_CEP_SET_STATE; 1074 break; 1075 } 1076 } 1077 1078 if (cmd->attr_mask & IB_QP_PKEY_INDEX) { 1079 if (qp_infop->qp_trans == IBT_UD_SRV) { 1080 udp->ud_pkey_ix = cmd->pkey_index; 1081 } else if (qp_infop->qp_trans == IBT_RC_SRV) { 1082 rcp->rc_path.cep_pkey_ix = cmd->pkey_index; 1083 } 1084 *flags |= IBT_CEP_SET_PKEY_IX; 1085 } 1086 1087 1088 if (cmd->attr_mask & IB_QP_AV) { 1089 if (qp_infop->qp_trans == IBT_RC_SRV) { 1090 uverbs_copy_path_info_from_ibv(&cmd->dest, 1091 &rcp->rc_path); 1092 } 1093 *flags |= IBT_CEP_SET_ADDS_VECT; 1094 } 1095 1096 if (qp_infop->qp_trans == IBT_RC_SRV) { 1097 if (cmd->attr_mask & IB_QP_TIMEOUT) { 1098 rcp->rc_path.cep_timeout = cmd->timeout; 1099 *flags |= IBT_CEP_SET_TIMEOUT; 1100 } 1101 } 1102 1103 if (cmd->attr_mask & IB_QP_PORT) { 1104 if (qp_infop->qp_trans == IBT_UD_SRV) { 1105 udp->ud_port = cmd->port_num; 1106 } else if (qp_infop->qp_trans == IBT_RC_SRV) { 1107 rcp->rc_path.cep_hca_port_num = cmd->port_num; 1108 } 1109 *flags |= IBT_CEP_SET_PORT; 1110 } 1111 1112 if (cmd->attr_mask & IB_QP_QKEY) { 1113 if (qp_infop->qp_trans == IBT_UD_SRV) { 1114 udp->ud_qkey = cmd->qkey; 1115 } 1116 if (qp_infop->qp_trans == IBT_RD_SRV) { 1117 qp_infop->qp_transport.rd.rd_qkey = cmd->qkey; 1118 } 1119 *flags |= IBT_CEP_SET_QKEY; 1120 } 1121 1122 if (cmd->attr_mask & IB_QP_PATH_MTU) { 1123 if (qp_infop->qp_trans == IBT_UC_SRV) { 1124 ucp->uc_path_mtu = cmd->path_mtu; 1125 } 1126 if (qp_infop->qp_trans == IBT_RC_SRV) { 1127 rcp->rc_path_mtu = cmd->path_mtu; 1128 } 1129 } 1130 1131 if (cmd->attr_mask & IB_QP_RETRY_CNT) { 1132 if (qp_infop->qp_trans == IBT_RC_SRV) { 1133 rcp->rc_retry_cnt = cmd->retry_cnt & 0x7; 1134 } 1135 *flags |= IBT_CEP_SET_RETRY; 1136 } 1137 1138 if (cmd->attr_mask & IB_QP_RNR_RETRY) { 1139 if (qp_infop->qp_trans == IBT_RC_SRV) { 1140 rcp->rc_rnr_retry_cnt = cmd->rnr_retry; 1141 } 1142 *flags |= IBT_CEP_SET_RNR_NAK_RETRY; 1143 } 1144 1145 if (cmd->attr_mask & IB_QP_MIN_RNR_TIMER) { 1146 if (qp_infop->qp_trans == IBT_RC_SRV) { 1147 rcp->rc_min_rnr_nak = cmd->min_rnr_timer; 1148 } 1149 *flags |= IBT_CEP_SET_MIN_RNR_NAK; 1150 } 1151 1152 if (cmd->attr_mask & IB_QP_RQ_PSN) { 1153 if (qp_infop->qp_trans == IBT_RC_SRV) { 1154 rcp->rc_rq_psn = cmd->rq_psn; 1155 } 1156 if (qp_infop->qp_trans == IBT_UC_SRV) { 1157 ucp->uc_rq_psn = cmd->rq_psn; 1158 } 1159 } 1160 1161 if (cmd->attr_mask & IB_QP_ALT_PATH) { 1162 if (qp_infop->qp_trans == IBT_RC_SRV) { 1163 uverbs_copy_path_info_from_ibv(&cmd->alt_dest, 1164 &rcp->rc_alt_path); 1165 1166 rcp->rc_alt_path.cep_hca_port_num = cmd->alt_port_num; 1167 rcp->rc_alt_path.cep_timeout = cmd->alt_timeout; 1168 } 1169 1170 if (qp_infop->qp_trans == IBT_UC_SRV) { 1171 uverbs_copy_path_info_from_ibv(&cmd->alt_dest, 1172 &ucp->uc_alt_path); 1173 1174 ucp->uc_alt_path.cep_hca_port_num = cmd->alt_port_num; 1175 ucp->uc_alt_path.cep_timeout = cmd->alt_timeout; 1176 } 1177 1178 *flags |= IBT_CEP_SET_ALT_PATH; 1179 } 1180 1181 1182 if (cmd->attr_mask & IB_QP_SQ_PSN) { 1183 if (qp_infop->qp_trans == IBT_UD_SRV) { 1184 udp->ud_sq_psn = cmd->sq_psn; 1185 } 1186 if (qp_infop->qp_trans == IBT_UC_SRV) { 1187 ucp->uc_sq_psn = cmd->sq_psn; 1188 } 1189 if (qp_infop->qp_trans == IBT_RC_SRV) { 1190 rcp->rc_sq_psn = cmd->sq_psn; 1191 } 1192 } 1193 1194 if (cmd->attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { 1195 if (qp_infop->qp_trans == IBT_RC_SRV) { 1196 rcp->rc_rdma_ra_out = cmd->max_rd_atomic; 1197 } 1198 *flags |= IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_STATE; 1199 } 1200 1201 if (cmd->attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { 1202 if (qp_infop->qp_trans == IBT_RC_SRV) { 1203 rcp->rc_rdma_ra_in = cmd->max_dest_rd_atomic; 1204 } 1205 *flags |= IBT_CEP_SET_RDMARA_IN | IBT_CEP_SET_STATE; 1206 } 1207 1208 if (cmd->attr_mask & (IB_QP_ACCESS_FLAGS | 1209 IB_QP_MAX_DEST_RD_ATOMIC)) { 1210 if (qp_infop->qp_trans == IBT_RC_SRV) { 1211 uint32_t access_flags = IBT_CEP_NO_FLAGS; 1212 1213 if (rcp->rc_rdma_ra_in) { 1214 access_flags |= IBT_CEP_RDMA_WR; 1215 *flags |= IBT_CEP_SET_RDMA_W; 1216 } 1217 1218 if (cmd->attr_mask & IB_QP_ACCESS_FLAGS) { 1219 if (cmd->qp_access_flags & 1220 IB_ACCESS_REMOTE_WRITE) { 1221 access_flags |= IBT_CEP_RDMA_WR; 1222 *flags |= IBT_CEP_SET_RDMA_W; 1223 } 1224 if (cmd->qp_access_flags & 1225 IB_ACCESS_REMOTE_READ) { 1226 access_flags |= IBT_CEP_RDMA_RD; 1227 *flags |= IBT_CEP_SET_RDMA_R; 1228 } 1229 if (cmd->qp_access_flags & 1230 IB_ACCESS_REMOTE_ATOMIC) { 1231 access_flags |= IBT_CEP_ATOMIC; 1232 *flags |= IBT_CEP_SET_ATOMIC; 1233 } 1234 } 1235 qp_infop->qp_flags &= ~(IBT_CEP_RDMA_WR | 1236 IBT_CEP_RDMA_RD | IBT_CEP_ATOMIC); 1237 qp_infop->qp_flags |= access_flags; 1238 } 1239 } 1240 1241 if (cmd->attr_mask & IB_QP_PATH_MIG_STATE) { 1242 if (qp_infop->qp_trans == IBT_RC_SRV) { 1243 if (cmd->path_mig_state == IB_MIG_MIGRATED) { 1244 rcp->rc_mig_state = IBT_STATE_MIGRATED; 1245 } 1246 if (cmd->path_mig_state == IB_MIG_REARM) { 1247 rcp->rc_mig_state = IBT_STATE_REARMED; 1248 } 1249 if (cmd->path_mig_state == IB_MIG_ARMED) { 1250 rcp->rc_mig_state = IBT_STATE_ARMED; 1251 } 1252 } 1253 1254 if (qp_infop->qp_trans == IBT_UC_SRV) { 1255 if (cmd->path_mig_state == IB_MIG_MIGRATED) { 1256 ucp->uc_mig_state = IBT_STATE_MIGRATED; 1257 } 1258 if (cmd->path_mig_state == IB_MIG_REARM) { 1259 ucp->uc_mig_state = IBT_STATE_REARMED; 1260 } 1261 if (cmd->path_mig_state == IB_MIG_ARMED) { 1262 ucp->uc_mig_state = IBT_STATE_ARMED; 1263 } 1264 } 1265 *flags |= IBT_CEP_SET_MIG; 1266 } 1267 1268 if (cmd->attr_mask & IB_QP_DEST_QPN) { 1269 if (qp_infop->qp_trans == IBT_RC_SRV) { 1270 rcp->rc_dst_qpn = cmd->dest_qp_num; 1271 } 1272 if (qp_infop->qp_trans == IBT_UC_SRV) { 1273 ucp->uc_dst_qpn = cmd->dest_qp_num; 1274 } 1275 } 1276 } 1277 1278 1279 static void 1280 uverbs_qp_print_path(ibt_cep_path_t *pathp) 1281 { 1282 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print_pathp %p", pathp); 1283 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "cep_pkey_ix %x, " 1284 "cep_hca_port_num %x", pathp->cep_pkey_ix, pathp->cep_hca_port_num); 1285 } 1286 1287 static void 1288 uverbs_print_query_qp(ibt_qp_hdl_t qp_hdlp) 1289 { 1290 ibt_qp_query_attr_t qp_query_attr; 1291 ibt_qp_info_t *qp_infop = &qp_query_attr.qp_info; 1292 ibt_qp_rc_attr_t *rcp = &((qp_infop->qp_transport).rc); 1293 ibt_status_t rc; 1294 1295 bzero(&qp_query_attr, sizeof (qp_query_attr)); 1296 rc = ibt_query_qp(qp_hdlp, &qp_query_attr); 1297 if (rc != IBT_SUCCESS) { 1298 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "print_query_qp -" 1299 "ibt_query_qp() failed - rc=%d", rc); 1300 return; 1301 } 1302 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print %p", qp_hdlp); 1303 1304 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_cq %p, qp_rq_cq %p, " 1305 "qp_qpn %x, qp_sq_sgl %x, qp_rq_sgl %x, qp_srq %p, qp_flags %x", 1306 qp_query_attr.qp_sq_cq, qp_query_attr.qp_rq_cq, 1307 qp_query_attr.qp_qpn, qp_query_attr.qp_sq_sgl, 1308 qp_query_attr.qp_rq_sgl, qp_query_attr.qp_srq, 1309 qp_query_attr.qp_flags); 1310 1311 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_sz %x, qp_rq_sz %x, " 1312 "qp_state %x, qp_current_state %x, qp_flags %x, qp_trans %x", 1313 qp_infop->qp_sq_sz, qp_infop->qp_rq_sz, qp_infop->qp_state, 1314 qp_infop->qp_current_state, qp_infop->qp_flags, 1315 qp_infop->qp_trans); 1316 1317 if (qp_infop->qp_trans == IBT_RC_SRV) { 1318 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "rc_sq_psn %x, rc_rq_psn %x, " 1319 "rc_dst_qpn %x, rc_mig_state %x, rc_rnr_retry_cnt %x," 1320 "rc_retry_cnt %x rc_rdma_ra_out %x, rc_rdma_ra_in %x," 1321 "rc_min_rnr_nak %x, rc_path_mtu %x", 1322 rcp->rc_sq_psn, rcp->rc_rq_psn, rcp->rc_dst_qpn, rcp->rc_mig_state, 1323 rcp->rc_rnr_retry_cnt, rcp->rc_retry_cnt, rcp->rc_rdma_ra_out, 1324 rcp->rc_rdma_ra_in, rcp->rc_min_rnr_nak, rcp->rc_path_mtu); 1325 uverbs_qp_print_path(&rcp->rc_path); 1326 uverbs_qp_print_path(&rcp->rc_alt_path); 1327 } 1328 } 1329 1330 1331 /* 1332 * Function: 1333 * sol_uverbs_modify_qp 1334 * Input: 1335 * uctxt - Pointer to the callers user context. 1336 * buf - Pointer to kernel buffer containing QP modify command. 1337 * in_len - Length in bytes of input command buffer. 1338 * out_len - Length in bytes of output response buffer. 1339 * Output: 1340 * The command output buffer is updated with command results. 1341 * Returns: 1342 * DDI_SUCCESS on success, else error code. 1343 * Description: 1344 * User verbs entry point to modify a device QP. 1345 */ 1346 /* ARGSUSED */ 1347 int 1348 sol_uverbs_modify_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 1349 int in_len, int out_len) 1350 { 1351 struct ib_uverbs_modify_qp cmd; 1352 uverbs_uqp_uobj_t *uqp; 1353 ibt_qp_query_attr_t qp_query_attr; 1354 ibt_cep_modify_flags_t flags; 1355 ibt_queue_sizes_t size; 1356 int rc; 1357 enum ib_qp_state cur_state, new_state; 1358 1359 (void) memcpy(&cmd, buf, sizeof (cmd)); 1360 1361 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp - qp_hdl %d, " 1362 "attr_mask %x", cmd.qp_handle, cmd.attr_mask); 1363 1364 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 1365 if (uqp == NULL) { 1366 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -" 1367 "List lookup failure"); 1368 rc = EINVAL; 1369 goto err_out; 1370 } 1371 1372 /* 1373 * Has the UCMA asked us to ignore QP modify operations? 1374 * This is required because of differences in the level of 1375 * abstraction fo CM processing between IBT and OFED. 1376 */ 1377 if (uqp->disable_qp_mod == TRUE) { 1378 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp -" 1379 "qp_mod disabled"); 1380 goto done; 1381 } 1382 1383 /* 1384 * Load the current QP attributes and then do a validation 1385 * based on OFA verbs expectations to see if the modify 1386 * should be performed. 1387 */ 1388 bzero(&qp_query_attr, sizeof (qp_query_attr)); 1389 rc = ibt_query_qp(uqp->qp, &qp_query_attr); 1390 if (rc != IBT_SUCCESS) { 1391 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -" 1392 "ibt_query_qp() failed - rc=%d", rc); 1393 rc = sol_uverbs_ibt_to_kernel_status(rc); 1394 goto err_deref; 1395 } 1396 1397 if (cmd.attr_mask & IB_QP_CUR_STATE) { 1398 cur_state = cmd.cur_qp_state; 1399 } else { 1400 cur_state = IBT_TO_OFA_QP_STATE(qp_query_attr.qp_info.qp_state); 1401 } 1402 1403 new_state = cmd.attr_mask & IB_QP_STATE ? cmd.qp_state : cur_state; 1404 1405 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp: ibt qp %p, handle " 1406 "%x, cur_state %x, new_state %x, qp_type %x, attr_mask %x", uqp->qp, 1407 cmd.qp_handle, cur_state, new_state, uqp->ofa_qp_type, 1408 cmd.attr_mask); 1409 1410 if (!uverbs_modify_qp_is_ok(cur_state, new_state, uqp->ofa_qp_type, 1411 (enum ib_qp_attr_mask *)&cmd.attr_mask)) { 1412 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp() -" 1413 "Failed modify OK test"); 1414 rc = EINVAL; 1415 goto err_deref; 1416 } 1417 1418 if (!cmd.attr_mask) { 1419 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp() -" 1420 "attr_mask after modify OK test is 0"); 1421 rc = 0; 1422 goto done; 1423 } 1424 1425 flags = 0; 1426 1427 switch (uqp->ofa_qp_type) { 1428 case IB_QPT_UC: 1429 qp_query_attr.qp_info.qp_trans = IBT_UC_SRV; 1430 break; 1431 case IB_QPT_UD: 1432 qp_query_attr.qp_info.qp_trans = IBT_UD_SRV; 1433 break; 1434 case IB_QPT_RC: 1435 qp_query_attr.qp_info.qp_trans = IBT_RC_SRV; 1436 break; 1437 default: 1438 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1439 "modify_qp: Invalid QP type"); 1440 rc = EINVAL; 1441 goto err_deref; 1442 } 1443 1444 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): qp_info.qp_flags " 1445 "before modify update = 0%08x", qp_query_attr.qp_info.qp_flags); 1446 1447 uverbs_modify_update(&cmd, cur_state, new_state, &qp_query_attr, 1448 &flags); 1449 1450 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): after " 1451 "modify_update hdl flags = 0x%08x, qp_info.qp_flags = 0%08x", 1452 flags, qp_query_attr.qp_info.qp_flags); 1453 1454 rc = ibt_modify_qp(uqp->qp, flags, &qp_query_attr.qp_info, &size); 1455 1456 if (rc != IBT_SUCCESS) { 1457 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1458 "modify_qp: Error in ibt_modify_qp() (rc=%d)", rc); 1459 uverbs_print_query_qp(uqp->qp); 1460 rc = sol_uverbs_ibt_to_kernel_status(rc); 1461 goto err_deref; 1462 } 1463 1464 done: 1465 sol_ofs_uobj_put(&uqp->uobj); 1466 return (DDI_SUCCESS); 1467 1468 err_deref: 1469 sol_ofs_uobj_put(&uqp->uobj); 1470 1471 err_out: 1472 return (rc); 1473 } 1474 1475 /* 1476 * Function: 1477 * uverbs_copy_path_info_from_ibt 1478 * Input: 1479 * src_path - The IBT path. 1480 * Output: 1481 * dest_path - The OFED user verbs path. 1482 * Returns: 1483 * None 1484 * Description: 1485 * Helper to convert IBT path to OFED user verbs path. 1486 */ 1487 static void 1488 uverbs_copy_path_info_from_ibt(ibt_cep_path_t *src_path, 1489 struct ib_uverbs_qp_dest *dest_path) 1490 { 1491 ASSERT(src_path != NULL); 1492 ASSERT(dest_path != NULL); 1493 1494 (void) memcpy(&dest_path->dgid[0], 1495 &src_path->cep_adds_vect.av_dgid, sizeof (dest_path->dgid)); 1496 1497 dest_path->flow_label = src_path->cep_adds_vect.av_flow; 1498 dest_path->dlid = src_path->cep_adds_vect.av_dlid; 1499 dest_path->hop_limit = src_path->cep_adds_vect.av_hop; 1500 dest_path->traffic_class = src_path->cep_adds_vect.av_tclass; 1501 dest_path->sl = src_path->cep_adds_vect.av_srvl; 1502 dest_path->port_num = src_path->cep_adds_vect.av_port_num; 1503 dest_path->src_path_bits = src_path->cep_adds_vect.av_src_path; 1504 dest_path->is_global = src_path->cep_adds_vect.av_send_grh; 1505 dest_path->sgid_index = src_path->cep_adds_vect.av_sgid_ix; 1506 dest_path->static_rate = src_path->cep_adds_vect.av_srate; 1507 } 1508 1509 /* 1510 * Function: 1511 * uverbs_query_copy_rc 1512 * Input: 1513 * src - The IBT RC QP attributes. 1514 * Output: 1515 * dest - The OFED user verbs QP attributes. 1516 * Returns: 1517 * None 1518 * Description: 1519 * Helper to copy IBT RC QP attributes to OFED QP attributes. 1520 */ 1521 static void 1522 uverbs_query_copy_rc(struct ib_uverbs_query_qp_resp *dest, 1523 ibt_qp_rc_attr_t *src) 1524 { 1525 dest->sq_psn = src->rc_sq_psn; 1526 dest->rq_psn = src->rc_rq_psn; 1527 dest->dest_qp_num = src->rc_dst_qpn; 1528 dest->rnr_retry = src->rc_rnr_retry_cnt; 1529 dest->retry_cnt = src->rc_retry_cnt; 1530 dest->max_dest_rd_atomic = src->rc_rdma_ra_in; 1531 dest->max_rd_atomic = src->rc_rdma_ra_out; 1532 dest->min_rnr_timer = src->rc_min_rnr_nak; 1533 dest->path_mtu = src->rc_path_mtu; 1534 dest->timeout = src->rc_path.cep_timeout; 1535 dest->alt_timeout = src->rc_alt_path.cep_timeout; 1536 dest->port_num = src->rc_path.cep_hca_port_num; 1537 dest->alt_port_num = src->rc_alt_path.cep_hca_port_num; 1538 1539 if (src->rc_mig_state == IBT_STATE_MIGRATED) { 1540 dest->path_mig_state = IB_MIG_MIGRATED; 1541 } 1542 if (src->rc_mig_state == IBT_STATE_REARMED) { 1543 dest->path_mig_state = IB_MIG_REARM; 1544 } 1545 if (src->rc_mig_state == IBT_STATE_ARMED) { 1546 dest->path_mig_state = IB_MIG_ARMED; 1547 } 1548 1549 uverbs_copy_path_info_from_ibt(&src->rc_path, &dest->dest); 1550 uverbs_copy_path_info_from_ibt(&src->rc_alt_path, &dest->alt_dest); 1551 } 1552 1553 /* 1554 * Function: 1555 * uverbs_query_copy_uc 1556 * Input: 1557 * src - The IBT UC QP attributes. 1558 * Output: 1559 * dest - The OFED user verbs QP attributes. 1560 * Returns: 1561 * None 1562 * Description: 1563 * Helper to copy IBT UC QP attributes to OFED user verbs 1564 * QP attributes. 1565 */ 1566 static void 1567 uverbs_query_copy_uc(struct ib_uverbs_query_qp_resp *dest, 1568 ibt_qp_uc_attr_t *src) 1569 { 1570 dest->sq_psn = src->uc_sq_psn; 1571 dest->rq_psn = src->uc_rq_psn; 1572 dest->dest_qp_num = src->uc_dst_qpn; 1573 dest->path_mtu = src->uc_path_mtu; 1574 1575 if (src->uc_mig_state == IBT_STATE_MIGRATED) { 1576 dest->path_mig_state = IB_MIG_MIGRATED; 1577 } 1578 if (src->uc_mig_state == IBT_STATE_REARMED) { 1579 dest->path_mig_state = IB_MIG_REARM; 1580 } 1581 if (src->uc_mig_state == IBT_STATE_ARMED) { 1582 dest->path_mig_state = IB_MIG_ARMED; 1583 } 1584 1585 uverbs_copy_path_info_from_ibt(&src->uc_path, &dest->dest); 1586 uverbs_copy_path_info_from_ibt(&src->uc_alt_path, &dest->alt_dest); 1587 } 1588 1589 /* 1590 * Function: 1591 * uverbs_query_copy_rd 1592 * Input: 1593 * src - The IBT RD QP attributes. 1594 * Output: 1595 * dest - The OFED user verbs QP attributes. 1596 * Returns: 1597 * None 1598 * Description: 1599 * Helper to copy IBT RD QP attributes to OFED user verb QP attributes. 1600 */ 1601 static void 1602 uverbs_query_copy_rd(struct ib_uverbs_query_qp_resp *dest, 1603 ibt_qp_rd_attr_t *src) 1604 { 1605 dest->qkey = src->rd_qkey; 1606 dest->min_rnr_timer = src->rd_min_rnr_nak; 1607 } 1608 1609 /* 1610 * Function: 1611 * uverbs_query_copy_ud 1612 * Input: 1613 * src - The IBT UD QP attributes. 1614 * Output: 1615 * dest - The OFED user verbs QP attributes. 1616 * Returns: 1617 * None 1618 * Description: 1619 * Helper to copy IBT UD QP attributes to OFED user verbs QP attributes. 1620 */ 1621 static void 1622 uverbs_query_copy_ud(struct ib_uverbs_query_qp_resp *dest, 1623 ibt_qp_ud_attr_t *src) 1624 { 1625 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1626 "query_copy_ud:entry - return UD info: qkey:%08X, " 1627 "psn:%d, pkey_idx:%d, port:%d", src->ud_qkey, src->ud_sq_psn, 1628 src->ud_pkey_ix, src->ud_port); 1629 1630 dest->qkey = src->ud_qkey; 1631 dest->sq_psn = src->ud_sq_psn; 1632 dest->pkey_index = src->ud_pkey_ix; 1633 dest->port_num = src->ud_port; 1634 } 1635 1636 /* 1637 * Function: 1638 * uverbs_query_copy_info 1639 * Input: 1640 * src - The IBT QP information. 1641 * Output: 1642 * dest - The OFED user verbs QP attributes. 1643 * Returns: 1644 * None 1645 * Description: 1646 * Helper to copy IBT QP info to OFED user verbs QP attributes. 1647 */ 1648 static void 1649 uverbs_query_copy_info(struct ib_uverbs_query_qp_resp *dest, 1650 ibt_qp_info_t *src) 1651 { 1652 1653 dest->max_send_wr = src->qp_sq_sz; 1654 dest->max_recv_wr = src->qp_rq_sz; 1655 dest->qp_access_flags = ibt_cep_flags2ibv(src->qp_flags); 1656 1657 switch (src->qp_state) { 1658 case IBT_STATE_RESET: 1659 dest->qp_state = IB_QPS_RESET; 1660 break; 1661 case IBT_STATE_INIT: 1662 dest->qp_state = IB_QPS_INIT; 1663 break; 1664 case IBT_STATE_RTR: 1665 dest->qp_state = IB_QPS_RTR; 1666 break; 1667 case IBT_STATE_RTS: 1668 dest->qp_state = IB_QPS_RTS; 1669 break; 1670 case IBT_STATE_SQD: 1671 dest->qp_state = IB_QPS_SQD; 1672 break; 1673 case IBT_STATE_SQE: 1674 dest->qp_state = IB_QPS_SQE; 1675 break; 1676 case IBT_STATE_ERROR: 1677 default: 1678 dest->qp_state = IB_QPS_ERR; 1679 break; 1680 } 1681 1682 switch (src->qp_current_state) { 1683 case IBT_STATE_RESET: 1684 dest->cur_qp_state = IB_QPS_RESET; 1685 break; 1686 case IBT_STATE_INIT: 1687 dest->cur_qp_state = IB_QPS_INIT; 1688 break; 1689 case IBT_STATE_RTR: 1690 dest->cur_qp_state = IB_QPS_RTR; 1691 break; 1692 case IBT_STATE_RTS: 1693 dest->cur_qp_state = IB_QPS_RTS; 1694 break; 1695 case IBT_STATE_SQD: 1696 dest->cur_qp_state = IB_QPS_SQD; 1697 break; 1698 case IBT_STATE_SQE: 1699 dest->cur_qp_state = IB_QPS_SQE; 1700 break; 1701 case IBT_STATE_ERROR: 1702 default: 1703 dest->cur_qp_state = IB_QPS_ERR; 1704 break; 1705 } 1706 1707 if ((src->qp_flags & IBT_ALL_SIGNALED) == IBT_ALL_SIGNALED) { 1708 dest->sq_sig_all = 1; 1709 } 1710 } 1711 1712 /* 1713 * Function: 1714 * uverbs_query_copy_attr 1715 * Input: 1716 * src - The IBT QP information. 1717 * Output: 1718 * dest - The OFED user verbs QP attributes. 1719 * Returns: 1720 * None 1721 * Description: 1722 * Helper to copy IBT QP attributes to OFED user verbs QP attributes. 1723 */ 1724 static void 1725 uverbs_query_copy_attr(struct ib_uverbs_query_qp_resp *dest, 1726 ibt_qp_query_attr_t *src) 1727 { 1728 dest->max_send_sge = src->qp_sq_sgl; 1729 dest->max_recv_sge = src->qp_rq_sgl; 1730 } 1731 1732 /* 1733 * Function: 1734 * sol_uverbs_query_qp 1735 * Input: 1736 * uctxt - Pointer to the callers user context. 1737 * buf - Pointer to kernel buffer containing query QP command. 1738 * in_len - Length in bytes of input command buffer. 1739 * out_len - Length in bytes of output response buffer. 1740 * Output: 1741 * The command output buffer is updated with command results. 1742 * Returns: 1743 * DDI_SUCCESS on success, else error code. 1744 * Description: 1745 * User verbs entry point to query a device QP properties. 1746 */ 1747 /* ARGSUSED */ 1748 int 1749 sol_uverbs_query_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 1750 int in_len, int out_len) 1751 { 1752 struct ib_uverbs_query_qp cmd; 1753 struct ib_uverbs_query_qp_resp resp; 1754 uverbs_uqp_uobj_t *uqp; 1755 ibt_qp_query_attr_t qp_query_attr; 1756 int rc; 1757 1758 (void) memset(&resp, 0, sizeof (resp)); 1759 (void) memcpy(&cmd, buf, sizeof (cmd)); 1760 1761 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1762 "query_qp: entry (qp_handle=%d)", cmd.qp_handle); 1763 1764 uqp = uverbs_uobj_get_uqp_read(cmd.qp_handle); 1765 if (uqp == NULL) { 1766 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1767 "query_qp(): List lookup failure"); 1768 rc = EINVAL; 1769 goto err_out; 1770 } 1771 1772 bzero(&qp_query_attr, sizeof (qp_query_attr)); 1773 rc = ibt_query_qp(uqp->qp, &qp_query_attr); 1774 sol_ofs_uobj_put(&uqp->uobj); 1775 1776 if (rc != IBT_SUCCESS) { 1777 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1778 "query_qp: Error in ibt_query_qp() (rc=%d)", rc); 1779 rc = sol_uverbs_ibt_to_kernel_status(rc); 1780 goto err_out; 1781 } 1782 1783 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1784 "query_qp(): qp_query_attr.qp_info.qp_trans = %d", 1785 qp_query_attr.qp_info.qp_trans); 1786 1787 uverbs_query_copy_attr(&resp, &qp_query_attr); 1788 uverbs_query_copy_info(&resp, &qp_query_attr.qp_info); 1789 1790 if (qp_query_attr.qp_info.qp_trans == IBT_RC_SRV) { 1791 uverbs_query_copy_rc(&resp, 1792 &qp_query_attr.qp_info.qp_transport.rc); 1793 } 1794 1795 if (qp_query_attr.qp_info.qp_trans == IBT_UC_SRV) { 1796 uverbs_query_copy_uc(&resp, 1797 &qp_query_attr.qp_info.qp_transport.uc); 1798 } 1799 1800 if (qp_query_attr.qp_info.qp_trans == IBT_RD_SRV) { 1801 uverbs_query_copy_rd(&resp, 1802 &qp_query_attr.qp_info.qp_transport.rd); 1803 } 1804 1805 1806 if (qp_query_attr.qp_info.qp_trans == IBT_UD_SRV) { 1807 uverbs_query_copy_ud(&resp, 1808 &qp_query_attr.qp_info.qp_transport.ud); 1809 } 1810 1811 resp.max_inline_data = uqp->max_inline_data; 1812 1813 #ifdef _LP64 1814 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 1815 #else 1816 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 1817 #endif 1818 if (rc != 0) { 1819 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1820 "query_qp(): Error writing resp data (rc=%d)", rc); 1821 rc = EFAULT; 1822 goto err_out; 1823 } 1824 1825 return (DDI_SUCCESS); 1826 1827 err_out: 1828 return (rc); 1829 } 1830 1831 /* 1832 * Function: 1833 * sol_uverbs_create_srq 1834 * Input: 1835 * uctxt - Pointer to the callers user context. 1836 * buf - Pointer to kernel buffer containing command. 1837 * in_len - Length in bytes of input command buffer. 1838 * out_len - Length in bytes of output response buffer. 1839 * Output: 1840 * The command output buffer is updated with command results. 1841 * Returns: 1842 * DDI_SUCCESS on success, else error code. 1843 * Description: 1844 * User verbs entry point to create a device shared receive queue. 1845 */ 1846 /* ARGSUSED */ 1847 int 1848 sol_uverbs_create_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 1849 int in_len, int out_len) 1850 { 1851 struct ib_uverbs_create_srq cmd; 1852 struct ib_uverbs_create_srq_resp resp; 1853 uverbs_usrq_uobj_t *usrq; 1854 uverbs_upd_uobj_t *upd; 1855 ibt_srq_flags_t flags = IBT_SRQ_USER_MAP; 1856 ibt_srq_sizes_t attr; 1857 ibt_srq_sizes_t real_attr; 1858 int rc; 1859 1860 (void) memcpy(&cmd, buf, sizeof (cmd)); 1861 (void) memset(&resp, 0, sizeof (resp)); 1862 (void) memset(&attr, 0, sizeof (attr)); 1863 1864 attr.srq_wr_sz = cmd.max_wr; 1865 attr.srq_sgl_sz = cmd.max_sge; 1866 1867 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_srq: " 1868 "max_wr=%d, max_sge=%d, srq_limit=%d", 1869 cmd.max_wr, cmd.max_sge, cmd.srq_limit); 1870 1871 if (!attr.srq_wr_sz) { 1872 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1873 "create_srq(): Invalid args, invalid work " 1874 "request size"); 1875 1876 rc = EINVAL; 1877 goto err_out; 1878 } 1879 1880 if (attr.srq_wr_sz > uctxt->hca->attr.hca_max_srqs_sz || 1881 attr.srq_sgl_sz > uctxt->hca->attr.hca_max_srq_sgl) { 1882 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1883 "create_srq(): Invalid args, too large"); 1884 rc = EINVAL; 1885 goto err_out; 1886 } 1887 1888 usrq = kmem_zalloc(sizeof (*usrq), KM_NOSLEEP); 1889 if (usrq == NULL) { 1890 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1891 "create_srq(): User object alloc failed"); 1892 rc = ENOMEM; 1893 goto err_out; 1894 } 1895 sol_ofs_uobj_init(&usrq->uobj, cmd.user_handle, 1896 SOL_UVERBS_USRQ_UOBJ_TYPE); 1897 rw_enter(&usrq->uobj.uo_lock, RW_WRITER); 1898 llist_head_init(&usrq->async_list, NULL); 1899 usrq->async_events_reported = 0; 1900 usrq->uctxt = uctxt; 1901 1902 upd = uverbs_uobj_get_upd_read(cmd.pd_handle); 1903 if (upd == NULL) { 1904 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1905 "create_srq(): PD Invalid"); 1906 rc = EINVAL; 1907 goto err_dealloc; 1908 } 1909 1910 rc = ibt_alloc_srq(uctxt->hca->hdl, flags, upd->pd, &attr, &usrq->srq, 1911 &real_attr); 1912 1913 if (rc != IBT_SUCCESS) { 1914 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1915 "create_srq(): Error in ibt_alloc_srq() (rc=%d)", rc); 1916 usrq->srq = NULL; 1917 rc = sol_uverbs_ibt_to_kernel_status(rc); 1918 usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t); 1919 goto err_release_pd; 1920 } 1921 1922 ibt_set_srq_private(usrq->srq, usrq); 1923 1924 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1925 "create_srq(): ib_alloc_srq()real wqe_sz=%d, real_sg_sz=%d", 1926 real_attr.srq_wr_sz, real_attr.srq_sgl_sz); 1927 1928 /* 1929 * Query underlying hardware for data used in mapping CQ back to user 1930 * space, we will return this information in the user verbs command 1931 * response. 1932 */ 1933 rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_SRQ, 1934 (void *)usrq->srq, &resp.drv_out, sizeof (resp.drv_out)); 1935 1936 if (rc != IBT_SUCCESS) { 1937 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1938 "create_srq(): Error in ibt_ci_data_out() (rc=%d)", rc); 1939 rc = EFAULT; 1940 usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t); 1941 goto err_srq_destroy; 1942 } 1943 1944 if (sol_ofs_uobj_add(&uverbs_usrq_uo_tbl, &usrq->uobj) != 0) { 1945 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1946 "create_srq(): uobj add failed"); 1947 rc = ENOMEM; 1948 goto err_srq_destroy; 1949 } 1950 1951 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1952 "create_srq(): ibt_ci_data_out: 0x%16llx 0x%16llx 0x%16llx " 1953 "0x%16llx", resp.drv_out[0], resp.drv_out[1], resp.drv_out[2], 1954 resp.drv_out[3]); 1955 1956 resp.srq_handle = usrq->uobj.uo_id; 1957 resp.max_wr = real_attr.srq_wr_sz; 1958 resp.max_sge = real_attr.srq_sgl_sz; 1959 1960 #ifdef _LP64 1961 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 1962 #else 1963 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 1964 #endif 1965 if (rc != 0) { 1966 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1967 "create_srq(): Error writing resp data (rc=%d)", rc); 1968 rc = EFAULT; 1969 goto err_uo_delete; 1970 } 1971 1972 mutex_enter(&uctxt->lock); 1973 usrq->list_entry = add_genlist(&uctxt->srq_list, (uintptr_t)usrq, 1974 uctxt); 1975 mutex_exit(&uctxt->lock); 1976 1977 if (!usrq->list_entry) { 1978 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1979 "create_srq() : Error adding usrq to srq_list failed"); 1980 rc = ENOMEM; 1981 goto err_uo_delete; 1982 } 1983 1984 usrq->uobj.uo_live = 1; 1985 rw_exit(&usrq->uobj.uo_lock); 1986 1987 sol_ofs_uobj_put(&upd->uobj); 1988 1989 return (DDI_SUCCESS); 1990 1991 err_uo_delete: 1992 /* 1993 * Need to set uo_live, so sol_ofs_uobj_remove() will 1994 * remove the object from the object table. 1995 */ 1996 usrq->uobj.uo_live = 1; 1997 (void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj); 1998 1999 err_srq_destroy: 2000 (void) ibt_free_srq(usrq->srq); 2001 2002 err_release_pd: 2003 sol_ofs_uobj_put(&upd->uobj); 2004 2005 err_dealloc: 2006 rw_exit(&usrq->uobj.uo_lock); 2007 sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free); 2008 2009 err_out: 2010 return (rc); 2011 } 2012 2013 /* 2014 * Function: 2015 * sol_uverbs_modify_srq 2016 * Input: 2017 * uctxt - Pointer to the callers user context. 2018 * buf - Pointer to kernel buffer containing SRQ modify command. 2019 * in_len - Length in bytes of input command buffer. 2020 * out_len - Length in bytes of output response buffer. 2021 * Output: 2022 * The command output buffer is updated with command results. 2023 * Returns: 2024 * DDI_SUCCESS on success, else error code. 2025 * Description: 2026 * User verbs entry point to modify a device shared receive queue. 2027 */ 2028 /* ARGSUSED */ 2029 int 2030 sol_uverbs_modify_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 2031 int in_len, int out_len) 2032 { 2033 struct ib_uverbs_modify_srq cmd; 2034 uverbs_usrq_uobj_t *usrq; 2035 uint_t limit = 0; 2036 uint_t size = 0; 2037 uint_t real_size = 0; 2038 ibt_srq_modify_flags_t flags = 0; 2039 int rc; 2040 2041 (void) memcpy(&cmd, buf, sizeof (cmd)); 2042 2043 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2044 "modify_srq(): entry (srq_handle=%d)", cmd.srq_handle); 2045 2046 usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle); 2047 if (usrq == NULL) { 2048 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2049 "modify_srq(): List lookup failure"); 2050 rc = EINVAL; 2051 goto err_out; 2052 } 2053 2054 if (cmd.attr_mask & IB_SRQ_MAX_WR) { 2055 flags = IBT_SRQ_SET_SIZE; 2056 size = cmd.max_wr; 2057 } 2058 2059 if (cmd.attr_mask & IB_SRQ_LIMIT) { 2060 flags |= IBT_SRQ_SET_LIMIT; 2061 limit = cmd.srq_limit; 2062 } 2063 2064 rc = ibt_modify_srq(usrq->srq, flags, size, limit, &real_size); 2065 if (rc != IBT_SUCCESS) { 2066 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2067 "modify_srq(): Error in ibt_modify_srq() (rc=%d)", rc); 2068 rc = sol_uverbs_ibt_to_kernel_status(rc); 2069 goto err_deref; 2070 } 2071 2072 done: 2073 sol_ofs_uobj_put(&usrq->uobj); 2074 return (DDI_SUCCESS); 2075 2076 err_deref: 2077 sol_ofs_uobj_put(&usrq->uobj); 2078 2079 err_out: 2080 return (rc); 2081 } 2082 2083 /* 2084 * Function: 2085 * sol_uverbs_query_srq 2086 * Input: 2087 * uctxt - Pointer to the callers user context. 2088 * buf - Pointer to kernel buffer containing command. 2089 * in_len - Length in bytes of input command buffer. 2090 * out_len - Length in bytes of output response buffer. 2091 * Output: 2092 * The command output buffer is updated with command results. 2093 * Returns: 2094 * DDI_SUCCESS on success, else error code. 2095 * Description: 2096 * User verbs entry point to query a device shared receive queue 2097 * properties. 2098 */ 2099 /* ARGSUSED */ 2100 int 2101 sol_uverbs_query_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 2102 int in_len, int out_len) 2103 { 2104 struct ib_uverbs_query_srq cmd; 2105 struct ib_uverbs_query_srq_resp resp; 2106 uverbs_usrq_uobj_t *usrq; 2107 ibt_pd_hdl_t pd; 2108 int rc; 2109 ibt_srq_sizes_t attr; 2110 uint_t limit; 2111 2112 (void) memcpy(&cmd, buf, sizeof (cmd)); 2113 (void) memset(&resp, 0, sizeof (resp)); 2114 2115 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2116 "query_srq(): entry (srq_handle=%d)", cmd.srq_handle); 2117 2118 usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle); 2119 if (usrq == NULL) { 2120 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2121 "query_srq(): Invalid handle: %d", cmd.srq_handle); 2122 rc = EINVAL; 2123 goto err_out; 2124 } 2125 2126 rc = ibt_query_srq(usrq->srq, &pd, &attr, &limit); 2127 sol_ofs_uobj_put(&usrq->uobj); 2128 2129 if (rc != IBT_SUCCESS) { 2130 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2131 "query_srq(): Error in ibt_query_srq() (rc=%d)", rc); 2132 rc = sol_uverbs_ibt_to_kernel_status(rc); 2133 goto err_out; 2134 } 2135 2136 resp.max_wr = attr.srq_wr_sz; 2137 resp.max_sge = attr.srq_sgl_sz; 2138 resp.srq_limit = limit; 2139 2140 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_srq() - " 2141 "max_wr=%d, max_sge=%d, limit=%d", resp.max_wr, 2142 resp.max_sge, resp.srq_limit); 2143 2144 /* 2145 * Release the reference from the find above, we leave the initial 2146 * reference placed at SRQ creation time. 2147 */ 2148 2149 #ifdef _LP64 2150 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 2151 #else 2152 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 2153 #endif 2154 if (rc != 0) { 2155 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "query_srq() - " 2156 "copyout failure %x", rc); 2157 rc = EFAULT; 2158 goto err_out; 2159 } 2160 2161 return (DDI_SUCCESS); 2162 2163 err_out: 2164 return (rc); 2165 } 2166 2167 int 2168 uverbs_usrq_free(uverbs_usrq_uobj_t *usrq, uverbs_uctxt_uobj_t *uctxt) 2169 { 2170 int rc; 2171 2172 if (!usrq->srq) 2173 goto skip_ibt_free_srq; 2174 2175 rc = ibt_free_srq(usrq->srq); 2176 if (rc != IBT_SUCCESS) { 2177 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "usrq_free() - " 2178 "Error in ibt_free_srq() (rc=%d)", rc); 2179 rc = sol_uverbs_ibt_to_kernel_status(rc); 2180 sol_ofs_uobj_put(&usrq->uobj); 2181 return (rc); 2182 } 2183 usrq->srq = NULL; 2184 2185 skip_ibt_free_srq : 2186 sol_ofs_uobj_put(&usrq->uobj); 2187 if (usrq->list_entry) { 2188 mutex_enter(&uctxt->lock); 2189 delete_genlist(&uctxt->srq_list, usrq->list_entry); 2190 mutex_exit(&uctxt->lock); 2191 (void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj); 2192 } 2193 sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free); 2194 2195 return (0); 2196 } 2197 2198 /* 2199 * Function: 2200 * sol_uverbs_destroy_srq 2201 * Input: 2202 * uctxt - Pointer to the callers user context. 2203 * buf - Pointer to kernel buffer containing command. 2204 * in_len - Length in bytes of input command buffer. 2205 * out_len - Length in bytes of output response buffer. 2206 * Output: 2207 * The command output buffer is updated with command results. 2208 * Returns: 2209 * DDI_SUCCESS on success, else error code. 2210 * Description: 2211 * User verbs entry point to destroy a device shared receive queue. 2212 */ 2213 /* ARGSUSED */ 2214 int 2215 sol_uverbs_destroy_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 2216 int in_len, int out_len) 2217 { 2218 struct ib_uverbs_destroy_srq cmd; 2219 struct ib_uverbs_destroy_srq_resp resp; 2220 uverbs_usrq_uobj_t *usrq; 2221 int rc; 2222 2223 (void) memcpy(&cmd, buf, sizeof (cmd)); 2224 (void) memset(&resp, 0, sizeof (resp)); 2225 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "destroy_srq() - " 2226 "srq_handle %d", cmd.srq_handle); 2227 2228 usrq = uverbs_uobj_get_usrq_write(cmd.srq_handle); 2229 if (usrq == NULL) { 2230 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2231 "destroy_srq() : inavlid hdl %d", cmd.srq_handle); 2232 rc = EINVAL; 2233 goto err_out; 2234 } 2235 2236 uverbs_release_usrq_uevents(uctxt->async_evfile, usrq); 2237 resp.events_reported = usrq->async_events_reported; 2238 if (usrq->active_qp_cnt) { 2239 sol_ofs_uobj_put(&usrq->uobj); 2240 return (EBUSY); 2241 } else { 2242 rc = uverbs_usrq_free(usrq, uctxt); 2243 if (rc) 2244 goto err_out; 2245 } 2246 2247 #ifdef _LP64 2248 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 2249 #else 2250 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 2251 #endif 2252 if (rc != 0) { 2253 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2254 "destroy_srq() : copyout failure %x", rc); 2255 rc = EFAULT; 2256 goto err_out; 2257 } 2258 2259 return (DDI_SUCCESS); 2260 2261 err_out: 2262 return (rc); 2263 } 2264 2265 /* 2266 * Function: 2267 * sol_uverbs_attach_mcast 2268 * Input: 2269 * uctxt - Pointer to the callers user context. 2270 * buf - Pointer to kernel buffer containing command. 2271 * in_len - Length in bytes of input command buffer. 2272 * out_len - Length in bytes of output response buffer. 2273 * Output: 2274 * The command output buffer is updated with command results. 2275 * Returns: 2276 * DDI_SUCCESS on success, else error code. 2277 * Description: 2278 * User verbs entry point to attach a QP to a multicast group 2279 */ 2280 /* ARGSUSED */ 2281 int 2282 sol_uverbs_attach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf, 2283 int in_len, int out_len) 2284 { 2285 struct ib_uverbs_attach_mcast cmd; 2286 uverbs_uqp_uobj_t *uqp; 2287 uverbs_mcast_entry_t *mc; 2288 llist_head_t *entry; 2289 int rc; 2290 ib_gid_t mc_gid; 2291 2292 (void) memcpy(&cmd, buf, sizeof (cmd)); 2293 2294 /* 2295 * API specifies gid in network order, Solaris expects the gid 2296 * in host order, do the conversion if required. 2297 */ 2298 mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0])); 2299 mc_gid.gid_guid = b2h64(*((uint64_t *)&cmd.gid[8])); 2300 2301 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "attach_mcast(qp_handle=%d, " 2302 "mlid=0x%04x, gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid, 2303 mc_gid.gid_prefix, mc_gid.gid_guid); 2304 2305 /* 2306 * Take object write to protect MC list. 2307 */ 2308 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 2309 if (uqp == NULL) { 2310 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2311 "attach_mcast QP not found"); 2312 rc = EINVAL; 2313 goto err_out; 2314 } 2315 2316 /* 2317 * Look to see if we are already attached and if so no need to attach 2318 * again, just return good status. 2319 */ 2320 list_for_each(entry, &uqp->mcast_list) { 2321 mc = (uverbs_mcast_entry_t *)entry->ptr; 2322 2323 if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid && 2324 !memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid, 2325 sizeof (mc_gid.gid))) { 2326 SOL_OFS_DPRINTF_L4(sol_uverbs_dbg_str, 2327 "attach_mcast: match entry found"); 2328 rc = DDI_SUCCESS; 2329 goto out_put; 2330 } 2331 } 2332 2333 mc = kmem_zalloc(sizeof (*mc), KM_NOSLEEP); 2334 if (mc == NULL) { 2335 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2336 "attach_mcast: kmem_zalloc fail"); 2337 rc = ENOMEM; 2338 goto out_put; 2339 } 2340 2341 llist_head_init(&mc->list, mc); 2342 mc->mcg.mc_adds_vect.av_dlid = cmd.mlid; 2343 bcopy(&mc_gid, &(mc->mcg.mc_adds_vect.av_dgid), sizeof (mc_gid)); 2344 2345 rc = ibt_attach_mcg(uqp->qp, &mc->mcg); 2346 if (rc != IBT_SUCCESS) { 2347 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2348 "attach_mcast: ibt_attach_mcq failed (r=%d)", rc); 2349 rc = sol_uverbs_ibt_to_kernel_status(rc); 2350 goto err_free; 2351 } 2352 2353 llist_add_tail(&mc->list, &uqp->mcast_list); 2354 sol_ofs_uobj_put(&uqp->uobj); 2355 2356 return (DDI_SUCCESS); 2357 2358 err_free: 2359 kmem_free(mc, sizeof (*mc)); 2360 out_put: 2361 sol_ofs_uobj_put(&uqp->uobj); 2362 err_out: 2363 return (rc); 2364 } 2365 2366 /* 2367 * Function: 2368 * sol_uverbs_detach_mcast 2369 * Input: 2370 * uctxt - Pointer to the callers user context. 2371 * buf - Pointer to kernel buffer containing command. 2372 * in_len - Length in bytes of input command buffer. 2373 * out_len - Length in bytes of output response buffer. 2374 * Output: 2375 * The command output buffer is updated with command results. 2376 * Returns: 2377 * DDI_SUCCESS on success, else error code. 2378 * Description: 2379 * User verbs entry point to detach a QP from a multicast group 2380 */ 2381 /* ARGSUSED */ 2382 int 2383 sol_uverbs_detach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf, 2384 int in_len, int out_len) 2385 { 2386 struct ib_uverbs_detach_mcast cmd; 2387 uverbs_uqp_uobj_t *uqp; 2388 ibt_mcg_info_t mcg; 2389 int rc; 2390 uverbs_mcast_entry_t *mc; 2391 llist_head_t *entry; 2392 llist_head_t *temp; 2393 ib_gid_t mc_gid; 2394 2395 (void) memcpy(&cmd, buf, sizeof (cmd)); 2396 2397 /* 2398 * API specifies gid in network order, Solaris expects the gid 2399 * in host order, do the conversion if required. 2400 */ 2401 mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0])); 2402 mc_gid.gid_guid = b2h64(*((uint64_t *)&cmd.gid[8])); 2403 2404 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2405 "detach_mcast: entry (qp_handle=%d, mlid=0x%04x," 2406 "gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid, mc_gid.gid_prefix, 2407 mc_gid.gid_guid); 2408 2409 (void) memset(&mcg, 0, sizeof (mcg)); 2410 2411 /* 2412 * Get object write to protect mcast list. 2413 */ 2414 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 2415 if (uqp == NULL) { 2416 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2417 "detach_mcast(): QP hdl %x not found", cmd.qp_handle); 2418 rc = EINVAL; 2419 goto err_out; 2420 } 2421 2422 mcg.mc_adds_vect.av_dlid = cmd.mlid; 2423 mcg.mc_adds_vect.av_dgid = mc_gid; 2424 2425 rc = ibt_detach_mcg(uqp->qp, &mcg); 2426 if (rc != IBT_SUCCESS) { 2427 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2428 "deatch_mcast(): ibt_attach_mcq failed (r=%d)", rc); 2429 rc = sol_uverbs_ibt_to_kernel_status(rc); 2430 goto err_put; 2431 } 2432 2433 /* 2434 * Find and delete MC group from the QP multicast list. 2435 */ 2436 entry = uqp->mcast_list.nxt; 2437 temp = entry->nxt; 2438 while (entry != &uqp->mcast_list) { 2439 ASSERT(entry); 2440 mc = (uverbs_mcast_entry_t *)entry->ptr; 2441 ASSERT(mc); 2442 2443 if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid && 2444 !memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid, 2445 sizeof (mc_gid.gid))) { 2446 llist_del(&mc->list); 2447 kmem_free(mc, sizeof (*mc)); 2448 break; 2449 } 2450 entry = temp; 2451 temp = entry->nxt; 2452 } 2453 2454 sol_ofs_uobj_put(&uqp->uobj); 2455 2456 return (DDI_SUCCESS); 2457 2458 err_put: 2459 sol_ofs_uobj_put(&uqp->uobj); 2460 2461 err_out: 2462 return (rc); 2463 } 2464 2465 /* 2466 * Function: 2467 * uverbs_release_uqp_mcast_entries 2468 * Input: 2469 * uctxt - Pointer to the callers user context. 2470 * uqp - Pointer to the user QP object for which the multicast 2471 * list should be flushed. 2472 * Output: 2473 * None 2474 * Returns: 2475 * None 2476 * Description: 2477 * Release any multicast resources held by this QP. The 2478 * user context associated with the QP should be locked 2479 * externally to this routine to protect the updates to the 2480 * multicast list. 2481 */ 2482 void 2483 uverbs_detach_uqp_mcast_entries(uverbs_uqp_uobj_t *uqp) 2484 { 2485 int rc; 2486 uverbs_mcast_entry_t *mc; 2487 llist_head_t *entry; 2488 llist_head_t *temp; 2489 2490 /* 2491 * Find and delete MC group from the QP multicast list. 2492 */ 2493 entry = uqp->mcast_list.nxt; 2494 temp = entry->nxt; 2495 while (entry != &uqp->mcast_list) { 2496 ASSERT(entry); 2497 mc = (uverbs_mcast_entry_t *)entry->ptr; 2498 ASSERT(mc); 2499 2500 rc = ibt_detach_mcg(uqp->qp, &mc->mcg); 2501 if (rc != IBT_SUCCESS) { 2502 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2503 "detach_mcast() : " 2504 "ibt_detach_mcq failed (r=%d)", rc); 2505 } 2506 llist_del(&mc->list); 2507 entry = temp; 2508 temp = entry->nxt; 2509 } 2510 } 2511 2512 /* 2513 * Function: 2514 * sol_uverbs_uqpid_to_ibt_handle 2515 * Input: 2516 * uqpid - A user verbs QP id, i.e. a QP handle that was 2517 * created via libibverbs and sol_uverbs. 2518 * Output: 2519 * None 2520 * Returns: 2521 * The ibt_qp_hdl_t associated with the user space QP handle. 2522 * -1 is returned if the id is not found. 2523 * Description: 2524 * Map the user verbs QP id to the associated IBT QP handle. 2525 */ 2526 ibt_qp_hdl_t 2527 sol_uverbs_uqpid_to_ibt_handle(uint32_t uqpid) 2528 { 2529 uverbs_uqp_uobj_t *uqp; 2530 void *qphdl; 2531 2532 uqp = uverbs_uobj_get_uqp_read(uqpid); 2533 if (uqp == NULL) { 2534 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2535 "uqpid2ibthdl: QP lookup failure: id %d", uqpid); 2536 return (NULL); 2537 } 2538 qphdl = (void *)uqp->qp; 2539 sol_ofs_uobj_put(&uqp->uobj); 2540 return (qphdl); 2541 } 2542 2543 /* 2544 * Function: 2545 * sol_uverbs_disable_user_qp_modify 2546 * Input: 2547 * uqpid - A user verbs QP id, i.e. a QP handle that was 2548 * created via libibverbs and sol_uverbs. 2549 * Output: 2550 * None 2551 * Returns: 2552 * 0 on success, EINVAL if associated QP is not found. 2553 * Description: 2554 * Inform sol_uverbs driver to ignore user qp modify 2555 * operations it receives for the specified qp. To re-enable 2556 * this capability see the function sol_uverbs_enable_user_qp_modify. 2557 */ 2558 int 2559 sol_uverbs_disable_user_qp_modify(uint32_t uqpid) 2560 { 2561 uverbs_uqp_uobj_t *uqp; 2562 2563 uqp = uverbs_uobj_get_uqp_write(uqpid); 2564 if (uqp == NULL) { 2565 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2566 "disable_uqp_modify(%d) -lookup failure", uqpid); 2567 return (EINVAL); 2568 } 2569 uqp->disable_qp_mod = TRUE; 2570 sol_ofs_uobj_put(&uqp->uobj); 2571 return (0); 2572 } 2573 2574 /* 2575 * Function: 2576 * sol_uverbs_enable_user_qp_modify 2577 * Input: 2578 * uqpid - A user verbs QP id, i.e. a QP handle that was 2579 * created via libibverbs and sol_uverbs. 2580 * Output: 2581 * None 2582 * Returns: 2583 * 0 on success, EINVAL if associated QP is not found. 2584 * Description: 2585 * Inform sol_uverbs driver to process user qp modify 2586 * operations it receives for the specified qp. This is 2587 * the default and this routine need only be invoked if 2588 * user QP modify operations have explicitly been disabled 2589 * with sol_uverbs_disable_user_qp_modify. 2590 */ 2591 int 2592 sol_uverbs_enable_user_qp_modify(uint32_t uqpid) 2593 { 2594 uverbs_uqp_uobj_t *uqp; 2595 2596 uqp = uverbs_uobj_get_uqp_write(uqpid); 2597 if (uqp == NULL) { 2598 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2599 "enable_uqp_modify(%d) -lookup failure", uqpid); 2600 return (EINVAL); 2601 } 2602 uqp->disable_qp_mod = FALSE; 2603 sol_ofs_uobj_put(&uqp->uobj); 2604 return (0); 2605 } 2606 2607 int 2608 uverbs_uqpn_cq_ctrl(uint32_t uqpid, sol_uverbs_cq_ctrl_t ctrl) 2609 { 2610 uverbs_uqp_uobj_t *uqp; 2611 uverbs_ucq_uobj_t *uscq; 2612 uverbs_ucq_uobj_t *urcq; 2613 2614 uqp = uverbs_uobj_get_uqp_write(uqpid); 2615 if (uqp == NULL) { 2616 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2617 "uqpn_cq_ctrl(%d) -lookup failure", uqpid); 2618 return (EINVAL); 2619 } 2620 uscq = uqp->uqp_scq; 2621 urcq = uqp->uqp_rcq; 2622 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2623 "ctrl - uqp %p, rcq %p. scq %p", uqp, urcq, uscq); 2624 2625 ASSERT(uscq); 2626 ASSERT(urcq); 2627 uverbs_cq_ctrl(uscq, ctrl); 2628 if (uscq != urcq) 2629 uverbs_cq_ctrl(urcq, ctrl); 2630 sol_ofs_uobj_put(&uqp->uobj); 2631 return (0); 2632 } 2633 2634 extern uint32_t sol_uverbs_qpnum2uqpid(uint32_t); 2635 2636 void 2637 sol_uverbs_flush_qp(uint32_t qpnum) 2638 { 2639 int32_t uqpid; 2640 ibt_status_t status; 2641 uverbs_uqp_uobj_t *uqp; 2642 2643 uqpid = sol_uverbs_qpnum2uqpid(qpnum); 2644 if (uqpid == DDI_FAILURE) { 2645 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2646 "sol_uverbs_flush_qp(%x) - Invalid qpnum", 2647 qpnum); 2648 return; 2649 } 2650 uqp = uverbs_uobj_get_uqp_write(uqpid); 2651 if (uqp == NULL) { 2652 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2653 "sol_uverbs_flush_qp(%x) - Invalid " 2654 "uqpid %x", qpnum, uqpid); 2655 return; 2656 } 2657 2658 if (uqp->qp) { 2659 status = ibt_flush_qp(uqp->qp); 2660 if (status != IBT_SUCCESS) 2661 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2662 "sol_uverbs_flush_qp(%x) - " 2663 "ibt_flush_qp(%p) failed - status %d", 2664 qpnum, uqp->qp, status); 2665 sol_ofs_uobj_put(&uqp->uobj); 2666 return; 2667 } else { 2668 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2669 "sol_uverbs_flush_qp(%x), uqpid %x -" 2670 "uqp->qp is NULL!!", qpnum, uqpid); 2671 sol_ofs_uobj_put(&uqp->uobj); 2672 return; 2673 } 2674 } 2675 static uint32_t 2676 ibt_cep_flags2ibv(ibt_cep_flags_t ibt_flags) 2677 { 2678 uint32_t ib_flags = 0; 2679 2680 if (ibt_flags & IBT_CEP_RDMA_WR) 2681 ib_flags |= IB_ACCESS_REMOTE_WRITE; 2682 if (ibt_flags & IBT_CEP_RDMA_RD) 2683 ib_flags |= IB_ACCESS_REMOTE_READ; 2684 if (ibt_flags & IBT_CEP_ATOMIC) 2685 ib_flags |= IB_ACCESS_REMOTE_ATOMIC; 2686 2687 return (ib_flags); 2688 } 2689 2690 static void 2691 uverbs_cq_ctrl(uverbs_ucq_uobj_t *ucq, sol_uverbs_cq_ctrl_t ctrl) 2692 { 2693 uverbs_ufile_uobj_t *ufile; 2694 2695 ufile = ucq->comp_chan; 2696 if (!ufile) { 2697 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, 2698 "cq_ctrl(%p), ufile NULL", ucq, ufile); 2699 return; 2700 } 2701 2702 mutex_enter(&ufile->lock); 2703 ufile->ufile_notify_enabled = ctrl; 2704 2705 if (ctrl == SOL_UVERBS2UCMA_CQ_NOTIFY_ENABLE) { 2706 if (!llist_empty(&ufile->event_list)) { 2707 cv_signal(&ufile->poll_wait); 2708 pollwakeup(&ufile->poll_head, 2709 POLLIN | POLLRDNORM); 2710 } 2711 } 2712 mutex_exit(&ufile->lock); 2713 } 2714