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