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