xref: /illumos-gate/usr/src/uts/common/io/ib/ibtl/ibtl_chan.c (revision 8d0c3d29bb99f6521f2dc5058a7e4debebad7899)
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 /*
26  * ibtl_chan.c
27  *
28  * This file contains Transport API functions related to Channel Functions
29  * and internal Protection Domain and Address Handle Verbs functions.
30  */
31 
32 #include <sys/ib/ibtl/impl/ibtl.h>
33 #include <sys/ib/ibtl/impl/ibtl_cm.h>
34 #include <sys/ib/ib_pkt_hdrs.h>
35 
36 static char ibtl_chan[] = "ibtl_chan";
37 
38 /*
39  * RC Channel.
40  */
41 /*
42  * Function:
43  *	ibt_alloc_rc_channel
44  * Input:
45  *	hca_hdl		HCA Handle.
46  *	flags		Channel allocate flags.
47  *	args		A pointer to an ibt_rc_chan_alloc_args_t struct that
48  *			specifies required channel attributes.
49  * Output:
50  *	rc_chan_p	The returned RC Channel handle.
51  *	sizes		NULL or a pointer to ibt_chan_sizes_s struct where
52  *			new SendQ/RecvQ, and WR SGL sizes are returned.
53  * Returns:
54  *	IBT_SUCCESS
55  *	IBT_INVALID_PARAM
56  * Description:
57  *	Allocates a RC communication channels that satisfy the specified
58  *	channel attributes.
59  */
60 ibt_status_t
61 ibt_alloc_rc_channel(ibt_hca_hdl_t hca_hdl, ibt_chan_alloc_flags_t flags,
62     ibt_rc_chan_alloc_args_t *args, ibt_channel_hdl_t *rc_chan_p,
63     ibt_chan_sizes_t *sizes)
64 {
65 	ibt_status_t		retval;
66 	ibt_qp_alloc_attr_t	qp_attr;
67 	ibt_qp_info_t		qp_modify_attr;
68 	ibt_channel_hdl_t	chanp;
69 
70 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_rc_channel(%p, %x, %p, %p)",
71 	    hca_hdl, flags, args, sizes);
72 
73 	bzero(&qp_modify_attr, sizeof (ibt_qp_info_t));
74 
75 	qp_attr.qp_alloc_flags = IBT_QP_NO_FLAGS;
76 	if (flags & IBT_ACHAN_USER_MAP)
77 		qp_attr.qp_alloc_flags |= IBT_QP_USER_MAP;
78 
79 	if (flags & IBT_ACHAN_DEFER_ALLOC)
80 		qp_attr.qp_alloc_flags |= IBT_QP_DEFER_ALLOC;
81 
82 	if (flags & IBT_ACHAN_USES_SRQ) {
83 		if (args->rc_srq == NULL) {
84 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
85 			    "NULL SRQ Handle specified.");
86 			return (IBT_INVALID_PARAM);
87 		}
88 		qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ;
89 	}
90 
91 	/*
92 	 * Check if this request is to clone the channel, or to allocate a
93 	 * fresh one.
94 	 */
95 	if (flags & IBT_ACHAN_CLONE) {
96 
97 		ibt_rc_chan_query_attr_t	chan_attrs;
98 
99 		if (args->rc_clone_chan == NULL) {
100 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
101 			    "Clone Channel info not available.");
102 			return (IBT_INVALID_PARAM);
103 		} else if (args->rc_clone_chan->ch_qp.qp_hca != hca_hdl) {
104 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
105 			    "Clone Channel's & requested HCA Handle mismatch");
106 			return (IBT_INVALID_PARAM);
107 		}
108 
109 		IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_rc_channel: "
110 		    "Clone <%p> - RC Channel", args->rc_clone_chan);
111 
112 		/*
113 		 * Query the source channel, to obtained the attributes
114 		 * so that the new channel share the same attributes.
115 		 */
116 		retval = ibt_query_rc_channel(args->rc_clone_chan, &chan_attrs);
117 		if (retval != IBT_SUCCESS) {
118 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
119 			    "Failed to query the source channel: %d", retval);
120 			return (retval);
121 		}
122 
123 		/* Setup QP alloc attributes. */
124 		qp_attr.qp_scq_hdl = chan_attrs.rc_scq;
125 		qp_attr.qp_rcq_hdl = chan_attrs.rc_rcq;
126 		qp_attr.qp_pd_hdl = chan_attrs.rc_pd;
127 		qp_attr.qp_flags = chan_attrs.rc_flags;
128 		qp_attr.qp_srq_hdl = chan_attrs.rc_srq;
129 
130 		bcopy(&chan_attrs.rc_chan_sizes, &qp_attr.qp_sizes,
131 		    sizeof (ibt_chan_sizes_t));
132 
133 		qp_modify_attr.qp_flags = chan_attrs.rc_control;
134 		qp_modify_attr.qp_transport.rc.rc_path.cep_hca_port_num =
135 		    chan_attrs.rc_prim_path.cep_hca_port_num;
136 		qp_modify_attr.qp_transport.rc.rc_path.cep_pkey_ix =
137 		    chan_attrs.rc_prim_path.cep_pkey_ix;
138 
139 	} else {
140 
141 		/* Setup QP alloc attributes. */
142 		qp_attr.qp_scq_hdl = args->rc_scq;
143 		qp_attr.qp_rcq_hdl = args->rc_rcq;
144 		qp_attr.qp_pd_hdl = args->rc_pd;
145 		qp_attr.qp_flags = args->rc_flags;
146 		qp_attr.qp_srq_hdl = args->rc_srq;
147 
148 		bcopy(&args->rc_sizes, &qp_attr.qp_sizes,
149 		    sizeof (ibt_chan_sizes_t));
150 
151 		qp_modify_attr.qp_flags = args->rc_control;
152 
153 		if ((args->rc_hca_port_num == 0) ||
154 		    (args->rc_hca_port_num > IBTL_HCA2NPORTS(hca_hdl))) {
155 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
156 			    "Invalid port_num %d, range is (1 to %d)",
157 			    args->rc_hca_port_num, IBTL_HCA2NPORTS(hca_hdl));
158 			return (IBT_HCA_PORT_INVALID);
159 		}
160 		qp_modify_attr.qp_transport.rc.rc_path.cep_hca_port_num =
161 		    args->rc_hca_port_num;
162 
163 		/*
164 		 * We allocate the Channel initially with the default PKey,
165 		 * and later client can update this when the channel is opened
166 		 * with the pkey returned from a path record lookup.
167 		 */
168 		mutex_enter(&ibtl_clnt_list_mutex);
169 		qp_modify_attr.qp_transport.rc.rc_path.cep_pkey_ix =
170 		    hca_hdl->ha_hca_devp->
171 		    hd_portinfop[args->rc_hca_port_num - 1].p_def_pkey_ix;
172 		mutex_exit(&ibtl_clnt_list_mutex);
173 	}
174 
175 	/* Allocate Channel and Initialize the channel. */
176 	retval = ibt_alloc_qp(hca_hdl, IBT_RC_RQP, &qp_attr, sizes, NULL,
177 	    &chanp);
178 	if (retval != IBT_SUCCESS) {
179 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
180 		    "Failed to allocate QP: %d", retval);
181 		*rc_chan_p = NULL;
182 		return (retval);
183 	}
184 
185 	qp_modify_attr.qp_trans = IBT_RC_SRV;
186 
187 	/* Initialize RC Channel by transitioning it to INIT State. */
188 	retval = ibt_initialize_qp(chanp, &qp_modify_attr);
189 	if (retval != IBT_SUCCESS) {
190 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_rc_channel: "
191 		    "Failed to Initialize QP: %d", retval);
192 
193 		/* Free the QP as we failed to initialize it. */
194 		(void) ibt_free_qp(chanp);
195 
196 		*rc_chan_p = NULL;
197 		return (retval);
198 	}
199 
200 	*rc_chan_p = chanp;
201 
202 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_rc_channel(%p): - SUCCESS (%p)",
203 	    hca_hdl, chanp);
204 
205 	return (IBT_SUCCESS);
206 }
207 
208 
209 /*
210  * Function:
211  *	ibt_query_rc_channel
212  * Input:
213  *	rc_chan		A previously allocated channel handle.
214  *	chan_attrs	A pointer to an ibt_rc_chan_query_args_t struct where
215  *			Channel's current attributes are returned.
216  * Output:
217  *	chan_attrs	A pointer to an ibt_rc_chan_query_args_t struct where
218  *			Channel's current attributes are returned.
219  * Returns:
220  *	IBT_SUCCESS
221  * Description:
222  *	Query an RC channel's attributes.
223  */
224 ibt_status_t
225 ibt_query_rc_channel(ibt_channel_hdl_t rc_chan,
226     ibt_rc_chan_query_attr_t *chan_attrs)
227 {
228 	ibt_status_t		retval;
229 	ibt_qp_query_attr_t	qp_attr;
230 
231 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_query_rc_channel(%p, %p)",
232 	    rc_chan, chan_attrs);
233 
234 	if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) {
235 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_rc_channel: "
236 		    "type of channel (%d) is not RC", rc_chan->ch_qp.qp_type);
237 		return (IBT_CHAN_SRV_TYPE_INVALID);
238 	}
239 
240 	bzero(&qp_attr, sizeof (ibt_qp_query_attr_t));
241 
242 	/* Query the channel (QP) */
243 	retval = ibt_query_qp(rc_chan, &qp_attr);
244 	if (retval != IBT_SUCCESS) {
245 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_rc_channel: "
246 		    "ibt_query_qp failed on QP %p: %d", rc_chan, retval);
247 		return (retval);
248 	}
249 
250 	chan_attrs->rc_hca_guid = IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(rc_chan));
251 
252 	chan_attrs->rc_scq = qp_attr.qp_sq_cq;
253 	chan_attrs->rc_rcq = qp_attr.qp_rq_cq;
254 	chan_attrs->rc_pd = rc_chan->ch_qp.qp_pd_hdl;
255 	chan_attrs->rc_state = qp_attr.qp_info.qp_state;
256 	chan_attrs->rc_path_mtu = qp_attr.qp_info.qp_transport.rc.rc_path_mtu;
257 	chan_attrs->rc_path_retry_cnt =
258 	    qp_attr.qp_info.qp_transport.rc.rc_retry_cnt;
259 	chan_attrs->rc_path_rnr_retry_cnt =
260 	    qp_attr.qp_info.qp_transport.rc.rc_rnr_retry_cnt;
261 	chan_attrs->rc_min_rnr_nak =
262 	    qp_attr.qp_info.qp_transport.rc.rc_min_rnr_nak;
263 
264 	chan_attrs->rc_prim_path = qp_attr.qp_info.qp_transport.rc.rc_path;
265 	chan_attrs->rc_alt_path = qp_attr.qp_info.qp_transport.rc.rc_alt_path;
266 
267 	chan_attrs->rc_chan_sizes.cs_sq = qp_attr.qp_info.qp_sq_sz;
268 	chan_attrs->rc_chan_sizes.cs_rq = qp_attr.qp_info.qp_rq_sz;
269 	chan_attrs->rc_chan_sizes.cs_sq_sgl = qp_attr.qp_sq_sgl;
270 	chan_attrs->rc_chan_sizes.cs_rq_sgl = qp_attr.qp_rq_sgl;
271 	chan_attrs->rc_srq = qp_attr.qp_srq;
272 
273 	chan_attrs->rc_rdma_ra_out =
274 	    qp_attr.qp_info.qp_transport.rc.rc_rdma_ra_out;
275 	chan_attrs->rc_rdma_ra_in =
276 	    qp_attr.qp_info.qp_transport.rc.rc_rdma_ra_in;
277 
278 	chan_attrs->rc_flags = rc_chan->ch_qp.qp_flags;
279 	chan_attrs->rc_control = qp_attr.qp_info.qp_flags;
280 	chan_attrs->rc_mig_state = qp_attr.qp_info.qp_transport.rc.rc_mig_state;
281 
282 	chan_attrs->rc_qpn = qp_attr.qp_qpn & IB_QPN_MASK;
283 	chan_attrs->rc_dst_qpn =
284 	    qp_attr.qp_info.qp_transport.rc.rc_dst_qpn & IB_QPN_MASK;
285 
286 	return (retval);
287 }
288 
289 
290 /*
291  * Function:
292  *	ibt_modify_rc_channel
293  * Input:
294  *	rc_chan		A previously allocated channel handle.
295  *	flags		Specifies which attributes in ibt_rc_chan_modify_attr_t
296  *			are to be modified.
297  *	attrs		Attributes to be modified.
298  * Output:
299  *	actual_sz	On return contains the new send and receive queue sizes.
300  * Returns:
301  *	IBT_SUCCESS
302  * Description:
303  *	Modifies an RC channel's attributes, as specified by a
304  *	ibt_cep_modify_flags_t parameter to those specified in the
305  *	ibt_rc_chan_modify_attr_t structure.
306  */
307 ibt_status_t
308 ibt_modify_rc_channel(ibt_channel_hdl_t rc_chan, ibt_cep_modify_flags_t flags,
309     ibt_rc_chan_modify_attr_t *attrs, ibt_queue_sizes_t *actual_sz)
310 {
311 	ibt_status_t		retval;
312 	ibt_qp_info_t		qp_info;
313 	int			retries = 1;
314 
315 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_rc_channel(%p, %x, %p, %p)",
316 	    rc_chan, flags, attrs, actual_sz);
317 
318 	if (rc_chan->ch_qp.qp_type != IBT_RC_SRV) {
319 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_rc_channel: "
320 		    "type of channel (%d) is not RC", rc_chan->ch_qp.qp_type);
321 		return (IBT_CHAN_SRV_TYPE_INVALID);
322 	}
323 
324 retry:
325 	bzero(&qp_info, sizeof (ibt_qp_info_t));
326 
327 	if (flags & IBT_CEP_SET_ADDS_VECT) {
328 		bcopy(&attrs->rc_prim_adds_vect,
329 		    &qp_info.qp_transport.rc.rc_path.cep_adds_vect,
330 		    sizeof (ibt_adds_vect_t));
331 	}
332 
333 	qp_info.qp_trans = IBT_RC_SRV;
334 	qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
335 	    attrs->rc_prim_port_num;
336 	qp_info.qp_transport.rc.rc_retry_cnt = attrs->rc_path_retry_cnt;
337 	qp_info.qp_transport.rc.rc_rnr_retry_cnt =
338 	    attrs->rc_path_rnr_retry_cnt;
339 	qp_info.qp_transport.rc.rc_rdma_ra_out = attrs->rc_rdma_ra_out;
340 	qp_info.qp_transport.rc.rc_rdma_ra_in = attrs->rc_rdma_ra_in;
341 
342 	/* Current channel state must be either SQD or RTS. */
343 	qp_info.qp_current_state = rc_chan->ch_current_state;
344 	qp_info.qp_state = rc_chan->ch_current_state;	/* No Change in State */
345 
346 	qp_info.qp_flags = attrs->rc_control;
347 	qp_info.qp_sq_sz = attrs->rc_sq_sz;
348 	qp_info.qp_rq_sz = attrs->rc_rq_sz;
349 	qp_info.qp_transport.rc.rc_min_rnr_nak = attrs->rc_min_rnr_nak;
350 
351 	if (flags & IBT_CEP_SET_ALT_PATH) {
352 		bcopy(&attrs->rc_alt_adds_vect,
353 		    &qp_info.qp_transport.rc.rc_alt_path.cep_adds_vect,
354 		    sizeof (ibt_adds_vect_t));
355 		qp_info.qp_transport.rc.rc_alt_path.cep_hca_port_num =
356 		    attrs->rc_alt_port_num;
357 	}
358 
359 	flags |= IBT_CEP_SET_STATE;
360 
361 	retval = ibt_modify_qp(rc_chan, flags, &qp_info, actual_sz);
362 	if (retval != IBT_SUCCESS) {
363 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_rc_channel: "
364 		    "ibt_modify_qp failed on QP %p: %d", rc_chan, retval);
365 		/* give it one more shot if the old current state was stale */
366 		if (qp_info.qp_current_state != rc_chan->ch_current_state &&
367 		    --retries >= 0 &&
368 		    (qp_info.qp_current_state == IBT_STATE_RTS ||
369 		    qp_info.qp_current_state == IBT_STATE_SQD))
370 			goto retry;
371 	}
372 
373 	return (retval);
374 }
375 
376 
377 /*
378  * UD Channel.
379  */
380 /*
381  * Function:
382  *	ibt_alloc_ud_channel
383  * Input:
384  *	hca_hdl		HCA Handle.
385  *	flags		Channel allocate flags.
386  *	args		A pointer to an ibt_ud_chan_alloc_args_t struct that
387  *			specifies required channel attributes.
388  * Output:
389  *	ud_chan_p	The returned UD Channel handle.
390  *	sizes		NULL or a pointer to ibt_chan_sizes_s struct where
391  *			new SendQ/RecvQ, and WR SGL sizes are returned.
392  * Returns:
393  *	IBT_SUCCESS
394  *	IBT_INVALID_PARAM
395  * Description:
396  *	Allocate UD channels that satisfy the specified channel attributes.
397  */
398 ibt_status_t
399 ibt_alloc_ud_channel(ibt_hca_hdl_t hca_hdl, ibt_chan_alloc_flags_t flags,
400     ibt_ud_chan_alloc_args_t *args, ibt_channel_hdl_t *ud_chan_p,
401     ibt_chan_sizes_t *sizes)
402 {
403 	ibt_status_t		retval;
404 	ibt_qp_alloc_attr_t	qp_attr;
405 	ibt_qp_info_t		qp_modify_attr;
406 	ibt_channel_hdl_t	chanp;
407 
408 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel(%p, %x, %p, %p)",
409 	    hca_hdl, flags, args, sizes);
410 
411 	bzero(&qp_modify_attr, sizeof (ibt_qp_info_t));
412 
413 	qp_attr.qp_alloc_flags = IBT_QP_NO_FLAGS;
414 	if (flags & IBT_ACHAN_USER_MAP)
415 		qp_attr.qp_alloc_flags |= IBT_QP_USER_MAP;
416 
417 	if (flags & IBT_ACHAN_DEFER_ALLOC)
418 		qp_attr.qp_alloc_flags |= IBT_QP_DEFER_ALLOC;
419 
420 	if (flags & IBT_ACHAN_USES_SRQ) {
421 		if (args->ud_srq == NULL) {
422 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
423 			    "NULL SRQ Handle specified.");
424 			return (IBT_INVALID_PARAM);
425 		}
426 		qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ;
427 	}
428 
429 	/*
430 	 * Check if this request is to clone the channel, or to allocate a
431 	 * fresh one.
432 	 */
433 	if (flags & IBT_ACHAN_CLONE) {
434 
435 		ibt_ud_chan_query_attr_t	chan_attrs;
436 
437 		if (args->ud_clone_chan == NULL) {
438 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
439 			    "Clone Channel info not available.");
440 			return (IBT_INVALID_PARAM);
441 		} else if (args->ud_clone_chan->ch_qp.qp_hca != hca_hdl) {
442 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
443 			    "Clone Channel and HCA Handle mismatch");
444 			return (IBT_INVALID_PARAM);
445 		}
446 
447 		IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel: "
448 		    "Clone <%p> - UD Channel", args->ud_clone_chan);
449 
450 		retval = ibt_query_ud_channel(args->ud_clone_chan, &chan_attrs);
451 		if (retval != IBT_SUCCESS) {
452 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
453 			    "Failed to Query the source channel: %d", retval);
454 			return (retval);
455 		}
456 
457 		/* Setup QP alloc attributes. */
458 		qp_attr.qp_scq_hdl = chan_attrs.ud_scq;
459 		qp_attr.qp_rcq_hdl = chan_attrs.ud_rcq;
460 		qp_attr.qp_pd_hdl = chan_attrs.ud_pd;
461 		qp_attr.qp_flags = chan_attrs.ud_flags;
462 		qp_attr.qp_srq_hdl = chan_attrs.ud_srq;
463 
464 		bcopy(&chan_attrs.ud_chan_sizes, &qp_attr.qp_sizes,
465 		    sizeof (ibt_chan_sizes_t));
466 
467 		qp_modify_attr.qp_transport.ud.ud_port =
468 		    chan_attrs.ud_hca_port_num;
469 		qp_modify_attr.qp_transport.ud.ud_qkey = chan_attrs.ud_qkey;
470 		qp_modify_attr.qp_transport.ud.ud_pkey_ix =
471 		    chan_attrs.ud_pkey_ix;
472 	} else {
473 		ib_pkey_t	tmp_pkey;
474 
475 		/* Setup QP alloc attributes. */
476 		qp_attr.qp_scq_hdl = args->ud_scq;
477 		qp_attr.qp_rcq_hdl = args->ud_rcq;
478 		qp_attr.qp_pd_hdl = args->ud_pd;
479 		qp_attr.qp_flags = args->ud_flags;
480 		qp_attr.qp_srq_hdl = args->ud_srq;
481 
482 		bcopy(&args->ud_sizes, &qp_attr.qp_sizes,
483 		    sizeof (ibt_chan_sizes_t));
484 
485 		qp_modify_attr.qp_transport.ud.ud_port = args->ud_hca_port_num;
486 		qp_modify_attr.qp_transport.ud.ud_qkey = args->ud_qkey;
487 
488 		/* Validate input hca_port_num and pkey_ix values. */
489 		if ((retval = ibt_index2pkey(hca_hdl, args->ud_hca_port_num,
490 		    args->ud_pkey_ix, &tmp_pkey)) != IBT_SUCCESS) {
491 			IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
492 			    "ibt_index2pkey failed, status: %d", retval);
493 			*ud_chan_p = NULL;
494 			return (retval);
495 		}
496 		qp_modify_attr.qp_transport.ud.ud_pkey_ix = args->ud_pkey_ix;
497 	}
498 
499 	/* Allocate Channel and Initialize the channel. */
500 	retval = ibt_alloc_qp(hca_hdl, IBT_UD_RQP, &qp_attr, sizes, NULL,
501 	    &chanp);
502 	if (retval != IBT_SUCCESS) {
503 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
504 		    "Failed to allocate QP: %d", retval);
505 		*ud_chan_p = NULL;
506 		return (retval);
507 	}
508 
509 	/* Initialize UD Channel by transitioning it to RTS State. */
510 	qp_modify_attr.qp_trans = IBT_UD_SRV;
511 	qp_modify_attr.qp_flags = IBT_CEP_NO_FLAGS;
512 	qp_modify_attr.qp_transport.ud.ud_sq_psn = 0;
513 
514 	retval = ibt_initialize_qp(chanp, &qp_modify_attr);
515 	if (retval != IBT_SUCCESS) {
516 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_channel: "
517 		    "Failed to Initialize QP: %d", retval);
518 
519 		/* Free the QP as we failed to initialize it. */
520 		(void) ibt_free_qp(chanp);
521 
522 		*ud_chan_p = NULL;
523 		return (retval);
524 	}
525 
526 	*ud_chan_p = chanp;
527 
528 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_channel(%p): - SUCCESS (%p)",
529 	    hca_hdl, chanp);
530 
531 	return (IBT_SUCCESS);
532 }
533 
534 
535 /*
536  * Function:
537  *	ibt_query_ud_channel
538  * Input:
539  *	ud_chan		A previously allocated UD channel handle.
540  * Output:
541  *	chan_attrs	Channel's current attributes.
542  * Returns:
543  *	IBT_SUCCESS
544  * Description:
545  *	Query a UD channel's attributes.
546  */
547 ibt_status_t
548 ibt_query_ud_channel(ibt_channel_hdl_t ud_chan,
549     ibt_ud_chan_query_attr_t *ud_chan_attrs)
550 {
551 	ibt_status_t		retval;
552 	ibt_qp_query_attr_t	qp_attr;
553 
554 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_query_ud_channel(%p, %p)",
555 	    ud_chan, ud_chan_attrs);
556 
557 	if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) {
558 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_ud_channel: "
559 		    "type of channel (%d) is not UD", ud_chan->ch_qp.qp_type);
560 		return (IBT_CHAN_SRV_TYPE_INVALID);
561 	}
562 
563 	bzero(&qp_attr, sizeof (ibt_qp_query_attr_t));
564 
565 	/* Query the channel (QP) */
566 	retval = ibt_query_qp(ud_chan, &qp_attr);
567 	if (retval != IBT_SUCCESS) {
568 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_ud_channel: "
569 		    "ibt_query_qp failed on QP %p: %d", ud_chan, retval);
570 		return (retval);
571 	}
572 
573 	ud_chan_attrs->ud_qpn = qp_attr.qp_qpn & IB_QPN_MASK;
574 	ud_chan_attrs->ud_hca_guid = IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(ud_chan));
575 
576 	ud_chan_attrs->ud_scq = qp_attr.qp_sq_cq;
577 	ud_chan_attrs->ud_rcq = qp_attr.qp_rq_cq;
578 	ud_chan_attrs->ud_pd = ud_chan->ch_qp.qp_pd_hdl;
579 
580 	ud_chan_attrs->ud_hca_port_num =
581 	    qp_attr.qp_info.qp_transport.ud.ud_port;
582 
583 	ud_chan_attrs->ud_state = qp_attr.qp_info.qp_state;
584 	ud_chan_attrs->ud_pkey_ix = qp_attr.qp_info.qp_transport.ud.ud_pkey_ix;
585 	ud_chan_attrs->ud_qkey = qp_attr.qp_info.qp_transport.ud.ud_qkey;
586 
587 	ud_chan_attrs->ud_chan_sizes.cs_sq = qp_attr.qp_info.qp_sq_sz;
588 	ud_chan_attrs->ud_chan_sizes.cs_rq = qp_attr.qp_info.qp_rq_sz;
589 	ud_chan_attrs->ud_chan_sizes.cs_sq_sgl = qp_attr.qp_sq_sgl;
590 	ud_chan_attrs->ud_chan_sizes.cs_rq_sgl = qp_attr.qp_rq_sgl;
591 	ud_chan_attrs->ud_srq = qp_attr.qp_srq;
592 
593 	ud_chan_attrs->ud_flags = ud_chan->ch_qp.qp_flags;
594 
595 	return (retval);
596 }
597 
598 
599 /*
600  * Function:
601  *	ibt_modify_ud_channel
602  * Input:
603  *	ud_chan		A previously allocated UD channel handle.
604  *	flags		Specifies which attributes in ibt_ud_chan_modify_attr_t
605  *			are to be modified.
606  *	attrs		Attributes to be modified.
607  * Output:
608  *	actual_sz	On return contains the new send and receive queue sizes.
609  * Returns:
610  *	IBT_SUCCESS
611  * Description:
612  *	Modifies an UD channel's attributes, as specified by a
613  *	ibt_cep_modify_flags_t parameter to those specified in the
614  *	ibt_ud_chan_modify_attr_t structure.
615  */
616 ibt_status_t
617 ibt_modify_ud_channel(ibt_channel_hdl_t ud_chan, ibt_cep_modify_flags_t flags,
618     ibt_ud_chan_modify_attr_t *attrs, ibt_queue_sizes_t *actual_sz)
619 {
620 	ibt_status_t		retval;
621 	ibt_qp_info_t		qp_info;
622 	ibt_cep_modify_flags_t	good_flags;
623 	int			retries = 1;
624 
625 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_ud_channel(%p, %x, %p, %p)",
626 	    ud_chan, flags, attrs, actual_sz);
627 
628 	if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) {
629 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_channel: "
630 		    "type of channel (%d) is not UD", ud_chan->ch_qp.qp_type);
631 		return (IBT_CHAN_SRV_TYPE_INVALID);
632 	}
633 
634 	good_flags = IBT_CEP_SET_SQ_SIZE | IBT_CEP_SET_RQ_SIZE |
635 	    IBT_CEP_SET_QKEY;
636 
637 	if (flags & ~good_flags) {
638 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_channel: "
639 		    "Invalid Modify Flags: %x", flags);
640 		return (IBT_INVALID_PARAM);
641 	}
642 
643 retry:
644 	bzero(&qp_info, sizeof (ibt_qp_info_t));
645 
646 	qp_info.qp_state = ud_chan->ch_current_state;	/* No Change in State */
647 	qp_info.qp_current_state = ud_chan->ch_current_state;
648 	qp_info.qp_flags = IBT_CEP_NO_FLAGS;
649 
650 	qp_info.qp_sq_sz = attrs->ud_sq_sz;
651 	qp_info.qp_rq_sz = attrs->ud_rq_sz;
652 	qp_info.qp_trans = IBT_UD_SRV;
653 	qp_info.qp_transport.ud.ud_qkey = attrs->ud_qkey;
654 
655 	flags |= IBT_CEP_SET_STATE;
656 
657 	retval = ibt_modify_qp(ud_chan, flags, &qp_info, actual_sz);
658 	if (retval != IBT_SUCCESS) {
659 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_channel: "
660 		    "ibt_modify_qp failed on QP %p: %d", ud_chan, retval);
661 		/* give it one more shot if the old current state was stale */
662 		if (qp_info.qp_current_state != ud_chan->ch_current_state &&
663 		    --retries >= 0 &&
664 		    (qp_info.qp_current_state == IBT_STATE_RTS ||
665 		    qp_info.qp_current_state == IBT_STATE_SQD))
666 			goto retry;
667 	}
668 
669 	return (retval);
670 }
671 
672 
673 /*
674  * Function:
675  *	ibt_recover_ud_channel
676  * Input:
677  *	ud_chan		An UD channel handle which is in SQError state.
678  * Output:
679  *	none.
680  * Returns:
681  *	IBT_SUCCESS
682  *	IBT_CHAN_HDL_INVALID
683  *	IBT_CHAN_SRV_TYPE_INVALID
684  *	IBT_CHAN_STATE_INVALID
685  * Description:
686  *	Recover an UD Channel which has transitioned to SQ Error state. The
687  *	ibt_recover_ud_channel() transitions the channel from SQ Error state
688  *	to Ready-To-Send channel state.
689  *
690  *	If a work request posted to a UD channel's send queue completes with
691  *	an error (see ibt_wc_status_t), the channel gets transitioned to SQ
692  *	Error state. In order to reuse this channel, ibt_recover_ud_channel()
693  *	can be used to recover the channel to a usable (Ready-to-Send) state.
694  */
695 ibt_status_t
696 ibt_recover_ud_channel(ibt_channel_hdl_t ud_chan)
697 {
698 	ibt_qp_info_t		modify_attr;
699 	ibt_status_t		retval;
700 
701 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_recover_ud_channel(%p)", ud_chan);
702 
703 	if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) {
704 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_recover_ud_channel: "
705 		    "Called for non-UD channels<%d>", ud_chan->ch_qp.qp_type);
706 		return (IBT_CHAN_SRV_TYPE_INVALID);
707 	}
708 
709 	bzero(&modify_attr, sizeof (ibt_qp_info_t));
710 
711 	/* Set the channel state to RTS, to activate the send processing. */
712 	modify_attr.qp_state = IBT_STATE_RTS;
713 	modify_attr.qp_trans = ud_chan->ch_qp.qp_type;
714 	modify_attr.qp_current_state = IBT_STATE_SQE;
715 
716 	retval = ibt_modify_qp(ud_chan, IBT_CEP_SET_STATE, &modify_attr, NULL);
717 
718 	if (retval != IBT_SUCCESS)
719 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_recover_ud_channel: "
720 		    "ibt_modify_qp failed on qp %p: status = %d",
721 		    ud_chan, retval);
722 
723 	return (retval);
724 }
725 
726 
727 /*
728  * Function:
729  *	ibt_flush_channel
730  * Input:
731  *	chan		The opaque channel handle returned in a previous call
732  *			to ibt_alloc_ud_channel() or ibt_alloc_rc_channel().
733  * Output:
734  *	none.
735  * Returns:
736  *	IBT_SUCCESS
737  * Description:
738  *	Flush the specified channel. Outstanding work requests are flushed
739  *	so that the client can do the associated clean up. After that, the
740  *	client will usually deregister the previously registered memory,
741  *	then free the channel by calling ibt_free_channel().  This function
742  *	applies to UD channels, or to RC channels that have not successfully
743  *	been opened.
744  */
745 ibt_status_t
746 ibt_flush_channel(ibt_channel_hdl_t chan)
747 {
748 	ibt_status_t retval;
749 
750 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_flush_channel(%p)", chan);
751 
752 	retval = ibt_flush_qp(chan);
753 	if (retval != IBT_SUCCESS) {
754 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_flush_channel: "
755 		    "ibt_flush_qp failed on QP %p: %d", chan, retval);
756 	}
757 
758 	return (retval);
759 }
760 
761 
762 /*
763  * Function:
764  *	ibt_free_channel
765  * Input:
766  *	chan		The opaque channel handle returned in a previous
767  *			call to ibt_alloc_{ud,rc}_channel().
768  * Output:
769  *	none.
770  * Returns:
771  *	IBT_SUCCESS
772  * Description:
773  *	Releases the resources associated with the specified channel.
774  *	It is well assumed that channel has been closed before this.
775  */
776 ibt_status_t
777 ibt_free_channel(ibt_channel_hdl_t chan)
778 {
779 	return (ibt_free_qp(chan));
780 }
781 
782 
783 /*
784  * UD Destination.
785  */
786 /*
787  * Function:
788  *	ibt_alloc_ud_dest
789  * Input:
790  *	hca_hdl		HCA Handle.
791  *	pd		Protection Domain
792  * Output:
793  *	ud_dest_p	Address to store the returned UD destination handle.
794  * Returns:
795  *	IBT_SUCCESS
796  * Description:
797  *	Allocate a UD destination handle. The returned UD destination handle
798  *	has no useful contents, but is usable after calling ibt_modify_ud_dest,
799  *	ibt_modify_reply_ud_dest, or ibt_open_ud_dest.
800  */
801 ibt_status_t
802 ibt_alloc_ud_dest(ibt_hca_hdl_t hca_hdl, ibt_ud_dest_flags_t flags,
803     ibt_pd_hdl_t pd, ibt_ud_dest_hdl_t *ud_dest_p)
804 {
805 	ibt_status_t	retval;
806 	ibt_ud_dest_t	*ud_destp;
807 	ibt_ah_hdl_t	ah;
808 	ibt_adds_vect_t adds_vect;
809 
810 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ud_dest(%p, %x, %p)",
811 	    hca_hdl, flags, pd);
812 
813 	bzero(&adds_vect, sizeof (adds_vect));
814 	adds_vect.av_port_num = 1;
815 	adds_vect.av_srate = IBT_SRATE_1X;	/* assume the minimum */
816 	retval = ibt_alloc_ah(hca_hdl, flags, pd, &adds_vect, &ah);
817 	if (retval != IBT_SUCCESS) {
818 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ud_dest: "
819 		    "Address Handle Allocation failed: %d", retval);
820 		*ud_dest_p = NULL;
821 		return (retval);
822 	}
823 	ud_destp = kmem_alloc(sizeof (*ud_destp), KM_SLEEP);
824 	ud_destp->ud_ah = ah;
825 	ud_destp->ud_dest_hca = hca_hdl;
826 	ud_destp->ud_dst_qpn = 0;
827 	ud_destp->ud_qkey = 0;
828 	*ud_dest_p = ud_destp;
829 	return (IBT_SUCCESS);
830 }
831 
832 /*
833  * Function:
834  *	ibt_query_ud_dest
835  * Input:
836  *	ud_dest		A previously allocated UD destination handle.
837  * Output:
838  *	dest_attrs	UD destination's current attributes.
839  * Returns:
840  *	IBT_SUCCESS
841  * Description:
842  *	Query a UD destination's attributes.
843  */
844 ibt_status_t
845 ibt_query_ud_dest(ibt_ud_dest_hdl_t ud_dest,
846     ibt_ud_dest_query_attr_t *dest_attrs)
847 {
848 	ibt_status_t	retval;
849 
850 	ASSERT(dest_attrs != NULL);
851 
852 	/* Query Address Handle */
853 	retval = ibt_query_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah,
854 	    &dest_attrs->ud_pd, &dest_attrs->ud_addr_vect);
855 
856 	if (retval != IBT_SUCCESS) {
857 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_query_ud_dest: "
858 		    "Failed to Query Address Handle: %d", retval);
859 		return (retval);
860 	}
861 
862 	/* Update the return struct. */
863 	dest_attrs->ud_hca_hdl = ud_dest->ud_dest_hca;
864 	dest_attrs->ud_dst_qpn = ud_dest->ud_dst_qpn;
865 	dest_attrs->ud_qkey = ud_dest->ud_qkey;
866 
867 	return (retval);
868 }
869 
870 /*
871  * Function:
872  *	ibt_modify_ud_dest
873  * Input:
874  *	ud_dest		A previously allocated UD destination handle
875  *			as returned by ibt_alloc_ud_dest().
876  *	qkey		QKey of the destination.
877  *	dest_qpn	QPN of the destination.
878  *	adds_vect	NULL or Address Vector for the destination.
879  *
880  * Output:
881  *	none.
882  * Returns:
883  *	IBT_SUCCESS
884  * Description:
885  *	Modify a previously allocated UD destination handle from the
886  *	arguments supplied by the caller.
887  */
888 ibt_status_t
889 ibt_modify_ud_dest(ibt_ud_dest_hdl_t ud_dest, ib_qkey_t qkey,
890     ib_qpn_t dest_qpn, ibt_adds_vect_t *adds_vect)
891 {
892 	ibt_status_t	retval;
893 
894 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_ud_dest(%p, %x, %x, %p) ",
895 	    ud_dest, qkey, dest_qpn, adds_vect);
896 
897 	if ((adds_vect != NULL) &&
898 	    (retval = ibt_modify_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah,
899 	    adds_vect)) != IBT_SUCCESS) {
900 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_ud_dest: "
901 		    "ibt_modify_ah() failed: status = %d", retval);
902 		return (retval);
903 	}
904 	ud_dest->ud_dst_qpn = dest_qpn;
905 	ud_dest->ud_qkey = qkey;
906 	return (IBT_SUCCESS);
907 }
908 
909 /*
910  * Function:
911  *	ibt_free_ud_dest
912  * Input:
913  *	ud_dest		The opaque destination handle returned in a previous
914  *			call to ibt_alloc_ud_dest() or ibt_alloc_mcg_dest().
915  * Output:
916  *	none.
917  * Returns:
918  *	IBT_SUCCESS
919  * Description:
920  *	Releases the resources associated with the specified destination
921  *	handle.
922  */
923 ibt_status_t
924 ibt_free_ud_dest(ibt_ud_dest_hdl_t ud_dest)
925 {
926 	ibt_status_t	retval;
927 
928 	retval = ibt_free_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah);
929 	if (retval != IBT_SUCCESS) {
930 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_free_ud_dest: "
931 		    "Address Handle free failed: %d", retval);
932 		return (retval);
933 	}
934 	kmem_free(ud_dest, sizeof (*ud_dest));
935 	return (IBT_SUCCESS);
936 }
937 
938 static ibt_status_t
939 ibtl_find_sgid_ix(ib_gid_t *sgid, ibt_channel_hdl_t ud_chan, uint8_t port,
940     uint_t *sgid_ix_p)
941 {
942 	ibtl_hca_devinfo_t *hca_devp = ud_chan->ch_qp.qp_hca->ha_hca_devp;
943 	ib_gid_t *sgidp;
944 	uint_t i;
945 	uint_t sgid_tbl_sz;
946 
947 	if (port == 0 || port > hca_devp->hd_hca_attr->hca_nports ||
948 	    sgid->gid_prefix == 0 || sgid->gid_guid == 0) {
949 		*sgid_ix_p = 0;
950 		return (IBT_INVALID_PARAM);
951 	}
952 	mutex_enter(&ibtl_clnt_list_mutex);
953 	sgidp = &hca_devp->hd_portinfop[port - 1].p_sgid_tbl[0];
954 	sgid_tbl_sz = hca_devp->hd_portinfop[port - 1].p_sgid_tbl_sz;
955 	for (i = 0; i < sgid_tbl_sz; i++, sgidp++) {
956 		if ((sgid->gid_guid != sgidp->gid_guid) ||
957 		    (sgid->gid_prefix != sgidp->gid_prefix))
958 			continue;
959 		mutex_exit(&ibtl_clnt_list_mutex);
960 		*sgid_ix_p = i;
961 		return (IBT_SUCCESS);
962 	}
963 	mutex_exit(&ibtl_clnt_list_mutex);
964 	*sgid_ix_p = 0;
965 	return (IBT_INVALID_PARAM);
966 }
967 
968 /*
969  * Function:
970  *	ibt_modify_reply_ud_dest
971  * Input:
972  *	ud_dest		A previously allocated UD reply destination handle
973  *			as returned by ibt_alloc_ud_dest().
974  *	qkey		Qkey.  0 means "not specified", so use the Q_Key
975  *			in the QP context.
976  *	recv_buf	Pointer to the first data buffer associated with the
977  *			receive work request.
978  * Output:
979  * Returns:
980  *	IBT_SUCCESS
981  * Description:
982  *	Modify a previously allocated UD destination handle, so that it
983  *	can be used to reply to the sender of the datagram contained in the
984  *	specified work request completion.  If the qkey is not supplied (0),
985  *	then use the qkey in the QP (we just set qkey to a privileged QKEY).
986  */
987 ibt_status_t
988 ibt_modify_reply_ud_dest(ibt_channel_hdl_t ud_chan, ibt_ud_dest_hdl_t ud_dest,
989     ib_qkey_t qkey, ibt_wc_t *wc, ib_vaddr_t recv_buf)
990 {
991 	ibt_status_t		retval;
992 	ibt_adds_vect_t		adds_vect;
993 	ib_grh_t		*grh;
994 	uint8_t			port;
995 	uint32_t		ver_tc_flow;
996 
997 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_reply_ud_dest(%p, %p, %x, %p, "
998 	    "%llx)", ud_chan, ud_dest, qkey, wc, recv_buf);
999 
1000 	if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) {
1001 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_reply_ud_dest: "
1002 		    "type of channel (%d) is not UD",
1003 		    ud_chan->ch_qp.qp_type);
1004 		return (IBT_CHAN_SRV_TYPE_INVALID);
1005 	}
1006 	if (qkey == 0)
1007 		qkey = ud_chan->ch_transport.ud.ud_qkey;
1008 	port = ud_chan->ch_transport.ud.ud_port_num;
1009 
1010 	if (wc->wc_flags & IBT_WC_GRH_PRESENT) {
1011 		grh = (ib_grh_t *)(uintptr_t)recv_buf;
1012 		adds_vect.av_send_grh = B_TRUE;
1013 		adds_vect.av_dgid.gid_prefix = b2h64(grh->SGID.gid_prefix);
1014 		adds_vect.av_dgid.gid_guid = b2h64(grh->SGID.gid_guid);
1015 		adds_vect.av_sgid.gid_prefix = b2h64(grh->DGID.gid_prefix);
1016 		adds_vect.av_sgid.gid_guid = b2h64(grh->DGID.gid_guid);
1017 		(void) ibtl_find_sgid_ix(&adds_vect.av_sgid, ud_chan,
1018 		    port, &adds_vect.av_sgid_ix);
1019 		ver_tc_flow = b2h32(grh->IPVer_TC_Flow);
1020 		adds_vect.av_flow = ver_tc_flow & IB_GRH_FLOW_LABEL_MASK;
1021 		adds_vect.av_tclass = (ver_tc_flow & IB_GRH_TCLASS_MASK) >> 20;
1022 		adds_vect.av_hop = grh->HopLmt;
1023 	} else {
1024 		adds_vect.av_send_grh = B_FALSE;
1025 		adds_vect.av_dgid.gid_prefix = 0;
1026 		adds_vect.av_sgid.gid_prefix = 0;
1027 		adds_vect.av_dgid.gid_guid = 0;
1028 		adds_vect.av_sgid.gid_guid = 0;
1029 		adds_vect.av_sgid_ix = 0;
1030 		adds_vect.av_flow = 0;
1031 		adds_vect.av_tclass = 0;
1032 		adds_vect.av_hop = 0;
1033 	}
1034 
1035 	adds_vect.av_srate = IBT_SRATE_1X;	/* assume the minimum */
1036 	adds_vect.av_srvl = wc->wc_sl;
1037 	adds_vect.av_dlid = wc->wc_slid;
1038 	adds_vect.av_src_path = wc->wc_path_bits;
1039 	adds_vect.av_port_num = port;
1040 
1041 	if ((retval = ibt_modify_ah(ud_dest->ud_dest_hca, ud_dest->ud_ah,
1042 	    &adds_vect)) != IBT_SUCCESS) {
1043 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_modify_reply_ud_dest: "
1044 		    "ibt_alloc_ah() failed: status = %d", retval);
1045 		return (retval);
1046 	}
1047 	ud_dest->ud_dst_qpn = wc->wc_qpn & IB_QPN_MASK;
1048 	ud_dest->ud_qkey = qkey;
1049 
1050 	return (IBT_SUCCESS);
1051 }
1052 
1053 
1054 /*
1055  * Function:
1056  *	ibt_is_privileged_ud_dest
1057  * Input:
1058  *	ud_dest		A previously allocated destination handle.
1059  * Output:
1060  *	none
1061  * Returns:
1062  *	B_FALSE/B_TRUE
1063  * Description:
1064  *	Determine if a UD destination Handle is a privileged handle.
1065  */
1066 boolean_t
1067 ibt_is_privileged_ud_dest(ibt_ud_dest_hdl_t ud_dest)
1068 {
1069 	return ((ud_dest->ud_qkey & IB_PRIVILEGED_QKEY_BIT) ? B_TRUE : B_FALSE);
1070 }
1071 
1072 
1073 /*
1074  * Function:
1075  *	ibt_update_channel_qkey
1076  * Input:
1077  *	ud_chan		The UD channel handle, that is to be used to
1078  *			communicate with the specified destination.
1079  *
1080  *	ud_dest		A UD destination handle returned from
1081  *			ibt_alloc_ud_dest(9F).
1082  * Output:
1083  *	none
1084  * Returns:
1085  *	IBT_SUCCESS
1086  * Description:
1087  *   ibt_update_channel_qkey() sets the Q_Key in the specified channel context
1088  *   to the Q_Key in the specified destination handle. This function can be used
1089  *   to enable sends to a privileged destination. All posted send work requests
1090  *   that contain a privileged destination handle now use the Q_Key in the
1091  *   channel context.
1092  *
1093  *   ibt_update_channel_qkey() can also be used to enable the caller to receive
1094  *   from the specified remote destination on the specified channel.
1095  */
1096 ibt_status_t
1097 ibt_update_channel_qkey(ibt_channel_hdl_t ud_chan, ibt_ud_dest_hdl_t ud_dest)
1098 {
1099 	ibt_status_t		retval;
1100 	ibt_qp_info_t		qp_info;
1101 
1102 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_update_channel_qkey(%p, %p)",
1103 	    ud_chan, ud_dest);
1104 
1105 	if (ud_chan->ch_qp.qp_type != IBT_UD_SRV) {
1106 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_update_channel_qkey: "
1107 		    "type of channel (%d) is not UD",
1108 		    ud_chan->ch_qp.qp_type);
1109 		return (IBT_CHAN_SRV_TYPE_INVALID);
1110 	}
1111 	bzero(&qp_info, sizeof (ibt_qp_info_t));
1112 
1113 	qp_info.qp_trans = IBT_UD_SRV;
1114 	qp_info.qp_state = ud_chan->ch_current_state;
1115 	qp_info.qp_current_state = ud_chan->ch_current_state;
1116 	qp_info.qp_transport.ud.ud_qkey = ud_dest->ud_qkey;
1117 
1118 	retval = ibt_modify_qp(ud_chan, IBT_CEP_SET_QKEY | IBT_CEP_SET_STATE,
1119 	    &qp_info, NULL);
1120 	if (retval != IBT_SUCCESS) {
1121 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_update_channel_qkey: "
1122 		    "Failed to modify QP %p: status %d", ud_chan, retval);
1123 	} else {
1124 		ud_chan->ch_transport.ud.ud_qkey = ud_dest->ud_qkey;
1125 	}
1126 
1127 	return (retval);
1128 }
1129 
1130 
1131 /*
1132  * Function:
1133  *	ibt_set_chan_private
1134  * Input:
1135  *	chan		A previously allocated channel handle.
1136  *	clnt_private	The client private data.
1137  * Output:
1138  *	none.
1139  * Returns:
1140  *	none.
1141  * Description:
1142  *	Set the client private data.
1143  */
1144 void
1145 ibt_set_chan_private(ibt_channel_hdl_t chan, void *clnt_private)
1146 {
1147 	chan->ch_clnt_private = clnt_private;
1148 }
1149 
1150 
1151 /*
1152  * Function:
1153  *	ibt_get_chan_private
1154  * Input:
1155  *	chan		A previously allocated channel handle.
1156  * Output:
1157  *	A pointer to the client private data.
1158  * Returns:
1159  *	none.
1160  * Description:
1161  *	Get a pointer to client private data.
1162  */
1163 void *
1164 ibt_get_chan_private(ibt_channel_hdl_t chan)
1165 {
1166 	return (chan->ch_clnt_private);
1167 }
1168 
1169 /*
1170  * Function:
1171  *	ibt_channel_to_hca_guid
1172  * Input:
1173  *	chan		Channel Handle.
1174  * Output:
1175  *	none.
1176  * Returns:
1177  *	hca_guid	Returned HCA GUID on which the specified Channel is
1178  *			allocated. Valid if it is non-NULL on return.
1179  * Description:
1180  *	A helper function to retrieve HCA GUID for the specified Channel.
1181  */
1182 ib_guid_t
1183 ibt_channel_to_hca_guid(ibt_channel_hdl_t chan)
1184 {
1185 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_channel_to_hca_guid(%p)", chan);
1186 
1187 	return (IBTL_HCA2HCAGUID(IBTL_CHAN2HCA(chan)));
1188 }
1189 
1190 /*
1191  * Protection Domain Verbs Functions.
1192  */
1193 
1194 /*
1195  * Function:
1196  *	ibt_alloc_pd
1197  * Input:
1198  *	hca_hdl		The IBT HCA handle, the device on which we need
1199  *			to create the requested Protection Domain.
1200  *	flags		IBT_PD_NO_FLAGS, IBT_PD_USER_MAP or IBT_PD_DEFER_ALLOC
1201  * Output:
1202  *	pd		IBT Protection Domain Handle.
1203  * Returns:
1204  *	IBT_SUCCESS
1205  *	IBT_HCA_HDL_INVALID
1206  * Description:
1207  *	Allocate a Protection Domain.
1208  */
1209 ibt_status_t
1210 ibt_alloc_pd(ibt_hca_hdl_t hca_hdl, ibt_pd_flags_t flags, ibt_pd_hdl_t *pd)
1211 {
1212 	ibt_status_t	retval;
1213 
1214 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_pd(%p, %x)", hca_hdl, flags);
1215 
1216 	/* re-direct the call to CI's call */
1217 	ibtl_qp_flow_control_enter();
1218 	retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_pd(
1219 	    IBTL_HCA2CIHCA(hca_hdl), flags, pd);
1220 	ibtl_qp_flow_control_exit();
1221 	if (retval != IBT_SUCCESS) {
1222 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_pd: CI PD Alloc Err");
1223 		return (retval);
1224 	}
1225 
1226 	/* Update the PDs Resource Count per HCA Device. */
1227 	atomic_inc_32(&hca_hdl->ha_pd_cnt);
1228 
1229 	return (retval);
1230 }
1231 
1232 /*
1233  * Function:
1234  *	ibt_free_pd
1235  * Input:
1236  *	hca_hdl		The IBT HCA handle, the device on which we need
1237  *			to free the requested Protection Domain.
1238  *	pd		IBT Protection Domain Handle.
1239  * Output:
1240  *	none.
1241  * Returns:
1242  *	IBT_SUCCESS
1243  *	IBT_HCA_HDL_INVALID
1244  *	IBT_MEM_PD_HDL_INVALID
1245  *	IBT_MEM_PD_IN_USE
1246  * Description:
1247  *	Release/de-allocate a Protection Domain.
1248  */
1249 ibt_status_t
1250 ibt_free_pd(ibt_hca_hdl_t hca_hdl, ibt_pd_hdl_t pd)
1251 {
1252 	ibt_status_t	retval;
1253 
1254 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_free_pd(%p, %p)", hca_hdl, pd);
1255 
1256 	/* re-direct the call to CI's call */
1257 	retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_free_pd(
1258 	    IBTL_HCA2CIHCA(hca_hdl), pd);
1259 	if (retval != IBT_SUCCESS) {
1260 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_free_pd: CI Free PD Failed");
1261 		return (retval);
1262 	}
1263 
1264 	/* Update the PDs Resource Count per HCA Device. */
1265 	atomic_dec_32(&hca_hdl->ha_pd_cnt);
1266 
1267 	return (retval);
1268 }
1269 
1270 
1271 /*
1272  * Address Handle Verbs Functions.
1273  */
1274 
1275 /*
1276  * Function:
1277  *	ibt_alloc_ah
1278  * Input:
1279  *	hca_hdl		The IBT HCA Handle.
1280  *	pd		The IBT Protection Domain to associate with this handle.
1281  *	adds_vectp	Points to an ibt_adds_vect_t struct.
1282  * Output:
1283  *	ah		IBT Address Handle.
1284  * Returns:
1285  *	IBT_SUCCESS
1286  *	IBT_HCA_HDL_INVALID
1287  *	IBT_INSUFF_RESOURCE
1288  *	IBT_MEM_PD_HDL_INVALID
1289  * Description:
1290  *	Allocate and returns an Address Handle.
1291  */
1292 ibt_status_t
1293 ibt_alloc_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_flags_t flags, ibt_pd_hdl_t pd,
1294     ibt_adds_vect_t *adds_vectp, ibt_ah_hdl_t *ah)
1295 {
1296 	ibt_status_t	retval;
1297 
1298 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_alloc_ah(%p, %x, %p, %p)",
1299 	    hca_hdl, flags, pd, adds_vectp);
1300 
1301 	/* XXX - if av_send_grh, need to compute av_sgid_ix from av_sgid */
1302 
1303 	/* re-direct the call to CI's call */
1304 	retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_ah(
1305 	    IBTL_HCA2CIHCA(hca_hdl), flags, pd, adds_vectp, ah);
1306 
1307 	if (retval != IBT_SUCCESS) {
1308 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_alloc_ah: "
1309 		    "ibc_alloc_ah failed: status = %d", retval);
1310 		return (retval);
1311 	}
1312 
1313 	/* Update the AHs Resource Count per HCA Device. */
1314 	atomic_inc_32(&hca_hdl->ha_ah_cnt);
1315 
1316 	return (retval);
1317 }
1318 
1319 
1320 /*
1321  * Function:
1322  *	ibt_free_ah
1323  * Input:
1324  *	hca_hdl		The IBT HCA Handle.
1325  *	ah		IBT Address Handle.
1326  * Output:
1327  *	none.
1328  * Returns:
1329  *	IBT_SUCCESS
1330  *	IBT_HCA_HDL_INVALID
1331  *	IBT_AH_HDL_INVALID
1332  * Description:
1333  *	Release/de-allocate the specified Address Handle.
1334  */
1335 ibt_status_t
1336 ibt_free_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_hdl_t ah)
1337 {
1338 	ibt_status_t	retval;
1339 
1340 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_free_ah(%p, %p)", hca_hdl, ah);
1341 
1342 	/* re-direct the call to CI's call */
1343 	retval = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_free_ah(
1344 	    IBTL_HCA2CIHCA(hca_hdl), ah);
1345 
1346 	if (retval != IBT_SUCCESS) {
1347 		IBTF_DPRINTF_L2(ibtl_chan, "ibt_free_ah: CI Free AH Failed");
1348 		return (retval);
1349 	}
1350 
1351 	/* Update the AHs Resource Count per HCA Device. */
1352 	atomic_dec_32(&hca_hdl->ha_ah_cnt);
1353 
1354 	return (retval);
1355 }
1356 
1357 
1358 /*
1359  * Function:
1360  *	ibt_query_ah
1361  * Input:
1362  *	hca_hdl		The IBT HCA Handle.
1363  *	ah		IBT Address Handle.
1364  * Output:
1365  *	pd		The Protection Domain Handle with which this
1366  *			Address Handle is associated.
1367  *	adds_vectp	Points to an ibt_adds_vect_t struct.
1368  * Returns:
1369  *	IBT_SUCCESS/IBT_HCA_HDL_INVALID/IBT_AH_HDL_INVALID
1370  * Description:
1371  *	Obtain the address vector information for the specified address handle.
1372  */
1373 ibt_status_t
1374 ibt_query_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_hdl_t ah, ibt_pd_hdl_t *pd,
1375     ibt_adds_vect_t *adds_vectp)
1376 {
1377 	ibt_status_t	retval;
1378 
1379 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_query_ah(%p, %p)", hca_hdl, ah);
1380 
1381 	/* re-direct the call to CI's call */
1382 	retval = (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_query_ah(
1383 	    IBTL_HCA2CIHCA(hca_hdl), ah, pd, adds_vectp));
1384 
1385 	/*
1386 	 * We need to fill in av_sgid, as the CI does only saves/restores
1387 	 * av_sgid_ix.
1388 	 */
1389 	if (retval == IBT_SUCCESS) {
1390 		ibtl_hca_devinfo_t *hca_devp = hca_hdl->ha_hca_devp;
1391 		uint8_t port = adds_vectp->av_port_num;
1392 
1393 		mutex_enter(&ibtl_clnt_list_mutex);
1394 		if (port > 0 && port <= hca_devp->hd_hca_attr->hca_nports &&
1395 		    adds_vectp->av_sgid_ix < IBTL_HDIP2SGIDTBLSZ(hca_devp)) {
1396 			ib_gid_t *sgidp;
1397 
1398 			sgidp = hca_devp->hd_portinfop[port-1].p_sgid_tbl;
1399 			adds_vectp->av_sgid = sgidp[adds_vectp->av_sgid_ix];
1400 		} else {
1401 			adds_vectp->av_sgid.gid_prefix = 0;
1402 			adds_vectp->av_sgid.gid_guid = 0;
1403 		}
1404 		mutex_exit(&ibtl_clnt_list_mutex);
1405 	}
1406 	return (retval);
1407 }
1408 
1409 
1410 /*
1411  * Function:
1412  *	ibt_modify_ah
1413  * Input:
1414  *	hca_hdl		The IBT HCA Handle.
1415  *	ah		IBT Address Handle.
1416  * Output:
1417  *	adds_vectp	Points to an ibt_adds_vect_t struct. The new address
1418  *			vector information is specified is returned in this
1419  *			structure.
1420  * Returns:
1421  *	IBT_SUCCESS/IBT_HCA_HDL_INVALID/IBT_AH_HDL_INVALID
1422  * Description:
1423  *	Modify the address vector information for the specified Address Handle.
1424  */
1425 ibt_status_t
1426 ibt_modify_ah(ibt_hca_hdl_t hca_hdl, ibt_ah_hdl_t ah,
1427     ibt_adds_vect_t *adds_vectp)
1428 {
1429 	IBTF_DPRINTF_L3(ibtl_chan, "ibt_modify_ah(%p, %p)", hca_hdl, ah);
1430 
1431 	/* XXX - if av_send_grh, need to compute av_sgid_ix from av_sgid */
1432 
1433 	/* re-direct the call to CI's call */
1434 	return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_modify_ah(
1435 	    IBTL_HCA2CIHCA(hca_hdl), ah, adds_vectp));
1436 }
1437