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