xref: /illumos-gate/usr/src/uts/common/io/ib/clients/of/sol_uverbs/sol_uverbs_qp.c (revision c39526b769298791ff5b0b6c5e761f49aabaeb4e)
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 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 /*
26  * sol_uverbs_qp.c
27  *
28  * OFED User Verbs kernel agent QP implementation.
29  *
30  */
31 #include <sys/vfs.h>
32 #include <sys/vnode.h>
33 #include <sys/errno.h>
34 #include <sys/cred.h>
35 #include <sys/uio.h>
36 #include <sys/semaphore.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 
40 #include <sys/ib/ibtl/ibvti.h>
41 #include <sys/ib/clients/of/ofa_solaris.h>
42 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
43 #include <sys/ib/clients/of/ofed_kernel.h>
44 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs.h>
45 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_qp.h>
46 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_event.h>
47 
48 
49 static uint32_t	ibt_cep_flags2ibv(ibt_cep_flags_t);
50 static void	uverbs_cq_ctrl(uverbs_ucq_uobj_t *, sol_uverbs_cq_ctrl_t);
51 
52 extern char	*sol_uverbs_dbg_str;
53 
54 /*
55  * Multicast Element
56  */
57 typedef struct uverbs_mcast_entry {
58 	llist_head_t	list;
59 	ibt_mcg_info_t	mcg;
60 } uverbs_mcast_entry_t;
61 
62 /*
63  * uverbs_qp_state_table
64  *
65  * Determine if the requested QP modify operation is valid.  To maintain/ensure
66  * consistency with the semantics expected by OFED user verbs operaton, this
67  * table is used to verify a QP transition.  A valid transition is one that is
68  * a legal state transition and meets the required/optional attributes
69  * associated with that transition for that QP type.
70  *
71  * Note: The OFED kern-abi (See ib_user_verbs.h) does not provide any
72  * mechanism to support queue resize, consequently the IBTA spec defined
73  * valid optional parameter to modify QP size (IB_QP_CAP) is not included
74  * in the state table.
75  */
76 typedef struct {
77 	int			valid;
78 	enum ib_qp_attr_mask	req_param[IB_QPT_RAW_ETY + 1];
79 	enum ib_qp_attr_mask	opt_param[IB_QPT_RAW_ETY + 1];
80 } uverbs_qp_state_tbl_t;
81 
82 static uverbs_qp_state_tbl_t
83 uverbs_qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
84 	[IB_QPS_RESET] = {
85 		[IB_QPS_RESET] = { .valid = 1 },
86 		[IB_QPS_ERR]   = { .valid = 1 },
87 		[IB_QPS_INIT]  = { .valid = 1,
88 			.req_param = {
89 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX |
90 						IB_QP_PORT | IB_QP_QKEY),
91 				[IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
92 						IB_QP_ACCESS_FLAGS),
93 				[IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
94 						IB_QP_ACCESS_FLAGS),
95 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
96 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
97 			}
98 		},
99 	},
100 	[IB_QPS_INIT]  = {
101 		[IB_QPS_RESET] = { .valid = 1 },
102 		[IB_QPS_ERR] =   { .valid = 1 },
103 		[IB_QPS_INIT]  = { .valid = 1,
104 			.opt_param = {
105 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
106 						IB_QP_QKEY),
107 				[IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
108 						IB_QP_ACCESS_FLAGS),
109 				[IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
110 						IB_QP_ACCESS_FLAGS),
111 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
112 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
113 			}
114 		},
115 		[IB_QPS_RTR] = { .valid = 1,
116 			.req_param = {
117 				[IB_QPT_UC] = (IB_QP_AV | IB_QP_PATH_MTU |
118 						IB_QP_DEST_QPN | IB_QP_RQ_PSN),
119 				[IB_QPT_RC] = (IB_QP_AV | IB_QP_PATH_MTU |
120 						IB_QP_DEST_QPN | IB_QP_RQ_PSN |
121 						IB_QP_MAX_DEST_RD_ATOMIC |
122 						IB_QP_MIN_RNR_TIMER),
123 			},
124 			.opt_param = {
125 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
126 				[IB_QPT_UC] = (IB_QP_ALT_PATH |
127 						IB_QP_ACCESS_FLAGS |
128 						IB_QP_PKEY_INDEX),
129 				[IB_QPT_RC] = (IB_QP_ALT_PATH |
130 						IB_QP_ACCESS_FLAGS |
131 						IB_QP_PKEY_INDEX),
132 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
133 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
134 			}
135 		}
136 	},
137 	[IB_QPS_RTR] = {
138 		[IB_QPS_RESET] = { .valid = 1 },
139 		[IB_QPS_ERR] = { .valid = 1 },
140 		[IB_QPS_RTS] = { .valid = 1,
141 			.req_param = {
142 				[IB_QPT_UD] = IB_QP_SQ_PSN,
143 				[IB_QPT_UC] = IB_QP_SQ_PSN,
144 				[IB_QPT_RC] = (IB_QP_TIMEOUT |
145 						IB_QP_RETRY_CNT |
146 						IB_QP_RNR_RETRY |
147 						IB_QP_SQ_PSN |
148 						IB_QP_MAX_QP_RD_ATOMIC),
149 				[IB_QPT_SMI] = IB_QP_SQ_PSN,
150 				[IB_QPT_GSI] = IB_QP_SQ_PSN,
151 			},
152 			.opt_param = {
153 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
154 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
155 						IB_QP_ALT_PATH |
156 						IB_QP_ACCESS_FLAGS |
157 						IB_QP_PATH_MIG_STATE),
158 				[IB_QPT_RC] = (IB_QP_CUR_STATE |
159 						IB_QP_ALT_PATH |
160 						IB_QP_ACCESS_FLAGS |
161 						IB_QP_MIN_RNR_TIMER |
162 						IB_QP_PATH_MIG_STATE),
163 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
164 				[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
165 			}
166 		}
167 	},
168 	[IB_QPS_RTS] = {
169 		[IB_QPS_RESET] = { .valid = 1 },
170 		[IB_QPS_ERR] = { .valid = 1 },
171 		[IB_QPS_RTS] = { .valid = 1,
172 			.opt_param = {
173 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
174 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
175 						IB_QP_ACCESS_FLAGS |
176 						IB_QP_ALT_PATH |
177 						IB_QP_PATH_MIG_STATE),
178 				[IB_QPT_RC] = (IB_QP_CUR_STATE |
179 						IB_QP_ACCESS_FLAGS |
180 						IB_QP_ALT_PATH |
181 						IB_QP_PATH_MIG_STATE |
182 						IB_QP_MIN_RNR_TIMER),
183 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
184 				[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
185 			}
186 		},
187 		[IB_QPS_SQD] = { .valid = 1,
188 			.opt_param = {
189 				[IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY,
190 				[IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
191 				[IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
192 				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
193 				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
194 			}
195 		},
196 	},
197 	[IB_QPS_SQD] = {
198 		[IB_QPS_RESET] = { .valid = 1 },
199 		[IB_QPS_ERR] =  { .valid = 1 },
200 		[IB_QPS_RTS] = { .valid = 1,
201 			.opt_param = {
202 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
203 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
204 						IB_QP_ALT_PATH |
205 						IB_QP_ACCESS_FLAGS |
206 						IB_QP_PATH_MIG_STATE),
207 				[IB_QPT_RC] = (IB_QP_CUR_STATE |
208 						IB_QP_ALT_PATH  |
209 						IB_QP_ACCESS_FLAGS |
210 						IB_QP_MIN_RNR_TIMER |
211 						IB_QP_PATH_MIG_STATE),
212 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
213 				[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
214 			}
215 		},
216 		[IB_QPS_SQD] = { .valid = 1,
217 			.opt_param = {
218 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
219 				[IB_QPT_UC] = (IB_QP_AV | IB_QP_ALT_PATH |
220 						IB_QP_ACCESS_FLAGS |
221 						IB_QP_PKEY_INDEX |
222 						IB_QP_PATH_MIG_STATE),
223 				[IB_QPT_RC]  = (IB_QP_PORT | IB_QP_AV |
224 						IB_QP_TIMEOUT |
225 						IB_QP_RETRY_CNT |
226 						IB_QP_RNR_RETRY |
227 						IB_QP_MAX_QP_RD_ATOMIC |
228 						IB_QP_MAX_DEST_RD_ATOMIC |
229 						IB_QP_ALT_PATH |
230 						IB_QP_ACCESS_FLAGS |
231 						IB_QP_PKEY_INDEX |
232 						IB_QP_MIN_RNR_TIMER |
233 						IB_QP_PATH_MIG_STATE),
234 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
235 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
236 			}
237 		}
238 	},
239 	[IB_QPS_SQE] = {
240 		[IB_QPS_RESET] = { .valid = 1 },
241 		[IB_QPS_ERR] = { .valid = 1 },
242 		[IB_QPS_RTS] = { .valid = 1,
243 			.opt_param = {
244 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
245 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
246 						IB_QP_ACCESS_FLAGS),
247 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
248 				[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
249 			}
250 		}
251 	},
252 	[IB_QPS_ERR] = {
253 		[IB_QPS_RESET] = { .valid = 1 },
254 		[IB_QPS_ERR] = { .valid = 1 }
255 	}
256 };
257 
258 /*
259  * Function:
260  *      uverbs_modify_qp_is_ok
261  * Input:
262  *      cur_state	- The current OFED QP state.
263  *	next_state	- The OFED QP state to transition to.
264  *	type		- The OFED QP transport type.
265  *      mask		- The OFED QP attribute mask for the QP transition.
266  * Output:
267  *      None
268  * Returns:
269  *      Returns 1 if the operation is valid; otherwise 0 for invalid
270  *	operations.
271  * Description:
272  *      Indicate whether the desired QP modify operation is a valid operation.
273  *	To be valid, the state transition must be legal and the required and
274  *	optional parameters must be valid for the transition and QP type.
275  */
276 static int
277 uverbs_modify_qp_is_ok(enum ib_qp_state cur_state,
278     enum ib_qp_state next_state, enum ib_qp_type type,
279     enum ib_qp_attr_mask *maskp)
280 {
281 	enum ib_qp_attr_mask 	req_param, opt_param;
282 	uverbs_qp_state_tbl_t	*state_tblp;
283 	enum ib_qp_attr_mask	mask = *maskp;
284 
285 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp_is_ok"
286 	    "(%x, %x, %x, %x)", cur_state, next_state, type, mask);
287 
288 	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
289 	    next_state < 0 || next_state > IB_QPS_ERR) {
290 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
291 		    "modify_qp_is_ok: bad state, cur %d, next %d",
292 		    cur_state, next_state);
293 		return (0);
294 	}
295 
296 	if (mask & IB_QP_CUR_STATE &&
297 	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
298 	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE) {
299 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
300 		    "modify_qp_is_ok: cur_state %d is a bad state",
301 		    cur_state);
302 		return (0);
303 	}
304 
305 	state_tblp = &uverbs_qp_state_table[cur_state][next_state];
306 	if (!state_tblp->valid) {
307 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp: "
308 		    "bad transition, cur = %d, next = %d", cur_state,
309 		    next_state);
310 		return (0);
311 	}
312 
313 	req_param = state_tblp->req_param[type];
314 	opt_param = state_tblp->opt_param[type];
315 
316 	if ((mask & req_param) != req_param) {
317 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
318 		    "modify_qp_is_ok: cur %d, next %d, "
319 		    "missing required parms, spec = 0x%08X, "
320 		    "req = 0%08X", cur_state, next_state,
321 		    mask, req_param);
322 		return (0);
323 	}
324 
325 	if (mask & ~(req_param | opt_param | IB_QP_STATE)) {
326 		SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
327 		    "modify_qp_is_ok: cur %d, next %d, "
328 		    "illegal optional parms, parms = 0x%08X, "
329 		    "illegal = 0x%08X", cur_state, next_state,
330 		    mask, mask & ~(req_param | opt_param | IB_QP_STATE));
331 		*maskp = mask & (req_param | opt_param | IB_QP_STATE);
332 		return (0);
333 	}
334 
335 	return (1);
336 }
337 
338 
339 /*
340  * Function:
341  *      sol_uverbs_create_qp
342  * Input:
343  *      uctxt   - Pointer to the callers user context.
344  *      buf     - Pointer to kernel buffer containing the create command.
345  *      in_len  - Length in bytes of input command buffer.
346  *      out_len - Length in bytes of output response buffer.
347  * Output:
348  *      The command output buffer is updated with command results.
349  * Returns:
350  *      DDI_SUCCESS on success, else error code.
351  * Description:
352  *      User verbs entry point to create a new device QP.
353  */
354 /* ARGSUSED */
355 int
356 sol_uverbs_create_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
357     int in_len, int out_len)
358 {
359 	struct ib_uverbs_create_qp	cmd;
360 	struct ib_uverbs_create_qp_resp	resp;
361 	uverbs_uqp_uobj_t		*uqp;
362 	ibt_qp_type_t			qp_type;
363 	ibt_qp_alloc_attr_t		qp_attr;
364 	ibt_chan_sizes_t		qp_sizes;
365 	int				rc = 0;
366 	uverbs_upd_uobj_t		*upd;
367 	uverbs_ucq_uobj_t		*uscq;
368 	uverbs_ucq_uobj_t		*urcq;
369 	uverbs_usrq_uobj_t		*usrq = NULL;
370 
371 	(void) memcpy(&cmd, buf, sizeof (cmd));
372 	(void) memset(&resp, 0, sizeof (resp));
373 	(void) memset(&qp_attr, 0, sizeof (qp_attr));
374 	(void) memset(&qp_sizes, 0, sizeof (qp_sizes));
375 
376 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_qp(): entry");
377 
378 	switch (cmd.qp_type) {
379 		case IB_QPT_UC:
380 			qp_type 		= IBT_UC_RQP;
381 			break;
382 		case IB_QPT_UD:
383 			qp_type 		= IBT_UD_RQP;
384 			break;
385 		case IB_QPT_RC:
386 			qp_type 		= IBT_RC_RQP;
387 			break;
388 		default:
389 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
390 			    "create_qp(): Invalid qp type");
391 			rc = EINVAL;
392 			goto err_out;
393 	}
394 
395 	qp_attr.qp_alloc_flags = IBT_QP_USER_MAP;
396 
397 	if (cmd.is_srq) {
398 		qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ;
399 	}
400 
401 	qp_attr.qp_flags = IBT_WR_SIGNALED;
402 	if (cmd.sq_sig_all) {
403 		qp_attr.qp_flags = IBT_ALL_SIGNALED;
404 	}
405 
406 	uqp = kmem_zalloc(sizeof (*uqp), KM_NOSLEEP);
407 	if (uqp == NULL) {
408 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
409 		    "create_qp(): User object allocation failed");
410 		rc = ENOMEM;
411 		goto err_out;
412 	}
413 	sol_ofs_uobj_init(&uqp->uobj, cmd.user_handle,
414 	    SOL_UVERBS_UQP_UOBJ_TYPE);
415 	rw_enter(&uqp->uobj.uo_lock, RW_WRITER);
416 	llist_head_init(&uqp->mcast_list, NULL);
417 	llist_head_init(&uqp->async_list, NULL);
418 
419 	uqp->async_events_reported	= 0;
420 	uqp->uctxt			= uctxt;
421 	uqp->disable_qp_mod		= FALSE;
422 
423 	if (cmd.is_srq) {
424 		usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle);
425 		uqp->uqp_rcq_srq_valid |= SOL_UVERBS_UQP_SRQ_VALID;
426 		uqp->uqp_srq_hdl = cmd.srq_handle;
427 	}
428 	upd  = uverbs_uobj_get_upd_read(cmd.pd_handle);
429 	uqp->uqp_pd_hdl = cmd.pd_handle;
430 	uscq = uverbs_uobj_get_ucq_read(cmd.send_cq_handle);
431 	uqp->uqp_scq_hdl = cmd.send_cq_handle;
432 	uqp->uqp_rcq_hdl = cmd.recv_cq_handle;
433 	if (cmd.recv_cq_handle != cmd.send_cq_handle) {
434 		urcq = uverbs_uobj_get_ucq_read(cmd.recv_cq_handle);
435 		uqp->uqp_rcq_srq_valid |= SOL_UVERBS_UQP_RCQ_VALID;
436 	} else
437 		urcq = uscq;
438 
439 	if (!upd || !uscq || !urcq || (cmd.is_srq && !usrq)) {
440 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
441 		    "create_qp(): Invalid resource handle");
442 		rc = EINVAL;
443 		goto err_put;
444 	}
445 	uqp->uqp_rcq = urcq;
446 	uqp->uqp_scq = uscq;
447 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
448 	    "uqp %p, rcq %p. scq %p", uqp, urcq, uscq);
449 
450 	qp_attr.qp_pd_hdl	= upd->pd;
451 	if (usrq) {
452 		qp_attr.qp_srq_hdl = usrq->srq;
453 	}
454 	qp_attr.qp_scq_hdl		= uscq->cq;
455 	qp_attr.qp_rcq_hdl		= urcq->cq;
456 	qp_attr.qp_sizes.cs_sq		= cmd.max_send_wr;
457 	qp_attr.qp_sizes.cs_rq		= cmd.max_recv_wr;
458 	qp_attr.qp_sizes.cs_sq_sgl	= cmd.max_send_sge;
459 	qp_attr.qp_sizes.cs_rq_sgl	= cmd.max_recv_sge;
460 
461 	uqp->max_inline_data	= cmd.max_inline_data;
462 	uqp->ofa_qp_type	= cmd.qp_type;
463 
464 	/*
465 	 * NOTE: We allocate the QP and leave it in the RESET state to follow
466 	 * usage semantics consistent with OFA verbs.
467 	 */
468 	rc = ibt_alloc_qp(uctxt->hca->hdl, qp_type, &qp_attr, &qp_sizes,
469 	    &uqp->qp_num, &uqp->qp);
470 	if (rc != IBT_SUCCESS) {
471 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
472 		    "create_qp(): Error in ibt_alloc_qp() (rc=%d)", rc);
473 		rc = sol_uverbs_ibt_to_kernel_status(rc);
474 		uqp->uobj.uo_uobj_sz = sizeof (uverbs_uqp_uobj_t);
475 		goto err_put;
476 	}
477 
478 	ibt_set_qp_private(uqp->qp, uqp);
479 
480 	/* Bump up the active_qp_cnt for CQ, SRQ & PD resources it is using */
481 	upd->active_qp_cnt++;
482 	uscq->active_qp_cnt++;
483 	if (cmd.recv_cq_handle != cmd.send_cq_handle)
484 		urcq->active_qp_cnt++;
485 	if (usrq)
486 		usrq->active_qp_cnt++;
487 
488 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
489 	    "\treq cs_sq=%d, actual cs_sq=%d",
490 	    qp_attr.qp_sizes.cs_sq, qp_sizes.cs_sq);
491 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
492 	    "\treq cs_sq_sgl=%d, actual cs_sg_sgl=%d",
493 	    qp_attr.qp_sizes.cs_sq_sgl, qp_sizes.cs_sq_sgl);
494 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
495 	    "\treq cs_rq=%d, actual cs_rq=%d",
496 	    qp_attr.qp_sizes.cs_rq, qp_sizes.cs_rq);
497 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
498 	    "\treq cs_rq_sgl=%d, actual cs_rq_sgl=%d",
499 	    qp_attr.qp_sizes.cs_rq_sgl, qp_sizes.cs_rq_sgl);
500 
501 	/*
502 	 * Query underlying hardware for data used in mapping QP work
503 	 * queues back to user space, we will return this information
504 	 * in the user verbs command response.
505 	 */
506 	rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_CHANNEL,
507 	    (void *)uqp->qp, &resp.drv_out, sizeof (resp.drv_out));
508 	if (rc != IBT_SUCCESS) {
509 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
510 		    "create_qp(): Error in ibt_ci_data_out() (rc=%d)", rc);
511 		rc = EFAULT;
512 		uqp->uobj.uo_uobj_sz = sizeof (uverbs_uqp_uobj_t);
513 		goto err_qp_destroy;
514 	}
515 
516 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
517 	    "create_qp QP: ibt_ci_data_out:0x%016llx 0x%016llx",
518 	    resp.drv_out[0], resp.drv_out[1]);
519 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
520 	    "                          :0x%016llx 0x%016llx",
521 	    resp.drv_out[2], resp.drv_out[3]);
522 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
523 	    "                          :0x%016llx 0x%016llx",
524 	    resp.drv_out[4], resp.drv_out[5]);
525 
526 	if (sol_ofs_uobj_add(&uverbs_uqp_uo_tbl, &uqp->uobj) != 0) {
527 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
528 		    "create_qp(): User object add failed (rc=%d)", rc);
529 		rc = ENOMEM;
530 		goto err_qp_destroy;
531 	}
532 
533 	resp.qp_handle		= uqp->uobj.uo_id;
534 	resp.qpn		= uqp->qp_num;
535 	resp.max_send_wr	= qp_sizes.cs_sq;
536 	resp.max_send_sge	= qp_sizes.cs_sq_sgl;
537 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_qp() : "
538 	    "resp.qp_handle=0x%08x, resp.qpn=0x%08x", resp.qp_handle, resp.qpn);
539 
540 	/*
541 	 * In Solaris the receive work requests and sg entries are cleared
542 	 * when a SRQ is used since these values are ignored.  To maintain
543 	 * consistency with OFED we return the requested values as is done
544 	 * in OFED, but these values will be ignored and SRQ valuves are
545 	 * used.  MTHCA lib will extract the zeroed out value from the
546 	 * driver out data.
547 	 */
548 	if (usrq) {
549 		resp.max_recv_wr    = cmd.max_recv_wr;
550 		resp.max_recv_sge   = cmd.max_recv_sge;
551 	} else {
552 		resp.max_recv_wr    = qp_sizes.cs_rq;
553 		resp.max_recv_sge   = qp_sizes.cs_rq_sgl;
554 	}
555 	resp.max_inline_data = cmd.max_inline_data;
556 
557 #ifdef	_LP64
558 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
559 #else
560 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
561 #endif
562 	if (rc != 0) {
563 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
564 		    "create_qp(): Error writing resp data (rc=%d)", rc);
565 		rc = EFAULT;
566 		goto err_uo_delete;
567 	}
568 
569 	mutex_enter(&uctxt->lock);
570 	uqp->list_entry = add_genlist(&uctxt->qp_list, (uintptr_t)uqp,
571 	    (void*)uctxt);
572 	mutex_exit(&uctxt->lock);
573 
574 	if (!uqp->list_entry) {
575 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
576 		    "create_qp(): Error adding uqp to qp_list\n");
577 		rc = ENOMEM;
578 		goto err_uo_delete;
579 	}
580 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
581 	    "create_qp() - uqp %p", uqp);
582 
583 	uqp->uobj.uo_live = 1;
584 
585 	sol_ofs_uobj_put(&upd->uobj);
586 	sol_ofs_uobj_put(&uscq->uobj);
587 
588 	if (urcq != uscq) {
589 		sol_ofs_uobj_put(&urcq->uobj);
590 	}
591 	if (usrq) {
592 		sol_ofs_uobj_put(&usrq->uobj);
593 	}
594 	rw_exit(&uqp->uobj.uo_lock);
595 
596 	return (DDI_SUCCESS);
597 
598 err_uo_delete:
599 	/*
600 	 * Need to set uo_live, so sol_ofs_uobj_remove() will
601 	 * remove the object from the object table.
602 	 */
603 	uqp->uobj.uo_live = 1;
604 	(void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj);
605 
606 err_qp_destroy:
607 	(void) ibt_free_qp(uqp->qp);
608 
609 	upd->active_qp_cnt--;
610 	uscq->active_qp_cnt--;
611 	if (cmd.recv_cq_handle != cmd.send_cq_handle)
612 		urcq->active_qp_cnt--;
613 	if (usrq)
614 		usrq->active_qp_cnt--;
615 
616 err_put:
617 	if (upd) {
618 		sol_ofs_uobj_put(&upd->uobj);
619 	}
620 	if (uscq) {
621 		sol_ofs_uobj_put(&uscq->uobj);
622 	}
623 	if (urcq && urcq != uscq) {
624 		sol_ofs_uobj_put(&urcq->uobj);
625 	}
626 	if (usrq) {
627 		sol_ofs_uobj_put(&usrq->uobj);
628 	}
629 
630 	rw_exit(&uqp->uobj.uo_lock);
631 	sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free);
632 
633 err_out:
634 	return (rc);
635 }
636 
637 /*
638  * Free the resources used by uqp. Return 0, if the free of all
639  * resources where succesful, return non-zero, if not.
640  *
641  * If other uQPs are holding the resources (PD, CQ, SRQ), do not
642  * free the resource, but return 0, so the free of uqp can be
643  * done. Return failure only if active_cnt cannot be decremented
644  * resource_free() fails.
645  */
646 static int
647 uverbs_uqp_rsrc_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt)
648 {
649 	uverbs_ucq_uobj_t	*uscq = NULL, *urcq = NULL;
650 	uverbs_usrq_uobj_t	*usrq = NULL;
651 	uverbs_upd_uobj_t	*upd = NULL;
652 	int			ret, rc = -1;
653 
654 	/* Get uobj for PD, CQ & SRQ resources used. */
655 	upd = uverbs_uobj_get_upd_write(uqp->uqp_pd_hdl);
656 	if (upd == NULL) {
657 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
658 		    "uqp_rsrc_free: get_upd %d failed", uqp->uqp_pd_hdl);
659 		goto err_free;
660 	}
661 	uscq = uverbs_uobj_get_ucq_write(uqp->uqp_scq_hdl);
662 	if (uscq == NULL) {
663 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
664 		    "uqp_rsrc_free: get_ucq %x failed", uqp->uqp_scq_hdl);
665 		goto err_free;
666 	}
667 	if (uqp->uqp_rcq_srq_valid & SOL_UVERBS_UQP_RCQ_VALID) {
668 		urcq = uverbs_uobj_get_ucq_write(uqp->uqp_rcq_hdl);
669 		if (urcq == NULL) {
670 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
671 			    "uqp_rsrc_free: get_ucq %x failed",
672 			    uqp->uqp_rcq_hdl);
673 			goto err_free;
674 		}
675 	}
676 	if (uqp->uqp_rcq_srq_valid & SOL_UVERBS_UQP_SRQ_VALID) {
677 		usrq = uverbs_uobj_get_usrq_write(uqp->uqp_srq_hdl);
678 		if (usrq == NULL) {
679 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
680 			    "uqp_rsrc_free: get_srq %x failed",
681 			    uqp->uqp_srq_hdl);
682 			goto err_free;
683 		}
684 	}
685 	rc = 0;
686 
687 	/* Decrement active_qp_cnt for resources used */
688 	upd->active_qp_cnt--;
689 	uscq->active_qp_cnt--;
690 	if (urcq)
691 		urcq->active_qp_cnt--;
692 	if (usrq)
693 		usrq->active_qp_cnt--;
694 
695 	/*
696 	 * Free the resources, if active_qp_cnt is 0 and userland free
697 	 * already been pending for the resource.
698 	 */
699 	if (upd->active_qp_cnt == 0 && upd->free_pending) {
700 		ret = uverbs_upd_free(upd, uctxt);
701 		if (ret && rc == 0) {
702 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
703 			    "uqp_rsrc_free: upd_free failed");
704 			rc = ret;
705 		}
706 	} else if (upd)
707 		sol_ofs_uobj_put(&upd->uobj);
708 	if (uscq && uscq->active_qp_cnt == 0 && uscq->free_pending) {
709 		ret = uverbs_ucq_free(uscq, uctxt);
710 		if (ret && rc == 0) {
711 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
712 			    "uqp_rsrc_free: ucq_free failed");
713 			rc = ret;
714 		}
715 	} else if (uscq)
716 		sol_ofs_uobj_put(&uscq->uobj);
717 	if (urcq && urcq->active_qp_cnt == 0 && urcq->free_pending) {
718 		rc = uverbs_ucq_free(urcq, uctxt);
719 		if (ret && rc == 0) {
720 		if (rc)
721 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
722 			    "uqp_rsrc_free: ucq_free failed");
723 			rc = ret;
724 		}
725 	} else if (urcq)
726 		sol_ofs_uobj_put(&urcq->uobj);
727 	if (usrq && usrq->active_qp_cnt == 0 && usrq->free_pending) {
728 		rc = uverbs_usrq_free(usrq, uctxt);
729 		if (ret && rc == 0) {
730 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
731 			    "uqp_rsrc_free: usrq_free failed");
732 			rc = ret;
733 		}
734 	} else if (usrq)
735 		sol_ofs_uobj_put(&usrq->uobj);
736 	return (rc);
737 
738 err_free:
739 	if (upd)
740 		sol_ofs_uobj_put(&upd->uobj);
741 	if (uscq)
742 		sol_ofs_uobj_put(&uscq->uobj);
743 	if (urcq)
744 		sol_ofs_uobj_put(&urcq->uobj);
745 	if (usrq)
746 		sol_ofs_uobj_put(&usrq->uobj);
747 
748 	return (rc);
749 }
750 
751 /*
752  * Free the resources held by the uqp.
753  * Call ibt_free_qp() to free the IBTF QP.
754  * Free uqp.
755  */
756 int
757 uverbs_uqp_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt)
758 {
759 	int		rc;
760 	ibt_status_t	status;
761 
762 	/* Detach  Mcast entries, if any. */
763 	uverbs_detach_uqp_mcast_entries(uqp);
764 
765 	if (!uqp->qp)
766 		goto skip_ibt_free_qp;
767 
768 	status = ibt_free_qp(uqp->qp);
769 	if (status != IBT_SUCCESS) {
770 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
771 		    "uqp_free: ibt_free_qp failed %d", status);
772 		sol_ofs_uobj_put(&uqp->uobj);
773 		return (status);
774 	}
775 	uqp->qp = NULL;
776 
777 skip_ibt_free_qp :
778 	rc = uverbs_uqp_rsrc_free(uqp, uctxt);
779 	if (rc) {
780 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
781 		    "uqp_free: uqp_rcrc_free failed  %d", rc);
782 		sol_ofs_uobj_put(&uqp->uobj);
783 		return (rc);
784 	}
785 
786 	(void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj);
787 	sol_ofs_uobj_put(&uqp->uobj);
788 
789 	if (uqp->list_entry) {
790 		mutex_enter(&uctxt->lock);
791 		delete_genlist(&uctxt->qp_list, uqp->list_entry);
792 		uqp->list_entry = NULL;
793 		mutex_exit(&uctxt->lock);
794 	}
795 
796 	sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free);
797 
798 	if (uctxt->uctxt_free_pending && (uctxt->qp_list).count == 0) {
799 		SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
800 		    "uqp_free: freeing uctxt %p", uctxt);
801 		sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free);
802 	}
803 	return (0);
804 }
805 
806 /*
807  * Function:
808  *      sol_uverbs_destroy_qp
809  * Input:
810  *      uctxt   - Pointer to the callers user context.
811  *      buf     - Pointer to kernel buffer containing the destroy command.
812  *      in_len  - Length in bytes of input command buffer.
813  *      out_len - Length in bytes of output response buffer.
814  * Output:
815  *      The command output buffer is updated with command results.
816  * Returns:
817  *      DDI_SUCCESS on success, else error code.
818  * Description:
819  *      User verbs  entry point to destroy a device QP.
820  */
821 /* ARGSUSED */
822 int
823 sol_uverbs_destroy_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
824     int in_len, int out_len)
825 {
826 	struct ib_uverbs_destroy_qp		cmd;
827 	struct ib_uverbs_destroy_qp_resp	resp;
828 	uverbs_uqp_uobj_t			*uqp;
829 	int					rc;
830 	int					uobj_put_req = 1;
831 
832 	(void) memcpy(&cmd, buf, sizeof (cmd));
833 	(void) memset(&resp, 0, sizeof (resp));
834 
835 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: entry "
836 	    "(qp_handle=%d)", cmd.qp_handle);
837 
838 	uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
839 	if (uqp == NULL) {
840 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
841 		    "destroy_qp() : List lookup failure");
842 		rc = EINVAL;
843 		goto err_out;
844 	}
845 
846 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: qp_handle=%d, "
847 	    "uqp %p, qp_ptr %p", cmd.qp_handle, uqp, uqp->qp);
848 
849 	if (!llist_empty(&uqp->mcast_list)) {
850 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
851 		    "destroy_qp() called with attached MC group(s)");
852 		rc = EBUSY;
853 		goto err_busy;
854 	}
855 
856 	uverbs_release_uqp_uevents(uctxt->async_evfile, uqp);
857 	resp.events_reported = uqp->async_events_reported;
858 
859 	/*
860 	 * If ucma has disabled QP free for this QP, set FREE_PENDING
861 	 * flag so that the QP can be freed when UCMA enables QP_FREE.
862 	 * Call ibt_free_qp() is ucma has not disabled QP free.
863 	 */
864 	if (uqp->uqp_free_state == SOL_UVERBS2UCMA_DISABLE_QP_FREE) {
865 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
866 		    "destroy_qp() - UCMA disabled");
867 		uqp->uqp_free_state = SOL_UVERBS2UCMA_FREE_PENDING;
868 		sol_ofs_uobj_put(&uqp->uobj);
869 		rc = 0;
870 		goto report_qp_evts;
871 	} else {
872 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
873 		    "destroy_qp() - freeing QP : %p", uqp);
874 		rc = uverbs_uqp_free(uqp, uctxt);
875 		uobj_put_req = 0;
876 	}
877 
878 	if (rc) {
879 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
880 		    "destroy_qp() - ibt_free_qp() fail %d", rc);
881 		rc = sol_uverbs_ibt_to_kernel_status(rc);
882 		if (uobj_put_req)
883 			goto err_busy;
884 		else
885 			goto err_out;
886 	}
887 
888 report_qp_evts:
889 #ifdef	_LP64
890 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
891 #else
892 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
893 #endif
894 	if (rc != 0) {
895 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
896 		    "destroy_qp() : copyout failure %x", rc);
897 		rc = EFAULT;
898 		goto err_out;
899 	}
900 
901 	return (DDI_SUCCESS);
902 
903 err_busy:
904 	sol_ofs_uobj_put(&uqp->uobj);
905 
906 err_out:
907 	return (rc);
908 }
909 
910 /*
911  * Function:
912  *      uverbs_copy_path_info_from_ibv
913  * Input:
914  *      src_path	- IB OFED path.
915  * Output:
916  *      dest_path	- IBT path.
917  * Returns:
918  *      None
919  * Description:
920  *      Helper to copy from the OFED path format to IBT path format.
921  */
922 static void
923 uverbs_copy_path_info_from_ibv(struct ib_uverbs_qp_dest *src_path,
924     ibt_cep_path_t *dest_path)
925 {
926 	ASSERT(src_path != NULL);
927 	ASSERT(dest_path != NULL);
928 
929 	(void) memcpy(&dest_path->cep_adds_vect.av_dgid,
930 	    &src_path->dgid[0], sizeof (src_path->dgid));
931 
932 	dest_path->cep_adds_vect.av_flow	= src_path->flow_label;
933 	dest_path->cep_adds_vect.av_dlid	= src_path->dlid;
934 	dest_path->cep_adds_vect.av_hop		= src_path->hop_limit;
935 	dest_path->cep_adds_vect.av_tclass	= src_path->traffic_class;
936 	dest_path->cep_adds_vect.av_srvl	= src_path->sl & 0x0f;
937 	dest_path->cep_adds_vect.av_port_num	= src_path->port_num;
938 	dest_path->cep_adds_vect.av_src_path	= src_path->src_path_bits;
939 	dest_path->cep_adds_vect.av_send_grh	= src_path->is_global;
940 	dest_path->cep_adds_vect.av_sgid_ix	= src_path->sgid_index;
941 	dest_path->cep_adds_vect.av_srate 	= src_path->static_rate;
942 }
943 
944 /*
945  * Function:
946  *      uverbs_modify_update
947  * Input:
948  *      cmd		- The user verbs modify command to be translated.
949  *	cur_state	- The current QP state
950  *	new_state	- The new QP state
951  * Output:
952  *      qp_query_attr	- The IBT QP attributes.
953  *	flags		- The IBT flags.
954  * Returns:
955  *      None
956  * Description:
957  *      Helper to convert OFED user verbs QP modify attributes to IBT
958  *	QP modify attributes.  Note that on required parameters, the
959  *	individual IBT modify flags are not set (there is a global
960  *	flag for the transition), only optional flags are set.
961  */
962 static void
963 uverbs_modify_update(struct ib_uverbs_modify_qp *cmd,
964     enum ib_qp_state cur_state, enum ib_qp_state new_state,
965     ibt_qp_query_attr_t *qp_query_attr, ibt_cep_modify_flags_t *flags)
966 {
967 	ibt_qp_info_t		*qp_infop;
968 	ibt_qp_rc_attr_t	*rcp;
969 	ibt_qp_uc_attr_t	*ucp;
970 	ibt_qp_ud_attr_t	*udp;
971 
972 	*flags = IBT_CEP_SET_NOTHING;
973 	qp_infop = &(qp_query_attr->qp_info);
974 	rcp = &(qp_infop->qp_transport.rc);
975 	ucp = &(qp_infop->qp_transport.uc);
976 	udp = &(qp_infop->qp_transport.ud);
977 
978 	switch (cur_state) {
979 	case IB_QPS_RESET:
980 		qp_infop->qp_current_state = IBT_STATE_RESET;
981 		break;
982 	case IB_QPS_INIT:
983 		qp_infop->qp_current_state = IBT_STATE_INIT;
984 		break;
985 	case IB_QPS_RTR:
986 		qp_infop->qp_current_state = IBT_STATE_RTR;
987 		break;
988 	case IB_QPS_RTS:
989 		qp_infop->qp_current_state = IBT_STATE_RTS;
990 		break;
991 	case IB_QPS_SQD:
992 		qp_infop->qp_current_state = IBT_STATE_SQD;
993 		break;
994 	case IB_QPS_SQE:
995 		qp_infop->qp_current_state = IBT_STATE_SQE;
996 		break;
997 	case IB_QPS_ERR:
998 		qp_infop->qp_current_state = IBT_STATE_ERROR;
999 		break;
1000 	}
1001 
1002 	if (cmd->attr_mask & IB_QP_STATE) {
1003 		switch (new_state) {
1004 		case IB_QPS_RESET:
1005 			qp_infop->qp_state = IBT_STATE_RESET;
1006 			*flags |= IBT_CEP_SET_STATE;
1007 			break;
1008 
1009 		case IB_QPS_INIT:
1010 			qp_infop->qp_state = IBT_STATE_INIT;
1011 			if (cur_state == IB_QPS_RESET) {
1012 				*flags |= IBT_CEP_SET_RESET_INIT;
1013 			} else {
1014 				*flags |= IBT_CEP_SET_STATE;
1015 			}
1016 			break;
1017 
1018 		case IB_QPS_RTR:
1019 			qp_infop->qp_state = IBT_STATE_RTR;
1020 			if (cur_state == IB_QPS_INIT) {
1021 				*flags |= IBT_CEP_SET_INIT_RTR;
1022 			} else {
1023 				*flags |= IBT_CEP_SET_STATE;
1024 			}
1025 			break;
1026 
1027 		case IB_QPS_RTS:
1028 			qp_infop->qp_state = IBT_STATE_RTS;
1029 
1030 			/*
1031 			 * For RTS transitions other than RTR we must
1032 			 * specify the assumption for the qp state.
1033 			 */
1034 			if (cur_state == IB_QPS_RTR) {
1035 				*flags |= IBT_CEP_SET_RTR_RTS;
1036 			} else {
1037 				ibt_cep_state_t *ibt_curr =
1038 				    &qp_infop->qp_current_state;
1039 
1040 				switch (cur_state) {
1041 				case IB_QPS_RTR:
1042 					*ibt_curr = IBT_STATE_RTR;
1043 					break;
1044 
1045 				case IB_QPS_RTS:
1046 					*ibt_curr = IBT_STATE_RTS;
1047 					break;
1048 
1049 				case IB_QPS_SQD:
1050 					*ibt_curr = IBT_STATE_SQD;
1051 					break;
1052 
1053 				case IB_QPS_SQE:
1054 					*ibt_curr = IBT_STATE_SQE;
1055 					break;
1056 				}
1057 				*flags |= IBT_CEP_SET_STATE;
1058 			}
1059 			break;
1060 
1061 		case IB_QPS_SQD:
1062 			qp_infop->qp_state = IBT_STATE_SQD;
1063 			*flags |= IBT_CEP_SET_STATE;
1064 			break;
1065 
1066 		case IB_QPS_SQE:
1067 			qp_infop->qp_state = IBT_STATE_SQE;
1068 			*flags |= IBT_CEP_SET_STATE;
1069 			break;
1070 
1071 		case IB_QPS_ERR:
1072 			qp_infop->qp_state = IBT_STATE_ERROR;
1073 			*flags |= IBT_CEP_SET_STATE;
1074 			break;
1075 		}
1076 	}
1077 
1078 	if (cmd->attr_mask & IB_QP_PKEY_INDEX) {
1079 		if (qp_infop->qp_trans == IBT_UD_SRV) {
1080 			udp->ud_pkey_ix = cmd->pkey_index;
1081 		} else if (qp_infop->qp_trans == IBT_RC_SRV) {
1082 			rcp->rc_path.cep_pkey_ix = cmd->pkey_index;
1083 		}
1084 		*flags |= IBT_CEP_SET_PKEY_IX;
1085 	}
1086 
1087 
1088 	if (cmd->attr_mask & IB_QP_AV) {
1089 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1090 			uverbs_copy_path_info_from_ibv(&cmd->dest,
1091 			    &rcp->rc_path);
1092 		}
1093 		*flags |= IBT_CEP_SET_ADDS_VECT;
1094 	}
1095 
1096 	if (qp_infop->qp_trans == IBT_RC_SRV) {
1097 		if (cmd->attr_mask & IB_QP_TIMEOUT) {
1098 			rcp->rc_path.cep_timeout = cmd->timeout;
1099 			*flags |= IBT_CEP_SET_TIMEOUT;
1100 		}
1101 	}
1102 
1103 	if (cmd->attr_mask & IB_QP_PORT) {
1104 		if (qp_infop->qp_trans == IBT_UD_SRV) {
1105 			udp->ud_port = cmd->port_num;
1106 		} else if (qp_infop->qp_trans == IBT_RC_SRV) {
1107 			rcp->rc_path.cep_hca_port_num = cmd->port_num;
1108 		}
1109 		*flags |= IBT_CEP_SET_PORT;
1110 	}
1111 
1112 	if (cmd->attr_mask & IB_QP_QKEY) {
1113 		if (qp_infop->qp_trans == IBT_UD_SRV) {
1114 			udp->ud_qkey = cmd->qkey;
1115 		}
1116 		if (qp_infop->qp_trans == IBT_RD_SRV) {
1117 			qp_infop->qp_transport.rd.rd_qkey = cmd->qkey;
1118 		}
1119 		*flags |= IBT_CEP_SET_QKEY;
1120 	}
1121 
1122 	if (cmd->attr_mask & IB_QP_PATH_MTU) {
1123 		if (qp_infop->qp_trans == IBT_UC_SRV) {
1124 			ucp->uc_path_mtu = cmd->path_mtu;
1125 		}
1126 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1127 			rcp->rc_path_mtu = cmd->path_mtu;
1128 		}
1129 	}
1130 
1131 	if (cmd->attr_mask & IB_QP_RETRY_CNT) {
1132 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1133 			rcp->rc_retry_cnt = cmd->retry_cnt & 0x7;
1134 		}
1135 		*flags |= IBT_CEP_SET_RETRY;
1136 	}
1137 
1138 	if (cmd->attr_mask & IB_QP_RNR_RETRY) {
1139 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1140 			rcp->rc_rnr_retry_cnt = cmd->rnr_retry;
1141 		}
1142 		*flags |= IBT_CEP_SET_RNR_NAK_RETRY;
1143 	}
1144 
1145 	if (cmd->attr_mask & IB_QP_MIN_RNR_TIMER) {
1146 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1147 			rcp->rc_min_rnr_nak = cmd->min_rnr_timer;
1148 		}
1149 		*flags |= IBT_CEP_SET_MIN_RNR_NAK;
1150 	}
1151 
1152 	if (cmd->attr_mask & IB_QP_RQ_PSN) {
1153 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1154 			rcp->rc_rq_psn = cmd->rq_psn;
1155 		}
1156 		if (qp_infop->qp_trans == IBT_UC_SRV) {
1157 			ucp->uc_rq_psn = cmd->rq_psn;
1158 		}
1159 	}
1160 
1161 	if (cmd->attr_mask & IB_QP_ALT_PATH) {
1162 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1163 			uverbs_copy_path_info_from_ibv(&cmd->alt_dest,
1164 			    &rcp->rc_alt_path);
1165 
1166 			rcp->rc_alt_path.cep_hca_port_num = cmd->alt_port_num;
1167 			rcp->rc_alt_path.cep_timeout = cmd->alt_timeout;
1168 		}
1169 
1170 		if (qp_infop->qp_trans == IBT_UC_SRV) {
1171 			uverbs_copy_path_info_from_ibv(&cmd->alt_dest,
1172 			    &ucp->uc_alt_path);
1173 
1174 			ucp->uc_alt_path.cep_hca_port_num = cmd->alt_port_num;
1175 			ucp->uc_alt_path.cep_timeout = cmd->alt_timeout;
1176 		}
1177 
1178 		*flags |= IBT_CEP_SET_ALT_PATH;
1179 	}
1180 
1181 
1182 	if (cmd->attr_mask & IB_QP_SQ_PSN) {
1183 		if (qp_infop->qp_trans == IBT_UD_SRV) {
1184 			udp->ud_sq_psn = cmd->sq_psn;
1185 		}
1186 		if (qp_infop->qp_trans == IBT_UC_SRV) {
1187 			ucp->uc_sq_psn = cmd->sq_psn;
1188 		}
1189 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1190 			rcp->rc_sq_psn = cmd->sq_psn;
1191 		}
1192 	}
1193 
1194 	if (cmd->attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
1195 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1196 			rcp->rc_rdma_ra_out = cmd->max_rd_atomic;
1197 		}
1198 		*flags |= IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_STATE;
1199 	}
1200 
1201 	if (cmd->attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
1202 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1203 			rcp->rc_rdma_ra_in = cmd->max_dest_rd_atomic;
1204 		}
1205 		*flags |= IBT_CEP_SET_RDMARA_IN | IBT_CEP_SET_STATE;
1206 	}
1207 
1208 	if (cmd->attr_mask & (IB_QP_ACCESS_FLAGS |
1209 	    IB_QP_MAX_DEST_RD_ATOMIC)) {
1210 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1211 			uint32_t	access_flags = IBT_CEP_NO_FLAGS;
1212 
1213 			if (rcp->rc_rdma_ra_in) {
1214 				access_flags	|= IBT_CEP_RDMA_WR;
1215 				*flags		|= IBT_CEP_SET_RDMA_W;
1216 			}
1217 
1218 			if (cmd->attr_mask & IB_QP_ACCESS_FLAGS) {
1219 				if (cmd->qp_access_flags &
1220 				    IB_ACCESS_REMOTE_WRITE) {
1221 					access_flags	|= IBT_CEP_RDMA_WR;
1222 					*flags		|= IBT_CEP_SET_RDMA_W;
1223 				}
1224 				if (cmd->qp_access_flags &
1225 				    IB_ACCESS_REMOTE_READ) {
1226 					access_flags	|= IBT_CEP_RDMA_RD;
1227 					*flags		|= IBT_CEP_SET_RDMA_R;
1228 				}
1229 				if (cmd->qp_access_flags &
1230 				    IB_ACCESS_REMOTE_ATOMIC) {
1231 					access_flags	|= IBT_CEP_ATOMIC;
1232 					*flags		|= IBT_CEP_SET_ATOMIC;
1233 				}
1234 			}
1235 			qp_infop->qp_flags &= ~(IBT_CEP_RDMA_WR |
1236 			    IBT_CEP_RDMA_RD | IBT_CEP_ATOMIC);
1237 			qp_infop->qp_flags |= access_flags;
1238 		}
1239 	}
1240 
1241 	if (cmd->attr_mask & IB_QP_PATH_MIG_STATE) {
1242 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1243 			if (cmd->path_mig_state == IB_MIG_MIGRATED) {
1244 				rcp->rc_mig_state = IBT_STATE_MIGRATED;
1245 			}
1246 			if (cmd->path_mig_state == IB_MIG_REARM) {
1247 				rcp->rc_mig_state = IBT_STATE_REARMED;
1248 			}
1249 			if (cmd->path_mig_state == IB_MIG_ARMED) {
1250 				rcp->rc_mig_state = IBT_STATE_ARMED;
1251 			}
1252 		}
1253 
1254 		if (qp_infop->qp_trans == IBT_UC_SRV) {
1255 			if (cmd->path_mig_state == IB_MIG_MIGRATED) {
1256 				ucp->uc_mig_state = IBT_STATE_MIGRATED;
1257 			}
1258 			if (cmd->path_mig_state == IB_MIG_REARM) {
1259 				ucp->uc_mig_state = IBT_STATE_REARMED;
1260 			}
1261 			if (cmd->path_mig_state == IB_MIG_ARMED) {
1262 				ucp->uc_mig_state = IBT_STATE_ARMED;
1263 			}
1264 		}
1265 		*flags |= IBT_CEP_SET_MIG;
1266 	}
1267 
1268 	if (cmd->attr_mask & IB_QP_DEST_QPN) {
1269 		if (qp_infop->qp_trans == IBT_RC_SRV) {
1270 			rcp->rc_dst_qpn = cmd->dest_qp_num;
1271 		}
1272 		if (qp_infop->qp_trans == IBT_UC_SRV) {
1273 			ucp->uc_dst_qpn = cmd->dest_qp_num;
1274 		}
1275 	}
1276 }
1277 
1278 
1279 static void
1280 uverbs_qp_print_path(ibt_cep_path_t *pathp)
1281 {
1282 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print_pathp %p", pathp);
1283 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "cep_pkey_ix %x, "
1284 	    "cep_hca_port_num %x", pathp->cep_pkey_ix, pathp->cep_hca_port_num);
1285 }
1286 
1287 static void
1288 uverbs_print_query_qp(ibt_qp_hdl_t qp_hdlp)
1289 {
1290 	ibt_qp_query_attr_t	qp_query_attr;
1291 	ibt_qp_info_t		*qp_infop = &qp_query_attr.qp_info;
1292 	ibt_qp_rc_attr_t	*rcp = &((qp_infop->qp_transport).rc);
1293 	ibt_status_t		rc;
1294 
1295 	bzero(&qp_query_attr, sizeof (qp_query_attr));
1296 	rc =  ibt_query_qp(qp_hdlp, &qp_query_attr);
1297 	if (rc != IBT_SUCCESS) {
1298 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "print_query_qp -"
1299 		    "ibt_query_qp() failed - rc=%d", rc);
1300 		return;
1301 	}
1302 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print %p", qp_hdlp);
1303 
1304 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_cq %p, qp_rq_cq %p, "
1305 	    "qp_qpn %x, qp_sq_sgl %x, qp_rq_sgl %x, qp_srq %p, qp_flags %x",
1306 	    qp_query_attr.qp_sq_cq, qp_query_attr.qp_rq_cq,
1307 	    qp_query_attr.qp_qpn, qp_query_attr.qp_sq_sgl,
1308 	    qp_query_attr.qp_rq_sgl, qp_query_attr.qp_srq,
1309 	    qp_query_attr.qp_flags);
1310 
1311 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_sz %x, qp_rq_sz %x, "
1312 	    "qp_state %x, qp_current_state %x, qp_flags %x, qp_trans %x",
1313 	    qp_infop->qp_sq_sz, qp_infop->qp_rq_sz, qp_infop->qp_state,
1314 	    qp_infop->qp_current_state,  qp_infop->qp_flags,
1315 	    qp_infop->qp_trans);
1316 
1317 	if (qp_infop->qp_trans == IBT_RC_SRV) {
1318 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "rc_sq_psn %x, rc_rq_psn %x, "
1319 	    "rc_dst_qpn %x, rc_mig_state %x, rc_rnr_retry_cnt %x,"
1320 	    "rc_retry_cnt %x rc_rdma_ra_out %x, rc_rdma_ra_in %x,"
1321 	    "rc_min_rnr_nak %x, rc_path_mtu %x",
1322 	    rcp->rc_sq_psn, rcp->rc_rq_psn, rcp->rc_dst_qpn, rcp->rc_mig_state,
1323 	    rcp->rc_rnr_retry_cnt, rcp->rc_retry_cnt, rcp->rc_rdma_ra_out,
1324 	    rcp->rc_rdma_ra_in, rcp->rc_min_rnr_nak, rcp->rc_path_mtu);
1325 	uverbs_qp_print_path(&rcp->rc_path);
1326 	uverbs_qp_print_path(&rcp->rc_alt_path);
1327 	}
1328 }
1329 
1330 
1331 /*
1332  * Function:
1333  *      sol_uverbs_modify_qp
1334  * Input:
1335  *      uctxt   - Pointer to the callers user context.
1336  *      buf     - Pointer to kernel buffer containing QP modify command.
1337  *      in_len  - Length in bytes of input command buffer.
1338  *      out_len - Length in bytes of output response buffer.
1339  * Output:
1340  *      The command output buffer is updated with command results.
1341  * Returns:
1342  *      DDI_SUCCESS on success, else error code.
1343  * Description:
1344  *      User verbs entry point to modify a device QP.
1345  */
1346 /* ARGSUSED */
1347 int
1348 sol_uverbs_modify_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
1349     int in_len, int out_len)
1350 {
1351 	struct ib_uverbs_modify_qp	cmd;
1352 	uverbs_uqp_uobj_t		*uqp;
1353 	ibt_qp_query_attr_t		qp_query_attr;
1354 	ibt_cep_modify_flags_t		flags;
1355 	ibt_queue_sizes_t		size;
1356 	int				rc;
1357 	enum ib_qp_state		cur_state, new_state;
1358 
1359 	(void) memcpy(&cmd, buf, sizeof (cmd));
1360 
1361 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp - qp_hdl %d, "
1362 	    "attr_mask %x", cmd.qp_handle, cmd.attr_mask);
1363 
1364 	uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
1365 	if (uqp == NULL) {
1366 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -"
1367 		    "List lookup failure");
1368 		rc = EINVAL;
1369 		goto err_out;
1370 	}
1371 
1372 	/*
1373 	 * Has the UCMA asked us to ignore QP modify operations?
1374 	 * This is required because of differences in the level of
1375 	 * abstraction fo CM processing between IBT and OFED.
1376 	 */
1377 	if (uqp->disable_qp_mod == TRUE) {
1378 		SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp -"
1379 		    "qp_mod disabled");
1380 		goto done;
1381 	}
1382 
1383 	/*
1384 	 * Load the current QP attributes and then do a validation
1385 	 * based on OFA verbs expectations to see if the modify
1386 	 * should be performed.
1387 	 */
1388 	bzero(&qp_query_attr, sizeof (qp_query_attr));
1389 	rc =  ibt_query_qp(uqp->qp, &qp_query_attr);
1390 	if (rc != IBT_SUCCESS) {
1391 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -"
1392 		    "ibt_query_qp() failed - rc=%d", rc);
1393 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1394 		goto err_deref;
1395 	}
1396 
1397 	if (cmd.attr_mask & IB_QP_CUR_STATE) {
1398 		cur_state = cmd.cur_qp_state;
1399 	} else {
1400 		cur_state = IBT_TO_OFA_QP_STATE(qp_query_attr.qp_info.qp_state);
1401 	}
1402 
1403 	new_state = cmd.attr_mask & IB_QP_STATE ? cmd.qp_state : cur_state;
1404 
1405 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp: ibt qp %p, handle "
1406 	    "%x, cur_state %x, new_state %x, qp_type %x, attr_mask %x", uqp->qp,
1407 	    cmd.qp_handle, cur_state, new_state, uqp->ofa_qp_type,
1408 	    cmd.attr_mask);
1409 
1410 	if (!uverbs_modify_qp_is_ok(cur_state, new_state, uqp->ofa_qp_type,
1411 	    (enum ib_qp_attr_mask *)&cmd.attr_mask)) {
1412 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp() -"
1413 		    "Failed modify OK test");
1414 		rc = EINVAL;
1415 		goto err_deref;
1416 	}
1417 
1418 	if (!cmd.attr_mask) {
1419 		SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp() -"
1420 		    "attr_mask after modify OK test is 0");
1421 		rc = 0;
1422 		goto done;
1423 	}
1424 
1425 	flags = 0;
1426 
1427 	switch (uqp->ofa_qp_type) {
1428 		case IB_QPT_UC:
1429 			qp_query_attr.qp_info.qp_trans = IBT_UC_SRV;
1430 			break;
1431 		case IB_QPT_UD:
1432 			qp_query_attr.qp_info.qp_trans = IBT_UD_SRV;
1433 			break;
1434 		case IB_QPT_RC:
1435 			qp_query_attr.qp_info.qp_trans = IBT_RC_SRV;
1436 			break;
1437 		default:
1438 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1439 			    "modify_qp: Invalid QP type");
1440 			rc = EINVAL;
1441 			goto err_deref;
1442 	}
1443 
1444 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): qp_info.qp_flags "
1445 	    "before modify update = 0%08x", qp_query_attr.qp_info.qp_flags);
1446 
1447 	uverbs_modify_update(&cmd, cur_state, new_state, &qp_query_attr,
1448 	    &flags);
1449 
1450 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): after "
1451 	    "modify_update hdl flags = 0x%08x, qp_info.qp_flags = 0%08x",
1452 	    flags, qp_query_attr.qp_info.qp_flags);
1453 
1454 	rc = ibt_modify_qp(uqp->qp, flags, &qp_query_attr.qp_info, &size);
1455 
1456 	if (rc != IBT_SUCCESS) {
1457 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1458 		    "modify_qp: Error in ibt_modify_qp() (rc=%d)", rc);
1459 		uverbs_print_query_qp(uqp->qp);
1460 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1461 		goto err_deref;
1462 	}
1463 
1464 done:
1465 	sol_ofs_uobj_put(&uqp->uobj);
1466 	return (DDI_SUCCESS);
1467 
1468 err_deref:
1469 	sol_ofs_uobj_put(&uqp->uobj);
1470 
1471 err_out:
1472 	return (rc);
1473 }
1474 
1475 /*
1476  * Function:
1477  *      uverbs_copy_path_info_from_ibt
1478  * Input:
1479  *      src_path	- The IBT path.
1480  * Output:
1481  *      dest_path	- The OFED user verbs path.
1482  * Returns:
1483  *      None
1484  * Description:
1485  *      Helper to convert IBT path to OFED  user verbs path.
1486  */
1487 static void
1488 uverbs_copy_path_info_from_ibt(ibt_cep_path_t *src_path,
1489     struct ib_uverbs_qp_dest *dest_path)
1490 {
1491 	ASSERT(src_path != NULL);
1492 	ASSERT(dest_path != NULL);
1493 
1494 	(void) memcpy(&dest_path->dgid[0],
1495 	    &src_path->cep_adds_vect.av_dgid, sizeof (dest_path->dgid));
1496 
1497 	dest_path->flow_label = src_path->cep_adds_vect.av_flow;
1498 	dest_path->dlid = src_path->cep_adds_vect.av_dlid;
1499 	dest_path->hop_limit = src_path->cep_adds_vect.av_hop;
1500 	dest_path->traffic_class = src_path->cep_adds_vect.av_tclass;
1501 	dest_path->sl = src_path->cep_adds_vect.av_srvl;
1502 	dest_path->port_num = src_path->cep_adds_vect.av_port_num;
1503 	dest_path->src_path_bits = src_path->cep_adds_vect.av_src_path;
1504 	dest_path->is_global = src_path->cep_adds_vect.av_send_grh;
1505 	dest_path->sgid_index = src_path->cep_adds_vect.av_sgid_ix;
1506 	dest_path->static_rate =  src_path->cep_adds_vect.av_srate;
1507 }
1508 
1509 /*
1510  * Function:
1511  *      uverbs_query_copy_rc
1512  * Input:
1513  *      src	- The IBT RC QP attributes.
1514  * Output:
1515  *      dest	- The OFED user verbs QP attributes.
1516  * Returns:
1517  *      None
1518  * Description:
1519  *      Helper to copy IBT RC QP attributes to OFED QP attributes.
1520  */
1521 static void
1522 uverbs_query_copy_rc(struct ib_uverbs_query_qp_resp *dest,
1523     ibt_qp_rc_attr_t *src)
1524 {
1525 	dest->sq_psn = src->rc_sq_psn;
1526 	dest->rq_psn = src->rc_rq_psn;
1527 	dest->dest_qp_num = src->rc_dst_qpn;
1528 	dest->rnr_retry = src->rc_rnr_retry_cnt;
1529 	dest->retry_cnt = src->rc_retry_cnt;
1530 	dest->max_dest_rd_atomic = src->rc_rdma_ra_in;
1531 	dest->max_rd_atomic = src->rc_rdma_ra_out;
1532 	dest->min_rnr_timer = src->rc_min_rnr_nak;
1533 	dest->path_mtu = src->rc_path_mtu;
1534 	dest->timeout = src->rc_path.cep_timeout;
1535 	dest->alt_timeout = src->rc_alt_path.cep_timeout;
1536 	dest->port_num = src->rc_path.cep_hca_port_num;
1537 	dest->alt_port_num = src->rc_alt_path.cep_hca_port_num;
1538 
1539 	if (src->rc_mig_state == IBT_STATE_MIGRATED) {
1540 		dest->path_mig_state = IB_MIG_MIGRATED;
1541 	}
1542 	if (src->rc_mig_state == IBT_STATE_REARMED) {
1543 		dest->path_mig_state = IB_MIG_REARM;
1544 	}
1545 	if (src->rc_mig_state == IBT_STATE_ARMED) {
1546 		dest->path_mig_state = IB_MIG_ARMED;
1547 	}
1548 
1549 	uverbs_copy_path_info_from_ibt(&src->rc_path, &dest->dest);
1550 	uverbs_copy_path_info_from_ibt(&src->rc_alt_path, &dest->alt_dest);
1551 }
1552 
1553 /*
1554  * Function:
1555  *      uverbs_query_copy_uc
1556  * Input:
1557  *      src	- The IBT UC QP attributes.
1558  * Output:
1559  *      dest	- The OFED user verbs QP attributes.
1560  * Returns:
1561  *      None
1562  * Description:
1563  *      Helper to copy IBT UC QP attributes to OFED user verbs
1564  *	QP attributes.
1565  */
1566 static void
1567 uverbs_query_copy_uc(struct ib_uverbs_query_qp_resp *dest,
1568     ibt_qp_uc_attr_t *src)
1569 {
1570 	dest->sq_psn	  = src->uc_sq_psn;
1571 	dest->rq_psn	  = src->uc_rq_psn;
1572 	dest->dest_qp_num = src->uc_dst_qpn;
1573 	dest->path_mtu	  = src->uc_path_mtu;
1574 
1575 	if (src->uc_mig_state == IBT_STATE_MIGRATED) {
1576 		dest->path_mig_state = IB_MIG_MIGRATED;
1577 	}
1578 	if (src->uc_mig_state == IBT_STATE_REARMED) {
1579 		dest->path_mig_state = IB_MIG_REARM;
1580 	}
1581 	if (src->uc_mig_state == IBT_STATE_ARMED) {
1582 		dest->path_mig_state = IB_MIG_ARMED;
1583 	}
1584 
1585 	uverbs_copy_path_info_from_ibt(&src->uc_path, &dest->dest);
1586 	uverbs_copy_path_info_from_ibt(&src->uc_alt_path, &dest->alt_dest);
1587 }
1588 
1589 /*
1590  * Function:
1591  *      uverbs_query_copy_rd
1592  * Input:
1593  *      src	- The IBT RD QP attributes.
1594  * Output:
1595  *      dest	- The OFED user verbs QP attributes.
1596  * Returns:
1597  *      None
1598  * Description:
1599  *      Helper to copy IBT RD QP attributes to OFED user verb QP attributes.
1600  */
1601 static void
1602 uverbs_query_copy_rd(struct ib_uverbs_query_qp_resp *dest,
1603     ibt_qp_rd_attr_t *src)
1604 {
1605 	dest->qkey	    = src->rd_qkey;
1606 	dest->min_rnr_timer = src->rd_min_rnr_nak;
1607 }
1608 
1609 /*
1610  * Function:
1611  *      uverbs_query_copy_ud
1612  * Input:
1613  *      src	- The IBT UD QP attributes.
1614  * Output:
1615  *      dest	- The OFED user verbs QP attributes.
1616  * Returns:
1617  *      None
1618  * Description:
1619  *      Helper to copy IBT UD QP attributes to OFED user verbs QP attributes.
1620  */
1621 static void
1622 uverbs_query_copy_ud(struct ib_uverbs_query_qp_resp *dest,
1623     ibt_qp_ud_attr_t *src)
1624 {
1625 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1626 	    "query_copy_ud:entry - return UD info: qkey:%08X, "
1627 	    "psn:%d, pkey_idx:%d, port:%d", src->ud_qkey, src->ud_sq_psn,
1628 	    src->ud_pkey_ix, src->ud_port);
1629 
1630 	dest->qkey	 = src->ud_qkey;
1631 	dest->sq_psn	 = src->ud_sq_psn;
1632 	dest->pkey_index = src->ud_pkey_ix;
1633 	dest->port_num	 = src->ud_port;
1634 }
1635 
1636 /*
1637  * Function:
1638  *      uverbs_query_copy_info
1639  * Input:
1640  *      src	- The IBT QP information.
1641  * Output:
1642  *      dest	- The OFED user verbs QP attributes.
1643  * Returns:
1644  *      None
1645  * Description:
1646  *      Helper to copy IBT QP info to OFED user verbs QP attributes.
1647  */
1648 static void
1649 uverbs_query_copy_info(struct ib_uverbs_query_qp_resp *dest,
1650     ibt_qp_info_t *src)
1651 {
1652 
1653 	dest->max_send_wr = src->qp_sq_sz;
1654 	dest->max_recv_wr = src->qp_rq_sz;
1655 	dest->qp_access_flags = ibt_cep_flags2ibv(src->qp_flags);
1656 
1657 	switch (src->qp_state) {
1658 		case IBT_STATE_RESET:
1659 			dest->qp_state = IB_QPS_RESET;
1660 			break;
1661 		case IBT_STATE_INIT:
1662 			dest->qp_state = IB_QPS_INIT;
1663 			break;
1664 		case IBT_STATE_RTR:
1665 			dest->qp_state = IB_QPS_RTR;
1666 			break;
1667 		case IBT_STATE_RTS:
1668 			dest->qp_state = IB_QPS_RTS;
1669 			break;
1670 		case IBT_STATE_SQD:
1671 			dest->qp_state = IB_QPS_SQD;
1672 			break;
1673 		case IBT_STATE_SQE:
1674 			dest->qp_state = IB_QPS_SQE;
1675 			break;
1676 		case IBT_STATE_ERROR:
1677 		default:
1678 			dest->qp_state = IB_QPS_ERR;
1679 			break;
1680 	}
1681 
1682 	switch (src->qp_current_state) {
1683 		case IBT_STATE_RESET:
1684 			dest->cur_qp_state = IB_QPS_RESET;
1685 			break;
1686 		case IBT_STATE_INIT:
1687 			dest->cur_qp_state = IB_QPS_INIT;
1688 			break;
1689 		case IBT_STATE_RTR:
1690 			dest->cur_qp_state = IB_QPS_RTR;
1691 			break;
1692 		case IBT_STATE_RTS:
1693 			dest->cur_qp_state = IB_QPS_RTS;
1694 			break;
1695 		case IBT_STATE_SQD:
1696 			dest->cur_qp_state = IB_QPS_SQD;
1697 			break;
1698 		case IBT_STATE_SQE:
1699 			dest->cur_qp_state = IB_QPS_SQE;
1700 			break;
1701 		case IBT_STATE_ERROR:
1702 		default:
1703 			dest->cur_qp_state = IB_QPS_ERR;
1704 			break;
1705 	}
1706 
1707 	if ((src->qp_flags & IBT_ALL_SIGNALED) == IBT_ALL_SIGNALED) {
1708 		dest->sq_sig_all = 1;
1709 	}
1710 }
1711 
1712 /*
1713  * Function:
1714  *      uverbs_query_copy_attr
1715  * Input:
1716  *      src	- The IBT QP information.
1717  * Output:
1718  *      dest	- The OFED user verbs QP attributes.
1719  * Returns:
1720  *      None
1721  * Description:
1722  *      Helper to copy IBT QP attributes to OFED user verbs QP attributes.
1723  */
1724 static void
1725 uverbs_query_copy_attr(struct ib_uverbs_query_qp_resp *dest,
1726     ibt_qp_query_attr_t *src)
1727 {
1728 	dest->max_send_sge = src->qp_sq_sgl;
1729 	dest->max_recv_sge = src->qp_rq_sgl;
1730 }
1731 
1732 /*
1733  * Function:
1734  *      sol_uverbs_query_qp
1735  * Input:
1736  *      uctxt   - Pointer to the callers user context.
1737  *      buf     - Pointer to kernel buffer containing query QP command.
1738  *      in_len  - Length in bytes of input command buffer.
1739  *      out_len - Length in bytes of output response buffer.
1740  * Output:
1741  *      The command output buffer is updated with command results.
1742  * Returns:
1743  *      DDI_SUCCESS on success, else error code.
1744  * Description:
1745  *      User verbs entry point to query a device QP properties.
1746  */
1747 /* ARGSUSED */
1748 int
1749 sol_uverbs_query_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
1750     int in_len, int out_len)
1751 {
1752 	struct ib_uverbs_query_qp	cmd;
1753 	struct ib_uverbs_query_qp_resp	resp;
1754 	uverbs_uqp_uobj_t		*uqp;
1755 	ibt_qp_query_attr_t		qp_query_attr;
1756 	int				rc;
1757 
1758 	(void) memset(&resp, 0, sizeof (resp));
1759 	(void) memcpy(&cmd, buf, sizeof (cmd));
1760 
1761 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1762 	    "query_qp: entry (qp_handle=%d)", cmd.qp_handle);
1763 
1764 	uqp = uverbs_uobj_get_uqp_read(cmd.qp_handle);
1765 	if (uqp == NULL) {
1766 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1767 		    "query_qp(): List lookup failure");
1768 		rc = EINVAL;
1769 		goto err_out;
1770 	}
1771 
1772 	bzero(&qp_query_attr, sizeof (qp_query_attr));
1773 	rc =  ibt_query_qp(uqp->qp, &qp_query_attr);
1774 	sol_ofs_uobj_put(&uqp->uobj);
1775 
1776 	if (rc != IBT_SUCCESS) {
1777 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1778 		    "query_qp: Error in ibt_query_qp() (rc=%d)", rc);
1779 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1780 		goto err_out;
1781 	}
1782 
1783 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1784 	    "query_qp(): qp_query_attr.qp_info.qp_trans = %d",
1785 	    qp_query_attr.qp_info.qp_trans);
1786 
1787 	uverbs_query_copy_attr(&resp, &qp_query_attr);
1788 	uverbs_query_copy_info(&resp, &qp_query_attr.qp_info);
1789 
1790 	if (qp_query_attr.qp_info.qp_trans == IBT_RC_SRV) {
1791 		uverbs_query_copy_rc(&resp,
1792 		    &qp_query_attr.qp_info.qp_transport.rc);
1793 	}
1794 
1795 	if (qp_query_attr.qp_info.qp_trans == IBT_UC_SRV) {
1796 		uverbs_query_copy_uc(&resp,
1797 		    &qp_query_attr.qp_info.qp_transport.uc);
1798 	}
1799 
1800 	if (qp_query_attr.qp_info.qp_trans == IBT_RD_SRV) {
1801 		uverbs_query_copy_rd(&resp,
1802 		    &qp_query_attr.qp_info.qp_transport.rd);
1803 	}
1804 
1805 
1806 	if (qp_query_attr.qp_info.qp_trans == IBT_UD_SRV) {
1807 		uverbs_query_copy_ud(&resp,
1808 		    &qp_query_attr.qp_info.qp_transport.ud);
1809 	}
1810 
1811 	resp.max_inline_data = uqp->max_inline_data;
1812 
1813 #ifdef	_LP64
1814 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1815 #else
1816 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1817 #endif
1818 	if (rc != 0) {
1819 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1820 		    "query_qp(): Error writing resp data (rc=%d)", rc);
1821 		rc = EFAULT;
1822 		goto err_out;
1823 	}
1824 
1825 	return (DDI_SUCCESS);
1826 
1827 err_out:
1828 	return (rc);
1829 }
1830 
1831 /*
1832  * Function:
1833  *      sol_uverbs_create_srq
1834  * Input:
1835  *      uctxt   - Pointer to the callers user context.
1836  *      buf     - Pointer to kernel buffer containing command.
1837  *      in_len  - Length in bytes of input command buffer.
1838  *      out_len - Length in bytes of output response buffer.
1839  * Output:
1840  *      The command output buffer is updated with command results.
1841  * Returns:
1842  *      DDI_SUCCESS on success, else error code.
1843  * Description:
1844  *      User verbs entry point to create a device shared receive queue.
1845  */
1846 /* ARGSUSED */
1847 int
1848 sol_uverbs_create_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
1849     int in_len, int out_len)
1850 {
1851 	struct ib_uverbs_create_srq		cmd;
1852 	struct ib_uverbs_create_srq_resp	resp;
1853 	uverbs_usrq_uobj_t			*usrq;
1854 	uverbs_upd_uobj_t			*upd;
1855 	ibt_srq_flags_t				flags = IBT_SRQ_USER_MAP;
1856 	ibt_srq_sizes_t				attr;
1857 	ibt_srq_sizes_t				real_attr;
1858 	int					rc;
1859 
1860 	(void) memcpy(&cmd, buf, sizeof (cmd));
1861 	(void) memset(&resp, 0, sizeof (resp));
1862 	(void) memset(&attr, 0, sizeof (attr));
1863 
1864 	attr.srq_wr_sz   = cmd.max_wr;
1865 	attr.srq_sgl_sz  = cmd.max_sge;
1866 
1867 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_srq: "
1868 	    "max_wr=%d, max_sge=%d, srq_limit=%d",
1869 	    cmd.max_wr, cmd.max_sge, cmd.srq_limit);
1870 
1871 	if (!attr.srq_wr_sz) {
1872 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1873 		    "create_srq(): Invalid args, invalid work "
1874 		    "request size");
1875 
1876 		rc = EINVAL;
1877 		goto err_out;
1878 	}
1879 
1880 	if (attr.srq_wr_sz > uctxt->hca->attr.hca_max_srqs_sz ||
1881 	    attr.srq_sgl_sz > uctxt->hca->attr.hca_max_srq_sgl) {
1882 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1883 		    "create_srq(): Invalid args, too large");
1884 		rc = EINVAL;
1885 		goto err_out;
1886 	}
1887 
1888 	usrq = kmem_zalloc(sizeof (*usrq), KM_NOSLEEP);
1889 	if (usrq == NULL) {
1890 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1891 		    "create_srq(): User object alloc failed");
1892 		rc = ENOMEM;
1893 		goto err_out;
1894 	}
1895 	sol_ofs_uobj_init(&usrq->uobj, cmd.user_handle,
1896 	    SOL_UVERBS_USRQ_UOBJ_TYPE);
1897 	rw_enter(&usrq->uobj.uo_lock, RW_WRITER);
1898 	llist_head_init(&usrq->async_list, NULL);
1899 	usrq->async_events_reported = 0;
1900 	usrq->uctxt = uctxt;
1901 
1902 	upd = uverbs_uobj_get_upd_read(cmd.pd_handle);
1903 	if (upd == NULL) {
1904 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1905 		    "create_srq(): PD Invalid");
1906 		rc = EINVAL;
1907 		goto err_dealloc;
1908 	}
1909 
1910 	rc = ibt_alloc_srq(uctxt->hca->hdl, flags, upd->pd, &attr, &usrq->srq,
1911 	    &real_attr);
1912 
1913 	if (rc != IBT_SUCCESS) {
1914 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1915 		    "create_srq(): Error in ibt_alloc_srq() (rc=%d)", rc);
1916 		usrq->srq = NULL;
1917 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1918 		usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t);
1919 		goto err_release_pd;
1920 	}
1921 
1922 	ibt_set_srq_private(usrq->srq, usrq);
1923 
1924 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1925 	    "create_srq(): ib_alloc_srq()real wqe_sz=%d, real_sg_sz=%d",
1926 	    real_attr.srq_wr_sz, real_attr.srq_sgl_sz);
1927 
1928 	/*
1929 	 * Query underlying hardware for data used in mapping CQ back to user
1930 	 * space, we will return this information in the user verbs command
1931 	 * response.
1932 	 */
1933 	rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_SRQ,
1934 	    (void *)usrq->srq,  &resp.drv_out, sizeof (resp.drv_out));
1935 
1936 	if (rc != IBT_SUCCESS) {
1937 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1938 		    "create_srq(): Error in ibt_ci_data_out() (rc=%d)", rc);
1939 		rc = EFAULT;
1940 		usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t);
1941 		goto err_srq_destroy;
1942 	}
1943 
1944 	if (sol_ofs_uobj_add(&uverbs_usrq_uo_tbl, &usrq->uobj) != 0) {
1945 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1946 		    "create_srq(): uobj add failed");
1947 		rc = ENOMEM;
1948 		goto err_srq_destroy;
1949 	}
1950 
1951 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1952 	    "create_srq(): ibt_ci_data_out: 0x%16llx 0x%16llx 0x%16llx "
1953 	    "0x%16llx", resp.drv_out[0], resp.drv_out[1], resp.drv_out[2],
1954 	    resp.drv_out[3]);
1955 
1956 	resp.srq_handle	= usrq->uobj.uo_id;
1957 	resp.max_wr	= real_attr.srq_wr_sz;
1958 	resp.max_sge	= real_attr.srq_sgl_sz;
1959 
1960 #ifdef	_LP64
1961 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1962 #else
1963 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1964 #endif
1965 	if (rc != 0) {
1966 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1967 		    "create_srq(): Error writing resp data (rc=%d)", rc);
1968 		rc = EFAULT;
1969 		goto err_uo_delete;
1970 	}
1971 
1972 	mutex_enter(&uctxt->lock);
1973 	usrq->list_entry = add_genlist(&uctxt->srq_list, (uintptr_t)usrq,
1974 	    uctxt);
1975 	mutex_exit(&uctxt->lock);
1976 
1977 	if (!usrq->list_entry) {
1978 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1979 		    "create_srq() : Error adding usrq to srq_list failed");
1980 		rc = ENOMEM;
1981 		goto err_uo_delete;
1982 	}
1983 
1984 	usrq->uobj.uo_live = 1;
1985 	rw_exit(&usrq->uobj.uo_lock);
1986 
1987 	sol_ofs_uobj_put(&upd->uobj);
1988 
1989 	return (DDI_SUCCESS);
1990 
1991 err_uo_delete:
1992 	/*
1993 	 * Need to set uo_live, so sol_ofs_uobj_remove() will
1994 	 * remove the object from the object table.
1995 	 */
1996 	usrq->uobj.uo_live = 1;
1997 	(void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj);
1998 
1999 err_srq_destroy:
2000 	(void) ibt_free_srq(usrq->srq);
2001 
2002 err_release_pd:
2003 	sol_ofs_uobj_put(&upd->uobj);
2004 
2005 err_dealloc:
2006 	rw_exit(&usrq->uobj.uo_lock);
2007 	sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free);
2008 
2009 err_out:
2010 	return (rc);
2011 }
2012 
2013 /*
2014  * Function:
2015  *      sol_uverbs_modify_srq
2016  * Input:
2017  *      uctxt   - Pointer to the callers user context.
2018  *      buf     - Pointer to kernel buffer containing SRQ modify command.
2019  *      in_len  - Length in bytes of input command buffer.
2020  *      out_len - Length in bytes of output response buffer.
2021  * Output:
2022  *      The command output buffer is updated with command results.
2023  * Returns:
2024  *      DDI_SUCCESS on success, else error code.
2025  * Description:
2026  *      User verbs entry point to modify a device shared receive queue.
2027  */
2028 /* ARGSUSED */
2029 int
2030 sol_uverbs_modify_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
2031     int in_len, int out_len)
2032 {
2033 	struct ib_uverbs_modify_srq	cmd;
2034 	uverbs_usrq_uobj_t		*usrq;
2035 	uint_t				limit = 0;
2036 	uint_t				size = 0;
2037 	uint_t				real_size = 0;
2038 	ibt_srq_modify_flags_t 		flags = 0;
2039 	int				rc;
2040 
2041 	(void) memcpy(&cmd, buf, sizeof (cmd));
2042 
2043 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2044 	    "modify_srq(): entry (srq_handle=%d)", cmd.srq_handle);
2045 
2046 	usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle);
2047 	if (usrq == NULL) {
2048 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2049 		    "modify_srq(): List lookup failure");
2050 		rc = EINVAL;
2051 		goto err_out;
2052 	}
2053 
2054 	if (cmd.attr_mask & IB_SRQ_MAX_WR) {
2055 		flags = IBT_SRQ_SET_SIZE;
2056 		size = cmd.max_wr;
2057 	}
2058 
2059 	if (cmd.attr_mask & IB_SRQ_LIMIT) {
2060 		flags |= IBT_SRQ_SET_LIMIT;
2061 		limit = cmd.srq_limit;
2062 	}
2063 
2064 	rc = ibt_modify_srq(usrq->srq, flags, size, limit, &real_size);
2065 	if (rc != IBT_SUCCESS) {
2066 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2067 		    "modify_srq(): Error in ibt_modify_srq() (rc=%d)", rc);
2068 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2069 		goto err_deref;
2070 	}
2071 
2072 done:
2073 	sol_ofs_uobj_put(&usrq->uobj);
2074 	return (DDI_SUCCESS);
2075 
2076 err_deref:
2077 	sol_ofs_uobj_put(&usrq->uobj);
2078 
2079 err_out:
2080 	return (rc);
2081 }
2082 
2083 /*
2084  * Function:
2085  *      sol_uverbs_query_srq
2086  * Input:
2087  *      uctxt   - Pointer to the callers user context.
2088  *      buf     - Pointer to kernel buffer containing command.
2089  *      in_len  - Length in bytes of input command buffer.
2090  *      out_len - Length in bytes of output response buffer.
2091  * Output:
2092  *      The command output buffer is updated with command results.
2093  * Returns:
2094  *      DDI_SUCCESS on success, else error code.
2095  * Description:
2096  *      User verbs entry point to query a device shared receive queue
2097  *	properties.
2098  */
2099 /* ARGSUSED */
2100 int
2101 sol_uverbs_query_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
2102     int in_len, int out_len)
2103 {
2104 	struct ib_uverbs_query_srq	cmd;
2105 	struct ib_uverbs_query_srq_resp	resp;
2106 	uverbs_usrq_uobj_t		*usrq;
2107 	ibt_pd_hdl_t			pd;
2108 	int				rc;
2109 	ibt_srq_sizes_t			attr;
2110 	uint_t				limit;
2111 
2112 	(void) memcpy(&cmd, buf, sizeof (cmd));
2113 	(void) memset(&resp, 0, sizeof (resp));
2114 
2115 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2116 	    "query_srq(): entry (srq_handle=%d)", cmd.srq_handle);
2117 
2118 	usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle);
2119 	if (usrq == NULL) {
2120 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2121 		    "query_srq(): Invalid handle: %d", cmd.srq_handle);
2122 		rc = EINVAL;
2123 		goto err_out;
2124 	}
2125 
2126 	rc = ibt_query_srq(usrq->srq, &pd, &attr, &limit);
2127 	sol_ofs_uobj_put(&usrq->uobj);
2128 
2129 	if (rc != IBT_SUCCESS) {
2130 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2131 		    "query_srq(): Error in ibt_query_srq() (rc=%d)", rc);
2132 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2133 		goto err_out;
2134 	}
2135 
2136 	resp.max_wr    = attr.srq_wr_sz;
2137 	resp.max_sge   = attr.srq_sgl_sz;
2138 	resp.srq_limit = limit;
2139 
2140 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_srq() - "
2141 	    "max_wr=%d, max_sge=%d, limit=%d", resp.max_wr,
2142 	    resp.max_sge, resp.srq_limit);
2143 
2144 	/*
2145 	 * Release the reference from the find above, we leave the initial
2146 	 * reference placed at SRQ creation time.
2147 	 */
2148 
2149 #ifdef	_LP64
2150 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
2151 #else
2152 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
2153 #endif
2154 	if (rc != 0) {
2155 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "query_srq() - "
2156 		    "copyout failure %x", rc);
2157 		rc = EFAULT;
2158 		goto err_out;
2159 	}
2160 
2161 	return (DDI_SUCCESS);
2162 
2163 err_out:
2164 	return (rc);
2165 }
2166 
2167 int
2168 uverbs_usrq_free(uverbs_usrq_uobj_t *usrq, uverbs_uctxt_uobj_t *uctxt)
2169 {
2170 	int	rc;
2171 
2172 	if (!usrq->srq)
2173 		goto skip_ibt_free_srq;
2174 
2175 	rc = ibt_free_srq(usrq->srq);
2176 	if (rc != IBT_SUCCESS) {
2177 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "usrq_free() - "
2178 		    "Error in ibt_free_srq() (rc=%d)", rc);
2179 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2180 		sol_ofs_uobj_put(&usrq->uobj);
2181 		return (rc);
2182 	}
2183 	usrq->srq = NULL;
2184 
2185 skip_ibt_free_srq :
2186 	sol_ofs_uobj_put(&usrq->uobj);
2187 	if (usrq->list_entry) {
2188 		mutex_enter(&uctxt->lock);
2189 		delete_genlist(&uctxt->srq_list,  usrq->list_entry);
2190 		mutex_exit(&uctxt->lock);
2191 		(void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj);
2192 	}
2193 	sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free);
2194 
2195 	return (0);
2196 }
2197 
2198 /*
2199  * Function:
2200  *      sol_uverbs_destroy_srq
2201  * Input:
2202  *      uctxt   - Pointer to the callers user context.
2203  *      buf     - Pointer to kernel buffer containing command.
2204  *      in_len  - Length in bytes of input command buffer.
2205  *      out_len - Length in bytes of output response buffer.
2206  * Output:
2207  *      The command output buffer is updated with command results.
2208  * Returns:
2209  *      DDI_SUCCESS on success, else error code.
2210  * Description:
2211  *      User verbs entry point to destroy a device shared receive queue.
2212  */
2213 /* ARGSUSED */
2214 int
2215 sol_uverbs_destroy_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
2216     int in_len, int out_len)
2217 {
2218 	struct ib_uverbs_destroy_srq		cmd;
2219 	struct ib_uverbs_destroy_srq_resp	resp;
2220 	uverbs_usrq_uobj_t			*usrq;
2221 	int					rc;
2222 
2223 	(void) memcpy(&cmd, buf, sizeof (cmd));
2224 	(void) memset(&resp, 0, sizeof (resp));
2225 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "destroy_srq() - "
2226 	    "srq_handle %d", cmd.srq_handle);
2227 
2228 	usrq = uverbs_uobj_get_usrq_write(cmd.srq_handle);
2229 	if (usrq == NULL) {
2230 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2231 		    "destroy_srq() : inavlid hdl %d", cmd.srq_handle);
2232 		rc = EINVAL;
2233 		goto err_out;
2234 	}
2235 
2236 	uverbs_release_usrq_uevents(uctxt->async_evfile, usrq);
2237 	resp.events_reported = usrq->async_events_reported;
2238 	if (usrq->active_qp_cnt) {
2239 		sol_ofs_uobj_put(&usrq->uobj);
2240 		return (EBUSY);
2241 	} else {
2242 		rc = uverbs_usrq_free(usrq, uctxt);
2243 		if (rc)
2244 			goto err_out;
2245 	}
2246 
2247 #ifdef	_LP64
2248 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
2249 #else
2250 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
2251 #endif
2252 	if (rc != 0) {
2253 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2254 		    "destroy_srq() : copyout failure %x", rc);
2255 		rc = EFAULT;
2256 		goto err_out;
2257 	}
2258 
2259 	return (DDI_SUCCESS);
2260 
2261 err_out:
2262 	return (rc);
2263 }
2264 
2265 /*
2266  * Function:
2267  *      sol_uverbs_attach_mcast
2268  * Input:
2269  *      uctxt   - Pointer to the callers user context.
2270  *      buf     - Pointer to kernel buffer containing command.
2271  *      in_len  - Length in bytes of input command buffer.
2272  *      out_len - Length in bytes of output response buffer.
2273  * Output:
2274  *      The command output buffer is updated with command results.
2275  * Returns:
2276  *      DDI_SUCCESS on success, else error code.
2277  * Description:
2278  *      User verbs entry point to attach a QP to a multicast group
2279  */
2280 /* ARGSUSED */
2281 int
2282 sol_uverbs_attach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf,
2283     int in_len, int out_len)
2284 {
2285 	struct ib_uverbs_attach_mcast	cmd;
2286 	uverbs_uqp_uobj_t		*uqp;
2287 	uverbs_mcast_entry_t		*mc;
2288 	llist_head_t			*entry;
2289 	int				rc;
2290 	ib_gid_t			mc_gid;
2291 
2292 	(void) memcpy(&cmd, buf, sizeof (cmd));
2293 
2294 	/*
2295 	 * API specifies gid in network order, Solaris expects the gid
2296 	 * in host order, do the conversion if required.
2297 	 */
2298 	mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0]));
2299 	mc_gid.gid_guid   = b2h64(*((uint64_t *)&cmd.gid[8]));
2300 
2301 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "attach_mcast(qp_handle=%d, "
2302 	    "mlid=0x%04x, gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid,
2303 	    mc_gid.gid_prefix, mc_gid.gid_guid);
2304 
2305 	/*
2306 	 * Take object write to protect MC list.
2307 	 */
2308 	uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
2309 	if (uqp == NULL) {
2310 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2311 		    "attach_mcast QP not found");
2312 		rc = EINVAL;
2313 		goto err_out;
2314 	}
2315 
2316 	/*
2317 	 * Look to see if we are already attached and if so no need to attach
2318 	 * again, just return good status.
2319 	 */
2320 	list_for_each(entry, &uqp->mcast_list) {
2321 		mc = (uverbs_mcast_entry_t *)entry->ptr;
2322 
2323 		if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid &&
2324 		    !memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid,
2325 		    sizeof (mc_gid.gid))) {
2326 			SOL_OFS_DPRINTF_L4(sol_uverbs_dbg_str,
2327 			    "attach_mcast: match entry found");
2328 			rc = DDI_SUCCESS;
2329 			goto out_put;
2330 		}
2331 	}
2332 
2333 	mc = kmem_zalloc(sizeof (*mc), KM_NOSLEEP);
2334 	if (mc == NULL) {
2335 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2336 		    "attach_mcast: kmem_zalloc fail");
2337 		rc = ENOMEM;
2338 		goto out_put;
2339 	}
2340 
2341 	llist_head_init(&mc->list, mc);
2342 	mc->mcg.mc_adds_vect.av_dlid  = cmd.mlid;
2343 	bcopy(&mc_gid, &(mc->mcg.mc_adds_vect.av_dgid), sizeof (mc_gid));
2344 
2345 	rc = ibt_attach_mcg(uqp->qp, &mc->mcg);
2346 	if (rc != IBT_SUCCESS) {
2347 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2348 		    "attach_mcast: ibt_attach_mcq failed (r=%d)", rc);
2349 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2350 		goto err_free;
2351 	}
2352 
2353 	llist_add_tail(&mc->list, &uqp->mcast_list);
2354 	sol_ofs_uobj_put(&uqp->uobj);
2355 
2356 	return (DDI_SUCCESS);
2357 
2358 err_free:
2359 	kmem_free(mc, sizeof (*mc));
2360 out_put:
2361 	sol_ofs_uobj_put(&uqp->uobj);
2362 err_out:
2363 	return (rc);
2364 }
2365 
2366 /*
2367  * Function:
2368  *      sol_uverbs_detach_mcast
2369  * Input:
2370  *      uctxt   - Pointer to the callers user context.
2371  *      buf     - Pointer to kernel buffer containing command.
2372  *      in_len  - Length in bytes of input command buffer.
2373  *      out_len - Length in bytes of output response buffer.
2374  * Output:
2375  *      The command output buffer is updated with command results.
2376  * Returns:
2377  *      DDI_SUCCESS on success, else error code.
2378  * Description:
2379  *      User verbs entry point to detach a QP from a multicast group
2380  */
2381 /* ARGSUSED */
2382 int
2383 sol_uverbs_detach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf,
2384     int in_len, int out_len)
2385 {
2386 	struct ib_uverbs_detach_mcast	cmd;
2387 	uverbs_uqp_uobj_t		*uqp;
2388 	ibt_mcg_info_t			mcg;
2389 	int				rc;
2390 	uverbs_mcast_entry_t		*mc;
2391 	llist_head_t			*entry;
2392 	llist_head_t			*temp;
2393 	ib_gid_t			mc_gid;
2394 
2395 	(void) memcpy(&cmd, buf, sizeof (cmd));
2396 
2397 	/*
2398 	 * API specifies gid in network order, Solaris expects the gid
2399 	 * in host order, do the conversion if required.
2400 	 */
2401 	mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0]));
2402 	mc_gid.gid_guid   = b2h64(*((uint64_t *)&cmd.gid[8]));
2403 
2404 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2405 	    "detach_mcast: entry (qp_handle=%d, mlid=0x%04x,"
2406 	    "gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid, mc_gid.gid_prefix,
2407 	    mc_gid.gid_guid);
2408 
2409 	(void) memset(&mcg, 0, sizeof (mcg));
2410 
2411 	/*
2412 	 * Get object write to protect mcast list.
2413 	 */
2414 	uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
2415 	if (uqp == NULL) {
2416 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2417 		    "detach_mcast(): QP hdl %x not found", cmd.qp_handle);
2418 		rc = EINVAL;
2419 		goto err_out;
2420 	}
2421 
2422 	mcg.mc_adds_vect.av_dlid = cmd.mlid;
2423 	mcg.mc_adds_vect.av_dgid = mc_gid;
2424 
2425 	rc = ibt_detach_mcg(uqp->qp, &mcg);
2426 	if (rc != IBT_SUCCESS) {
2427 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2428 		    "deatch_mcast(): ibt_attach_mcq failed (r=%d)", rc);
2429 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2430 		goto err_put;
2431 	}
2432 
2433 	/*
2434 	 * Find and delete MC group from the QP multicast list.
2435 	 */
2436 	entry = uqp->mcast_list.nxt;
2437 	temp = entry->nxt;
2438 	while (entry != &uqp->mcast_list) {
2439 		ASSERT(entry);
2440 		mc    = (uverbs_mcast_entry_t *)entry->ptr;
2441 		ASSERT(mc);
2442 
2443 		if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid &&
2444 		    !memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid,
2445 		    sizeof (mc_gid.gid))) {
2446 			llist_del(&mc->list);
2447 			kmem_free(mc, sizeof (*mc));
2448 			break;
2449 		}
2450 		entry = temp;
2451 		temp = entry->nxt;
2452 	}
2453 
2454 	sol_ofs_uobj_put(&uqp->uobj);
2455 
2456 	return (DDI_SUCCESS);
2457 
2458 err_put:
2459 	sol_ofs_uobj_put(&uqp->uobj);
2460 
2461 err_out:
2462 	return (rc);
2463 }
2464 
2465 /*
2466  * Function:
2467  *      uverbs_release_uqp_mcast_entries
2468  * Input:
2469  *      uctxt   - Pointer to the callers user context.
2470  *      uqp     - Pointer to the user QP object for which the multicast
2471  *                list should be flushed.
2472  * Output:
2473  *      None
2474  * Returns:
2475  *      None
2476  * Description:
2477  *      Release any multicast resources held by this QP.  The
2478  *	user context associated with the QP should be locked
2479  *	externally to this routine to protect the updates to the
2480  *	multicast list.
2481  */
2482 void
2483 uverbs_detach_uqp_mcast_entries(uverbs_uqp_uobj_t *uqp)
2484 {
2485 	int			rc;
2486 	uverbs_mcast_entry_t	*mc;
2487 	llist_head_t		*entry;
2488 	llist_head_t		*temp;
2489 
2490 	/*
2491 	 * Find and delete MC group from the QP multicast list.
2492 	 */
2493 	entry = uqp->mcast_list.nxt;
2494 	temp = entry->nxt;
2495 	while (entry != &uqp->mcast_list) {
2496 		ASSERT(entry);
2497 		mc    = (uverbs_mcast_entry_t *)entry->ptr;
2498 		ASSERT(mc);
2499 
2500 		rc = ibt_detach_mcg(uqp->qp, &mc->mcg);
2501 		if (rc != IBT_SUCCESS) {
2502 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2503 			    "detach_mcast() : "
2504 			    "ibt_detach_mcq failed (r=%d)", rc);
2505 		}
2506 		llist_del(&mc->list);
2507 		entry = temp;
2508 		temp = entry->nxt;
2509 	}
2510 }
2511 
2512 /*
2513  * Function:
2514  *      sol_uverbs_uqpid_to_ibt_handle
2515  * Input:
2516  *      uqpid   - A user verbs QP id, i.e. a QP handle that was
2517  *	          created via libibverbs and sol_uverbs.
2518  * Output:
2519  *      None
2520  * Returns:
2521  *      The ibt_qp_hdl_t associated with the user space QP handle.
2522  *	-1 is returned if the id is not found.
2523  * Description:
2524  *      Map the user verbs QP id to the associated IBT QP handle.
2525  */
2526 ibt_qp_hdl_t
2527 sol_uverbs_uqpid_to_ibt_handle(uint32_t uqpid)
2528 {
2529 	uverbs_uqp_uobj_t	*uqp;
2530 	void			*qphdl;
2531 
2532 	uqp = uverbs_uobj_get_uqp_read(uqpid);
2533 	if (uqp == NULL) {
2534 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2535 		    "uqpid2ibthdl: QP lookup failure: id %d", uqpid);
2536 		return (NULL);
2537 	}
2538 	qphdl = (void *)uqp->qp;
2539 	sol_ofs_uobj_put(&uqp->uobj);
2540 	return (qphdl);
2541 }
2542 
2543 /*
2544  * Function:
2545  *      sol_uverbs_disable_user_qp_modify
2546  * Input:
2547  *      uqpid   - A user verbs QP id, i.e. a QP handle that was
2548  *	          created via libibverbs and sol_uverbs.
2549  * Output:
2550  *      None
2551  * Returns:
2552  *      0 on success, EINVAL if associated QP is not found.
2553  * Description:
2554  *      Inform sol_uverbs driver to ignore user qp modify
2555  *	operations it receives for the specified qp.  To re-enable
2556  *	this capability see the function sol_uverbs_enable_user_qp_modify.
2557  */
2558 int
2559 sol_uverbs_disable_user_qp_modify(uint32_t uqpid)
2560 {
2561 	uverbs_uqp_uobj_t	*uqp;
2562 
2563 	uqp = uverbs_uobj_get_uqp_write(uqpid);
2564 	if (uqp == NULL) {
2565 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2566 		    "disable_uqp_modify(%d) -lookup failure", uqpid);
2567 		return (EINVAL);
2568 	}
2569 	uqp->disable_qp_mod = TRUE;
2570 	sol_ofs_uobj_put(&uqp->uobj);
2571 	return (0);
2572 }
2573 
2574 /*
2575  * Function:
2576  *      sol_uverbs_enable_user_qp_modify
2577  * Input:
2578  *      uqpid   - A user verbs QP id, i.e. a QP handle that was
2579  *	          created via libibverbs and sol_uverbs.
2580  * Output:
2581  *      None
2582  * Returns:
2583  *      0 on success, EINVAL if associated QP is not found.
2584  * Description:
2585  *      Inform sol_uverbs driver to process user qp modify
2586  *	operations it receives for the specified qp.  This is
2587  *	the default and this routine need only be invoked if
2588  *	user QP modify operations have explicitly been disabled
2589  *	with sol_uverbs_disable_user_qp_modify.
2590  */
2591 int
2592 sol_uverbs_enable_user_qp_modify(uint32_t uqpid)
2593 {
2594 	uverbs_uqp_uobj_t    *uqp;
2595 
2596 	uqp = uverbs_uobj_get_uqp_write(uqpid);
2597 	if (uqp == NULL) {
2598 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2599 		    "enable_uqp_modify(%d) -lookup failure", uqpid);
2600 		return (EINVAL);
2601 	}
2602 	uqp->disable_qp_mod = FALSE;
2603 	sol_ofs_uobj_put(&uqp->uobj);
2604 	return (0);
2605 }
2606 
2607 int
2608 uverbs_uqpn_cq_ctrl(uint32_t uqpid, sol_uverbs_cq_ctrl_t ctrl)
2609 {
2610 	uverbs_uqp_uobj_t	*uqp;
2611 	uverbs_ucq_uobj_t	*uscq;
2612 	uverbs_ucq_uobj_t	*urcq;
2613 
2614 	uqp = uverbs_uobj_get_uqp_write(uqpid);
2615 	if (uqp == NULL) {
2616 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2617 		    "uqpn_cq_ctrl(%d) -lookup failure", uqpid);
2618 		return (EINVAL);
2619 	}
2620 	uscq = uqp->uqp_scq;
2621 	urcq = uqp->uqp_rcq;
2622 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2623 	    "ctrl - uqp %p, rcq %p. scq %p", uqp, urcq, uscq);
2624 
2625 	ASSERT(uscq);
2626 	ASSERT(urcq);
2627 	uverbs_cq_ctrl(uscq, ctrl);
2628 	if (uscq != urcq)
2629 		uverbs_cq_ctrl(urcq, ctrl);
2630 	sol_ofs_uobj_put(&uqp->uobj);
2631 	return (0);
2632 }
2633 
2634 extern uint32_t	sol_uverbs_qpnum2uqpid(uint32_t);
2635 
2636 void
2637 sol_uverbs_flush_qp(uint32_t qpnum)
2638 {
2639 	int32_t			uqpid;
2640 	ibt_status_t		status;
2641 	uverbs_uqp_uobj_t	*uqp;
2642 
2643 	uqpid = sol_uverbs_qpnum2uqpid(qpnum);
2644 	if (uqpid == DDI_FAILURE) {
2645 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2646 		    "sol_uverbs_flush_qp(%x) - Invalid qpnum",
2647 		    qpnum);
2648 		return;
2649 	}
2650 	uqp = uverbs_uobj_get_uqp_write(uqpid);
2651 	if (uqp == NULL) {
2652 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2653 		    "sol_uverbs_flush_qp(%x) - Invalid "
2654 		    "uqpid %x", qpnum, uqpid);
2655 		return;
2656 	}
2657 
2658 	if (uqp->qp) {
2659 		status = ibt_flush_qp(uqp->qp);
2660 		if (status != IBT_SUCCESS)
2661 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2662 			    "sol_uverbs_flush_qp(%x) - "
2663 			    "ibt_flush_qp(%p) failed - status %d",
2664 			    qpnum, uqp->qp, status);
2665 		sol_ofs_uobj_put(&uqp->uobj);
2666 		return;
2667 	} else {
2668 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2669 		    "sol_uverbs_flush_qp(%x), uqpid %x -"
2670 		    "uqp->qp is NULL!!", qpnum, uqpid);
2671 		sol_ofs_uobj_put(&uqp->uobj);
2672 		return;
2673 	}
2674 }
2675 static uint32_t
2676 ibt_cep_flags2ibv(ibt_cep_flags_t ibt_flags)
2677 {
2678 	uint32_t	ib_flags = 0;
2679 
2680 	if (ibt_flags & IBT_CEP_RDMA_WR)
2681 		ib_flags |= IB_ACCESS_REMOTE_WRITE;
2682 	if (ibt_flags & IBT_CEP_RDMA_RD)
2683 		ib_flags |= IB_ACCESS_REMOTE_READ;
2684 	if (ibt_flags & IBT_CEP_ATOMIC)
2685 		ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
2686 
2687 	return (ib_flags);
2688 }
2689 
2690 static void
2691 uverbs_cq_ctrl(uverbs_ucq_uobj_t *ucq, sol_uverbs_cq_ctrl_t ctrl)
2692 {
2693 	uverbs_ufile_uobj_t	*ufile;
2694 
2695 	ufile = ucq->comp_chan;
2696 	if (!ufile) {
2697 		SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
2698 		    "cq_ctrl(%p), ufile NULL", ucq, ufile);
2699 		return;
2700 	}
2701 
2702 	mutex_enter(&ufile->lock);
2703 	ufile->ufile_notify_enabled = ctrl;
2704 
2705 	if (ctrl == SOL_UVERBS2UCMA_CQ_NOTIFY_ENABLE) {
2706 		if (!llist_empty(&ufile->event_list)) {
2707 			cv_signal(&ufile->poll_wait);
2708 			pollwakeup(&ufile->poll_head,
2709 			    POLLIN | POLLRDNORM);
2710 		}
2711 	}
2712 	mutex_exit(&ufile->lock);
2713 }
2714