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