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