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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/ib/ibtl/impl/ibtl.h> 30 #include <sys/ib/ibtl/impl/ibtl_cm.h> 31 32 /* 33 * ibtl_qp.c 34 * These routines implement (most of) the verbs related to 35 * Queue Pairs. 36 */ 37 38 /* Globals. */ 39 static char ibtf_qp[] = "ibtl"; 40 41 /* This table indirectly initializes the ibt_cep_next_state[] table. */ 42 typedef struct ibt_cep_next_state_s { 43 ibt_cep_state_t next_state; 44 ibt_cep_modify_flags_t modify_flags; 45 } ibt_cep_next_state_t; 46 47 struct { 48 ibt_cep_state_t current_state; 49 ibt_cep_state_t next_state; 50 ibt_cep_modify_flags_t modify_flags; 51 } ibt_cep_next_state_inits[] = { 52 { IBT_STATE_RESET, IBT_STATE_INIT, IBT_CEP_SET_RESET_INIT}, 53 { IBT_STATE_INIT, IBT_STATE_RTR, IBT_CEP_SET_INIT_RTR}, 54 { IBT_STATE_RTR, IBT_STATE_RTS, IBT_CEP_SET_RTR_RTS} 55 }; 56 57 ibt_cep_next_state_t ibt_cep_next_state[IBT_STATE_NUM]; 58 59 _NOTE(SCHEME_PROTECTS_DATA("unique", ibt_cep_next_state)) 60 61 /* The following data and functions can increase system stability. */ 62 63 int ibtl_qp_calls_curr; 64 int ibtl_qp_calls_max = 128; /* limit on # of simultaneous QP verb calls */ 65 kmutex_t ibtl_qp_mutex; 66 kcondvar_t ibtl_qp_cv; 67 68 void 69 ibtl_qp_flow_control_enter(void) 70 { 71 mutex_enter(&ibtl_qp_mutex); 72 while (ibtl_qp_calls_curr >= ibtl_qp_calls_max) { 73 cv_wait(&ibtl_qp_cv, &ibtl_qp_mutex); 74 } 75 ++ibtl_qp_calls_curr; 76 mutex_exit(&ibtl_qp_mutex); 77 } 78 79 void 80 ibtl_qp_flow_control_exit(void) 81 { 82 mutex_enter(&ibtl_qp_mutex); 83 cv_signal(&ibtl_qp_cv); 84 --ibtl_qp_calls_curr; 85 mutex_exit(&ibtl_qp_mutex); 86 } 87 88 /* 89 * Function: 90 * ibt_alloc_qp 91 * Input: 92 * hca_hdl HCA Handle. 93 * type Specifies the type of QP to alloc in ibt_alloc_qp() 94 * qp_attrp Specifies the ibt_qp_alloc_attr_t that are needed to 95 * allocate a QP and transition it to the RTS state for 96 * UDs and INIT state for all other QPs. 97 * Output: 98 * queue_sizes_p Returned sizes for SQ, RQ, SQ WR SGL elements & RQ 99 * WR SGL elements. 100 * qpn_p Returned QP Number of the allocated QP. 101 * ibt_qp_p The ibt_qp_hdl_t of the allocated QP. 102 * Returns: 103 * IBT_SUCCESS 104 * Description: 105 * Allocate a QP with specified attributes. 106 */ 107 ibt_status_t 108 ibt_alloc_qp(ibt_hca_hdl_t hca_hdl, ibt_qp_type_t type, 109 ibt_qp_alloc_attr_t *qp_attrp, ibt_chan_sizes_t *queue_sizes_p, 110 ib_qpn_t *qpn_p, ibt_qp_hdl_t *ibt_qp_p) 111 { 112 ibt_status_t retval; 113 ibtl_channel_t *chanp; 114 ibt_tran_srv_t qp_type; 115 116 IBTF_DPRINTF_L3(ibtf_qp, "ibt_alloc_qp(%p, %d, %p, %p, %p, %p) ", 117 hca_hdl, type, qp_attrp, queue_sizes_p, qpn_p, ibt_qp_p); 118 119 switch (type) { 120 case IBT_UD_RQP: 121 qp_type = IBT_UD_SRV; 122 break; 123 case IBT_RC_RQP: 124 qp_type = IBT_RC_SRV; 125 break; 126 case IBT_UC_RQP: 127 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Unreliable Connected " 128 "Transport Type is not supported."); 129 *ibt_qp_p = NULL; 130 return (IBT_NOT_SUPPORTED); 131 case IBT_RD_RQP: 132 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Reliable Datagram " 133 "Transport Type is not supported."); 134 *ibt_qp_p = NULL; 135 return (IBT_NOT_SUPPORTED); 136 default: 137 /* shouldn't happen ILLEGAL Type */ 138 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Illegal Transport Type " 139 "%d", type); 140 *ibt_qp_p = NULL; 141 return (IBT_QP_SRV_TYPE_INVALID); 142 } 143 144 /* Get CI CQ handles */ 145 if ((qp_attrp->qp_scq_hdl == NULL) || (qp_attrp->qp_rcq_hdl == NULL)) { 146 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: Invalid CQ Handle"); 147 *ibt_qp_p = NULL; 148 return (IBT_CQ_HDL_INVALID); 149 } 150 qp_attrp->qp_ibc_scq_hdl = qp_attrp->qp_scq_hdl->cq_ibc_cq_hdl; 151 qp_attrp->qp_ibc_rcq_hdl = qp_attrp->qp_rcq_hdl->cq_ibc_cq_hdl; 152 153 if ((qp_attrp->qp_alloc_flags & IBT_QP_USES_SRQ) && 154 (qp_attrp->qp_srq_hdl != NULL)) 155 qp_attrp->qp_ibc_srq_hdl = 156 qp_attrp->qp_srq_hdl->srq_ibc_srq_hdl; 157 else 158 qp_attrp->qp_ibc_srq_hdl = NULL; 159 160 /* Allocate Channel structure */ 161 chanp = kmem_zalloc(sizeof (*chanp), KM_SLEEP); 162 163 ibtl_qp_flow_control_enter(); 164 retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_qp)( 165 IBTL_HCA2CIHCA(hca_hdl), &chanp->ch_qp, type, qp_attrp, 166 queue_sizes_p, qpn_p, &chanp->ch_qp.qp_ibc_qp_hdl); 167 ibtl_qp_flow_control_exit(); 168 if (retval != IBT_SUCCESS) { 169 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: " 170 "Failed to allocate QP: %d", retval); 171 kmem_free(chanp, sizeof (*chanp)); 172 *ibt_qp_p = NULL; 173 return (retval); 174 } 175 176 /* Initialize the internal QP struct. */ 177 chanp->ch_qp.qp_type = qp_type; 178 chanp->ch_qp.qp_hca = hca_hdl; 179 chanp->ch_qp.qp_send_cq = qp_attrp->qp_scq_hdl; 180 chanp->ch_qp.qp_recv_cq = qp_attrp->qp_rcq_hdl; 181 chanp->ch_current_state = IBT_STATE_RESET; 182 mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL); 183 cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL); 184 185 mutex_enter(&hca_hdl->ha_mutex); 186 hca_hdl->ha_qp_cnt++; 187 mutex_exit(&hca_hdl->ha_mutex); 188 189 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_qp: SUCCESS: qp %p owned by '%s'", 190 chanp, hca_hdl->ha_clnt_devp->clnt_name); 191 192 *ibt_qp_p = chanp; 193 194 return (retval); 195 } 196 197 198 /* 199 * Function: 200 * ibt_initialize_qp 201 * Input: 202 * ibt_qp The previously allocated IBT QP Handle. 203 * modify_attrp Specifies the QP Modify attributes that to transition 204 * the QP to the RTS state for UDs (including special QPs) 205 * and INIT state for all other QPs. 206 * Output: 207 * none. 208 * Returns: 209 * IBT_SUCCESS 210 * Description: 211 * Transition the QP to the RTS state for UDs (including special QPs) 212 * and INIT state for all other QPs. 213 */ 214 ibt_status_t 215 ibt_initialize_qp(ibt_qp_hdl_t ibt_qp, ibt_qp_info_t *modify_attrp) 216 { 217 ibt_status_t status; 218 ibt_cep_state_t state; 219 ibc_hca_hdl_t ibc_hca_hdl = IBTL_CHAN2CIHCA(ibt_qp); 220 ibc_qp_hdl_t ibc_qp_hdl = IBTL_CHAN2CIQP(ibt_qp); 221 ibc_operations_t *hca_ops_p = IBTL_CHAN2CIHCAOPS_P(ibt_qp); 222 ibt_cep_modify_flags_t modify_flags; 223 224 IBTF_DPRINTF_L3(ibtf_qp, "ibt_initialize_qp(%p, %p)", 225 ibt_qp, modify_attrp); 226 227 /* 228 * Validate the QP Type from the channel with QP Type from the 229 * modify attribute struct. 230 */ 231 if (ibt_qp->ch_qp.qp_type != modify_attrp->qp_trans) { 232 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: " 233 "QP Type mismatch: Chan QP Type<%d>, Modify QP Type<%d>", 234 ibt_qp->ch_qp.qp_type, modify_attrp->qp_trans); 235 return (IBT_QP_SRV_TYPE_INVALID); 236 } 237 if (ibt_qp->ch_current_state != IBT_STATE_RESET) { 238 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: " 239 "QP needs to be in RESET state: Chan QP State<%d>", 240 ibt_qp->ch_current_state); 241 return (IBT_CHAN_STATE_INVALID); 242 } 243 244 /* 245 * Initialize the QP to the RTS state for UDs 246 * and INIT state for all other QPs. 247 */ 248 switch (modify_attrp->qp_trans) { 249 case IBT_UD_SRV: 250 251 /* 252 * Bring the QP to the RTS state. 253 */ 254 state = IBT_STATE_RESET; 255 ibtl_qp_flow_control_enter(); 256 do { 257 modify_attrp->qp_current_state = state; 258 modify_flags = ibt_cep_next_state[state].modify_flags; 259 modify_attrp->qp_state = state = 260 ibt_cep_next_state[state].next_state; 261 262 IBTF_DPRINTF_L3(ibtf_qp, "ibt_initialize_qp: " 263 "modifying qp state to 0x%x", state); 264 status = (hca_ops_p->ibc_modify_qp)(ibc_hca_hdl, 265 ibc_qp_hdl, modify_flags, modify_attrp, NULL); 266 } while ((state != IBT_STATE_RTS) && (status == IBT_SUCCESS)); 267 ibtl_qp_flow_control_exit(); 268 269 if (status == IBT_SUCCESS) { 270 ibt_qp->ch_current_state = state; 271 ibt_qp->ch_transport.ud.ud_port_num = 272 modify_attrp->qp_transport.ud.ud_port; 273 ibt_qp->ch_transport.ud.ud_qkey = 274 modify_attrp->qp_transport.ud.ud_qkey; 275 } 276 break; 277 case IBT_UC_SRV: 278 case IBT_RD_SRV: 279 case IBT_RC_SRV: 280 281 /* 282 * Bring the QP to the INIT state. 283 */ 284 modify_attrp->qp_state = IBT_STATE_INIT; 285 286 ibtl_qp_flow_control_enter(); 287 status = (hca_ops_p->ibc_modify_qp)(ibc_hca_hdl, ibc_qp_hdl, 288 IBT_CEP_SET_RESET_INIT, modify_attrp, NULL); 289 ibtl_qp_flow_control_exit(); 290 if (status == IBT_SUCCESS) 291 ibt_qp->ch_current_state = IBT_STATE_INIT; 292 break; 293 default: 294 /* shouldn't happen ILLEGAL Type */ 295 IBTF_DPRINTF_L2(ibtf_qp, "ibt_initialize_qp: Illegal Type %d", 296 modify_attrp->qp_trans); 297 return (IBT_QP_SRV_TYPE_INVALID); 298 } /* End switch */ 299 300 return (status); 301 } 302 303 304 /* 305 * Function: 306 * ibt_alloc_special_qp 307 * Input: 308 * hca_hdl HCA Handle. 309 * type Specifies the type of Special QP to be allocated. 310 * qp_attrp Specifies the ibt_qp_alloc_attr_t that are needed to 311 * allocate a special QP. 312 * Output: 313 * queue_sizes_p Returned sizes for SQ, RQ, SQ WR SGL elements & RQ 314 * WR SGL elements. 315 * qpn_p Returned qpn of the allocated QP. 316 * ibt_qp_p The ibt_qp_hdl_t of the allocated QP. 317 * Returns: 318 * IBT_SUCCESS 319 * Description: 320 * Allocate a special QP with specified attributes. 321 */ 322 ibt_status_t 323 ibt_alloc_special_qp(ibt_hca_hdl_t hca_hdl, uint8_t port, ibt_sqp_type_t type, 324 ibt_qp_alloc_attr_t *qp_attrp, ibt_chan_sizes_t *queue_sizes_p, 325 ibt_qp_hdl_t *ibt_qp_p) 326 { 327 ibt_qp_hdl_t chanp; 328 ibt_status_t retval; 329 ibt_tran_srv_t sqp_type; 330 331 IBTF_DPRINTF_L3(ibtf_qp, "ibt_alloc_special_qp(%p, %d, %x, %p, %p, %p)", 332 hca_hdl, port, type, qp_attrp, queue_sizes_p, ibt_qp_p); 333 334 switch (type) { 335 case IBT_SMI_SQP: 336 case IBT_GSI_SQP: 337 sqp_type = IBT_UD_SRV; 338 break; 339 340 case IBT_RAWIP_SQP: 341 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: Raw IP " 342 "Transport Type is not supported."); 343 *ibt_qp_p = NULL; 344 return (IBT_NOT_SUPPORTED); 345 346 case IBT_RAWETHER_SQP: 347 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: Raw Ethernet " 348 "Transport Type is not supported."); 349 *ibt_qp_p = NULL; 350 return (IBT_NOT_SUPPORTED); 351 352 default: 353 /* Shouldn't happen */ 354 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: " 355 "Illegal Type 0x%x", type); 356 *ibt_qp_p = NULL; 357 return (IBT_QP_SPECIAL_TYPE_INVALID); 358 } 359 360 /* convert the CQ handles for the CI */ 361 qp_attrp->qp_ibc_scq_hdl = qp_attrp->qp_scq_hdl->cq_ibc_cq_hdl; 362 qp_attrp->qp_ibc_rcq_hdl = qp_attrp->qp_rcq_hdl->cq_ibc_cq_hdl; 363 364 /* Allocate Channel structure */ 365 chanp = kmem_zalloc(sizeof (*chanp), KM_SLEEP); 366 367 ibtl_qp_flow_control_enter(); 368 retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_special_qp)( 369 IBTL_HCA2CIHCA(hca_hdl), port, &chanp->ch_qp, type, qp_attrp, 370 queue_sizes_p, &chanp->ch_qp.qp_ibc_qp_hdl); 371 ibtl_qp_flow_control_exit(); 372 if (retval != IBT_SUCCESS) { 373 IBTF_DPRINTF_L2(ibtf_qp, "ibt_alloc_special_qp: " 374 "Failed to allocate Special QP: %d", retval); 375 kmem_free(chanp, sizeof (*chanp)); 376 *ibt_qp_p = NULL; 377 return (retval); 378 } 379 380 /* Initialize the internal QP struct. */ 381 chanp->ch_qp.qp_type = sqp_type; 382 chanp->ch_qp.qp_hca = hca_hdl; 383 chanp->ch_qp.qp_send_cq = qp_attrp->qp_scq_hdl; 384 chanp->ch_qp.qp_recv_cq = qp_attrp->qp_rcq_hdl; 385 chanp->ch_current_state = IBT_STATE_RESET; 386 mutex_init(&chanp->ch_cm_mutex, NULL, MUTEX_DEFAULT, NULL); 387 cv_init(&chanp->ch_cm_cv, NULL, CV_DEFAULT, NULL); 388 389 mutex_enter(&hca_hdl->ha_mutex); 390 hca_hdl->ha_qp_cnt++; 391 mutex_exit(&hca_hdl->ha_mutex); 392 393 *ibt_qp_p = chanp; 394 395 return (retval); 396 } 397 398 399 /* 400 * Function: 401 * ibt_flush_qp 402 * Input: 403 * ibtl_qp Handle for QP that needs to be flushed. 404 * Output: 405 * none. 406 * Returns: 407 * IBT_SUCCESS 408 * IBT_QP_HDL_INVALID 409 * Description: 410 * Put the QP into error state to flush out work requests. 411 */ 412 ibt_status_t 413 ibt_flush_qp(ibt_qp_hdl_t ibt_qp) 414 { 415 ibt_qp_info_t modify_attr; 416 ibt_status_t retval; 417 418 IBTF_DPRINTF_L3(ibtf_qp, "ibt_flush_qp(%p)", ibt_qp); 419 420 if (ibt_qp->ch_qp.qp_type == IBT_RC_SRV) { 421 mutex_enter(&ibtl_free_qp_mutex); 422 if (ibt_qp->ch_transport.rc.rc_free_flags & 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_L1(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 &= ~IBTL_RC_QP_CLOSED; 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_L2(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_L2(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_L2(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