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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/ib/ibtl/impl/ibtl.h> 29 #include <sys/ib/ibtl/impl/ibtl_cm.h> 30 31 /* 32 * ibtl_qp.c 33 * These routines implement (most of) the verbs related to 34 * Queue Pairs. 35 */ 36 37 /* Globals. */ 38 static char ibtf_qp[] = "ibtl"; 39 40 /* This table indirectly initializes the ibt_cep_next_state[] table. */ 41 typedef struct ibt_cep_next_state_s { 42 ibt_cep_state_t next_state; 43 ibt_cep_modify_flags_t modify_flags; 44 } ibt_cep_next_state_t; 45 46 struct { 47 ibt_cep_state_t current_state; 48 ibt_cep_state_t next_state; 49 ibt_cep_modify_flags_t modify_flags; 50 } ibt_cep_next_state_inits[] = { 51 { IBT_STATE_RESET, IBT_STATE_INIT, IBT_CEP_SET_RESET_INIT}, 52 { IBT_STATE_INIT, IBT_STATE_RTR, IBT_CEP_SET_INIT_RTR}, 53 { IBT_STATE_RTR, IBT_STATE_RTS, IBT_CEP_SET_RTR_RTS} 54 }; 55 56 ibt_cep_next_state_t ibt_cep_next_state[IBT_STATE_NUM]; 57 58 _NOTE(SCHEME_PROTECTS_DATA("unique", ibt_cep_next_state)) 59 60 /* The following data and functions can increase system stability. */ 61 62 int ibtl_qp_calls_curr; 63 int ibtl_qp_calls_max = 128; /* limit on # of simultaneous QP verb calls */ 64 kmutex_t ibtl_qp_mutex; 65 kcondvar_t ibtl_qp_cv; 66 67 void 68 ibtl_qp_flow_control_enter(void) 69 { 70 mutex_enter(&ibtl_qp_mutex); 71 while (ibtl_qp_calls_curr >= ibtl_qp_calls_max) { 72 cv_wait(&ibtl_qp_cv, &ibtl_qp_mutex); 73 } 74 ++ibtl_qp_calls_curr; 75 mutex_exit(&ibtl_qp_mutex); 76 } 77 78 void 79 ibtl_qp_flow_control_exit(void) 80 { 81 mutex_enter(&ibtl_qp_mutex); 82 cv_signal(&ibtl_qp_cv); 83 --ibtl_qp_calls_curr; 84 mutex_exit(&ibtl_qp_mutex); 85 } 86 87 /* 88 * Function: 89 * ibt_alloc_qp 90 * Input: 91 * hca_hdl HCA Handle. 92 * type Specifies the type of QP to alloc in ibt_alloc_qp() 93 * qp_attrp Specifies the ibt_qp_alloc_attr_t that are needed to 94 * allocate a QP and transition it to the RTS state for 95 * UDs and INIT state for all other QPs. 96 * Output: 97 * queue_sizes_p Returned sizes for SQ, RQ, SQ WR SGL elements & RQ 98 * WR SGL elements. 99 * qpn_p Returned QP Number of the allocated QP. 100 * ibt_qp_p The ibt_qp_hdl_t of the allocated QP. 101 * Returns: 102 * IBT_SUCCESS 103 * Description: 104 * Allocate a QP with specified attributes. 105 */ 106 ibt_status_t 107 ibt_alloc_qp(ibt_hca_hdl_t hca_hdl, ibt_qp_type_t type, 108 ibt_qp_alloc_attr_t *qp_attrp, ibt_chan_sizes_t *queue_sizes_p, 109 ib_qpn_t *qpn_p, ibt_qp_hdl_t *ibt_qp_p) 110 { 111 ibt_status_t retval; 112 ibtl_channel_t *chanp; 113 ibt_tran_srv_t qp_type; 114 115 IBTF_DPRINTF_L3(ibtf_qp, "ibt_alloc_qp(%p, %d, %p, %p, %p, %p) ", 116 hca_hdl, type, qp_attrp, queue_sizes_p, qpn_p, ibt_qp_p); 117 118 switch (type) { 119 case IBT_UD_RQP: 120 qp_type = IBT_UD_SRV; 121 break; 122 case IBT_RC_RQP: 123 qp_type = IBT_RC_SRV; 124 break; 125 case IBT_UC_RQP: 126 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Unreliable Connected " 127 "Transport Type is not supported."); 128 *ibt_qp_p = NULL; 129 return (IBT_NOT_SUPPORTED); 130 case IBT_RD_RQP: 131 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Reliable Datagram " 132 "Transport Type is not supported."); 133 *ibt_qp_p = NULL; 134 return (IBT_NOT_SUPPORTED); 135 default: 136 /* shouldn't happen ILLEGAL Type */ 137 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Illegal Transport Type " 138 "%d", type); 139 *ibt_qp_p = NULL; 140 return (IBT_QP_SRV_TYPE_INVALID); 141 } 142 143 /* Get CI CQ handles */ 144 if ((qp_attrp->qp_scq_hdl == NULL) || (qp_attrp->qp_rcq_hdl == NULL)) { 145 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Invalid CQ Handle"); 146 *ibt_qp_p = NULL; 147 return (IBT_CQ_HDL_INVALID); 148 } 149 qp_attrp->qp_ibc_scq_hdl = qp_attrp->qp_scq_hdl->cq_ibc_cq_hdl; 150 qp_attrp->qp_ibc_rcq_hdl = qp_attrp->qp_rcq_hdl->cq_ibc_cq_hdl; 151 152 if ((qp_attrp->qp_alloc_flags & IBT_QP_USES_SRQ) && 153 (qp_attrp->qp_srq_hdl != NULL)) 154 qp_attrp->qp_ibc_srq_hdl = 155 qp_attrp->qp_srq_hdl->srq_ibc_srq_hdl; 156 else 157 qp_attrp->qp_ibc_srq_hdl = NULL; 158 159 /* Allocate Channel structure */ 160 chanp = kmem_zalloc(sizeof (*chanp), KM_SLEEP); 161 162 ibtl_qp_flow_control_enter(); 163 retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_qp)( 164 IBTL_HCA2CIHCA(hca_hdl), &chanp->ch_qp, type, qp_attrp, 165 queue_sizes_p, qpn_p, &chanp->ch_qp.qp_ibc_qp_hdl); 166 ibtl_qp_flow_control_exit(); 167 if (retval != IBT_SUCCESS) { 168 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: " 169 "Failed to allocate QP: %d", retval); 170 kmem_free(chanp, sizeof (*chanp)); 171 *ibt_qp_p = NULL; 172 return (retval); 173 } 174 175 /* Initialize the internal QP struct. */ 176 chanp->ch_qp.qp_type = qp_type; 177 chanp->ch_qp.qp_hca = hca_hdl; 178 chanp->ch_qp.qp_send_cq = qp_attrp->qp_scq_hdl; 179 chanp->ch_qp.qp_recv_cq = qp_attrp->qp_rcq_hdl; 180 chanp->ch_current_state = IBT_STATE_RESET; 181 mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL); 182 cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL); 183 184 mutex_enter(&hca_hdl->ha_mutex); 185 hca_hdl->ha_qp_cnt++; 186 mutex_exit(&hca_hdl->ha_mutex); 187 188 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: SUCCESS: qp %p owned by '%s'", 189 chanp, hca_hdl->ha_clnt_devp->clnt_name); 190 191 *ibt_qp_p = chanp; 192 193 return (retval); 194 } 195 196 197 /* 198 * Function: 199 * ibt_initialize_qp 200 * Input: 201 * ibt_qp The previously allocated IBT QP Handle. 202 * modify_attrp Specifies the QP Modify attributes that to transition 203 * the QP to the RTS state for UDs (including special QPs) 204 * and INIT state for all other QPs. 205 * Output: 206 * none. 207 * Returns: 208 * IBT_SUCCESS 209 * Description: 210 * Transition the QP to the RTS state for UDs (including special QPs) 211 * and INIT state for all other QPs. 212 */ 213 ibt_status_t 214 ibt_initialize_qp(ibt_qp_hdl_t ibt_qp, ibt_qp_info_t *modify_attrp) 215 { 216 ibt_status_t status; 217 ibt_cep_state_t state; 218 ibc_hca_hdl_t ibc_hca_hdl = IBTL_CHAN2CIHCA(ibt_qp); 219 ibc_qp_hdl_t ibc_qp_hdl = IBTL_CHAN2CIQP(ibt_qp); 220 ibc_operations_t *hca_ops_p = IBTL_CHAN2CIHCAOPS_P(ibt_qp); 221 ibt_cep_modify_flags_t modify_flags; 222 223 IBTF_DPRINTF_L3(ibtf_qp, "ibt_initialize_qp(%p, %p)", 224 ibt_qp, modify_attrp); 225 226 /* 227 * Validate the QP Type from the channel with QP Type from the 228 * modify attribute struct. 229 */ 230 if (ibt_qp->ch_qp.qp_type != modify_attrp->qp_trans) { 231 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: " 232 "QP Type mismatch: Chan QP Type<%d>, Modify QP Type<%d>", 233 ibt_qp->ch_qp.qp_type, modify_attrp->qp_trans); 234 return (IBT_QP_SRV_TYPE_INVALID); 235 } 236 if (ibt_qp->ch_current_state != IBT_STATE_RESET) { 237 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: " 238 "QP needs to be in RESET state: Chan QP State<%d>", 239 ibt_qp->ch_current_state); 240 return (IBT_CHAN_STATE_INVALID); 241 } 242 243 /* 244 * Initialize the QP to the RTS state for UDs 245 * and INIT state for all other QPs. 246 */ 247 switch (modify_attrp->qp_trans) { 248 case IBT_UD_SRV: 249 250 /* 251 * Bring the QP to the RTS state. 252 */ 253 state = IBT_STATE_RESET; 254 ibtl_qp_flow_control_enter(); 255 do { 256 modify_attrp->qp_current_state = state; 257 modify_flags = ibt_cep_next_state[state].modify_flags; 258 modify_attrp->qp_state = state = 259 ibt_cep_next_state[state].next_state; 260 261 IBTF_DPRINTF_L3(ibtf_qp, "ibt_initialize_qp: " 262 "modifying qp state to 0x%x", state); 263 status = (hca_ops_p->ibc_modify_qp)(ibc_hca_hdl, 264 ibc_qp_hdl, modify_flags, modify_attrp, NULL); 265 } while ((state != IBT_STATE_RTS) && (status == IBT_SUCCESS)); 266 ibtl_qp_flow_control_exit(); 267 268 if (status == IBT_SUCCESS) { 269 ibt_qp->ch_current_state = state; 270 ibt_qp->ch_transport.ud.ud_port_num = 271 modify_attrp->qp_transport.ud.ud_port; 272 ibt_qp->ch_transport.ud.ud_qkey = 273 modify_attrp->qp_transport.ud.ud_qkey; 274 } 275 break; 276 case IBT_UC_SRV: 277 case IBT_RD_SRV: 278 case IBT_RC_SRV: 279 280 /* 281 * Bring the QP to the INIT state. 282 */ 283 modify_attrp->qp_state = IBT_STATE_INIT; 284 285 ibtl_qp_flow_control_enter(); 286 status = (hca_ops_p->ibc_modify_qp)(ibc_hca_hdl, ibc_qp_hdl, 287 IBT_CEP_SET_RESET_INIT, modify_attrp, NULL); 288 ibtl_qp_flow_control_exit(); 289 if (status == IBT_SUCCESS) 290 ibt_qp->ch_current_state = IBT_STATE_INIT; 291 break; 292 default: 293 /* shouldn't happen ILLEGAL Type */ 294 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: Illegal Type %d", 295 modify_attrp->qp_trans); 296 return (IBT_QP_SRV_TYPE_INVALID); 297 } /* End switch */ 298 299 return (status); 300 } 301 302 303 /* 304 * Function: 305 * ibt_alloc_special_qp 306 * Input: 307 * hca_hdl HCA Handle. 308 * type Specifies the type of Special QP to be allocated. 309 * qp_attrp Specifies the ibt_qp_alloc_attr_t that are needed to 310 * allocate a special QP. 311 * Output: 312 * queue_sizes_p Returned sizes for SQ, RQ, SQ WR SGL elements & RQ 313 * WR SGL elements. 314 * qpn_p Returned qpn of the allocated QP. 315 * ibt_qp_p The ibt_qp_hdl_t of the allocated QP. 316 * Returns: 317 * IBT_SUCCESS 318 * Description: 319 * Allocate a special QP with specified attributes. 320 */ 321 ibt_status_t 322 ibt_alloc_special_qp(ibt_hca_hdl_t hca_hdl, uint8_t port, ibt_sqp_type_t type, 323 ibt_qp_alloc_attr_t *qp_attrp, ibt_chan_sizes_t *queue_sizes_p, 324 ibt_qp_hdl_t *ibt_qp_p) 325 { 326 ibt_qp_hdl_t chanp; 327 ibt_status_t retval; 328 ibt_tran_srv_t sqp_type; 329 330 IBTF_DPRINTF_L3(ibtf_qp, "ibt_alloc_special_qp(%p, %d, %x, %p, %p, %p)", 331 hca_hdl, port, type, qp_attrp, queue_sizes_p, ibt_qp_p); 332 333 switch (type) { 334 case IBT_SMI_SQP: 335 case IBT_GSI_SQP: 336 sqp_type = IBT_UD_SRV; 337 break; 338 339 case IBT_RAWIP_SQP: 340 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: Raw IP " 341 "Transport Type is not supported."); 342 *ibt_qp_p = NULL; 343 return (IBT_NOT_SUPPORTED); 344 345 case IBT_RAWETHER_SQP: 346 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: Raw Ethernet " 347 "Transport Type is not supported."); 348 *ibt_qp_p = NULL; 349 return (IBT_NOT_SUPPORTED); 350 351 default: 352 /* Shouldn't happen */ 353 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: " 354 "Illegal Type 0x%x", type); 355 *ibt_qp_p = NULL; 356 return (IBT_QP_SPECIAL_TYPE_INVALID); 357 } 358 359 /* convert the CQ handles for the CI */ 360 qp_attrp->qp_ibc_scq_hdl = qp_attrp->qp_scq_hdl->cq_ibc_cq_hdl; 361 qp_attrp->qp_ibc_rcq_hdl = qp_attrp->qp_rcq_hdl->cq_ibc_cq_hdl; 362 363 /* Allocate Channel structure */ 364 chanp = kmem_zalloc(sizeof (*chanp), KM_SLEEP); 365 366 ibtl_qp_flow_control_enter(); 367 retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_special_qp)( 368 IBTL_HCA2CIHCA(hca_hdl), port, &chanp->ch_qp, type, qp_attrp, 369 queue_sizes_p, &chanp->ch_qp.qp_ibc_qp_hdl); 370 ibtl_qp_flow_control_exit(); 371 if (retval != IBT_SUCCESS) { 372 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: " 373 "Failed to allocate Special QP: %d", retval); 374 kmem_free(chanp, sizeof (*chanp)); 375 *ibt_qp_p = NULL; 376 return (retval); 377 } 378 379 /* Initialize the internal QP struct. */ 380 chanp->ch_qp.qp_type = sqp_type; 381 chanp->ch_qp.qp_hca = hca_hdl; 382 chanp->ch_qp.qp_send_cq = qp_attrp->qp_scq_hdl; 383 chanp->ch_qp.qp_recv_cq = qp_attrp->qp_rcq_hdl; 384 chanp->ch_current_state = IBT_STATE_RESET; 385 mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL); 386 cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL); 387 388 mutex_enter(&hca_hdl->ha_mutex); 389 hca_hdl->ha_qp_cnt++; 390 mutex_exit(&hca_hdl->ha_mutex); 391 392 *ibt_qp_p = chanp; 393 394 return (retval); 395 } 396 397 398 /* 399 * Function: 400 * ibt_flush_qp 401 * Input: 402 * ibtl_qp Handle for QP that needs to be flushed. 403 * Output: 404 * none. 405 * Returns: 406 * IBT_SUCCESS 407 * IBT_QP_HDL_INVALID 408 * Description: 409 * Put the QP into error state to flush out work requests. 410 */ 411 ibt_status_t 412 ibt_flush_qp(ibt_qp_hdl_t ibt_qp) 413 { 414 ibt_qp_info_t modify_attr; 415 ibt_status_t retval; 416 417 IBTF_DPRINTF_L3(ibtf_qp, "ibt_flush_qp(%p)", ibt_qp); 418 419 if (ibt_qp->ch_qp.qp_type == IBT_RC_SRV) { 420 mutex_enter(&ibtl_free_qp_mutex); 421 if ((ibt_qp->ch_transport.rc.rc_free_flags & 422 (IBTL_RC_QP_CONNECTED | IBTL_RC_QP_CLOSING)) == 423 IBTL_RC_QP_CONNECTED) { 424 mutex_exit(&ibtl_free_qp_mutex); 425 IBTF_DPRINTF_L2(ibtf_qp, "ibt_flush_qp(%p): " 426 "called with a connected RC QP", ibt_qp); 427 return (IBT_CHAN_STATE_INVALID); 428 } 429 mutex_exit(&ibtl_free_qp_mutex); 430 } 431 432 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 433 434 /* 435 * Set the QP state to error to flush any uncompleted WRs. 436 */ 437 modify_attr.qp_state = IBT_STATE_ERROR; 438 modify_attr.qp_trans = ibt_qp->ch_qp.qp_type; 439 440 retval = ibt_modify_qp(ibt_qp, IBT_CEP_SET_STATE, &modify_attr, NULL); 441 442 if (retval != IBT_SUCCESS) { 443 IBTF_DPRINTF_L2(ibtf_qp, "ibt_flush_qp: " 444 "failed on chan %p: %d", ibt_qp, retval); 445 } 446 return (retval); 447 } 448 449 450 /* 451 * ibtl_cm_chan_is_open() 452 * 453 * Inform IBTL that the connection has been established on this 454 * channel so that a later call to ibtl_cm_chan_is_closed() 455 * will be required to free the QPN used by this channel. 456 * 457 * chan Channel Handle 458 */ 459 void 460 ibtl_cm_chan_is_open(ibt_channel_hdl_t chan) 461 { 462 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_open(%p)", chan); 463 ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV); 464 mutex_enter(&ibtl_free_qp_mutex); 465 ASSERT(chan->ch_transport.rc.rc_free_flags == 0); 466 chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CONNECTED; 467 mutex_exit(&ibtl_free_qp_mutex); 468 } 469 470 /* 471 * ibtl_cm_is_chan_closing() 472 * 473 * Returns 1, if the connection that has been 474 * started for this channel has moved to TIMEWAIT 475 * If not, returns 0 476 * 477 * chan Channel Handle 478 */ 479 int 480 ibtl_cm_is_chan_closing(ibt_channel_hdl_t chan) 481 { 482 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_is_chan_closing(%p)", chan); 483 ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV); 484 mutex_enter(&ibtl_free_qp_mutex); 485 if (chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_CLOSING) { 486 mutex_exit(&ibtl_free_qp_mutex); 487 return (1); 488 } 489 mutex_exit(&ibtl_free_qp_mutex); 490 return (0); 491 } 492 493 /* 494 * ibtl_cm_is_chan_closed() 495 * 496 * Returns 1, if the connection that has been 497 * started for this channel has completed TIMEWAIT 498 * If not, returns 0 499 * 500 * chan Channel Handle 501 */ 502 int 503 ibtl_cm_is_chan_closed(ibt_channel_hdl_t chan) 504 { 505 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_is_chan_closed(%p)", chan); 506 ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV); 507 mutex_enter(&ibtl_free_qp_mutex); 508 if (chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_CLOSED) { 509 mutex_exit(&ibtl_free_qp_mutex); 510 return (1); 511 } 512 mutex_exit(&ibtl_free_qp_mutex); 513 return (0); 514 } 515 /* 516 * ibtl_cm_chan_is_closing() 517 * 518 * Inform IBTL that the TIMEWAIT delay for the connection has been 519 * started for this channel so that the QP can be freed. 520 * 521 * chan Channel Handle 522 */ 523 void 524 ibtl_cm_chan_is_closing(ibt_channel_hdl_t chan) 525 { 526 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_closing(%p)", chan); 527 ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV); 528 mutex_enter(&ibtl_free_qp_mutex); 529 ASSERT(chan->ch_transport.rc.rc_free_flags == IBTL_RC_QP_CONNECTED); 530 chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CLOSING; 531 mutex_exit(&ibtl_free_qp_mutex); 532 } 533 /* 534 * ibtl_cm_chan_is_closed() 535 * 536 * Inform IBTL that the TIMEWAIT delay for the connection has been 537 * reached for this channel so that the QPN can be reused. 538 * 539 * chan Channel Handle 540 */ 541 void 542 ibtl_cm_chan_is_closed(ibt_channel_hdl_t chan) 543 { 544 ibt_status_t status; 545 ibtl_hca_t *ibtl_hca = chan->ch_qp.qp_hca; 546 547 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_closed(%p)", chan); 548 ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV); 549 mutex_enter(&ibtl_free_qp_mutex); 550 ASSERT((chan->ch_transport.rc.rc_free_flags & 551 (IBTL_RC_QP_CONNECTED | IBTL_RC_QP_CLOSING)) == 552 (IBTL_RC_QP_CONNECTED | IBTL_RC_QP_CLOSING)); 553 554 chan->ch_transport.rc.rc_free_flags &= ~IBTL_RC_QP_CONNECTED; 555 chan->ch_transport.rc.rc_free_flags &= ~IBTL_RC_QP_CLOSING; 556 chan->ch_transport.rc.rc_free_flags |= IBTL_RC_QP_CLOSED; 557 558 ibtl_cm_set_chan_private(chan, NULL); 559 560 if ((chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_FREED) == 0) { 561 mutex_exit(&ibtl_free_qp_mutex); 562 return; 563 } 564 mutex_exit(&ibtl_free_qp_mutex); 565 ibtl_qp_flow_control_enter(); 566 if ((status = (IBTL_CHAN2CIHCAOPS_P(chan)->ibc_release_qpn) 567 (IBTL_CHAN2CIHCA(chan), chan->ch_transport.rc.rc_qpn_hdl)) == 568 IBT_SUCCESS) { 569 /* effectively, this is kmem_free(chan); */ 570 ibtl_free_qp_async_check(&chan->ch_qp); 571 572 /* decrement ha_qpn_cnt and check for close in progress */ 573 ibtl_close_hca_check(ibtl_hca); 574 } else 575 IBTF_DPRINTF_L2(ibtf_qp, "ibtl_cm_chan_is_closed: " 576 "ibc_release_qpn failed: status = %d\n", status); 577 ibtl_qp_flow_control_exit(); 578 } 579 580 /* 581 * ibtl_cm_chan_is_reused() 582 * 583 * Inform IBTL that the channel is going to be re-used 584 * chan Channel Handle 585 */ 586 void 587 ibtl_cm_chan_is_reused(ibt_channel_hdl_t chan) 588 { 589 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_cm_chan_is_reused(%p)", chan); 590 ASSERT(chan->ch_qp.qp_type == IBT_RC_SRV); 591 mutex_enter(&ibtl_free_qp_mutex); 592 ASSERT(((chan->ch_transport.rc.rc_free_flags & IBTL_RC_QP_CONNECTED) != 593 IBTL_RC_QP_CONNECTED)); 594 595 /* channel is no longer in closed state, shall be re-used */ 596 chan->ch_transport.rc.rc_free_flags = 0; 597 598 mutex_exit(&ibtl_free_qp_mutex); 599 600 } 601 602 /* 603 * Function: ibt_free_qp() 604 * 605 * Input: ibt_qp Handle for Channel(QP) that needs to be freed. 606 * 607 * Output: NONE. 608 * 609 * Returns: IBT_SUCCESS 610 * IBT_QP_STATE_INVALID 611 * IBT_QP_HDL_INVALID 612 * 613 * Description: 614 * Free a previously allocated QP. 615 */ 616 ibt_status_t 617 ibt_free_qp(ibt_qp_hdl_t ibt_qp) 618 { 619 ibt_status_t status; 620 ibtl_hca_t *ibtl_hca = ibt_qp->ch_qp.qp_hca; 621 622 IBTF_DPRINTF_L3(ibtf_qp, "ibt_free_qp(%p)", ibt_qp); 623 624 if (ibt_qp->ch_qp.qp_type == IBT_RC_SRV) { 625 ibtl_qp_flow_control_enter(); 626 mutex_enter(&ibtl_free_qp_mutex); 627 if (ibt_qp->ch_transport.rc.rc_free_flags & 628 IBTL_RC_QP_CONNECTED) { 629 if ((ibt_qp->ch_transport.rc.rc_free_flags & 630 IBTL_RC_QP_CLOSING) == 0) { 631 IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: ERROR - " 632 "need to call ibt_close_rc_channel"); 633 mutex_exit(&ibtl_free_qp_mutex); 634 ibtl_qp_flow_control_exit(); 635 return (IBT_CHAN_STATE_INVALID); 636 } 637 ibt_qp->ch_transport.rc.rc_free_flags |= 638 IBTL_RC_QP_FREED; 639 status = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_free_qp) 640 (IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp), 641 IBC_FREE_QP_ONLY, 642 &ibt_qp->ch_transport.rc.rc_qpn_hdl); 643 mutex_exit(&ibtl_free_qp_mutex); 644 ibtl_qp_flow_control_exit(); 645 646 if (status == IBT_SUCCESS) { 647 mutex_enter(&ibtl_clnt_list_mutex); 648 ibtl_hca->ha_qpn_cnt++; 649 mutex_exit(&ibtl_clnt_list_mutex); 650 mutex_enter(&ibtl_hca->ha_mutex); 651 ibtl_hca->ha_qp_cnt--; 652 mutex_exit(&ibtl_hca->ha_mutex); 653 IBTF_DPRINTF_L3(ibtf_qp, "ibt_free_qp(%p) - " 654 "SUCCESS", ibt_qp); 655 } else 656 IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: " 657 "ibc_free_qp failed: status = %d", status); 658 return (status); 659 } 660 mutex_exit(&ibtl_free_qp_mutex); 661 } else 662 ibtl_qp_flow_control_enter(); 663 664 status = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_free_qp) 665 (IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp), 666 IBC_FREE_QP_AND_QPN, NULL); 667 ibtl_qp_flow_control_exit(); 668 669 if (status == IBT_SUCCESS) { 670 /* effectively, this is kmem_free(ibt_qp); */ 671 ibtl_free_qp_async_check(&ibt_qp->ch_qp); 672 673 mutex_enter(&ibtl_hca->ha_mutex); 674 ibtl_hca->ha_qp_cnt--; 675 mutex_exit(&ibtl_hca->ha_mutex); 676 IBTF_DPRINTF_L3(ibtf_qp, "ibt_free_qp(%p) - SUCCESS", ibt_qp); 677 } else { 678 IBTF_DPRINTF_L2(ibtf_qp, "ibt_free_qp: " 679 "ibc_free_qp failed with error %d", status); 680 } 681 682 return (status); 683 } 684 685 686 /* helper function for ibt_query_qp */ 687 static void 688 ibtl_fillin_sgid(ibt_cep_path_t *pathp, ibtl_hca_devinfo_t *hca_devp) 689 { 690 uint8_t port; 691 uint32_t sgid_ix; 692 ib_gid_t *sgidp; 693 694 port = pathp->cep_hca_port_num; 695 sgid_ix = pathp->cep_adds_vect.av_sgid_ix; 696 if (port == 0 || port > hca_devp->hd_hca_attr->hca_nports || 697 sgid_ix >= IBTL_HDIP2SGIDTBLSZ(hca_devp)) { 698 pathp->cep_adds_vect.av_sgid.gid_prefix = 0; 699 pathp->cep_adds_vect.av_sgid.gid_guid = 0; 700 } else { 701 mutex_enter(&ibtl_clnt_list_mutex); 702 sgidp = hca_devp->hd_portinfop[port-1].p_sgid_tbl; 703 pathp->cep_adds_vect.av_sgid = sgidp[sgid_ix]; 704 mutex_exit(&ibtl_clnt_list_mutex); 705 } 706 } 707 708 709 /* 710 * Function: ibt_query_qp 711 * 712 * Input: ibt_qp - The IBT QP Handle. 713 * 714 * Output: ibt_qp_query_attrp - Points to a ibt_qp_query_attr_t 715 * that on return contains all the 716 * attributes of the specified qp. 717 * 718 * Returns: IBT_SUCCESS 719 * IBT_QP_HDL_INVALID 720 * 721 * Description: 722 * Query QP attributes 723 * 724 */ 725 ibt_status_t 726 ibt_query_qp(ibt_qp_hdl_t ibt_qp, ibt_qp_query_attr_t *qp_query_attrp) 727 { 728 ibt_status_t retval; 729 ibtl_hca_devinfo_t *hca_devp; 730 ibt_qp_info_t *qp_infop; 731 732 IBTF_DPRINTF_L3(ibtf_qp, "ibt_query_qp(%p, %p)", 733 ibt_qp, qp_query_attrp); 734 735 ibtl_qp_flow_control_enter(); 736 retval = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_query_qp( 737 IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp), qp_query_attrp)); 738 ibtl_qp_flow_control_exit(); 739 if (retval == IBT_SUCCESS) { 740 ibt_qp->ch_current_state = qp_query_attrp->qp_info.qp_state; 741 742 /* need to fill in sgid from port and sgid_ix for RC and UC */ 743 hca_devp = ibt_qp->ch_qp.qp_hca->ha_hca_devp; 744 qp_infop = &qp_query_attrp->qp_info; 745 746 switch (qp_infop->qp_trans) { 747 case IBT_RC_SRV: 748 ibtl_fillin_sgid(&qp_infop->qp_transport.rc.rc_path, 749 hca_devp); 750 ibtl_fillin_sgid(&qp_infop->qp_transport.rc.rc_alt_path, 751 hca_devp); 752 break; 753 case IBT_UC_SRV: 754 ibtl_fillin_sgid(&qp_infop->qp_transport.uc.uc_path, 755 hca_devp); 756 ibtl_fillin_sgid(&qp_infop->qp_transport.uc.uc_alt_path, 757 hca_devp); 758 break; 759 } 760 } else { 761 IBTF_DPRINTF_L2(ibtf_qp, "ibt_query_qp: " 762 "failed on chan %p: %d", ibt_qp, retval); 763 } 764 765 return (retval); 766 } 767 768 769 /* 770 * Function: 771 * ibt_modify_qp 772 * Input: 773 * ibt_qp The IBT QP Handle. 774 * flags Specifies which attributes in ibt_qp_mod_attr_t 775 * are to be modified. 776 * qp_attrp Points to an ibt_qp_mod_attr_t struct that contains all 777 * the attributes of the specified QP that a client is 778 * allowed to modify after a QP has been allocated 779 * Output: 780 * actual_sz Returned actual queue sizes. 781 * Returns: 782 * IBT_SUCCESS 783 * Description: 784 * Modify the attributes of an existing QP. 785 */ 786 ibt_status_t 787 ibt_modify_qp(ibt_qp_hdl_t ibt_qp, ibt_cep_modify_flags_t flags, 788 ibt_qp_info_t *modify_attrp, ibt_queue_sizes_t *actual_sz) 789 { 790 ibt_status_t retval; 791 792 IBTF_DPRINTF_L3(ibtf_qp, "ibt_modify_qp(%p, %d, %p, %p)", 793 ibt_qp, flags, modify_attrp, actual_sz); 794 795 ibtl_qp_flow_control_enter(); 796 retval = (IBTL_CHAN2CIHCAOPS_P(ibt_qp)->ibc_modify_qp)( 797 IBTL_CHAN2CIHCA(ibt_qp), IBTL_CHAN2CIQP(ibt_qp), flags, 798 modify_attrp, actual_sz); 799 ibtl_qp_flow_control_exit(); 800 if (retval == IBT_SUCCESS) { 801 ibt_qp->ch_current_state = modify_attrp->qp_state; 802 if (ibt_qp->ch_qp.qp_type == IBT_UD_SRV) { 803 if (flags & (IBT_CEP_SET_PORT | IBT_CEP_SET_RESET_INIT)) 804 ibt_qp->ch_transport.ud.ud_port_num = 805 modify_attrp->qp_transport.ud.ud_port; 806 if (flags & (IBT_CEP_SET_QKEY | IBT_CEP_SET_RESET_INIT)) 807 ibt_qp->ch_transport.ud.ud_qkey = 808 modify_attrp->qp_transport.ud.ud_qkey; 809 } 810 } else { 811 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_qp: failed on chan %p: %d", 812 ibt_qp, retval); 813 814 if (retval == IBT_CHAN_STATE_INVALID) { 815 /* That means our cache had invalid QP state value. */ 816 ibt_qp_query_attr_t qp_attr; 817 818 /* Query the channel (QP) */ 819 if (ibt_query_qp(ibt_qp, &qp_attr) == IBT_SUCCESS) 820 ibt_qp->ch_current_state = 821 qp_attr.qp_info.qp_state; 822 } 823 } 824 return (retval); 825 } 826 827 828 /* 829 * Function: 830 * ibt_migrate_path 831 * Input: 832 * rc_chan A previously allocated RC channel handle. 833 * Output: 834 * none. 835 * Returns: 836 * IBT_SUCCESS on Success else appropriate error. 837 * Description: 838 * Force the CI to use the alternate path. The alternate path becomes 839 * the primary path. A new alternate path should be loaded and enabled. 840 * Assumes that the given channel is in RTS/SQD state 841 */ 842 ibt_status_t 843 ibt_migrate_path(ibt_channel_hdl_t rc_chan) 844 { 845 ibt_status_t retval; 846 ibt_qp_info_t qp_info; 847 ibt_qp_query_attr_t qp_attr; 848 ibt_cep_modify_flags_t cep_flags; 849 int retries = 1; 850 851 IBTF_DPRINTF_L3(ibtf_qp, "ibt_migrate_path: channel %p", rc_chan); 852 853 if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) { 854 IBTF_DPRINTF_L2(ibtf_qp, "ibt_migrate_path: " 855 "Invalid Channel type: Applicable only to RC Channel"); 856 return (IBT_CHAN_SRV_TYPE_INVALID); 857 } 858 859 if (rc_chan->ch_current_state != IBT_STATE_RTS && 860 rc_chan->ch_current_state != IBT_STATE_SQD) { 861 if (ibt_query_qp(rc_chan, &qp_attr) == IBT_SUCCESS) { 862 /* ch_current_state is fixed by ibt_query_qp */ 863 if (rc_chan->ch_current_state != IBT_STATE_RTS && 864 rc_chan->ch_current_state != IBT_STATE_SQD) 865 return (IBT_CHAN_STATE_INVALID); 866 retries = 0; 867 } else /* query_qp should never really fail */ 868 return (IBT_CHAN_STATE_INVALID); 869 } 870 871 retry: 872 /* Call modify_qp */ 873 cep_flags = IBT_CEP_SET_MIG | IBT_CEP_SET_STATE; 874 qp_info.qp_state = rc_chan->ch_current_state; 875 qp_info.qp_current_state = rc_chan->ch_current_state; 876 qp_info.qp_trans = IBT_RC_SRV; 877 qp_info.qp_transport.rc.rc_mig_state = IBT_STATE_MIGRATED; 878 retval = ibt_modify_qp(rc_chan, cep_flags, &qp_info, NULL); 879 880 if (retval != IBT_SUCCESS) { 881 IBTF_DPRINTF_L2(ibtf_qp, "ibt_migrate_path:" 882 " ibt_modify_qp() returned = %d", retval); 883 if (rc_chan->ch_current_state != qp_info.qp_state && 884 --retries >= 0) { 885 /* 886 * That means our cached 'state' was invalid. 887 * We know ibt_modify_qp() fixed it up, so it 888 * might be worth retrying. 889 */ 890 if (rc_chan->ch_current_state != IBT_STATE_RTS && 891 rc_chan->ch_current_state != IBT_STATE_SQD) 892 return (IBT_CHAN_STATE_INVALID); 893 IBTF_DPRINTF_L2(ibtf_qp, "ibt_migrate_path:" 894 " retrying after 'state' fixed"); 895 goto retry; 896 } 897 } 898 return (retval); 899 } 900 901 902 /* 903 * Function: 904 * ibt_set_qp_private 905 * Input: 906 * ibt_qp The ibt_qp_hdl_t of the allocated QP. 907 * clnt_private The client private data. 908 * Output: 909 * none. 910 * Returns: 911 * none. 912 * Description: 913 * Set the client private data. 914 */ 915 void 916 ibt_set_qp_private(ibt_qp_hdl_t ibt_qp, void *clnt_private) 917 { 918 ibt_qp->ch_clnt_private = clnt_private; 919 } 920 921 922 /* 923 * Function: 924 * ibt_get_qp_private 925 * Input: 926 * ibt_qp The ibt_qp_hdl_t of the allocated QP. 927 * Output: 928 * none. 929 * Returns: 930 * The client private data. 931 * Description: 932 * Get the client private data. 933 */ 934 void * 935 ibt_get_qp_private(ibt_qp_hdl_t ibt_qp) 936 { 937 return (ibt_qp->ch_clnt_private); 938 } 939 940 941 /* 942 * Function: 943 * ibt_qp_to_hca_guid 944 * Input: 945 * ibt_qp The ibt_qp_hdl_t of the allocated QP. 946 * Output: 947 * none. 948 * Returns: 949 * hca_guid Returned HCA GUID on which the specified QP is 950 * allocated. Valid if it is non-NULL on return. 951 * Description: 952 * A helper function to retrieve HCA GUID for the specified QP. 953 */ 954 ib_guid_t 955 ibt_qp_to_hca_guid(ibt_qp_hdl_t ibt_qp) 956 { 957 IBTF_DPRINTF_L3(ibtf_qp, "ibt_qp_to_hca_guid(%p)", ibt_qp); 958 959 return (IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(ibt_qp))); 960 } 961 962 963 /* 964 * Function: 965 * ibt_recover_ud_qp 966 * Input: 967 * ibt_qp An QP Handle which is in SQError state. 968 * Output: 969 * none. 970 * Returns: 971 * IBT_SUCCESS 972 * IBT_QP_SRV_TYPE_INVALID 973 * IBT_QP_STATE_INVALID. 974 * Description: 975 * Recover an UD QP which has transitioned to SQ Error state. The 976 * ibt_recover_ud_qp() transitions the QP from SQ Error state to 977 * Ready-To-Send QP state. 978 * 979 * If a work request posted to a UD QP's send queue completes with an 980 * error (see ibt_wc_status_t), the QP gets transitioned to SQ Error state. 981 * In order to reuse this QP, ibt_recover_ud_qp() can be used to recover 982 * the QP to a usable (Ready-to-Send) state. 983 */ 984 ibt_status_t 985 ibt_recover_ud_qp(ibt_qp_hdl_t ibt_qp) 986 { 987 IBTF_DPRINTF_L3(ibtf_qp, "ibt_recover_ud_qp(%p)", ibt_qp); 988 989 return (ibt_recover_ud_channel(IBTL_QP2CHAN(ibt_qp))); 990 } 991 992 993 /* 994 * Function: 995 * ibt_recycle_ud 996 * Input: 997 * ud_chan The IBT UD QP Handle. 998 * various attributes 999 * 1000 * Output: 1001 * none 1002 * Returns: 1003 * IBT_SUCCESS 1004 * IBT_CHAN_SRV_TYPE_INVALID 1005 * IBT_CHAN_STATE_INVALID 1006 * 1007 * Description: 1008 * Revert the UD QP back to a usable state. 1009 */ 1010 ibt_status_t 1011 ibt_recycle_ud(ibt_channel_hdl_t ud_chan, uint8_t hca_port_num, 1012 uint16_t pkey_ix, ib_qkey_t qkey) 1013 { 1014 ibt_qp_query_attr_t qp_attr; 1015 ibt_status_t retval; 1016 1017 IBTF_DPRINTF_L3(ibtf_qp, "ibt_recycle_ud(%p, %d, %x, %x): ", 1018 ud_chan, hca_port_num, pkey_ix, qkey); 1019 1020 if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) { 1021 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: " 1022 "chan %p is not a UD channel", ud_chan); 1023 return (IBT_CHAN_SRV_TYPE_INVALID); 1024 } 1025 1026 retval = ibt_query_qp(ud_chan, &qp_attr); 1027 if (retval != IBT_SUCCESS) { 1028 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: " 1029 "ibt_query_qp failed on chan %p: %d", ud_chan, retval); 1030 return (retval); 1031 } 1032 if (qp_attr.qp_info.qp_state != IBT_STATE_ERROR) { 1033 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: " 1034 "chan %p is in state %d (not in ERROR state)", 1035 ud_chan, qp_attr.qp_info.qp_state); 1036 ud_chan->ch_current_state = qp_attr.qp_info.qp_state; 1037 return (IBT_CHAN_STATE_INVALID); 1038 } 1039 1040 /* transition the QP from ERROR to RESET */ 1041 qp_attr.qp_info.qp_state = IBT_STATE_RESET; 1042 qp_attr.qp_info.qp_trans = ud_chan->ch_qp.qp_type; 1043 retval = ibt_modify_qp(ud_chan, IBT_CEP_SET_STATE, &qp_attr.qp_info, 1044 NULL); 1045 if (retval != IBT_SUCCESS) { 1046 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: " 1047 "ibt_modify_qp(ERROR=>RESET) failed on chan %p: %d", 1048 ud_chan, retval); 1049 return (retval); 1050 } 1051 ud_chan->ch_current_state = IBT_STATE_RESET; 1052 1053 /* transition the QP back to RTS */ 1054 qp_attr.qp_info.qp_transport.ud.ud_port = hca_port_num; 1055 qp_attr.qp_info.qp_transport.ud.ud_qkey = qkey; 1056 qp_attr.qp_info.qp_transport.ud.ud_pkey_ix = pkey_ix; 1057 retval = ibt_initialize_qp(ud_chan, &qp_attr.qp_info); 1058 if (retval != IBT_SUCCESS) { 1059 IBTF_DPRINTF_L2(ibtf_qp, "ibt_recycle_ud: " 1060 "ibt_initialize_qp failed on chan %p: %d", ud_chan, retval); 1061 /* the man page says the QP should be left in ERROR state */ 1062 (void) ibt_flush_qp(ud_chan); 1063 } 1064 return (retval); 1065 } 1066 1067 /* 1068 * Function: 1069 * ibt_pause_sendq 1070 * Input: 1071 * chan The IBT QP Handle. 1072 * modify_flags IBT_CEP_SET_NOTHING or IBT_CEP_SET_SQD_EVENT 1073 * 1074 * Output: 1075 * none. 1076 * Returns: 1077 * IBT_SUCCESS 1078 * IBT_CHAN_HDL_INVALID 1079 * IBT_CHAN_STATE_INVALID 1080 * IBT_INVALID_PARAM 1081 * 1082 * Description: 1083 * Place the send queue of the specified channel into the send queue 1084 * drained (SQD) state. 1085 * 1086 */ 1087 ibt_status_t 1088 ibt_pause_sendq(ibt_channel_hdl_t chan, ibt_cep_modify_flags_t modify_flags) 1089 { 1090 ibt_qp_info_t modify_attr; 1091 ibt_status_t retval; 1092 1093 IBTF_DPRINTF_L3(ibtf_qp, "ibt_pause_sendq(%p, %x)", chan, modify_flags); 1094 1095 modify_flags &= IBT_CEP_SET_SQD_EVENT; /* ignore other bits */ 1096 modify_flags |= IBT_CEP_SET_STATE; 1097 1098 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 1099 /* 1100 * Set the QP state to SQD. 1101 */ 1102 modify_attr.qp_state = IBT_STATE_SQD; 1103 modify_attr.qp_trans = chan->ch_qp.qp_type; 1104 1105 retval = ibt_modify_qp(chan, modify_flags, &modify_attr, NULL); 1106 1107 if (retval != IBT_SUCCESS) { 1108 IBTF_DPRINTF_L2(ibtf_qp, "ibt_pause_sendq: " 1109 "failed on chan %p: %d", chan, retval); 1110 } 1111 return (retval); 1112 } 1113 1114 1115 /* 1116 * Function: 1117 * ibt_unpause_sendq 1118 * Input: 1119 * chan The IBT Channel Handle. 1120 * Output: 1121 * none. 1122 * Returns: 1123 * IBT_SUCCESS 1124 * IBT_CHAN_HDL_INVALID 1125 * IBT_CHAN_STATE_INVALID 1126 * Description: 1127 * Un-pauses the previously paused channel. This call will transition the 1128 * QP from SQD to RTS state. 1129 */ 1130 ibt_status_t 1131 ibt_unpause_sendq(ibt_channel_hdl_t chan) 1132 { 1133 ibt_qp_info_t modify_attr; 1134 ibt_status_t retval; 1135 1136 IBTF_DPRINTF_L3(ibtf_qp, "ibt_unpause_sendq(%p)", chan); 1137 1138 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 1139 1140 /* 1141 * Set the QP state to RTS. 1142 */ 1143 modify_attr.qp_current_state = IBT_STATE_SQD; 1144 modify_attr.qp_state = IBT_STATE_RTS; 1145 modify_attr.qp_trans = chan->ch_qp.qp_type; 1146 1147 retval = ibt_modify_qp(chan, IBT_CEP_SET_STATE, &modify_attr, NULL); 1148 if (retval != IBT_SUCCESS) { 1149 IBTF_DPRINTF_L2(ibtf_qp, "ibt_unpause_sendq: " 1150 "failed on chan %p: %d", chan, retval); 1151 } 1152 return (retval); 1153 } 1154 1155 1156 /* 1157 * Function: 1158 * ibt_resize_queues 1159 * Input: 1160 * chan A previously allocated channel handle. 1161 * flags QP Flags 1162 * IBT_SEND_Q 1163 * IBT_RECV_Q 1164 * request_sz Requested new sizes. 1165 * Output: 1166 * actual_sz Returned actual sizes. 1167 * Returns: 1168 * IBT_SUCCESS 1169 * Description: 1170 * Resize the SendQ/RecvQ sizes of a channel. Can only be called on 1171 * a previously opened channel. 1172 */ 1173 ibt_status_t 1174 ibt_resize_queues(ibt_channel_hdl_t chan, ibt_qflags_t flags, 1175 ibt_queue_sizes_t *request_sz, ibt_queue_sizes_t *actual_sz) 1176 { 1177 ibt_cep_modify_flags_t modify_flags = IBT_CEP_SET_STATE; 1178 ibt_qp_info_t modify_attr; 1179 ibt_status_t retval; 1180 1181 IBTF_DPRINTF_L3(ibtf_qp, "ibt_resize_queues(%p, 0x%X, %p, %p)", 1182 chan, flags, request_sz, actual_sz); 1183 1184 if ((flags & (IBT_SEND_Q | IBT_RECV_Q)) == 0) { 1185 IBTF_DPRINTF_L2(ibtf_qp, "ibt_resize_queues: " 1186 "Flags <0x%X> not set", flags); 1187 return (IBT_INVALID_PARAM); 1188 } 1189 1190 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 1191 1192 modify_attr.qp_current_state = chan->ch_current_state; 1193 modify_attr.qp_trans = chan->ch_qp.qp_type; 1194 modify_attr.qp_state = chan->ch_current_state; 1195 1196 if (flags & IBT_SEND_Q) { 1197 modify_attr.qp_sq_sz = request_sz->qs_sq; 1198 modify_flags |= IBT_CEP_SET_SQ_SIZE; 1199 } 1200 1201 if (flags & IBT_RECV_Q) { 1202 modify_attr.qp_rq_sz = request_sz->qs_rq; 1203 modify_flags |= IBT_CEP_SET_RQ_SIZE; 1204 } 1205 1206 retval = ibt_modify_qp(chan, modify_flags, &modify_attr, actual_sz); 1207 if (retval != IBT_SUCCESS) { 1208 IBTF_DPRINTF_L2(ibtf_qp, "ibt_resize_queues: " 1209 "failed on QP %p: %d", chan, retval); 1210 } 1211 1212 return (retval); 1213 } 1214 1215 1216 /* 1217 * Function: 1218 * ibt_query_queues 1219 * Input: 1220 * chan A previously allocated channel handle. 1221 * Output: 1222 * actual_sz Returned actual sizes. 1223 * Returns: 1224 * IBT_SUCCESS 1225 * Description: 1226 * Query the SendQ/RecvQ sizes of a channel. 1227 */ 1228 ibt_status_t 1229 ibt_query_queues(ibt_channel_hdl_t chan, ibt_queue_sizes_t *actual_sz) 1230 { 1231 ibt_status_t retval; 1232 ibt_qp_query_attr_t qp_query_attr; 1233 1234 IBTF_DPRINTF_L3(ibtf_qp, "ibt_query_queues(%p)", chan); 1235 1236 /* Perform Query QP and retrieve QP sizes. */ 1237 retval = ibt_query_qp(chan, &qp_query_attr); 1238 if (retval != IBT_SUCCESS) { 1239 IBTF_DPRINTF_L2(ibtf_qp, "ibt_query_queues: " 1240 "ibt_query_qp failed: qp %p: %d", chan, retval); 1241 return (retval); 1242 } 1243 1244 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(actual_sz->qs_rq, 1245 actual_sz->qs_sq)) 1246 actual_sz->qs_sq = qp_query_attr.qp_info.qp_sq_sz; 1247 actual_sz->qs_rq = qp_query_attr.qp_info.qp_rq_sz; 1248 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(actual_sz->qs_rq, 1249 actual_sz->qs_sq)) 1250 chan->ch_current_state = qp_query_attr.qp_info.qp_state; 1251 1252 return (retval); 1253 } 1254 1255 1256 /* 1257 * Function: 1258 * ibt_modify_rdma 1259 * Input: 1260 * rc_chan A previously allocated channel handle. 1261 * 1262 * modify_flags Bitwise "or" of any of the following: 1263 * IBT_CEP_SET_RDMA_R Enable/Disable RDMA RD 1264 * IBT_CEP_SET_RDMA_W Enable/Disable RDMA WR 1265 * IBT_CEP_SET_ATOMIC Enable/Disable Atomics 1266 * 1267 * flags Channel End Point (CEP) Disable Flags (0 => enable). 1268 * IBT_CEP_NO_RDMA_RD Disable incoming RDMA RD's 1269 * IBT_CEP_NO_RDMA_WR Disable incoming RDMA WR's 1270 * IBT_CEP_NO_ATOMIC Disable incoming Atomics. 1271 * Output: 1272 * none. 1273 * Returns: 1274 * IBT_SUCCESS 1275 * IBT_QP_SRV_TYPE_INVALID 1276 * IBT_CHAN_HDL_INVALID 1277 * IBT_CHAN_ATOMICS_NOT_SUPPORTED 1278 * IBT_CHAN_STATE_INVALID 1279 * Description: 1280 * Enable/disable RDMA operations. To enable an operation clear the 1281 * "disable" flag. Can call this function when the channel is in 1282 * INIT, RTS or SQD states. If called in any other state 1283 * IBT_CHAN_STATE_INVALID is returned. When the operation completes the 1284 * channel state is left unchanged. 1285 */ 1286 ibt_status_t 1287 ibt_modify_rdma(ibt_channel_hdl_t rc_chan, 1288 ibt_cep_modify_flags_t modify_flags, ibt_cep_flags_t flags) 1289 { 1290 ibt_status_t retval; 1291 ibt_qp_info_t modify_attr; 1292 1293 IBTF_DPRINTF_L3(ibtf_qp, "ibt_modify_rdma(%p, 0x%x, 0x%x)", 1294 rc_chan, modify_flags, flags); 1295 1296 if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) { 1297 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_rdma: " 1298 "Invalid Channel type: 0x%X, Applicable only to RC Channel", 1299 rc_chan->ch_qp.qp_type); 1300 return (IBT_QP_SRV_TYPE_INVALID); 1301 } 1302 1303 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 1304 1305 /* 1306 * Can only call this function when the channel in INIT, RTS or SQD 1307 * states. 1308 */ 1309 if ((rc_chan->ch_current_state != IBT_STATE_INIT) && 1310 (rc_chan->ch_current_state != IBT_STATE_RTS) && 1311 (rc_chan->ch_current_state != IBT_STATE_SQD)) { 1312 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_rdma: Invalid Channel " 1313 "state: 0x%X", rc_chan->ch_current_state); 1314 return (IBT_CHAN_STATE_INVALID); 1315 } 1316 1317 modify_attr.qp_state = modify_attr.qp_current_state = 1318 rc_chan->ch_current_state; 1319 modify_attr.qp_trans = rc_chan->ch_qp.qp_type; 1320 modify_attr.qp_flags = flags; 1321 1322 modify_flags &= (IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W | 1323 IBT_CEP_SET_ATOMIC); 1324 modify_flags |= IBT_CEP_SET_STATE; 1325 1326 retval = ibt_modify_qp(rc_chan, modify_flags, &modify_attr, NULL); 1327 if (retval != IBT_SUCCESS) { 1328 IBTF_DPRINTF_L2(ibtf_qp, "ibt_modify_rdma: " 1329 "failed on chan %p: %d", rc_chan, retval); 1330 } 1331 return (retval); 1332 } 1333 1334 1335 /* 1336 * Function: 1337 * ibt_set_rdma_resource 1338 * Input: 1339 * chan A previously allocated RC channel handle. 1340 * modify_flags Bitwise "or" of any of the following: 1341 * IBT_CEP_SET_RDMARA_OUT Initiator depth (rdma_ra_out) 1342 * IBT_CEP_SET_RDMARA_IN Responder Resources 1343 * (rdma_ra_in) 1344 * rdma_ra_out Outgoing RDMA Reads/Atomics 1345 * rdma_ra_in Incoming RDMA Reads/Atomics 1346 * Output: 1347 * none. 1348 * Returns: 1349 * IBT_SUCCESS 1350 * Description: 1351 * Change the number of resources to be used for incoming and outgoing 1352 * RDMA reads & Atomics. Can only be called on a previously opened 1353 * RC channel. Can only be called on a paused channel, and this will 1354 * un-pause that channel. 1355 */ 1356 ibt_status_t 1357 ibt_set_rdma_resource(ibt_channel_hdl_t chan, 1358 ibt_cep_modify_flags_t modify_flags, uint8_t rdma_ra_out, 1359 uint8_t resp_rdma_ra_out) 1360 { 1361 ibt_qp_info_t modify_attr; 1362 ibt_status_t retval; 1363 1364 IBTF_DPRINTF_L3(ibtf_qp, "ibt_set_rdma_resource(%p, 0x%x, %d, %d)", 1365 chan, modify_flags, rdma_ra_out, resp_rdma_ra_out); 1366 1367 if (chan->ch_qp.qp_type != IBT_RC_SRV) { 1368 IBTF_DPRINTF_L2(ibtf_qp, "ibt_set_rdma_resource: " 1369 "Invalid Channel type: 0x%X, Applicable only to RC Channel", 1370 chan->ch_qp.qp_type); 1371 return (IBT_CHAN_SRV_TYPE_INVALID); 1372 } 1373 1374 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 1375 1376 modify_attr.qp_trans = chan->ch_qp.qp_type; 1377 modify_attr.qp_state = IBT_STATE_SQD; 1378 1379 modify_attr.qp_transport.rc.rc_rdma_ra_out = rdma_ra_out; 1380 modify_attr.qp_transport.rc.rc_rdma_ra_in = resp_rdma_ra_out; 1381 modify_flags &= (IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN); 1382 modify_flags |= IBT_CEP_SET_STATE; 1383 1384 retval = ibt_modify_qp(chan, modify_flags, &modify_attr, NULL); 1385 if (retval != IBT_SUCCESS) { 1386 IBTF_DPRINTF_L2(ibtf_qp, "ibt_set_rdma_resource: " 1387 "failed on chan %p: %d", chan, retval); 1388 } 1389 return (retval); 1390 } 1391 1392 1393 /* 1394 * Function: 1395 * ibt_change_port 1396 * Input: 1397 * rc_chan A previously allocated RC channel handle. 1398 * port_num New HCA port. 1399 * Output: 1400 * none. 1401 * Returns: 1402 * IBT_SUCCESS 1403 * Description: 1404 * Change the primary physical port of a channel. (This is done only if 1405 * HCA supports this capability). 1406 */ 1407 ibt_status_t 1408 ibt_change_port(ibt_channel_hdl_t chan, uint8_t port_num) 1409 { 1410 ibt_cep_modify_flags_t modify_flags; 1411 ibt_qp_info_t modify_attr; 1412 ibt_status_t retval; 1413 1414 IBTF_DPRINTF_L3(ibtf_qp, "ibt_change_port(%p, %d)", chan, port_num); 1415 1416 if (chan->ch_qp.qp_type != IBT_RC_SRV) { 1417 IBTF_DPRINTF_L2(ibtf_qp, "ibt_change_port: " 1418 "Invalid Channel type: 0x%X, Applicable only to RC Channel", 1419 chan->ch_qp.qp_type); 1420 return (IBT_CHAN_SRV_TYPE_INVALID); 1421 } 1422 bzero(&modify_attr, sizeof (ibt_qp_info_t)); 1423 1424 modify_attr.qp_state = IBT_STATE_SQD; 1425 modify_attr.qp_trans = chan->ch_qp.qp_type; 1426 modify_attr.qp_transport.rc.rc_path.cep_hca_port_num = port_num; 1427 1428 modify_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PORT; 1429 1430 retval = ibt_modify_qp(chan, modify_flags, &modify_attr, NULL); 1431 if (retval != IBT_SUCCESS) { 1432 IBTF_DPRINTF_L2(ibtf_qp, "ibt_change_port: " 1433 "failed on chan %p: %d", chan, retval); 1434 } 1435 return (retval); 1436 } 1437 1438 1439 void 1440 ibtl_init_cep_states(void) 1441 { 1442 int index; 1443 int ibt_nstate_inits; 1444 1445 IBTF_DPRINTF_L3(ibtf_qp, "ibtl_init_cep_states()"); 1446 1447 ibt_nstate_inits = sizeof (ibt_cep_next_state_inits) / 1448 sizeof (ibt_cep_next_state_inits[0]); 1449 1450 /* 1451 * Initialize CEP next state table, using an indirect lookup table so 1452 * that this code isn't dependent on the ibt_cep_state_t enum values. 1453 */ 1454 for (index = 0; index < ibt_nstate_inits; index++) { 1455 ibt_cep_state_t state; 1456 1457 state = ibt_cep_next_state_inits[index].current_state; 1458 1459 ibt_cep_next_state[state].next_state = 1460 ibt_cep_next_state_inits[index].next_state; 1461 1462 ibt_cep_next_state[state].modify_flags = 1463 ibt_cep_next_state_inits[index].modify_flags; 1464 } 1465 } 1466