1c39526b7SPramod Gunjikar /*
2c39526b7SPramod Gunjikar  * CDDL HEADER START
3c39526b7SPramod Gunjikar  *
4c39526b7SPramod Gunjikar  * The contents of this file are subject to the terms of the
5c39526b7SPramod Gunjikar  * Common Development and Distribution License (the "License").
6c39526b7SPramod Gunjikar  * You may not use this file except in compliance with the License.
7c39526b7SPramod Gunjikar  *
8c39526b7SPramod Gunjikar  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c39526b7SPramod Gunjikar  * or http://www.opensolaris.org/os/licensing.
10c39526b7SPramod Gunjikar  * See the License for the specific language governing permissions
11c39526b7SPramod Gunjikar  * and limitations under the License.
12c39526b7SPramod Gunjikar  *
13c39526b7SPramod Gunjikar  * When distributing Covered Code, include this CDDL HEADER in each
14c39526b7SPramod Gunjikar  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c39526b7SPramod Gunjikar  * If applicable, add the following below this CDDL HEADER, with the
16c39526b7SPramod Gunjikar  * fields enclosed by brackets "[]" replaced with your own identifying
17c39526b7SPramod Gunjikar  * information: Portions Copyright [yyyy] [name of copyright owner]
18c39526b7SPramod Gunjikar  *
19c39526b7SPramod Gunjikar  * CDDL HEADER END
20c39526b7SPramod Gunjikar  */
21c39526b7SPramod Gunjikar 
22c39526b7SPramod Gunjikar /*
23c39526b7SPramod Gunjikar  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24c39526b7SPramod Gunjikar  */
25c39526b7SPramod Gunjikar 
26c39526b7SPramod Gunjikar 
27c39526b7SPramod Gunjikar /*
28c39526b7SPramod Gunjikar  * NAME: sol_uverbs_comp.c
29c39526b7SPramod Gunjikar  *
30c39526b7SPramod Gunjikar  * OFED User Verbs Kernel completion queue/processing implementation
31c39526b7SPramod Gunjikar  *
32c39526b7SPramod Gunjikar  */
33c39526b7SPramod Gunjikar #include <sys/file.h>
34c39526b7SPramod Gunjikar #include <sys/vfs.h>
35c39526b7SPramod Gunjikar #include <sys/vnode.h>
36c39526b7SPramod Gunjikar #include <sys/errno.h>
37c39526b7SPramod Gunjikar #include <sys/cred.h>
38c39526b7SPramod Gunjikar #include <sys/uio.h>
39c39526b7SPramod Gunjikar #include <sys/semaphore.h>
40c39526b7SPramod Gunjikar #include <sys/ddi.h>
41c39526b7SPramod Gunjikar 
42c39526b7SPramod Gunjikar #include <sys/ib/clients/of/ofa_solaris.h>
43c39526b7SPramod Gunjikar #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
44c39526b7SPramod Gunjikar #include <sys/ib/ibtl/ibvti.h>
45c39526b7SPramod Gunjikar #include <sys/ib/clients/of/ofed_kernel.h>
46c39526b7SPramod Gunjikar #include <sys/ib/clients/of/sol_uverbs/sol_uverbs.h>
47c39526b7SPramod Gunjikar #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_comp.h>
48c39526b7SPramod Gunjikar #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_event.h>
49c39526b7SPramod Gunjikar 
50c39526b7SPramod Gunjikar extern char	*sol_uverbs_dbg_str;
51c39526b7SPramod Gunjikar 
52c39526b7SPramod Gunjikar /*
53c39526b7SPramod Gunjikar  * Function:
54c39526b7SPramod Gunjikar  *      uverbs_convert_wc
55c39526b7SPramod Gunjikar  * Input:
56c39526b7SPramod Gunjikar  *      uctxt	- Pointer to the callers user context.
57c39526b7SPramod Gunjikar  *	ibt_wc	- Pointer to IBT work completion.
58c39526b7SPramod Gunjikar  * Output:
59c39526b7SPramod Gunjikar  *      ofed_wc	- Pointer to hold converted OFED work completion.
60c39526b7SPramod Gunjikar  * Returns:
61c39526b7SPramod Gunjikar  *      None
62c39526b7SPramod Gunjikar  * Description:
63c39526b7SPramod Gunjikar  *      Convert and IBT work completion to an OFED work completion.
64c39526b7SPramod Gunjikar  */
65c39526b7SPramod Gunjikar /* ARGSUSED */
66c39526b7SPramod Gunjikar static void
uverbs_convert_wc(uverbs_uctxt_uobj_t * uctxt,ibt_wc_t * ibt_wc,struct ib_uverbs_wc * ofed_wc)67c39526b7SPramod Gunjikar uverbs_convert_wc(uverbs_uctxt_uobj_t *uctxt, ibt_wc_t *ibt_wc,
68c39526b7SPramod Gunjikar     struct ib_uverbs_wc *ofed_wc)
69c39526b7SPramod Gunjikar {
70c39526b7SPramod Gunjikar 	ASSERT(uctxt != NULL);
71c39526b7SPramod Gunjikar 	ASSERT(ibt_wc != NULL);
72c39526b7SPramod Gunjikar 	ASSERT(ofed_wc != NULL);
73c39526b7SPramod Gunjikar 
74c39526b7SPramod Gunjikar 	ofed_wc->wr_id	= ibt_wc->wc_id;
75c39526b7SPramod Gunjikar 
76c39526b7SPramod Gunjikar 	switch (ibt_wc->wc_status) {
77c39526b7SPramod Gunjikar 
78c39526b7SPramod Gunjikar 		case IBT_WC_SUCCESS:
79c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_SUCCESS;
80c39526b7SPramod Gunjikar 			break;
81c39526b7SPramod Gunjikar 		case IBT_WC_LOCAL_LEN_ERR:
82c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_LOC_LEN_ERR;
83c39526b7SPramod Gunjikar 			break;
84c39526b7SPramod Gunjikar 		case IBT_WC_LOCAL_CHAN_OP_ERR:
85c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_LOC_QP_OP_ERR;
86c39526b7SPramod Gunjikar 			break;
87c39526b7SPramod Gunjikar 		case IBT_WC_LOCAL_PROTECT_ERR:
88c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_LOC_PROT_ERR;
89c39526b7SPramod Gunjikar 			break;
90c39526b7SPramod Gunjikar 		case IBT_WC_WR_FLUSHED_ERR:
91c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_WR_FLUSH_ERR;
92c39526b7SPramod Gunjikar 			break;
93c39526b7SPramod Gunjikar 		case IBT_WC_MEM_WIN_BIND_ERR:
94c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_MW_BIND_ERR;
95c39526b7SPramod Gunjikar 			break;
96c39526b7SPramod Gunjikar 		case IBT_WC_BAD_RESPONSE_ERR:
97c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_BAD_RESP_ERR;
98c39526b7SPramod Gunjikar 			break;
99c39526b7SPramod Gunjikar 		case IBT_WC_LOCAL_ACCESS_ERR:
100c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_LOC_ACCESS_ERR;
101c39526b7SPramod Gunjikar 			break;
102c39526b7SPramod Gunjikar 		case IBT_WC_REMOTE_INVALID_REQ_ERR:
103c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_REM_INV_REQ_ERR;
104c39526b7SPramod Gunjikar 			break;
105c39526b7SPramod Gunjikar 		case IBT_WC_REMOTE_ACCESS_ERR:
106c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_REM_ACCESS_ERR;
107c39526b7SPramod Gunjikar 			break;
108c39526b7SPramod Gunjikar 		case IBT_WC_REMOTE_OP_ERR:
109c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_REM_OP_ERR;
110c39526b7SPramod Gunjikar 			break;
111c39526b7SPramod Gunjikar 		case IBT_WC_TRANS_TIMEOUT_ERR:
112c39526b7SPramod Gunjikar 		case IBT_WC_RNR_NAK_TIMEOUT_ERR:
113c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_RESP_TIMEOUT_ERR;
114c39526b7SPramod Gunjikar 			break;
115c39526b7SPramod Gunjikar 		default:
116c39526b7SPramod Gunjikar 			ofed_wc->status	= IB_WC_FATAL_ERR;
117c39526b7SPramod Gunjikar 			break;
118c39526b7SPramod Gunjikar 	}
119c39526b7SPramod Gunjikar 
120c39526b7SPramod Gunjikar 	switch (ibt_wc->wc_type) {
121c39526b7SPramod Gunjikar 
122c39526b7SPramod Gunjikar 		case IBT_WRC_SEND:
123c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_SEND;
124c39526b7SPramod Gunjikar 			break;
125c39526b7SPramod Gunjikar 		case IBT_WRC_RDMAR:
126c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_RDMA_READ;
127c39526b7SPramod Gunjikar 			break;
128c39526b7SPramod Gunjikar 		case IBT_WRC_RDMAW:
129c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_RDMA_WRITE;
130c39526b7SPramod Gunjikar 			break;
131c39526b7SPramod Gunjikar 		case IBT_WRC_CSWAP:
132c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_COMP_SWAP;
133c39526b7SPramod Gunjikar 			break;
134c39526b7SPramod Gunjikar 		case IBT_WRC_FADD:
135c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_FETCH_ADD;
136c39526b7SPramod Gunjikar 			break;
137c39526b7SPramod Gunjikar 		case IBT_WRC_BIND:
138c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_BIND_MW;
139c39526b7SPramod Gunjikar 			break;
140c39526b7SPramod Gunjikar 		case IBT_WRC_RECV:
141c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_RECV;
142c39526b7SPramod Gunjikar 			break;
143c39526b7SPramod Gunjikar 		case IBT_WRC_RECV_RDMAWI:
144c39526b7SPramod Gunjikar 			ofed_wc->opcode	= IB_WC_RECV_RDMA_WITH_IMM;
145c39526b7SPramod Gunjikar 			break;
146c39526b7SPramod Gunjikar 
147c39526b7SPramod Gunjikar 		case IBT_WRC_FAST_REG_PMR:
148c39526b7SPramod Gunjikar 		case IBT_WRC_LOCAL_INVALIDATE:
149c39526b7SPramod Gunjikar 		default:
150c39526b7SPramod Gunjikar 			ofed_wc->opcode	= -1; /* (?) What to do here */
151c39526b7SPramod Gunjikar 			break;
152c39526b7SPramod Gunjikar 	}
153c39526b7SPramod Gunjikar 
154c39526b7SPramod Gunjikar 	ofed_wc->vendor_err 	= 0;
155c39526b7SPramod Gunjikar 	ofed_wc->byte_len 	= ibt_wc->wc_bytes_xfer;
156c39526b7SPramod Gunjikar 	ofed_wc->imm_data 	= ibt_wc->wc_immed_data;
157c39526b7SPramod Gunjikar 	ofed_wc->qp_num 	= ibt_wc->wc_local_qpn;
158c39526b7SPramod Gunjikar 	ofed_wc->src_qp 	= ibt_wc->wc_qpn;
159c39526b7SPramod Gunjikar 	ofed_wc->wc_flags	= 0;
160c39526b7SPramod Gunjikar 
161c39526b7SPramod Gunjikar 	if (ibt_wc->wc_flags & IBT_WC_GRH_PRESENT) {
162c39526b7SPramod Gunjikar 		ofed_wc->wc_flags |= IB_WC_GRH;
163c39526b7SPramod Gunjikar 	}
164c39526b7SPramod Gunjikar 
165c39526b7SPramod Gunjikar 	if (ibt_wc->wc_flags & IBT_WC_IMMED_DATA_PRESENT) {
166c39526b7SPramod Gunjikar 		ofed_wc->wc_flags |= IB_WC_WITH_IMM;
167c39526b7SPramod Gunjikar 	}
168c39526b7SPramod Gunjikar 
169c39526b7SPramod Gunjikar 	ofed_wc->pkey_index	= ibt_wc->wc_pkey_ix;
170c39526b7SPramod Gunjikar 	ofed_wc->slid		= ibt_wc->wc_slid;
171c39526b7SPramod Gunjikar 	ofed_wc->sl		= ibt_wc->wc_sl;
172c39526b7SPramod Gunjikar 	ofed_wc->dlid_path_bits	= ibt_wc->wc_path_bits;
173c39526b7SPramod Gunjikar 	ofed_wc->port_num	= 0;
174c39526b7SPramod Gunjikar 	ofed_wc->reserved	= 0;
175c39526b7SPramod Gunjikar }
176c39526b7SPramod Gunjikar 
177c39526b7SPramod Gunjikar /*
178c39526b7SPramod Gunjikar  * Function:
179c39526b7SPramod Gunjikar  *      sol_uverbs_create_cq
180c39526b7SPramod Gunjikar  * Input:
181c39526b7SPramod Gunjikar  *	uctxt   - Pointer to the callers user context.
182c39526b7SPramod Gunjikar  *	buf     - Pointer to kernel buffer containing create CQ command.
183c39526b7SPramod Gunjikar  *	in_len  - Length in bytes of input command buffer.
184c39526b7SPramod Gunjikar  *	out_len - Length in bytes of output response buffer.
185c39526b7SPramod Gunjikar  * Output:
186c39526b7SPramod Gunjikar  *	The command output buffer is updated with command results.
187c39526b7SPramod Gunjikar  * Returns:
188c39526b7SPramod Gunjikar  *      DDI_SUCCESS on success, else error code.
189c39526b7SPramod Gunjikar  * Description:
190c39526b7SPramod Gunjikar  *      User verbs entry point to create a device CQ.
191c39526b7SPramod Gunjikar  */
192c39526b7SPramod Gunjikar /* ARGSUSED */
193c39526b7SPramod Gunjikar int
sol_uverbs_create_cq(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)194c39526b7SPramod Gunjikar sol_uverbs_create_cq(uverbs_uctxt_uobj_t *uctxt, char *buf,
195c39526b7SPramod Gunjikar     int in_len, int out_len)
196c39526b7SPramod Gunjikar {
197c39526b7SPramod Gunjikar 	struct ib_uverbs_create_cq	cmd;
198c39526b7SPramod Gunjikar 	struct ib_uverbs_create_cq_resp	resp;
199c39526b7SPramod Gunjikar 	uverbs_ucq_uobj_t		*ucq;
200c39526b7SPramod Gunjikar 	ibt_cq_attr_t			cq_attr;
201c39526b7SPramod Gunjikar 	uint_t				real_size;
202c39526b7SPramod Gunjikar 	int				rc;
203c39526b7SPramod Gunjikar 
204c39526b7SPramod Gunjikar 	(void) memcpy(&cmd, buf, sizeof (cmd));
205c39526b7SPramod Gunjikar 	(void) memset(&resp, 0, sizeof (resp));
206c39526b7SPramod Gunjikar 	(void) memset(&cq_attr, 0, sizeof (cq_attr));
207c39526b7SPramod Gunjikar 
208c39526b7SPramod Gunjikar 	cq_attr.cq_size	  = cmd.cqe;
209c39526b7SPramod Gunjikar 	cq_attr.cq_sched  = 0;
210c39526b7SPramod Gunjikar 	cq_attr.cq_flags  = IBT_CQ_USER_MAP;
211c39526b7SPramod Gunjikar 
212c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_cq: "
213c39526b7SPramod Gunjikar 	    "num_cqe=%d, sched=%x, flags=%x",
214c39526b7SPramod Gunjikar 	    cq_attr.cq_size, cq_attr.cq_sched, cq_attr.cq_flags);
215c39526b7SPramod Gunjikar 
216c39526b7SPramod Gunjikar 	/*
217c39526b7SPramod Gunjikar 	 * To be consistent with OFED semantics, we fail a CQ that is being
218c39526b7SPramod Gunjikar 	 * created with 0 CQ entries.
219c39526b7SPramod Gunjikar 	 */
220c39526b7SPramod Gunjikar 	if (!cmd.cqe) {
221c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "create_cq: 0 cqe");
222c39526b7SPramod Gunjikar 		rc = EINVAL;
223c39526b7SPramod Gunjikar 		goto err_out;
224c39526b7SPramod Gunjikar 	}
225c39526b7SPramod Gunjikar 
226c39526b7SPramod Gunjikar 	ucq = kmem_zalloc(sizeof (*ucq), KM_NOSLEEP);
227c39526b7SPramod Gunjikar 	if (!ucq) {
228c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
229c39526b7SPramod Gunjikar 		    "create_cq: mem alloc failure");
230c39526b7SPramod Gunjikar 		rc = ENOMEM;
231c39526b7SPramod Gunjikar 		goto err_out;
232c39526b7SPramod Gunjikar 	}
233c39526b7SPramod Gunjikar 	sol_ofs_uobj_init(&ucq->uobj, cmd.user_handle,
234c39526b7SPramod Gunjikar 	    SOL_UVERBS_UCQ_UOBJ_TYPE);
235c39526b7SPramod Gunjikar 	rw_enter(&ucq->uobj.uo_lock, RW_WRITER);
236c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
237c39526b7SPramod Gunjikar 	    "create_cq: ucq %p, comp_chan %d", ucq, cmd.comp_channel);
238c39526b7SPramod Gunjikar 
239c39526b7SPramod Gunjikar 	/*
240c39526b7SPramod Gunjikar 	 * If a event completion channel was specified look it up and
241c39526b7SPramod Gunjikar 	 * assign the channel to the user CQ object.  Note that this
242c39526b7SPramod Gunjikar 	 * places a reference on the file itself.
243c39526b7SPramod Gunjikar 	 */
244c39526b7SPramod Gunjikar 	if ((int)cmd.comp_channel > SOL_UVERBS_DRIVER_MAX_MINOR) {
245c39526b7SPramod Gunjikar 		uverbs_uctxt_uobj_t	*compl_uctxt = NULL;
246c39526b7SPramod Gunjikar 		uverbs_ufile_uobj_t	*ufile;
247c39526b7SPramod Gunjikar 
248c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_cq: "
249c39526b7SPramod Gunjikar 		    "cmd.comp_chan %d", cmd.comp_channel);
250c39526b7SPramod Gunjikar 		compl_uctxt = uverbs_uobj_get_uctxt_write(
251c39526b7SPramod Gunjikar 		    cmd.comp_channel - SOL_UVERBS_DRIVER_MAX_MINOR);
252c39526b7SPramod Gunjikar 		if (!compl_uctxt) {
253c39526b7SPramod Gunjikar 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
254c39526b7SPramod Gunjikar 			    "create_cq: Invalid comp channel %d",
255c39526b7SPramod Gunjikar 			    cmd.comp_channel);
256c39526b7SPramod Gunjikar 			rc = EINVAL;
257c39526b7SPramod Gunjikar 			goto chan_err;
258c39526b7SPramod Gunjikar 		}
259c39526b7SPramod Gunjikar 		if (compl_uctxt->uctxt_verbs_id != uctxt->uobj.uo_id +
260c39526b7SPramod Gunjikar 		    SOL_UVERBS_DRIVER_MAX_MINOR) {
261c39526b7SPramod Gunjikar 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
262c39526b7SPramod Gunjikar 			    "create_cq: Invalid comp channel %d, "
263c39526b7SPramod Gunjikar 			    "verbs id %d mismatch",
264c39526b7SPramod Gunjikar 			    cmd.comp_channel,
265c39526b7SPramod Gunjikar 			    compl_uctxt->uctxt_verbs_id);
266c39526b7SPramod Gunjikar 			rc = EINVAL;
267c39526b7SPramod Gunjikar 			sol_ofs_uobj_put(&compl_uctxt->uobj);
268c39526b7SPramod Gunjikar 			goto chan_err;
269c39526b7SPramod Gunjikar 		}
270c39526b7SPramod Gunjikar 		ufile = compl_uctxt->comp_evfile;
271c39526b7SPramod Gunjikar 		ucq->comp_chan = ufile;
272c39526b7SPramod Gunjikar 		rw_enter(&ufile->uobj.uo_lock, RW_WRITER);
273c39526b7SPramod Gunjikar 		ufile->ufile_cq_cnt++;
274c39526b7SPramod Gunjikar 		rw_exit(&ufile->uobj.uo_lock);
275c39526b7SPramod Gunjikar 		sol_ofs_uobj_put(&compl_uctxt->uobj);
276c39526b7SPramod Gunjikar 
277c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_cq: "
278c39526b7SPramod Gunjikar 		    "ucq %p, comp_chan %p", ucq, ucq->comp_chan);
279c39526b7SPramod Gunjikar 	} else {
280c39526b7SPramod Gunjikar 		ucq->comp_chan = NULL;
281c39526b7SPramod Gunjikar 	}
282c39526b7SPramod Gunjikar 
283c39526b7SPramod Gunjikar 	llist_head_init(&ucq->async_list, NULL);
284c39526b7SPramod Gunjikar 	llist_head_init(&ucq->comp_list, NULL);
285c39526b7SPramod Gunjikar 
286c39526b7SPramod Gunjikar 	rc = ibt_alloc_cq(uctxt->hca->hdl, &cq_attr, &ucq->cq, &real_size);
287c39526b7SPramod Gunjikar 
288c39526b7SPramod Gunjikar 	if (rc != IBT_SUCCESS) {
289c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
290c39526b7SPramod Gunjikar 		    "create_cq: ibt_alloc_cq() (rc=%d)", rc);
291c39526b7SPramod Gunjikar 		rc = sol_uverbs_ibt_to_kernel_status(rc);
292c39526b7SPramod Gunjikar 		ucq->uobj.uo_uobj_sz = sizeof (uverbs_ucq_uobj_t);
293c39526b7SPramod Gunjikar 		goto alloc_err;
294c39526b7SPramod Gunjikar 	}
295c39526b7SPramod Gunjikar 
296c39526b7SPramod Gunjikar 	ibt_set_cq_private(ucq->cq, ucq);
297c39526b7SPramod Gunjikar 
298c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
299c39526b7SPramod Gunjikar 	    "create_cq: ib_alloc_cq() (rc=%d), real_size=%d",
300c39526b7SPramod Gunjikar 	    rc, real_size);
301c39526b7SPramod Gunjikar 	/*
302c39526b7SPramod Gunjikar 	 * Query underlying hardware for data used in mapping CQ back to user
303c39526b7SPramod Gunjikar 	 * space, we will return this information in the user verbs command
304c39526b7SPramod Gunjikar 	 * response.
305c39526b7SPramod Gunjikar 	 */
306c39526b7SPramod Gunjikar 	rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_CQ,
307c39526b7SPramod Gunjikar 	    (void *) ucq->cq,  &resp.drv_out, sizeof (resp.drv_out));
308c39526b7SPramod Gunjikar 	if (rc != IBT_SUCCESS) {
309c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
310c39526b7SPramod Gunjikar 		    "create_cq: ibt_ci_data_out() rc=%d", rc);
311c39526b7SPramod Gunjikar 		rc = EFAULT;
312c39526b7SPramod Gunjikar 		ucq->uobj.uo_uobj_sz = sizeof (uverbs_ucq_uobj_t);
313c39526b7SPramod Gunjikar 		goto err_cq_destroy;
314c39526b7SPramod Gunjikar 	}
315c39526b7SPramod Gunjikar 
316c39526b7SPramod Gunjikar 	if (sol_ofs_uobj_add(&uverbs_ucq_uo_tbl, &ucq->uobj) != 0) {
317c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
318c39526b7SPramod Gunjikar 		    "create_cq: User object add failed");
319c39526b7SPramod Gunjikar 		rc = ENOMEM;
320c39526b7SPramod Gunjikar 		goto err_cq_destroy;
321c39526b7SPramod Gunjikar 	}
322c39526b7SPramod Gunjikar 
323c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
324c39526b7SPramod Gunjikar 	    "create_cq: ibt_ci_data_out: 0x%16llx 0x%16llx "
325c39526b7SPramod Gunjikar 	    "0x%16llx 0x%16llx", resp.drv_out[0], resp.drv_out[1],
326c39526b7SPramod Gunjikar 	    resp.drv_out[2], resp.drv_out[3]);
327c39526b7SPramod Gunjikar 
328c39526b7SPramod Gunjikar 	resp.cqe	= real_size;
329c39526b7SPramod Gunjikar 	resp.cq_handle	= ucq->uobj.uo_id;
330c39526b7SPramod Gunjikar 
331c39526b7SPramod Gunjikar #ifdef	_LP64
332c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
333c39526b7SPramod Gunjikar #else
334c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
335c39526b7SPramod Gunjikar #endif
336c39526b7SPramod Gunjikar 	if (rc != 0) {
337c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
338c39526b7SPramod Gunjikar 		    "create_cq: copyout failed %x", rc);
339c39526b7SPramod Gunjikar 		rc = EFAULT;
340c39526b7SPramod Gunjikar 		goto err_uo_delete;
341c39526b7SPramod Gunjikar 	}
342c39526b7SPramod Gunjikar 
343c39526b7SPramod Gunjikar 	ucq->uctxt = uctxt;
344c39526b7SPramod Gunjikar 
345c39526b7SPramod Gunjikar 	mutex_enter(&uctxt->lock);
346c39526b7SPramod Gunjikar 	ucq->list_entry = add_genlist(&uctxt->cq_list, (uintptr_t)ucq, uctxt);
347c39526b7SPramod Gunjikar 	mutex_exit(&uctxt->lock);
348c39526b7SPramod Gunjikar 
349c39526b7SPramod Gunjikar 	if (!ucq->list_entry) {
350c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
351c39526b7SPramod Gunjikar 		    "create_cq: Error adding ucq to cq_list");
352c39526b7SPramod Gunjikar 		rc = ENOMEM;
353c39526b7SPramod Gunjikar 		goto err_uo_delete;
354c39526b7SPramod Gunjikar 	}
355c39526b7SPramod Gunjikar 
356c39526b7SPramod Gunjikar 	if (ucq->comp_chan) {
357c39526b7SPramod Gunjikar 		ibt_set_cq_handler(ucq->cq, sol_uverbs_comp_event_handler, ucq);
358c39526b7SPramod Gunjikar 	}
359c39526b7SPramod Gunjikar 
360c39526b7SPramod Gunjikar 	ucq->uobj.uo_live = 1;
361c39526b7SPramod Gunjikar 	rw_exit(&ucq->uobj.uo_lock);
362c39526b7SPramod Gunjikar 
363c39526b7SPramod Gunjikar 	return (DDI_SUCCESS);
364c39526b7SPramod Gunjikar 
365c39526b7SPramod Gunjikar err_uo_delete:
366c39526b7SPramod Gunjikar 	/*
367c39526b7SPramod Gunjikar 	 * Need to set uo_live, so sol_ofs_uobj_remove() will
368c39526b7SPramod Gunjikar 	 * remove the object from the object table.
369c39526b7SPramod Gunjikar 	 */
370c39526b7SPramod Gunjikar 	ucq->uobj.uo_live = 1;
371c39526b7SPramod Gunjikar 	(void) sol_ofs_uobj_remove(&uverbs_ucq_uo_tbl, &ucq->uobj);
372c39526b7SPramod Gunjikar 
373c39526b7SPramod Gunjikar err_cq_destroy:
374c39526b7SPramod Gunjikar 	(void) ibt_free_cq(ucq->cq);
375c39526b7SPramod Gunjikar 
376c39526b7SPramod Gunjikar alloc_err:
377c39526b7SPramod Gunjikar 	if (ucq->comp_chan) {
378c39526b7SPramod Gunjikar 		uverbs_release_ucq_channel(uctxt, ucq->comp_chan, ucq);
379c39526b7SPramod Gunjikar 	}
380c39526b7SPramod Gunjikar 
381c39526b7SPramod Gunjikar chan_err:
382c39526b7SPramod Gunjikar 	rw_exit(&ucq->uobj.uo_lock);
383c39526b7SPramod Gunjikar 	sol_ofs_uobj_deref(&ucq->uobj, sol_ofs_uobj_free);
384c39526b7SPramod Gunjikar 
385c39526b7SPramod Gunjikar err_out:
386c39526b7SPramod Gunjikar 	return (rc);
387c39526b7SPramod Gunjikar }
388c39526b7SPramod Gunjikar 
389c39526b7SPramod Gunjikar int
uverbs_ucq_free(uverbs_ucq_uobj_t * ucq,uverbs_uctxt_uobj_t * uctxt)390c39526b7SPramod Gunjikar uverbs_ucq_free(uverbs_ucq_uobj_t *ucq, uverbs_uctxt_uobj_t *uctxt)
391c39526b7SPramod Gunjikar {
392c39526b7SPramod Gunjikar 	int	rc;
393c39526b7SPramod Gunjikar 
394c39526b7SPramod Gunjikar 	rc = ibt_free_cq(ucq->cq);
395c39526b7SPramod Gunjikar 	if (rc != IBT_SUCCESS) {
396c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
397c39526b7SPramod Gunjikar 		    "destroy_id: ibt_free_cq() rc=%d",
398c39526b7SPramod Gunjikar 		    rc);
399c39526b7SPramod Gunjikar 		rc = sol_uverbs_ibt_to_kernel_status(rc);
400c39526b7SPramod Gunjikar 		sol_ofs_uobj_put(&ucq->uobj);
401c39526b7SPramod Gunjikar 		return (rc);
402c39526b7SPramod Gunjikar 	}
403c39526b7SPramod Gunjikar 	(void) sol_ofs_uobj_remove(&uverbs_ucq_uo_tbl, &ucq->uobj);
404c39526b7SPramod Gunjikar 	sol_ofs_uobj_put(&ucq->uobj);
405c39526b7SPramod Gunjikar 
406c39526b7SPramod Gunjikar 	if (ucq->list_entry) {
407c39526b7SPramod Gunjikar 		mutex_enter(&uctxt->lock);
408c39526b7SPramod Gunjikar 		delete_genlist(&uctxt->cq_list,  ucq->list_entry);
409c39526b7SPramod Gunjikar 		mutex_exit(&uctxt->lock);
410c39526b7SPramod Gunjikar 	}
411c39526b7SPramod Gunjikar 	sol_ofs_uobj_deref(&ucq->uobj, sol_ofs_uobj_free);
412c39526b7SPramod Gunjikar 	return (0);
413c39526b7SPramod Gunjikar }
414c39526b7SPramod Gunjikar 
415c39526b7SPramod Gunjikar /*
416c39526b7SPramod Gunjikar  * Function:
417c39526b7SPramod Gunjikar  *      sol_uverbs_destroy_cq
418c39526b7SPramod Gunjikar  * Input:
419c39526b7SPramod Gunjikar  *	uctxt   - Pointer to the callers user context.
420c39526b7SPramod Gunjikar  *	buf     - Pointer to kernel buffer containing a destroy CQ command.
421c39526b7SPramod Gunjikar  *	in_len  - Length in bytes of input command buffer.
422c39526b7SPramod Gunjikar  *	out_len - Length in bytes of output response buffer.
423c39526b7SPramod Gunjikar  * Output:
424c39526b7SPramod Gunjikar  *	The command output buffer is updated with command results.
425c39526b7SPramod Gunjikar  * Returns:
426c39526b7SPramod Gunjikar  *      DDI_SUCCESS on success, else error code.
427c39526b7SPramod Gunjikar  * Description:
428c39526b7SPramod Gunjikar  *      User verbs entry point to destroy a device CQ.
429c39526b7SPramod Gunjikar  */
430c39526b7SPramod Gunjikar /* ARGSUSED */
431c39526b7SPramod Gunjikar int
sol_uverbs_destroy_cq(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)432c39526b7SPramod Gunjikar sol_uverbs_destroy_cq(uverbs_uctxt_uobj_t *uctxt, char *buf,
433c39526b7SPramod Gunjikar     int in_len, int out_len)
434c39526b7SPramod Gunjikar {
435c39526b7SPramod Gunjikar 	struct ib_uverbs_destroy_cq		cmd;
436c39526b7SPramod Gunjikar 	struct ib_uverbs_destroy_cq_resp	resp;
437c39526b7SPramod Gunjikar 	uverbs_ucq_uobj_t			*ucq;
438c39526b7SPramod Gunjikar 	int					rc;
439c39526b7SPramod Gunjikar 
440c39526b7SPramod Gunjikar 	(void) memcpy(&cmd, buf, sizeof (cmd));
441c39526b7SPramod Gunjikar 	(void) memset(&resp, 0, sizeof (resp));
442c39526b7SPramod Gunjikar 
443c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
444c39526b7SPramod Gunjikar 	    "destroy_cq(cq_handle=%d)", cmd.cq_handle);
445c39526b7SPramod Gunjikar 
446c39526b7SPramod Gunjikar 	ucq = uverbs_uobj_get_ucq_write(cmd.cq_handle);
447c39526b7SPramod Gunjikar 	if (ucq == NULL) {
448c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
449c39526b7SPramod Gunjikar 		    "destroy_cq: Invalid handle: %d",
450c39526b7SPramod Gunjikar 		    cmd.cq_handle);
451c39526b7SPramod Gunjikar 		rc = EINVAL;
452c39526b7SPramod Gunjikar 		goto err_out;
453c39526b7SPramod Gunjikar 	}
454c39526b7SPramod Gunjikar 
455c39526b7SPramod Gunjikar 	uverbs_release_ucq_channel(uctxt, ucq->comp_chan, ucq);
456c39526b7SPramod Gunjikar 	cmd.cq_handle			= 0;
457c39526b7SPramod Gunjikar 	resp.comp_events_reported	= ucq->comp_events_reported;
458c39526b7SPramod Gunjikar 	resp.async_events_reported	= ucq->async_events_reported;
459c39526b7SPramod Gunjikar 
460c39526b7SPramod Gunjikar 	if (ucq->active_qp_cnt) {
461c39526b7SPramod Gunjikar 		sol_ofs_uobj_put(&ucq->uobj);
462c39526b7SPramod Gunjikar 		return (EBUSY);
463c39526b7SPramod Gunjikar 	} else {
464c39526b7SPramod Gunjikar 		rc = uverbs_ucq_free(ucq, uctxt);
465c39526b7SPramod Gunjikar 		if (rc)
466c39526b7SPramod Gunjikar 			goto err_out;
467c39526b7SPramod Gunjikar 	}
468c39526b7SPramod Gunjikar 
469c39526b7SPramod Gunjikar #ifdef	_LP64
470c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
471c39526b7SPramod Gunjikar #else
472c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
473c39526b7SPramod Gunjikar #endif
474c39526b7SPramod Gunjikar 	if (rc != 0) {
475c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
476c39526b7SPramod Gunjikar 		    "destroy_cq: copuout failed %x", rc);
477c39526b7SPramod Gunjikar 		rc = EFAULT;
478c39526b7SPramod Gunjikar 		goto err_out;
479c39526b7SPramod Gunjikar 	}
480c39526b7SPramod Gunjikar 
481c39526b7SPramod Gunjikar 	return (DDI_SUCCESS);
482c39526b7SPramod Gunjikar 
483c39526b7SPramod Gunjikar err_out:
484c39526b7SPramod Gunjikar 	return (rc);
485c39526b7SPramod Gunjikar }
486c39526b7SPramod Gunjikar 
487c39526b7SPramod Gunjikar /*
488c39526b7SPramod Gunjikar  * Function:
489c39526b7SPramod Gunjikar  *      sol_uverbs_resize_cq
490c39526b7SPramod Gunjikar  * Input:
491c39526b7SPramod Gunjikar  *	uctxt   - Pointer to the callers user context.
492c39526b7SPramod Gunjikar  *	buf     - Pointer to kernel buffer containing a resize CQ command.
493c39526b7SPramod Gunjikar  *	in_len  - Length in bytes of input command buffer.
494c39526b7SPramod Gunjikar  *	out_len - Length in bytes of output response buffer.
495c39526b7SPramod Gunjikar  * Output:
496c39526b7SPramod Gunjikar  *	The command output buffer is updated with command results.
497c39526b7SPramod Gunjikar  * Returns:
498c39526b7SPramod Gunjikar  *      DDI_SUCCESS on success, else error code.
499c39526b7SPramod Gunjikar  * Description:
500c39526b7SPramod Gunjikar  *      User verbs entry point to resize a device CQ.
501c39526b7SPramod Gunjikar  */
502c39526b7SPramod Gunjikar /* ARGSUSED */
503c39526b7SPramod Gunjikar int
sol_uverbs_resize_cq(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)504c39526b7SPramod Gunjikar sol_uverbs_resize_cq(uverbs_uctxt_uobj_t *uctxt, char *buf,
505c39526b7SPramod Gunjikar     int in_len, int out_len)
506c39526b7SPramod Gunjikar {
507c39526b7SPramod Gunjikar 	struct ib_uverbs_resize_cq	cmd;
508c39526b7SPramod Gunjikar 	struct ib_uverbs_resize_cq_resp	resp;
509c39526b7SPramod Gunjikar 	uverbs_ucq_uobj_t		*ucq;
510c39526b7SPramod Gunjikar 	int				rc;
511c39526b7SPramod Gunjikar 	int				resize_status;
512c39526b7SPramod Gunjikar 
513c39526b7SPramod Gunjikar 	(void) memcpy(&cmd, buf, sizeof (cmd));
514c39526b7SPramod Gunjikar 	(void) memset(&resp, 0, sizeof (resp));
515c39526b7SPramod Gunjikar 
516c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
517c39526b7SPramod Gunjikar 	    "resize_cq(cq_handle=%d)", cmd.cq_handle);
518c39526b7SPramod Gunjikar 
519c39526b7SPramod Gunjikar 	ucq = uverbs_uobj_get_ucq_write(cmd.cq_handle);
520c39526b7SPramod Gunjikar 	if (ucq == NULL) {
521c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
522c39526b7SPramod Gunjikar 		    "resize_cq: Invalid handle: %d",
523c39526b7SPramod Gunjikar 		    cmd.cq_handle);
524c39526b7SPramod Gunjikar 		rc = EINVAL;
525c39526b7SPramod Gunjikar 		goto err_out;
526c39526b7SPramod Gunjikar 	}
527c39526b7SPramod Gunjikar 
528c39526b7SPramod Gunjikar 	/*
529c39526b7SPramod Gunjikar 	 * If CQ resize fails, note the error but keep going.  In this case we
530c39526b7SPramod Gunjikar 	 * expect the old CQ size to be returned, and when we extract the
531c39526b7SPramod Gunjikar 	 * mapping data, we expect the offset and length are approrpriate for
532c39526b7SPramod Gunjikar 	 * the old CQ.
533c39526b7SPramod Gunjikar 	 */
534c39526b7SPramod Gunjikar 	resize_status = ibt_resize_cq(ucq->cq, cmd.cqe, &resp.cqe);
535c39526b7SPramod Gunjikar 	if (resize_status != IBT_SUCCESS) {
536c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
537*fffafeb2SJohnny Cheung 		    "resize_cq: ibt_resize_cq() (resize_status=%d), using "
538*fffafeb2SJohnny Cheung 		    "original CQ", resize_status);
539*fffafeb2SJohnny Cheung 		rc = sol_uverbs_ibt_to_kernel_status(resize_status);
540*fffafeb2SJohnny Cheung 		goto err_out;
541c39526b7SPramod Gunjikar 	}
542c39526b7SPramod Gunjikar 
543c39526b7SPramod Gunjikar 	sol_ofs_uobj_put(&ucq->uobj);
544c39526b7SPramod Gunjikar 
545c39526b7SPramod Gunjikar 	rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_CQ,
546c39526b7SPramod Gunjikar 	    (void *) ucq->cq,  &resp.drv_out, sizeof (resp.drv_out));
547c39526b7SPramod Gunjikar 	if (rc != IBT_SUCCESS) {
548c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
549c39526b7SPramod Gunjikar 		    "resize_cq: Error in ibt_ci_data_out() "
550c39526b7SPramod Gunjikar 		    "(rc=%d)", rc);
551c39526b7SPramod Gunjikar 		rc = EFAULT;
552c39526b7SPramod Gunjikar 		goto err_out;
553c39526b7SPramod Gunjikar 	}
554c39526b7SPramod Gunjikar 
555c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
556c39526b7SPramod Gunjikar 	    "resize_cq: ibt_ci_data_out: 0x%16llx 0x%16llx "
557c39526b7SPramod Gunjikar 	    "0x%16llx 0x%16llx", resp.drv_out[0], resp.drv_out[1],
558c39526b7SPramod Gunjikar 	    resp.drv_out[2], resp.drv_out[3]);
559c39526b7SPramod Gunjikar 
560c39526b7SPramod Gunjikar #ifdef	_LP64
561c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
562c39526b7SPramod Gunjikar #else
563c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
564c39526b7SPramod Gunjikar #endif
565c39526b7SPramod Gunjikar 	if (rc != 0) {
566c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
567c39526b7SPramod Gunjikar 		    "resize_cq: copyout %d", rc);
568c39526b7SPramod Gunjikar 		rc = EFAULT;
569c39526b7SPramod Gunjikar 		goto err_out;
570c39526b7SPramod Gunjikar 	}
571c39526b7SPramod Gunjikar 
572c39526b7SPramod Gunjikar 	return (resize_status);
573c39526b7SPramod Gunjikar 
574c39526b7SPramod Gunjikar err_out:
575c39526b7SPramod Gunjikar 	return (rc);
576c39526b7SPramod Gunjikar }
577c39526b7SPramod Gunjikar 
578c39526b7SPramod Gunjikar /*
579c39526b7SPramod Gunjikar  * Function:
580c39526b7SPramod Gunjikar  *      sol_uverbs_req_notify_cq
581c39526b7SPramod Gunjikar  * Input:
582c39526b7SPramod Gunjikar  *	uctxt   - Pointer to the callers user context.
583c39526b7SPramod Gunjikar  *	buf     - Pointer to kernel buffer containing request notify
584c39526b7SPramod Gunjikar  *	          command.
585c39526b7SPramod Gunjikar  *	in_len  - Length in bytes of input command buffer.
586c39526b7SPramod Gunjikar  *	out_len - Length in bytes of output response buffer.
587c39526b7SPramod Gunjikar  * Output:
588c39526b7SPramod Gunjikar  *	The command output buffer is updated with command results.
589c39526b7SPramod Gunjikar  * Returns:
590c39526b7SPramod Gunjikar  *      DDI_SUCCESS on success, else error code.
591c39526b7SPramod Gunjikar  * Description:
592c39526b7SPramod Gunjikar  *      User verbs entry point to request notification of CQ events.
593c39526b7SPramod Gunjikar  */
594c39526b7SPramod Gunjikar /* ARGSUSED */
595c39526b7SPramod Gunjikar int
sol_uverbs_req_notify_cq(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)596c39526b7SPramod Gunjikar sol_uverbs_req_notify_cq(uverbs_uctxt_uobj_t *uctxt, char *buf,
597c39526b7SPramod Gunjikar     int in_len, int out_len)
598c39526b7SPramod Gunjikar {
599c39526b7SPramod Gunjikar 	struct ib_uverbs_req_notify_cq	cmd;
600c39526b7SPramod Gunjikar 	ibt_cq_notify_flags_t		flag;
601c39526b7SPramod Gunjikar 	uverbs_ucq_uobj_t		*ucq;
602c39526b7SPramod Gunjikar 	int				rc;
603c39526b7SPramod Gunjikar 
604c39526b7SPramod Gunjikar 	(void) memcpy(&cmd, buf, sizeof (cmd));
605c39526b7SPramod Gunjikar 
606c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
607c39526b7SPramod Gunjikar 	    "req_notify_cq(cq_handle=%d)", cmd.cq_handle);
608c39526b7SPramod Gunjikar 
609c39526b7SPramod Gunjikar 	ucq = uverbs_uobj_get_ucq_read(cmd.cq_handle);
610c39526b7SPramod Gunjikar 	if (ucq == NULL) {
611c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
612c39526b7SPramod Gunjikar 		    "req_notify_cq: List lookup failure");
613c39526b7SPramod Gunjikar 		rc = EINVAL;
614c39526b7SPramod Gunjikar 		goto err_out;
615c39526b7SPramod Gunjikar 	}
616c39526b7SPramod Gunjikar 
617c39526b7SPramod Gunjikar 	flag = IBT_NEXT_COMPLETION;
618c39526b7SPramod Gunjikar 
619c39526b7SPramod Gunjikar 	if (cmd.solicited_only != 0) {
620c39526b7SPramod Gunjikar 		flag = IBT_NEXT_SOLICITED;
621c39526b7SPramod Gunjikar 	}
622c39526b7SPramod Gunjikar 
623c39526b7SPramod Gunjikar 	rc = ibt_enable_cq_notify(ucq->cq, flag);
624c39526b7SPramod Gunjikar 	if (rc != IBT_SUCCESS) {
625c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
626c39526b7SPramod Gunjikar 		    "req_notify_cq: ibt_enable_cq_notify() "
627c39526b7SPramod Gunjikar 		    "(rc=%d)", rc);
628c39526b7SPramod Gunjikar 		rc = sol_uverbs_ibt_to_kernel_status(rc);
629c39526b7SPramod Gunjikar 		goto err_put;
630c39526b7SPramod Gunjikar 	}
631c39526b7SPramod Gunjikar 
632c39526b7SPramod Gunjikar 	sol_ofs_uobj_put(&ucq->uobj);
633c39526b7SPramod Gunjikar 	return (DDI_SUCCESS);
634c39526b7SPramod Gunjikar 
635c39526b7SPramod Gunjikar err_put:
636c39526b7SPramod Gunjikar 	sol_ofs_uobj_put(&ucq->uobj);
637c39526b7SPramod Gunjikar 
638c39526b7SPramod Gunjikar err_out:
639c39526b7SPramod Gunjikar 	return (rc);
640c39526b7SPramod Gunjikar }
641c39526b7SPramod Gunjikar 
642c39526b7SPramod Gunjikar /*
643c39526b7SPramod Gunjikar  * Function:
644c39526b7SPramod Gunjikar  *      sol_uverbs_poll_cq
645c39526b7SPramod Gunjikar  * Input:
646c39526b7SPramod Gunjikar  *	uctxt   - Pointer to the callers user context.
647c39526b7SPramod Gunjikar  *	buf     - Pointer to kernel buffer containing poll CQ command.
648c39526b7SPramod Gunjikar  *	in_len  - Length in bytes of input command buffer.
649c39526b7SPramod Gunjikar  *	out_len - Length in bytes of output response buffer.
650c39526b7SPramod Gunjikar  * Output:
651c39526b7SPramod Gunjikar  *	The command output buffer is updated with command results.
652c39526b7SPramod Gunjikar  * Returns:
653c39526b7SPramod Gunjikar  *      DDI_SUCCESS on success, else error code.
654c39526b7SPramod Gunjikar  * Description:
655c39526b7SPramod Gunjikar  *      User verbs entry point to poll a CQ for completion events.  Note that
656c39526b7SPramod Gunjikar  * 	this is	a non OS Bypass version, the CQ normally would be polled
657c39526b7SPramod Gunjikar  *	directly from the user space driver.
658c39526b7SPramod Gunjikar  */
659c39526b7SPramod Gunjikar /* ARGSUSED */
660c39526b7SPramod Gunjikar int
sol_uverbs_poll_cq(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)661c39526b7SPramod Gunjikar sol_uverbs_poll_cq(uverbs_uctxt_uobj_t *uctxt, char *buf,
662c39526b7SPramod Gunjikar     int in_len, int out_len)
663c39526b7SPramod Gunjikar {
664c39526b7SPramod Gunjikar 	struct ib_uverbs_poll_cq	cmd;
665c39526b7SPramod Gunjikar 	struct ib_uverbs_poll_cq_resp	resp;
666c39526b7SPramod Gunjikar 	uverbs_ucq_uobj_t		*ucq;
667c39526b7SPramod Gunjikar 	ibt_wc_t			*completions;
668c39526b7SPramod Gunjikar 	struct ib_uverbs_wc		ofed_wc;
669c39526b7SPramod Gunjikar 	int				rc;
670c39526b7SPramod Gunjikar 	int				i;
671c39526b7SPramod Gunjikar 
672c39526b7SPramod Gunjikar 	(void) memcpy(&cmd, buf, sizeof (cmd));
673c39526b7SPramod Gunjikar 	(void) memset(&resp, 0, sizeof (resp));
674c39526b7SPramod Gunjikar 
675c39526b7SPramod Gunjikar #ifdef DEBUG
676c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
677c39526b7SPramod Gunjikar 	    "poll_cq(cq_handle=%d)", cmd.cq_handle);
678c39526b7SPramod Gunjikar #endif
679c39526b7SPramod Gunjikar 
680c39526b7SPramod Gunjikar 	ucq = uverbs_uobj_get_ucq_read(cmd.cq_handle);
681c39526b7SPramod Gunjikar 	if (ucq == NULL) {
682c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
683c39526b7SPramod Gunjikar 		    "poll_cq: List lookup failure");
684c39526b7SPramod Gunjikar 		rc = EINVAL;
685c39526b7SPramod Gunjikar 		goto err_find;
686c39526b7SPramod Gunjikar 	}
687c39526b7SPramod Gunjikar 
688c39526b7SPramod Gunjikar 	completions = (ibt_wc_t *)kmem_zalloc(sizeof (ibt_wc_t) * cmd.ne,
689c39526b7SPramod Gunjikar 	    KM_NOSLEEP);
690c39526b7SPramod Gunjikar 	if (completions == NULL) {
691c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
692c39526b7SPramod Gunjikar 		    "poll_cq: Allocation Error");
693c39526b7SPramod Gunjikar 		rc = ENOMEM;
694c39526b7SPramod Gunjikar 		goto err_alloc;
695c39526b7SPramod Gunjikar 	}
696c39526b7SPramod Gunjikar 
697c39526b7SPramod Gunjikar 	rc = ibt_poll_cq(ucq->cq, completions, cmd.ne, &resp.count);
698c39526b7SPramod Gunjikar 	if (rc != IBT_SUCCESS) {
699c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
700c39526b7SPramod Gunjikar 		    "poll_cq: ibt_poll_cq() (rc=%d)", rc);
701c39526b7SPramod Gunjikar 		rc = sol_uverbs_ibt_to_kernel_status(rc);
702c39526b7SPramod Gunjikar 		goto err_poll;
703c39526b7SPramod Gunjikar 	}
704c39526b7SPramod Gunjikar 
705c39526b7SPramod Gunjikar #ifdef	_LP64
706c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
707c39526b7SPramod Gunjikar #else
708c39526b7SPramod Gunjikar 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
709c39526b7SPramod Gunjikar #endif
710c39526b7SPramod Gunjikar 	if (rc != 0) {
711c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
712c39526b7SPramod Gunjikar 		    "poll_cq: copyout %x", rc);
713c39526b7SPramod Gunjikar 		rc = EFAULT;
714c39526b7SPramod Gunjikar 		goto err_poll;
715c39526b7SPramod Gunjikar 	}
716c39526b7SPramod Gunjikar 
717c39526b7SPramod Gunjikar 	for (i = 0; i < resp.count; i++) {
718c39526b7SPramod Gunjikar 		(void) memset(&ofed_wc, 0, sizeof (ofed_wc));
719c39526b7SPramod Gunjikar 		uverbs_convert_wc(uctxt, &completions[i], &ofed_wc);
720c39526b7SPramod Gunjikar 
721c39526b7SPramod Gunjikar #ifdef	_LP64
722c39526b7SPramod Gunjikar 		rc = copyout((void*)&ofed_wc,
723c39526b7SPramod Gunjikar 		    (void *)cmd.response.r_laddr, sizeof (ofed_wc));
724c39526b7SPramod Gunjikar #else
725c39526b7SPramod Gunjikar 		rc = copyout((void*)&ofed_wc,
726c39526b7SPramod Gunjikar 		    (void *)cmd.response.r_addr, sizeof (ofed_wc));
727c39526b7SPramod Gunjikar #endif
728c39526b7SPramod Gunjikar 		if (rc != 0) {
729c39526b7SPramod Gunjikar 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
730c39526b7SPramod Gunjikar 			    "poll_cq: copyout wc data %x", rc);
731c39526b7SPramod Gunjikar 			rc = EFAULT;
732c39526b7SPramod Gunjikar 			goto err_poll;
733c39526b7SPramod Gunjikar 		}
734c39526b7SPramod Gunjikar 	}
735c39526b7SPramod Gunjikar 
736c39526b7SPramod Gunjikar 	kmem_free((void*)completions, sizeof (ibt_wc_t) * cmd.ne);
737c39526b7SPramod Gunjikar 	sol_ofs_uobj_put(&ucq->uobj);
738c39526b7SPramod Gunjikar 
739c39526b7SPramod Gunjikar 	return (DDI_SUCCESS);
740c39526b7SPramod Gunjikar 
741c39526b7SPramod Gunjikar err_poll:
742c39526b7SPramod Gunjikar 	kmem_free((void *)completions, sizeof (ibt_wc_t) * cmd.ne);
743c39526b7SPramod Gunjikar 
744c39526b7SPramod Gunjikar err_alloc:
745c39526b7SPramod Gunjikar 	sol_ofs_uobj_put(&ucq->uobj);
746c39526b7SPramod Gunjikar 
747c39526b7SPramod Gunjikar err_find:
748c39526b7SPramod Gunjikar 	return (rc);
749c39526b7SPramod Gunjikar }
750c39526b7SPramod Gunjikar 
751c39526b7SPramod Gunjikar /*
752c39526b7SPramod Gunjikar  * Function:
753c39526b7SPramod Gunjikar  *      sol_uverbs_comp_event_handler
754c39526b7SPramod Gunjikar  * Input:
755c39526b7SPramod Gunjikar  *      ibt_cq  - Handle to the IBT CQ.
756c39526b7SPramod Gunjikar  *      arg     - Address of the associated Solaris User Verbs CQ
757c39526b7SPramod Gunjikar  *	          object.
758c39526b7SPramod Gunjikar  * Output:
759c39526b7SPramod Gunjikar  *      None
760c39526b7SPramod Gunjikar  * Returns:
761c39526b7SPramod Gunjikar  *      None
762c39526b7SPramod Gunjikar  * Description:
763c39526b7SPramod Gunjikar  *	Solaris User Verbs completion channel IBT CQ callback.  Queue
764c39526b7SPramod Gunjikar  *	the completion event and wakeup/notify consumers that may be
765c39526b7SPramod Gunjikar  *	blocked waiting for the completion.
766c39526b7SPramod Gunjikar  */
767c39526b7SPramod Gunjikar /* ARGSUSED */
768c39526b7SPramod Gunjikar void
sol_uverbs_comp_event_handler(ibt_cq_hdl_t ibt_cq,void * arg)769c39526b7SPramod Gunjikar sol_uverbs_comp_event_handler(ibt_cq_hdl_t ibt_cq, void *arg)
770c39526b7SPramod Gunjikar {
771c39526b7SPramod Gunjikar 	uverbs_ucq_uobj_t	*ucq = arg;
772c39526b7SPramod Gunjikar 	uverbs_ufile_uobj_t	*ufile;
773c39526b7SPramod Gunjikar 	uverbs_event_t		*entry;
774c39526b7SPramod Gunjikar 
775c39526b7SPramod Gunjikar 	if (!ucq || !ucq->comp_chan) {
776c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "comp_evt_hdlr "
777c39526b7SPramod Gunjikar 		    "ucq %p ucq->comp_chan %p", ucq, (ucq) ? ucq->comp_chan :
778c39526b7SPramod Gunjikar 		    NULL);
779c39526b7SPramod Gunjikar 		return;
780c39526b7SPramod Gunjikar 	}
781c39526b7SPramod Gunjikar 
782*fffafeb2SJohnny Cheung #ifdef DEBUG
783*fffafeb2SJohnny Cheung 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "comp_evt_hdlr(%p, %p) - ",
784*fffafeb2SJohnny Cheung 	    "ucq = %p, ucq->cq = %p, ucq->uctxt = %p, ucq->comp_chan =%p",
785*fffafeb2SJohnny Cheung 	    ibt_cq, arg, ucq, ucq->cq, ucq->uctxt, ucq->comp_chan);
786*fffafeb2SJohnny Cheung #endif
787*fffafeb2SJohnny Cheung 
788c39526b7SPramod Gunjikar 	ufile = ucq->comp_chan;
789c39526b7SPramod Gunjikar 
790c39526b7SPramod Gunjikar 	mutex_enter(&ufile->lock);
791c39526b7SPramod Gunjikar 	if (!ufile->uctxt) {
792c39526b7SPramod Gunjikar 		mutex_exit(&ufile->lock);
793c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "comp_evt_hdlr "
794c39526b7SPramod Gunjikar 		    "ufile->uctxt %p", ufile->uctxt);
795c39526b7SPramod Gunjikar 		return;
796c39526b7SPramod Gunjikar 	}
797c39526b7SPramod Gunjikar 
798c39526b7SPramod Gunjikar 	entry = kmem_zalloc(sizeof (*entry), KM_NOSLEEP);
799c39526b7SPramod Gunjikar 	if (!entry) {
800c39526b7SPramod Gunjikar 		mutex_exit(&ufile->lock);
801c39526b7SPramod Gunjikar 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "comp_evt_hdlr() "
802c39526b7SPramod Gunjikar 		    "memory allocation error");
803c39526b7SPramod Gunjikar 		return;
804c39526b7SPramod Gunjikar 	}
805c39526b7SPramod Gunjikar 
806c39526b7SPramod Gunjikar 	entry->ev_desc.comp.cq_handle	= ucq->uobj.uo_user_handle;
807c39526b7SPramod Gunjikar 	entry->ev_counter		= &ucq->comp_events_reported;
808c39526b7SPramod Gunjikar 
809c39526b7SPramod Gunjikar 	/*
810c39526b7SPramod Gunjikar 	 * Add to list of entries associated with completion channel
811c39526b7SPramod Gunjikar 	 * and the list associated with the specific CQ.
812c39526b7SPramod Gunjikar 	 */
813c39526b7SPramod Gunjikar 	llist_head_init(&entry->ev_list, entry);
814c39526b7SPramod Gunjikar 	llist_head_init(&entry->ev_obj_list, entry);
815c39526b7SPramod Gunjikar 
816c39526b7SPramod Gunjikar #ifdef DEBUG
817c39526b7SPramod Gunjikar 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "comp_evt_hdlr() "
818c39526b7SPramod Gunjikar 	    "Add COMP entry->ev_list=%p, &entry->ev_obj_list, entry=%p",
819c39526b7SPramod Gunjikar 	    &entry->ev_list, &entry->ev_obj_list, entry);
820c39526b7SPramod Gunjikar #endif
821c39526b7SPramod Gunjikar 
822c39526b7SPramod Gunjikar 	llist_add_tail(&entry->ev_list, &ufile->event_list);
823c39526b7SPramod Gunjikar 	llist_add_tail(&entry->ev_obj_list, &ucq->comp_list);
824c39526b7SPramod Gunjikar 
825c39526b7SPramod Gunjikar 	/* Do not notify users if sol_ucma has disabled CQ notify */
826c39526b7SPramod Gunjikar 	if (ufile->ufile_notify_enabled ==
827c39526b7SPramod Gunjikar 	    SOL_UVERBS2UCMA_CQ_NOTIFY_DISABLE) {
828c39526b7SPramod Gunjikar 		mutex_exit(&ufile->lock);
829c39526b7SPramod Gunjikar 		return;
830c39526b7SPramod Gunjikar 	}
831c39526b7SPramod Gunjikar 
832c39526b7SPramod Gunjikar 	cv_signal(&ufile->poll_wait);
833c39526b7SPramod Gunjikar 	mutex_exit(&ufile->lock);
834c39526b7SPramod Gunjikar 	pollwakeup(&ufile->poll_head, POLLIN | POLLRDNORM);
835c39526b7SPramod Gunjikar }
836