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