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 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * ibtl_chan.c 27 * 28 * This file contains Transport API functions related to Channel Functions 29 * and internal Protection Domain and Address Handle Verbs functions. 30 */ 31 32 #include <sys/ib/ibtl/impl/ibtl.h> 33 #include <sys/ib/ibtl/impl/ibtl_cm.h> 34 #include <sys/ib/ib_pkt_hdrs.h> 35 36 static char ibtl_chan[] = "ibtl_chan"; 37 38 /* 39 * RC Channel. 40 */ 41 /* 42 * Function: 43 * ibt_alloc_rc_channel 44 * Input: 45 * hca_hdl HCA Handle. 46 * flags Channel allocate flags. 47 * args A pointer to an ibt_rc_chan_alloc_args_t struct that 48 * specifies required channel attributes. 49 * Output: 50 * rc_chan_p The returned RC Channel handle. 51 * sizes NULL or a pointer to ibt_chan_sizes_s struct where 52 * new SendQ/RecvQ, and WR SGL sizes are returned. 53 * Returns: 54 * IBT_SUCCESS 55 * IBT_INVALID_PARAM 56 * Description: 57 * Allocates a RC communication channels that satisfy the specified 58 * channel attributes. 59 */ 60 ibt_status_t 61 ibt_alloc_rc_channel(ibt_hca_hdl_t hca_hdl, ibt_chan_alloc_flags_t flags, 62 ibt_rc_chan_alloc_args_t *args, ibt_channel_hdl_t *rc_chan_p, 63 ibt_chan_sizes_t *sizes) 64 { 65 ibt_status_t retval; 66 ibt_qp_alloc_attr_t qp_attr; 67 ibt_qp_info_t qp_modify_attr; 68 ibt_channel_hdl_t chanp; 69 70 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_rc_channel(%p, %x, %p, %p)", 71 hca_hdl, flags, args, sizes); 72 73 bzero(&qp_modify_attr, sizeof (ibt_qp_info_t)); 74 75 qp_attr.qp_alloc_flags = IBT_QP_NO_FLAGS; 76 if (flags & IBT_ACHAN_USER_MAP) 77 qp_attr.qp_alloc_flags |= IBT_QP_USER_MAP; 78 79 if (flags & IBT_ACHAN_DEFER_ALLOC) 80 qp_attr.qp_alloc_flags |= IBT_QP_DEFER_ALLOC; 81 82 if (flags & IBT_ACHAN_USES_SRQ) { 83 if (args->rc_srq == NULL) { 84 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 85 "NULL SRQ Handle specified."); 86 return (IBT_INVALID_PARAM); 87 } 88 qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ; 89 } 90 91 /* 92 * Check if this request is to clone the channel, or to allocate a 93 * fresh one. 94 */ 95 if (flags & IBT_ACHAN_CLONE) { 96 97 ibt_rc_chan_query_attr_t chan_attrs; 98 99 if (args->rc_clone_chan == NULL) { 100 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 101 "Clone Channel info not available."); 102 return (IBT_INVALID_PARAM); 103 } else if (args->rc_clone_chan->ch_qp.qp_hca != hca_hdl) { 104 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 105 "Clone Channel's & requested HCA Handle mismatch"); 106 return (IBT_INVALID_PARAM); 107 } 108 109 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_rc_channel: " 110 "Clone <%p> - RC Channel", args->rc_clone_chan); 111 112 /* 113 * Query the source channel, to obtained the attributes 114 * so that the new channel share the same attributes. 115 */ 116 retval = ibt_query_rc_channel(args->rc_clone_chan, &chan_attrs); 117 if (retval != IBT_SUCCESS) { 118 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 119 "Failed to query the source channel: %d", retval); 120 return (retval); 121 } 122 123 /* Setup QP alloc attributes. */ 124 qp_attr.qp_scq_hdl = chan_attrs.rc_scq; 125 qp_attr.qp_rcq_hdl = chan_attrs.rc_rcq; 126 qp_attr.qp_pd_hdl = chan_attrs.rc_pd; 127 qp_attr.qp_flags = chan_attrs.rc_flags; 128 qp_attr.qp_srq_hdl = chan_attrs.rc_srq; 129 130 bcopy(&chan_attrs.rc_chan_sizes, &qp_attr.qp_sizes, 131 sizeof (ibt_chan_sizes_t)); 132 133 qp_modify_attr.qp_flags = chan_attrs.rc_control; 134 qp_modify_attr.qp_transport.rc.rc_path.cep_hca_port_num = 135 chan_attrs.rc_prim_path.cep_hca_port_num; 136 qp_modify_attr.qp_transport.rc.rc_path.cep_pkey_ix = 137 chan_attrs.rc_prim_path.cep_pkey_ix; 138 139 } else { 140 141 /* Setup QP alloc attributes. */ 142 qp_attr.qp_scq_hdl = args->rc_scq; 143 qp_attr.qp_rcq_hdl = args->rc_rcq; 144 qp_attr.qp_pd_hdl = args->rc_pd; 145 qp_attr.qp_flags = args->rc_flags; 146 qp_attr.qp_srq_hdl = args->rc_srq; 147 148 bcopy(&args->rc_sizes, &qp_attr.qp_sizes, 149 sizeof (ibt_chan_sizes_t)); 150 151 qp_modify_attr.qp_flags = args->rc_control; 152 153 if ((args->rc_hca_port_num == 0) || 154 (args->rc_hca_port_num > IBTL_HCA2NPORTS(hca_hdl))) { 155 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 156 "Invalid port_num %d, range is (1 to %d)", 157 args->rc_hca_port_num, IBTL_HCA2NPORTS(hca_hdl)); 158 return (IBT_HCA_PORT_INVALID); 159 } 160 qp_modify_attr.qp_transport.rc.rc_path.cep_hca_port_num = 161 args->rc_hca_port_num; 162 163 /* 164 * We allocate the Channel initially with the default PKey, 165 * and later client can update this when the channel is opened 166 * with the pkey returned from a path record lookup. 167 */ 168 mutex_enter(&ibtl_clnt_list_mutex); 169 qp_modify_attr.qp_transport.rc.rc_path.cep_pkey_ix = 170 hca_hdl->ha_hca_devp-> 171 hd_portinfop[args->rc_hca_port_num - 1].p_def_pkey_ix; 172 mutex_exit(&ibtl_clnt_list_mutex); 173 } 174 175 /* Allocate Channel and Initialize the channel. */ 176 retval = ibt_alloc_qp(hca_hdl, IBT_RC_RQP, &qp_attr, sizes, NULL, 177 &chanp); 178 if (retval != IBT_SUCCESS) { 179 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 180 "Failed to allocate QP: %d", retval); 181 *rc_chan_p = NULL; 182 return (retval); 183 } 184 185 qp_modify_attr.qp_trans = IBT_RC_SRV; 186 187 /* Initialize RC Channel by transitioning it to INIT State. */ 188 retval = ibt_initialize_qp(chanp, &qp_modify_attr); 189 if (retval != IBT_SUCCESS) { 190 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: " 191 "Failed to Initialize QP: %d", retval); 192 193 /* Free the QP as we failed to initialize it. */ 194 (void) ibt_free_qp(chanp); 195 196 *rc_chan_p = NULL; 197 return (retval); 198 } 199 200 *rc_chan_p = chanp; 201 202 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_rc_channel(%p): - SUCCESS (%p)", 203 hca_hdl, chanp); 204 205 return (IBT_SUCCESS); 206 } 207 208 209 /* 210 * Function: 211 * ibt_query_rc_channel 212 * Input: 213 * rc_chan A previously allocated channel handle. 214 * chan_attrs A pointer to an ibt_rc_chan_query_args_t struct where 215 * Channel's current attributes are returned. 216 * Output: 217 * chan_attrs A pointer to an ibt_rc_chan_query_args_t struct where 218 * Channel's current attributes are returned. 219 * Returns: 220 * IBT_SUCCESS 221 * Description: 222 * Query an RC channel's attributes. 223 */ 224 ibt_status_t 225 ibt_query_rc_channel(ibt_channel_hdl_t rc_chan, 226 ibt_rc_chan_query_attr_t *chan_attrs) 227 { 228 ibt_status_t retval; 229 ibt_qp_query_attr_t qp_attr; 230 231 IBTF_DPRINTF_L3(ibtl_chan, "ibt_query_rc_channel(%p, %p)", 232 rc_chan, chan_attrs); 233 234 if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) { 235 IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_rc_channel: " 236 "type of channel (%d) is not RC", rc_chan->ch_qp.qp_type); 237 return (IBT_CHAN_SRV_TYPE_INVALID); 238 } 239 240 bzero(&qp_attr, sizeof (ibt_qp_query_attr_t)); 241 242 /* Query the channel (QP) */ 243 retval = ibt_query_qp(rc_chan, &qp_attr); 244 if (retval != IBT_SUCCESS) { 245 IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_rc_channel: " 246 "ibt_query_qp failed on QP %p: %d", rc_chan, retval); 247 return (retval); 248 } 249 250 chan_attrs->rc_hca_guid = IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(rc_chan)); 251 252 chan_attrs->rc_scq = qp_attr.qp_sq_cq; 253 chan_attrs->rc_rcq = qp_attr.qp_rq_cq; 254 chan_attrs->rc_pd = rc_chan->ch_qp.qp_pd_hdl; 255 chan_attrs->rc_state = qp_attr.qp_info.qp_state; 256 chan_attrs->rc_path_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu; 257 chan_attrs->rc_path_retry_cnt = 258 qp_attr.qp_info.qp_transport.rc.rc_retry_cnt; 259 chan_attrs->rc_path_rnr_retry_cnt = 260 qp_attr.qp_info.qp_transport.rc.rc_rnr_retry_cnt; 261 chan_attrs->rc_min_rnr_nak = 262 qp_attr.qp_info.qp_transport.rc.rc_min_rnr_nak; 263 264 chan_attrs->rc_prim_path = qp_attr.qp_info.qp_transport.rc.rc_path; 265 chan_attrs->rc_alt_path = qp_attr.qp_info.qp_transport.rc.rc_alt_path; 266 267 chan_attrs->rc_chan_sizes.cs_sq = qp_attr.qp_info.qp_sq_sz; 268 chan_attrs->rc_chan_sizes.cs_rq = qp_attr.qp_info.qp_rq_sz; 269 chan_attrs->rc_chan_sizes.cs_sq_sgl = qp_attr.qp_sq_sgl; 270 chan_attrs->rc_chan_sizes.cs_rq_sgl = qp_attr.qp_rq_sgl; 271 chan_attrs->rc_srq = qp_attr.qp_srq; 272 273 chan_attrs->rc_rdma_ra_out = 274 qp_attr.qp_info.qp_transport.rc.rc_rdma_ra_out; 275 chan_attrs->rc_rdma_ra_in = 276 qp_attr.qp_info.qp_transport.rc.rc_rdma_ra_in; 277 278 chan_attrs->rc_flags = rc_chan->ch_qp.qp_flags; 279 chan_attrs->rc_control = qp_attr.qp_info.qp_flags; 280 chan_attrs->rc_mig_state = qp_attr.qp_info.qp_transport.rc.rc_mig_state; 281 282 chan_attrs->rc_qpn = qp_attr.qp_qpn & IB_QPN_MASK; 283 chan_attrs->rc_dst_qpn = 284 qp_attr.qp_info.qp_transport.rc.rc_dst_qpn & IB_QPN_MASK; 285 286 return (retval); 287 } 288 289 290 /* 291 * Function: 292 * ibt_modify_rc_channel 293 * Input: 294 * rc_chan A previously allocated channel handle. 295 * flags Specifies which attributes in ibt_rc_chan_modify_attr_t 296 * are to be modified. 297 * attrs Attributes to be modified. 298 * Output: 299 * actual_sz On return contains the new send and receive queue sizes. 300 * Returns: 301 * IBT_SUCCESS 302 * Description: 303 * Modifies an RC channel's attributes, as specified by a 304 * ibt_cep_modify_flags_t parameter to those specified in the 305 * ibt_rc_chan_modify_attr_t structure. 306 */ 307 ibt_status_t 308 ibt_modify_rc_channel(ibt_channel_hdl_t rc_chan, ibt_cep_modify_flags_t flags, 309 ibt_rc_chan_modify_attr_t *attrs, ibt_queue_sizes_t *actual_sz) 310 { 311 ibt_status_t retval; 312 ibt_qp_info_t qp_info; 313 int retries = 1; 314 315 IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_rc_channel(%p, %x, %p, %p)", 316 rc_chan, flags, attrs, actual_sz); 317 318 if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) { 319 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_rc_channel: " 320 "type of channel (%d) is not RC", rc_chan->ch_qp.qp_type); 321 return (IBT_CHAN_SRV_TYPE_INVALID); 322 } 323 324 retry: 325 bzero(&qp_info, sizeof (ibt_qp_info_t)); 326 327 if (flags & IBT_CEP_SET_ADDS_VECT) { 328 bcopy(&attrs->rc_prim_adds_vect, 329 &qp_info.qp_transport.rc.rc_path.cep_adds_vect, 330 sizeof (ibt_adds_vect_t)); 331 } 332 333 qp_info.qp_trans = IBT_RC_SRV; 334 qp_info.qp_transport.rc.rc_path.cep_hca_port_num = 335 attrs->rc_prim_port_num; 336 qp_info.qp_transport.rc.rc_retry_cnt = attrs->rc_path_retry_cnt; 337 qp_info.qp_transport.rc.rc_rnr_retry_cnt = 338 attrs->rc_path_rnr_retry_cnt; 339 qp_info.qp_transport.rc.rc_rdma_ra_out = attrs->rc_rdma_ra_out; 340 qp_info.qp_transport.rc.rc_rdma_ra_in = attrs->rc_rdma_ra_in; 341 342 /* Current channel state must be either SQD or RTS. */ 343 qp_info.qp_current_state = rc_chan->ch_current_state; 344 qp_info.qp_state = rc_chan->ch_current_state; /* No Change in State */ 345 346 qp_info.qp_flags = attrs->rc_control; 347 qp_info.qp_sq_sz = attrs->rc_sq_sz; 348 qp_info.qp_rq_sz = attrs->rc_rq_sz; 349 qp_info.qp_transport.rc.rc_min_rnr_nak = attrs->rc_min_rnr_nak; 350 351 if (flags & IBT_CEP_SET_ALT_PATH) { 352 bcopy(&attrs->rc_alt_adds_vect, 353 &qp_info.qp_transport.rc.rc_alt_path.cep_adds_vect, 354 sizeof (ibt_adds_vect_t)); 355 qp_info.qp_transport.rc.rc_alt_path.cep_hca_port_num = 356 attrs->rc_alt_port_num; 357 } 358 359 flags |= IBT_CEP_SET_STATE; 360 361 retval = ibt_modify_qp(rc_chan, flags, &qp_info, actual_sz); 362 if (retval != IBT_SUCCESS) { 363 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_rc_channel: " 364 "ibt_modify_qp failed on QP %p: %d", rc_chan, retval); 365 /* give it one more shot if the old current state was stale */ 366 if (qp_info.qp_current_state != rc_chan->ch_current_state && 367 --retries >= 0 && 368 (qp_info.qp_current_state == IBT_STATE_RTS || 369 qp_info.qp_current_state == IBT_STATE_SQD)) 370 goto retry; 371 } 372 373 return (retval); 374 } 375 376 377 /* 378 * UD Channel. 379 */ 380 /* 381 * Function: 382 * ibt_alloc_ud_channel 383 * Input: 384 * hca_hdl HCA Handle. 385 * flags Channel allocate flags. 386 * args A pointer to an ibt_ud_chan_alloc_args_t struct that 387 * specifies required channel attributes. 388 * Output: 389 * ud_chan_p The returned UD Channel handle. 390 * sizes NULL or a pointer to ibt_chan_sizes_s struct where 391 * new SendQ/RecvQ, and WR SGL sizes are returned. 392 * Returns: 393 * IBT_SUCCESS 394 * IBT_INVALID_PARAM 395 * Description: 396 * Allocate UD channels that satisfy the specified channel attributes. 397 */ 398 ibt_status_t 399 ibt_alloc_ud_channel(ibt_hca_hdl_t hca_hdl, ibt_chan_alloc_flags_t flags, 400 ibt_ud_chan_alloc_args_t *args, ibt_channel_hdl_t *ud_chan_p, 401 ibt_chan_sizes_t *sizes) 402 { 403 ibt_status_t retval; 404 ibt_qp_alloc_attr_t qp_attr; 405 ibt_qp_info_t qp_modify_attr; 406 ibt_channel_hdl_t chanp; 407 ibt_chan_alloc_flags_t variant_flags; 408 409 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel(%p, %x, %p, %p)", 410 hca_hdl, flags, args, sizes); 411 412 if (flags & IBT_ACHAN_USES_FEXCH) { 413 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 414 "FEXCH QPs are allocated by ibt_alloc_ud_channel_range()"); 415 return (IBT_CHAN_SRV_TYPE_INVALID); 416 } 417 418 bzero(&qp_modify_attr, sizeof (ibt_qp_info_t)); 419 bzero(&qp_attr, sizeof (ibt_qp_alloc_attr_t)); 420 qp_attr.qp_alloc_flags = IBT_QP_NO_FLAGS; 421 422 /* allow at most one of these flags */ 423 variant_flags = flags & (IBT_ACHAN_USER_MAP | IBT_ACHAN_USES_RSS | 424 IBT_ACHAN_USES_RFCI | IBT_ACHAN_USES_FCMD | IBT_ACHAN_CLONE); 425 switch (variant_flags) { 426 case IBT_ACHAN_USER_MAP: 427 qp_attr.qp_alloc_flags |= IBT_QP_USER_MAP; 428 break; 429 case IBT_ACHAN_USES_RSS: 430 qp_attr.qp_alloc_flags |= IBT_QP_USES_RSS; 431 qp_modify_attr.qp_transport.ud.ud_rss = args->ud_rss; 432 break; 433 case IBT_ACHAN_USES_RFCI: 434 qp_attr.qp_alloc_flags |= IBT_QP_USES_RFCI; 435 qp_modify_attr.qp_transport.ud.ud_fc = qp_attr.qp_fc = 436 args->ud_fc; 437 break; 438 case IBT_ACHAN_USES_FCMD: 439 qp_attr.qp_alloc_flags |= IBT_QP_USES_FCMD; 440 qp_modify_attr.qp_transport.ud.ud_fc = qp_attr.qp_fc = 441 args->ud_fc; 442 break; 443 case IBT_ACHAN_CLONE: 444 case 0: 445 break; 446 default: 447 return (IBT_INVALID_PARAM); 448 } 449 450 if (flags & IBT_ACHAN_DEFER_ALLOC) 451 qp_attr.qp_alloc_flags |= IBT_QP_DEFER_ALLOC; 452 453 if (flags & IBT_ACHAN_USES_SRQ) { 454 if (args->ud_srq == NULL) { 455 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 456 "NULL SRQ Handle specified."); 457 return (IBT_INVALID_PARAM); 458 } 459 if (flags & IBT_ACHAN_USES_RSS) { 460 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 461 "SRQ not allowed with RSS."); 462 return (IBT_INVALID_PARAM); 463 } 464 qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ; 465 } 466 467 /* 468 * Check if this request is to clone the channel, or to allocate a 469 * fresh one. 470 */ 471 if (flags & IBT_ACHAN_CLONE) { 472 473 ibt_ud_chan_query_attr_t chan_attrs; 474 475 if (args->ud_clone_chan == NULL) { 476 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 477 "Clone Channel info not available."); 478 return (IBT_INVALID_PARAM); 479 } else if (args->ud_clone_chan->ch_qp.qp_hca != hca_hdl) { 480 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 481 "Clone Channel and HCA Handle mismatch"); 482 return (IBT_INVALID_PARAM); 483 } 484 485 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel: " 486 "Clone <%p> - UD Channel", args->ud_clone_chan); 487 488 retval = ibt_query_ud_channel(args->ud_clone_chan, &chan_attrs); 489 if (retval != IBT_SUCCESS) { 490 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 491 "Failed to Query the source channel: %d", retval); 492 return (retval); 493 } 494 495 /* Setup QP alloc attributes. */ 496 qp_attr.qp_scq_hdl = chan_attrs.ud_scq; 497 qp_attr.qp_rcq_hdl = chan_attrs.ud_rcq; 498 qp_attr.qp_pd_hdl = chan_attrs.ud_pd; 499 qp_attr.qp_flags = chan_attrs.ud_flags; 500 qp_attr.qp_srq_hdl = chan_attrs.ud_srq; 501 502 bcopy(&chan_attrs.ud_chan_sizes, &qp_attr.qp_sizes, 503 sizeof (ibt_chan_sizes_t)); 504 505 qp_modify_attr.qp_transport.ud.ud_port = 506 chan_attrs.ud_hca_port_num; 507 qp_modify_attr.qp_transport.ud.ud_qkey = chan_attrs.ud_qkey; 508 qp_modify_attr.qp_transport.ud.ud_pkey_ix = 509 chan_attrs.ud_pkey_ix; 510 } else { 511 ib_pkey_t tmp_pkey; 512 513 /* Setup QP alloc attributes. */ 514 qp_attr.qp_scq_hdl = args->ud_scq; 515 qp_attr.qp_rcq_hdl = args->ud_rcq; 516 qp_attr.qp_pd_hdl = args->ud_pd; 517 qp_attr.qp_flags = args->ud_flags; 518 qp_attr.qp_srq_hdl = args->ud_srq; 519 520 bcopy(&args->ud_sizes, &qp_attr.qp_sizes, 521 sizeof (ibt_chan_sizes_t)); 522 523 qp_modify_attr.qp_transport.ud.ud_port = args->ud_hca_port_num; 524 qp_modify_attr.qp_transport.ud.ud_qkey = args->ud_qkey; 525 526 /* Validate input hca_port_num and pkey_ix values. */ 527 if ((retval = ibt_index2pkey(hca_hdl, args->ud_hca_port_num, 528 args->ud_pkey_ix, &tmp_pkey)) != IBT_SUCCESS) { 529 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 530 "ibt_index2pkey failed, status: %d", retval); 531 *ud_chan_p = NULL; 532 return (retval); 533 } 534 qp_modify_attr.qp_transport.ud.ud_pkey_ix = args->ud_pkey_ix; 535 } 536 537 /* Allocate Channel and Initialize the channel. */ 538 retval = ibt_alloc_qp(hca_hdl, IBT_UD_RQP, &qp_attr, sizes, NULL, 539 &chanp); 540 if (retval != IBT_SUCCESS) { 541 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 542 "Failed to allocate QP: %d", retval); 543 *ud_chan_p = NULL; 544 return (retval); 545 } 546 547 /* Initialize UD Channel by transitioning it to RTS State. */ 548 qp_modify_attr.qp_trans = IBT_UD_SRV; 549 qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS; 550 qp_modify_attr.qp_transport.ud.ud_sq_psn = 0; 551 552 retval = ibt_initialize_qp(chanp, &qp_modify_attr); 553 if (retval != IBT_SUCCESS) { 554 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 555 "Failed to Initialize QP: %d", retval); 556 557 /* Free the QP as we failed to initialize it. */ 558 (void) ibt_free_qp(chanp); 559 560 *ud_chan_p = NULL; 561 return (retval); 562 } 563 564 *ud_chan_p = chanp; 565 566 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel(%p): - SUCCESS (%p)", 567 hca_hdl, chanp); 568 569 return (IBT_SUCCESS); 570 } 571 572 573 /* 574 * Function: 575 * ibt_alloc_ud_channel_range 576 * Input: 577 * hca_hdl HCA Handle. 578 * log2 Log (base 2) of the number of QPs to allocate. 579 * flags Channel allocate flags. 580 * args A pointer to an ibt_ud_chan_alloc_args_t struct that 581 * specifies required channel attributes. 582 * send_cq A pointer to an array of CQ handles. 583 * recv_cq A pointer to an array of CQ handles. 584 * Output: 585 * base_qpn_p The returned QP number of the base QP. 586 * ud_chan_p The returned UD Channel handle. 587 * sizes NULL or a pointer to ibt_chan_sizes_s struct where 588 * new SendQ/RecvQ, and WR SGL sizes are returned. 589 * Returns: 590 * IBT_SUCCESS 591 * IBT_INVALID_PARAM 592 * Description: 593 * Allocate UD channels that satisfy the specified channel attributes. 594 */ 595 ibt_status_t 596 ibt_alloc_ud_channel_range(ibt_hca_hdl_t hca_hdl, uint_t log2, 597 ibt_chan_alloc_flags_t flags, ibt_ud_chan_alloc_args_t *args, 598 ibt_cq_hdl_t *send_cq, ibt_cq_hdl_t *recv_cq, ib_qpn_t *base_qpn_p, 599 ibt_channel_hdl_t *ud_chan_p, ibt_chan_sizes_t *sizes) 600 { 601 ibt_status_t retval; 602 ibt_qp_alloc_attr_t qp_attr; 603 ibt_qp_info_t qp_modify_attr; 604 ibtl_channel_t *chanp; 605 ibt_cq_hdl_t ibt_cq_hdl; 606 ibc_cq_hdl_t *ibc_send_cq, *ibc_recv_cq; 607 ibc_qp_hdl_t *ibc_qp_hdl_p; 608 int i, n = 1 << log2; 609 ib_pkey_t tmp_pkey; 610 611 612 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel_range(%p, %x, %p, %p)", 613 hca_hdl, flags, args, sizes); 614 615 bzero(&qp_modify_attr, sizeof (ibt_qp_info_t)); 616 617 qp_attr.qp_alloc_flags = IBT_QP_NO_FLAGS; 618 619 if (flags & IBT_ACHAN_CLONE) 620 return (IBT_INVALID_PARAM); 621 622 if (flags & IBT_ACHAN_USER_MAP) 623 qp_attr.qp_alloc_flags |= IBT_QP_USER_MAP; 624 625 if (flags & IBT_ACHAN_DEFER_ALLOC) 626 qp_attr.qp_alloc_flags |= IBT_QP_DEFER_ALLOC; 627 628 if (flags & IBT_ACHAN_USES_SRQ) { 629 if (args->ud_srq == NULL) { 630 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: " 631 "NULL SRQ Handle specified."); 632 return (IBT_INVALID_PARAM); 633 } 634 qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ; 635 } 636 637 if (flags & IBT_ACHAN_USES_FEXCH) { 638 qp_attr.qp_alloc_flags |= IBT_QP_USES_FEXCH; 639 qp_attr.qp_fc = args->ud_fc; 640 qp_modify_attr.qp_transport.ud.ud_fc = qp_attr.qp_fc = 641 args->ud_fc; 642 } 643 if (flags & IBT_ACHAN_USES_RSS) { 644 if (log2 > 645 hca_hdl->ha_hca_devp->hd_hca_attr->hca_rss_max_log2_table) 646 return (IBT_INSUFF_RESOURCE); 647 qp_attr.qp_alloc_flags |= IBT_QP_USES_RSS; 648 } 649 650 ibc_send_cq = kmem_alloc(sizeof (ibc_cq_hdl_t) << log2, KM_SLEEP); 651 ibc_recv_cq = kmem_alloc(sizeof (ibc_cq_hdl_t) << log2, KM_SLEEP); 652 ibc_qp_hdl_p = kmem_alloc(sizeof (ibc_qp_hdl_t) << log2, KM_SLEEP); 653 654 for (i = 0; i < 1 << log2; i++) { 655 ud_chan_p[i] = kmem_zalloc(sizeof (ibtl_channel_t), KM_SLEEP); 656 ibt_cq_hdl = send_cq[i]; 657 ibc_send_cq[i] = ibt_cq_hdl ? ibt_cq_hdl->cq_ibc_cq_hdl : NULL; 658 ibt_cq_hdl = recv_cq[i]; 659 ibc_recv_cq[i] = ibt_cq_hdl ? ibt_cq_hdl->cq_ibc_cq_hdl : NULL; 660 } 661 662 /* Setup QP alloc attributes. */ 663 qp_attr.qp_pd_hdl = args->ud_pd; 664 qp_attr.qp_flags = args->ud_flags; 665 qp_attr.qp_srq_hdl = args->ud_srq; 666 667 bcopy(&args->ud_sizes, &qp_attr.qp_sizes, 668 sizeof (ibt_chan_sizes_t)); 669 670 qp_modify_attr.qp_transport.ud.ud_port = args->ud_hca_port_num; 671 qp_modify_attr.qp_transport.ud.ud_qkey = args->ud_qkey; 672 673 /* Validate input hca_port_num and pkey_ix values. */ 674 if ((retval = ibt_index2pkey(hca_hdl, args->ud_hca_port_num, 675 args->ud_pkey_ix, &tmp_pkey)) != IBT_SUCCESS) { 676 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel_range:" 677 " ibt_index2pkey failed, status: %d", retval); 678 goto fail; 679 } 680 qp_modify_attr.qp_transport.ud.ud_pkey_ix = args->ud_pkey_ix; 681 682 /* Allocate Channel and Initialize the channel. */ 683 retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_qp_range)( 684 IBTL_HCA2CIHCA(hca_hdl), log2, (ibtl_qp_hdl_t *)ud_chan_p, 685 IBT_UD_RQP, &qp_attr, sizes, ibc_send_cq, ibc_recv_cq, 686 base_qpn_p, ibc_qp_hdl_p); 687 if (retval != IBT_SUCCESS) { 688 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel_range: " 689 "Failed to allocate QPs: %d", retval); 690 goto fail; 691 } 692 693 /* Initialize UD Channel by transitioning it to RTS State. */ 694 qp_modify_attr.qp_trans = IBT_UD_SRV; 695 qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS; 696 qp_modify_attr.qp_transport.ud.ud_sq_psn = 0; 697 698 for (i = 0; i < n; i++) { 699 /* Initialize the internal QP struct. */ 700 chanp = ud_chan_p[i]; 701 chanp->ch_qp.qp_type = IBT_UD_SRV; 702 chanp->ch_qp.qp_hca = hca_hdl; 703 chanp->ch_qp.qp_ibc_qp_hdl = ibc_qp_hdl_p[i]; 704 chanp->ch_qp.qp_send_cq = send_cq[i]; 705 chanp->ch_qp.qp_recv_cq = recv_cq[i]; 706 chanp->ch_current_state = IBT_STATE_RESET; 707 mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL); 708 cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL); 709 710 retval = ibt_initialize_qp(chanp, &qp_modify_attr); 711 if (retval != IBT_SUCCESS) { 712 int j; 713 714 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel_range:" 715 " Failed to Initialize QP: %d", retval); 716 717 /* Free the QP as we failed to initialize it. */ 718 (void) ibt_free_qp(chanp); 719 for (j = 0; j < i; j++) { 720 chanp = ud_chan_p[j]; 721 (void) ibt_free_qp(chanp); 722 } 723 goto fail; 724 } 725 726 /* 727 * The IBTA spec does not include the signal type or PD on a QP 728 * query operation. In order to implement the "CLONE" feature 729 * we need to cache these values. 730 */ 731 chanp->ch_qp.qp_flags = qp_attr.qp_flags; 732 chanp->ch_qp.qp_pd_hdl = qp_attr.qp_pd_hdl; 733 } 734 735 736 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel_range(%p): SUCCESS"); 737 738 atomic_add_32(&hca_hdl->ha_qp_cnt, n); 739 740 retval = IBT_SUCCESS; 741 742 fail: 743 kmem_free(ibc_send_cq, sizeof (ibc_cq_hdl_t) << log2); 744 kmem_free(ibc_recv_cq, sizeof (ibc_cq_hdl_t) << log2); 745 kmem_free(ibc_qp_hdl_p, sizeof (ibc_qp_hdl_t) << log2); 746 if (retval != IBT_SUCCESS) { 747 for (i = 0; i < 1 << log2; i++) { 748 kmem_free(ud_chan_p[i], sizeof (ibtl_channel_t)); 749 ud_chan_p[i] = NULL; 750 } 751 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel_range(%p): " 752 "failed: %d", retval); 753 } 754 return (retval); 755 } 756 757 758 /* 759 * Function: 760 * ibt_query_ud_channel 761 * Input: 762 * ud_chan A previously allocated UD channel handle. 763 * Output: 764 * chan_attrs Channel's current attributes. 765 * Returns: 766 * IBT_SUCCESS 767 * Description: 768 * Query a UD channel's attributes. 769 */ 770 ibt_status_t 771 ibt_query_ud_channel(ibt_channel_hdl_t ud_chan, 772 ibt_ud_chan_query_attr_t *ud_chan_attrs) 773 { 774 ibt_status_t retval; 775 ibt_qp_query_attr_t qp_attr; 776 777 IBTF_DPRINTF_L3(ibtl_chan, "ibt_query_ud_channel(%p, %p)", 778 ud_chan, ud_chan_attrs); 779 780 if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) { 781 IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_ud_channel: " 782 "type of channel (%d) is not UD", ud_chan->ch_qp.qp_type); 783 return (IBT_CHAN_SRV_TYPE_INVALID); 784 } 785 786 bzero(&qp_attr, sizeof (ibt_qp_query_attr_t)); 787 788 /* Query the channel (QP) */ 789 retval = ibt_query_qp(ud_chan, &qp_attr); 790 if (retval != IBT_SUCCESS) { 791 IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_ud_channel: " 792 "ibt_query_qp failed on QP %p: %d", ud_chan, retval); 793 return (retval); 794 } 795 796 ud_chan_attrs->ud_qpn = qp_attr.qp_qpn & IB_QPN_MASK; 797 ud_chan_attrs->ud_hca_guid = IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(ud_chan)); 798 799 ud_chan_attrs->ud_scq = qp_attr.qp_sq_cq; 800 ud_chan_attrs->ud_rcq = qp_attr.qp_rq_cq; 801 ud_chan_attrs->ud_pd = ud_chan->ch_qp.qp_pd_hdl; 802 803 ud_chan_attrs->ud_hca_port_num = 804 qp_attr.qp_info.qp_transport.ud.ud_port; 805 806 ud_chan_attrs->ud_state = qp_attr.qp_info.qp_state; 807 ud_chan_attrs->ud_pkey_ix = qp_attr.qp_info.qp_transport.ud.ud_pkey_ix; 808 ud_chan_attrs->ud_qkey = qp_attr.qp_info.qp_transport.ud.ud_qkey; 809 810 ud_chan_attrs->ud_chan_sizes.cs_sq = qp_attr.qp_info.qp_sq_sz; 811 ud_chan_attrs->ud_chan_sizes.cs_rq = qp_attr.qp_info.qp_rq_sz; 812 ud_chan_attrs->ud_chan_sizes.cs_sq_sgl = qp_attr.qp_sq_sgl; 813 ud_chan_attrs->ud_chan_sizes.cs_rq_sgl = qp_attr.qp_rq_sgl; 814 ud_chan_attrs->ud_srq = qp_attr.qp_srq; 815 816 ud_chan_attrs->ud_flags = ud_chan->ch_qp.qp_flags; 817 818 ud_chan_attrs->ud_query_fc = qp_attr.qp_query_fexch; 819 820 return (retval); 821 } 822 823 824 /* 825 * Function: 826 * ibt_modify_ud_channel 827 * Input: 828 * ud_chan A previously allocated UD channel handle. 829 * flags Specifies which attributes in ibt_ud_chan_modify_attr_t 830 * are to be modified. 831 * attrs Attributes to be modified. 832 * Output: 833 * actual_sz On return contains the new send and receive queue sizes. 834 * Returns: 835 * IBT_SUCCESS 836 * Description: 837 * Modifies an UD channel's attributes, as specified by a 838 * ibt_cep_modify_flags_t parameter to those specified in the 839 * ibt_ud_chan_modify_attr_t structure. 840 */ 841 ibt_status_t 842 ibt_modify_ud_channel(ibt_channel_hdl_t ud_chan, ibt_cep_modify_flags_t flags, 843 ibt_ud_chan_modify_attr_t *attrs, ibt_queue_sizes_t *actual_sz) 844 { 845 ibt_status_t retval; 846 ibt_qp_info_t qp_info; 847 ibt_cep_modify_flags_t good_flags; 848 int retries = 1; 849 850 IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_ud_channel(%p, %x, %p, %p)", 851 ud_chan, flags, attrs, actual_sz); 852 853 if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) { 854 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_channel: " 855 "type of channel (%d) is not UD", ud_chan->ch_qp.qp_type); 856 return (IBT_CHAN_SRV_TYPE_INVALID); 857 } 858 859 good_flags = IBT_CEP_SET_SQ_SIZE | IBT_CEP_SET_RQ_SIZE | 860 IBT_CEP_SET_QKEY; 861 862 if (flags & ~good_flags) { 863 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_channel: " 864 "Invalid Modify Flags: %x", flags); 865 return (IBT_INVALID_PARAM); 866 } 867 868 retry: 869 bzero(&qp_info, sizeof (ibt_qp_info_t)); 870 871 qp_info.qp_state = ud_chan->ch_current_state; /* No Change in State */ 872 qp_info.qp_current_state = ud_chan->ch_current_state; 873 qp_info.qp_flags = IBT_CEP_NO_FLAGS; 874 875 qp_info.qp_sq_sz = attrs->ud_sq_sz; 876 qp_info.qp_rq_sz = attrs->ud_rq_sz; 877 qp_info.qp_trans = IBT_UD_SRV; 878 qp_info.qp_transport.ud.ud_qkey = attrs->ud_qkey; 879 880 flags |= IBT_CEP_SET_STATE; 881 882 retval = ibt_modify_qp(ud_chan, flags, &qp_info, actual_sz); 883 if (retval != IBT_SUCCESS) { 884 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_channel: " 885 "ibt_modify_qp failed on QP %p: %d", ud_chan, retval); 886 /* give it one more shot if the old current state was stale */ 887 if (qp_info.qp_current_state != ud_chan->ch_current_state && 888 --retries >= 0 && 889 (qp_info.qp_current_state == IBT_STATE_RTS || 890 qp_info.qp_current_state == IBT_STATE_SQD)) 891 goto retry; 892 } 893 894 return (retval); 895 } 896 897 898 /* 899 * Function: 900 * ibt_recover_ud_channel 901 * Input: 902 * ud_chan An UD channel handle which is in SQError state. 903 * Output: 904 * none. 905 * Returns: 906 * IBT_SUCCESS 907 * IBT_CHAN_HDL_INVALID 908 * IBT_CHAN_SRV_TYPE_INVALID 909 * IBT_CHAN_STATE_INVALID 910 * Description: 911 * Recover an UD Channel which has transitioned to SQ Error state. The 912 * ibt_recover_ud_channel() transitions the channel from SQ Error state 913 * to Ready-To-Send channel state. 914 * 915 * If a work request posted to a UD channel's send queue completes with 916 * an error (see ibt_wc_status_t), the channel gets transitioned to SQ 917 * Error state. In order to reuse this channel, ibt_recover_ud_channel() 918 * can be used to recover the channel to a usable (Ready-to-Send) state. 919 */ 920 ibt_status_t 921 ibt_recover_ud_channel(ibt_channel_hdl_t ud_chan) 922 { 923 ibt_qp_info_t modify_attr; 924 ibt_status_t retval; 925 926 IBTF_DPRINTF_L3(ibtl_chan, "ibt_recover_ud_channel(%p)", ud_chan); 927 928 if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) { 929 IBTF_DPRINTF_L2(ibtl_chan, "ibt_recover_ud_channel: " 930 "Called for non-UD channels<%d>", ud_chan->ch_qp.qp_type); 931 return (IBT_CHAN_SRV_TYPE_INVALID); 932 } 933 934 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 935 936 /* Set the channel state to RTS, to activate the send processing. */ 937 modify_attr.qp_state = IBT_STATE_RTS; 938 modify_attr.qp_trans = ud_chan->ch_qp.qp_type; 939 modify_attr.qp_current_state = IBT_STATE_SQE; 940 941 retval = ibt_modify_qp(ud_chan, IBT_CEP_SET_STATE, &modify_attr, NULL); 942 943 if (retval != IBT_SUCCESS) 944 IBTF_DPRINTF_L2(ibtl_chan, "ibt_recover_ud_channel: " 945 "ibt_modify_qp failed on qp %p: status = %d", 946 ud_chan, retval); 947 948 return (retval); 949 } 950 951 952 /* 953 * Function: 954 * ibt_flush_channel 955 * Input: 956 * chan The opaque channel handle returned in a previous call 957 * to ibt_alloc_ud_channel() or ibt_alloc_rc_channel(). 958 * Output: 959 * none. 960 * Returns: 961 * IBT_SUCCESS 962 * Description: 963 * Flush the specified channel. Outstanding work requests are flushed 964 * so that the client can do the associated clean up. After that, the 965 * client will usually deregister the previously registered memory, 966 * then free the channel by calling ibt_free_channel(). This function 967 * applies to UD channels, or to RC channels that have not successfully 968 * been opened. 969 */ 970 ibt_status_t 971 ibt_flush_channel(ibt_channel_hdl_t chan) 972 { 973 ibt_status_t retval; 974 975 IBTF_DPRINTF_L3(ibtl_chan, "ibt_flush_channel(%p)", chan); 976 977 retval = ibt_flush_qp(chan); 978 if (retval != IBT_SUCCESS) { 979 IBTF_DPRINTF_L2(ibtl_chan, "ibt_flush_channel: " 980 "ibt_flush_qp failed on QP %p: %d", chan, retval); 981 } 982 983 return (retval); 984 } 985 986 987 /* 988 * Function: 989 * ibt_free_channel 990 * Input: 991 * chan The opaque channel handle returned in a previous 992 * call to ibt_alloc_{ud,rc}_channel(). 993 * Output: 994 * none. 995 * Returns: 996 * IBT_SUCCESS 997 * Description: 998 * Releases the resources associated with the specified channel. 999 * It is well assumed that channel has been closed before this. 1000 */ 1001 ibt_status_t 1002 ibt_free_channel(ibt_channel_hdl_t chan) 1003 { 1004 return (ibt_free_qp(chan)); 1005 } 1006 1007 1008 /* 1009 * UD Destination. 1010 */ 1011 /* 1012 * Function: 1013 * ibt_alloc_ud_dest 1014 * Input: 1015 * hca_hdl HCA Handle. 1016 * pd Protection Domain 1017 * Output: 1018 * ud_dest_p Address to store the returned UD destination handle. 1019 * Returns: 1020 * IBT_SUCCESS 1021 * Description: 1022 * Allocate a UD destination handle. The returned UD destination handle 1023 * has no useful contents, but is usable after calling ibt_modify_ud_dest, 1024 * ibt_modify_reply_ud_dest, or ibt_open_ud_dest. 1025 */ 1026 ibt_status_t 1027 ibt_alloc_ud_dest(ibt_hca_hdl_t hca_hdl, ibt_ud_dest_flags_t flags, 1028 ibt_pd_hdl_t pd, ibt_ud_dest_hdl_t *ud_dest_p) 1029 { 1030 ibt_status_t retval; 1031 ibt_ud_dest_t *ud_destp; 1032 ibt_ah_hdl_t ah; 1033 ibt_adds_vect_t adds_vect; 1034 1035 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_dest(%p, %x, %p)", 1036 hca_hdl, flags, pd); 1037 1038 bzero(&adds_vect, sizeof (adds_vect)); 1039 adds_vect.av_port_num = 1; 1040 adds_vect.av_srate = IBT_SRATE_1X; /* assume the minimum */ 1041 retval = ibt_alloc_ah(hca_hdl, flags, pd, &adds_vect, &ah); 1042 if (retval != IBT_SUCCESS) { 1043 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_dest: " 1044 "Address Handle Allocation failed: %d", retval); 1045 *ud_dest_p = NULL; 1046 return (retval); 1047 } 1048 ud_destp = kmem_alloc(sizeof (*ud_destp), KM_SLEEP); 1049 ud_destp->ud_ah = ah; 1050 ud_destp->ud_dest_hca = hca_hdl; 1051 ud_destp->ud_dst_qpn = 0; 1052 ud_destp->ud_qkey = 0; 1053 *ud_dest_p = ud_destp; 1054 return (IBT_SUCCESS); 1055 } 1056 1057 /* 1058 * Function: 1059 * ibt_query_ud_dest 1060 * Input: 1061 * ud_dest A previously allocated UD destination handle. 1062 * Output: 1063 * dest_attrs UD destination's current attributes. 1064 * Returns: 1065 * IBT_SUCCESS 1066 * Description: 1067 * Query a UD destination's attributes. 1068 */ 1069 ibt_status_t 1070 ibt_query_ud_dest(ibt_ud_dest_hdl_t ud_dest, 1071 ibt_ud_dest_query_attr_t *dest_attrs) 1072 { 1073 ibt_status_t retval; 1074 1075 ASSERT(dest_attrs != NULL); 1076 1077 /* Query Address Handle */ 1078 retval = ibt_query_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah, 1079 &dest_attrs->ud_pd, &dest_attrs->ud_addr_vect); 1080 1081 if (retval != IBT_SUCCESS) { 1082 IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_ud_dest: " 1083 "Failed to Query Address Handle: %d", retval); 1084 return (retval); 1085 } 1086 1087 /* Update the return struct. */ 1088 dest_attrs->ud_hca_hdl = ud_dest->ud_dest_hca; 1089 dest_attrs->ud_dst_qpn = ud_dest->ud_dst_qpn; 1090 dest_attrs->ud_qkey = ud_dest->ud_qkey; 1091 1092 return (retval); 1093 } 1094 1095 /* 1096 * Function: 1097 * ibt_modify_ud_dest 1098 * Input: 1099 * ud_dest A previously allocated UD destination handle 1100 * as returned by ibt_alloc_ud_dest(). 1101 * qkey QKey of the destination. 1102 * dest_qpn QPN of the destination. 1103 * adds_vect NULL or Address Vector for the destination. 1104 * 1105 * Output: 1106 * none. 1107 * Returns: 1108 * IBT_SUCCESS 1109 * Description: 1110 * Modify a previously allocated UD destination handle from the 1111 * arguments supplied by the caller. 1112 */ 1113 ibt_status_t 1114 ibt_modify_ud_dest(ibt_ud_dest_hdl_t ud_dest, ib_qkey_t qkey, 1115 ib_qpn_t dest_qpn, ibt_adds_vect_t *adds_vect) 1116 { 1117 ibt_status_t retval; 1118 1119 IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_ud_dest(%p, %x, %x, %p) ", 1120 ud_dest, qkey, dest_qpn, adds_vect); 1121 1122 if ((adds_vect != NULL) && 1123 (retval = ibt_modify_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah, 1124 adds_vect)) != IBT_SUCCESS) { 1125 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_dest: " 1126 "ibt_modify_ah() failed: status = %d", retval); 1127 return (retval); 1128 } 1129 ud_dest->ud_dst_qpn = dest_qpn; 1130 ud_dest->ud_qkey = qkey; 1131 return (IBT_SUCCESS); 1132 } 1133 1134 /* 1135 * Function: 1136 * ibt_free_ud_dest 1137 * Input: 1138 * ud_dest The opaque destination handle returned in a previous 1139 * call to ibt_alloc_ud_dest() or ibt_alloc_mcg_dest(). 1140 * Output: 1141 * none. 1142 * Returns: 1143 * IBT_SUCCESS 1144 * Description: 1145 * Releases the resources associated with the specified destination 1146 * handle. 1147 */ 1148 ibt_status_t 1149 ibt_free_ud_dest(ibt_ud_dest_hdl_t ud_dest) 1150 { 1151 ibt_status_t retval; 1152 1153 retval = ibt_free_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah); 1154 if (retval != IBT_SUCCESS) { 1155 IBTF_DPRINTF_L2(ibtl_chan, "ibt_free_ud_dest: " 1156 "Address Handle free failed: %d", retval); 1157 return (retval); 1158 } 1159 kmem_free(ud_dest, sizeof (*ud_dest)); 1160 return (IBT_SUCCESS); 1161 } 1162 1163 static ibt_status_t 1164 ibtl_find_sgid_ix(ib_gid_t *sgid, ibt_channel_hdl_t ud_chan, uint8_t port, 1165 uint_t *sgid_ix_p) 1166 { 1167 ibtl_hca_devinfo_t *hca_devp = ud_chan->ch_qp.qp_hca->ha_hca_devp; 1168 ib_gid_t *sgidp; 1169 uint_t i; 1170 uint_t sgid_tbl_sz; 1171 1172 if (port == 0 || port > hca_devp->hd_hca_attr->hca_nports || 1173 sgid->gid_prefix == 0 || sgid->gid_guid == 0) { 1174 *sgid_ix_p = 0; 1175 return (IBT_INVALID_PARAM); 1176 } 1177 mutex_enter(&ibtl_clnt_list_mutex); 1178 sgidp = &hca_devp->hd_portinfop[port - 1].p_sgid_tbl[0]; 1179 sgid_tbl_sz = hca_devp->hd_portinfop[port - 1].p_sgid_tbl_sz; 1180 for (i = 0; i < sgid_tbl_sz; i++, sgidp++) { 1181 if ((sgid->gid_guid != sgidp->gid_guid) || 1182 (sgid->gid_prefix != sgidp->gid_prefix)) 1183 continue; 1184 mutex_exit(&ibtl_clnt_list_mutex); 1185 *sgid_ix_p = i; 1186 return (IBT_SUCCESS); 1187 } 1188 mutex_exit(&ibtl_clnt_list_mutex); 1189 *sgid_ix_p = 0; 1190 return (IBT_INVALID_PARAM); 1191 } 1192 1193 /* 1194 * Function: 1195 * ibt_modify_reply_ud_dest 1196 * Input: 1197 * ud_dest A previously allocated UD reply destination handle 1198 * as returned by ibt_alloc_ud_dest(). 1199 * qkey Qkey. 0 means "not specified", so use the Q_Key 1200 * in the QP context. 1201 * recv_buf Pointer to the first data buffer associated with the 1202 * receive work request. 1203 * Output: 1204 * Returns: 1205 * IBT_SUCCESS 1206 * Description: 1207 * Modify a previously allocated UD destination handle, so that it 1208 * can be used to reply to the sender of the datagram contained in the 1209 * specified work request completion. If the qkey is not supplied (0), 1210 * then use the qkey in the QP (we just set qkey to a privileged QKEY). 1211 */ 1212 ibt_status_t 1213 ibt_modify_reply_ud_dest(ibt_channel_hdl_t ud_chan, ibt_ud_dest_hdl_t ud_dest, 1214 ib_qkey_t qkey, ibt_wc_t *wc, ib_vaddr_t recv_buf) 1215 { 1216 ibt_status_t retval; 1217 ibt_adds_vect_t adds_vect; 1218 ib_grh_t *grh; 1219 uint8_t port; 1220 uint32_t ver_tc_flow; 1221 1222 IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_reply_ud_dest(%p, %p, %x, %p, " 1223 "%llx)", ud_chan, ud_dest, qkey, wc, recv_buf); 1224 1225 if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) { 1226 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_reply_ud_dest: " 1227 "type of channel (%d) is not UD", 1228 ud_chan->ch_qp.qp_type); 1229 return (IBT_CHAN_SRV_TYPE_INVALID); 1230 } 1231 if (qkey == 0) 1232 qkey = ud_chan->ch_transport.ud.ud_qkey; 1233 port = ud_chan->ch_transport.ud.ud_port_num; 1234 1235 if (wc->wc_flags & IBT_WC_GRH_PRESENT) { 1236 grh = (ib_grh_t *)(uintptr_t)recv_buf; 1237 adds_vect.av_send_grh = B_TRUE; 1238 adds_vect.av_dgid.gid_prefix = b2h64(grh->SGID.gid_prefix); 1239 adds_vect.av_dgid.gid_guid = b2h64(grh->SGID.gid_guid); 1240 adds_vect.av_sgid.gid_prefix = b2h64(grh->DGID.gid_prefix); 1241 adds_vect.av_sgid.gid_guid = b2h64(grh->DGID.gid_guid); 1242 (void) ibtl_find_sgid_ix(&adds_vect.av_sgid, ud_chan, 1243 port, &adds_vect.av_sgid_ix); 1244 ver_tc_flow = b2h32(grh->IPVer_TC_Flow); 1245 adds_vect.av_flow = ver_tc_flow & IB_GRH_FLOW_LABEL_MASK; 1246 adds_vect.av_tclass = (ver_tc_flow & IB_GRH_TCLASS_MASK) >> 20; 1247 adds_vect.av_hop = grh->HopLmt; 1248 } else { 1249 adds_vect.av_send_grh = B_FALSE; 1250 adds_vect.av_dgid.gid_prefix = 0; 1251 adds_vect.av_sgid.gid_prefix = 0; 1252 adds_vect.av_dgid.gid_guid = 0; 1253 adds_vect.av_sgid.gid_guid = 0; 1254 adds_vect.av_sgid_ix = 0; 1255 adds_vect.av_flow = 0; 1256 adds_vect.av_tclass = 0; 1257 adds_vect.av_hop = 0; 1258 } 1259 1260 adds_vect.av_srate = IBT_SRATE_1X; /* assume the minimum */ 1261 adds_vect.av_srvl = wc->wc_sl; 1262 adds_vect.av_dlid = wc->wc_slid; 1263 adds_vect.av_src_path = wc->wc_path_bits; 1264 adds_vect.av_port_num = port; 1265 1266 if ((retval = ibt_modify_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah, 1267 &adds_vect)) != IBT_SUCCESS) { 1268 IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_reply_ud_dest: " 1269 "ibt_alloc_ah() failed: status = %d", retval); 1270 return (retval); 1271 } 1272 ud_dest->ud_dst_qpn = wc->wc_qpn & IB_QPN_MASK; 1273 ud_dest->ud_qkey = qkey; 1274 1275 return (IBT_SUCCESS); 1276 } 1277 1278 1279 /* 1280 * Function: 1281 * ibt_is_privileged_ud_dest 1282 * Input: 1283 * ud_dest A previously allocated destination handle. 1284 * Output: 1285 * none 1286 * Returns: 1287 * B_FALSE/B_TRUE 1288 * Description: 1289 * Determine if a UD destination Handle is a privileged handle. 1290 */ 1291 boolean_t 1292 ibt_is_privileged_ud_dest(ibt_ud_dest_hdl_t ud_dest) 1293 { 1294 return ((ud_dest->ud_qkey & IB_PRIVILEGED_QKEY_BIT) ? B_TRUE : B_FALSE); 1295 } 1296 1297 1298 /* 1299 * Function: 1300 * ibt_update_channel_qkey 1301 * Input: 1302 * ud_chan The UD channel handle, that is to be used to 1303 * communicate with the specified destination. 1304 * 1305 * ud_dest A UD destination handle returned from 1306 * ibt_alloc_ud_dest(9F). 1307 * Output: 1308 * none 1309 * Returns: 1310 * IBT_SUCCESS 1311 * Description: 1312 * ibt_update_channel_qkey() sets the Q_Key in the specified channel context 1313 * to the Q_Key in the specified destination handle. This function can be used 1314 * to enable sends to a privileged destination. All posted send work requests 1315 * that contain a privileged destination handle now use the Q_Key in the 1316 * channel context. 1317 * 1318 * ibt_update_channel_qkey() can also be used to enable the caller to receive 1319 * from the specified remote destination on the specified channel. 1320 */ 1321 ibt_status_t 1322 ibt_update_channel_qkey(ibt_channel_hdl_t ud_chan, ibt_ud_dest_hdl_t ud_dest) 1323 { 1324 ibt_status_t retval; 1325 ibt_qp_info_t qp_info; 1326 1327 IBTF_DPRINTF_L3(ibtl_chan, "ibt_update_channel_qkey(%p, %p)", 1328 ud_chan, ud_dest); 1329 1330 if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) { 1331 IBTF_DPRINTF_L2(ibtl_chan, "ibt_update_channel_qkey: " 1332 "type of channel (%d) is not UD", 1333 ud_chan->ch_qp.qp_type); 1334 return (IBT_CHAN_SRV_TYPE_INVALID); 1335 } 1336 bzero(&qp_info, sizeof (ibt_qp_info_t)); 1337 1338 qp_info.qp_trans = IBT_UD_SRV; 1339 qp_info.qp_state = ud_chan->ch_current_state; 1340 qp_info.qp_current_state = ud_chan->ch_current_state; 1341 qp_info.qp_transport.ud.ud_qkey = ud_dest->ud_qkey; 1342 1343 retval = ibt_modify_qp(ud_chan, IBT_CEP_SET_QKEY | IBT_CEP_SET_STATE, 1344 &qp_info, NULL); 1345 if (retval != IBT_SUCCESS) { 1346 IBTF_DPRINTF_L2(ibtl_chan, "ibt_update_channel_qkey: " 1347 "Failed to modify QP %p: status %d", ud_chan, retval); 1348 } else { 1349 ud_chan->ch_transport.ud.ud_qkey = ud_dest->ud_qkey; 1350 } 1351 1352 return (retval); 1353 } 1354 1355 1356 /* 1357 * Function: 1358 * ibt_set_chan_private 1359 * Input: 1360 * chan A previously allocated channel handle. 1361 * clnt_private The client private data. 1362 * Output: 1363 * none. 1364 * Returns: 1365 * none. 1366 * Description: 1367 * Set the client private data. 1368 */ 1369 void 1370 ibt_set_chan_private(ibt_channel_hdl_t chan, void *clnt_private) 1371 { 1372 chan->ch_clnt_private = clnt_private; 1373 } 1374 1375 1376 /* 1377 * Function: 1378 * ibt_get_chan_private 1379 * Input: 1380 * chan A previously allocated channel handle. 1381 * Output: 1382 * A pointer to the client private data. 1383 * Returns: 1384 * none. 1385 * Description: 1386 * Get a pointer to client private data. 1387 */ 1388 void * 1389 ibt_get_chan_private(ibt_channel_hdl_t chan) 1390 { 1391 return (chan->ch_clnt_private); 1392 } 1393 1394 /* 1395 * Function: 1396 * ibt_channel_to_hca_guid 1397 * Input: 1398 * chan Channel Handle. 1399 * Output: 1400 * none. 1401 * Returns: 1402 * hca_guid Returned HCA GUID on which the specified Channel is 1403 * allocated. Valid if it is non-NULL on return. 1404 * Description: 1405 * A helper function to retrieve HCA GUID for the specified Channel. 1406 */ 1407 ib_guid_t 1408 ibt_channel_to_hca_guid(ibt_channel_hdl_t chan) 1409 { 1410 IBTF_DPRINTF_L3(ibtl_chan, "ibt_channel_to_hca_guid(%p)", chan); 1411 1412 return (IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(chan))); 1413 } 1414 1415 /* 1416 * Protection Domain Verbs Functions. 1417 */ 1418 1419 /* 1420 * Function: 1421 * ibt_alloc_pd 1422 * Input: 1423 * hca_hdl The IBT HCA handle, the device on which we need 1424 * to create the requested Protection Domain. 1425 * flags IBT_PD_NO_FLAGS, IBT_PD_USER_MAP or IBT_PD_DEFER_ALLOC 1426 * Output: 1427 * pd IBT Protection Domain Handle. 1428 * Returns: 1429 * IBT_SUCCESS 1430 * IBT_HCA_HDL_INVALID 1431 * Description: 1432 * Allocate a Protection Domain. 1433 */ 1434 ibt_status_t 1435 ibt_alloc_pd(ibt_hca_hdl_t hca_hdl, ibt_pd_flags_t flags, ibt_pd_hdl_t *pd) 1436 { 1437 ibt_status_t retval; 1438 1439 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_pd(%p, %x)", hca_hdl, flags); 1440 1441 /* re-direct the call to CI's call */ 1442 ibtl_qp_flow_control_enter(); 1443 retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_pd( 1444 IBTL_HCA2CIHCA(hca_hdl), flags, pd); 1445 ibtl_qp_flow_control_exit(); 1446 if (retval != IBT_SUCCESS) { 1447 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_pd: CI PD Alloc Err"); 1448 return (retval); 1449 } 1450 1451 /* Update the PDs Resource Count per HCA Device. */ 1452 atomic_inc_32(&hca_hdl->ha_pd_cnt); 1453 1454 return (retval); 1455 } 1456 1457 /* 1458 * Function: 1459 * ibt_free_pd 1460 * Input: 1461 * hca_hdl The IBT HCA handle, the device on which we need 1462 * to free the requested Protection Domain. 1463 * pd IBT Protection Domain Handle. 1464 * Output: 1465 * none. 1466 * Returns: 1467 * IBT_SUCCESS 1468 * IBT_HCA_HDL_INVALID 1469 * IBT_MEM_PD_HDL_INVALID 1470 * IBT_MEM_PD_IN_USE 1471 * Description: 1472 * Release/de-allocate a Protection Domain. 1473 */ 1474 ibt_status_t 1475 ibt_free_pd(ibt_hca_hdl_t hca_hdl, ibt_pd_hdl_t pd) 1476 { 1477 ibt_status_t retval; 1478 1479 IBTF_DPRINTF_L3(ibtl_chan, "ibt_free_pd(%p, %p)", hca_hdl, pd); 1480 1481 /* re-direct the call to CI's call */ 1482 retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_free_pd( 1483 IBTL_HCA2CIHCA(hca_hdl), pd); 1484 if (retval != IBT_SUCCESS) { 1485 IBTF_DPRINTF_L2(ibtl_chan, "ibt_free_pd: CI Free PD Failed"); 1486 return (retval); 1487 } 1488 1489 /* Update the PDs Resource Count per HCA Device. */ 1490 atomic_dec_32(&hca_hdl->ha_pd_cnt); 1491 1492 return (retval); 1493 } 1494 1495 1496 /* 1497 * Address Handle Verbs Functions. 1498 */ 1499 1500 /* 1501 * Function: 1502 * ibt_alloc_ah 1503 * Input: 1504 * hca_hdl The IBT HCA Handle. 1505 * pd The IBT Protection Domain to associate with this handle. 1506 * adds_vectp Points to an ibt_adds_vect_t struct. 1507 * Output: 1508 * ah IBT Address Handle. 1509 * Returns: 1510 * IBT_SUCCESS 1511 * IBT_HCA_HDL_INVALID 1512 * IBT_INSUFF_RESOURCE 1513 * IBT_MEM_PD_HDL_INVALID 1514 * Description: 1515 * Allocate and returns an Address Handle. 1516 */ 1517 ibt_status_t 1518 ibt_alloc_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_flags_t flags, ibt_pd_hdl_t pd, 1519 ibt_adds_vect_t *adds_vectp, ibt_ah_hdl_t *ah) 1520 { 1521 ibt_status_t retval; 1522 1523 IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ah(%p, %x, %p, %p)", 1524 hca_hdl, flags, pd, adds_vectp); 1525 1526 /* XXX - if av_send_grh, need to compute av_sgid_ix from av_sgid */ 1527 1528 /* re-direct the call to CI's call */ 1529 retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_ah( 1530 IBTL_HCA2CIHCA(hca_hdl), flags, pd, adds_vectp, ah); 1531 1532 if (retval != IBT_SUCCESS) { 1533 IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ah: " 1534 "ibc_alloc_ah failed: status = %d", retval); 1535 return (retval); 1536 } 1537 1538 /* Update the AHs Resource Count per HCA Device. */ 1539 atomic_inc_32(&hca_hdl->ha_ah_cnt); 1540 1541 return (retval); 1542 } 1543 1544 1545 /* 1546 * Function: 1547 * ibt_free_ah 1548 * Input: 1549 * hca_hdl The IBT HCA Handle. 1550 * ah IBT Address Handle. 1551 * Output: 1552 * none. 1553 * Returns: 1554 * IBT_SUCCESS 1555 * IBT_HCA_HDL_INVALID 1556 * IBT_AH_HDL_INVALID 1557 * Description: 1558 * Release/de-allocate the specified Address Handle. 1559 */ 1560 ibt_status_t 1561 ibt_free_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_hdl_t ah) 1562 { 1563 ibt_status_t retval; 1564 1565 IBTF_DPRINTF_L3(ibtl_chan, "ibt_free_ah(%p, %p)", hca_hdl, ah); 1566 1567 /* re-direct the call to CI's call */ 1568 retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_free_ah( 1569 IBTL_HCA2CIHCA(hca_hdl), ah); 1570 1571 if (retval != IBT_SUCCESS) { 1572 IBTF_DPRINTF_L2(ibtl_chan, "ibt_free_ah: CI Free AH Failed"); 1573 return (retval); 1574 } 1575 1576 /* Update the AHs Resource Count per HCA Device. */ 1577 atomic_dec_32(&hca_hdl->ha_ah_cnt); 1578 1579 return (retval); 1580 } 1581 1582 1583 /* 1584 * Function: 1585 * ibt_query_ah 1586 * Input: 1587 * hca_hdl The IBT HCA Handle. 1588 * ah IBT Address Handle. 1589 * Output: 1590 * pd The Protection Domain Handle with which this 1591 * Address Handle is associated. 1592 * adds_vectp Points to an ibt_adds_vect_t struct. 1593 * Returns: 1594 * IBT_SUCCESS/IBT_HCA_HDL_INVALID/IBT_AH_HDL_INVALID 1595 * Description: 1596 * Obtain the address vector information for the specified address handle. 1597 */ 1598 ibt_status_t 1599 ibt_query_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_hdl_t ah, ibt_pd_hdl_t *pd, 1600 ibt_adds_vect_t *adds_vectp) 1601 { 1602 ibt_status_t retval; 1603 1604 IBTF_DPRINTF_L3(ibtl_chan, "ibt_query_ah(%p, %p)", hca_hdl, ah); 1605 1606 /* re-direct the call to CI's call */ 1607 retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_query_ah( 1608 IBTL_HCA2CIHCA(hca_hdl), ah, pd, adds_vectp)); 1609 1610 /* 1611 * We need to fill in av_sgid, as the CI does only saves/restores 1612 * av_sgid_ix. 1613 */ 1614 if (retval == IBT_SUCCESS) { 1615 ibtl_hca_devinfo_t *hca_devp = hca_hdl->ha_hca_devp; 1616 uint8_t port = adds_vectp->av_port_num; 1617 1618 mutex_enter(&ibtl_clnt_list_mutex); 1619 if (port > 0 && port <= hca_devp->hd_hca_attr->hca_nports && 1620 adds_vectp->av_sgid_ix < IBTL_HDIP2SGIDTBLSZ(hca_devp)) { 1621 ib_gid_t *sgidp; 1622 1623 sgidp = hca_devp->hd_portinfop[port-1].p_sgid_tbl; 1624 adds_vectp->av_sgid = sgidp[adds_vectp->av_sgid_ix]; 1625 } else { 1626 adds_vectp->av_sgid.gid_prefix = 0; 1627 adds_vectp->av_sgid.gid_guid = 0; 1628 } 1629 mutex_exit(&ibtl_clnt_list_mutex); 1630 } 1631 return (retval); 1632 } 1633 1634 1635 /* 1636 * Function: 1637 * ibt_modify_ah 1638 * Input: 1639 * hca_hdl The IBT HCA Handle. 1640 * ah IBT Address Handle. 1641 * Output: 1642 * adds_vectp Points to an ibt_adds_vect_t struct. The new address 1643 * vector information is specified is returned in this 1644 * structure. 1645 * Returns: 1646 * IBT_SUCCESS/IBT_HCA_HDL_INVALID/IBT_AH_HDL_INVALID 1647 * Description: 1648 * Modify the address vector information for the specified Address Handle. 1649 */ 1650 ibt_status_t 1651 ibt_modify_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_hdl_t ah, 1652 ibt_adds_vect_t *adds_vectp) 1653 { 1654 IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_ah(%p, %p)", hca_hdl, ah); 1655 1656 /* XXX - if av_send_grh, need to compute av_sgid_ix from av_sgid */ 1657 1658 /* re-direct the call to CI's call */ 1659 return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_ah( 1660 IBTL_HCA2CIHCA(hca_hdl), ah, adds_vectp)); 1661 } 1662