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