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 ret = uverbs_ucq_free(urcq, uctxt); 719 if (ret && rc == 0) { 720 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 721 "uqp_rsrc_free: ucq_free failed"); 722 rc = ret; 723 } 724 } else if (urcq) 725 sol_ofs_uobj_put(&urcq->uobj); 726 if (usrq && usrq->active_qp_cnt == 0 && usrq->free_pending) { 727 ret = uverbs_usrq_free(usrq, uctxt); 728 if (ret && rc == 0) { 729 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 730 "uqp_rsrc_free: usrq_free failed"); 731 rc = ret; 732 } 733 } else if (usrq) 734 sol_ofs_uobj_put(&usrq->uobj); 735 return (rc); 736 737 err_free: 738 if (upd) 739 sol_ofs_uobj_put(&upd->uobj); 740 if (uscq) 741 sol_ofs_uobj_put(&uscq->uobj); 742 if (urcq) 743 sol_ofs_uobj_put(&urcq->uobj); 744 745 return (rc); 746 } 747 748 /* 749 * Free the resources held by the uqp. 750 * Call ibt_free_qp() to free the IBTF QP. 751 * Free uqp. 752 */ 753 int 754 uverbs_uqp_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt) 755 { 756 int rc; 757 ibt_status_t status; 758 759 /* Detach Mcast entries, if any. */ 760 uverbs_detach_uqp_mcast_entries(uqp); 761 762 if (!uqp->qp) 763 goto skip_ibt_free_qp; 764 765 status = ibt_free_qp(uqp->qp); 766 if (status != IBT_SUCCESS) { 767 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 768 "uqp_free: ibt_free_qp failed %d", status); 769 sol_ofs_uobj_put(&uqp->uobj); 770 return (status); 771 } 772 uqp->qp = NULL; 773 774 skip_ibt_free_qp : 775 rc = uverbs_uqp_rsrc_free(uqp, uctxt); 776 if (rc) { 777 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 778 "uqp_free: uqp_rcrc_free failed %d", rc); 779 sol_ofs_uobj_put(&uqp->uobj); 780 return (rc); 781 } 782 783 (void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj); 784 sol_ofs_uobj_put(&uqp->uobj); 785 786 if (uqp->list_entry) { 787 mutex_enter(&uctxt->lock); 788 delete_genlist(&uctxt->qp_list, uqp->list_entry); 789 uqp->list_entry = NULL; 790 mutex_exit(&uctxt->lock); 791 } 792 793 sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free); 794 795 if (uctxt->uctxt_free_pending && (uctxt->qp_list).count == 0) { 796 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, 797 "uqp_free: freeing uctxt %p", uctxt); 798 sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free); 799 } 800 return (0); 801 } 802 803 /* 804 * Function: 805 * sol_uverbs_destroy_qp 806 * Input: 807 * uctxt - Pointer to the callers user context. 808 * buf - Pointer to kernel buffer containing the destroy command. 809 * in_len - Length in bytes of input command buffer. 810 * out_len - Length in bytes of output response buffer. 811 * Output: 812 * The command output buffer is updated with command results. 813 * Returns: 814 * DDI_SUCCESS on success, else error code. 815 * Description: 816 * User verbs entry point to destroy a device QP. 817 */ 818 /* ARGSUSED */ 819 int 820 sol_uverbs_destroy_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 821 int in_len, int out_len) 822 { 823 struct ib_uverbs_destroy_qp cmd; 824 struct ib_uverbs_destroy_qp_resp resp; 825 uverbs_uqp_uobj_t *uqp; 826 int rc; 827 828 (void) memcpy(&cmd, buf, sizeof (cmd)); 829 (void) memset(&resp, 0, sizeof (resp)); 830 831 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: entry " 832 "(qp_handle=%d)", cmd.qp_handle); 833 834 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 835 if (uqp == NULL) { 836 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 837 "destroy_qp() : List lookup failure"); 838 rc = EINVAL; 839 goto err_out; 840 } 841 842 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: qp_handle=%d, " 843 "uqp %p, qp_ptr %p", cmd.qp_handle, uqp, uqp->qp); 844 845 if (!llist_empty(&uqp->mcast_list)) { 846 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 847 "destroy_qp() called with attached MC group(s)"); 848 rc = EBUSY; 849 goto err_busy; 850 } 851 852 uverbs_release_uqp_uevents(uctxt->async_evfile, uqp); 853 resp.events_reported = uqp->async_events_reported; 854 855 /* 856 * If ucma has disabled QP free for this QP, set FREE_PENDING 857 * flag so that the QP can be freed when UCMA enables QP_FREE. 858 * Call ibt_free_qp() is ucma has not disabled QP free. 859 */ 860 if (uqp->uqp_free_state == SOL_UVERBS2UCMA_DISABLE_QP_FREE) { 861 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 862 "destroy_qp() - UCMA disabled"); 863 uqp->uqp_free_state = SOL_UVERBS2UCMA_FREE_PENDING; 864 sol_ofs_uobj_put(&uqp->uobj); 865 rc = 0; 866 goto report_qp_evts; 867 } else { 868 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 869 "destroy_qp() - freeing QP : %p", uqp); 870 rc = uverbs_uqp_free(uqp, uctxt); 871 } 872 873 if (rc) { 874 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 875 "destroy_qp() - ibt_free_qp() fail %d", rc); 876 rc = sol_uverbs_ibt_to_kernel_status(rc); 877 goto err_out; 878 } 879 880 report_qp_evts: 881 #ifdef _LP64 882 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 883 #else 884 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 885 #endif 886 if (rc != 0) { 887 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 888 "destroy_qp() : copyout failure %x", rc); 889 rc = EFAULT; 890 goto err_out; 891 } 892 893 return (DDI_SUCCESS); 894 895 err_busy: 896 sol_ofs_uobj_put(&uqp->uobj); 897 898 err_out: 899 return (rc); 900 } 901 902 /* 903 * Function: 904 * uverbs_copy_path_info_from_ibv 905 * Input: 906 * src_path - IB OFED path. 907 * Output: 908 * dest_path - IBT path. 909 * Returns: 910 * None 911 * Description: 912 * Helper to copy from the OFED path format to IBT path format. 913 */ 914 static void 915 uverbs_copy_path_info_from_ibv(struct ib_uverbs_qp_dest *src_path, 916 ibt_cep_path_t *dest_path) 917 { 918 ASSERT(src_path != NULL); 919 ASSERT(dest_path != NULL); 920 921 (void) memcpy(&dest_path->cep_adds_vect.av_dgid, 922 &src_path->dgid[0], sizeof (src_path->dgid)); 923 924 dest_path->cep_adds_vect.av_flow = src_path->flow_label; 925 dest_path->cep_adds_vect.av_dlid = src_path->dlid; 926 dest_path->cep_adds_vect.av_hop = src_path->hop_limit; 927 dest_path->cep_adds_vect.av_tclass = src_path->traffic_class; 928 dest_path->cep_adds_vect.av_srvl = src_path->sl & 0x0f; 929 dest_path->cep_adds_vect.av_port_num = src_path->port_num; 930 dest_path->cep_adds_vect.av_src_path = src_path->src_path_bits; 931 dest_path->cep_adds_vect.av_send_grh = src_path->is_global; 932 dest_path->cep_adds_vect.av_sgid_ix = src_path->sgid_index; 933 dest_path->cep_adds_vect.av_srate = src_path->static_rate; 934 } 935 936 /* 937 * Function: 938 * uverbs_modify_update 939 * Input: 940 * cmd - The user verbs modify command to be translated. 941 * cur_state - The current QP state 942 * new_state - The new QP state 943 * Output: 944 * qp_query_attr - The IBT QP attributes. 945 * flags - The IBT flags. 946 * Returns: 947 * None 948 * Description: 949 * Helper to convert OFED user verbs QP modify attributes to IBT 950 * QP modify attributes. Note that on required parameters, the 951 * individual IBT modify flags are not set (there is a global 952 * flag for the transition), only optional flags are set. 953 */ 954 static void 955 uverbs_modify_update(struct ib_uverbs_modify_qp *cmd, 956 enum ib_qp_state cur_state, enum ib_qp_state new_state, 957 ibt_qp_query_attr_t *qp_query_attr, ibt_cep_modify_flags_t *flags) 958 { 959 ibt_qp_info_t *qp_infop; 960 ibt_qp_rc_attr_t *rcp; 961 ibt_qp_uc_attr_t *ucp; 962 ibt_qp_ud_attr_t *udp; 963 964 *flags = IBT_CEP_SET_NOTHING; 965 qp_infop = &(qp_query_attr->qp_info); 966 rcp = &(qp_infop->qp_transport.rc); 967 ucp = &(qp_infop->qp_transport.uc); 968 udp = &(qp_infop->qp_transport.ud); 969 970 switch (cur_state) { 971 case IB_QPS_RESET: 972 qp_infop->qp_current_state = IBT_STATE_RESET; 973 break; 974 case IB_QPS_INIT: 975 qp_infop->qp_current_state = IBT_STATE_INIT; 976 break; 977 case IB_QPS_RTR: 978 qp_infop->qp_current_state = IBT_STATE_RTR; 979 break; 980 case IB_QPS_RTS: 981 qp_infop->qp_current_state = IBT_STATE_RTS; 982 break; 983 case IB_QPS_SQD: 984 qp_infop->qp_current_state = IBT_STATE_SQD; 985 break; 986 case IB_QPS_SQE: 987 qp_infop->qp_current_state = IBT_STATE_SQE; 988 break; 989 case IB_QPS_ERR: 990 qp_infop->qp_current_state = IBT_STATE_ERROR; 991 break; 992 } 993 994 if (cmd->attr_mask & IB_QP_STATE) { 995 switch (new_state) { 996 case IB_QPS_RESET: 997 qp_infop->qp_state = IBT_STATE_RESET; 998 *flags |= IBT_CEP_SET_STATE; 999 break; 1000 1001 case IB_QPS_INIT: 1002 qp_infop->qp_state = IBT_STATE_INIT; 1003 if (cur_state == IB_QPS_RESET) { 1004 *flags |= IBT_CEP_SET_RESET_INIT; 1005 } else { 1006 *flags |= IBT_CEP_SET_STATE; 1007 } 1008 break; 1009 1010 case IB_QPS_RTR: 1011 qp_infop->qp_state = IBT_STATE_RTR; 1012 if (cur_state == IB_QPS_INIT) { 1013 *flags |= IBT_CEP_SET_INIT_RTR; 1014 } else { 1015 *flags |= IBT_CEP_SET_STATE; 1016 } 1017 break; 1018 1019 case IB_QPS_RTS: 1020 qp_infop->qp_state = IBT_STATE_RTS; 1021 1022 /* 1023 * For RTS transitions other than RTR we must 1024 * specify the assumption for the qp state. 1025 */ 1026 if (cur_state == IB_QPS_RTR) { 1027 *flags |= IBT_CEP_SET_RTR_RTS; 1028 } else { 1029 ibt_cep_state_t *ibt_curr = 1030 &qp_infop->qp_current_state; 1031 1032 switch (cur_state) { 1033 case IB_QPS_RTS: 1034 *ibt_curr = IBT_STATE_RTS; 1035 break; 1036 1037 case IB_QPS_SQD: 1038 *ibt_curr = IBT_STATE_SQD; 1039 break; 1040 1041 case IB_QPS_SQE: 1042 *ibt_curr = IBT_STATE_SQE; 1043 break; 1044 } 1045 *flags |= IBT_CEP_SET_STATE; 1046 } 1047 break; 1048 1049 case IB_QPS_SQD: 1050 qp_infop->qp_state = IBT_STATE_SQD; 1051 *flags |= IBT_CEP_SET_STATE; 1052 break; 1053 1054 case IB_QPS_SQE: 1055 qp_infop->qp_state = IBT_STATE_SQE; 1056 *flags |= IBT_CEP_SET_STATE; 1057 break; 1058 1059 case IB_QPS_ERR: 1060 qp_infop->qp_state = IBT_STATE_ERROR; 1061 *flags |= IBT_CEP_SET_STATE; 1062 break; 1063 } 1064 } 1065 1066 if (cmd->attr_mask & IB_QP_PKEY_INDEX) { 1067 if (qp_infop->qp_trans == IBT_UD_SRV) { 1068 udp->ud_pkey_ix = cmd->pkey_index; 1069 } else if (qp_infop->qp_trans == IBT_RC_SRV) { 1070 rcp->rc_path.cep_pkey_ix = cmd->pkey_index; 1071 } 1072 *flags |= IBT_CEP_SET_PKEY_IX; 1073 } 1074 1075 1076 if (cmd->attr_mask & IB_QP_AV) { 1077 if (qp_infop->qp_trans == IBT_RC_SRV) { 1078 uverbs_copy_path_info_from_ibv(&cmd->dest, 1079 &rcp->rc_path); 1080 } 1081 *flags |= IBT_CEP_SET_ADDS_VECT; 1082 } 1083 1084 if (qp_infop->qp_trans == IBT_RC_SRV) { 1085 if (cmd->attr_mask & IB_QP_TIMEOUT) { 1086 rcp->rc_path.cep_timeout = cmd->timeout; 1087 *flags |= IBT_CEP_SET_TIMEOUT; 1088 } 1089 } 1090 1091 if (cmd->attr_mask & IB_QP_PORT) { 1092 if (qp_infop->qp_trans == IBT_UD_SRV) { 1093 udp->ud_port = cmd->port_num; 1094 } else if (qp_infop->qp_trans == IBT_RC_SRV) { 1095 rcp->rc_path.cep_hca_port_num = cmd->port_num; 1096 } 1097 *flags |= IBT_CEP_SET_PORT; 1098 } 1099 1100 if (cmd->attr_mask & IB_QP_QKEY) { 1101 if (qp_infop->qp_trans == IBT_UD_SRV) { 1102 udp->ud_qkey = cmd->qkey; 1103 } 1104 if (qp_infop->qp_trans == IBT_RD_SRV) { 1105 qp_infop->qp_transport.rd.rd_qkey = cmd->qkey; 1106 } 1107 *flags |= IBT_CEP_SET_QKEY; 1108 } 1109 1110 if (cmd->attr_mask & IB_QP_PATH_MTU) { 1111 if (qp_infop->qp_trans == IBT_UC_SRV) { 1112 ucp->uc_path_mtu = cmd->path_mtu; 1113 } 1114 if (qp_infop->qp_trans == IBT_RC_SRV) { 1115 rcp->rc_path_mtu = cmd->path_mtu; 1116 } 1117 } 1118 1119 if (cmd->attr_mask & IB_QP_RETRY_CNT) { 1120 if (qp_infop->qp_trans == IBT_RC_SRV) { 1121 rcp->rc_retry_cnt = cmd->retry_cnt & 0x7; 1122 } 1123 *flags |= IBT_CEP_SET_RETRY; 1124 } 1125 1126 if (cmd->attr_mask & IB_QP_RNR_RETRY) { 1127 if (qp_infop->qp_trans == IBT_RC_SRV) { 1128 rcp->rc_rnr_retry_cnt = cmd->rnr_retry; 1129 } 1130 *flags |= IBT_CEP_SET_RNR_NAK_RETRY; 1131 } 1132 1133 if (cmd->attr_mask & IB_QP_MIN_RNR_TIMER) { 1134 if (qp_infop->qp_trans == IBT_RC_SRV) { 1135 rcp->rc_min_rnr_nak = cmd->min_rnr_timer; 1136 } 1137 *flags |= IBT_CEP_SET_MIN_RNR_NAK; 1138 } 1139 1140 if (cmd->attr_mask & IB_QP_RQ_PSN) { 1141 if (qp_infop->qp_trans == IBT_RC_SRV) { 1142 rcp->rc_rq_psn = cmd->rq_psn; 1143 } 1144 if (qp_infop->qp_trans == IBT_UC_SRV) { 1145 ucp->uc_rq_psn = cmd->rq_psn; 1146 } 1147 } 1148 1149 if (cmd->attr_mask & IB_QP_ALT_PATH) { 1150 if (qp_infop->qp_trans == IBT_RC_SRV) { 1151 uverbs_copy_path_info_from_ibv(&cmd->alt_dest, 1152 &rcp->rc_alt_path); 1153 1154 rcp->rc_alt_path.cep_hca_port_num = cmd->alt_port_num; 1155 rcp->rc_alt_path.cep_timeout = cmd->alt_timeout; 1156 } 1157 1158 if (qp_infop->qp_trans == IBT_UC_SRV) { 1159 uverbs_copy_path_info_from_ibv(&cmd->alt_dest, 1160 &ucp->uc_alt_path); 1161 1162 ucp->uc_alt_path.cep_hca_port_num = cmd->alt_port_num; 1163 ucp->uc_alt_path.cep_timeout = cmd->alt_timeout; 1164 } 1165 1166 *flags |= IBT_CEP_SET_ALT_PATH; 1167 } 1168 1169 1170 if (cmd->attr_mask & IB_QP_SQ_PSN) { 1171 if (qp_infop->qp_trans == IBT_UD_SRV) { 1172 udp->ud_sq_psn = cmd->sq_psn; 1173 } 1174 if (qp_infop->qp_trans == IBT_UC_SRV) { 1175 ucp->uc_sq_psn = cmd->sq_psn; 1176 } 1177 if (qp_infop->qp_trans == IBT_RC_SRV) { 1178 rcp->rc_sq_psn = cmd->sq_psn; 1179 } 1180 } 1181 1182 if (cmd->attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { 1183 if (qp_infop->qp_trans == IBT_RC_SRV) { 1184 rcp->rc_rdma_ra_out = cmd->max_rd_atomic; 1185 } 1186 *flags |= IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_STATE; 1187 } 1188 1189 if (cmd->attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { 1190 if (qp_infop->qp_trans == IBT_RC_SRV) { 1191 rcp->rc_rdma_ra_in = cmd->max_dest_rd_atomic; 1192 } 1193 *flags |= IBT_CEP_SET_RDMARA_IN | IBT_CEP_SET_STATE; 1194 } 1195 1196 if (cmd->attr_mask & (IB_QP_ACCESS_FLAGS | 1197 IB_QP_MAX_DEST_RD_ATOMIC)) { 1198 if (qp_infop->qp_trans == IBT_RC_SRV) { 1199 uint32_t access_flags = IBT_CEP_NO_FLAGS; 1200 1201 if (rcp->rc_rdma_ra_in) { 1202 access_flags |= IBT_CEP_RDMA_WR; 1203 *flags |= IBT_CEP_SET_RDMA_W; 1204 } 1205 1206 if (cmd->attr_mask & IB_QP_ACCESS_FLAGS) { 1207 if (cmd->qp_access_flags & 1208 IB_ACCESS_REMOTE_WRITE) { 1209 access_flags |= IBT_CEP_RDMA_WR; 1210 *flags |= IBT_CEP_SET_RDMA_W; 1211 } 1212 if (cmd->qp_access_flags & 1213 IB_ACCESS_REMOTE_READ) { 1214 access_flags |= IBT_CEP_RDMA_RD; 1215 *flags |= IBT_CEP_SET_RDMA_R; 1216 } 1217 if (cmd->qp_access_flags & 1218 IB_ACCESS_REMOTE_ATOMIC) { 1219 access_flags |= IBT_CEP_ATOMIC; 1220 *flags |= IBT_CEP_SET_ATOMIC; 1221 } 1222 } 1223 qp_infop->qp_flags &= ~(IBT_CEP_RDMA_WR | 1224 IBT_CEP_RDMA_RD | IBT_CEP_ATOMIC); 1225 qp_infop->qp_flags |= access_flags; 1226 } 1227 } 1228 1229 if (cmd->attr_mask & IB_QP_PATH_MIG_STATE) { 1230 if (qp_infop->qp_trans == IBT_RC_SRV) { 1231 if (cmd->path_mig_state == IB_MIG_MIGRATED) { 1232 rcp->rc_mig_state = IBT_STATE_MIGRATED; 1233 } 1234 if (cmd->path_mig_state == IB_MIG_REARM) { 1235 rcp->rc_mig_state = IBT_STATE_REARMED; 1236 } 1237 if (cmd->path_mig_state == IB_MIG_ARMED) { 1238 rcp->rc_mig_state = IBT_STATE_ARMED; 1239 } 1240 } 1241 1242 if (qp_infop->qp_trans == IBT_UC_SRV) { 1243 if (cmd->path_mig_state == IB_MIG_MIGRATED) { 1244 ucp->uc_mig_state = IBT_STATE_MIGRATED; 1245 } 1246 if (cmd->path_mig_state == IB_MIG_REARM) { 1247 ucp->uc_mig_state = IBT_STATE_REARMED; 1248 } 1249 if (cmd->path_mig_state == IB_MIG_ARMED) { 1250 ucp->uc_mig_state = IBT_STATE_ARMED; 1251 } 1252 } 1253 *flags |= IBT_CEP_SET_MIG; 1254 } 1255 1256 if (cmd->attr_mask & IB_QP_DEST_QPN) { 1257 if (qp_infop->qp_trans == IBT_RC_SRV) { 1258 rcp->rc_dst_qpn = cmd->dest_qp_num; 1259 } 1260 if (qp_infop->qp_trans == IBT_UC_SRV) { 1261 ucp->uc_dst_qpn = cmd->dest_qp_num; 1262 } 1263 } 1264 } 1265 1266 1267 static void 1268 uverbs_qp_print_path(ibt_cep_path_t *pathp) 1269 { 1270 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print_pathp %p", pathp); 1271 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "cep_pkey_ix %x, " 1272 "cep_hca_port_num %x", pathp->cep_pkey_ix, pathp->cep_hca_port_num); 1273 } 1274 1275 static void 1276 uverbs_print_query_qp(ibt_qp_hdl_t qp_hdlp) 1277 { 1278 ibt_qp_query_attr_t qp_query_attr; 1279 ibt_qp_info_t *qp_infop = &qp_query_attr.qp_info; 1280 ibt_qp_rc_attr_t *rcp = &((qp_infop->qp_transport).rc); 1281 ibt_status_t rc; 1282 1283 bzero(&qp_query_attr, sizeof (qp_query_attr)); 1284 rc = ibt_query_qp(qp_hdlp, &qp_query_attr); 1285 if (rc != IBT_SUCCESS) { 1286 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "print_query_qp -" 1287 "ibt_query_qp() failed - rc=%d", rc); 1288 return; 1289 } 1290 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print %p", qp_hdlp); 1291 1292 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_cq %p, qp_rq_cq %p, " 1293 "qp_qpn %x, qp_sq_sgl %x, qp_rq_sgl %x, qp_srq %p, qp_flags %x", 1294 qp_query_attr.qp_sq_cq, qp_query_attr.qp_rq_cq, 1295 qp_query_attr.qp_qpn, qp_query_attr.qp_sq_sgl, 1296 qp_query_attr.qp_rq_sgl, qp_query_attr.qp_srq, 1297 qp_query_attr.qp_flags); 1298 1299 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_sz %x, qp_rq_sz %x, " 1300 "qp_state %x, qp_current_state %x, qp_flags %x, qp_trans %x", 1301 qp_infop->qp_sq_sz, qp_infop->qp_rq_sz, qp_infop->qp_state, 1302 qp_infop->qp_current_state, qp_infop->qp_flags, 1303 qp_infop->qp_trans); 1304 1305 if (qp_infop->qp_trans == IBT_RC_SRV) { 1306 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "rc_sq_psn %x, rc_rq_psn %x, " 1307 "rc_dst_qpn %x, rc_mig_state %x, rc_rnr_retry_cnt %x," 1308 "rc_retry_cnt %x rc_rdma_ra_out %x, rc_rdma_ra_in %x," 1309 "rc_min_rnr_nak %x, rc_path_mtu %x", 1310 rcp->rc_sq_psn, rcp->rc_rq_psn, rcp->rc_dst_qpn, rcp->rc_mig_state, 1311 rcp->rc_rnr_retry_cnt, rcp->rc_retry_cnt, rcp->rc_rdma_ra_out, 1312 rcp->rc_rdma_ra_in, rcp->rc_min_rnr_nak, rcp->rc_path_mtu); 1313 uverbs_qp_print_path(&rcp->rc_path); 1314 uverbs_qp_print_path(&rcp->rc_alt_path); 1315 } 1316 } 1317 1318 1319 /* 1320 * Function: 1321 * sol_uverbs_modify_qp 1322 * Input: 1323 * uctxt - Pointer to the callers user context. 1324 * buf - Pointer to kernel buffer containing QP modify command. 1325 * in_len - Length in bytes of input command buffer. 1326 * out_len - Length in bytes of output response buffer. 1327 * Output: 1328 * The command output buffer is updated with command results. 1329 * Returns: 1330 * DDI_SUCCESS on success, else error code. 1331 * Description: 1332 * User verbs entry point to modify a device QP. 1333 */ 1334 /* ARGSUSED */ 1335 int 1336 sol_uverbs_modify_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 1337 int in_len, int out_len) 1338 { 1339 struct ib_uverbs_modify_qp cmd; 1340 uverbs_uqp_uobj_t *uqp; 1341 ibt_qp_query_attr_t qp_query_attr; 1342 ibt_cep_modify_flags_t flags; 1343 ibt_queue_sizes_t size; 1344 int rc; 1345 enum ib_qp_state cur_state, new_state; 1346 1347 (void) memcpy(&cmd, buf, sizeof (cmd)); 1348 1349 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp - qp_hdl %d, " 1350 "attr_mask %x", cmd.qp_handle, cmd.attr_mask); 1351 1352 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 1353 if (uqp == NULL) { 1354 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -" 1355 "List lookup failure"); 1356 rc = EINVAL; 1357 goto err_out; 1358 } 1359 1360 /* 1361 * Has the UCMA asked us to ignore QP modify operations? 1362 * This is required because of differences in the level of 1363 * abstraction fo CM processing between IBT and OFED. 1364 */ 1365 if (uqp->disable_qp_mod == TRUE) { 1366 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp -" 1367 "qp_mod disabled"); 1368 goto done; 1369 } 1370 1371 /* 1372 * Load the current QP attributes and then do a validation 1373 * based on OFA verbs expectations to see if the modify 1374 * should be performed. 1375 */ 1376 bzero(&qp_query_attr, sizeof (qp_query_attr)); 1377 rc = ibt_query_qp(uqp->qp, &qp_query_attr); 1378 if (rc != IBT_SUCCESS) { 1379 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -" 1380 "ibt_query_qp() failed - rc=%d", rc); 1381 rc = sol_uverbs_ibt_to_kernel_status(rc); 1382 goto err_deref; 1383 } 1384 1385 if (cmd.attr_mask & IB_QP_CUR_STATE) { 1386 cur_state = cmd.cur_qp_state; 1387 } else { 1388 cur_state = IBT_TO_OFA_QP_STATE(qp_query_attr.qp_info.qp_state); 1389 } 1390 1391 new_state = cmd.attr_mask & IB_QP_STATE ? cmd.qp_state : cur_state; 1392 1393 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp: ibt qp %p, handle " 1394 "%x, cur_state %x, new_state %x, qp_type %x, attr_mask %x", uqp->qp, 1395 cmd.qp_handle, cur_state, new_state, uqp->ofa_qp_type, 1396 cmd.attr_mask); 1397 1398 if (!uverbs_modify_qp_is_ok(cur_state, new_state, uqp->ofa_qp_type, 1399 (enum ib_qp_attr_mask *)&cmd.attr_mask)) { 1400 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp() -" 1401 "Failed modify OK test"); 1402 rc = EINVAL; 1403 goto err_deref; 1404 } 1405 1406 if (!cmd.attr_mask) { 1407 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp() -" 1408 "attr_mask after modify OK test is 0"); 1409 rc = 0; 1410 goto done; 1411 } 1412 1413 flags = 0; 1414 1415 switch (uqp->ofa_qp_type) { 1416 case IB_QPT_UC: 1417 qp_query_attr.qp_info.qp_trans = IBT_UC_SRV; 1418 break; 1419 case IB_QPT_UD: 1420 qp_query_attr.qp_info.qp_trans = IBT_UD_SRV; 1421 break; 1422 case IB_QPT_RC: 1423 qp_query_attr.qp_info.qp_trans = IBT_RC_SRV; 1424 break; 1425 default: 1426 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1427 "modify_qp: Invalid QP type"); 1428 rc = EINVAL; 1429 goto err_deref; 1430 } 1431 1432 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): qp_info.qp_flags " 1433 "before modify update = 0%08x", qp_query_attr.qp_info.qp_flags); 1434 1435 uverbs_modify_update(&cmd, cur_state, new_state, &qp_query_attr, 1436 &flags); 1437 1438 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): after " 1439 "modify_update hdl flags = 0x%08x, qp_info.qp_flags = 0%08x", 1440 flags, qp_query_attr.qp_info.qp_flags); 1441 1442 rc = ibt_modify_qp(uqp->qp, flags, &qp_query_attr.qp_info, &size); 1443 1444 if (rc != IBT_SUCCESS) { 1445 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1446 "modify_qp: Error in ibt_modify_qp() (rc=%d)", rc); 1447 uverbs_print_query_qp(uqp->qp); 1448 rc = sol_uverbs_ibt_to_kernel_status(rc); 1449 goto err_deref; 1450 } 1451 1452 done: 1453 sol_ofs_uobj_put(&uqp->uobj); 1454 return (DDI_SUCCESS); 1455 1456 err_deref: 1457 sol_ofs_uobj_put(&uqp->uobj); 1458 1459 err_out: 1460 return (rc); 1461 } 1462 1463 /* 1464 * Function: 1465 * uverbs_copy_path_info_from_ibt 1466 * Input: 1467 * src_path - The IBT path. 1468 * Output: 1469 * dest_path - The OFED user verbs path. 1470 * Returns: 1471 * None 1472 * Description: 1473 * Helper to convert IBT path to OFED user verbs path. 1474 */ 1475 static void 1476 uverbs_copy_path_info_from_ibt(ibt_cep_path_t *src_path, 1477 struct ib_uverbs_qp_dest *dest_path) 1478 { 1479 ASSERT(src_path != NULL); 1480 ASSERT(dest_path != NULL); 1481 1482 (void) memcpy(&dest_path->dgid[0], 1483 &src_path->cep_adds_vect.av_dgid, sizeof (dest_path->dgid)); 1484 1485 dest_path->flow_label = src_path->cep_adds_vect.av_flow; 1486 dest_path->dlid = src_path->cep_adds_vect.av_dlid; 1487 dest_path->hop_limit = src_path->cep_adds_vect.av_hop; 1488 dest_path->traffic_class = src_path->cep_adds_vect.av_tclass; 1489 dest_path->sl = src_path->cep_adds_vect.av_srvl; 1490 dest_path->port_num = src_path->cep_adds_vect.av_port_num; 1491 dest_path->src_path_bits = src_path->cep_adds_vect.av_src_path; 1492 dest_path->is_global = src_path->cep_adds_vect.av_send_grh; 1493 dest_path->sgid_index = src_path->cep_adds_vect.av_sgid_ix; 1494 dest_path->static_rate = src_path->cep_adds_vect.av_srate; 1495 } 1496 1497 /* 1498 * Function: 1499 * uverbs_query_copy_rc 1500 * Input: 1501 * src - The IBT RC QP attributes. 1502 * Output: 1503 * dest - The OFED user verbs QP attributes. 1504 * Returns: 1505 * None 1506 * Description: 1507 * Helper to copy IBT RC QP attributes to OFED QP attributes. 1508 */ 1509 static void 1510 uverbs_query_copy_rc(struct ib_uverbs_query_qp_resp *dest, 1511 ibt_qp_rc_attr_t *src) 1512 { 1513 dest->sq_psn = src->rc_sq_psn; 1514 dest->rq_psn = src->rc_rq_psn; 1515 dest->dest_qp_num = src->rc_dst_qpn; 1516 dest->rnr_retry = src->rc_rnr_retry_cnt; 1517 dest->retry_cnt = src->rc_retry_cnt; 1518 dest->max_dest_rd_atomic = src->rc_rdma_ra_in; 1519 dest->max_rd_atomic = src->rc_rdma_ra_out; 1520 dest->min_rnr_timer = src->rc_min_rnr_nak; 1521 dest->path_mtu = src->rc_path_mtu; 1522 dest->timeout = src->rc_path.cep_timeout; 1523 dest->alt_timeout = src->rc_alt_path.cep_timeout; 1524 dest->port_num = src->rc_path.cep_hca_port_num; 1525 dest->alt_port_num = src->rc_alt_path.cep_hca_port_num; 1526 1527 if (src->rc_mig_state == IBT_STATE_MIGRATED) { 1528 dest->path_mig_state = IB_MIG_MIGRATED; 1529 } 1530 if (src->rc_mig_state == IBT_STATE_REARMED) { 1531 dest->path_mig_state = IB_MIG_REARM; 1532 } 1533 if (src->rc_mig_state == IBT_STATE_ARMED) { 1534 dest->path_mig_state = IB_MIG_ARMED; 1535 } 1536 1537 uverbs_copy_path_info_from_ibt(&src->rc_path, &dest->dest); 1538 uverbs_copy_path_info_from_ibt(&src->rc_alt_path, &dest->alt_dest); 1539 } 1540 1541 /* 1542 * Function: 1543 * uverbs_query_copy_uc 1544 * Input: 1545 * src - The IBT UC QP attributes. 1546 * Output: 1547 * dest - The OFED user verbs QP attributes. 1548 * Returns: 1549 * None 1550 * Description: 1551 * Helper to copy IBT UC QP attributes to OFED user verbs 1552 * QP attributes. 1553 */ 1554 static void 1555 uverbs_query_copy_uc(struct ib_uverbs_query_qp_resp *dest, 1556 ibt_qp_uc_attr_t *src) 1557 { 1558 dest->sq_psn = src->uc_sq_psn; 1559 dest->rq_psn = src->uc_rq_psn; 1560 dest->dest_qp_num = src->uc_dst_qpn; 1561 dest->path_mtu = src->uc_path_mtu; 1562 1563 if (src->uc_mig_state == IBT_STATE_MIGRATED) { 1564 dest->path_mig_state = IB_MIG_MIGRATED; 1565 } 1566 if (src->uc_mig_state == IBT_STATE_REARMED) { 1567 dest->path_mig_state = IB_MIG_REARM; 1568 } 1569 if (src->uc_mig_state == IBT_STATE_ARMED) { 1570 dest->path_mig_state = IB_MIG_ARMED; 1571 } 1572 1573 uverbs_copy_path_info_from_ibt(&src->uc_path, &dest->dest); 1574 uverbs_copy_path_info_from_ibt(&src->uc_alt_path, &dest->alt_dest); 1575 } 1576 1577 /* 1578 * Function: 1579 * uverbs_query_copy_rd 1580 * Input: 1581 * src - The IBT RD QP attributes. 1582 * Output: 1583 * dest - The OFED user verbs QP attributes. 1584 * Returns: 1585 * None 1586 * Description: 1587 * Helper to copy IBT RD QP attributes to OFED user verb QP attributes. 1588 */ 1589 static void 1590 uverbs_query_copy_rd(struct ib_uverbs_query_qp_resp *dest, 1591 ibt_qp_rd_attr_t *src) 1592 { 1593 dest->qkey = src->rd_qkey; 1594 dest->min_rnr_timer = src->rd_min_rnr_nak; 1595 } 1596 1597 /* 1598 * Function: 1599 * uverbs_query_copy_ud 1600 * Input: 1601 * src - The IBT UD QP attributes. 1602 * Output: 1603 * dest - The OFED user verbs QP attributes. 1604 * Returns: 1605 * None 1606 * Description: 1607 * Helper to copy IBT UD QP attributes to OFED user verbs QP attributes. 1608 */ 1609 static void 1610 uverbs_query_copy_ud(struct ib_uverbs_query_qp_resp *dest, 1611 ibt_qp_ud_attr_t *src) 1612 { 1613 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1614 "query_copy_ud:entry - return UD info: qkey:%08X, " 1615 "psn:%d, pkey_idx:%d, port:%d", src->ud_qkey, src->ud_sq_psn, 1616 src->ud_pkey_ix, src->ud_port); 1617 1618 dest->qkey = src->ud_qkey; 1619 dest->sq_psn = src->ud_sq_psn; 1620 dest->pkey_index = src->ud_pkey_ix; 1621 dest->port_num = src->ud_port; 1622 } 1623 1624 /* 1625 * Function: 1626 * uverbs_query_copy_info 1627 * Input: 1628 * src - The IBT QP information. 1629 * Output: 1630 * dest - The OFED user verbs QP attributes. 1631 * Returns: 1632 * None 1633 * Description: 1634 * Helper to copy IBT QP info to OFED user verbs QP attributes. 1635 */ 1636 static void 1637 uverbs_query_copy_info(struct ib_uverbs_query_qp_resp *dest, 1638 ibt_qp_info_t *src) 1639 { 1640 1641 dest->max_send_wr = src->qp_sq_sz; 1642 dest->max_recv_wr = src->qp_rq_sz; 1643 dest->qp_access_flags = ibt_cep_flags2ibv(src->qp_flags); 1644 1645 switch (src->qp_state) { 1646 case IBT_STATE_RESET: 1647 dest->qp_state = IB_QPS_RESET; 1648 break; 1649 case IBT_STATE_INIT: 1650 dest->qp_state = IB_QPS_INIT; 1651 break; 1652 case IBT_STATE_RTR: 1653 dest->qp_state = IB_QPS_RTR; 1654 break; 1655 case IBT_STATE_RTS: 1656 dest->qp_state = IB_QPS_RTS; 1657 break; 1658 case IBT_STATE_SQD: 1659 dest->qp_state = IB_QPS_SQD; 1660 break; 1661 case IBT_STATE_SQE: 1662 dest->qp_state = IB_QPS_SQE; 1663 break; 1664 case IBT_STATE_ERROR: 1665 default: 1666 dest->qp_state = IB_QPS_ERR; 1667 break; 1668 } 1669 1670 switch (src->qp_current_state) { 1671 case IBT_STATE_RESET: 1672 dest->cur_qp_state = IB_QPS_RESET; 1673 break; 1674 case IBT_STATE_INIT: 1675 dest->cur_qp_state = IB_QPS_INIT; 1676 break; 1677 case IBT_STATE_RTR: 1678 dest->cur_qp_state = IB_QPS_RTR; 1679 break; 1680 case IBT_STATE_RTS: 1681 dest->cur_qp_state = IB_QPS_RTS; 1682 break; 1683 case IBT_STATE_SQD: 1684 dest->cur_qp_state = IB_QPS_SQD; 1685 break; 1686 case IBT_STATE_SQE: 1687 dest->cur_qp_state = IB_QPS_SQE; 1688 break; 1689 case IBT_STATE_ERROR: 1690 default: 1691 dest->cur_qp_state = IB_QPS_ERR; 1692 break; 1693 } 1694 1695 if ((src->qp_flags & IBT_ALL_SIGNALED) == IBT_ALL_SIGNALED) { 1696 dest->sq_sig_all = 1; 1697 } 1698 } 1699 1700 /* 1701 * Function: 1702 * uverbs_query_copy_attr 1703 * Input: 1704 * src - The IBT QP information. 1705 * Output: 1706 * dest - The OFED user verbs QP attributes. 1707 * Returns: 1708 * None 1709 * Description: 1710 * Helper to copy IBT QP attributes to OFED user verbs QP attributes. 1711 */ 1712 static void 1713 uverbs_query_copy_attr(struct ib_uverbs_query_qp_resp *dest, 1714 ibt_qp_query_attr_t *src) 1715 { 1716 dest->max_send_sge = src->qp_sq_sgl; 1717 dest->max_recv_sge = src->qp_rq_sgl; 1718 } 1719 1720 /* 1721 * Function: 1722 * sol_uverbs_query_qp 1723 * Input: 1724 * uctxt - Pointer to the callers user context. 1725 * buf - Pointer to kernel buffer containing query QP command. 1726 * in_len - Length in bytes of input command buffer. 1727 * out_len - Length in bytes of output response buffer. 1728 * Output: 1729 * The command output buffer is updated with command results. 1730 * Returns: 1731 * DDI_SUCCESS on success, else error code. 1732 * Description: 1733 * User verbs entry point to query a device QP properties. 1734 */ 1735 /* ARGSUSED */ 1736 int 1737 sol_uverbs_query_qp(uverbs_uctxt_uobj_t *uctxt, char *buf, 1738 int in_len, int out_len) 1739 { 1740 struct ib_uverbs_query_qp cmd; 1741 struct ib_uverbs_query_qp_resp resp; 1742 uverbs_uqp_uobj_t *uqp; 1743 ibt_qp_query_attr_t qp_query_attr; 1744 int rc; 1745 1746 (void) memset(&resp, 0, sizeof (resp)); 1747 (void) memcpy(&cmd, buf, sizeof (cmd)); 1748 1749 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1750 "query_qp: entry (qp_handle=%d)", cmd.qp_handle); 1751 1752 uqp = uverbs_uobj_get_uqp_read(cmd.qp_handle); 1753 if (uqp == NULL) { 1754 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1755 "query_qp(): List lookup failure"); 1756 rc = EINVAL; 1757 goto err_out; 1758 } 1759 1760 bzero(&qp_query_attr, sizeof (qp_query_attr)); 1761 rc = ibt_query_qp(uqp->qp, &qp_query_attr); 1762 sol_ofs_uobj_put(&uqp->uobj); 1763 1764 if (rc != IBT_SUCCESS) { 1765 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1766 "query_qp: Error in ibt_query_qp() (rc=%d)", rc); 1767 rc = sol_uverbs_ibt_to_kernel_status(rc); 1768 goto err_out; 1769 } 1770 1771 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1772 "query_qp(): qp_query_attr.qp_info.qp_trans = %d", 1773 qp_query_attr.qp_info.qp_trans); 1774 1775 uverbs_query_copy_attr(&resp, &qp_query_attr); 1776 uverbs_query_copy_info(&resp, &qp_query_attr.qp_info); 1777 1778 if (qp_query_attr.qp_info.qp_trans == IBT_RC_SRV) { 1779 uverbs_query_copy_rc(&resp, 1780 &qp_query_attr.qp_info.qp_transport.rc); 1781 } 1782 1783 if (qp_query_attr.qp_info.qp_trans == IBT_UC_SRV) { 1784 uverbs_query_copy_uc(&resp, 1785 &qp_query_attr.qp_info.qp_transport.uc); 1786 } 1787 1788 if (qp_query_attr.qp_info.qp_trans == IBT_RD_SRV) { 1789 uverbs_query_copy_rd(&resp, 1790 &qp_query_attr.qp_info.qp_transport.rd); 1791 } 1792 1793 1794 if (qp_query_attr.qp_info.qp_trans == IBT_UD_SRV) { 1795 uverbs_query_copy_ud(&resp, 1796 &qp_query_attr.qp_info.qp_transport.ud); 1797 } 1798 1799 resp.max_inline_data = uqp->max_inline_data; 1800 1801 #ifdef _LP64 1802 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 1803 #else 1804 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 1805 #endif 1806 if (rc != 0) { 1807 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1808 "query_qp(): Error writing resp data (rc=%d)", rc); 1809 rc = EFAULT; 1810 goto err_out; 1811 } 1812 1813 return (DDI_SUCCESS); 1814 1815 err_out: 1816 return (rc); 1817 } 1818 1819 /* 1820 * Function: 1821 * sol_uverbs_create_srq 1822 * Input: 1823 * uctxt - Pointer to the callers user context. 1824 * buf - Pointer to kernel buffer containing command. 1825 * in_len - Length in bytes of input command buffer. 1826 * out_len - Length in bytes of output response buffer. 1827 * Output: 1828 * The command output buffer is updated with command results. 1829 * Returns: 1830 * DDI_SUCCESS on success, else error code. 1831 * Description: 1832 * User verbs entry point to create a device shared receive queue. 1833 */ 1834 /* ARGSUSED */ 1835 int 1836 sol_uverbs_create_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 1837 int in_len, int out_len) 1838 { 1839 struct ib_uverbs_create_srq cmd; 1840 struct ib_uverbs_create_srq_resp resp; 1841 uverbs_usrq_uobj_t *usrq; 1842 uverbs_upd_uobj_t *upd; 1843 ibt_srq_flags_t flags = IBT_SRQ_USER_MAP; 1844 ibt_srq_sizes_t attr; 1845 ibt_srq_sizes_t real_attr; 1846 int rc; 1847 1848 (void) memcpy(&cmd, buf, sizeof (cmd)); 1849 (void) memset(&resp, 0, sizeof (resp)); 1850 (void) memset(&attr, 0, sizeof (attr)); 1851 1852 attr.srq_wr_sz = cmd.max_wr; 1853 attr.srq_sgl_sz = cmd.max_sge; 1854 1855 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_srq: " 1856 "max_wr=%d, max_sge=%d, srq_limit=%d", 1857 cmd.max_wr, cmd.max_sge, cmd.srq_limit); 1858 1859 if (!attr.srq_wr_sz) { 1860 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1861 "create_srq(): Invalid args, invalid work " 1862 "request size"); 1863 1864 rc = EINVAL; 1865 goto err_out; 1866 } 1867 1868 if (attr.srq_wr_sz > uctxt->hca->attr.hca_max_srqs_sz || 1869 attr.srq_sgl_sz > uctxt->hca->attr.hca_max_srq_sgl) { 1870 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1871 "create_srq(): Invalid args, too large"); 1872 rc = EINVAL; 1873 goto err_out; 1874 } 1875 1876 usrq = kmem_zalloc(sizeof (*usrq), KM_NOSLEEP); 1877 if (usrq == NULL) { 1878 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1879 "create_srq(): User object alloc failed"); 1880 rc = ENOMEM; 1881 goto err_out; 1882 } 1883 sol_ofs_uobj_init(&usrq->uobj, cmd.user_handle, 1884 SOL_UVERBS_USRQ_UOBJ_TYPE); 1885 rw_enter(&usrq->uobj.uo_lock, RW_WRITER); 1886 llist_head_init(&usrq->async_list, NULL); 1887 usrq->async_events_reported = 0; 1888 usrq->uctxt = uctxt; 1889 1890 upd = uverbs_uobj_get_upd_read(cmd.pd_handle); 1891 if (upd == NULL) { 1892 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1893 "create_srq(): PD Invalid"); 1894 rc = EINVAL; 1895 goto err_dealloc; 1896 } 1897 1898 rc = ibt_alloc_srq(uctxt->hca->hdl, flags, upd->pd, &attr, &usrq->srq, 1899 &real_attr); 1900 1901 if (rc != IBT_SUCCESS) { 1902 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1903 "create_srq(): Error in ibt_alloc_srq() (rc=%d)", rc); 1904 usrq->srq = NULL; 1905 rc = sol_uverbs_ibt_to_kernel_status(rc); 1906 usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t); 1907 goto err_release_pd; 1908 } 1909 1910 ibt_set_srq_private(usrq->srq, usrq); 1911 1912 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1913 "create_srq(): ib_alloc_srq()real wqe_sz=%d, real_sg_sz=%d", 1914 real_attr.srq_wr_sz, real_attr.srq_sgl_sz); 1915 1916 /* 1917 * Query underlying hardware for data used in mapping CQ back to user 1918 * space, we will return this information in the user verbs command 1919 * response. 1920 */ 1921 rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_SRQ, 1922 (void *)usrq->srq, &resp.drv_out, sizeof (resp.drv_out)); 1923 1924 if (rc != IBT_SUCCESS) { 1925 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1926 "create_srq(): Error in ibt_ci_data_out() (rc=%d)", rc); 1927 rc = EFAULT; 1928 usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t); 1929 goto err_srq_destroy; 1930 } 1931 1932 if (sol_ofs_uobj_add(&uverbs_usrq_uo_tbl, &usrq->uobj) != 0) { 1933 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1934 "create_srq(): uobj add failed"); 1935 rc = ENOMEM; 1936 goto err_srq_destroy; 1937 } 1938 1939 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 1940 "create_srq(): ibt_ci_data_out: 0x%16llx 0x%16llx 0x%16llx " 1941 "0x%16llx", resp.drv_out[0], resp.drv_out[1], resp.drv_out[2], 1942 resp.drv_out[3]); 1943 1944 resp.srq_handle = usrq->uobj.uo_id; 1945 resp.max_wr = real_attr.srq_wr_sz; 1946 resp.max_sge = real_attr.srq_sgl_sz; 1947 1948 #ifdef _LP64 1949 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 1950 #else 1951 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 1952 #endif 1953 if (rc != 0) { 1954 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1955 "create_srq(): Error writing resp data (rc=%d)", rc); 1956 rc = EFAULT; 1957 goto err_uo_delete; 1958 } 1959 1960 mutex_enter(&uctxt->lock); 1961 usrq->list_entry = add_genlist(&uctxt->srq_list, (uintptr_t)usrq, 1962 uctxt); 1963 mutex_exit(&uctxt->lock); 1964 1965 if (!usrq->list_entry) { 1966 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 1967 "create_srq() : Error adding usrq to srq_list failed"); 1968 rc = ENOMEM; 1969 goto err_uo_delete; 1970 } 1971 1972 usrq->uobj.uo_live = 1; 1973 rw_exit(&usrq->uobj.uo_lock); 1974 1975 sol_ofs_uobj_put(&upd->uobj); 1976 1977 return (DDI_SUCCESS); 1978 1979 err_uo_delete: 1980 /* 1981 * Need to set uo_live, so sol_ofs_uobj_remove() will 1982 * remove the object from the object table. 1983 */ 1984 usrq->uobj.uo_live = 1; 1985 (void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj); 1986 1987 err_srq_destroy: 1988 (void) ibt_free_srq(usrq->srq); 1989 1990 err_release_pd: 1991 sol_ofs_uobj_put(&upd->uobj); 1992 1993 err_dealloc: 1994 rw_exit(&usrq->uobj.uo_lock); 1995 sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free); 1996 1997 err_out: 1998 return (rc); 1999 } 2000 2001 /* 2002 * Function: 2003 * sol_uverbs_modify_srq 2004 * Input: 2005 * uctxt - Pointer to the callers user context. 2006 * buf - Pointer to kernel buffer containing SRQ modify command. 2007 * in_len - Length in bytes of input command buffer. 2008 * out_len - Length in bytes of output response buffer. 2009 * Output: 2010 * The command output buffer is updated with command results. 2011 * Returns: 2012 * DDI_SUCCESS on success, else error code. 2013 * Description: 2014 * User verbs entry point to modify a device shared receive queue. 2015 */ 2016 /* ARGSUSED */ 2017 int 2018 sol_uverbs_modify_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 2019 int in_len, int out_len) 2020 { 2021 struct ib_uverbs_modify_srq cmd; 2022 uverbs_usrq_uobj_t *usrq; 2023 uint_t limit = 0; 2024 uint_t size = 0; 2025 uint_t real_size = 0; 2026 ibt_srq_modify_flags_t flags = 0; 2027 int rc; 2028 2029 (void) memcpy(&cmd, buf, sizeof (cmd)); 2030 2031 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2032 "modify_srq(): entry (srq_handle=%d)", cmd.srq_handle); 2033 2034 usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle); 2035 if (usrq == NULL) { 2036 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2037 "modify_srq(): List lookup failure"); 2038 rc = EINVAL; 2039 goto err_out; 2040 } 2041 2042 if (cmd.attr_mask & IB_SRQ_MAX_WR) { 2043 flags = IBT_SRQ_SET_SIZE; 2044 size = cmd.max_wr; 2045 } 2046 2047 if (cmd.attr_mask & IB_SRQ_LIMIT) { 2048 flags |= IBT_SRQ_SET_LIMIT; 2049 limit = cmd.srq_limit; 2050 } 2051 2052 rc = ibt_modify_srq(usrq->srq, flags, size, limit, &real_size); 2053 if (rc != IBT_SUCCESS) { 2054 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2055 "modify_srq(): Error in ibt_modify_srq() (rc=%d)", rc); 2056 rc = sol_uverbs_ibt_to_kernel_status(rc); 2057 goto err_deref; 2058 } 2059 2060 done: 2061 sol_ofs_uobj_put(&usrq->uobj); 2062 return (DDI_SUCCESS); 2063 2064 err_deref: 2065 sol_ofs_uobj_put(&usrq->uobj); 2066 2067 err_out: 2068 return (rc); 2069 } 2070 2071 /* 2072 * Function: 2073 * sol_uverbs_query_srq 2074 * Input: 2075 * uctxt - Pointer to the callers user context. 2076 * buf - Pointer to kernel buffer containing command. 2077 * in_len - Length in bytes of input command buffer. 2078 * out_len - Length in bytes of output response buffer. 2079 * Output: 2080 * The command output buffer is updated with command results. 2081 * Returns: 2082 * DDI_SUCCESS on success, else error code. 2083 * Description: 2084 * User verbs entry point to query a device shared receive queue 2085 * properties. 2086 */ 2087 /* ARGSUSED */ 2088 int 2089 sol_uverbs_query_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 2090 int in_len, int out_len) 2091 { 2092 struct ib_uverbs_query_srq cmd; 2093 struct ib_uverbs_query_srq_resp resp; 2094 uverbs_usrq_uobj_t *usrq; 2095 ibt_pd_hdl_t pd; 2096 int rc; 2097 ibt_srq_sizes_t attr; 2098 uint_t limit; 2099 2100 (void) memcpy(&cmd, buf, sizeof (cmd)); 2101 (void) memset(&resp, 0, sizeof (resp)); 2102 2103 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2104 "query_srq(): entry (srq_handle=%d)", cmd.srq_handle); 2105 2106 usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle); 2107 if (usrq == NULL) { 2108 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2109 "query_srq(): Invalid handle: %d", cmd.srq_handle); 2110 rc = EINVAL; 2111 goto err_out; 2112 } 2113 2114 rc = ibt_query_srq(usrq->srq, &pd, &attr, &limit); 2115 sol_ofs_uobj_put(&usrq->uobj); 2116 2117 if (rc != IBT_SUCCESS) { 2118 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2119 "query_srq(): Error in ibt_query_srq() (rc=%d)", rc); 2120 rc = sol_uverbs_ibt_to_kernel_status(rc); 2121 goto err_out; 2122 } 2123 2124 resp.max_wr = attr.srq_wr_sz; 2125 resp.max_sge = attr.srq_sgl_sz; 2126 resp.srq_limit = limit; 2127 2128 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_srq() - " 2129 "max_wr=%d, max_sge=%d, limit=%d", resp.max_wr, 2130 resp.max_sge, resp.srq_limit); 2131 2132 /* 2133 * Release the reference from the find above, we leave the initial 2134 * reference placed at SRQ creation time. 2135 */ 2136 2137 #ifdef _LP64 2138 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 2139 #else 2140 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 2141 #endif 2142 if (rc != 0) { 2143 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "query_srq() - " 2144 "copyout failure %x", rc); 2145 rc = EFAULT; 2146 goto err_out; 2147 } 2148 2149 return (DDI_SUCCESS); 2150 2151 err_out: 2152 return (rc); 2153 } 2154 2155 int 2156 uverbs_usrq_free(uverbs_usrq_uobj_t *usrq, uverbs_uctxt_uobj_t *uctxt) 2157 { 2158 int rc; 2159 2160 if (!usrq->srq) 2161 goto skip_ibt_free_srq; 2162 2163 rc = ibt_free_srq(usrq->srq); 2164 if (rc != IBT_SUCCESS) { 2165 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "usrq_free() - " 2166 "Error in ibt_free_srq() (rc=%d)", rc); 2167 rc = sol_uverbs_ibt_to_kernel_status(rc); 2168 sol_ofs_uobj_put(&usrq->uobj); 2169 return (rc); 2170 } 2171 usrq->srq = NULL; 2172 2173 skip_ibt_free_srq : 2174 sol_ofs_uobj_put(&usrq->uobj); 2175 if (usrq->list_entry) { 2176 mutex_enter(&uctxt->lock); 2177 delete_genlist(&uctxt->srq_list, usrq->list_entry); 2178 mutex_exit(&uctxt->lock); 2179 (void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj); 2180 } 2181 sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free); 2182 2183 return (0); 2184 } 2185 2186 /* 2187 * Function: 2188 * sol_uverbs_destroy_srq 2189 * Input: 2190 * uctxt - Pointer to the callers user context. 2191 * buf - Pointer to kernel buffer containing command. 2192 * in_len - Length in bytes of input command buffer. 2193 * out_len - Length in bytes of output response buffer. 2194 * Output: 2195 * The command output buffer is updated with command results. 2196 * Returns: 2197 * DDI_SUCCESS on success, else error code. 2198 * Description: 2199 * User verbs entry point to destroy a device shared receive queue. 2200 */ 2201 /* ARGSUSED */ 2202 int 2203 sol_uverbs_destroy_srq(uverbs_uctxt_uobj_t *uctxt, char *buf, 2204 int in_len, int out_len) 2205 { 2206 struct ib_uverbs_destroy_srq cmd; 2207 struct ib_uverbs_destroy_srq_resp resp; 2208 uverbs_usrq_uobj_t *usrq; 2209 int rc; 2210 2211 (void) memcpy(&cmd, buf, sizeof (cmd)); 2212 (void) memset(&resp, 0, sizeof (resp)); 2213 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "destroy_srq() - " 2214 "srq_handle %d", cmd.srq_handle); 2215 2216 usrq = uverbs_uobj_get_usrq_write(cmd.srq_handle); 2217 if (usrq == NULL) { 2218 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2219 "destroy_srq() : inavlid hdl %d", cmd.srq_handle); 2220 rc = EINVAL; 2221 goto err_out; 2222 } 2223 2224 uverbs_release_usrq_uevents(uctxt->async_evfile, usrq); 2225 resp.events_reported = usrq->async_events_reported; 2226 if (usrq->active_qp_cnt) { 2227 sol_ofs_uobj_put(&usrq->uobj); 2228 return (EBUSY); 2229 } else { 2230 rc = uverbs_usrq_free(usrq, uctxt); 2231 if (rc) 2232 goto err_out; 2233 } 2234 2235 #ifdef _LP64 2236 rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp)); 2237 #else 2238 rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp)); 2239 #endif 2240 if (rc != 0) { 2241 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2242 "destroy_srq() : copyout failure %x", rc); 2243 rc = EFAULT; 2244 goto err_out; 2245 } 2246 2247 return (DDI_SUCCESS); 2248 2249 err_out: 2250 return (rc); 2251 } 2252 2253 /* 2254 * Function: 2255 * sol_uverbs_attach_mcast 2256 * Input: 2257 * uctxt - Pointer to the callers user context. 2258 * buf - Pointer to kernel buffer containing command. 2259 * in_len - Length in bytes of input command buffer. 2260 * out_len - Length in bytes of output response buffer. 2261 * Output: 2262 * The command output buffer is updated with command results. 2263 * Returns: 2264 * DDI_SUCCESS on success, else error code. 2265 * Description: 2266 * User verbs entry point to attach a QP to a multicast group 2267 */ 2268 /* ARGSUSED */ 2269 int 2270 sol_uverbs_attach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf, 2271 int in_len, int out_len) 2272 { 2273 struct ib_uverbs_attach_mcast cmd; 2274 uverbs_uqp_uobj_t *uqp; 2275 uverbs_mcast_entry_t *mc; 2276 llist_head_t *entry; 2277 int rc; 2278 ib_gid_t mc_gid; 2279 2280 (void) memcpy(&cmd, buf, sizeof (cmd)); 2281 2282 /* 2283 * API specifies gid in network order, Solaris expects the gid 2284 * in host order, do the conversion if required. 2285 */ 2286 mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0])); 2287 mc_gid.gid_guid = b2h64(*((uint64_t *)&cmd.gid[8])); 2288 2289 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "attach_mcast(qp_handle=%d, " 2290 "mlid=0x%04x, gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid, 2291 mc_gid.gid_prefix, mc_gid.gid_guid); 2292 2293 /* 2294 * Take object write to protect MC list. 2295 */ 2296 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 2297 if (uqp == NULL) { 2298 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2299 "attach_mcast QP not found"); 2300 rc = EINVAL; 2301 goto err_out; 2302 } 2303 2304 /* 2305 * Look to see if we are already attached and if so no need to attach 2306 * again, just return good status. 2307 */ 2308 list_for_each(entry, &uqp->mcast_list) { 2309 mc = (uverbs_mcast_entry_t *)entry->ptr; 2310 2311 if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid && 2312 !memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid, 2313 sizeof (mc_gid.gid))) { 2314 SOL_OFS_DPRINTF_L4(sol_uverbs_dbg_str, 2315 "attach_mcast: match entry found"); 2316 rc = DDI_SUCCESS; 2317 goto out_put; 2318 } 2319 } 2320 2321 mc = kmem_zalloc(sizeof (*mc), KM_NOSLEEP); 2322 if (mc == NULL) { 2323 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2324 "attach_mcast: kmem_zalloc fail"); 2325 rc = ENOMEM; 2326 goto out_put; 2327 } 2328 2329 llist_head_init(&mc->list, mc); 2330 mc->mcg.mc_adds_vect.av_dlid = cmd.mlid; 2331 bcopy(&mc_gid, &(mc->mcg.mc_adds_vect.av_dgid), sizeof (mc_gid)); 2332 2333 rc = ibt_attach_mcg(uqp->qp, &mc->mcg); 2334 if (rc != IBT_SUCCESS) { 2335 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2336 "attach_mcast: ibt_attach_mcq failed (r=%d)", rc); 2337 rc = sol_uverbs_ibt_to_kernel_status(rc); 2338 goto err_free; 2339 } 2340 2341 llist_add_tail(&mc->list, &uqp->mcast_list); 2342 sol_ofs_uobj_put(&uqp->uobj); 2343 2344 return (DDI_SUCCESS); 2345 2346 err_free: 2347 kmem_free(mc, sizeof (*mc)); 2348 out_put: 2349 sol_ofs_uobj_put(&uqp->uobj); 2350 err_out: 2351 return (rc); 2352 } 2353 2354 /* 2355 * Function: 2356 * sol_uverbs_detach_mcast 2357 * Input: 2358 * uctxt - Pointer to the callers user context. 2359 * buf - Pointer to kernel buffer containing command. 2360 * in_len - Length in bytes of input command buffer. 2361 * out_len - Length in bytes of output response buffer. 2362 * Output: 2363 * The command output buffer is updated with command results. 2364 * Returns: 2365 * DDI_SUCCESS on success, else error code. 2366 * Description: 2367 * User verbs entry point to detach a QP from a multicast group 2368 */ 2369 /* ARGSUSED */ 2370 int 2371 sol_uverbs_detach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf, 2372 int in_len, int out_len) 2373 { 2374 struct ib_uverbs_detach_mcast cmd; 2375 uverbs_uqp_uobj_t *uqp; 2376 ibt_mcg_info_t mcg; 2377 int rc; 2378 uverbs_mcast_entry_t *mc; 2379 llist_head_t *entry; 2380 llist_head_t *temp; 2381 ib_gid_t mc_gid; 2382 2383 (void) memcpy(&cmd, buf, sizeof (cmd)); 2384 2385 /* 2386 * API specifies gid in network order, Solaris expects the gid 2387 * in host order, do the conversion if required. 2388 */ 2389 mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0])); 2390 mc_gid.gid_guid = b2h64(*((uint64_t *)&cmd.gid[8])); 2391 2392 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2393 "detach_mcast: entry (qp_handle=%d, mlid=0x%04x," 2394 "gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid, mc_gid.gid_prefix, 2395 mc_gid.gid_guid); 2396 2397 (void) memset(&mcg, 0, sizeof (mcg)); 2398 2399 /* 2400 * Get object write to protect mcast list. 2401 */ 2402 uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle); 2403 if (uqp == NULL) { 2404 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2405 "detach_mcast(): QP hdl %x not found", cmd.qp_handle); 2406 rc = EINVAL; 2407 goto err_out; 2408 } 2409 2410 mcg.mc_adds_vect.av_dlid = cmd.mlid; 2411 mcg.mc_adds_vect.av_dgid = mc_gid; 2412 2413 rc = ibt_detach_mcg(uqp->qp, &mcg); 2414 if (rc != IBT_SUCCESS) { 2415 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2416 "deatch_mcast(): ibt_attach_mcq failed (r=%d)", rc); 2417 rc = sol_uverbs_ibt_to_kernel_status(rc); 2418 goto err_put; 2419 } 2420 2421 /* 2422 * Find and delete MC group from the QP multicast list. 2423 */ 2424 entry = uqp->mcast_list.nxt; 2425 temp = entry->nxt; 2426 while (entry != &uqp->mcast_list) { 2427 ASSERT(entry); 2428 mc = (uverbs_mcast_entry_t *)entry->ptr; 2429 ASSERT(mc); 2430 2431 if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid && 2432 !memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid, 2433 sizeof (mc_gid.gid))) { 2434 llist_del(&mc->list); 2435 kmem_free(mc, sizeof (*mc)); 2436 break; 2437 } 2438 entry = temp; 2439 temp = entry->nxt; 2440 } 2441 2442 sol_ofs_uobj_put(&uqp->uobj); 2443 2444 return (DDI_SUCCESS); 2445 2446 err_put: 2447 sol_ofs_uobj_put(&uqp->uobj); 2448 2449 err_out: 2450 return (rc); 2451 } 2452 2453 /* 2454 * Function: 2455 * uverbs_release_uqp_mcast_entries 2456 * Input: 2457 * uctxt - Pointer to the callers user context. 2458 * uqp - Pointer to the user QP object for which the multicast 2459 * list should be flushed. 2460 * Output: 2461 * None 2462 * Returns: 2463 * None 2464 * Description: 2465 * Release any multicast resources held by this QP. The 2466 * user context associated with the QP should be locked 2467 * externally to this routine to protect the updates to the 2468 * multicast list. 2469 */ 2470 void 2471 uverbs_detach_uqp_mcast_entries(uverbs_uqp_uobj_t *uqp) 2472 { 2473 int rc; 2474 uverbs_mcast_entry_t *mc; 2475 llist_head_t *entry; 2476 llist_head_t *temp; 2477 2478 /* 2479 * Find and delete MC group from the QP multicast list. 2480 */ 2481 entry = uqp->mcast_list.nxt; 2482 temp = entry->nxt; 2483 while (entry != &uqp->mcast_list) { 2484 ASSERT(entry); 2485 mc = (uverbs_mcast_entry_t *)entry->ptr; 2486 ASSERT(mc); 2487 2488 rc = ibt_detach_mcg(uqp->qp, &mc->mcg); 2489 if (rc != IBT_SUCCESS) { 2490 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2491 "detach_mcast() : " 2492 "ibt_detach_mcq failed (r=%d)", rc); 2493 } 2494 llist_del(&mc->list); 2495 entry = temp; 2496 temp = entry->nxt; 2497 } 2498 } 2499 2500 /* 2501 * Function: 2502 * sol_uverbs_uqpid_to_ibt_handle 2503 * Input: 2504 * uqpid - A user verbs QP id, i.e. a QP handle that was 2505 * created via libibverbs and sol_uverbs. 2506 * Output: 2507 * None 2508 * Returns: 2509 * The ibt_qp_hdl_t associated with the user space QP handle. 2510 * -1 is returned if the id is not found. 2511 * Description: 2512 * Map the user verbs QP id to the associated IBT QP handle. 2513 */ 2514 ibt_qp_hdl_t 2515 sol_uverbs_uqpid_to_ibt_handle(uint32_t uqpid) 2516 { 2517 uverbs_uqp_uobj_t *uqp; 2518 void *qphdl; 2519 2520 uqp = uverbs_uobj_get_uqp_read(uqpid); 2521 if (uqp == NULL) { 2522 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2523 "uqpid2ibthdl: QP lookup failure: id %d", uqpid); 2524 return (NULL); 2525 } 2526 qphdl = (void *)uqp->qp; 2527 sol_ofs_uobj_put(&uqp->uobj); 2528 return (qphdl); 2529 } 2530 2531 /* 2532 * Function: 2533 * sol_uverbs_disable_user_qp_modify 2534 * Input: 2535 * uqpid - A user verbs QP id, i.e. a QP handle that was 2536 * created via libibverbs and sol_uverbs. 2537 * Output: 2538 * None 2539 * Returns: 2540 * 0 on success, EINVAL if associated QP is not found. 2541 * Description: 2542 * Inform sol_uverbs driver to ignore user qp modify 2543 * operations it receives for the specified qp. To re-enable 2544 * this capability see the function sol_uverbs_enable_user_qp_modify. 2545 */ 2546 int 2547 sol_uverbs_disable_user_qp_modify(uint32_t uqpid) 2548 { 2549 uverbs_uqp_uobj_t *uqp; 2550 2551 uqp = uverbs_uobj_get_uqp_write(uqpid); 2552 if (uqp == NULL) { 2553 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2554 "disable_uqp_modify(%d) -lookup failure", uqpid); 2555 return (EINVAL); 2556 } 2557 uqp->disable_qp_mod = TRUE; 2558 sol_ofs_uobj_put(&uqp->uobj); 2559 return (0); 2560 } 2561 2562 /* 2563 * Function: 2564 * sol_uverbs_enable_user_qp_modify 2565 * Input: 2566 * uqpid - A user verbs QP id, i.e. a QP handle that was 2567 * created via libibverbs and sol_uverbs. 2568 * Output: 2569 * None 2570 * Returns: 2571 * 0 on success, EINVAL if associated QP is not found. 2572 * Description: 2573 * Inform sol_uverbs driver to process user qp modify 2574 * operations it receives for the specified qp. This is 2575 * the default and this routine need only be invoked if 2576 * user QP modify operations have explicitly been disabled 2577 * with sol_uverbs_disable_user_qp_modify. 2578 */ 2579 int 2580 sol_uverbs_enable_user_qp_modify(uint32_t uqpid) 2581 { 2582 uverbs_uqp_uobj_t *uqp; 2583 2584 uqp = uverbs_uobj_get_uqp_write(uqpid); 2585 if (uqp == NULL) { 2586 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2587 "enable_uqp_modify(%d) -lookup failure", uqpid); 2588 return (EINVAL); 2589 } 2590 uqp->disable_qp_mod = FALSE; 2591 sol_ofs_uobj_put(&uqp->uobj); 2592 return (0); 2593 } 2594 2595 int 2596 uverbs_uqpn_cq_ctrl(uint32_t uqpid, sol_uverbs_cq_ctrl_t ctrl) 2597 { 2598 uverbs_uqp_uobj_t *uqp; 2599 uverbs_ucq_uobj_t *uscq; 2600 uverbs_ucq_uobj_t *urcq; 2601 2602 uqp = uverbs_uobj_get_uqp_write(uqpid); 2603 if (uqp == NULL) { 2604 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2605 "uqpn_cq_ctrl(%d) -lookup failure", uqpid); 2606 return (EINVAL); 2607 } 2608 uscq = uqp->uqp_scq; 2609 urcq = uqp->uqp_rcq; 2610 SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, 2611 "ctrl - uqp %p, rcq %p. scq %p", uqp, urcq, uscq); 2612 2613 ASSERT(uscq); 2614 ASSERT(urcq); 2615 uverbs_cq_ctrl(uscq, ctrl); 2616 if (uscq != urcq) 2617 uverbs_cq_ctrl(urcq, ctrl); 2618 sol_ofs_uobj_put(&uqp->uobj); 2619 return (0); 2620 } 2621 2622 extern uint32_t sol_uverbs_qpnum2uqpid(uint32_t); 2623 2624 void 2625 sol_uverbs_flush_qp(uint32_t qpnum) 2626 { 2627 int32_t uqpid; 2628 ibt_status_t status; 2629 uverbs_uqp_uobj_t *uqp; 2630 2631 uqpid = sol_uverbs_qpnum2uqpid(qpnum); 2632 if (uqpid == DDI_FAILURE) { 2633 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2634 "sol_uverbs_flush_qp(%x) - Invalid qpnum", 2635 qpnum); 2636 return; 2637 } 2638 uqp = uverbs_uobj_get_uqp_write(uqpid); 2639 if (uqp == NULL) { 2640 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2641 "sol_uverbs_flush_qp(%x) - Invalid " 2642 "uqpid %x", qpnum, uqpid); 2643 return; 2644 } 2645 2646 if (uqp->qp) { 2647 status = ibt_flush_qp(uqp->qp); 2648 if (status != IBT_SUCCESS) 2649 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2650 "sol_uverbs_flush_qp(%x) - " 2651 "ibt_flush_qp(%p) failed - status %d", 2652 qpnum, uqp->qp, status); 2653 sol_ofs_uobj_put(&uqp->uobj); 2654 return; 2655 } else { 2656 SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, 2657 "sol_uverbs_flush_qp(%x), uqpid %x -" 2658 "uqp->qp is NULL!!", qpnum, uqpid); 2659 sol_ofs_uobj_put(&uqp->uobj); 2660 return; 2661 } 2662 } 2663 static uint32_t 2664 ibt_cep_flags2ibv(ibt_cep_flags_t ibt_flags) 2665 { 2666 uint32_t ib_flags = 0; 2667 2668 if (ibt_flags & IBT_CEP_RDMA_WR) 2669 ib_flags |= IB_ACCESS_REMOTE_WRITE; 2670 if (ibt_flags & IBT_CEP_RDMA_RD) 2671 ib_flags |= IB_ACCESS_REMOTE_READ; 2672 if (ibt_flags & IBT_CEP_ATOMIC) 2673 ib_flags |= IB_ACCESS_REMOTE_ATOMIC; 2674 2675 return (ib_flags); 2676 } 2677 2678 static void 2679 uverbs_cq_ctrl(uverbs_ucq_uobj_t *ucq, sol_uverbs_cq_ctrl_t ctrl) 2680 { 2681 uverbs_ufile_uobj_t *ufile; 2682 2683 ufile = ucq->comp_chan; 2684 if (!ufile) { 2685 SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, 2686 "cq_ctrl(%p), ufile NULL", ucq, ufile); 2687 return; 2688 } 2689 2690 mutex_enter(&ufile->lock); 2691 ufile->ufile_notify_enabled = ctrl; 2692 2693 if (ctrl == SOL_UVERBS2UCMA_CQ_NOTIFY_ENABLE) { 2694 if (!llist_empty(&ufile->event_list)) { 2695 cv_signal(&ufile->poll_wait); 2696 pollwakeup(&ufile->poll_head, 2697 POLLIN | POLLRDNORM); 2698 } 2699 } 2700 mutex_exit(&ufile->lock); 2701 } 2702