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